import { ClawHubService } from '@electron/gateway/clawhub'; import { SkillInstallService, SkillInstallServiceError, type SkillInstallRequest, } from '@electron/service/skill-install-service'; import { getAllSkillConfigs, updateSkillConfig } from '@electron/utils/skill-config'; import type { GatewayEvent, GatewayRpcParams, GatewayRpcReturns } from '../types'; type GatewayBroadcast = (event: GatewayEvent) => void; function broadcastSkillsRuntimeChanged(broadcast?: GatewayBroadcast, reason = 'skills:changed'): void { broadcast?.({ type: 'runtime:changed', topics: ['skills'], reason, syncedAt: new Date().toISOString(), }); } export async function handleSkillsStatus(): Promise { const configs = await getAllSkillConfigs(); return { skills: Object.entries(configs).map(([skillKey, config]) => ({ skillKey, slug: config.slug || skillKey, name: config.name || skillKey, description: config.description || '', disabled: config.enabled === false, emoji: config.icon, version: config.version || '1.0.0', author: config.author, config: { ...(config.config || {}), ...(config.apiKey ? { apiKey: config.apiKey } : {}), ...(config.env ? { env: config.env } : {}), }, bundled: typeof config.isBundled === 'boolean' ? config.isBundled : config.source === 'openclaw-bundled', always: Boolean(config.isCore), source: config.source, baseDir: config.baseDir, filePath: config.filePath, })), }; } export async function handleSkillsUpdate( params: { skillKey: string; enabled?: boolean }, ): Promise { const { skillKey, enabled } = params; if (!skillKey || !String(skillKey).trim()) { throw new Error('skillKey is required'); } const result = await updateSkillConfig(String(skillKey).trim(), { enabled }); if (!result.success) { throw new Error(result.error || 'Failed to update skill'); } return { success: true }; } export async function handleSkillsInstall( params: GatewayRpcParams['skills.install'], broadcast?: GatewayBroadcast, ): Promise { const request = params as SkillInstallRequest; const installService = new SkillInstallService({ clawHubService: new ClawHubService(), }); try { const result = await installService.install(request); broadcastSkillsRuntimeChanged( broadcast, `skills:install:${result.source}:${result.slug}`, ); return result; } catch (error) { if (error instanceof SkillInstallServiceError) { throw new Error(error.message); } throw error instanceof Error ? error : new Error(String(error)); } }