diff --git a/src/app/api/skills/route.ts b/src/app/api/skills/route.ts index 6033d73..082ee94 100644 --- a/src/app/api/skills/route.ts +++ b/src/app/api/skills/route.ts @@ -94,6 +94,22 @@ function getSkillRoots(): SkillRoot[] { const workspaceSkills = resolveSkillRoot('MC_SKILLS_WORKSPACE_DIR', join(workspaceDir, 'skills')) roots.push({ source: 'workspace', path: workspaceSkills }) + // Dynamic: scan for workspace- directories + try { + const { readdirSync, existsSync } = require('node:fs') as typeof import('node:fs') + const entries = readdirSync(openclawState) as string[] + for (const entry of entries) { + if (!entry.startsWith('workspace-')) continue + const skillsDir = join(openclawState, entry, 'skills') + if (existsSync(skillsDir)) { + const agentName = entry.replace('workspace-', '') + roots.push({ source: `workspace-${agentName}`, path: skillsDir }) + } + } + } catch { + // openclawBase may not exist + } + return roots } @@ -259,6 +275,10 @@ export async function GET(request: NextRequest) { groupMap.set(root.source, { source: root.source, path: root.path, skills: [] }) } for (const skill of dbSkills) { + // Dynamically add workspace-* groups not already in roots + if (!groupMap.has(skill.source) && skill.source.startsWith('workspace-')) { + groupMap.set(skill.source, { source: skill.source, path: '', skills: [] }) + } const group = groupMap.get(skill.source) if (group) group.skills.push(skill) } diff --git a/src/components/panels/skills-panel.tsx b/src/components/panels/skills-panel.tsx index 71f94ac..f706202 100644 --- a/src/components/panels/skills-panel.tsx +++ b/src/components/panels/skills-panel.tsx @@ -59,6 +59,15 @@ const SOURCE_LABELS: Record = { 'workspace': '~/.openclaw/workspace/skills', } +function getSourceLabel(source: string): string { + if (SOURCE_LABELS[source]) return SOURCE_LABELS[source] + if (source.startsWith('workspace-')) { + const agentName = source.replace('workspace-', '') + return `${agentName} workspace` + } + return source +} + export function SkillsPanel() { const t = useTranslations('skills') const { dashboardMode, skillsList, skillGroups, skillsTotal, setSkillsData } = useMissionControl() @@ -552,17 +561,19 @@ export function SkillsPanel() { {t('showAllRoots')} )} - {(skillGroups || []).filter(g => g.skills.length > 0 || ['user-agents', 'user-codex', 'openclaw', 'workspace'].includes(g.source)).map((group) => ( + {(skillGroups || []).filter(g => g.skills.length > 0 || ['user-agents', 'user-codex', 'openclaw', 'workspace'].includes(g.source) || g.source.startsWith('workspace-')).map((group) => ( @@ -593,11 +604,13 @@ export function SkillsPanel() { - {SOURCE_LABELS[skill.source] || skill.source} + {getSourceLabel(skill.source)}