@claude-collective/cli 0.13.3 → 0.21.0
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 +190 -0
- package/config/skills-matrix.yaml +180 -113
- package/config/stacks.yaml +6 -6
- package/dist/{chunk-6DCSSORF.js → chunk-2LSGX6R4.js} +54 -119
- package/dist/chunk-2LSGX6R4.js.map +1 -0
- package/dist/chunk-2OKUEELH.js +32 -0
- package/dist/chunk-2OKUEELH.js.map +1 -0
- package/dist/{chunk-V46GGCCI.js → chunk-374JNMR6.js} +14 -96
- package/dist/chunk-374JNMR6.js.map +1 -0
- package/dist/chunk-3EHUF54X.js +133 -0
- package/dist/chunk-3EHUF54X.js.map +1 -0
- package/dist/{chunk-7Q44DMSP.js → chunk-3XR4PALU.js} +92 -145
- package/dist/chunk-3XR4PALU.js.map +1 -0
- package/dist/{chunk-IAUAQJQ2.js → chunk-5K2ZLUO5.js} +5 -5
- package/dist/{chunk-IAUAQJQ2.js.map → chunk-5K2ZLUO5.js.map} +1 -1
- package/dist/{chunk-ACNBKXXJ.js → chunk-5KXUDHAB.js} +8 -36
- package/dist/chunk-5KXUDHAB.js.map +1 -0
- package/dist/chunk-7SLV7CMF.js +615 -0
- package/dist/chunk-7SLV7CMF.js.map +1 -0
- package/dist/{chunk-CDX4W4DM.js → chunk-A46TPNBJ.js} +61 -32
- package/dist/chunk-A46TPNBJ.js.map +1 -0
- package/dist/{chunk-TKFPKEV3.js → chunk-AL74GBW4.js} +1 -1
- package/dist/chunk-AL74GBW4.js.map +1 -0
- package/dist/chunk-BQX23RBV.js +191 -0
- package/dist/chunk-BQX23RBV.js.map +1 -0
- package/dist/{chunk-IMDW5ZUP.js → chunk-CA4LH4LI.js} +5 -5
- package/dist/chunk-CA4LH4LI.js.map +1 -0
- package/dist/{chunk-D237EVNB.js → chunk-CBLPAMZO.js} +5 -8
- package/dist/chunk-CBLPAMZO.js.map +1 -0
- package/dist/{chunk-B7CCVP6Q.js → chunk-CKPQHGXR.js} +52 -274
- package/dist/chunk-CKPQHGXR.js.map +1 -0
- package/dist/{chunk-SVYPSDWY.js → chunk-CXOFOJCN.js} +6 -10
- package/dist/chunk-CXOFOJCN.js.map +1 -0
- package/dist/{chunk-UQTEPWU7.js → chunk-EHGD7HIE.js} +2 -6
- package/dist/chunk-EHGD7HIE.js.map +1 -0
- package/dist/{chunk-76DWXGQE.js → chunk-FJFEKPXF.js} +1 -1
- package/dist/chunk-FJFEKPXF.js.map +1 -0
- package/dist/{chunk-E3FJH4TF.js → chunk-HEOHU5EZ.js} +2 -13
- package/dist/chunk-HEOHU5EZ.js.map +1 -0
- package/dist/{chunk-JIPWV2FX.js → chunk-HGCBZUH5.js} +6 -27
- package/dist/chunk-HGCBZUH5.js.map +1 -0
- package/dist/{chunk-ED4E6Q2T.js → chunk-HPGFY5ZN.js} +4 -4
- package/dist/chunk-HPGFY5ZN.js.map +1 -0
- package/dist/chunk-INJ2EFRW.js +127 -0
- package/dist/chunk-INJ2EFRW.js.map +1 -0
- package/dist/{chunk-KAAEN2PO.js → chunk-IOBFMF6X.js} +6 -2
- package/dist/{chunk-KAAEN2PO.js.map → chunk-IOBFMF6X.js.map} +1 -1
- package/dist/{chunk-K7EVM5LY.js → chunk-KH3HA7J7.js} +8 -33
- package/dist/chunk-KH3HA7J7.js.map +1 -0
- package/dist/{chunk-4K4ZXQRM.js → chunk-N6JNE326.js} +38 -94
- package/dist/chunk-N6JNE326.js.map +1 -0
- package/dist/chunk-NAGU7TVZ.js +36 -0
- package/dist/chunk-NAGU7TVZ.js.map +1 -0
- package/dist/{chunk-Z7G4B5HJ.js → chunk-OQYYMQJR.js} +68 -142
- package/dist/chunk-OQYYMQJR.js.map +1 -0
- package/dist/{chunk-CPZOTVCI.js → chunk-PLZOUVDD.js} +185 -74
- package/dist/chunk-PLZOUVDD.js.map +1 -0
- package/dist/chunk-Q3J43SF3.js +21 -0
- package/dist/chunk-Q3J43SF3.js.map +1 -0
- package/dist/{chunk-3U3R4NCG.js → chunk-T25OEQFI.js} +6 -2
- package/dist/chunk-T25OEQFI.js.map +1 -0
- package/dist/chunk-UMORK7OK.js +29 -0
- package/dist/chunk-UMORK7OK.js.map +1 -0
- package/dist/{chunk-ZFPSUQOU.js → chunk-VFHWU7JU.js} +12 -121
- package/dist/chunk-VFHWU7JU.js.map +1 -0
- package/dist/{chunk-GDH553MV.js → chunk-VS4GVTZE.js} +3 -3
- package/dist/chunk-VS4GVTZE.js.map +1 -0
- package/dist/chunk-WFEFICFM.js +67 -0
- package/dist/chunk-WFEFICFM.js.map +1 -0
- package/dist/{chunk-P26A2K5N.js → chunk-WG6KIAPK.js} +6 -16
- package/dist/chunk-WG6KIAPK.js.map +1 -0
- package/dist/{chunk-X6QONICW.js → chunk-ZEI3ZUDU.js} +3 -7
- package/dist/chunk-ZEI3ZUDU.js.map +1 -0
- package/dist/chunk-ZNIDWLL5.js +68 -0
- package/dist/chunk-ZNIDWLL5.js.map +1 -0
- package/dist/chunk-ZSVMS677.js +45 -0
- package/dist/chunk-ZSVMS677.js.map +1 -0
- package/dist/cli/defaults/agent-mappings.yaml +13 -13
- package/dist/commands/build/marketplace.js +8 -14
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +10 -21
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +13 -18
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +25 -40
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +7 -7
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +6 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +5 -7
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +8 -9
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +8 -9
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +17 -40
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +14 -25
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +41 -54
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +24 -44
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +19 -39
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +10 -15
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +452 -451
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +85 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +9 -10
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +12 -16
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +12 -89
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +12 -18
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +12 -21
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +26 -146
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +407 -15
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +7 -23
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +6 -21
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +6 -23
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +6 -21
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/message.js +2 -6
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +1 -1
- package/dist/components/wizard/category-grid.js +1 -1
- package/dist/components/wizard/category-grid.test.js +20 -92
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/menu-item.js +9 -0
- package/dist/components/wizard/section-progress.js +1 -1
- package/dist/components/wizard/section-progress.test.js +13 -103
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/step-approach.js +5 -4
- package/dist/components/wizard/step-build.js +3 -4
- package/dist/components/wizard/step-build.test.js +81 -186
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +1 -2
- package/dist/components/wizard/step-refine.js +1 -2
- package/dist/components/wizard/step-refine.test.js +6 -14
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +5 -3
- package/dist/components/wizard/view-title.js +9 -0
- package/dist/components/wizard/wizard-layout.js +16 -0
- package/dist/components/wizard/wizard-layout.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +1 -1
- package/dist/components/wizard/wizard.js +12 -13
- package/dist/config/skills-matrix.yaml +180 -113
- package/dist/config/stacks.yaml +6 -6
- package/dist/hooks/init.js +5 -7
- package/dist/hooks/init.js.map +1 -1
- package/dist/src/agents/developer/web-developer/examples.md +1 -6
- package/dist/src/agents/meta/documentor/workflow.md +1 -5
- package/dist/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/dist/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +60 -23
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/developer/web-developer/examples.md +1 -6
- package/src/agents/meta/documentor/workflow.md +1 -5
- package/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/chunk-3U3R4NCG.js.map +0 -1
- package/dist/chunk-4K4ZXQRM.js.map +0 -1
- package/dist/chunk-6DCSSORF.js.map +0 -1
- package/dist/chunk-76DWXGQE.js.map +0 -1
- package/dist/chunk-7Q44DMSP.js.map +0 -1
- package/dist/chunk-ACNBKXXJ.js.map +0 -1
- package/dist/chunk-B7CCVP6Q.js.map +0 -1
- package/dist/chunk-BDLUZVKU.js +0 -54
- package/dist/chunk-BDLUZVKU.js.map +0 -1
- package/dist/chunk-CDX4W4DM.js.map +0 -1
- package/dist/chunk-CPZOTVCI.js.map +0 -1
- package/dist/chunk-D237EVNB.js.map +0 -1
- package/dist/chunk-DRXPNNPB.js +0 -393
- package/dist/chunk-DRXPNNPB.js.map +0 -1
- package/dist/chunk-E3FJH4TF.js.map +0 -1
- package/dist/chunk-ED4E6Q2T.js.map +0 -1
- package/dist/chunk-GDH553MV.js.map +0 -1
- package/dist/chunk-HLJX2FTL.js +0 -95
- package/dist/chunk-HLJX2FTL.js.map +0 -1
- package/dist/chunk-I2DSLOXZ.js +0 -75
- package/dist/chunk-I2DSLOXZ.js.map +0 -1
- package/dist/chunk-I4TPKIYX.js +0 -493
- package/dist/chunk-I4TPKIYX.js.map +0 -1
- package/dist/chunk-IBE7JIAG.js +0 -129
- package/dist/chunk-IBE7JIAG.js.map +0 -1
- package/dist/chunk-IMDW5ZUP.js.map +0 -1
- package/dist/chunk-JIPWV2FX.js.map +0 -1
- package/dist/chunk-K7EVM5LY.js.map +0 -1
- package/dist/chunk-NDY25DTL.js +0 -453
- package/dist/chunk-NDY25DTL.js.map +0 -1
- package/dist/chunk-P26A2K5N.js.map +0 -1
- package/dist/chunk-SVYPSDWY.js.map +0 -1
- package/dist/chunk-TKFPKEV3.js.map +0 -1
- package/dist/chunk-UQTEPWU7.js.map +0 -1
- package/dist/chunk-V46GGCCI.js.map +0 -1
- package/dist/chunk-X6QONICW.js.map +0 -1
- package/dist/chunk-Y2LW7R3Y.js +0 -23
- package/dist/chunk-Y2LW7R3Y.js.map +0 -1
- package/dist/chunk-Z7G4B5HJ.js.map +0 -1
- package/dist/chunk-ZENYS6KW.js +0 -90
- package/dist/chunk-ZENYS6KW.js.map +0 -1
- package/dist/chunk-ZFPSUQOU.js.map +0 -1
- package/dist/commands/config/set.js +0 -61
- package/dist/commands/config/set.js.map +0 -1
- package/dist/commands/config/unset.js +0 -57
- package/dist/commands/config/unset.js.map +0 -1
- package/dist/commands/test-imports.js +0 -92
- package/dist/commands/test-imports.js.map +0 -1
- package/dist/components/wizard/step-stack-options.js +0 -11
- package/dist/components/wizard/wizard-footer.js +0 -9
- /package/dist/components/wizard/{step-stack-options.js.map → menu-item.js.map} +0 -0
- /package/dist/components/wizard/{wizard-footer.js.map → view-title.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/stack-plugin-compiler.ts","../src/cli/lib/compiler.ts","../src/cli/lib/resolver.ts"],"sourcesContent":["import path from \"path\";\nimport { Liquid } from \"liquidjs\";\nimport {\n readFile,\n readFileOptional,\n writeFile,\n ensureDir,\n copy,\n fileExists,\n directoryExists,\n} from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { DIRS, PROJECT_ROOT, DEFAULT_VERSION } from \"../consts\";\nimport { createLiquidEngine } from \"./compiler\";\nimport {\n generateStackPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"./plugin-manifest\";\nimport { loadSkillsByIds, loadAllAgents } from \"./loader\";\nimport { loadStackById, resolveAgentConfigToSkills } from \"./stacks-loader\";\nimport { loadSkillsMatrix } from \"./matrix-loader\";\nimport { SKILLS_MATRIX_PATH } from \"../consts\";\nimport { resolveAgents, stackToCompileConfig } from \"./resolver\";\nimport type { Stack } from \"../types-stacks\";\nimport { hashString, getCurrentDate } from \"./versioning\";\nimport type {\n PluginManifest,\n ProjectConfig,\n AgentConfig,\n CompileConfig,\n Skill,\n CompiledAgentData,\n AgentHookDefinition,\n} from \"../../types\";\n\nconst CONTENT_HASH_FILE = \".content-hash\";\n\nfunction parseMajorVersion(version: string): number {\n const match = version.match(/^(\\d+)\\./);\n return match ? parseInt(match[1], 10) : 1;\n}\n\nfunction bumpMajorVersion(version: string): string {\n const major = parseMajorVersion(version);\n return `${major + 1}.0.0`;\n}\n\nasync function readExistingManifest(\n pluginDir: string,\n): Promise<{ version: string; contentHash: string | undefined } | null> {\n const manifestPath = getPluginManifestPath(pluginDir);\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n\n const hashFilePath = manifestPath.replace(\"plugin.json\", CONTENT_HASH_FILE);\n let contentHash: string | undefined;\n if (await fileExists(hashFilePath)) {\n contentHash = (await readFile(hashFilePath)).trim();\n }\n\n return {\n version: manifest.version ?? DEFAULT_VERSION,\n contentHash,\n };\n } catch {\n return null;\n }\n}\n\nfunction hashStackConfig(stack: ProjectConfig): string {\n const parts: string[] = [\n `name:${stack.name}`,\n `description:${stack.description ?? \"\"}`,\n `skills:${(stack.skills || [])\n .map((s) => (typeof s === \"string\" ? s : s.id))\n .sort()\n .join(\",\")}`,\n `agents:${(stack.agents || []).sort().join(\",\")}`,\n ];\n return hashString(parts.join(\"\\n\"));\n}\n\nasync function determineStackVersion(\n stack: ProjectConfig,\n pluginDir: string,\n): Promise<{ version: string; contentHash: string }> {\n const newHash = hashStackConfig(stack);\n\n const existing = await readExistingManifest(pluginDir);\n\n if (!existing) {\n return {\n version: DEFAULT_VERSION,\n contentHash: newHash,\n };\n }\n\n if (existing.contentHash !== newHash) {\n return {\n version: bumpMajorVersion(existing.version),\n contentHash: newHash,\n };\n }\n\n return {\n version: existing.version,\n contentHash: newHash,\n };\n}\n\nexport interface StackPluginOptions {\n stackId: string;\n outputDir: string;\n projectRoot: string;\n agentSourcePath?: string;\n /** Optional stack configuration - if provided, bypasses loading from config/stacks.yaml */\n stack?: Stack;\n}\n\nexport interface CompiledStackPlugin {\n pluginPath: string;\n manifest: PluginManifest;\n stackName: string;\n agents: string[];\n skillPlugins: string[];\n hasHooks: boolean;\n}\n\nexport async function compileAgentForPlugin(\n name: string,\n agent: AgentConfig,\n fallbackRoot: string,\n engine: Liquid,\n): Promise<string> {\n verbose(`Compiling agent: ${name}`);\n\n // Use agent's sourceRoot if available (for multi-source loading), otherwise fallback\n const agentSourceRoot = agent.sourceRoot || fallbackRoot;\n // Use agent's agentBaseDir if available (for project agents in .claude-src/agents/)\n const agentBaseDir = agent.agentBaseDir || DIRS.agents;\n const agentDir = path.join(agentSourceRoot, agentBaseDir, agent.path || name);\n\n const intro = await readFile(path.join(agentDir, \"intro.md\"));\n const workflow = await readFile(path.join(agentDir, \"workflow.md\"));\n const examples = await readFileOptional(\n path.join(agentDir, \"examples.md\"),\n \"## Examples\\n\\n_No examples defined._\",\n );\n const criticalRequirementsTop = await readFileOptional(\n path.join(agentDir, \"critical-requirements.md\"),\n \"\",\n );\n const criticalReminders = await readFileOptional(\n path.join(agentDir, \"critical-reminders.md\"),\n \"\",\n );\n\n const agentPath = agent.path || name;\n const category = agentPath.split(\"/\")[0];\n const categoryDir = path.join(agentSourceRoot, agentBaseDir, category);\n\n let outputFormat = await readFileOptional(path.join(agentDir, \"output-format.md\"), \"\");\n if (!outputFormat) {\n outputFormat = await readFileOptional(path.join(categoryDir, \"output-format.md\"), \"\");\n }\n\n const preloadedSkills = agent.skills.filter((s) => s.preloaded);\n const dynamicSkills = agent.skills.filter((s) => !s.preloaded);\n\n const preloadedSkillIds = preloadedSkills.map((s) => s.id);\n\n verbose(\n `Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`,\n );\n\n const data: CompiledAgentData = {\n agent,\n intro,\n workflow,\n examples,\n criticalRequirementsTop,\n criticalReminders,\n outputFormat,\n skills: agent.skills,\n preloadedSkills,\n dynamicSkills,\n preloadedSkillIds,\n };\n\n return engine.renderFile(\"agent\", data);\n}\n\nfunction generateStackReadme(\n stackId: string,\n stack: ProjectConfig,\n agents: string[],\n skillPlugins: string[],\n): string {\n const lines: string[] = [];\n\n lines.push(`# ${stack.name}`);\n lines.push(\"\");\n lines.push(stack.description || \"A Claude Code stack plugin.\");\n lines.push(\"\");\n\n if (stack.tags && stack.tags.length > 0) {\n lines.push(\"## Tags\");\n lines.push(\"\");\n lines.push(stack.tags.map((t) => `\\`${t}\\``).join(\" \"));\n lines.push(\"\");\n }\n\n lines.push(\"## Installation\");\n lines.push(\"\");\n lines.push(\"Add this plugin to your Claude Code configuration:\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(`{`);\n lines.push(` \"plugins\": [\"${stackId}\"]`);\n lines.push(`}`);\n lines.push(\"```\");\n lines.push(\"\");\n\n lines.push(\"## Agents\");\n lines.push(\"\");\n lines.push(\"This stack includes the following agents:\");\n lines.push(\"\");\n for (const agent of agents) {\n lines.push(`- \\`${agent}\\``);\n }\n lines.push(\"\");\n\n if (skillPlugins.length > 0) {\n lines.push(\"## Included Skills\");\n lines.push(\"\");\n lines.push(\"This stack includes the following skills:\");\n lines.push(\"\");\n const uniqueSkills = [...new Set(skillPlugins)].sort();\n for (const skill of uniqueSkills) {\n lines.push(`- \\`${skill}\\``);\n }\n lines.push(\"\");\n }\n\n if (stack.philosophy) {\n lines.push(\"## Philosophy\");\n lines.push(\"\");\n lines.push(stack.philosophy);\n lines.push(\"\");\n }\n\n if (stack.principles && stack.principles.length > 0) {\n lines.push(\"## Principles\");\n lines.push(\"\");\n for (const principle of stack.principles) {\n lines.push(`- ${principle}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(\"*Generated by Claude Collective stack-plugin-compiler*\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\ninterface HooksJsonOutput {\n hooks: Record<string, AgentHookDefinition[]>;\n}\n\nfunction stackHasHooks(stack: ProjectConfig): boolean {\n return stack.hooks !== undefined && Object.keys(stack.hooks).length > 0;\n}\n\nfunction generateHooksJson(hooks: Record<string, AgentHookDefinition[]>): string {\n const output: HooksJsonOutput = { hooks };\n return JSON.stringify(output, null, 2);\n}\n\nexport async function compileStackPlugin(\n options: StackPluginOptions,\n): Promise<CompiledStackPlugin> {\n const { stackId, outputDir, projectRoot, agentSourcePath } = options;\n const localAgentRoot = agentSourcePath || projectRoot;\n\n verbose(`Compiling stack plugin: ${stackId}`);\n verbose(` Stack/skills source: ${projectRoot}`);\n verbose(` Local agent source: ${localAgentRoot}`);\n verbose(` CLI agent source: ${PROJECT_ROOT}`);\n\n // Load agents from both local project and CLI, with local taking precedence\n const cliAgents = await loadAllAgents(PROJECT_ROOT);\n const localAgents = await loadAllAgents(localAgentRoot);\n const agents = { ...cliAgents, ...localAgents };\n\n verbose(\n ` Loaded ${Object.keys(localAgents).length} local agents, ${Object.keys(cliAgents).length} CLI agents`,\n );\n\n // Use provided stack or load from CLI's config/stacks.yaml\n const newStack = options.stack || (await loadStackById(stackId, PROJECT_ROOT));\n\n // Load skill aliases from the matrix to resolve technology aliases to skill IDs\n // This is needed for Phase 7 skill resolution in resolveAgents\n const matrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n const matrix = await loadSkillsMatrix(matrixPath);\n const skillAliases = matrix.skill_aliases || {};\n\n let stack: ProjectConfig;\n if (newStack) {\n verbose(` Found stack: ${newStack.name}`);\n\n // Extract skills from stack's agent configurations (Phase 7: skills in stacks, not agents)\n const agentSkillIds = new Set<string>();\n for (const agentName of Object.keys(newStack.agents)) {\n const agentConfig = newStack.agents[agentName];\n const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);\n for (const ref of skillRefs) {\n agentSkillIds.add(ref.id);\n }\n }\n\n // Build ProjectConfig for rest of function\n stack = {\n name: newStack.name,\n description: newStack.description,\n skills: Array.from(agentSkillIds).map((id) => ({ id })),\n agents: Object.keys(newStack.agents),\n philosophy: newStack.philosophy,\n };\n } else {\n throw new Error(`Stack '${stackId}' not found in config/stacks.yaml`);\n }\n\n const normalizedSkillIds = (stack.skills || []).map((s) =>\n typeof s === \"string\" ? { id: s } : s,\n );\n const skills = await loadSkillsByIds(normalizedSkillIds, projectRoot);\n\n const compileConfig: CompileConfig = stackToCompileConfig(stackId, stack);\n\n // Pass newStack and skillAliases for Phase 7 skill resolution\n const resolvedAgents = await resolveAgents(\n agents,\n skills,\n compileConfig,\n projectRoot,\n newStack,\n skillAliases,\n );\n\n const pluginDir = path.join(outputDir, stackId);\n const agentsDir = path.join(pluginDir, \"agents\");\n\n await ensureDir(pluginDir);\n await ensureDir(agentsDir);\n\n const pluginSkillsDir = path.join(pluginDir, \"skills\");\n await ensureDir(pluginSkillsDir);\n\n const copiedSourcePaths = new Set<string>();\n\n for (const [, resolvedSkill] of Object.entries(skills)) {\n const sourceSkillDir = path.join(projectRoot, resolvedSkill.path);\n\n if (copiedSourcePaths.has(resolvedSkill.path)) {\n continue;\n }\n\n const destSkillDir = path.join(pluginSkillsDir, resolvedSkill.canonicalId);\n\n if (await directoryExists(sourceSkillDir)) {\n await copy(sourceSkillDir, destSkillDir);\n copiedSourcePaths.add(resolvedSkill.path);\n verbose(` Copied skill: ${resolvedSkill.canonicalId}`);\n } else {\n verbose(` Warning: Skill directory not found: ${sourceSkillDir}`);\n }\n }\n\n const engine = await createLiquidEngine();\n\n const compiledAgentNames: string[] = [];\n const allSkillPlugins: string[] = [];\n\n for (const [name, agent] of Object.entries(resolvedAgents)) {\n const output = await compileAgentForPlugin(name, agent, PROJECT_ROOT, engine);\n await writeFile(path.join(agentsDir, `${name}.md`), output);\n compiledAgentNames.push(name);\n\n for (const skill of agent.skills) {\n allSkillPlugins.push(skill.id);\n }\n\n verbose(` Compiled agent: ${name}`);\n }\n\n const stackDir = path.join(projectRoot, DIRS.stacks, stackId);\n const claudeMdPath = path.join(stackDir, \"CLAUDE.md\");\n if (await fileExists(claudeMdPath)) {\n const claudeContent = await readFile(claudeMdPath);\n await writeFile(path.join(pluginDir, \"CLAUDE.md\"), claudeContent);\n verbose(` Copied CLAUDE.md`);\n }\n\n const hasHooks = stackHasHooks(stack);\n if (hasHooks && stack.hooks) {\n const hooksDir = path.join(pluginDir, \"hooks\");\n await ensureDir(hooksDir);\n const hooksJson = generateHooksJson(stack.hooks);\n await writeFile(path.join(hooksDir, \"hooks.json\"), hooksJson);\n verbose(` Generated hooks/hooks.json`);\n }\n\n const { version, contentHash } = await determineStackVersion(stack, pluginDir);\n\n const uniqueSkillPlugins = [...new Set(allSkillPlugins)];\n const manifest = generateStackPluginManifest({\n stackName: stackId,\n description: stack.description,\n author: stack.author,\n version,\n keywords: stack.tags,\n hasAgents: true,\n hasHooks,\n hasSkills: true,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n const hashFilePath = getPluginManifestPath(pluginDir).replace(\"plugin.json\", CONTENT_HASH_FILE);\n await writeFile(hashFilePath, contentHash);\n\n verbose(` Wrote plugin.json (v${version})`);\n\n const readme = generateStackReadme(stackId, stack, compiledAgentNames, uniqueSkillPlugins);\n await writeFile(path.join(pluginDir, \"README.md\"), readme);\n verbose(` Generated README.md`);\n\n return {\n pluginPath: pluginDir,\n manifest,\n stackName: stack.name,\n agents: compiledAgentNames,\n skillPlugins: uniqueSkillPlugins,\n hasHooks,\n };\n}\n\nexport function printStackCompilationSummary(result: CompiledStackPlugin): void {\n console.log(`\\nStack plugin compiled: ${result.stackName}`);\n console.log(` Path: ${result.pluginPath}`);\n console.log(` Agents: ${result.agents.length}`);\n for (const agent of result.agents) {\n console.log(` - ${agent}`);\n }\n if (result.skillPlugins.length > 0) {\n console.log(` Skills included: ${result.skillPlugins.length}`);\n for (const skill of result.skillPlugins) {\n console.log(` - ${skill}`);\n }\n }\n if (result.hasHooks) {\n console.log(` Hooks: enabled`);\n }\n}\n","import { Liquid } from \"liquidjs\";\nimport path from \"path\";\nimport {\n readFile,\n readFileOptional,\n writeFile,\n ensureDir,\n remove,\n copy,\n glob,\n fileExists,\n directoryExists,\n} from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR, DIRS, OUTPUT_DIR, PROJECT_ROOT } from \"../consts\";\nimport { resolveClaudeMd } from \"./resolver\";\nimport { validateCompiledAgent, printOutputValidationResult } from \"./output-validator\";\nimport type {\n Skill,\n AgentConfig,\n CompiledAgentData,\n CompileConfig,\n CompileContext,\n} from \"../types\";\n\nasync function compileAgent(\n name: string,\n agent: AgentConfig,\n projectRoot: string,\n engine: Liquid,\n): Promise<string> {\n verbose(`Reading agent files for ${name}...`);\n\n // Use agent's sourceRoot and agentBaseDir if available (for project agents in .claude-src/agents/)\n const agentSourceRoot = agent.sourceRoot || projectRoot;\n const agentBaseDir = agent.agentBaseDir || DIRS.agents;\n const agentDir = path.join(agentSourceRoot, agentBaseDir, agent.path || name);\n\n const intro = await readFile(path.join(agentDir, \"intro.md\"));\n const workflow = await readFile(path.join(agentDir, \"workflow.md\"));\n const examples = await readFileOptional(\n path.join(agentDir, \"examples.md\"),\n \"## Examples\\n\\n_No examples defined._\",\n );\n const criticalRequirementsTop = await readFileOptional(\n path.join(agentDir, \"critical-requirements.md\"),\n \"\",\n );\n const criticalReminders = await readFileOptional(\n path.join(agentDir, \"critical-reminders.md\"),\n \"\",\n );\n\n const agentPath = agent.path || name;\n const category = agentPath.split(\"/\")[0];\n const categoryDir = path.join(agentSourceRoot, agentBaseDir, category);\n\n let outputFormat = await readFileOptional(path.join(agentDir, \"output-format.md\"), \"\");\n if (!outputFormat) {\n outputFormat = await readFileOptional(path.join(categoryDir, \"output-format.md\"), \"\");\n }\n\n const preloadedSkills = agent.skills.filter((s) => s.preloaded);\n const dynamicSkills = agent.skills.filter((s) => !s.preloaded);\n const preloadedSkillIds = preloadedSkills.map((s) => s.id);\n\n verbose(\n `Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`,\n );\n\n const data: CompiledAgentData = {\n agent,\n intro,\n workflow,\n examples,\n criticalRequirementsTop,\n criticalReminders,\n outputFormat,\n skills: agent.skills,\n preloadedSkills,\n dynamicSkills,\n preloadedSkillIds,\n };\n\n verbose(`Rendering template for ${name}...`);\n return engine.renderFile(\"agent\", data);\n}\n\nexport async function compileAllAgents(\n resolvedAgents: Record<string, AgentConfig>,\n config: CompileConfig,\n ctx: CompileContext,\n engine: Liquid,\n): Promise<void> {\n const outDir = path.join(ctx.outputDir, \"agents\");\n await ensureDir(outDir);\n\n let hasValidationIssues = false;\n\n for (const [name, agent] of Object.entries(resolvedAgents)) {\n try {\n const output = await compileAgent(name, agent, ctx.projectRoot, engine);\n await writeFile(path.join(outDir, `${name}.md`), output);\n console.log(` ✓ ${name}.md`);\n\n const validationResult = validateCompiledAgent(output);\n if (!validationResult.valid || validationResult.warnings.length > 0) {\n hasValidationIssues = true;\n printOutputValidationResult(name, validationResult);\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(` ✗ ${name}.md - ${errorMessage}`);\n throw new Error(\n `Failed to compile agent '${name}': ${errorMessage}. Check that all required files exist in src/agents/${agent.path || name}/`,\n );\n }\n }\n\n if (hasValidationIssues) {\n console.log(\"\");\n }\n}\n\nexport async function compileAllSkills(\n resolvedAgents: Record<string, AgentConfig>,\n ctx: CompileContext,\n): Promise<void> {\n const allSkills = Object.values(resolvedAgents)\n .flatMap((a) => a.skills)\n .filter((s) => s.path);\n\n const uniqueSkills = [...new Map(allSkills.map((s) => [s.id, s])).values()];\n\n for (const skill of uniqueSkills) {\n const id = skill.id.replace(\"/\", \"-\");\n const outDir = path.join(ctx.outputDir, \"skills\", id);\n await ensureDir(outDir);\n\n const sourcePath = path.join(ctx.projectRoot, skill.path);\n const isFolder = skill.path.endsWith(\"/\");\n\n try {\n if (isFolder) {\n const mainContent = await readFile(path.join(sourcePath, \"SKILL.md\"));\n await writeFile(path.join(outDir, \"SKILL.md\"), mainContent);\n console.log(` ✓ skills/${id}/SKILL.md`);\n\n const referenceContent = await readFileOptional(path.join(sourcePath, \"reference.md\"));\n if (referenceContent) {\n await writeFile(path.join(outDir, \"reference.md\"), referenceContent);\n console.log(` ✓ skills/${id}/reference.md`);\n }\n\n const examplesDir = path.join(sourcePath, \"examples\");\n if (await fileExists(examplesDir)) {\n await copy(examplesDir, path.join(outDir, \"examples\"));\n console.log(` ✓ skills/${id}/examples/`);\n }\n\n const scriptsDir = path.join(sourcePath, \"scripts\");\n if (await fileExists(scriptsDir)) {\n await copy(scriptsDir, path.join(outDir, \"scripts\"));\n console.log(` ✓ skills/${id}/scripts/`);\n }\n } else {\n const content = await readFile(sourcePath);\n await writeFile(path.join(outDir, \"SKILL.md\"), content);\n console.log(` ✓ skills/${id}/SKILL.md`);\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(` ✗ skills/${id}/SKILL.md - ${errorMessage}`);\n throw new Error(\n `Failed to compile skill '${skill.id}': ${errorMessage}. Expected skill at: ${sourcePath}`,\n );\n }\n }\n}\n\nexport async function copyClaude(ctx: CompileContext): Promise<void> {\n const claudePath = await resolveClaudeMd(ctx.projectRoot, ctx.stackId, ctx.mode);\n\n const content = await readFile(claudePath);\n const outputPath = path.join(ctx.outputDir, \"..\", \"CLAUDE.md\");\n await writeFile(outputPath, content);\n console.log(` ✓ CLAUDE.md (from stack)`);\n}\n\nexport async function compileAllCommands(ctx: CompileContext): Promise<void> {\n const commandsDir = path.join(ctx.projectRoot, DIRS.commands);\n const outDir = path.join(ctx.outputDir, \"commands\");\n\n if (!(await fileExists(commandsDir))) {\n console.log(\" - No commands directory found, skipping...\");\n return;\n }\n\n const files = await glob(\"*.md\", commandsDir);\n\n if (files.length === 0) {\n console.log(\" - No commands found, skipping...\");\n return;\n }\n\n await ensureDir(outDir);\n\n for (const file of files) {\n try {\n const content = await readFile(path.join(commandsDir, file));\n await writeFile(path.join(outDir, file), content);\n console.log(` ✓ ${file}`);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(` ✗ ${file} - ${errorMessage}`);\n throw new Error(\n `Failed to compile command '${file}': ${errorMessage}. Expected at: ${path.join(commandsDir, file)}`,\n );\n }\n }\n}\n\nexport async function createLiquidEngine(projectDir?: string): Promise<Liquid> {\n const roots: string[] = [];\n\n if (projectDir) {\n // Check .claude-src/agents/_templates/ FIRST (new location)\n const srcTemplatesDir = path.join(projectDir, CLAUDE_SRC_DIR, \"agents\", \"_templates\");\n if (await directoryExists(srcTemplatesDir)) {\n roots.push(srcTemplatesDir);\n verbose(`Using local templates from: ${srcTemplatesDir}`);\n }\n\n // Then check .claude/templates/ as fallback (legacy location)\n const legacyTemplatesDir = path.join(projectDir, CLAUDE_DIR, \"templates\");\n if (await directoryExists(legacyTemplatesDir)) {\n roots.push(legacyTemplatesDir);\n verbose(`Using legacy templates from: ${legacyTemplatesDir}`);\n }\n }\n\n roots.push(path.join(PROJECT_ROOT, DIRS.templates));\n\n return new Liquid({\n root: roots,\n extname: \".liquid\",\n strictVariables: false,\n strictFilters: true,\n });\n}\n\nexport async function cleanOutputDir(outputDir: string): Promise<void> {\n await remove(path.join(outputDir, \"agents\"));\n await remove(path.join(outputDir, \"skills\"));\n await remove(path.join(outputDir, \"commands\"));\n}\n","import path from \"path\";\nimport { fileExists } from \"../utils/fs\";\nimport { getDirs, type CompileMode } from \"./loader\";\nimport { verbose } from \"../utils/logger\";\nimport type {\n AgentConfig,\n AgentDefinition,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n Skill,\n SkillAssignment,\n SkillDefinition,\n SkillEntry,\n SkillReference,\n} from \"../types\";\nimport type { Stack, StackAgentConfig } from \"../types-stacks\";\n\nexport async function resolveTemplate(\n projectRoot: string,\n stackId: string,\n mode: CompileMode = \"dev\",\n): Promise<string> {\n const dirs = getDirs(mode);\n const stackTemplate = path.join(projectRoot, dirs.stacks, stackId, \"agent.liquid\");\n if (await fileExists(stackTemplate)) return stackTemplate;\n\n return path.join(projectRoot, dirs.templates, \"agent.liquid\");\n}\n\nexport async function resolveClaudeMd(\n projectRoot: string,\n stackId: string,\n mode: CompileMode = \"dev\",\n): Promise<string> {\n const dirs = getDirs(mode);\n const stackClaude = path.join(projectRoot, dirs.stacks, stackId, \"CLAUDE.md\");\n if (await fileExists(stackClaude)) return stackClaude;\n\n throw new Error(\n `Stack '${stackId}' is missing required CLAUDE.md file. Expected at: ${stackClaude}`,\n );\n}\n\nexport function resolveSkillReference(\n ref: SkillReference,\n skills: Record<string, SkillDefinition>,\n): Skill | null {\n const definition = skills[ref.id];\n if (!definition) {\n verbose(`Skill '${ref.id}' not found in available skills, skipping`);\n return null;\n }\n return {\n id: ref.id,\n path: definition.path,\n name: definition.name,\n description: definition.description,\n usage: ref.usage,\n preloaded: ref.preloaded ?? false,\n };\n}\n\nexport function resolveSkillReferences(\n skillRefs: SkillReference[],\n skills: Record<string, SkillDefinition>,\n): Skill[] {\n return skillRefs\n .map((ref) => resolveSkillReference(ref, skills))\n .filter((skill): skill is Skill => skill !== null);\n}\n\nfunction getStackSkillIds(stackSkills: SkillAssignment[]): string[] {\n return stackSkills.map((s) => s.id);\n}\n\nfunction flattenAgentSkills(\n categorizedSkills: Record<string, SkillAssignment[]>,\n): SkillAssignment[] {\n const assignments: SkillAssignment[] = [];\n for (const category of Object.keys(categorizedSkills)) {\n assignments.push(...categorizedSkills[category]);\n }\n return assignments;\n}\n\nfunction normalizeSkillEntry(entry: SkillEntry): SkillAssignment {\n if (typeof entry === \"string\") {\n return { id: entry };\n }\n return entry;\n}\n\nfunction expandSkillIdIfDirectory(\n skillId: string,\n skills: Record<string, SkillDefinition>,\n): string[] {\n if (skills[skillId]) {\n return [skillId];\n }\n\n // Use path as unique key to deduplicate (both frontmatter name and directory path map to same skill)\n const allSkillIds = Object.keys(skills);\n const seenPaths = new Set<string>();\n const matchingSkills: string[] = [];\n\n for (const id of allSkillIds) {\n const skillDef = skills[id];\n if (skillDef.path.startsWith(`src/skills/${skillId}/`)) {\n if (!seenPaths.has(skillDef.path)) {\n seenPaths.add(skillDef.path);\n matchingSkills.push(id);\n }\n }\n }\n\n if (matchingSkills.length > 0) {\n return matchingSkills;\n }\n\n return [skillId];\n}\n\n/**\n * Subcategories considered \"key\" skills that should be preloaded.\n * These are primary technology choices that define the stack's core.\n */\nconst KEY_SUBCATEGORIES = new Set([\n \"framework\",\n \"api\",\n \"database\",\n \"meta-framework\",\n \"base-framework\",\n \"platform\",\n]);\n\n/**\n * Resolve skills for an agent from a Stack definition (Phase 7 format).\n * Takes a stack and skill aliases, returns skill references for the specified agent.\n *\n * @param agentName - The agent ID to resolve skills for\n * @param stack - The stack definition with agent technology selections\n * @param skillAliases - Mapping from technology aliases to full skill IDs\n * @returns Array of SkillReference objects for the agent\n *\n * @example\n * ```typescript\n * const stack = {\n * id: 'nextjs-fullstack',\n * agents: {\n * 'web-developer': { framework: 'react', styling: 'scss-modules' }\n * }\n * };\n *\n * const aliases = { react: 'web-framework-react', ... };\n *\n * const skills = resolveAgentSkillsFromStack('web-developer', stack, aliases);\n * // Returns: [{ id: 'web-framework-react', usage: '...', preloaded: true }, ...]\n * ```\n */\nexport function resolveAgentSkillsFromStack(\n agentName: string,\n stack: Stack,\n skillAliases: Record<string, string>,\n): SkillReference[] {\n const agentConfig = stack.agents[agentName];\n\n // Agent not in this stack\n if (!agentConfig) {\n verbose(`Agent '${agentName}' not found in stack '${stack.id}'`);\n return [];\n }\n\n // Empty config {} means agent has no technology-specific skills\n if (Object.keys(agentConfig).length === 0) {\n verbose(`Agent '${agentName}' has no technology config in stack '${stack.id}'`);\n return [];\n }\n\n const skillRefs: SkillReference[] = [];\n\n for (const [subcategory, technologyAlias] of Object.entries(agentConfig)) {\n const fullSkillId = skillAliases[technologyAlias];\n\n if (!fullSkillId) {\n verbose(\n `Warning: No skill alias found for '${technologyAlias}' (agent: ${agentName}, subcategory: ${subcategory}). Skipping.`,\n );\n continue;\n }\n\n const isKeySkill = KEY_SUBCATEGORIES.has(subcategory);\n\n skillRefs.push({\n id: fullSkillId,\n usage: `when working with ${subcategory}`,\n preloaded: isKeySkill,\n });\n }\n\n verbose(`Resolved ${skillRefs.length} skills for agent '${agentName}' from stack '${stack.id}'`);\n\n return skillRefs;\n}\n\nexport function resolveStackSkills(\n stack: ProjectConfig,\n agentName: string,\n skills: Record<string, SkillDefinition>,\n): SkillReference[] {\n const skillRefs: SkillReference[] = [];\n\n const rawAgentSkills = stack.agent_skills?.[agentName];\n const normalizedSkills: SkillAssignment[] = (stack.skills ?? []).map(normalizeSkillEntry);\n\n let assignments: SkillAssignment[];\n if (rawAgentSkills) {\n if (Array.isArray(rawAgentSkills)) {\n // Simple list format: SkillEntry[]\n assignments = rawAgentSkills.map(normalizeSkillEntry);\n } else {\n // Categorized format: Record<string, SkillEntry[]>\n const normalized: Record<string, SkillAssignment[]> = {};\n for (const [category, entries] of Object.entries(rawAgentSkills)) {\n normalized[category] = entries.map(normalizeSkillEntry);\n }\n assignments = flattenAgentSkills(normalized);\n }\n } else {\n assignments = normalizedSkills;\n }\n\n const validSkillIds = new Set<string>();\n for (const s of normalizedSkills) {\n const expandedIds = expandSkillIdIfDirectory(s.id, skills);\n for (const id of expandedIds) {\n validSkillIds.add(id);\n }\n }\n\n const addedSkills = new Set<string>();\n\n for (const assignment of assignments) {\n const skillId = assignment.id;\n const expandedSkillIds = expandSkillIdIfDirectory(skillId, skills);\n\n for (const expandedId of expandedSkillIds) {\n if (addedSkills.has(expandedId)) {\n continue;\n }\n\n if (!skills[expandedId]) {\n throw new Error(\n `Stack \"${stack.name}\" references skill \"${expandedId}\" for agent \"${agentName}\" not found in scanned skills`,\n );\n }\n\n if (rawAgentSkills && !validSkillIds.has(expandedId)) {\n throw new Error(\n `Stack \"${stack.name}\" agent_skills for \"${agentName}\" includes skill \"${expandedId}\" not in stack's skills array`,\n );\n }\n\n const skillDef = skills[expandedId];\n skillRefs.push({\n id: expandedId,\n usage: `when working with ${skillDef.name.toLowerCase()}`,\n preloaded: assignment.preloaded ?? false,\n });\n\n addedSkills.add(expandedId);\n }\n }\n\n return skillRefs;\n}\n\n/**\n * Options for getAgentSkills function.\n * Supports stack-based (Phase 7) configurations.\n */\nexport interface GetAgentSkillsOptions {\n /** The agent name/ID */\n agentName: string;\n /** Per-agent compile config (may have explicit skills) */\n agentConfig: CompileAgentConfig;\n /** Overall compile config */\n compileConfig: CompileConfig;\n /** All available skill definitions */\n skills: Record<string, SkillDefinition>;\n /** Project root path */\n projectRoot: string;\n /** Stack definition (Phase 7) */\n stack?: Stack;\n /** Skill aliases mapping (Phase 7) */\n skillAliases?: Record<string, string>;\n}\n\n/**\n * Get skill references for an agent.\n * Supports multiple resolution strategies with the following priority:\n *\n * 1. Explicit skills in compile config (agentConfig.skills)\n * 2. Stack-based skills (Phase 7) if stack and skillAliases provided\n *\n * @param options - Configuration options for skill resolution\n * @returns Array of SkillReference objects\n */\nexport async function getAgentSkills(\n agentName: string,\n agentConfig: CompileAgentConfig,\n _compileConfig: CompileConfig,\n _skills: Record<string, SkillDefinition>,\n _projectRoot: string,\n stack?: Stack,\n skillAliases?: Record<string, string>,\n): Promise<SkillReference[]> {\n // Priority 1: Explicit skills in compile config\n if (agentConfig.skills && agentConfig.skills.length > 0) {\n return agentConfig.skills;\n }\n\n // Priority 2: Stack-based skills (Phase 7)\n if (stack && skillAliases) {\n const stackSkills = resolveAgentSkillsFromStack(agentName, stack, skillAliases);\n if (stackSkills.length > 0) {\n verbose(`Resolved ${stackSkills.length} skills from stack for ${agentName}`);\n return stackSkills;\n }\n }\n\n // No skills defined for this agent\n return [];\n}\n\n/**\n * Options for resolveAgents function.\n */\nexport interface ResolveAgentsOptions {\n /** All loaded agent definitions */\n agents: Record<string, AgentDefinition>;\n /** All loaded skill definitions */\n skills: Record<string, SkillDefinition>;\n /** Compile configuration */\n compileConfig: CompileConfig;\n /** Project root path */\n projectRoot: string;\n /** Stack definition (Phase 7) - optional */\n stack?: Stack;\n /** Skill aliases mapping (Phase 7) - optional */\n skillAliases?: Record<string, string>;\n}\n\nexport async function resolveAgents(\n agents: Record<string, AgentDefinition>,\n skills: Record<string, SkillDefinition>,\n compileConfig: CompileConfig,\n projectRoot: string,\n stack?: Stack,\n skillAliases?: Record<string, string>,\n): Promise<Record<string, AgentConfig>> {\n const resolved: Record<string, AgentConfig> = {};\n const agentNames = Object.keys(compileConfig.agents);\n\n for (const agentName of agentNames) {\n const definition = agents[agentName];\n if (!definition) {\n const availableAgents = Object.keys(agents);\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 agents found in scanned directories\";\n throw new Error(\n `Agent '${agentName}' referenced in compile config but not found in scanned agents. ${agentList}. Check that src/agents/${agentName}/agent.yaml exists.`,\n );\n }\n\n const agentConfig = compileConfig.agents[agentName];\n\n const skillRefs = await getAgentSkills(\n agentName,\n agentConfig,\n compileConfig,\n skills,\n projectRoot,\n stack,\n skillAliases,\n );\n\n const resolvedSkills = resolveSkillReferences(skillRefs, skills);\n\n resolved[agentName] = {\n name: agentName,\n title: definition.title,\n description: definition.description,\n model: definition.model,\n tools: definition.tools,\n skills: resolvedSkills,\n path: definition.path,\n sourceRoot: definition.sourceRoot,\n agentBaseDir: definition.agentBaseDir,\n };\n }\n\n return resolved;\n}\n\nexport function stackToCompileConfig(stackId: string, stack: ProjectConfig): CompileConfig {\n const agents: Record<string, CompileAgentConfig> = {};\n\n for (const agentId of stack.agents) {\n agents[agentId] = {};\n }\n\n return {\n name: stack.name,\n description: stack.description || \"\",\n claude_md: \"\",\n stack: stackId,\n agents,\n };\n}\n"],"mappings":"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","names":["path","path"]}
|
|
@@ -1,60 +1,89 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ViewTitle
|
|
4
|
+
} from "./chunk-Q3J43SF3.js";
|
|
5
|
+
import {
|
|
6
|
+
MenuItem
|
|
7
|
+
} from "./chunk-UMORK7OK.js";
|
|
2
8
|
import {
|
|
3
9
|
useWizardStore
|
|
4
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CBLPAMZO.js";
|
|
5
11
|
import {
|
|
6
12
|
init_esm_shims
|
|
7
13
|
} from "./chunk-DHET7RCE.js";
|
|
8
14
|
|
|
9
15
|
// src/cli/components/wizard/step-stack.tsx
|
|
10
16
|
init_esm_shims();
|
|
11
|
-
import {
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Box, Text, useInput } from "ink";
|
|
12
19
|
import { Select } from "@inkjs/ui";
|
|
13
20
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
21
|
var BACK_VALUE = "_back";
|
|
15
22
|
var CONTINUE_VALUE = "_continue";
|
|
23
|
+
var INITIAL_FOCUSED_INDEX = 0;
|
|
16
24
|
var AVAILABLE_DOMAINS = [
|
|
17
25
|
{ id: "web", label: "Web", description: "Frontend web applications" },
|
|
26
|
+
{
|
|
27
|
+
id: "web-extras",
|
|
28
|
+
label: "Web Extras",
|
|
29
|
+
description: "Animation, files, realtime, PWA, accessibility"
|
|
30
|
+
},
|
|
18
31
|
{ id: "api", label: "API", description: "Backend APIs and services" },
|
|
19
32
|
{ id: "cli", label: "CLI", description: "Command-line tools" },
|
|
20
33
|
{ id: "mobile", label: "Mobile", description: "Mobile applications" }
|
|
21
34
|
];
|
|
22
35
|
var StackSelection = ({ matrix }) => {
|
|
23
|
-
const { selectStack, setStep, goBack } = useWizardStore();
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}))
|
|
30
|
-
];
|
|
31
|
-
const handleSelect = (value) => {
|
|
32
|
-
if (value === BACK_VALUE) {
|
|
36
|
+
const { selectStack, setStep, setStackAction, populateFromStack, goBack } = useWizardStore();
|
|
37
|
+
const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);
|
|
38
|
+
const stacks = matrix.suggestedStacks;
|
|
39
|
+
const stackCount = stacks.length;
|
|
40
|
+
useInput((input, key) => {
|
|
41
|
+
if (key.escape) {
|
|
33
42
|
goBack();
|
|
34
43
|
return;
|
|
35
44
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
if (key.return && stackCount > 0) {
|
|
46
|
+
const focusedStack = stacks[focusedIndex];
|
|
47
|
+
if (focusedStack) {
|
|
48
|
+
selectStack(focusedStack.id);
|
|
49
|
+
setStackAction("customize");
|
|
50
|
+
const resolvedStack = matrix.suggestedStacks.find((s) => s.id === focusedStack.id);
|
|
51
|
+
if (resolvedStack) {
|
|
52
|
+
const pseudoAgents = {};
|
|
53
|
+
for (let i = 0; i < resolvedStack.allSkillIds.length; i++) {
|
|
54
|
+
const skillId = resolvedStack.allSkillIds[i];
|
|
55
|
+
const skill = matrix.skills[skillId];
|
|
56
|
+
if (skill?.category) {
|
|
57
|
+
const displayId = skill.alias || skill.id;
|
|
58
|
+
pseudoAgents[`s${i}`] = { [skill.category]: displayId };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
populateFromStack({ agents: pseudoAgents }, matrix.categories);
|
|
62
|
+
}
|
|
63
|
+
setStep("build");
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
40
66
|
}
|
|
41
|
-
|
|
67
|
+
if (key.upArrow || input === "k") {
|
|
68
|
+
setFocusedIndex((prev) => Math.max(0, prev - 1));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (key.downArrow || input === "j") {
|
|
72
|
+
setFocusedIndex((prev) => Math.min(stackCount - 1, prev + 1));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
42
76
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
43
|
-
/* @__PURE__ */ jsx(
|
|
44
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
45
|
-
|
|
77
|
+
/* @__PURE__ */ jsx(ViewTitle, { children: "Select a pre-built template" }),
|
|
78
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: stacks.map((stack, index) => /* @__PURE__ */ jsx(
|
|
79
|
+
MenuItem,
|
|
46
80
|
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"\u2191",
|
|
54
|
-
"/",
|
|
55
|
-
"\u2193",
|
|
56
|
-
" navigate ENTER select ESC back"
|
|
57
|
-
] }) })
|
|
81
|
+
label: stack.name,
|
|
82
|
+
description: stack.description,
|
|
83
|
+
isFocused: index === focusedIndex
|
|
84
|
+
},
|
|
85
|
+
stack.id
|
|
86
|
+
)) })
|
|
58
87
|
] });
|
|
59
88
|
};
|
|
60
89
|
var DomainSelection = () => {
|
|
@@ -117,4 +146,4 @@ var StepStack = ({ matrix }) => {
|
|
|
117
146
|
export {
|
|
118
147
|
StepStack
|
|
119
148
|
};
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
149
|
+
//# sourceMappingURL=chunk-A46TPNBJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/step-stack.tsx"],"sourcesContent":["/**\n * StepStack component - Dual-purpose step for stack selection or domain selection.\n *\n * Stack path (approach === \"stack\"):\n * - Shows list of pre-built stacks using MenuItem for chevron + label pattern\n * - Keyboard navigation with arrow keys, Enter to select, Escape to go back\n * - Focused item has cyan chevron and label\n *\n * Scratch path (approach === \"scratch\"):\n * - Shows multi-select of domains (Web, API, CLI, Mobile)\n * - User selects which domains to configure\n * - Continue goes to build step for first selected domain\n */\nimport React, { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { Select } from \"@inkjs/ui\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\nimport { MenuItem } from \"./menu-item.js\";\nimport { ViewTitle } from \"./view-title.js\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst BACK_VALUE = \"_back\";\nconst CONTINUE_VALUE = \"_continue\";\n\n/** Default focused index starts at first stack item (0) */\nconst INITIAL_FOCUSED_INDEX = 0;\n\n/** Available domains for scratch path */\nconst AVAILABLE_DOMAINS = [\n { id: \"web\", label: \"Web\", description: \"Frontend web applications\" },\n {\n id: \"web-extras\",\n label: \"Web Extras\",\n description: \"Animation, files, realtime, PWA, accessibility\",\n },\n { id: \"api\", label: \"API\", description: \"Backend APIs and services\" },\n { id: \"cli\", label: \"CLI\", description: \"Command-line tools\" },\n { id: \"mobile\", label: \"Mobile\", description: \"Mobile applications\" },\n];\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface StepStackProps {\n matrix: MergedSkillsMatrix;\n}\n\n// =============================================================================\n// Stack Selection Sub-component\n// =============================================================================\n\ninterface StackSelectionProps {\n matrix: MergedSkillsMatrix;\n}\n\nconst StackSelection: React.FC<StackSelectionProps> = ({ matrix }) => {\n const { selectStack, setStep, setStackAction, populateFromStack, goBack } = useWizardStore();\n const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);\n\n const stacks = matrix.suggestedStacks;\n const stackCount = stacks.length;\n\n useInput((input, key) => {\n // Escape to go back\n if (key.escape) {\n goBack();\n return;\n }\n\n // Enter to select the focused stack\n if (key.return && stackCount > 0) {\n const focusedStack = stacks[focusedIndex];\n if (focusedStack) {\n selectStack(focusedStack.id);\n setStackAction(\"customize\");\n\n // Pre-populate domainSelections from the stack's skill mappings\n const resolvedStack = matrix.suggestedStacks.find((s) => s.id === focusedStack.id);\n if (resolvedStack) {\n // Build one pseudo-agent per skill so populateFromStack can handle\n // categories with multiple skills (e.g. testing: vitest + playwright-e2e)\n // without overwriting. populateFromStack deduplicates internally.\n const pseudoAgents: Record<string, Record<string, string>> = {};\n\n for (let i = 0; i < resolvedStack.allSkillIds.length; i++) {\n const skillId = resolvedStack.allSkillIds[i];\n const skill = matrix.skills[skillId];\n if (skill?.category) {\n const displayId = skill.alias || skill.id;\n pseudoAgents[`s${i}`] = { [skill.category]: displayId };\n }\n }\n\n populateFromStack({ agents: pseudoAgents }, matrix.categories);\n }\n\n setStep(\"build\");\n }\n return;\n }\n\n // Arrow key navigation (clamped at boundaries)\n if (key.upArrow || input === \"k\") {\n setFocusedIndex((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow || input === \"j\") {\n setFocusedIndex((prev) => Math.min(stackCount - 1, prev + 1));\n return;\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <ViewTitle>Select a pre-built template</ViewTitle>\n <Box flexDirection=\"column\" marginTop={1}>\n {stacks.map((stack, index) => (\n <MenuItem\n key={stack.id}\n label={stack.name}\n description={stack.description}\n isFocused={index === focusedIndex}\n />\n ))}\n </Box>\n </Box>\n );\n};\n\n// =============================================================================\n// Domain Selection Sub-component\n// =============================================================================\n\nconst DomainSelection: React.FC = () => {\n const { selectedDomains, toggleDomain, setStep, goBack } = useWizardStore();\n\n // Build options with checkboxes showing selection state\n const domainOptions = AVAILABLE_DOMAINS.map((domain) => {\n const isSelected = selectedDomains.includes(domain.id);\n const checkbox = isSelected ? \"[\\u2713]\" : \"[ ]\";\n return {\n value: domain.id,\n label: `${checkbox} ${domain.label} - ${domain.description}`,\n };\n });\n\n const options = [\n { value: BACK_VALUE, label: \"\\u2190 Back\" },\n ...domainOptions,\n ...(selectedDomains.length > 0\n ? [\n {\n value: CONTINUE_VALUE,\n label: `\\u2192 Continue with ${selectedDomains.length} domain(s)`,\n },\n ]\n : []),\n ];\n\n const handleSelect = (value: string) => {\n if (value === BACK_VALUE) {\n goBack();\n return;\n }\n\n if (value === CONTINUE_VALUE) {\n if (selectedDomains.length > 0) {\n setStep(\"build\");\n }\n return;\n }\n\n // Toggle domain selection\n toggleDomain(value);\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Select domains to configure:</Text>\n <Text dimColor>Select one or more domains, then continue</Text>\n <Box marginTop={1}>\n <Select options={options} onChange={handleSelect} />\n </Box>\n {selectedDomains.length > 0 ? (\n <Box marginTop={1}>\n <Text>\n Selected: <Text color=\"cyan\">{selectedDomains.join(\", \")}</Text>\n </Text>\n </Box>\n ) : (\n <Box marginTop={1}>\n <Text color=\"yellow\">Please select at least one domain</Text>\n </Box>\n )}\n <Box marginTop={1}>\n <Text dimColor>\n {\"\\u2191\"}/{\"\\u2193\"} navigate ENTER toggle/select ESC back\n </Text>\n </Box>\n </Box>\n );\n};\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const StepStack: React.FC<StepStackProps> = ({ matrix }) => {\n const { approach } = useWizardStore();\n\n if (approach === \"stack\") {\n return <StackSelection matrix={matrix} />;\n }\n\n // approach === \"scratch\"\n return <DomainSelection />;\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/utils/fs.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport fg from \"fast-glob\";\nimport path from \"path\";\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, \"utf-8\");\n}\n\nexport async function readFileOptional(filePath: string, fallback = \"\"): Promise<string> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return fallback;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function listDirectories(dirPath: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function glob(pattern: string, cwd: string): Promise<string[]> {\n return fg(pattern, { cwd, onlyFiles: true });\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function remove(filePath: string): Promise<void> {\n await fs.remove(filePath);\n}\n\nexport async function copy(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest);\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,SAAS,UAAmC;AAChE,SAAO,GAAG,SAAS,UAAU,OAAO;AACtC;AAEA,eAAsB,iBAAiB,UAAkB,WAAW,IAAqB;AACvF,MAAI;AACF,WAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,SAAO,GAAG,WAAW,QAAQ;AAC/B;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,SAAoC;AACxE,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,KAAK,SAAiB,KAAgC;AAC1E,SAAO,GAAG,SAAS,EAAE,KAAK,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,UAAU,UAAkB,SAAgC;AAChF,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,OAAO,UAAiC;AAC5D,QAAM,GAAG,OAAO,QAAQ;AAC1B;AAEA,eAAsB,KAAK,KAAa,MAA6B;AACnE,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;","names":[]}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
verbose
|
|
4
|
+
} from "./chunk-T25OEQFI.js";
|
|
5
|
+
import {
|
|
6
|
+
directoryExists,
|
|
7
|
+
glob,
|
|
8
|
+
readFile
|
|
9
|
+
} from "./chunk-AL74GBW4.js";
|
|
10
|
+
import {
|
|
11
|
+
CLAUDE_SRC_DIR,
|
|
12
|
+
DIRS
|
|
13
|
+
} from "./chunk-FJFEKPXF.js";
|
|
14
|
+
import {
|
|
15
|
+
init_esm_shims
|
|
16
|
+
} from "./chunk-DHET7RCE.js";
|
|
17
|
+
|
|
18
|
+
// src/cli/lib/loader.ts
|
|
19
|
+
init_esm_shims();
|
|
20
|
+
import { parse as parseYaml } from "yaml";
|
|
21
|
+
import path from "path";
|
|
22
|
+
var FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
|
|
23
|
+
function parseFrontmatter(content) {
|
|
24
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
25
|
+
if (!match) return null;
|
|
26
|
+
const yamlContent = match[1];
|
|
27
|
+
const frontmatter = parseYaml(yamlContent);
|
|
28
|
+
if (!frontmatter.name || !frontmatter.description) return null;
|
|
29
|
+
return frontmatter;
|
|
30
|
+
}
|
|
31
|
+
function extractDisplayName(skillId) {
|
|
32
|
+
const withoutCategory = skillId.split("/").pop() || skillId;
|
|
33
|
+
const withoutAuthor = withoutCategory.replace(/\s*\(@\w+\)$/, "").trim();
|
|
34
|
+
return withoutAuthor.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
35
|
+
}
|
|
36
|
+
async function loadAllAgents(projectRoot) {
|
|
37
|
+
const agents = {};
|
|
38
|
+
const agentSourcesDir = path.join(projectRoot, DIRS.agents);
|
|
39
|
+
const files = await glob("**/agent.yaml", agentSourcesDir);
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
const fullPath = path.join(agentSourcesDir, file);
|
|
42
|
+
const content = await readFile(fullPath);
|
|
43
|
+
const config = parseYaml(content);
|
|
44
|
+
const agentPath = path.dirname(file);
|
|
45
|
+
agents[config.id] = {
|
|
46
|
+
title: config.title,
|
|
47
|
+
description: config.description,
|
|
48
|
+
model: config.model,
|
|
49
|
+
tools: config.tools,
|
|
50
|
+
path: agentPath,
|
|
51
|
+
sourceRoot: projectRoot
|
|
52
|
+
};
|
|
53
|
+
verbose(`Loaded agent: ${config.id} from ${file}`);
|
|
54
|
+
}
|
|
55
|
+
return agents;
|
|
56
|
+
}
|
|
57
|
+
async function loadProjectAgents(projectRoot) {
|
|
58
|
+
const agents = {};
|
|
59
|
+
const projectAgentsDir = path.join(projectRoot, CLAUDE_SRC_DIR, "agents");
|
|
60
|
+
if (!await directoryExists(projectAgentsDir)) {
|
|
61
|
+
verbose(`No project agents directory at ${projectAgentsDir}`);
|
|
62
|
+
return agents;
|
|
63
|
+
}
|
|
64
|
+
const files = await glob("**/agent.yaml", projectAgentsDir);
|
|
65
|
+
for (const file of files) {
|
|
66
|
+
const fullPath = path.join(projectAgentsDir, file);
|
|
67
|
+
const content = await readFile(fullPath);
|
|
68
|
+
const config = parseYaml(content);
|
|
69
|
+
const agentPath = path.dirname(file);
|
|
70
|
+
agents[config.id] = {
|
|
71
|
+
title: config.title,
|
|
72
|
+
description: config.description,
|
|
73
|
+
model: config.model,
|
|
74
|
+
tools: config.tools,
|
|
75
|
+
path: agentPath,
|
|
76
|
+
sourceRoot: projectRoot,
|
|
77
|
+
agentBaseDir: `${CLAUDE_SRC_DIR}/agents`
|
|
78
|
+
// Project agents are in .claude-src/agents/
|
|
79
|
+
};
|
|
80
|
+
verbose(`Loaded project agent: ${config.id} from ${file}`);
|
|
81
|
+
}
|
|
82
|
+
return agents;
|
|
83
|
+
}
|
|
84
|
+
async function buildIdToDirectoryPathMap(skillsDir) {
|
|
85
|
+
const map = {};
|
|
86
|
+
const files = await glob("**/SKILL.md", skillsDir);
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
const fullPath = path.join(skillsDir, file);
|
|
89
|
+
const content = await readFile(fullPath);
|
|
90
|
+
const frontmatter = parseFrontmatter(content);
|
|
91
|
+
if (frontmatter?.name) {
|
|
92
|
+
const directoryPath = file.replace("/SKILL.md", "");
|
|
93
|
+
map[frontmatter.name] = directoryPath;
|
|
94
|
+
map[directoryPath] = directoryPath;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return map;
|
|
98
|
+
}
|
|
99
|
+
async function loadSkillsByIds(skillIds, projectRoot) {
|
|
100
|
+
const skills = {};
|
|
101
|
+
const skillsDir = path.join(projectRoot, DIRS.skills);
|
|
102
|
+
const idToDirectoryPath = await buildIdToDirectoryPathMap(skillsDir);
|
|
103
|
+
const allSkillIds = Object.keys(idToDirectoryPath);
|
|
104
|
+
const expandedSkillIds = [];
|
|
105
|
+
for (const { id: skillId } of skillIds) {
|
|
106
|
+
if (idToDirectoryPath[skillId]) {
|
|
107
|
+
expandedSkillIds.push(skillId);
|
|
108
|
+
} else {
|
|
109
|
+
const childSkills = allSkillIds.filter((id) => {
|
|
110
|
+
const dirPath = idToDirectoryPath[id];
|
|
111
|
+
return dirPath.startsWith(skillId + "/");
|
|
112
|
+
});
|
|
113
|
+
if (childSkills.length > 0) {
|
|
114
|
+
expandedSkillIds.push(...childSkills);
|
|
115
|
+
verbose(`Expanded directory '${skillId}' to ${childSkills.length} skills`);
|
|
116
|
+
} else {
|
|
117
|
+
console.warn(` Warning: Unknown skill reference '${skillId}'`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const uniqueSkillIds = [...new Set(expandedSkillIds)];
|
|
122
|
+
for (const skillId of uniqueSkillIds) {
|
|
123
|
+
const directoryPath = idToDirectoryPath[skillId];
|
|
124
|
+
if (!directoryPath) {
|
|
125
|
+
console.warn(` Warning: Could not find skill ${skillId}: No matching skill found`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const skillPath = path.join(skillsDir, directoryPath);
|
|
129
|
+
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
130
|
+
try {
|
|
131
|
+
const content = await readFile(skillMdPath);
|
|
132
|
+
const frontmatter = parseFrontmatter(content);
|
|
133
|
+
if (!frontmatter) {
|
|
134
|
+
console.warn(` Warning: Skipping ${skillId}: Missing or invalid frontmatter`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const canonicalId = frontmatter.name;
|
|
138
|
+
const skillDef = {
|
|
139
|
+
path: `${DIRS.skills}/${directoryPath}/`,
|
|
140
|
+
name: extractDisplayName(frontmatter.name),
|
|
141
|
+
description: frontmatter.description,
|
|
142
|
+
canonicalId
|
|
143
|
+
};
|
|
144
|
+
skills[canonicalId] = skillDef;
|
|
145
|
+
if (directoryPath !== canonicalId) {
|
|
146
|
+
skills[directoryPath] = skillDef;
|
|
147
|
+
}
|
|
148
|
+
verbose(`Loaded skill: ${canonicalId} (from ${directoryPath})`);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.warn(` Warning: Could not load skill ${skillId}: ${error}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return skills;
|
|
154
|
+
}
|
|
155
|
+
async function loadPluginSkills(pluginDir) {
|
|
156
|
+
const skills = {};
|
|
157
|
+
const pluginSkillsDir = path.join(pluginDir, "skills");
|
|
158
|
+
if (!await directoryExists(pluginSkillsDir)) {
|
|
159
|
+
return skills;
|
|
160
|
+
}
|
|
161
|
+
const files = await glob("**/SKILL.md", pluginSkillsDir);
|
|
162
|
+
for (const file of files) {
|
|
163
|
+
const fullPath = path.join(pluginSkillsDir, file);
|
|
164
|
+
const content = await readFile(fullPath);
|
|
165
|
+
const frontmatter = parseFrontmatter(content);
|
|
166
|
+
if (!frontmatter) {
|
|
167
|
+
console.warn(` Warning: Skipping ${file}: Missing or invalid frontmatter`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const folderPath = file.replace("/SKILL.md", "");
|
|
171
|
+
const skillPath = `skills/${folderPath}/`;
|
|
172
|
+
const skillId = frontmatter.name;
|
|
173
|
+
skills[skillId] = {
|
|
174
|
+
path: skillPath,
|
|
175
|
+
name: extractDisplayName(frontmatter.name),
|
|
176
|
+
description: frontmatter.description,
|
|
177
|
+
canonicalId: skillId
|
|
178
|
+
};
|
|
179
|
+
verbose(`Loaded plugin skill: ${skillId} from ${file}`);
|
|
180
|
+
}
|
|
181
|
+
return skills;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
parseFrontmatter,
|
|
186
|
+
loadAllAgents,
|
|
187
|
+
loadProjectAgents,
|
|
188
|
+
loadSkillsByIds,
|
|
189
|
+
loadPluginSkills
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=chunk-BQX23RBV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/loader.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { glob, readFile, directoryExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_SRC_DIR, DIRS } from \"../consts\";\nimport type { AgentDefinition, AgentYamlConfig, SkillDefinition, SkillFrontmatter } from \"../types\";\n\nexport type CompileMode = \"dev\";\n\nexport function getDirs(_mode: CompileMode) {\n return DIRS;\n}\n\nconst FRONTMATTER_REGEX = /^---\\n([\\s\\S]*?)\\n---/;\n\nexport function parseFrontmatter(content: string): SkillFrontmatter | null {\n const match = content.match(FRONTMATTER_REGEX);\n if (!match) return null;\n\n const yamlContent = match[1];\n const frontmatter = parseYaml(yamlContent) as SkillFrontmatter;\n\n if (!frontmatter.name || !frontmatter.description) return null;\n return frontmatter;\n}\n\nfunction extractDisplayName(skillId: string): string {\n const withoutCategory = skillId.split(\"/\").pop() || skillId;\n const withoutAuthor = withoutCategory.replace(/\\s*\\(@\\w+\\)$/, \"\").trim();\n return withoutAuthor\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nexport async function loadAllAgents(projectRoot: string): Promise<Record<string, AgentDefinition>> {\n const agents: Record<string, AgentDefinition> = {};\n const agentSourcesDir = path.join(projectRoot, DIRS.agents);\n\n const files = await glob(\"**/agent.yaml\", agentSourcesDir);\n\n for (const file of files) {\n const fullPath = path.join(agentSourcesDir, file);\n const content = await readFile(fullPath);\n const config = parseYaml(content) as AgentYamlConfig;\n const agentPath = path.dirname(file);\n\n agents[config.id] = {\n title: config.title,\n description: config.description,\n model: config.model,\n tools: config.tools,\n path: agentPath,\n sourceRoot: projectRoot,\n };\n\n verbose(`Loaded agent: ${config.id} from ${file}`);\n }\n\n return agents;\n}\n\n/**\n * Load agents from project's .claude-src/agents/ directory.\n * Returns empty object if directory doesn't exist.\n */\nexport async function loadProjectAgents(\n projectRoot: string,\n): Promise<Record<string, AgentDefinition>> {\n const agents: Record<string, AgentDefinition> = {};\n const projectAgentsDir = path.join(projectRoot, CLAUDE_SRC_DIR, \"agents\");\n\n if (!(await directoryExists(projectAgentsDir))) {\n verbose(`No project agents directory at ${projectAgentsDir}`);\n return agents;\n }\n\n const files = await glob(\"**/agent.yaml\", projectAgentsDir);\n\n for (const file of files) {\n const fullPath = path.join(projectAgentsDir, file);\n const content = await readFile(fullPath);\n const config = parseYaml(content) as AgentYamlConfig;\n const agentPath = path.dirname(file);\n\n agents[config.id] = {\n title: config.title,\n description: config.description,\n model: config.model,\n tools: config.tools,\n path: agentPath,\n sourceRoot: projectRoot,\n agentBaseDir: `${CLAUDE_SRC_DIR}/agents`, // Project agents are in .claude-src/agents/\n };\n\n verbose(`Loaded project agent: ${config.id} from ${file}`);\n }\n\n return agents;\n}\n\nasync function buildIdToDirectoryPathMap(skillsDir: string): Promise<Record<string, string>> {\n const map: Record<string, string> = {};\n const files = await glob(\"**/SKILL.md\", skillsDir);\n\n for (const file of files) {\n const fullPath = path.join(skillsDir, file);\n const content = await readFile(fullPath);\n const frontmatter = parseFrontmatter(content);\n\n if (frontmatter?.name) {\n const directoryPath = file.replace(\"/SKILL.md\", \"\");\n map[frontmatter.name] = directoryPath;\n map[directoryPath] = directoryPath;\n }\n }\n\n return map;\n}\n\nexport async function loadSkillsByIds(\n skillIds: Array<{ id: string }>,\n projectRoot: string,\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const skillsDir = path.join(projectRoot, DIRS.skills);\n\n const idToDirectoryPath = await buildIdToDirectoryPathMap(skillsDir);\n const allSkillIds = Object.keys(idToDirectoryPath);\n const expandedSkillIds: string[] = [];\n\n for (const { id: skillId } of skillIds) {\n if (idToDirectoryPath[skillId]) {\n expandedSkillIds.push(skillId);\n } else {\n const childSkills = allSkillIds.filter((id) => {\n const dirPath = idToDirectoryPath[id];\n return dirPath.startsWith(skillId + \"/\");\n });\n\n if (childSkills.length > 0) {\n expandedSkillIds.push(...childSkills);\n verbose(`Expanded directory '${skillId}' to ${childSkills.length} skills`);\n } else {\n console.warn(` Warning: Unknown skill reference '${skillId}'`);\n }\n }\n }\n\n const uniqueSkillIds = [...new Set(expandedSkillIds)];\n\n for (const skillId of uniqueSkillIds) {\n const directoryPath = idToDirectoryPath[skillId];\n if (!directoryPath) {\n console.warn(` Warning: Could not find skill ${skillId}: No matching skill found`);\n continue;\n }\n\n const skillPath = path.join(skillsDir, directoryPath);\n const skillMdPath = path.join(skillPath, \"SKILL.md\");\n\n try {\n const content = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(content);\n\n if (!frontmatter) {\n console.warn(` Warning: Skipping ${skillId}: Missing or invalid frontmatter`);\n continue;\n }\n\n const canonicalId = frontmatter.name;\n const skillDef: SkillDefinition = {\n path: `${DIRS.skills}/${directoryPath}/`,\n name: extractDisplayName(frontmatter.name),\n description: frontmatter.description,\n canonicalId,\n };\n\n skills[canonicalId] = skillDef;\n\n if (directoryPath !== canonicalId) {\n skills[directoryPath] = skillDef;\n }\n\n verbose(`Loaded skill: ${canonicalId} (from ${directoryPath})`);\n } catch (error) {\n console.warn(` Warning: Could not load skill ${skillId}: ${error}`);\n }\n }\n\n return skills;\n}\n\nexport async function loadPluginSkills(\n pluginDir: string,\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const pluginSkillsDir = path.join(pluginDir, \"skills\");\n\n if (!(await directoryExists(pluginSkillsDir))) {\n return skills;\n }\n\n const files = await glob(\"**/SKILL.md\", pluginSkillsDir);\n\n for (const file of files) {\n const fullPath = path.join(pluginSkillsDir, file);\n const content = await readFile(fullPath);\n\n const frontmatter = parseFrontmatter(content);\n if (!frontmatter) {\n console.warn(` Warning: Skipping ${file}: Missing or invalid frontmatter`);\n continue;\n }\n\n const folderPath = file.replace(\"/SKILL.md\", \"\");\n const skillPath = `skills/${folderPath}/`;\n const skillId = frontmatter.name;\n\n skills[skillId] = {\n path: skillPath,\n name: extractDisplayName(frontmatter.name),\n description: frontmatter.description,\n canonicalId: skillId,\n };\n\n verbose(`Loaded plugin skill: ${skillId} from ${file}`);\n }\n\n return skills;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
isLocalSource
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-374JNMR6.js";
|
|
5
5
|
import {
|
|
6
6
|
verbose
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-T25OEQFI.js";
|
|
8
8
|
import {
|
|
9
9
|
directoryExists,
|
|
10
10
|
ensureDir
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-AL74GBW4.js";
|
|
12
12
|
import {
|
|
13
13
|
CACHE_DIR
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FJFEKPXF.js";
|
|
15
15
|
import {
|
|
16
16
|
init_esm_shims
|
|
17
17
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -129,4 +129,4 @@ If you're behind a corporate proxy, you may need to set:
|
|
|
129
129
|
export {
|
|
130
130
|
fetchFromSource
|
|
131
131
|
};
|
|
132
|
-
//# sourceMappingURL=chunk-
|
|
132
|
+
//# sourceMappingURL=chunk-CA4LH4LI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/source-fetcher.ts"],"sourcesContent":["import path from \"path\";\nimport { downloadTemplate } from \"giget\";\nimport { verbose } from \"../utils/logger\";\nimport { CACHE_DIR } from \"../consts\";\nimport { ensureDir, directoryExists, readFile } from \"../utils/fs\";\nimport { isLocalSource } from \"./config\";\nimport type { Marketplace, MarketplaceFetchResult } from \"../../types\";\n\nexport interface FetchOptions {\n forceRefresh?: boolean;\n subdir?: string;\n}\n\nexport interface FetchResult {\n path: string;\n fromCache: boolean;\n source: string;\n}\n\nexport function sanitizeSourceForCache(source: string): string {\n return source.replace(/:/g, \"-\").replace(/[\\/]/g, \"-\").replace(/--+/g, \"-\").replace(/^-|-$/g, \"\");\n}\n\nfunction getCacheDir(source: string): string {\n const sanitized = sanitizeSourceForCache(source);\n return path.join(CACHE_DIR, \"sources\", sanitized);\n}\n\nexport async function fetchFromSource(\n source: string,\n options: FetchOptions = {},\n): Promise<FetchResult> {\n const { forceRefresh = false, subdir } = options;\n\n if (isLocalSource(source)) {\n return fetchFromLocalSource(source, subdir);\n }\n\n return fetchFromRemoteSource(source, { forceRefresh, subdir });\n}\n\nasync function fetchFromLocalSource(source: string, subdir?: string): Promise<FetchResult> {\n const fullPath = subdir ? path.join(source, subdir) : source;\n const absolutePath = path.isAbsolute(fullPath) ? fullPath : path.resolve(process.cwd(), fullPath);\n\n if (!(await directoryExists(absolutePath))) {\n throw new Error(`Local source not found: ${absolutePath}`);\n }\n\n verbose(`Using local source: ${absolutePath}`);\n\n return {\n path: absolutePath,\n fromCache: false,\n source,\n };\n}\n\nasync function fetchFromRemoteSource(source: string, options: FetchOptions): Promise<FetchResult> {\n const { forceRefresh = false, subdir } = options;\n const cacheDir = getCacheDir(source);\n\n const fullSource = subdir ? `${source}/${subdir}` : source;\n\n verbose(`Fetching from remote: ${fullSource}`);\n verbose(`Cache directory: ${cacheDir}`);\n\n // If cache exists and not forcing refresh, use it directly\n if (!forceRefresh && (await directoryExists(cacheDir))) {\n verbose(`Using cached source: ${cacheDir}`);\n return {\n path: cacheDir,\n fromCache: true,\n source: fullSource,\n };\n }\n\n await ensureDir(path.dirname(cacheDir));\n\n try {\n const result = await downloadTemplate(fullSource, {\n dir: cacheDir,\n force: true, // Always force when downloading to avoid \"already exists\" error\n offline: false,\n });\n\n verbose(`Downloaded to: ${result.dir}`);\n\n return {\n path: result.dir,\n fromCache: false,\n source: fullSource,\n };\n } catch (error) {\n throw wrapGigetError(error, source);\n }\n}\n\nfunction wrapGigetError(error: unknown, source: string): Error {\n const message = error instanceof Error ? error.message : String(error);\n\n if (message.includes(\"404\") || message.includes(\"Not Found\")) {\n return new Error(\n `Repository not found: ${source}\\n\\n` +\n `This could mean:\\n` +\n ` - The repository doesn't exist\\n` +\n ` - The repository is private and you need to set authentication\\n` +\n ` - There's a typo in the URL\\n\\n` +\n `For private repositories, set the GIGET_AUTH environment variable:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token`,\n );\n }\n\n if (message.includes(\"401\") || message.includes(\"Unauthorized\")) {\n return new Error(\n `Authentication required for: ${source}\\n\\n` +\n `Set the GIGET_AUTH environment variable with a GitHub token:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token\\n\\n` +\n `Create a token at: https://github.com/settings/tokens\\n` +\n `Required scope: repo (for private repos) or public_repo (for public)`,\n );\n }\n\n if (message.includes(\"403\") || message.includes(\"Forbidden\")) {\n return new Error(\n `Access denied to: ${source}\\n\\n` +\n `Your token may not have sufficient permissions.\\n` +\n `Ensure your GIGET_AUTH token has the 'repo' scope for private repositories.`,\n );\n }\n\n if (\n message.includes(\"ENOTFOUND\") ||\n message.includes(\"ETIMEDOUT\") ||\n message.includes(\"network\")\n ) {\n return new Error(\n `Network error fetching: ${source}\\n\\n` +\n `Please check your internet connection.\\n` +\n `If you're behind a corporate proxy, you may need to set:\\n` +\n ` export HTTPS_PROXY=http://your-proxy:port\\n` +\n ` export FORCE_NODE_FETCH=true # Required for Node 20+`,\n );\n }\n\n return new Error(`Failed to fetch ${source}: ${message}`);\n}\n\nexport async function fetchMarketplace(\n source: string,\n options: FetchOptions = {},\n): Promise<MarketplaceFetchResult> {\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\", // Root of repo\n });\n\n const marketplacePath = path.join(result.path, \".claude-plugin\", \"marketplace.json\");\n\n if (!(await directoryExists(path.dirname(marketplacePath)))) {\n throw new Error(\n `Marketplace not found at: ${marketplacePath}\\n\\n` +\n `Expected .claude-plugin/marketplace.json in the source repository.`,\n );\n }\n\n const content = await readFile(marketplacePath);\n const marketplace = JSON.parse(content) as Marketplace;\n\n verbose(`Loaded marketplace: ${marketplace.name} v${marketplace.version}`);\n\n return {\n marketplace,\n sourcePath: result.path,\n fromCache: result.fromCache ?? false,\n cacheKey: sanitizeSourceForCache(source),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_PRESELECTED_SKILLS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FJFEKPXF.js";
|
|
5
5
|
import {
|
|
6
6
|
init_esm_shims
|
|
7
7
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
// src/cli/stores/wizard-store.ts
|
|
10
10
|
init_esm_shims();
|
|
11
11
|
import { create } from "zustand";
|
|
12
|
+
var ALL_DOMAINS = ["web", "web-extras", "api", "cli", "mobile", "shared"];
|
|
12
13
|
var createInitialState = () => ({
|
|
13
14
|
step: "approach",
|
|
14
15
|
approach: null,
|
|
@@ -21,7 +22,6 @@ var createInitialState = () => ({
|
|
|
21
22
|
focusedCol: 0,
|
|
22
23
|
currentRefineIndex: 0,
|
|
23
24
|
skillSources: {},
|
|
24
|
-
refineAction: null,
|
|
25
25
|
showDescriptions: false,
|
|
26
26
|
expertMode: false,
|
|
27
27
|
installMode: "local",
|
|
@@ -43,9 +43,7 @@ var useWizardStore = create((set, get) => ({
|
|
|
43
43
|
const domainSelections = {};
|
|
44
44
|
const domains = /* @__PURE__ */ new Set();
|
|
45
45
|
for (const agentConfig of Object.values(stack.agents)) {
|
|
46
|
-
for (const [subcategoryId, technologyAlias] of Object.entries(
|
|
47
|
-
agentConfig
|
|
48
|
-
)) {
|
|
46
|
+
for (const [subcategoryId, technologyAlias] of Object.entries(agentConfig)) {
|
|
49
47
|
const category = categories[subcategoryId];
|
|
50
48
|
const domain = category?.domain;
|
|
51
49
|
if (!domain) {
|
|
@@ -65,7 +63,7 @@ var useWizardStore = create((set, get) => ({
|
|
|
65
63
|
}
|
|
66
64
|
return {
|
|
67
65
|
domainSelections,
|
|
68
|
-
selectedDomains:
|
|
66
|
+
selectedDomains: ALL_DOMAINS
|
|
69
67
|
};
|
|
70
68
|
}),
|
|
71
69
|
toggleDomain: (domain) => set((state) => {
|
|
@@ -128,7 +126,6 @@ var useWizardStore = create((set, get) => ({
|
|
|
128
126
|
return false;
|
|
129
127
|
},
|
|
130
128
|
setFocus: (row, col) => set({ focusedRow: row, focusedCol: col }),
|
|
131
|
-
setRefineAction: (action) => set({ refineAction: action }),
|
|
132
129
|
setSkillSource: (technology, skillId) => set((state) => ({
|
|
133
130
|
skillSources: {
|
|
134
131
|
...state.skillSources,
|
|
@@ -184,4 +181,4 @@ var useWizardStore = create((set, get) => ({
|
|
|
184
181
|
export {
|
|
185
182
|
useWizardStore
|
|
186
183
|
};
|
|
187
|
-
//# sourceMappingURL=chunk-
|
|
184
|
+
//# sourceMappingURL=chunk-CBLPAMZO.js.map
|