@claude-collective/cli 0.13.2 → 0.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +18 -17
- package/dist/{chunk-LE6IY6IT.js → chunk-4K4ZXQRM.js} +8 -4
- package/dist/chunk-4K4ZXQRM.js.map +1 -0
- package/dist/{chunk-ORVG4P2D.js → chunk-7Q44DMSP.js} +4 -4
- package/dist/{chunk-SGJ23HIP.js → chunk-IAUAQJQ2.js} +2 -2
- package/dist/{chunk-57Y5RALO.js → chunk-IBE7JIAG.js} +3 -3
- package/dist/{chunk-SWZXWQ6I.js → chunk-K3NB6DSG.js} +11 -16
- package/dist/{chunk-SWZXWQ6I.js.map → chunk-K3NB6DSG.js.map} +1 -1
- package/dist/{chunk-CPZOTVCI.js → chunk-RFTSZDHV.js} +29 -24
- package/dist/chunk-RFTSZDHV.js.map +1 -0
- package/dist/{chunk-CJEHB4TB.js → chunk-ZFPSUQOU.js} +28 -2
- package/dist/{chunk-CJEHB4TB.js.map → chunk-ZFPSUQOU.js.map} +1 -1
- package/dist/commands/compile.js +3 -3
- package/dist/commands/diff.js +1 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/edit.js +10 -10
- package/dist/commands/eject.js +1 -1
- package/dist/commands/info.js +1 -1
- package/dist/commands/init.js +8 -8
- package/dist/commands/list.js +3 -3
- package/dist/commands/outdated.js +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/test-imports.js +4 -4
- package/dist/commands/update.js +3 -3
- package/dist/components/wizard/step-build.js +2 -2
- package/dist/components/wizard/step-build.test.js +2 -2
- package/dist/components/wizard/wizard.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-CPZOTVCI.js.map +0 -1
- package/dist/chunk-LE6IY6IT.js.map +0 -1
- /package/dist/{chunk-ORVG4P2D.js.map → chunk-7Q44DMSP.js.map} +0 -0
- /package/dist/{chunk-SGJ23HIP.js.map → chunk-IAUAQJQ2.js.map} +0 -0
- /package/dist/{chunk-57Y5RALO.js.map → chunk-IBE7JIAG.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.13.4] - 2026-02-06
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **local skills lose category metadata** - Local skills from `.claude/skills/` were hardcoded to `category: "local/custom"`, destroying their original category (e.g., `"framework"`, `"styling"`). This broke framework pre-selection in the wizard's Build step and domain filtering. Now preserves the original category from `metadata.yaml` when it matches a matrix category, and carries forward aliases and relationships from source skills.
|
|
13
|
+
|
|
14
|
+
## [0.13.3] - 2026-02-06
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **local config not found during recompile** - `recompileAgents` only looked for config in the plugin directory, missing local mode configs in the project directory. now falls back to project directory when plugin dir has no config
|
|
19
|
+
- **agent_skills normalization** - `agent_skills` from project config was passed to the compiler without normalizing mixed formats (string arrays vs object maps), causing compilation failures
|
|
20
|
+
|
|
8
21
|
## [0.13.2] - 2026-02-06
|
|
9
22
|
|
|
10
23
|
### Fixed
|
|
@@ -42,6 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
42
55
|
|
|
43
56
|
- Old `search.ts` command - Replaced with dual-mode `search.tsx` (static + interactive)
|
|
44
57
|
|
|
58
|
+
[0.13.4]: https://github.com/claude-collective/cli/releases/tag/v0.13.4
|
|
59
|
+
[0.13.3]: https://github.com/claude-collective/cli/releases/tag/v0.13.3
|
|
45
60
|
[0.13.2]: https://github.com/claude-collective/cli/releases/tag/v0.13.2
|
|
46
61
|
[0.13.1]: https://github.com/claude-collective/cli/releases/tag/v0.13.1
|
|
47
62
|
[0.13.0]: https://github.com/claude-collective/cli/releases/tag/v0.13.0
|
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ cc config # manage settings
|
|
|
40
40
|
cc validate # check your setup is correct
|
|
41
41
|
cc new skill # create a custom skill
|
|
42
42
|
cc new agent # create a custom agent
|
|
43
|
+
cc import skill # import a skill from a remote source
|
|
43
44
|
cc update # update local skills from source
|
|
44
45
|
cc uninstall # remove Claude Collective from project
|
|
45
46
|
cc doctor # diagnose setup issues
|
|
@@ -60,29 +61,29 @@ a skill is focused knowledge for one technology. not surface-level docs but actu
|
|
|
60
61
|
|
|
61
62
|
skills live in the [claude-collective/skills](https://github.com/claude-collective/skills) repository, organized by category:
|
|
62
63
|
|
|
63
|
-
| category | what's there
|
|
64
|
-
| -------- |
|
|
65
|
-
| web | react
|
|
66
|
-
| api | hono, drizzle, better-auth, posthog, resend, axiom+pino+sentry
|
|
67
|
-
| mobile | react-native, expo
|
|
68
|
-
| cli | oclif, ink
|
|
69
|
-
| infra | turborepo,
|
|
70
|
-
|
|
|
71
|
-
| meta | code reviewing, research methodology |
|
|
64
|
+
| category | what's there |
|
|
65
|
+
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
+
| web | react, vue, angular, solidjs, next.js, remix, nuxt, scss-modules, cva, zustand, pinia, ngrx-signalstore, jotai, react-query, swr, trpc, graphql, react-hook-form, zod, shadcn-ui, radix-ui, tanstack-table, vitest, playwright, cypress, msw, framer-motion, storybook, accessibility |
|
|
67
|
+
| api | hono, express, fastify, drizzle, prisma, better-auth, posthog, resend, axiom+pino+sentry, github-actions |
|
|
68
|
+
| mobile | react-native, expo |
|
|
69
|
+
| cli | commander, oclif, yargs, clack, inquirer, ink |
|
|
70
|
+
| infra | turborepo, tooling, env config |
|
|
71
|
+
| meta | code reviewing, research methodology, investigation requirements, anti-over-engineering, context management |
|
|
72
72
|
|
|
73
73
|
## stacks
|
|
74
74
|
|
|
75
75
|
stacks bundle skills together with pre-configured agents. instead of picking 20 skills individually, grab a stack that matches your setup:
|
|
76
76
|
|
|
77
|
-
- **nextjs-fullstack** - next.js
|
|
78
|
-
- **
|
|
79
|
-
- **vue-stack** - vue 3 +
|
|
80
|
-
- **
|
|
81
|
-
- **remix-stack** - remix
|
|
82
|
-
- **solidjs-stack** - solidjs
|
|
83
|
-
- **
|
|
77
|
+
- **nextjs-fullstack** - next.js + react + hono + drizzle + posthog + zustand + react-query
|
|
78
|
+
- **angular-stack** - angular 19 + signals + ngrx signalstore + hono + drizzle
|
|
79
|
+
- **vue-stack** - vue 3 composition API + pinia + hono + drizzle
|
|
80
|
+
- **nuxt-stack** - nuxt + vue 3 full-stack + pinia + hono + drizzle
|
|
81
|
+
- **remix-stack** - remix + react + hono + drizzle
|
|
82
|
+
- **solidjs-stack** - solidjs + hono + drizzle
|
|
83
|
+
- **react-native-stack** - react native + expo + zustand + react-query
|
|
84
|
+
- **meta-stack** - agents for creating agents, skills, docs, and extracting patterns
|
|
84
85
|
|
|
85
|
-
each stack includes agents like `web-developer`, `api-reviewer`, `web-tester` - roles that use the right skills for the job.
|
|
86
|
+
each stack includes agents like `web-developer`, `api-developer`, `web-reviewer`, `web-tester`, `web-researcher`, `pattern-scout`, `documentor` - roles that use the right skills for the job.
|
|
86
87
|
|
|
87
88
|
## installation options
|
|
88
89
|
|
|
@@ -13,8 +13,9 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
isLegacyStackConfig,
|
|
15
15
|
loadProjectConfig,
|
|
16
|
+
normalizeAgentSkills,
|
|
16
17
|
normalizeStackConfig
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-ZFPSUQOU.js";
|
|
18
19
|
import {
|
|
19
20
|
loadAllAgents,
|
|
20
21
|
loadPluginSkills,
|
|
@@ -154,7 +155,7 @@ function projectConfigToStackLike(config) {
|
|
|
154
155
|
description: config.description,
|
|
155
156
|
skills: config.skills?.map((s) => typeof s === "string" ? { id: s } : s) ?? [],
|
|
156
157
|
agents: config.agents,
|
|
157
|
-
agent_skills: config.agent_skills,
|
|
158
|
+
agent_skills: config.agent_skills ? normalizeAgentSkills(config.agent_skills) : void 0,
|
|
158
159
|
hooks: config.hooks,
|
|
159
160
|
framework: config.framework,
|
|
160
161
|
philosophy: config.philosophy,
|
|
@@ -176,7 +177,10 @@ async function recompileAgents(options) {
|
|
|
176
177
|
failed: [],
|
|
177
178
|
warnings: []
|
|
178
179
|
};
|
|
179
|
-
|
|
180
|
+
let loadedConfig = await loadConfigWithFallback(pluginDir);
|
|
181
|
+
if (!loadedConfig && projectDir) {
|
|
182
|
+
loadedConfig = await loadConfigWithFallback(projectDir);
|
|
183
|
+
}
|
|
180
184
|
const projectConfig = loadedConfig?.config ?? null;
|
|
181
185
|
const builtinAgents = await loadAllAgents(sourcePath);
|
|
182
186
|
const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};
|
|
@@ -310,4 +314,4 @@ async function recompileAgents(options) {
|
|
|
310
314
|
export {
|
|
311
315
|
recompileAgents
|
|
312
316
|
};
|
|
313
|
-
//# sourceMappingURL=chunk-
|
|
317
|
+
//# sourceMappingURL=chunk-4K4ZXQRM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/agent-recompiler.ts","../src/cli/lib/custom-agent-resolver.ts"],"sourcesContent":["import path from \"path\";\nimport { glob, writeFile, ensureDir, readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { loadAllAgents, loadPluginSkills, loadProjectAgents } from \"./loader\";\nimport { resolveAgents, resolveStackSkills } from \"./resolver\";\nimport { compileAgentForPlugin } from \"./stack-plugin-compiler\";\nimport { getPluginAgentsDir } from \"./plugin-finder\";\nimport { createLiquidEngine } from \"./compiler\";\nimport {\n loadProjectConfig,\n isLegacyStackConfig,\n normalizeStackConfig,\n normalizeAgentSkills,\n type LoadedProjectConfig,\n} from \"./project-config\";\nimport {\n resolveCustomAgents,\n validateCustomAgentIds,\n} from \"./custom-agent-resolver\";\nimport { parse as parseYaml } from \"yaml\";\nimport type {\n CompileConfig,\n CompileAgentConfig,\n StackConfig,\n SkillReference,\n SkillDefinition,\n ProjectConfig,\n AgentDefinition,\n} from \"../../types\";\n\nexport interface RecompileAgentsOptions {\n pluginDir: string;\n sourcePath: string;\n agents?: string[];\n skills?: Record<string, SkillDefinition>;\n projectDir?: string;\n outputDir?: string;\n}\n\nexport interface RecompileAgentsResult {\n compiled: string[];\n failed: string[];\n warnings: string[];\n}\n\nasync function getExistingAgentNames(pluginDir: string): Promise<string[]> {\n const agentsDir = getPluginAgentsDir(pluginDir);\n const files = await glob(\"*.md\", agentsDir);\n return files.map((f) => path.basename(f, \".md\"));\n}\n\n/**\n * Load config from either:\n * 1. pluginDir/config.yaml (legacy plugin location)\n * 2. pluginDir/.claude/config.yaml (new project config location)\n *\n * This provides backward compatibility with existing plugins.\n */\nasync function loadConfigWithFallback(\n pluginDir: string,\n): Promise<LoadedProjectConfig | null> {\n // First try the legacy plugin location (pluginDir/config.yaml)\n const legacyConfigPath = path.join(pluginDir, \"config.yaml\");\n if (await fileExists(legacyConfigPath)) {\n try {\n const content = await readFile(legacyConfigPath);\n const parsed = parseYaml(content);\n\n if (parsed && typeof parsed === \"object\") {\n verbose(`Loaded config.yaml from ${legacyConfigPath}`);\n\n // Check if it's legacy StackConfig format\n if (isLegacyStackConfig(parsed)) {\n const normalized = normalizeStackConfig(parsed as StackConfig);\n return {\n config: normalized,\n configPath: legacyConfigPath,\n isLegacy: true,\n };\n }\n\n return {\n config: parsed as ProjectConfig,\n configPath: legacyConfigPath,\n isLegacy: false,\n };\n }\n } catch (error) {\n verbose(`Failed to parse config.yaml: ${error}`);\n }\n }\n\n // Fall back to project config location (.claude/config.yaml)\n return loadProjectConfig(pluginDir);\n}\n\n/**\n * Convert ProjectConfig to StackConfig-like structure for compatibility\n * with existing resolveStackSkills function\n */\nfunction projectConfigToStackLike(config: ProjectConfig): StackConfig {\n return {\n name: config.name,\n version: \"1.0.0\",\n author: config.author ?? \"@unknown\",\n description: config.description,\n skills:\n config.skills?.map((s) => (typeof s === \"string\" ? { id: s } : s)) ?? [],\n agents: config.agents,\n agent_skills: config.agent_skills\n ? normalizeAgentSkills(config.agent_skills)\n : undefined,\n hooks: config.hooks,\n framework: config.framework,\n philosophy: config.philosophy,\n principles: config.principles,\n tags: config.tags,\n };\n}\n\nexport async function recompileAgents(\n options: RecompileAgentsOptions,\n): Promise<RecompileAgentsResult> {\n const {\n pluginDir,\n sourcePath,\n agents: specifiedAgents,\n skills: providedSkills,\n projectDir,\n outputDir,\n } = options;\n\n const result: RecompileAgentsResult = {\n compiled: [],\n failed: [],\n warnings: [],\n };\n\n // Load project config (handles both legacy plugin config and new ProjectConfig)\n // Try plugin dir first, then fall back to project dir for local mode\n let loadedConfig = await loadConfigWithFallback(pluginDir);\n if (!loadedConfig && projectDir) {\n loadedConfig = await loadConfigWithFallback(projectDir);\n }\n const projectConfig = loadedConfig?.config ?? null;\n\n // Load built-in agents from source\n const builtinAgents = await loadAllAgents(sourcePath);\n\n // Load project agents from .claude-src/agents/ (if projectDir provided)\n const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};\n\n // Resolve custom agents and merge with built-in agents\n // Priority: custom_agents > project agents > built-in agents\n let allAgents: Record<string, AgentDefinition> = {\n ...builtinAgents,\n ...projectAgents,\n };\n if (projectConfig?.custom_agents) {\n // Validate custom agent IDs don't conflict with built-in agents\n const idConflicts = validateCustomAgentIds(\n projectConfig.custom_agents,\n builtinAgents,\n );\n if (idConflicts.length > 0) {\n for (const error of idConflicts) {\n result.warnings.push(error);\n }\n }\n\n // Resolve custom agents to AgentDefinition\n try {\n const resolvedCustomAgents = resolveCustomAgents(\n projectConfig.custom_agents,\n builtinAgents,\n );\n // Merge: custom agents can override built-in if same name (though we warn above)\n allAgents = { ...builtinAgents, ...resolvedCustomAgents };\n verbose(\n `Resolved ${Object.keys(resolvedCustomAgents).length} custom agents`,\n );\n } catch (error) {\n result.warnings.push(\n `Failed to resolve custom agents: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // Convert to StackConfig-like for compatibility with existing functions\n const pluginConfig = projectConfig\n ? projectConfigToStackLike(projectConfig)\n : null;\n\n let agentNames: string[];\n if (specifiedAgents) {\n agentNames = specifiedAgents;\n } else if (pluginConfig?.agents) {\n agentNames = pluginConfig.agents;\n verbose(`Using agents from config.yaml: ${agentNames.join(\", \")}`);\n } else if (outputDir) {\n agentNames = Object.keys(allAgents);\n verbose(`Using all available agents from source: ${agentNames.join(\", \")}`);\n } else {\n agentNames = await getExistingAgentNames(pluginDir);\n }\n\n if (agentNames.length === 0) {\n result.warnings.push(\"No agents found to recompile\");\n return result;\n }\n\n verbose(\n `Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`,\n );\n\n const pluginSkills = providedSkills ?? (await loadPluginSkills(pluginDir));\n\n const compileAgents: Record<string, CompileAgentConfig> = {};\n for (const agentName of agentNames) {\n if (allAgents[agentName]) {\n // Check if this is a custom agent with its own skills defined\n const customAgentConfig = projectConfig?.custom_agents?.[agentName];\n if (customAgentConfig?.skills && customAgentConfig.skills.length > 0) {\n // Custom agent has explicit skills defined\n const skillRefs: SkillReference[] = customAgentConfig.skills.map(\n (s) => ({\n id: typeof s === \"string\" ? s : s.id,\n usage: `when working with ${(typeof s === \"string\" ? s : s.id).split(\" \")[0]}`,\n preloaded:\n (typeof s === \"object\" && \"preloaded\" in s && s.preloaded) ??\n false,\n }),\n );\n compileAgents[agentName] = { skills: skillRefs };\n verbose(\n ` Agent ${agentName}: ${skillRefs.length} skills from custom_agents`,\n );\n } else if (pluginConfig?.agent_skills?.[agentName]) {\n const skillRefs = resolveStackSkills(\n pluginConfig,\n agentName,\n pluginSkills,\n );\n compileAgents[agentName] = { skills: skillRefs };\n verbose(` Agent ${agentName}: ${skillRefs.length} skills from config`);\n } else if (pluginConfig?.skills) {\n // Fall back to all skills in the config\n const skillRefs: SkillReference[] = pluginConfig.skills.map((s) => ({\n id: s.id,\n usage: `when working with ${s.id.split(\" \")[0]}`,\n preloaded: s.preloaded ?? false,\n }));\n compileAgents[agentName] = { skills: skillRefs };\n verbose(` Agent ${agentName}: ${skillRefs.length} skills (all)`);\n } else {\n compileAgents[agentName] = {};\n }\n } else {\n result.warnings.push(\n `Agent \"${agentName}\" not found in source definitions`,\n );\n }\n }\n\n const compileConfig: CompileConfig = {\n name: pluginConfig?.name || path.basename(pluginDir),\n description: pluginConfig?.description || \"Recompiled plugin\",\n claude_md: \"\",\n agents: compileAgents,\n };\n\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(\n allAgents,\n pluginSkills,\n compileConfig,\n sourcePath,\n );\n\n const agentsDir = outputDir ?? getPluginAgentsDir(pluginDir);\n await ensureDir(agentsDir);\n\n for (const [name, agent] of Object.entries(resolvedAgents)) {\n try {\n const output = await compileAgentForPlugin(\n name,\n agent,\n sourcePath,\n engine,\n );\n await writeFile(path.join(agentsDir, `${name}.md`), output);\n result.compiled.push(name);\n verbose(` Recompiled: ${name}`);\n } catch (error) {\n result.failed.push(name);\n result.warnings.push(\n `Failed to compile ${name}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n return result;\n}\n","import type { CustomAgentConfig, AgentDefinition } from \"../../types\";\n\n/** Default tools for standalone custom agents (no extends) */\nconst DEFAULT_TOOLS = [\"Read\", \"Grep\", \"Glob\"];\n\n/** Marker path for standalone custom agents (no extends) */\nconst CUSTOM_AGENT_PATH = \"_custom\";\n\n/**\n * Resolve a custom agent config to a full AgentDefinition.\n * If extends is specified, inherit from the base agent.\n *\n * @param agentId - The custom agent's identifier\n * @param customConfig - The custom agent configuration from config.yaml\n * @param builtinAgents - Record of built-in agent definitions to extend from\n * @returns Fully resolved AgentDefinition\n * @throws Error if extends references an unknown agent\n */\nexport function resolveCustomAgent(\n agentId: string,\n customConfig: CustomAgentConfig,\n builtinAgents: Record<string, AgentDefinition>,\n): AgentDefinition {\n let baseAgent: Partial<AgentDefinition> = {};\n\n if (customConfig.extends) {\n const base = builtinAgents[customConfig.extends];\n if (!base) {\n const availableAgents = Object.keys(builtinAgents);\n const agentList =\n availableAgents.length > 0\n ? `Available agents: ${availableAgents.slice(0, 5).join(\", \")}${availableAgents.length > 5 ? ` (and ${availableAgents.length - 5} more)` : \"\"}`\n : \"No built-in agents found\";\n throw new Error(\n `Custom agent \"${agentId}\" extends unknown agent \"${customConfig.extends}\". ${agentList}`,\n );\n }\n baseAgent = { ...base };\n }\n\n // Merge disallowed_tools: custom + inherited\n let disallowedTools: string[] | undefined;\n if (customConfig.disallowed_tools || baseAgent.disallowed_tools) {\n const merged = new Set<string>([\n ...(baseAgent.disallowed_tools || []),\n ...(customConfig.disallowed_tools || []),\n ]);\n disallowedTools = [...merged];\n }\n\n // Merge hooks: custom hooks added to inherited\n let hooks: AgentDefinition[\"hooks\"] | undefined;\n if (customConfig.hooks || baseAgent.hooks) {\n hooks = { ...baseAgent.hooks };\n if (customConfig.hooks) {\n for (const [hookType, hookDefs] of Object.entries(customConfig.hooks)) {\n if (hooks[hookType]) {\n hooks[hookType] = [...hooks[hookType], ...hookDefs];\n } else {\n hooks[hookType] = hookDefs;\n }\n }\n }\n }\n\n return {\n title: customConfig.title,\n description: customConfig.description,\n model: customConfig.model || baseAgent.model,\n tools: customConfig.tools || baseAgent.tools || DEFAULT_TOOLS,\n disallowed_tools: disallowedTools,\n permission_mode: customConfig.permission_mode || baseAgent.permission_mode,\n hooks,\n // Use extended agent's path for template resolution, or _custom for standalone\n path: baseAgent.path || CUSTOM_AGENT_PATH,\n sourceRoot: baseAgent.sourceRoot,\n };\n}\n\n/**\n * Resolve all custom agents from config to AgentDefinition records.\n *\n * @param customAgents - Record of custom agent configs from config.yaml\n * @param builtinAgents - Record of built-in agent definitions\n * @returns Record of resolved AgentDefinitions keyed by custom agent ID\n */\nexport function resolveCustomAgents(\n customAgents: Record<string, CustomAgentConfig>,\n builtinAgents: Record<string, AgentDefinition>,\n): Record<string, AgentDefinition> {\n const resolved: Record<string, AgentDefinition> = {};\n\n for (const [id, config] of Object.entries(customAgents)) {\n resolved[id] = resolveCustomAgent(id, config, builtinAgents);\n }\n\n return resolved;\n}\n\n/**\n * Check if a custom agent ID conflicts with a built-in agent ID.\n *\n * @param customAgentId - The custom agent's identifier\n * @param builtinAgents - Record of built-in agent definitions\n * @returns true if there's a conflict\n */\nexport function hasAgentIdConflict(\n customAgentId: string,\n builtinAgents: Record<string, AgentDefinition>,\n): boolean {\n return customAgentId in builtinAgents;\n}\n\n/**\n * Validate custom agents don't conflict with built-in agents.\n *\n * @param customAgents - Record of custom agent configs\n * @param builtinAgents - Record of built-in agent definitions\n * @returns Array of error messages (empty if no conflicts)\n */\nexport function validateCustomAgentIds(\n customAgents: Record<string, CustomAgentConfig>,\n builtinAgents: Record<string, AgentDefinition>,\n): string[] {\n const errors: string[] = [];\n\n for (const customId of Object.keys(customAgents)) {\n if (hasAgentIdConflict(customId, builtinAgents)) {\n errors.push(\n `Custom agent \"${customId}\" conflicts with built-in agent of the same name. Choose a unique name.`,\n );\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
WizardFooter
|
|
4
|
-
} from "./chunk-Y2LW7R3Y.js";
|
|
5
2
|
import {
|
|
6
3
|
CategoryGrid
|
|
7
4
|
} from "./chunk-Z7G4B5HJ.js";
|
|
8
5
|
import {
|
|
9
6
|
SectionProgress
|
|
10
7
|
} from "./chunk-BDLUZVKU.js";
|
|
8
|
+
import {
|
|
9
|
+
WizardFooter
|
|
10
|
+
} from "./chunk-Y2LW7R3Y.js";
|
|
11
11
|
import {
|
|
12
12
|
init_esm_shims
|
|
13
13
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -579,4 +579,4 @@ export {
|
|
|
579
579
|
getDisplayLabel,
|
|
580
580
|
StepBuild
|
|
581
581
|
};
|
|
582
|
-
//# sourceMappingURL=chunk-
|
|
582
|
+
//# sourceMappingURL=chunk-7Q44DMSP.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-ED4E6Q2T.js";
|
|
5
5
|
import {
|
|
6
6
|
loadProjectConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZFPSUQOU.js";
|
|
8
8
|
import {
|
|
9
9
|
directoryExists,
|
|
10
10
|
fileExists
|
|
@@ -54,4 +54,4 @@ async function detectInstallation(projectDir = process.cwd()) {
|
|
|
54
54
|
export {
|
|
55
55
|
detectInstallation
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-IAUAQJQ2.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
detectInstallation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IAUAQJQ2.js";
|
|
5
5
|
import {
|
|
6
6
|
getCollectivePluginDir,
|
|
7
7
|
getPluginAgentsDir,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-ED4E6Q2T.js";
|
|
11
11
|
import {
|
|
12
12
|
loadProjectConfig
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZFPSUQOU.js";
|
|
14
14
|
import {
|
|
15
15
|
directoryExists
|
|
16
16
|
} from "./chunk-TKFPKEV3.js";
|
|
@@ -126,4 +126,4 @@ export {
|
|
|
126
126
|
getInstallationInfo,
|
|
127
127
|
formatInstallationDisplay
|
|
128
128
|
};
|
|
129
|
-
//# sourceMappingURL=chunk-
|
|
129
|
+
//# sourceMappingURL=chunk-IBE7JIAG.js.map
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
StepRefine
|
|
4
|
+
} from "./chunk-E3FJH4TF.js";
|
|
5
|
+
import {
|
|
6
|
+
StepStackOptions
|
|
7
|
+
} from "./chunk-HLJX2FTL.js";
|
|
8
|
+
import {
|
|
9
|
+
StepStack
|
|
10
|
+
} from "./chunk-CDX4W4DM.js";
|
|
2
11
|
import {
|
|
3
12
|
WIZARD_STEPS,
|
|
4
13
|
WizardTabs
|
|
@@ -9,19 +18,10 @@ import {
|
|
|
9
18
|
import {
|
|
10
19
|
StepBuild,
|
|
11
20
|
validateSelection
|
|
12
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-7Q44DMSP.js";
|
|
13
22
|
import {
|
|
14
23
|
StepConfirm
|
|
15
24
|
} from "./chunk-X6QONICW.js";
|
|
16
|
-
import {
|
|
17
|
-
StepRefine
|
|
18
|
-
} from "./chunk-E3FJH4TF.js";
|
|
19
|
-
import {
|
|
20
|
-
StepStackOptions
|
|
21
|
-
} from "./chunk-HLJX2FTL.js";
|
|
22
|
-
import {
|
|
23
|
-
StepStack
|
|
24
|
-
} from "./chunk-CDX4W4DM.js";
|
|
25
25
|
import {
|
|
26
26
|
useWizardStore
|
|
27
27
|
} from "./chunk-D237EVNB.js";
|
|
@@ -148,11 +148,6 @@ var Wizard = ({
|
|
|
148
148
|
const currentDomain = store.getCurrentDomain();
|
|
149
149
|
const effectiveDomains = store.selectedDomains.length > 0 ? store.selectedDomains : ["web"];
|
|
150
150
|
const allSelections = store.getAllSelectedTechnologies();
|
|
151
|
-
console.log("DEBUG allSelections for Build step:", allSelections);
|
|
152
|
-
console.log(
|
|
153
|
-
"DEBUG store.domainSelections:",
|
|
154
|
-
JSON.stringify(store.domainSelections, null, 2)
|
|
155
|
-
);
|
|
156
151
|
return /* @__PURE__ */ jsx(
|
|
157
152
|
StepBuild,
|
|
158
153
|
{
|
|
@@ -261,4 +256,4 @@ var Wizard = ({
|
|
|
261
256
|
export {
|
|
262
257
|
Wizard
|
|
263
258
|
};
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
259
|
+
//# sourceMappingURL=chunk-K3NB6DSG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/wizard/wizard.tsx"],"sourcesContent":["/**\n * Wizard component - Main orchestrator for the skill selection wizard.\n *\n * V2 Flow:\n * - approach: Choose stack template or build from scratch\n * - stack: Select pre-built stack (stack path) OR domains (scratch path)\n * - stack-options: Continue defaults or customize (stack path only)\n * - build: CategoryGrid for technology selection\n * - refine: Skill source selection\n * - confirm: Final confirmation\n *\n * Navigation:\n * - ESC goes back through history\n * - ESC at approach cancels wizard\n * - Ctrl+C cancels at any point\n */\nimport React, { useCallback, useMemo } from \"react\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport { ThemeProvider } from \"@inkjs/ui\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { cliTheme } from \"../themes/default.js\";\nimport { WizardTabs, WIZARD_STEPS } from \"./wizard-tabs.js\";\nimport { StepApproach } from \"./step-approach.js\";\nimport { StepStack } from \"./step-stack.js\";\nimport { StepStackOptions } from \"./step-stack-options.js\";\nimport { StepBuild } from \"./step-build.js\";\nimport { StepRefine } from \"./step-refine.js\";\nimport { StepConfirm } from \"./step-confirm.js\";\nimport { validateSelection } from \"../../lib/matrix-resolver.js\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface WizardResultV2 {\n selectedSkills: string[];\n selectedStackId: string | null;\n domainSelections: Record<string, Record<string, string[]>>;\n expertMode: boolean;\n installMode: \"plugin\" | \"local\";\n cancelled: boolean;\n validation: {\n valid: boolean;\n errors: Array<{ message: string }>;\n warnings: Array<{ message: string }>;\n };\n}\n\n/** @deprecated Use WizardResultV2 instead */\nexport interface WizardResult {\n selectedSkills: string[];\n selectedStack: { id: string } | null;\n expertMode: boolean;\n installMode: \"plugin\" | \"local\";\n cancelled: boolean;\n validation: {\n valid: boolean;\n errors: Array<{ message: string }>;\n warnings: Array<{ message: string }>;\n };\n}\n\ninterface WizardProps {\n matrix: MergedSkillsMatrix;\n onComplete: (result: WizardResultV2 | WizardResult) => void;\n onCancel: () => void;\n /** CLI version string to display in header */\n version?: string;\n /** @deprecated Initial skills no longer skip to category */\n initialSkills?: string[];\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Minimum terminal width required for the wizard */\nconst MIN_TERMINAL_WIDTH = 80;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Get display name for a domain.\n */\nfunction getDomainDisplayName(domain: string): string {\n const displayNames: Record<string, string> = {\n web: \"Web\",\n api: \"API\",\n cli: \"CLI\",\n mobile: \"Mobile\",\n shared: \"Shared\",\n };\n return (\n displayNames[domain] || domain.charAt(0).toUpperCase() + domain.slice(1)\n );\n}\n\n/**\n * Get stack name from matrix by stack ID.\n */\nfunction getStackName(\n stackId: string | null,\n matrix: MergedSkillsMatrix,\n): string | undefined {\n if (!stackId) return undefined;\n const stack = matrix.suggestedStacks.find((s) => s.id === stackId);\n return stack?.name;\n}\n\n/**\n * Count technologies in a stack.\n */\nfunction getStackTechnologyCount(\n stackId: string | null,\n matrix: MergedSkillsMatrix,\n): number {\n if (!stackId) return 0;\n const stack = matrix.suggestedStacks.find((s) => s.id === stackId);\n if (!stack) return 0;\n return stack.allSkillIds.length;\n}\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const Wizard: React.FC<WizardProps> = ({\n matrix,\n onComplete,\n onCancel,\n version,\n}) => {\n const store = useWizardStore();\n const { exit } = useApp();\n const { stdout } = useStdout();\n\n // Check terminal width\n const terminalWidth = stdout.columns || MIN_TERMINAL_WIDTH;\n const isNarrowTerminal = terminalWidth < MIN_TERMINAL_WIDTH;\n\n // Compute completed and skipped steps for WizardTabs\n const { completedSteps, skippedSteps } = useMemo(() => {\n const completed: string[] = [];\n const skipped: string[] = [];\n\n // Approach is complete when we've moved past it\n if (store.step !== \"approach\") {\n completed.push(\"approach\");\n }\n\n // Stack step handling\n if (\n store.step !== \"approach\" &&\n store.step !== \"stack\" &&\n store.step !== \"stack-options\"\n ) {\n completed.push(\"stack\");\n }\n\n // Build step handling\n // Stack path with defaults skips build\n if (\n store.approach === \"stack\" &&\n store.selectedStackId &&\n store.stackAction === \"defaults\"\n ) {\n skipped.push(\"build\");\n } else if (store.step === \"refine\" || store.step === \"confirm\") {\n completed.push(\"build\");\n }\n\n // Refine step\n if (store.step === \"confirm\") {\n completed.push(\"refine\");\n }\n\n return { completedSteps: completed, skippedSteps: skipped };\n }, [store.step, store.approach, store.selectedStackId, store.stackAction]);\n\n // Global escape handler\n useInput((input, key) => {\n if (key.escape) {\n if (store.step === \"approach\") {\n onCancel();\n exit();\n } else {\n store.goBack();\n }\n }\n });\n\n // Handle wizard completion\n const handleComplete = useCallback(() => {\n let allSkills: string[];\n\n if (store.selectedStackId && store.stackAction === \"defaults\") {\n // Stack + defaults path: use stack's allSkillIds directly\n const stack = matrix.suggestedStacks.find(\n (s) => s.id === store.selectedStackId,\n );\n if (!stack) {\n console.warn(`Stack not found in matrix: ${store.selectedStackId}`);\n }\n allSkills = [...(stack?.allSkillIds || [])];\n } else {\n // Scratch / Customize path: resolve domainSelections via aliases\n const techNames = store.getAllSelectedTechnologies();\n // Resolve each technology name to its full skill ID via aliases\n allSkills = techNames.map((tech) => matrix.aliases[tech] || tech);\n }\n\n // Add methodology skills (always included)\n const methodologySkills = store.getSelectedSkills();\n for (const skill of methodologySkills) {\n if (!allSkills.includes(skill)) {\n allSkills.push(skill);\n }\n }\n\n const validation = validateSelection(allSkills, matrix);\n\n const result: WizardResultV2 = {\n selectedSkills: allSkills,\n selectedStackId: store.selectedStackId,\n domainSelections: store.domainSelections,\n expertMode: store.expertMode,\n installMode: store.installMode,\n cancelled: false,\n validation,\n };\n\n onComplete(result);\n exit();\n }, [store, matrix, onComplete, exit]);\n\n // Render current step\n const renderStep = () => {\n switch (store.step) {\n case \"approach\":\n return <StepApproach />;\n\n case \"stack\":\n return <StepStack matrix={matrix} />;\n\n case \"stack-options\": {\n const stackName =\n getStackName(store.selectedStackId, matrix) || \"Selected Stack\";\n const techCount = getStackTechnologyCount(\n store.selectedStackId,\n matrix,\n );\n return (\n <StepStackOptions\n stackName={stackName}\n technologyCount={techCount}\n matrix={matrix}\n />\n );\n }\n\n case \"build\": {\n const currentDomain = store.getCurrentDomain();\n // For stack path with customize, use all domains from stack\n // For scratch path, use selectedDomains\n const effectiveDomains =\n store.selectedDomains.length > 0 ? store.selectedDomains : [\"web\"]; // Default to web if no domains selected\n\n // DEBUG: trace data flow for pre-selection bug\n const allSelections = store.getAllSelectedTechnologies();\n console.log(\"DEBUG allSelections for Build step:\", allSelections);\n console.log(\n \"DEBUG store.domainSelections:\",\n JSON.stringify(store.domainSelections, null, 2),\n );\n\n return (\n <StepBuild\n matrix={matrix}\n domain={currentDomain || effectiveDomains[0] || \"web\"}\n selectedDomains={effectiveDomains}\n currentDomainIndex={store.currentDomainIndex}\n selections={store.domainSelections[currentDomain || \"web\"] || {}}\n allSelections={allSelections}\n focusedRow={store.focusedRow}\n focusedCol={store.focusedCol}\n showDescriptions={store.showDescriptions}\n expertMode={store.expertMode}\n onToggle={(subcategoryId, techId) => {\n const domain = store.getCurrentDomain() || \"web\";\n const cat = matrix.categories[subcategoryId];\n store.toggleTechnology(\n domain,\n subcategoryId,\n techId,\n cat?.exclusive ?? true,\n );\n }}\n onFocusChange={store.setFocus}\n onToggleDescriptions={store.toggleShowDescriptions}\n onToggleExpertMode={store.toggleExpertMode}\n onContinue={() => {\n if (!store.nextDomain()) {\n store.setStep(\"refine\");\n }\n }}\n onBack={() => {\n if (!store.prevDomain()) {\n store.goBack();\n }\n }}\n />\n );\n }\n\n case \"refine\":\n return (\n <StepRefine\n technologyCount={store.getAllSelectedTechnologies().length}\n refineAction={store.refineAction}\n onSelectAction={store.setRefineAction}\n onContinue={() => store.setStep(\"confirm\")}\n onBack={store.goBack}\n />\n );\n\n case \"confirm\": {\n const stackName = getStackName(store.selectedStackId, matrix);\n return (\n <StepConfirm\n matrix={matrix}\n onComplete={handleComplete}\n stackName={stackName}\n selectedDomains={store.selectedDomains}\n domainSelections={store.domainSelections}\n technologyCount={store.getAllSelectedTechnologies().length}\n skillCount={store.getSelectedSkills().length}\n installMode={store.installMode}\n onBack={store.goBack}\n />\n );\n }\n\n default:\n return null;\n }\n };\n\n // Show warning if terminal is too narrow\n if (isNarrowTerminal) {\n return (\n <ThemeProvider theme={cliTheme}>\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"yellow\">\n Terminal too narrow ({terminalWidth} columns). Please resize to at\n least {MIN_TERMINAL_WIDTH} columns.\n </Text>\n <Box marginTop={1}>\n <Text dimColor>Current width: {terminalWidth} columns</Text>\n </Box>\n </Box>\n </ThemeProvider>\n );\n }\n\n return (\n <ThemeProvider theme={cliTheme}>\n <Box flexDirection=\"column\" padding={1}>\n {/* Header with version */}\n {version && (\n <Box marginBottom={1}>\n <Text dimColor>Claude Collective v{version}</Text>\n </Box>\n )}\n <WizardTabs\n steps={WIZARD_STEPS}\n currentStep={store.step}\n completedSteps={completedSteps}\n skippedSteps={skippedSteps}\n />\n {renderStep()}\n </Box>\n </ThemeProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAgBA,SAAgB,aAAa,eAAe;AAC5C,SAAS,KAAK,MAAM,QAAQ,UAAU,iBAAiB;AACvD,SAAS,qBAAqB;AAgOf,cAiHL,YAjHK;AApKf,IAAM,qBAAqB;AAyB3B,SAAS,aACP,SACA,QACoB;AACpB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,OAAO,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AACjE,SAAO,OAAO;AAChB;AAKA,SAAS,wBACP,SACA,QACQ;AACR,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,OAAO,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AACjE,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,YAAY;AAC3B;AAMO,IAAM,SAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,eAAe;AAC7B,QAAM,EAAE,KAAK,IAAI,OAAO;AACxB,QAAM,EAAE,OAAO,IAAI,UAAU;AAG7B,QAAM,gBAAgB,OAAO,WAAW;AACxC,QAAM,mBAAmB,gBAAgB;AAGzC,QAAM,EAAE,gBAAgB,aAAa,IAAI,QAAQ,MAAM;AACrD,UAAM,YAAsB,CAAC;AAC7B,UAAM,UAAoB,CAAC;AAG3B,QAAI,MAAM,SAAS,YAAY;AAC7B,gBAAU,KAAK,UAAU;AAAA,IAC3B;AAGA,QACE,MAAM,SAAS,cACf,MAAM,SAAS,WACf,MAAM,SAAS,iBACf;AACA,gBAAU,KAAK,OAAO;AAAA,IACxB;AAIA,QACE,MAAM,aAAa,WACnB,MAAM,mBACN,MAAM,gBAAgB,YACtB;AACA,cAAQ,KAAK,OAAO;AAAA,IACtB,WAAW,MAAM,SAAS,YAAY,MAAM,SAAS,WAAW;AAC9D,gBAAU,KAAK,OAAO;AAAA,IACxB;AAGA,QAAI,MAAM,SAAS,WAAW;AAC5B,gBAAU,KAAK,QAAQ;AAAA,IACzB;AAEA,WAAO,EAAE,gBAAgB,WAAW,cAAc,QAAQ;AAAA,EAC5D,GAAG,CAAC,MAAM,MAAM,MAAM,UAAU,MAAM,iBAAiB,MAAM,WAAW,CAAC;AAGzE,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ;AACd,UAAI,MAAM,SAAS,YAAY;AAC7B,iBAAS;AACT,aAAK;AAAA,MACP,OAAO;AACL,cAAM,OAAO;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AAGD,QAAM,iBAAiB,YAAY,MAAM;AACvC,QAAI;AAEJ,QAAI,MAAM,mBAAmB,MAAM,gBAAgB,YAAY;AAE7D,YAAM,QAAQ,OAAO,gBAAgB;AAAA,QACnC,CAAC,MAAM,EAAE,OAAO,MAAM;AAAA,MACxB;AACA,UAAI,CAAC,OAAO;AACV,gBAAQ,KAAK,8BAA8B,MAAM,eAAe,EAAE;AAAA,MACpE;AACA,kBAAY,CAAC,GAAI,OAAO,eAAe,CAAC,CAAE;AAAA,IAC5C,OAAO;AAEL,YAAM,YAAY,MAAM,2BAA2B;AAEnD,kBAAY,UAAU,IAAI,CAAC,SAAS,OAAO,QAAQ,IAAI,KAAK,IAAI;AAAA,IAClE;AAGA,UAAM,oBAAoB,MAAM,kBAAkB;AAClD,eAAW,SAAS,mBAAmB;AACrC,UAAI,CAAC,UAAU,SAAS,KAAK,GAAG;AAC9B,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,aAAa,kBAAkB,WAAW,MAAM;AAEtD,UAAM,SAAyB;AAAA,MAC7B,gBAAgB;AAAA,MAChB,iBAAiB,MAAM;AAAA,MACvB,kBAAkB,MAAM;AAAA,MACxB,YAAY,MAAM;AAAA,MAClB,aAAa,MAAM;AAAA,MACnB,WAAW;AAAA,MACX;AAAA,IACF;AAEA,eAAW,MAAM;AACjB,SAAK;AAAA,EACP,GAAG,CAAC,OAAO,QAAQ,YAAY,IAAI,CAAC;AAGpC,QAAM,aAAa,MAAM;AACvB,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,oBAAC,gBAAa;AAAA,MAEvB,KAAK;AACH,eAAO,oBAAC,aAAU,QAAgB;AAAA,MAEpC,KAAK,iBAAiB;AACpB,cAAM,YACJ,aAAa,MAAM,iBAAiB,MAAM,KAAK;AACjD,cAAM,YAAY;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,QACF;AACA,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,iBAAiB;AAAA,YACjB;AAAA;AAAA,QACF;AAAA,MAEJ;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,gBAAgB,MAAM,iBAAiB;AAG7C,cAAM,mBACJ,MAAM,gBAAgB,SAAS,IAAI,MAAM,kBAAkB,CAAC,KAAK;AAGnE,cAAM,gBAAgB,MAAM,2BAA2B;AACvD,gBAAQ,IAAI,uCAAuC,aAAa;AAChE,gBAAQ;AAAA,UACN;AAAA,UACA,KAAK,UAAU,MAAM,kBAAkB,MAAM,CAAC;AAAA,QAChD;AAEA,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,QAAQ,iBAAiB,iBAAiB,CAAC,KAAK;AAAA,YAChD,iBAAiB;AAAA,YACjB,oBAAoB,MAAM;AAAA,YAC1B,YAAY,MAAM,iBAAiB,iBAAiB,KAAK,KAAK,CAAC;AAAA,YAC/D;AAAA,YACA,YAAY,MAAM;AAAA,YAClB,YAAY,MAAM;AAAA,YAClB,kBAAkB,MAAM;AAAA,YACxB,YAAY,MAAM;AAAA,YAClB,UAAU,CAAC,eAAe,WAAW;AACnC,oBAAM,SAAS,MAAM,iBAAiB,KAAK;AAC3C,oBAAM,MAAM,OAAO,WAAW,aAAa;AAC3C,oBAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,KAAK,aAAa;AAAA,cACpB;AAAA,YACF;AAAA,YACA,eAAe,MAAM;AAAA,YACrB,sBAAsB,MAAM;AAAA,YAC5B,oBAAoB,MAAM;AAAA,YAC1B,YAAY,MAAM;AAChB,kBAAI,CAAC,MAAM,WAAW,GAAG;AACvB,sBAAM,QAAQ,QAAQ;AAAA,cACxB;AAAA,YACF;AAAA,YACA,QAAQ,MAAM;AACZ,kBAAI,CAAC,MAAM,WAAW,GAAG;AACvB,sBAAM,OAAO;AAAA,cACf;AAAA,YACF;AAAA;AAAA,QACF;AAAA,MAEJ;AAAA,MAEA,KAAK;AACH,eACE;AAAA,UAAC;AAAA;AAAA,YACC,iBAAiB,MAAM,2BAA2B,EAAE;AAAA,YACpD,cAAc,MAAM;AAAA,YACpB,gBAAgB,MAAM;AAAA,YACtB,YAAY,MAAM,MAAM,QAAQ,SAAS;AAAA,YACzC,QAAQ,MAAM;AAAA;AAAA,QAChB;AAAA,MAGJ,KAAK,WAAW;AACd,cAAM,YAAY,aAAa,MAAM,iBAAiB,MAAM;AAC5D,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,YAAY;AAAA,YACZ;AAAA,YACA,iBAAiB,MAAM;AAAA,YACvB,kBAAkB,MAAM;AAAA,YACxB,iBAAiB,MAAM,2BAA2B,EAAE;AAAA,YACpD,YAAY,MAAM,kBAAkB,EAAE;AAAA,YACtC,aAAa,MAAM;AAAA,YACnB,QAAQ,MAAM;AAAA;AAAA,QAChB;AAAA,MAEJ;AAAA,MAEA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAGA,MAAI,kBAAkB;AACpB,WACE,oBAAC,iBAAc,OAAO,UACpB,+BAAC,OAAI,eAAc,UAAS,SAAS,GACnC;AAAA,2BAAC,QAAK,OAAM,UAAS;AAAA;AAAA,QACG;AAAA,QAAc;AAAA,QAC7B;AAAA,QAAmB;AAAA,SAC5B;AAAA,MACA,oBAAC,OAAI,WAAW,GACd,+BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QAAgB;AAAA,QAAc;AAAA,SAAQ,GACvD;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,iBAAc,OAAO,UACpB,+BAAC,OAAI,eAAc,UAAS,SAAS,GAElC;AAAA,eACC,oBAAC,OAAI,cAAc,GACjB,+BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,MAAoB;AAAA,OAAQ,GAC7C;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,aAAa,MAAM;AAAA,QACnB;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IACC,WAAW;AAAA,KACd,GACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/wizard.tsx"],"sourcesContent":["/**\n * Wizard component - Main orchestrator for the skill selection wizard.\n *\n * V2 Flow:\n * - approach: Choose stack template or build from scratch\n * - stack: Select pre-built stack (stack path) OR domains (scratch path)\n * - stack-options: Continue defaults or customize (stack path only)\n * - build: CategoryGrid for technology selection\n * - refine: Skill source selection\n * - confirm: Final confirmation\n *\n * Navigation:\n * - ESC goes back through history\n * - ESC at approach cancels wizard\n * - Ctrl+C cancels at any point\n */\nimport React, { useCallback, useMemo } from \"react\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport { ThemeProvider } from \"@inkjs/ui\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { cliTheme } from \"../themes/default.js\";\nimport { WizardTabs, WIZARD_STEPS } from \"./wizard-tabs.js\";\nimport { StepApproach } from \"./step-approach.js\";\nimport { StepStack } from \"./step-stack.js\";\nimport { StepStackOptions } from \"./step-stack-options.js\";\nimport { StepBuild } from \"./step-build.js\";\nimport { StepRefine } from \"./step-refine.js\";\nimport { StepConfirm } from \"./step-confirm.js\";\nimport { validateSelection } from \"../../lib/matrix-resolver.js\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface WizardResultV2 {\n selectedSkills: string[];\n selectedStackId: string | null;\n domainSelections: Record<string, Record<string, string[]>>;\n expertMode: boolean;\n installMode: \"plugin\" | \"local\";\n cancelled: boolean;\n validation: {\n valid: boolean;\n errors: Array<{ message: string }>;\n warnings: Array<{ message: string }>;\n };\n}\n\n/** @deprecated Use WizardResultV2 instead */\nexport interface WizardResult {\n selectedSkills: string[];\n selectedStack: { id: string } | null;\n expertMode: boolean;\n installMode: \"plugin\" | \"local\";\n cancelled: boolean;\n validation: {\n valid: boolean;\n errors: Array<{ message: string }>;\n warnings: Array<{ message: string }>;\n };\n}\n\ninterface WizardProps {\n matrix: MergedSkillsMatrix;\n onComplete: (result: WizardResultV2 | WizardResult) => void;\n onCancel: () => void;\n /** CLI version string to display in header */\n version?: string;\n /** @deprecated Initial skills no longer skip to category */\n initialSkills?: string[];\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Minimum terminal width required for the wizard */\nconst MIN_TERMINAL_WIDTH = 80;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Get display name for a domain.\n */\nfunction getDomainDisplayName(domain: string): string {\n const displayNames: Record<string, string> = {\n web: \"Web\",\n api: \"API\",\n cli: \"CLI\",\n mobile: \"Mobile\",\n shared: \"Shared\",\n };\n return (\n displayNames[domain] || domain.charAt(0).toUpperCase() + domain.slice(1)\n );\n}\n\n/**\n * Get stack name from matrix by stack ID.\n */\nfunction getStackName(\n stackId: string | null,\n matrix: MergedSkillsMatrix,\n): string | undefined {\n if (!stackId) return undefined;\n const stack = matrix.suggestedStacks.find((s) => s.id === stackId);\n return stack?.name;\n}\n\n/**\n * Count technologies in a stack.\n */\nfunction getStackTechnologyCount(\n stackId: string | null,\n matrix: MergedSkillsMatrix,\n): number {\n if (!stackId) return 0;\n const stack = matrix.suggestedStacks.find((s) => s.id === stackId);\n if (!stack) return 0;\n return stack.allSkillIds.length;\n}\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const Wizard: React.FC<WizardProps> = ({\n matrix,\n onComplete,\n onCancel,\n version,\n}) => {\n const store = useWizardStore();\n const { exit } = useApp();\n const { stdout } = useStdout();\n\n // Check terminal width\n const terminalWidth = stdout.columns || MIN_TERMINAL_WIDTH;\n const isNarrowTerminal = terminalWidth < MIN_TERMINAL_WIDTH;\n\n // Compute completed and skipped steps for WizardTabs\n const { completedSteps, skippedSteps } = useMemo(() => {\n const completed: string[] = [];\n const skipped: string[] = [];\n\n // Approach is complete when we've moved past it\n if (store.step !== \"approach\") {\n completed.push(\"approach\");\n }\n\n // Stack step handling\n if (\n store.step !== \"approach\" &&\n store.step !== \"stack\" &&\n store.step !== \"stack-options\"\n ) {\n completed.push(\"stack\");\n }\n\n // Build step handling\n // Stack path with defaults skips build\n if (\n store.approach === \"stack\" &&\n store.selectedStackId &&\n store.stackAction === \"defaults\"\n ) {\n skipped.push(\"build\");\n } else if (store.step === \"refine\" || store.step === \"confirm\") {\n completed.push(\"build\");\n }\n\n // Refine step\n if (store.step === \"confirm\") {\n completed.push(\"refine\");\n }\n\n return { completedSteps: completed, skippedSteps: skipped };\n }, [store.step, store.approach, store.selectedStackId, store.stackAction]);\n\n // Global escape handler\n useInput((input, key) => {\n if (key.escape) {\n if (store.step === \"approach\") {\n onCancel();\n exit();\n } else {\n store.goBack();\n }\n }\n });\n\n // Handle wizard completion\n const handleComplete = useCallback(() => {\n let allSkills: string[];\n\n if (store.selectedStackId && store.stackAction === \"defaults\") {\n // Stack + defaults path: use stack's allSkillIds directly\n const stack = matrix.suggestedStacks.find(\n (s) => s.id === store.selectedStackId,\n );\n if (!stack) {\n console.warn(`Stack not found in matrix: ${store.selectedStackId}`);\n }\n allSkills = [...(stack?.allSkillIds || [])];\n } else {\n // Scratch / Customize path: resolve domainSelections via aliases\n const techNames = store.getAllSelectedTechnologies();\n // Resolve each technology name to its full skill ID via aliases\n allSkills = techNames.map((tech) => matrix.aliases[tech] || tech);\n }\n\n // Add methodology skills (always included)\n const methodologySkills = store.getSelectedSkills();\n for (const skill of methodologySkills) {\n if (!allSkills.includes(skill)) {\n allSkills.push(skill);\n }\n }\n\n const validation = validateSelection(allSkills, matrix);\n\n const result: WizardResultV2 = {\n selectedSkills: allSkills,\n selectedStackId: store.selectedStackId,\n domainSelections: store.domainSelections,\n expertMode: store.expertMode,\n installMode: store.installMode,\n cancelled: false,\n validation,\n };\n\n onComplete(result);\n exit();\n }, [store, matrix, onComplete, exit]);\n\n // Render current step\n const renderStep = () => {\n switch (store.step) {\n case \"approach\":\n return <StepApproach />;\n\n case \"stack\":\n return <StepStack matrix={matrix} />;\n\n case \"stack-options\": {\n const stackName =\n getStackName(store.selectedStackId, matrix) || \"Selected Stack\";\n const techCount = getStackTechnologyCount(\n store.selectedStackId,\n matrix,\n );\n return (\n <StepStackOptions\n stackName={stackName}\n technologyCount={techCount}\n matrix={matrix}\n />\n );\n }\n\n case \"build\": {\n const currentDomain = store.getCurrentDomain();\n // For stack path with customize, use all domains from stack\n // For scratch path, use selectedDomains\n const effectiveDomains =\n store.selectedDomains.length > 0 ? store.selectedDomains : [\"web\"]; // Default to web if no domains selected\n\n const allSelections = store.getAllSelectedTechnologies();\n\n return (\n <StepBuild\n matrix={matrix}\n domain={currentDomain || effectiveDomains[0] || \"web\"}\n selectedDomains={effectiveDomains}\n currentDomainIndex={store.currentDomainIndex}\n selections={store.domainSelections[currentDomain || \"web\"] || {}}\n allSelections={allSelections}\n focusedRow={store.focusedRow}\n focusedCol={store.focusedCol}\n showDescriptions={store.showDescriptions}\n expertMode={store.expertMode}\n onToggle={(subcategoryId, techId) => {\n const domain = store.getCurrentDomain() || \"web\";\n const cat = matrix.categories[subcategoryId];\n store.toggleTechnology(\n domain,\n subcategoryId,\n techId,\n cat?.exclusive ?? true,\n );\n }}\n onFocusChange={store.setFocus}\n onToggleDescriptions={store.toggleShowDescriptions}\n onToggleExpertMode={store.toggleExpertMode}\n onContinue={() => {\n if (!store.nextDomain()) {\n store.setStep(\"refine\");\n }\n }}\n onBack={() => {\n if (!store.prevDomain()) {\n store.goBack();\n }\n }}\n />\n );\n }\n\n case \"refine\":\n return (\n <StepRefine\n technologyCount={store.getAllSelectedTechnologies().length}\n refineAction={store.refineAction}\n onSelectAction={store.setRefineAction}\n onContinue={() => store.setStep(\"confirm\")}\n onBack={store.goBack}\n />\n );\n\n case \"confirm\": {\n const stackName = getStackName(store.selectedStackId, matrix);\n return (\n <StepConfirm\n matrix={matrix}\n onComplete={handleComplete}\n stackName={stackName}\n selectedDomains={store.selectedDomains}\n domainSelections={store.domainSelections}\n technologyCount={store.getAllSelectedTechnologies().length}\n skillCount={store.getSelectedSkills().length}\n installMode={store.installMode}\n onBack={store.goBack}\n />\n );\n }\n\n default:\n return null;\n }\n };\n\n // Show warning if terminal is too narrow\n if (isNarrowTerminal) {\n return (\n <ThemeProvider theme={cliTheme}>\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"yellow\">\n Terminal too narrow ({terminalWidth} columns). Please resize to at\n least {MIN_TERMINAL_WIDTH} columns.\n </Text>\n <Box marginTop={1}>\n <Text dimColor>Current width: {terminalWidth} columns</Text>\n </Box>\n </Box>\n </ThemeProvider>\n );\n }\n\n return (\n <ThemeProvider theme={cliTheme}>\n <Box flexDirection=\"column\" padding={1}>\n {/* Header with version */}\n {version && (\n <Box marginBottom={1}>\n <Text dimColor>Claude Collective v{version}</Text>\n </Box>\n )}\n <WizardTabs\n steps={WIZARD_STEPS}\n currentStep={store.step}\n completedSteps={completedSteps}\n skippedSteps={skippedSteps}\n />\n {renderStep()}\n </Box>\n </ThemeProvider>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -89,21 +89,22 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
|
89
89
|
}
|
|
90
90
|
const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;
|
|
91
91
|
const skillId = frontmatter.name;
|
|
92
|
+
const category = metadata.category || LOCAL_CATEGORY;
|
|
92
93
|
const extracted = {
|
|
93
94
|
id: skillId,
|
|
94
95
|
directoryPath: skillDirName,
|
|
95
96
|
name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,
|
|
96
97
|
description: metadata.cli_description || frontmatter.description,
|
|
97
|
-
usageGuidance:
|
|
98
|
-
category
|
|
99
|
-
categoryExclusive: false,
|
|
98
|
+
usageGuidance: metadata.usage_guidance,
|
|
99
|
+
category,
|
|
100
|
+
categoryExclusive: metadata.category_exclusive ?? false,
|
|
100
101
|
author: LOCAL_AUTHOR,
|
|
101
|
-
tags: [],
|
|
102
|
-
compatibleWith: [],
|
|
103
|
-
conflictsWith: [],
|
|
104
|
-
requires: [],
|
|
105
|
-
requiresSetup: [],
|
|
106
|
-
providesSetupFor: [],
|
|
102
|
+
tags: metadata.tags ?? [],
|
|
103
|
+
compatibleWith: metadata.compatible_with ?? [],
|
|
104
|
+
conflictsWith: metadata.conflicts_with ?? [],
|
|
105
|
+
requires: metadata.requires ?? [],
|
|
106
|
+
requiresSetup: metadata.requires_setup ?? [],
|
|
107
|
+
providesSetupFor: metadata.provides_setup_for ?? [],
|
|
107
108
|
path: relativePath,
|
|
108
109
|
local: true,
|
|
109
110
|
localPath: relativePath
|
|
@@ -271,32 +272,36 @@ function mergeLocalSkillsIntoMatrix(matrix, localResult) {
|
|
|
271
272
|
matrix.categories["local/custom"] = LOCAL_CATEGORY_CUSTOM;
|
|
272
273
|
}
|
|
273
274
|
for (const metadata of localResult.skills) {
|
|
275
|
+
const hasOriginalCategory = metadata.category !== "local" && matrix.categories[metadata.category];
|
|
276
|
+
const category = hasOriginalCategory ? metadata.category : "local/custom";
|
|
277
|
+
const existingSkill = matrix.skills[metadata.id];
|
|
278
|
+
const alias = existingSkill?.alias ?? matrix.aliasesReverse[metadata.id];
|
|
274
279
|
const resolvedSkill = {
|
|
275
280
|
id: metadata.id,
|
|
276
|
-
alias
|
|
281
|
+
alias,
|
|
277
282
|
name: metadata.name,
|
|
278
283
|
description: metadata.description,
|
|
279
284
|
usageGuidance: metadata.usageGuidance,
|
|
280
|
-
category
|
|
281
|
-
categoryExclusive:
|
|
285
|
+
category,
|
|
286
|
+
categoryExclusive: metadata.categoryExclusive,
|
|
282
287
|
tags: metadata.tags ?? [],
|
|
283
288
|
author: "@local",
|
|
284
|
-
conflictsWith: [],
|
|
285
|
-
recommends: [],
|
|
286
|
-
recommendedBy: [],
|
|
287
|
-
requires: [],
|
|
288
|
-
requiredBy: [],
|
|
289
|
-
alternatives: [],
|
|
290
|
-
discourages: [],
|
|
291
|
-
compatibleWith: [],
|
|
292
|
-
requiresSetup: [],
|
|
293
|
-
providesSetupFor: [],
|
|
289
|
+
conflictsWith: existingSkill?.conflictsWith ?? [],
|
|
290
|
+
recommends: existingSkill?.recommends ?? [],
|
|
291
|
+
recommendedBy: existingSkill?.recommendedBy ?? [],
|
|
292
|
+
requires: existingSkill?.requires ?? [],
|
|
293
|
+
requiredBy: existingSkill?.requiredBy ?? [],
|
|
294
|
+
alternatives: existingSkill?.alternatives ?? [],
|
|
295
|
+
discourages: existingSkill?.discourages ?? [],
|
|
296
|
+
compatibleWith: existingSkill?.compatibleWith ?? [],
|
|
297
|
+
requiresSetup: existingSkill?.requiresSetup ?? [],
|
|
298
|
+
providesSetupFor: existingSkill?.providesSetupFor ?? [],
|
|
294
299
|
path: metadata.path,
|
|
295
300
|
local: true,
|
|
296
301
|
localPath: metadata.localPath
|
|
297
302
|
};
|
|
298
303
|
matrix.skills[metadata.id] = resolvedSkill;
|
|
299
|
-
verbose(`Added local skill: ${metadata.id}`);
|
|
304
|
+
verbose(`Added local skill: ${metadata.id} (category: ${category})`);
|
|
300
305
|
}
|
|
301
306
|
return matrix;
|
|
302
307
|
}
|
|
@@ -305,4 +310,4 @@ export {
|
|
|
305
310
|
discoverLocalSkills,
|
|
306
311
|
loadSkillsMatrixFromSource
|
|
307
312
|
};
|
|
308
|
-
//# sourceMappingURL=chunk-
|
|
313
|
+
//# sourceMappingURL=chunk-RFTSZDHV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/local-skill-loader.ts","../src/cli/lib/source-loader.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport {\n directoryExists,\n listDirectories,\n fileExists,\n readFile,\n} from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { LOCAL_SKILLS_PATH } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type { ExtractedSkillMetadata } from \"../types-matrix\";\n\nconst LOCAL_CATEGORY = \"local\";\nconst LOCAL_AUTHOR = \"@local\";\n\ninterface LocalRawMetadata {\n cli_name: string;\n cli_description?: string;\n /** Original skill category from source (e.g., \"framework\", \"styling\", \"api\") */\n category?: string;\n category_exclusive?: boolean;\n usage_guidance?: string;\n tags?: string[];\n compatible_with?: string[];\n conflicts_with?: string[];\n requires?: string[];\n requires_setup?: string[];\n provides_setup_for?: string[];\n}\n\nexport interface LocalSkillDiscoveryResult {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n}\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skills: ExtractedSkillMetadata[] = [];\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const skillDirName of skillDirs) {\n const skill = await extractLocalSkill(localSkillsPath, skillDirName);\n if (skill) {\n skills.push(skill);\n }\n }\n\n verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as LocalRawMetadata;\n\n if (!metadata.cli_name) {\n verbose(\n `Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`,\n );\n return null;\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(\n `Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`,\n );\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const skillId = frontmatter.name;\n\n // Use category from metadata.yaml if available (preserved from source skill),\n // otherwise fall back to generic \"local\" category\n const category = metadata.category || LOCAL_CATEGORY;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: metadata.usage_guidance,\n category,\n categoryExclusive: metadata.category_exclusive ?? false,\n author: LOCAL_AUTHOR,\n tags: metadata.tags ?? [],\n compatibleWith: metadata.compatible_with ?? [],\n conflictsWith: metadata.conflicts_with ?? [],\n requires: metadata.requires ?? [],\n requiresSetup: metadata.requires_setup ?? [],\n providesSetupFor: metadata.provides_setup_for ?? [],\n path: relativePath,\n local: true,\n localPath: relativePath,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import path from \"path\";\nimport { PROJECT_ROOT, SKILLS_DIR_PATH, SKILLS_MATRIX_PATH } from \"../consts\";\nimport type {\n CategoryDefinition,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n} from \"../types-matrix\";\nimport type { Stack } from \"../types-stacks\";\nimport { fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { isLocalSource, resolveSource, type ResolvedConfig } from \"./config\";\nimport {\n discoverLocalSkills,\n type LocalSkillDiscoveryResult,\n} from \"./local-skill-loader\";\nimport {\n extractAllSkills,\n loadSkillsMatrix,\n mergeMatrixWithSkills,\n} from \"./matrix-loader\";\nimport { fetchFromSource } from \"./source-fetcher\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"./stacks-loader\";\n\nexport interface SourceLoadOptions {\n sourceFlag?: string;\n projectDir?: string;\n forceRefresh?: boolean;\n devMode?: boolean;\n}\n\nexport interface SourceLoadResult {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n}\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const {\n sourceFlag,\n projectDir,\n forceRefresh = false,\n devMode = false,\n } = options;\n\n const sourceConfig = await resolveSource(sourceFlag, projectDir);\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const isLocal = isLocalSource(source) || devMode === true;\n\n let result: SourceLoadResult;\n if (isLocal) {\n result = await loadFromLocal(source, sourceConfig);\n } else {\n result = await loadFromRemote(source, sourceConfig, forceRefresh);\n }\n\n const resolvedProjectDir = projectDir || process.cwd();\n const localSkillsResult = await discoverLocalSkills(resolvedProjectDir);\n\n if (localSkillsResult && localSkillsResult.skills.length > 0) {\n verbose(\n `Found ${localSkillsResult.skills.length} local skill(s) in ${localSkillsResult.localSkillsPath}`,\n );\n result.matrix = mergeLocalSkillsIntoMatrix(\n result.matrix,\n localSkillsResult,\n );\n }\n\n return result;\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n): Promise<SourceLoadResult> {\n let skillsPath: string;\n\n if (isLocalSource(source)) {\n skillsPath = path.isAbsolute(source)\n ? source\n : path.resolve(process.cwd(), source);\n } else {\n skillsPath = PROJECT_ROOT;\n }\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(skillsPath, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(skillsPath, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n marketplace: sourceConfig.marketplace,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source, { forceRefresh });\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(fetchResult.path, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(fetchResult.path, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n marketplace: sourceConfig.marketplace,\n };\n}\n\n/**\n * Convert a Stack (from config/stacks.yaml) to ResolvedStack format\n * for compatibility with the wizard.\n *\n * Phase 7: Skills are defined in stacks per agent (subcategory -> technology alias).\n * Uses skill_aliases from the matrix to resolve aliases to full skill IDs.\n */\nfunction stackToResolvedStack(\n stack: Stack,\n skillAliases: Record<string, string>,\n): ResolvedStack {\n // Collect all unique skill IDs from agent configs in this stack\n const allSkillIds: string[] = [];\n const seenSkillIds = new Set<string>();\n\n // stack.agents is Record<string, StackAgentConfig> - iterate over agent IDs\n for (const agentId of Object.keys(stack.agents)) {\n const agentConfig = stack.agents[agentId];\n\n // Resolve this agent's technology selections to skill IDs\n const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);\n\n for (const ref of skillRefs) {\n if (!seenSkillIds.has(ref.id)) {\n seenSkillIds.add(ref.id);\n allSkillIds.push(ref.id);\n }\n }\n }\n\n const agentCount = Object.keys(stack.agents).length;\n verbose(\n `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`,\n );\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: [], // Not used in new format\n skills: {}, // Skills come from stack agent configs, resolved at runtime\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\nconst LOCAL_CATEGORY_TOP: CategoryDefinition = {\n id: \"local\",\n name: \"Local Skills\",\n description: \"Project-specific skills from .claude/skills/\",\n exclusive: false,\n required: false,\n order: 0,\n};\n\nconst LOCAL_CATEGORY_CUSTOM: CategoryDefinition = {\n id: \"local/custom\",\n name: \"Custom\",\n description: \"Your project-specific skills\",\n exclusive: false,\n required: false,\n order: 0,\n parent: \"local\",\n};\n\nfunction mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n if (!matrix.categories[\"local\"]) {\n matrix.categories[\"local\"] = LOCAL_CATEGORY_TOP;\n }\n if (!matrix.categories[\"local/custom\"]) {\n matrix.categories[\"local/custom\"] = LOCAL_CATEGORY_CUSTOM;\n }\n\n for (const metadata of localResult.skills) {\n // Use the skill's original category from metadata.yaml when available,\n // falling back to \"local/custom\" for truly new local skills\n const hasOriginalCategory =\n metadata.category !== \"local\" && matrix.categories[metadata.category];\n const category = hasOriginalCategory ? metadata.category : \"local/custom\";\n\n // Preserve alias from existing matrix entry (if skill was in source)\n const existingSkill = matrix.skills[metadata.id];\n const alias = existingSkill?.alias ?? matrix.aliasesReverse[metadata.id];\n\n const resolvedSkill: ResolvedSkill = {\n id: metadata.id,\n alias,\n name: metadata.name,\n description: metadata.description,\n usageGuidance: metadata.usageGuidance,\n\n category,\n categoryExclusive: metadata.categoryExclusive,\n tags: metadata.tags ?? [],\n\n author: \"@local\",\n\n conflictsWith: existingSkill?.conflictsWith ?? [],\n recommends: existingSkill?.recommends ?? [],\n recommendedBy: existingSkill?.recommendedBy ?? [],\n requires: existingSkill?.requires ?? [],\n requiredBy: existingSkill?.requiredBy ?? [],\n alternatives: existingSkill?.alternatives ?? [],\n discourages: existingSkill?.discourages ?? [],\n compatibleWith: existingSkill?.compatibleWith ?? [],\n\n requiresSetup: existingSkill?.requiresSetup ?? [],\n providesSetupFor: existingSkill?.providesSetupFor ?? [],\n\n path: metadata.path,\n\n local: true,\n localPath: metadata.localPath,\n };\n\n matrix.skills[metadata.id] = resolvedSkill;\n verbose(`Added local skill: ${metadata.id} (category: ${category})`);\n }\n\n return matrix;\n}\n"],"mappings":"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","names":["path","path"]}
|
|
@@ -360,11 +360,37 @@ function validateAgentSkillConfig(agentName, agentSkills) {
|
|
|
360
360
|
}
|
|
361
361
|
return `agent_skills.${agentName} must be an array or object`;
|
|
362
362
|
}
|
|
363
|
+
function isSimpleAgentSkills(value) {
|
|
364
|
+
return Array.isArray(value);
|
|
365
|
+
}
|
|
366
|
+
function normalizeSkillEntry(entry) {
|
|
367
|
+
if (typeof entry === "string") {
|
|
368
|
+
return { id: entry };
|
|
369
|
+
}
|
|
370
|
+
return entry;
|
|
371
|
+
}
|
|
372
|
+
function normalizeAgentSkills(agentSkills) {
|
|
373
|
+
const result = {};
|
|
374
|
+
for (const [agentName, skills] of Object.entries(agentSkills)) {
|
|
375
|
+
if (isSimpleAgentSkills(skills)) {
|
|
376
|
+
result[agentName] = {
|
|
377
|
+
uncategorized: skills.map(normalizeSkillEntry)
|
|
378
|
+
};
|
|
379
|
+
} else {
|
|
380
|
+
result[agentName] = {};
|
|
381
|
+
for (const [category, categorySkills] of Object.entries(skills)) {
|
|
382
|
+
result[agentName][category] = categorySkills.map(normalizeSkillEntry);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
363
388
|
|
|
364
389
|
export {
|
|
365
390
|
loadProjectConfig,
|
|
366
391
|
isLegacyStackConfig,
|
|
367
392
|
normalizeStackConfig,
|
|
368
|
-
validateProjectConfig
|
|
393
|
+
validateProjectConfig,
|
|
394
|
+
normalizeAgentSkills
|
|
369
395
|
};
|
|
370
|
-
//# sourceMappingURL=chunk-
|
|
396
|
+
//# sourceMappingURL=chunk-ZFPSUQOU.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/project-config.ts"],"sourcesContent":["import path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\nimport type {\n ProjectConfig,\n StackConfig,\n SkillAssignment,\n SkillEntry,\n AgentSkillConfig,\n ValidationResult,\n CustomAgentConfig,\n} from \"../../types\";\n\nconst CONFIG_PATH = `${CLAUDE_SRC_DIR}/config.yaml`;\nconst LEGACY_CONFIG_PATH = `${CLAUDE_DIR}/config.yaml`;\n\nexport interface LoadedProjectConfig {\n config: ProjectConfig;\n configPath: string;\n /** true if was StackConfig format (legacy) */\n isLegacy: boolean;\n}\n\n/**\n * Load project config from .claude-src/config.yaml (with fallback to .claude/config.yaml)\n */\nexport async function loadProjectConfig(\n projectDir: string,\n): Promise<LoadedProjectConfig | null> {\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = path.join(projectDir, CONFIG_PATH);\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, LEGACY_CONFIG_PATH);\n\n let configPath = srcConfigPath;\n if (!(await fileExists(srcConfigPath))) {\n if (await fileExists(legacyConfigPath)) {\n configPath = legacyConfigPath;\n verbose(`Using legacy config location: ${legacyConfigPath}`);\n } else {\n verbose(\n `Project config not found at ${srcConfigPath} or ${legacyConfigPath}`,\n );\n return null;\n }\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n\n if (!parsed || typeof parsed !== \"object\") {\n verbose(`Invalid project config structure at ${configPath}`);\n return null;\n }\n\n // Detect if this is legacy StackConfig format\n const isLegacy = isLegacyStackConfig(parsed);\n\n if (isLegacy) {\n verbose(`Detected legacy StackConfig format at ${configPath}`);\n const normalized = normalizeStackConfig(parsed as StackConfig);\n return {\n config: normalized,\n configPath,\n isLegacy: true,\n };\n }\n\n verbose(`Loaded project config from ${configPath}`);\n return {\n config: parsed as ProjectConfig,\n configPath,\n isLegacy: false,\n };\n } catch (error) {\n verbose(`Failed to parse project config: ${error}`);\n return null;\n }\n}\n\n/**\n * Check if a config object is in legacy StackConfig format.\n * Detection logic:\n * - If version is semver (e.g., \"1.0.0\") -> legacy\n * - If version is \"1\" -> new format\n * - If has 'id' field -> legacy\n * - If has 'created' or 'updated' fields -> legacy\n */\nexport function isLegacyStackConfig(config: unknown): boolean {\n if (!config || typeof config !== \"object\") return false;\n\n const obj = config as Record<string, unknown>;\n\n // If version looks like semver (x.y.z), it's legacy\n if (typeof obj.version === \"string\" && obj.version.includes(\".\")) {\n return true;\n }\n\n // If has legacy-only fields, it's legacy\n if (\n obj.id !== undefined ||\n obj.created !== undefined ||\n obj.updated !== undefined\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Normalize StackConfig to ProjectConfig (for backward compatibility)\n */\nexport function normalizeStackConfig(stackConfig: StackConfig): ProjectConfig {\n const config: ProjectConfig = {\n name: stackConfig.name,\n agents: stackConfig.agents,\n };\n\n // Copy optional fields\n if (stackConfig.description) {\n config.description = stackConfig.description;\n }\n\n if (stackConfig.skills && stackConfig.skills.length > 0) {\n config.skills = stackConfig.skills;\n }\n\n if (stackConfig.agent_skills) {\n // StackConfig agent_skills is always categorized format\n config.agent_skills = stackConfig.agent_skills;\n }\n\n if (stackConfig.hooks) {\n config.hooks = stackConfig.hooks;\n }\n\n if (stackConfig.author) {\n config.author = stackConfig.author;\n }\n\n if (stackConfig.framework) {\n config.framework = stackConfig.framework;\n }\n\n if (stackConfig.philosophy) {\n config.philosophy = stackConfig.philosophy;\n }\n\n if (stackConfig.principles && stackConfig.principles.length > 0) {\n config.principles = stackConfig.principles;\n }\n\n if (stackConfig.tags && stackConfig.tags.length > 0) {\n config.tags = stackConfig.tags;\n }\n\n return config;\n}\n\n/**\n * Validate project config structure.\n * Returns validation result with errors and warnings.\n */\nexport function validateProjectConfig(config: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!config || typeof config !== \"object\") {\n return { valid: false, errors: [\"Config must be an object\"], warnings: [] };\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: name\n if (!c.name || typeof c.name !== \"string\") {\n errors.push(\"name is required and must be a string\");\n }\n\n // Required: agents (for compilation)\n if (!c.agents || !Array.isArray(c.agents)) {\n errors.push(\"agents is required and must be an array\");\n } else {\n for (const agent of c.agents) {\n if (typeof agent !== \"string\") {\n errors.push(`agents must contain strings, found: ${typeof agent}`);\n }\n }\n }\n\n // Optional: version\n if (c.version !== undefined && c.version !== \"1\") {\n errors.push('version must be \"1\" (or omitted for default)');\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(\"skills must be an array\");\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(skillError);\n }\n }\n }\n }\n\n // Optional: agent_skills\n if (c.agent_skills !== undefined) {\n if (typeof c.agent_skills !== \"object\" || c.agent_skills === null) {\n errors.push(\"agent_skills must be an object\");\n } else {\n for (const [agentName, agentSkills] of Object.entries(c.agent_skills)) {\n const agentSkillsError = validateAgentSkillConfig(\n agentName,\n agentSkills,\n );\n if (agentSkillsError) {\n errors.push(agentSkillsError);\n }\n }\n }\n }\n\n // Optional: preload_patterns\n if (c.preload_patterns !== undefined) {\n if (typeof c.preload_patterns !== \"object\" || c.preload_patterns === null) {\n errors.push(\"preload_patterns must be an object\");\n } else {\n for (const [agentName, patterns] of Object.entries(c.preload_patterns)) {\n if (!Array.isArray(patterns)) {\n errors.push(\n `preload_patterns.${agentName} must be an array of strings`,\n );\n } else {\n for (const pattern of patterns) {\n if (typeof pattern !== \"string\") {\n errors.push(\n `preload_patterns.${agentName} must contain only strings`,\n );\n break;\n }\n }\n }\n }\n }\n }\n\n // Optional: custom_agents\n if (c.custom_agents !== undefined) {\n const customAgentsErrors = validateCustomAgents(c.custom_agents, c.agents);\n errors.push(...customAgentsErrors);\n }\n\n // Warnings for deprecated patterns\n if (c.id !== undefined) {\n warnings.push(\"id field is deprecated in project config\");\n }\n if (c.created !== undefined) {\n warnings.push(\"created field is deprecated in project config\");\n }\n if (c.updated !== undefined) {\n warnings.push(\"updated field is deprecated in project config\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/** Maximum number of custom agents allowed per project */\nconst MAX_CUSTOM_AGENTS = 20;\n\n/** Valid model values for custom agents */\nconst VALID_MODELS = [\"sonnet\", \"opus\", \"haiku\", \"inherit\"];\n\n/** Valid permission modes for custom agents */\nconst VALID_PERMISSION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"dontAsk\",\n \"bypassPermissions\",\n \"plan\",\n \"delegate\",\n];\n\n/**\n * Validate custom_agents section of config\n */\nfunction validateCustomAgents(\n customAgents: unknown,\n agents: unknown,\n): string[] {\n const errors: string[] = [];\n\n if (typeof customAgents !== \"object\" || customAgents === null) {\n errors.push(\"custom_agents must be an object\");\n return errors;\n }\n\n const customAgentEntries = Object.entries(customAgents);\n\n // Check maximum limit\n if (customAgentEntries.length > MAX_CUSTOM_AGENTS) {\n errors.push(\n `custom_agents cannot exceed ${MAX_CUSTOM_AGENTS} agents (found ${customAgentEntries.length})`,\n );\n }\n\n // Collect custom agent names for circular reference check\n const customAgentNames = new Set(customAgentEntries.map(([name]) => name));\n\n for (const [agentName, agentConfig] of customAgentEntries) {\n const agentErrors = validateCustomAgentConfig(\n agentName,\n agentConfig,\n customAgentNames,\n );\n errors.push(...agentErrors);\n }\n\n return errors;\n}\n\n/**\n * Validate a single custom agent configuration\n */\nfunction validateCustomAgentConfig(\n agentName: string,\n config: unknown,\n customAgentNames: Set<string>,\n): string[] {\n const errors: string[] = [];\n const prefix = `custom_agents.${agentName}`;\n\n if (typeof config !== \"object\" || config === null) {\n errors.push(`${prefix} must be an object`);\n return errors;\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: title\n if (!c.title || typeof c.title !== \"string\") {\n errors.push(`${prefix}.title is required and must be a string`);\n }\n\n // Required: description\n if (!c.description || typeof c.description !== \"string\") {\n errors.push(`${prefix}.description is required and must be a string`);\n }\n\n // Optional: extends\n if (c.extends !== undefined) {\n if (typeof c.extends !== \"string\") {\n errors.push(`${prefix}.extends must be a string`);\n } else if (customAgentNames.has(c.extends)) {\n // Custom agents cannot extend other custom agents\n errors.push(\n `${prefix}.extends cannot reference another custom agent \"${c.extends}\"`,\n );\n }\n }\n\n // Optional: model\n if (c.model !== undefined) {\n if (typeof c.model !== \"string\" || !VALID_MODELS.includes(c.model)) {\n errors.push(`${prefix}.model must be one of: ${VALID_MODELS.join(\", \")}`);\n }\n }\n\n // Optional: tools\n if (c.tools !== undefined) {\n if (!Array.isArray(c.tools)) {\n errors.push(`${prefix}.tools must be an array`);\n } else {\n for (const tool of c.tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: disallowed_tools\n if (c.disallowed_tools !== undefined) {\n if (!Array.isArray(c.disallowed_tools)) {\n errors.push(`${prefix}.disallowed_tools must be an array`);\n } else {\n for (const tool of c.disallowed_tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.disallowed_tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: permission_mode\n if (c.permission_mode !== undefined) {\n if (\n typeof c.permission_mode !== \"string\" ||\n !VALID_PERMISSION_MODES.includes(c.permission_mode)\n ) {\n errors.push(\n `${prefix}.permission_mode must be one of: ${VALID_PERMISSION_MODES.join(\", \")}`,\n );\n }\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(`${prefix}.skills must be an array`);\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(`${prefix}.skills: ${skillError}`);\n }\n }\n }\n }\n\n // Optional: hooks\n if (c.hooks !== undefined) {\n if (typeof c.hooks !== \"object\" || c.hooks === null) {\n errors.push(`${prefix}.hooks must be an object`);\n }\n // Note: Detailed hook validation could be added later if needed\n }\n\n return errors;\n}\n\n/**\n * Validate a single skill entry\n */\nfunction validateSkillEntry(skill: unknown): string | null {\n if (typeof skill === \"string\") {\n return null; // String skill IDs are valid\n }\n\n if (typeof skill !== \"object\" || skill === null) {\n return \"skills must be strings or objects\";\n }\n\n const s = skill as Record<string, unknown>;\n\n if (!s.id || typeof s.id !== \"string\") {\n return \"skill object must have an id string\";\n }\n\n if (s.local === true && !s.path) {\n return `local skill \"${s.id}\" must have a path`;\n }\n\n if (s.preloaded !== undefined && typeof s.preloaded !== \"boolean\") {\n return `skill \"${s.id}\" preloaded must be a boolean`;\n }\n\n if (s.local !== undefined && typeof s.local !== \"boolean\") {\n return `skill \"${s.id}\" local must be a boolean`;\n }\n\n if (s.path !== undefined && typeof s.path !== \"string\") {\n return `skill \"${s.id}\" path must be a string`;\n }\n\n return null;\n}\n\n/**\n * Validate agent skill config (can be simple list or categorized)\n */\nfunction validateAgentSkillConfig(\n agentName: string,\n agentSkills: unknown,\n): string | null {\n // Check if it's a simple list (array)\n if (Array.isArray(agentSkills)) {\n for (const skill of agentSkills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}: ${skillError}`;\n }\n }\n return null;\n }\n\n // Check if it's categorized (object with array values)\n if (typeof agentSkills === \"object\" && agentSkills !== null) {\n for (const [category, skills] of Object.entries(agentSkills)) {\n if (!Array.isArray(skills)) {\n return `agent_skills.${agentName}.${category} must be an array`;\n }\n for (const skill of skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}.${category}: ${skillError}`;\n }\n }\n }\n return null;\n }\n\n return `agent_skills.${agentName} must be an array or object`;\n}\n\n/**\n * Check if agent_skills value is in simple list format (array)\n */\nexport function isSimpleAgentSkills(value: unknown): value is SkillEntry[] {\n return Array.isArray(value);\n}\n\n/**\n * Normalize a skill entry to SkillAssignment\n */\nexport function normalizeSkillEntry(entry: SkillEntry): SkillAssignment {\n if (typeof entry === \"string\") {\n return { id: entry };\n }\n return entry;\n}\n\n/**\n * Normalize agent_skills to always be categorized format for internal use.\n * Simple lists are placed under an \"uncategorized\" key.\n */\nexport function normalizeAgentSkills(\n agentSkills: Record<string, AgentSkillConfig>,\n): Record<string, Record<string, SkillAssignment[]>> {\n const result: Record<string, Record<string, SkillAssignment[]>> = {};\n\n for (const [agentName, skills] of Object.entries(agentSkills)) {\n if (isSimpleAgentSkills(skills)) {\n // Simple list -> put under \"uncategorized\"\n result[agentName] = {\n uncategorized: skills.map(normalizeSkillEntry),\n };\n } else {\n // Already categorized -> normalize entries\n result[agentName] = {};\n for (const [category, categorySkills] of Object.entries(skills)) {\n result[agentName][category] = categorySkills.map(normalizeSkillEntry);\n }\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/project-config.ts"],"sourcesContent":["import path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\nimport type {\n ProjectConfig,\n StackConfig,\n SkillAssignment,\n SkillEntry,\n AgentSkillConfig,\n ValidationResult,\n CustomAgentConfig,\n} from \"../../types\";\n\nconst CONFIG_PATH = `${CLAUDE_SRC_DIR}/config.yaml`;\nconst LEGACY_CONFIG_PATH = `${CLAUDE_DIR}/config.yaml`;\n\nexport interface LoadedProjectConfig {\n config: ProjectConfig;\n configPath: string;\n /** true if was StackConfig format (legacy) */\n isLegacy: boolean;\n}\n\n/**\n * Load project config from .claude-src/config.yaml (with fallback to .claude/config.yaml)\n */\nexport async function loadProjectConfig(\n projectDir: string,\n): Promise<LoadedProjectConfig | null> {\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = path.join(projectDir, CONFIG_PATH);\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, LEGACY_CONFIG_PATH);\n\n let configPath = srcConfigPath;\n if (!(await fileExists(srcConfigPath))) {\n if (await fileExists(legacyConfigPath)) {\n configPath = legacyConfigPath;\n verbose(`Using legacy config location: ${legacyConfigPath}`);\n } else {\n verbose(\n `Project config not found at ${srcConfigPath} or ${legacyConfigPath}`,\n );\n return null;\n }\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n\n if (!parsed || typeof parsed !== \"object\") {\n verbose(`Invalid project config structure at ${configPath}`);\n return null;\n }\n\n // Detect if this is legacy StackConfig format\n const isLegacy = isLegacyStackConfig(parsed);\n\n if (isLegacy) {\n verbose(`Detected legacy StackConfig format at ${configPath}`);\n const normalized = normalizeStackConfig(parsed as StackConfig);\n return {\n config: normalized,\n configPath,\n isLegacy: true,\n };\n }\n\n verbose(`Loaded project config from ${configPath}`);\n return {\n config: parsed as ProjectConfig,\n configPath,\n isLegacy: false,\n };\n } catch (error) {\n verbose(`Failed to parse project config: ${error}`);\n return null;\n }\n}\n\n/**\n * Check if a config object is in legacy StackConfig format.\n * Detection logic:\n * - If version is semver (e.g., \"1.0.0\") -> legacy\n * - If version is \"1\" -> new format\n * - If has 'id' field -> legacy\n * - If has 'created' or 'updated' fields -> legacy\n */\nexport function isLegacyStackConfig(config: unknown): boolean {\n if (!config || typeof config !== \"object\") return false;\n\n const obj = config as Record<string, unknown>;\n\n // If version looks like semver (x.y.z), it's legacy\n if (typeof obj.version === \"string\" && obj.version.includes(\".\")) {\n return true;\n }\n\n // If has legacy-only fields, it's legacy\n if (\n obj.id !== undefined ||\n obj.created !== undefined ||\n obj.updated !== undefined\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Normalize StackConfig to ProjectConfig (for backward compatibility)\n */\nexport function normalizeStackConfig(stackConfig: StackConfig): ProjectConfig {\n const config: ProjectConfig = {\n name: stackConfig.name,\n agents: stackConfig.agents,\n };\n\n // Copy optional fields\n if (stackConfig.description) {\n config.description = stackConfig.description;\n }\n\n if (stackConfig.skills && stackConfig.skills.length > 0) {\n config.skills = stackConfig.skills;\n }\n\n if (stackConfig.agent_skills) {\n // StackConfig agent_skills is always categorized format\n config.agent_skills = stackConfig.agent_skills;\n }\n\n if (stackConfig.hooks) {\n config.hooks = stackConfig.hooks;\n }\n\n if (stackConfig.author) {\n config.author = stackConfig.author;\n }\n\n if (stackConfig.framework) {\n config.framework = stackConfig.framework;\n }\n\n if (stackConfig.philosophy) {\n config.philosophy = stackConfig.philosophy;\n }\n\n if (stackConfig.principles && stackConfig.principles.length > 0) {\n config.principles = stackConfig.principles;\n }\n\n if (stackConfig.tags && stackConfig.tags.length > 0) {\n config.tags = stackConfig.tags;\n }\n\n return config;\n}\n\n/**\n * Validate project config structure.\n * Returns validation result with errors and warnings.\n */\nexport function validateProjectConfig(config: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!config || typeof config !== \"object\") {\n return { valid: false, errors: [\"Config must be an object\"], warnings: [] };\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: name\n if (!c.name || typeof c.name !== \"string\") {\n errors.push(\"name is required and must be a string\");\n }\n\n // Required: agents (for compilation)\n if (!c.agents || !Array.isArray(c.agents)) {\n errors.push(\"agents is required and must be an array\");\n } else {\n for (const agent of c.agents) {\n if (typeof agent !== \"string\") {\n errors.push(`agents must contain strings, found: ${typeof agent}`);\n }\n }\n }\n\n // Optional: version\n if (c.version !== undefined && c.version !== \"1\") {\n errors.push('version must be \"1\" (or omitted for default)');\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(\"skills must be an array\");\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(skillError);\n }\n }\n }\n }\n\n // Optional: agent_skills\n if (c.agent_skills !== undefined) {\n if (typeof c.agent_skills !== \"object\" || c.agent_skills === null) {\n errors.push(\"agent_skills must be an object\");\n } else {\n for (const [agentName, agentSkills] of Object.entries(c.agent_skills)) {\n const agentSkillsError = validateAgentSkillConfig(\n agentName,\n agentSkills,\n );\n if (agentSkillsError) {\n errors.push(agentSkillsError);\n }\n }\n }\n }\n\n // Optional: preload_patterns\n if (c.preload_patterns !== undefined) {\n if (typeof c.preload_patterns !== \"object\" || c.preload_patterns === null) {\n errors.push(\"preload_patterns must be an object\");\n } else {\n for (const [agentName, patterns] of Object.entries(c.preload_patterns)) {\n if (!Array.isArray(patterns)) {\n errors.push(\n `preload_patterns.${agentName} must be an array of strings`,\n );\n } else {\n for (const pattern of patterns) {\n if (typeof pattern !== \"string\") {\n errors.push(\n `preload_patterns.${agentName} must contain only strings`,\n );\n break;\n }\n }\n }\n }\n }\n }\n\n // Optional: custom_agents\n if (c.custom_agents !== undefined) {\n const customAgentsErrors = validateCustomAgents(c.custom_agents, c.agents);\n errors.push(...customAgentsErrors);\n }\n\n // Warnings for deprecated patterns\n if (c.id !== undefined) {\n warnings.push(\"id field is deprecated in project config\");\n }\n if (c.created !== undefined) {\n warnings.push(\"created field is deprecated in project config\");\n }\n if (c.updated !== undefined) {\n warnings.push(\"updated field is deprecated in project config\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/** Maximum number of custom agents allowed per project */\nconst MAX_CUSTOM_AGENTS = 20;\n\n/** Valid model values for custom agents */\nconst VALID_MODELS = [\"sonnet\", \"opus\", \"haiku\", \"inherit\"];\n\n/** Valid permission modes for custom agents */\nconst VALID_PERMISSION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"dontAsk\",\n \"bypassPermissions\",\n \"plan\",\n \"delegate\",\n];\n\n/**\n * Validate custom_agents section of config\n */\nfunction validateCustomAgents(\n customAgents: unknown,\n agents: unknown,\n): string[] {\n const errors: string[] = [];\n\n if (typeof customAgents !== \"object\" || customAgents === null) {\n errors.push(\"custom_agents must be an object\");\n return errors;\n }\n\n const customAgentEntries = Object.entries(customAgents);\n\n // Check maximum limit\n if (customAgentEntries.length > MAX_CUSTOM_AGENTS) {\n errors.push(\n `custom_agents cannot exceed ${MAX_CUSTOM_AGENTS} agents (found ${customAgentEntries.length})`,\n );\n }\n\n // Collect custom agent names for circular reference check\n const customAgentNames = new Set(customAgentEntries.map(([name]) => name));\n\n for (const [agentName, agentConfig] of customAgentEntries) {\n const agentErrors = validateCustomAgentConfig(\n agentName,\n agentConfig,\n customAgentNames,\n );\n errors.push(...agentErrors);\n }\n\n return errors;\n}\n\n/**\n * Validate a single custom agent configuration\n */\nfunction validateCustomAgentConfig(\n agentName: string,\n config: unknown,\n customAgentNames: Set<string>,\n): string[] {\n const errors: string[] = [];\n const prefix = `custom_agents.${agentName}`;\n\n if (typeof config !== \"object\" || config === null) {\n errors.push(`${prefix} must be an object`);\n return errors;\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: title\n if (!c.title || typeof c.title !== \"string\") {\n errors.push(`${prefix}.title is required and must be a string`);\n }\n\n // Required: description\n if (!c.description || typeof c.description !== \"string\") {\n errors.push(`${prefix}.description is required and must be a string`);\n }\n\n // Optional: extends\n if (c.extends !== undefined) {\n if (typeof c.extends !== \"string\") {\n errors.push(`${prefix}.extends must be a string`);\n } else if (customAgentNames.has(c.extends)) {\n // Custom agents cannot extend other custom agents\n errors.push(\n `${prefix}.extends cannot reference another custom agent \"${c.extends}\"`,\n );\n }\n }\n\n // Optional: model\n if (c.model !== undefined) {\n if (typeof c.model !== \"string\" || !VALID_MODELS.includes(c.model)) {\n errors.push(`${prefix}.model must be one of: ${VALID_MODELS.join(\", \")}`);\n }\n }\n\n // Optional: tools\n if (c.tools !== undefined) {\n if (!Array.isArray(c.tools)) {\n errors.push(`${prefix}.tools must be an array`);\n } else {\n for (const tool of c.tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: disallowed_tools\n if (c.disallowed_tools !== undefined) {\n if (!Array.isArray(c.disallowed_tools)) {\n errors.push(`${prefix}.disallowed_tools must be an array`);\n } else {\n for (const tool of c.disallowed_tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.disallowed_tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: permission_mode\n if (c.permission_mode !== undefined) {\n if (\n typeof c.permission_mode !== \"string\" ||\n !VALID_PERMISSION_MODES.includes(c.permission_mode)\n ) {\n errors.push(\n `${prefix}.permission_mode must be one of: ${VALID_PERMISSION_MODES.join(\", \")}`,\n );\n }\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(`${prefix}.skills must be an array`);\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(`${prefix}.skills: ${skillError}`);\n }\n }\n }\n }\n\n // Optional: hooks\n if (c.hooks !== undefined) {\n if (typeof c.hooks !== \"object\" || c.hooks === null) {\n errors.push(`${prefix}.hooks must be an object`);\n }\n // Note: Detailed hook validation could be added later if needed\n }\n\n return errors;\n}\n\n/**\n * Validate a single skill entry\n */\nfunction validateSkillEntry(skill: unknown): string | null {\n if (typeof skill === \"string\") {\n return null; // String skill IDs are valid\n }\n\n if (typeof skill !== \"object\" || skill === null) {\n return \"skills must be strings or objects\";\n }\n\n const s = skill as Record<string, unknown>;\n\n if (!s.id || typeof s.id !== \"string\") {\n return \"skill object must have an id string\";\n }\n\n if (s.local === true && !s.path) {\n return `local skill \"${s.id}\" must have a path`;\n }\n\n if (s.preloaded !== undefined && typeof s.preloaded !== \"boolean\") {\n return `skill \"${s.id}\" preloaded must be a boolean`;\n }\n\n if (s.local !== undefined && typeof s.local !== \"boolean\") {\n return `skill \"${s.id}\" local must be a boolean`;\n }\n\n if (s.path !== undefined && typeof s.path !== \"string\") {\n return `skill \"${s.id}\" path must be a string`;\n }\n\n return null;\n}\n\n/**\n * Validate agent skill config (can be simple list or categorized)\n */\nfunction validateAgentSkillConfig(\n agentName: string,\n agentSkills: unknown,\n): string | null {\n // Check if it's a simple list (array)\n if (Array.isArray(agentSkills)) {\n for (const skill of agentSkills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}: ${skillError}`;\n }\n }\n return null;\n }\n\n // Check if it's categorized (object with array values)\n if (typeof agentSkills === \"object\" && agentSkills !== null) {\n for (const [category, skills] of Object.entries(agentSkills)) {\n if (!Array.isArray(skills)) {\n return `agent_skills.${agentName}.${category} must be an array`;\n }\n for (const skill of skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}.${category}: ${skillError}`;\n }\n }\n }\n return null;\n }\n\n return `agent_skills.${agentName} must be an array or object`;\n}\n\n/**\n * Check if agent_skills value is in simple list format (array)\n */\nexport function isSimpleAgentSkills(value: unknown): value is SkillEntry[] {\n return Array.isArray(value);\n}\n\n/**\n * Normalize a skill entry to SkillAssignment\n */\nexport function normalizeSkillEntry(entry: SkillEntry): SkillAssignment {\n if (typeof entry === \"string\") {\n return { id: entry };\n }\n return entry;\n}\n\n/**\n * Normalize agent_skills to always be categorized format for internal use.\n * Simple lists are placed under an \"uncategorized\" key.\n */\nexport function normalizeAgentSkills(\n agentSkills: Record<string, AgentSkillConfig>,\n): Record<string, Record<string, SkillAssignment[]>> {\n const result: Record<string, Record<string, SkillAssignment[]>> = {};\n\n for (const [agentName, skills] of Object.entries(agentSkills)) {\n if (isSimpleAgentSkills(skills)) {\n // Simple list -> put under \"uncategorized\"\n result[agentName] = {\n uncategorized: skills.map(normalizeSkillEntry),\n };\n } else {\n // Already categorized -> normalize entries\n result[agentName] = {};\n for (const [category, categorySkills] of Object.entries(skills)) {\n result[agentName][category] = categorySkills.map(normalizeSkillEntry);\n }\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
|
package/dist/commands/compile.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "../chunk-SVYPSDWY.js";
|
|
5
5
|
import {
|
|
6
6
|
detectInstallation
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-IAUAQJQ2.js";
|
|
8
8
|
import {
|
|
9
9
|
recompileAgents
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-4K4ZXQRM.js";
|
|
11
11
|
import "../chunk-DRXPNNPB.js";
|
|
12
12
|
import "../chunk-GDH553MV.js";
|
|
13
13
|
import "../chunk-I4TPKIYX.js";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getPluginManifestPath,
|
|
18
18
|
getProjectPluginsDir
|
|
19
19
|
} from "../chunk-ED4E6Q2T.js";
|
|
20
|
-
import "../chunk-
|
|
20
|
+
import "../chunk-ZFPSUQOU.js";
|
|
21
21
|
import "../chunk-KAAEN2PO.js";
|
|
22
22
|
import {
|
|
23
23
|
loadPluginSkills
|
package/dist/commands/diff.js
CHANGED
package/dist/commands/doctor.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
loadProjectConfig,
|
|
4
4
|
validateProjectConfig
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-ZFPSUQOU.js";
|
|
6
6
|
import {
|
|
7
7
|
discoverLocalSkills,
|
|
8
8
|
loadSkillsMatrixFromSource
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-RFTSZDHV.js";
|
|
10
10
|
import "../chunk-B7CCVP6Q.js";
|
|
11
11
|
import "../chunk-IMDW5ZUP.js";
|
|
12
12
|
import {
|
package/dist/commands/edit.js
CHANGED
|
@@ -7,23 +7,23 @@ import {
|
|
|
7
7
|
} from "../chunk-SVYPSDWY.js";
|
|
8
8
|
import {
|
|
9
9
|
detectInstallation
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-IAUAQJQ2.js";
|
|
11
11
|
import {
|
|
12
12
|
recompileAgents
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-4K4ZXQRM.js";
|
|
14
14
|
import {
|
|
15
15
|
Wizard
|
|
16
|
-
} from "../chunk-
|
|
17
|
-
import "../chunk-I2DSLOXZ.js";
|
|
18
|
-
import "../chunk-ZENYS6KW.js";
|
|
19
|
-
import "../chunk-ORVG4P2D.js";
|
|
20
|
-
import "../chunk-X6QONICW.js";
|
|
16
|
+
} from "../chunk-K3NB6DSG.js";
|
|
21
17
|
import "../chunk-E3FJH4TF.js";
|
|
22
|
-
import "../chunk-Y2LW7R3Y.js";
|
|
23
18
|
import "../chunk-HLJX2FTL.js";
|
|
24
19
|
import "../chunk-CDX4W4DM.js";
|
|
20
|
+
import "../chunk-I2DSLOXZ.js";
|
|
21
|
+
import "../chunk-ZENYS6KW.js";
|
|
22
|
+
import "../chunk-7Q44DMSP.js";
|
|
25
23
|
import "../chunk-Z7G4B5HJ.js";
|
|
26
24
|
import "../chunk-BDLUZVKU.js";
|
|
25
|
+
import "../chunk-X6QONICW.js";
|
|
26
|
+
import "../chunk-Y2LW7R3Y.js";
|
|
27
27
|
import "../chunk-D237EVNB.js";
|
|
28
28
|
import "../chunk-Z2CWURZ6.js";
|
|
29
29
|
import "../chunk-DRXPNNPB.js";
|
|
@@ -34,14 +34,14 @@ import {
|
|
|
34
34
|
getPluginSkillIds,
|
|
35
35
|
getPluginSkillsDir
|
|
36
36
|
} from "../chunk-ED4E6Q2T.js";
|
|
37
|
-
import "../chunk-
|
|
37
|
+
import "../chunk-ZFPSUQOU.js";
|
|
38
38
|
import {
|
|
39
39
|
copySkillsToPluginFromSource
|
|
40
40
|
} from "../chunk-K7EVM5LY.js";
|
|
41
41
|
import "../chunk-KAAEN2PO.js";
|
|
42
42
|
import {
|
|
43
43
|
loadSkillsMatrixFromSource
|
|
44
|
-
} from "../chunk-
|
|
44
|
+
} from "../chunk-RFTSZDHV.js";
|
|
45
45
|
import "../chunk-B7CCVP6Q.js";
|
|
46
46
|
import "../chunk-IMDW5ZUP.js";
|
|
47
47
|
import {
|
package/dist/commands/eject.js
CHANGED
package/dist/commands/info.js
CHANGED
package/dist/commands/init.js
CHANGED
|
@@ -7,17 +7,17 @@ import {
|
|
|
7
7
|
} from "../chunk-UQTEPWU7.js";
|
|
8
8
|
import {
|
|
9
9
|
Wizard
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-I2DSLOXZ.js";
|
|
12
|
-
import "../chunk-ZENYS6KW.js";
|
|
13
|
-
import "../chunk-ORVG4P2D.js";
|
|
14
|
-
import "../chunk-X6QONICW.js";
|
|
10
|
+
} from "../chunk-K3NB6DSG.js";
|
|
15
11
|
import "../chunk-E3FJH4TF.js";
|
|
16
|
-
import "../chunk-Y2LW7R3Y.js";
|
|
17
12
|
import "../chunk-HLJX2FTL.js";
|
|
18
13
|
import "../chunk-CDX4W4DM.js";
|
|
14
|
+
import "../chunk-I2DSLOXZ.js";
|
|
15
|
+
import "../chunk-ZENYS6KW.js";
|
|
16
|
+
import "../chunk-7Q44DMSP.js";
|
|
19
17
|
import "../chunk-Z7G4B5HJ.js";
|
|
20
18
|
import "../chunk-BDLUZVKU.js";
|
|
19
|
+
import "../chunk-X6QONICW.js";
|
|
20
|
+
import "../chunk-Y2LW7R3Y.js";
|
|
21
21
|
import "../chunk-D237EVNB.js";
|
|
22
22
|
import "../chunk-Z2CWURZ6.js";
|
|
23
23
|
import {
|
|
@@ -36,14 +36,14 @@ import {
|
|
|
36
36
|
} from "../chunk-ED4E6Q2T.js";
|
|
37
37
|
import {
|
|
38
38
|
loadProjectConfig as loadProjectConfig2
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-ZFPSUQOU.js";
|
|
40
40
|
import {
|
|
41
41
|
copySkillsToLocalFlattened
|
|
42
42
|
} from "../chunk-K7EVM5LY.js";
|
|
43
43
|
import "../chunk-KAAEN2PO.js";
|
|
44
44
|
import {
|
|
45
45
|
loadSkillsMatrixFromSource
|
|
46
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-RFTSZDHV.js";
|
|
47
47
|
import {
|
|
48
48
|
loadAllAgents,
|
|
49
49
|
loadStackById
|
package/dist/commands/list.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatInstallationDisplay,
|
|
4
4
|
getInstallationInfo
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-IBE7JIAG.js";
|
|
6
|
+
import "../chunk-IAUAQJQ2.js";
|
|
7
7
|
import "../chunk-ED4E6Q2T.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-ZFPSUQOU.js";
|
|
9
9
|
import {
|
|
10
10
|
BaseCommand
|
|
11
11
|
} from "../chunk-EHS3TWWP.js";
|
package/dist/commands/search.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getPluginInfo
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-IBE7JIAG.js";
|
|
5
5
|
import {
|
|
6
6
|
validatePluginManifest
|
|
7
7
|
} from "../chunk-NDY25DTL.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-IAUAQJQ2.js";
|
|
9
9
|
import {
|
|
10
10
|
compileAllAgents,
|
|
11
11
|
resolveSkillReference
|
|
12
12
|
} from "../chunk-I4TPKIYX.js";
|
|
13
13
|
import "../chunk-ED4E6Q2T.js";
|
|
14
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-ZFPSUQOU.js";
|
|
15
15
|
import {
|
|
16
16
|
loadSkillsMatrixFromSource
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-RFTSZDHV.js";
|
|
18
18
|
import "../chunk-B7CCVP6Q.js";
|
|
19
19
|
import "../chunk-IMDW5ZUP.js";
|
|
20
20
|
import {
|
package/dist/commands/update.js
CHANGED
|
@@ -4,20 +4,20 @@ import {
|
|
|
4
4
|
} from "../chunk-RTE64SJA.js";
|
|
5
5
|
import {
|
|
6
6
|
recompileAgents
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-4K4ZXQRM.js";
|
|
8
8
|
import "../chunk-DRXPNNPB.js";
|
|
9
9
|
import "../chunk-GDH553MV.js";
|
|
10
10
|
import "../chunk-I4TPKIYX.js";
|
|
11
11
|
import {
|
|
12
12
|
getCollectivePluginDir
|
|
13
13
|
} from "../chunk-ED4E6Q2T.js";
|
|
14
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-ZFPSUQOU.js";
|
|
15
15
|
import {
|
|
16
16
|
hashFile
|
|
17
17
|
} from "../chunk-KAAEN2PO.js";
|
|
18
18
|
import {
|
|
19
19
|
loadSkillsMatrixFromSource
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-RFTSZDHV.js";
|
|
21
21
|
import "../chunk-B7CCVP6Q.js";
|
|
22
22
|
import "../chunk-IMDW5ZUP.js";
|
|
23
23
|
import {
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
StepBuild,
|
|
4
4
|
getDisplayLabel,
|
|
5
5
|
validateBuildStep
|
|
6
|
-
} from "../../chunk-
|
|
7
|
-
import "../../chunk-Y2LW7R3Y.js";
|
|
6
|
+
} from "../../chunk-7Q44DMSP.js";
|
|
8
7
|
import "../../chunk-Z7G4B5HJ.js";
|
|
9
8
|
import "../../chunk-BDLUZVKU.js";
|
|
9
|
+
import "../../chunk-Y2LW7R3Y.js";
|
|
10
10
|
import "../../chunk-DHET7RCE.js";
|
|
11
11
|
export {
|
|
12
12
|
StepBuild,
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
StepBuild,
|
|
21
21
|
getDisplayLabel,
|
|
22
22
|
validateBuildStep
|
|
23
|
-
} from "../../chunk-
|
|
24
|
-
import "../../chunk-Y2LW7R3Y.js";
|
|
23
|
+
} from "../../chunk-7Q44DMSP.js";
|
|
25
24
|
import "../../chunk-Z7G4B5HJ.js";
|
|
26
25
|
import "../../chunk-BDLUZVKU.js";
|
|
26
|
+
import "../../chunk-Y2LW7R3Y.js";
|
|
27
27
|
import {
|
|
28
28
|
init_esm_shims
|
|
29
29
|
} from "../../chunk-DHET7RCE.js";
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
Wizard
|
|
4
|
-
} from "../../chunk-
|
|
5
|
-
import "../../chunk-I2DSLOXZ.js";
|
|
6
|
-
import "../../chunk-ZENYS6KW.js";
|
|
7
|
-
import "../../chunk-ORVG4P2D.js";
|
|
8
|
-
import "../../chunk-X6QONICW.js";
|
|
4
|
+
} from "../../chunk-K3NB6DSG.js";
|
|
9
5
|
import "../../chunk-E3FJH4TF.js";
|
|
10
|
-
import "../../chunk-Y2LW7R3Y.js";
|
|
11
6
|
import "../../chunk-HLJX2FTL.js";
|
|
12
7
|
import "../../chunk-CDX4W4DM.js";
|
|
8
|
+
import "../../chunk-I2DSLOXZ.js";
|
|
9
|
+
import "../../chunk-ZENYS6KW.js";
|
|
10
|
+
import "../../chunk-7Q44DMSP.js";
|
|
13
11
|
import "../../chunk-Z7G4B5HJ.js";
|
|
14
12
|
import "../../chunk-BDLUZVKU.js";
|
|
13
|
+
import "../../chunk-X6QONICW.js";
|
|
14
|
+
import "../../chunk-Y2LW7R3Y.js";
|
|
15
15
|
import "../../chunk-D237EVNB.js";
|
|
16
16
|
import "../../chunk-Z2CWURZ6.js";
|
|
17
17
|
import "../../chunk-76DWXGQE.js";
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/local-skill-loader.ts","../src/cli/lib/source-loader.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport {\n directoryExists,\n listDirectories,\n fileExists,\n readFile,\n} from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { LOCAL_SKILLS_PATH } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type { ExtractedSkillMetadata } from \"../types-matrix\";\n\nconst LOCAL_CATEGORY = \"local\";\nconst LOCAL_AUTHOR = \"@local\";\n\ninterface LocalRawMetadata {\n cli_name: string;\n cli_description?: string;\n}\n\nexport interface LocalSkillDiscoveryResult {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n}\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skills: ExtractedSkillMetadata[] = [];\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const skillDirName of skillDirs) {\n const skill = await extractLocalSkill(localSkillsPath, skillDirName);\n if (skill) {\n skills.push(skill);\n }\n }\n\n verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as LocalRawMetadata;\n\n if (!metadata.cli_name) {\n verbose(\n `Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`,\n );\n return null;\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(\n `Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`,\n );\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: undefined,\n category: LOCAL_CATEGORY,\n categoryExclusive: false,\n author: LOCAL_AUTHOR,\n tags: [],\n compatibleWith: [],\n conflictsWith: [],\n requires: [],\n requiresSetup: [],\n providesSetupFor: [],\n path: relativePath,\n local: true,\n localPath: relativePath,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import path from \"path\";\nimport { PROJECT_ROOT, SKILLS_DIR_PATH, SKILLS_MATRIX_PATH } from \"../consts\";\nimport type {\n CategoryDefinition,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n} from \"../types-matrix\";\nimport type { Stack } from \"../types-stacks\";\nimport { fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { isLocalSource, resolveSource, type ResolvedConfig } from \"./config\";\nimport {\n discoverLocalSkills,\n type LocalSkillDiscoveryResult,\n} from \"./local-skill-loader\";\nimport {\n extractAllSkills,\n loadSkillsMatrix,\n mergeMatrixWithSkills,\n} from \"./matrix-loader\";\nimport { fetchFromSource } from \"./source-fetcher\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"./stacks-loader\";\n\nexport interface SourceLoadOptions {\n sourceFlag?: string;\n projectDir?: string;\n forceRefresh?: boolean;\n devMode?: boolean;\n}\n\nexport interface SourceLoadResult {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n}\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const {\n sourceFlag,\n projectDir,\n forceRefresh = false,\n devMode = false,\n } = options;\n\n const sourceConfig = await resolveSource(sourceFlag, projectDir);\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const isLocal = isLocalSource(source) || devMode === true;\n\n let result: SourceLoadResult;\n if (isLocal) {\n result = await loadFromLocal(source, sourceConfig);\n } else {\n result = await loadFromRemote(source, sourceConfig, forceRefresh);\n }\n\n const resolvedProjectDir = projectDir || process.cwd();\n const localSkillsResult = await discoverLocalSkills(resolvedProjectDir);\n\n if (localSkillsResult && localSkillsResult.skills.length > 0) {\n verbose(\n `Found ${localSkillsResult.skills.length} local skill(s) in ${localSkillsResult.localSkillsPath}`,\n );\n result.matrix = mergeLocalSkillsIntoMatrix(\n result.matrix,\n localSkillsResult,\n );\n }\n\n return result;\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n): Promise<SourceLoadResult> {\n let skillsPath: string;\n\n if (isLocalSource(source)) {\n skillsPath = path.isAbsolute(source)\n ? source\n : path.resolve(process.cwd(), source);\n } else {\n skillsPath = PROJECT_ROOT;\n }\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(skillsPath, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(skillsPath, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n marketplace: sourceConfig.marketplace,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source, { forceRefresh });\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(fetchResult.path, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(fetchResult.path, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n marketplace: sourceConfig.marketplace,\n };\n}\n\n/**\n * Convert a Stack (from config/stacks.yaml) to ResolvedStack format\n * for compatibility with the wizard.\n *\n * Phase 7: Skills are defined in stacks per agent (subcategory -> technology alias).\n * Uses skill_aliases from the matrix to resolve aliases to full skill IDs.\n */\nfunction stackToResolvedStack(\n stack: Stack,\n skillAliases: Record<string, string>,\n): ResolvedStack {\n // Collect all unique skill IDs from agent configs in this stack\n const allSkillIds: string[] = [];\n const seenSkillIds = new Set<string>();\n\n // stack.agents is Record<string, StackAgentConfig> - iterate over agent IDs\n for (const agentId of Object.keys(stack.agents)) {\n const agentConfig = stack.agents[agentId];\n\n // Resolve this agent's technology selections to skill IDs\n const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);\n\n for (const ref of skillRefs) {\n if (!seenSkillIds.has(ref.id)) {\n seenSkillIds.add(ref.id);\n allSkillIds.push(ref.id);\n }\n }\n }\n\n const agentCount = Object.keys(stack.agents).length;\n verbose(\n `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`,\n );\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: [], // Not used in new format\n skills: {}, // Skills come from stack agent configs, resolved at runtime\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\nconst LOCAL_CATEGORY_TOP: CategoryDefinition = {\n id: \"local\",\n name: \"Local Skills\",\n description: \"Project-specific skills from .claude/skills/\",\n exclusive: false,\n required: false,\n order: 0,\n};\n\nconst LOCAL_CATEGORY_CUSTOM: CategoryDefinition = {\n id: \"local/custom\",\n name: \"Custom\",\n description: \"Your project-specific skills\",\n exclusive: false,\n required: false,\n order: 0,\n parent: \"local\",\n};\n\nfunction mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n if (!matrix.categories[\"local\"]) {\n matrix.categories[\"local\"] = LOCAL_CATEGORY_TOP;\n }\n if (!matrix.categories[\"local/custom\"]) {\n matrix.categories[\"local/custom\"] = LOCAL_CATEGORY_CUSTOM;\n }\n\n for (const metadata of localResult.skills) {\n const resolvedSkill: ResolvedSkill = {\n id: metadata.id,\n alias: undefined,\n name: metadata.name,\n description: metadata.description,\n usageGuidance: metadata.usageGuidance,\n\n category: \"local/custom\",\n categoryExclusive: false,\n tags: metadata.tags ?? [],\n\n author: \"@local\",\n\n conflictsWith: [],\n recommends: [],\n recommendedBy: [],\n requires: [],\n requiredBy: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n\n requiresSetup: [],\n providesSetupFor: [],\n\n path: metadata.path,\n\n local: true,\n localPath: metadata.localPath,\n };\n\n matrix.skills[metadata.id] = resolvedSkill;\n verbose(`Added local skill: ${metadata.id}`);\n }\n\n return matrix;\n}\n"],"mappings":"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","names":["path","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/agent-recompiler.ts","../src/cli/lib/custom-agent-resolver.ts"],"sourcesContent":["import path from \"path\";\nimport { glob, writeFile, ensureDir, readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { loadAllAgents, loadPluginSkills, loadProjectAgents } from \"./loader\";\nimport { resolveAgents, resolveStackSkills } from \"./resolver\";\nimport { compileAgentForPlugin } from \"./stack-plugin-compiler\";\nimport { getPluginAgentsDir } from \"./plugin-finder\";\nimport { createLiquidEngine } from \"./compiler\";\nimport {\n loadProjectConfig,\n isLegacyStackConfig,\n normalizeStackConfig,\n type LoadedProjectConfig,\n} from \"./project-config\";\nimport {\n resolveCustomAgents,\n validateCustomAgentIds,\n} from \"./custom-agent-resolver\";\nimport { parse as parseYaml } from \"yaml\";\nimport type {\n CompileConfig,\n CompileAgentConfig,\n StackConfig,\n SkillReference,\n SkillDefinition,\n ProjectConfig,\n AgentDefinition,\n} from \"../../types\";\n\nexport interface RecompileAgentsOptions {\n pluginDir: string;\n sourcePath: string;\n agents?: string[];\n skills?: Record<string, SkillDefinition>;\n projectDir?: string;\n outputDir?: string;\n}\n\nexport interface RecompileAgentsResult {\n compiled: string[];\n failed: string[];\n warnings: string[];\n}\n\nasync function getExistingAgentNames(pluginDir: string): Promise<string[]> {\n const agentsDir = getPluginAgentsDir(pluginDir);\n const files = await glob(\"*.md\", agentsDir);\n return files.map((f) => path.basename(f, \".md\"));\n}\n\n/**\n * Load config from either:\n * 1. pluginDir/config.yaml (legacy plugin location)\n * 2. pluginDir/.claude/config.yaml (new project config location)\n *\n * This provides backward compatibility with existing plugins.\n */\nasync function loadConfigWithFallback(\n pluginDir: string,\n): Promise<LoadedProjectConfig | null> {\n // First try the legacy plugin location (pluginDir/config.yaml)\n const legacyConfigPath = path.join(pluginDir, \"config.yaml\");\n if (await fileExists(legacyConfigPath)) {\n try {\n const content = await readFile(legacyConfigPath);\n const parsed = parseYaml(content);\n\n if (parsed && typeof parsed === \"object\") {\n verbose(`Loaded config.yaml from ${legacyConfigPath}`);\n\n // Check if it's legacy StackConfig format\n if (isLegacyStackConfig(parsed)) {\n const normalized = normalizeStackConfig(parsed as StackConfig);\n return {\n config: normalized,\n configPath: legacyConfigPath,\n isLegacy: true,\n };\n }\n\n return {\n config: parsed as ProjectConfig,\n configPath: legacyConfigPath,\n isLegacy: false,\n };\n }\n } catch (error) {\n verbose(`Failed to parse config.yaml: ${error}`);\n }\n }\n\n // Fall back to project config location (.claude/config.yaml)\n return loadProjectConfig(pluginDir);\n}\n\n/**\n * Convert ProjectConfig to StackConfig-like structure for compatibility\n * with existing resolveStackSkills function\n */\nfunction projectConfigToStackLike(config: ProjectConfig): StackConfig {\n return {\n name: config.name,\n version: \"1.0.0\",\n author: config.author ?? \"@unknown\",\n description: config.description,\n skills:\n config.skills?.map((s) => (typeof s === \"string\" ? { id: s } : s)) ?? [],\n agents: config.agents,\n agent_skills: config.agent_skills as StackConfig[\"agent_skills\"],\n hooks: config.hooks,\n framework: config.framework,\n philosophy: config.philosophy,\n principles: config.principles,\n tags: config.tags,\n };\n}\n\nexport async function recompileAgents(\n options: RecompileAgentsOptions,\n): Promise<RecompileAgentsResult> {\n const {\n pluginDir,\n sourcePath,\n agents: specifiedAgents,\n skills: providedSkills,\n projectDir,\n outputDir,\n } = options;\n\n const result: RecompileAgentsResult = {\n compiled: [],\n failed: [],\n warnings: [],\n };\n\n // Load project config (handles both legacy plugin config and new ProjectConfig)\n const loadedConfig = await loadConfigWithFallback(pluginDir);\n const projectConfig = loadedConfig?.config ?? null;\n\n // Load built-in agents from source\n const builtinAgents = await loadAllAgents(sourcePath);\n\n // Load project agents from .claude-src/agents/ (if projectDir provided)\n const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};\n\n // Resolve custom agents and merge with built-in agents\n // Priority: custom_agents > project agents > built-in agents\n let allAgents: Record<string, AgentDefinition> = {\n ...builtinAgents,\n ...projectAgents,\n };\n if (projectConfig?.custom_agents) {\n // Validate custom agent IDs don't conflict with built-in agents\n const idConflicts = validateCustomAgentIds(\n projectConfig.custom_agents,\n builtinAgents,\n );\n if (idConflicts.length > 0) {\n for (const error of idConflicts) {\n result.warnings.push(error);\n }\n }\n\n // Resolve custom agents to AgentDefinition\n try {\n const resolvedCustomAgents = resolveCustomAgents(\n projectConfig.custom_agents,\n builtinAgents,\n );\n // Merge: custom agents can override built-in if same name (though we warn above)\n allAgents = { ...builtinAgents, ...resolvedCustomAgents };\n verbose(\n `Resolved ${Object.keys(resolvedCustomAgents).length} custom agents`,\n );\n } catch (error) {\n result.warnings.push(\n `Failed to resolve custom agents: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // Convert to StackConfig-like for compatibility with existing functions\n const pluginConfig = projectConfig\n ? projectConfigToStackLike(projectConfig)\n : null;\n\n let agentNames: string[];\n if (specifiedAgents) {\n agentNames = specifiedAgents;\n } else if (pluginConfig?.agents) {\n agentNames = pluginConfig.agents;\n verbose(`Using agents from config.yaml: ${agentNames.join(\", \")}`);\n } else if (outputDir) {\n agentNames = Object.keys(allAgents);\n verbose(`Using all available agents from source: ${agentNames.join(\", \")}`);\n } else {\n agentNames = await getExistingAgentNames(pluginDir);\n }\n\n if (agentNames.length === 0) {\n result.warnings.push(\"No agents found to recompile\");\n return result;\n }\n\n verbose(\n `Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`,\n );\n\n const pluginSkills = providedSkills ?? (await loadPluginSkills(pluginDir));\n\n const compileAgents: Record<string, CompileAgentConfig> = {};\n for (const agentName of agentNames) {\n if (allAgents[agentName]) {\n // Check if this is a custom agent with its own skills defined\n const customAgentConfig = projectConfig?.custom_agents?.[agentName];\n if (customAgentConfig?.skills && customAgentConfig.skills.length > 0) {\n // Custom agent has explicit skills defined\n const skillRefs: SkillReference[] = customAgentConfig.skills.map(\n (s) => ({\n id: typeof s === \"string\" ? s : s.id,\n usage: `when working with ${(typeof s === \"string\" ? s : s.id).split(\" \")[0]}`,\n preloaded:\n (typeof s === \"object\" && \"preloaded\" in s && s.preloaded) ??\n false,\n }),\n );\n compileAgents[agentName] = { skills: skillRefs };\n verbose(\n ` Agent ${agentName}: ${skillRefs.length} skills from custom_agents`,\n );\n } else if (pluginConfig?.agent_skills?.[agentName]) {\n const skillRefs = resolveStackSkills(\n pluginConfig,\n agentName,\n pluginSkills,\n );\n compileAgents[agentName] = { skills: skillRefs };\n verbose(` Agent ${agentName}: ${skillRefs.length} skills from config`);\n } else if (pluginConfig?.skills) {\n // Fall back to all skills in the config\n const skillRefs: SkillReference[] = pluginConfig.skills.map((s) => ({\n id: s.id,\n usage: `when working with ${s.id.split(\" \")[0]}`,\n preloaded: s.preloaded ?? false,\n }));\n compileAgents[agentName] = { skills: skillRefs };\n verbose(` Agent ${agentName}: ${skillRefs.length} skills (all)`);\n } else {\n compileAgents[agentName] = {};\n }\n } else {\n result.warnings.push(\n `Agent \"${agentName}\" not found in source definitions`,\n );\n }\n }\n\n const compileConfig: CompileConfig = {\n name: pluginConfig?.name || path.basename(pluginDir),\n description: pluginConfig?.description || \"Recompiled plugin\",\n claude_md: \"\",\n agents: compileAgents,\n };\n\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(\n allAgents,\n pluginSkills,\n compileConfig,\n sourcePath,\n );\n\n const agentsDir = outputDir ?? getPluginAgentsDir(pluginDir);\n await ensureDir(agentsDir);\n\n for (const [name, agent] of Object.entries(resolvedAgents)) {\n try {\n const output = await compileAgentForPlugin(\n name,\n agent,\n sourcePath,\n engine,\n );\n await writeFile(path.join(agentsDir, `${name}.md`), output);\n result.compiled.push(name);\n verbose(` Recompiled: ${name}`);\n } catch (error) {\n result.failed.push(name);\n result.warnings.push(\n `Failed to compile ${name}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n return result;\n}\n","import type { CustomAgentConfig, AgentDefinition } from \"../../types\";\n\n/** Default tools for standalone custom agents (no extends) */\nconst DEFAULT_TOOLS = [\"Read\", \"Grep\", \"Glob\"];\n\n/** Marker path for standalone custom agents (no extends) */\nconst CUSTOM_AGENT_PATH = \"_custom\";\n\n/**\n * Resolve a custom agent config to a full AgentDefinition.\n * If extends is specified, inherit from the base agent.\n *\n * @param agentId - The custom agent's identifier\n * @param customConfig - The custom agent configuration from config.yaml\n * @param builtinAgents - Record of built-in agent definitions to extend from\n * @returns Fully resolved AgentDefinition\n * @throws Error if extends references an unknown agent\n */\nexport function resolveCustomAgent(\n agentId: string,\n customConfig: CustomAgentConfig,\n builtinAgents: Record<string, AgentDefinition>,\n): AgentDefinition {\n let baseAgent: Partial<AgentDefinition> = {};\n\n if (customConfig.extends) {\n const base = builtinAgents[customConfig.extends];\n if (!base) {\n const availableAgents = Object.keys(builtinAgents);\n const agentList =\n availableAgents.length > 0\n ? `Available agents: ${availableAgents.slice(0, 5).join(\", \")}${availableAgents.length > 5 ? ` (and ${availableAgents.length - 5} more)` : \"\"}`\n : \"No built-in agents found\";\n throw new Error(\n `Custom agent \"${agentId}\" extends unknown agent \"${customConfig.extends}\". ${agentList}`,\n );\n }\n baseAgent = { ...base };\n }\n\n // Merge disallowed_tools: custom + inherited\n let disallowedTools: string[] | undefined;\n if (customConfig.disallowed_tools || baseAgent.disallowed_tools) {\n const merged = new Set<string>([\n ...(baseAgent.disallowed_tools || []),\n ...(customConfig.disallowed_tools || []),\n ]);\n disallowedTools = [...merged];\n }\n\n // Merge hooks: custom hooks added to inherited\n let hooks: AgentDefinition[\"hooks\"] | undefined;\n if (customConfig.hooks || baseAgent.hooks) {\n hooks = { ...baseAgent.hooks };\n if (customConfig.hooks) {\n for (const [hookType, hookDefs] of Object.entries(customConfig.hooks)) {\n if (hooks[hookType]) {\n hooks[hookType] = [...hooks[hookType], ...hookDefs];\n } else {\n hooks[hookType] = hookDefs;\n }\n }\n }\n }\n\n return {\n title: customConfig.title,\n description: customConfig.description,\n model: customConfig.model || baseAgent.model,\n tools: customConfig.tools || baseAgent.tools || DEFAULT_TOOLS,\n disallowed_tools: disallowedTools,\n permission_mode: customConfig.permission_mode || baseAgent.permission_mode,\n hooks,\n // Use extended agent's path for template resolution, or _custom for standalone\n path: baseAgent.path || CUSTOM_AGENT_PATH,\n sourceRoot: baseAgent.sourceRoot,\n };\n}\n\n/**\n * Resolve all custom agents from config to AgentDefinition records.\n *\n * @param customAgents - Record of custom agent configs from config.yaml\n * @param builtinAgents - Record of built-in agent definitions\n * @returns Record of resolved AgentDefinitions keyed by custom agent ID\n */\nexport function resolveCustomAgents(\n customAgents: Record<string, CustomAgentConfig>,\n builtinAgents: Record<string, AgentDefinition>,\n): Record<string, AgentDefinition> {\n const resolved: Record<string, AgentDefinition> = {};\n\n for (const [id, config] of Object.entries(customAgents)) {\n resolved[id] = resolveCustomAgent(id, config, builtinAgents);\n }\n\n return resolved;\n}\n\n/**\n * Check if a custom agent ID conflicts with a built-in agent ID.\n *\n * @param customAgentId - The custom agent's identifier\n * @param builtinAgents - Record of built-in agent definitions\n * @returns true if there's a conflict\n */\nexport function hasAgentIdConflict(\n customAgentId: string,\n builtinAgents: Record<string, AgentDefinition>,\n): boolean {\n return customAgentId in builtinAgents;\n}\n\n/**\n * Validate custom agents don't conflict with built-in agents.\n *\n * @param customAgents - Record of custom agent configs\n * @param builtinAgents - Record of built-in agent definitions\n * @returns Array of error messages (empty if no conflicts)\n */\nexport function validateCustomAgentIds(\n customAgents: Record<string, CustomAgentConfig>,\n builtinAgents: Record<string, AgentDefinition>,\n): string[] {\n const errors: string[] = [];\n\n for (const customId of Object.keys(customAgents)) {\n if (hasAgentIdConflict(customId, builtinAgents)) {\n errors.push(\n `Custom agent \"${customId}\" conflicts with built-in agent of the same name. Choose a unique name.`,\n );\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|