@claude-collective/cli 0.13.4 → 0.25.1
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 +357 -0
- package/README.md +41 -27
- package/config/skills-matrix.yaml +202 -134
- package/config/stacks.yaml +14 -20
- package/dist/chunk-3X5D7RM5.js +69 -0
- package/dist/chunk-3X5D7RM5.js.map +1 -0
- package/dist/chunk-4S4FCAA2.js +100 -0
- package/dist/chunk-4S4FCAA2.js.map +1 -0
- package/dist/chunk-4WGN6SUE.js +197 -0
- package/dist/chunk-4WGN6SUE.js.map +1 -0
- package/dist/{chunk-DHET7RCE.js → chunk-AWKZ5BDL.js} +9 -2
- package/dist/{chunk-DHET7RCE.js.map → chunk-AWKZ5BDL.js.map} +1 -1
- package/dist/{chunk-6Q3Y7KVB.js → chunk-DBRUQQUF.js} +8 -2
- package/dist/chunk-DBRUQQUF.js.map +1 -0
- package/dist/{chunk-Z7G4B5HJ.js → chunk-ETCVEV3S.js} +73 -150
- package/dist/chunk-ETCVEV3S.js.map +1 -0
- package/dist/chunk-F4RD5FYM.js +45 -0
- package/dist/chunk-F4RD5FYM.js.map +1 -0
- package/dist/{chunk-ACNBKXXJ.js → chunk-GGFOD5PK.js} +13 -44
- package/dist/chunk-GGFOD5PK.js.map +1 -0
- package/dist/chunk-H7SSBSPR.js +29 -0
- package/dist/chunk-H7SSBSPR.js.map +1 -0
- package/dist/chunk-HWD32NP7.js +19 -0
- package/dist/chunk-HWD32NP7.js.map +1 -0
- package/dist/{chunk-JIPWV2FX.js → chunk-IAYAE6MG.js} +12 -34
- package/dist/chunk-IAYAE6MG.js.map +1 -0
- package/dist/{chunk-RTE64SJA.js → chunk-IXBCRT3F.js} +2 -2
- package/dist/chunk-IXBCRT3F.js.map +1 -0
- package/dist/chunk-KWYO3M5Q.js +67 -0
- package/dist/chunk-KWYO3M5Q.js.map +1 -0
- package/dist/{chunk-E3FJH4TF.js → chunk-MCTSHLAF.js} +18 -18
- package/dist/chunk-MCTSHLAF.js.map +1 -0
- package/dist/chunk-MH66WDFV.js +251 -0
- package/dist/chunk-MH66WDFV.js.map +1 -0
- package/dist/{chunk-K3NB6DSG.js → chunk-MTPM7BX5.js} +108 -110
- package/dist/chunk-MTPM7BX5.js.map +1 -0
- package/dist/chunk-NQJ47R4N.js +1092 -0
- package/dist/chunk-NQJ47R4N.js.map +1 -0
- package/dist/chunk-NRC7XYCI.js +211 -0
- package/dist/chunk-NRC7XYCI.js.map +1 -0
- package/dist/{chunk-76DWXGQE.js → chunk-O6ZTD7ZI.js} +14 -3
- package/dist/chunk-O6ZTD7ZI.js.map +1 -0
- package/dist/chunk-OBXAY23Y.js +56 -0
- package/dist/chunk-OBXAY23Y.js.map +1 -0
- package/dist/{chunk-XY3XDVMI.js → chunk-QR2EBWL2.js} +3 -3
- package/dist/{chunk-66UDJBF6.js → chunk-REJGRCVQ.js} +2 -2
- package/dist/{chunk-D237EVNB.js → chunk-TMED5DQ2.js} +71 -48
- package/dist/chunk-TMED5DQ2.js.map +1 -0
- package/dist/chunk-U7HFKR74.js +21 -0
- package/dist/chunk-U7HFKR74.js.map +1 -0
- package/dist/chunk-UEMRJI2K.js +146 -0
- package/dist/chunk-UEMRJI2K.js.map +1 -0
- package/dist/{chunk-Z2CWURZ6.js → chunk-UNN7523L.js} +2 -2
- package/dist/chunk-V2ZIH7HV.js +29 -0
- package/dist/chunk-V2ZIH7HV.js.map +1 -0
- package/dist/{chunk-X6QONICW.js → chunk-VVYNZZUX.js} +7 -19
- package/dist/chunk-VVYNZZUX.js.map +1 -0
- package/dist/chunk-WXS4S3MA.js +220 -0
- package/dist/chunk-WXS4S3MA.js.map +1 -0
- package/dist/{chunk-CDX4W4DM.js → chunk-XENOESJZ.js} +53 -33
- package/dist/chunk-XENOESJZ.js.map +1 -0
- package/dist/chunk-YDBSSAJ6.js +4207 -0
- package/dist/chunk-YDBSSAJ6.js.map +1 -0
- package/dist/chunk-ZDREFYD2.js +696 -0
- package/dist/chunk-ZDREFYD2.js.map +1 -0
- package/dist/chunk-ZW2PELOH.js +197 -0
- package/dist/chunk-ZW2PELOH.js.map +1 -0
- package/dist/cli/defaults/agent-mappings.yaml +13 -14
- package/dist/commands/build/marketplace.js +19 -23
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +13 -240
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +13 -25
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +45 -82
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +9 -9
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +8 -8
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +7 -9
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +12 -13
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +7 -7
- package/dist/commands/config/unset-project.js +12 -13
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +15 -44
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +23 -67
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +98 -81
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +27 -79
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +38 -58
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +17 -24
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +103 -779
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +8 -11
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +11 -16
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +14 -18
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +16 -97
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +24 -43
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +22 -30
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +23 -154
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +38 -89
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +12 -28
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +8 -24
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +11 -26
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +8 -24
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +2 -2
- package/dist/components/common/confirm.test.js +203 -0
- package/dist/components/common/confirm.test.js.map +1 -0
- package/dist/components/common/message.js +3 -7
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +138 -156
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/menu-item.js +9 -0
- package/dist/components/wizard/search-modal.js +9 -0
- package/dist/components/wizard/search-modal.test.js +216 -0
- package/dist/components/wizard/search-modal.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +16 -106
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/source-grid.js +10 -0
- package/dist/components/wizard/source-grid.js.map +1 -0
- package/dist/components/wizard/source-grid.test.js +500 -0
- package/dist/components/wizard/source-grid.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +7 -5
- package/dist/components/wizard/step-approach.test.js +115 -0
- package/dist/components/wizard/step-approach.test.js.map +1 -0
- package/dist/components/wizard/step-build.js +9 -5
- package/dist/components/wizard/step-build.test.js +160 -284
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +3 -3
- package/dist/components/wizard/step-confirm.test.js +364 -0
- package/dist/components/wizard/step-confirm.test.js.map +1 -0
- package/dist/components/wizard/step-refine.js +2 -3
- package/dist/components/wizard/step-refine.test.js +24 -26
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +14 -0
- package/dist/components/wizard/step-settings.js.map +1 -0
- package/dist/components/wizard/step-settings.test.js +240 -0
- package/dist/components/wizard/step-settings.test.js.map +1 -0
- package/dist/components/wizard/step-sources.js +17 -0
- package/dist/components/wizard/step-sources.js.map +1 -0
- package/dist/components/wizard/step-sources.test.js +290 -0
- package/dist/components/wizard/step-sources.test.js.map +1 -0
- package/dist/components/wizard/step-stack.js +7 -4
- package/dist/components/wizard/step-stack.test.js +344 -0
- package/dist/components/wizard/step-stack.test.js.map +1 -0
- package/dist/components/wizard/view-title.js +9 -0
- package/dist/components/wizard/view-title.js.map +1 -0
- package/dist/components/wizard/wizard-layout.js +17 -0
- package/dist/components/wizard/wizard-layout.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +292 -0
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
- package/dist/components/wizard/wizard.js +22 -15
- package/dist/config/skills-matrix.yaml +202 -134
- package/dist/config/stacks.yaml +14 -20
- package/dist/hooks/init.js +6 -8
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{magic-string.es-RGXYGAW3.js → magic-string.es-PAH2SOTR.js} +2 -2
- package/dist/source-manager-DSYZEVGZ.js +16 -0
- package/dist/source-manager-DSYZEVGZ.js.map +1 -0
- package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/web-developer/examples.md +1 -6
- package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/dist/src/agents/meta/documentor/agent.yaml +1 -1
- package/dist/src/agents/meta/documentor/workflow.md +1 -5
- package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/dist/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
- package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
- package/dist/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/stores/wizard-store.js +4 -3
- package/dist/stores/wizard-store.test.js +94 -88
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +5 -3
- package/src/agents/developer/api-developer/agent.yaml +1 -1
- package/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/src/agents/developer/web-developer/agent.yaml +1 -1
- package/src/agents/developer/web-developer/examples.md +1 -6
- package/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/src/agents/meta/documentor/agent.yaml +1 -1
- package/src/agents/meta/documentor/workflow.md +1 -5
- package/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/src/agents/planning/web-pm/agent.yaml +1 -1
- package/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/src/agents/tester/web-tester/agent.yaml +1 -1
- package/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/chunk-3U3R4NCG.js +0 -22
- package/dist/chunk-3U3R4NCG.js.map +0 -1
- package/dist/chunk-4K4ZXQRM.js +0 -317
- package/dist/chunk-4K4ZXQRM.js.map +0 -1
- package/dist/chunk-6Q3Y7KVB.js.map +0 -1
- package/dist/chunk-76DWXGQE.js.map +0 -1
- package/dist/chunk-7Q44DMSP.js +0 -582
- package/dist/chunk-7Q44DMSP.js.map +0 -1
- package/dist/chunk-ACNBKXXJ.js.map +0 -1
- package/dist/chunk-B7CCVP6Q.js +0 -639
- 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-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 +0 -114
- package/dist/chunk-ED4E6Q2T.js.map +0 -1
- package/dist/chunk-EHS3TWWP.js +0 -95
- package/dist/chunk-EHS3TWWP.js.map +0 -1
- package/dist/chunk-GDH553MV.js +0 -91
- 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-IAUAQJQ2.js +0 -57
- package/dist/chunk-IAUAQJQ2.js.map +0 -1
- package/dist/chunk-IBE7JIAG.js +0 -129
- package/dist/chunk-IBE7JIAG.js.map +0 -1
- package/dist/chunk-IMDW5ZUP.js +0 -132
- package/dist/chunk-IMDW5ZUP.js.map +0 -1
- package/dist/chunk-JIPWV2FX.js.map +0 -1
- package/dist/chunk-K3NB6DSG.js.map +0 -1
- package/dist/chunk-K7EVM5LY.js +0 -141
- package/dist/chunk-K7EVM5LY.js.map +0 -1
- package/dist/chunk-KAAEN2PO.js +0 -57
- package/dist/chunk-KAAEN2PO.js.map +0 -1
- package/dist/chunk-NDY25DTL.js +0 -453
- package/dist/chunk-NDY25DTL.js.map +0 -1
- package/dist/chunk-P26A2K5N.js +0 -64
- package/dist/chunk-P26A2K5N.js.map +0 -1
- package/dist/chunk-RFTSZDHV.js +0 -313
- package/dist/chunk-RFTSZDHV.js.map +0 -1
- package/dist/chunk-RTE64SJA.js.map +0 -1
- package/dist/chunk-SVYPSDWY.js +0 -84
- package/dist/chunk-SVYPSDWY.js.map +0 -1
- package/dist/chunk-TKFPKEV3.js +0 -69
- package/dist/chunk-TKFPKEV3.js.map +0 -1
- package/dist/chunk-UQTEPWU7.js +0 -108
- package/dist/chunk-UQTEPWU7.js.map +0 -1
- package/dist/chunk-V46GGCCI.js +0 -294
- 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 +0 -396
- 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/{chunk-XY3XDVMI.js.map → chunk-QR2EBWL2.js.map} +0 -0
- /package/dist/{chunk-66UDJBF6.js.map → chunk-REJGRCVQ.js.map} +0 -0
- /package/dist/{chunk-Z2CWURZ6.js.map → chunk-UNN7523L.js.map} +0 -0
- /package/dist/components/wizard/{step-stack-options.js.map → menu-item.js.map} +0 -0
- /package/dist/components/wizard/{wizard-footer.js.map → search-modal.js.map} +0 -0
- /package/dist/{magic-string.es-RGXYGAW3.js.map → magic-string.es-PAH2SOTR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/loader.ts","../src/cli/lib/stacks-loader.ts","../src/cli/lib/matrix-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 {\n AgentDefinition,\n AgentYamlConfig,\n SkillDefinition,\n SkillFrontmatter,\n StackConfig,\n} 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(\n projectRoot: string,\n): 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 skills: config.skills,\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 skills: config.skills,\n };\n\n verbose(`Loaded project agent: ${config.id} from ${file}`);\n }\n\n return agents;\n}\n\n/** @deprecated Use loadSkillsByIds instead - stacks no longer embed skills */\nexport async function loadStackSkills(\n stackId: string,\n projectRoot: string,\n _mode: CompileMode = \"dev\",\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const stackSkillsDir = path.join(projectRoot, DIRS.stacks, stackId, \"skills\");\n\n if (!(await directoryExists(stackSkillsDir))) {\n verbose(`No embedded skills directory for stack ${stackId}`);\n return skills;\n }\n\n const files = await glob(\"**/SKILL.md\", stackSkillsDir);\n\n for (const file of files) {\n const fullPath = path.join(stackSkillsDir, file);\n const content = await readFile(fullPath);\n\n const frontmatter = parseFrontmatter(content);\n if (!frontmatter) {\n console.warn(\n ` Warning: Skipping ${file}: Missing or invalid frontmatter`,\n );\n continue;\n }\n\n const folderPath = file.replace(\"/SKILL.md\", \"\");\n const skillPath = `src/stacks/${stackId}/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 stack skill: ${skillId} from ${file}`);\n }\n\n return skills;\n}\n\nasync function buildIdToDirectoryPathMap(\n skillsDir: string,\n): 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(\n `Expanded directory '${skillId}' to ${childSkills.length} skills`,\n );\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(\n ` Warning: Could not find skill ${skillId}: No matching skill found`,\n );\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(\n ` Warning: Skipping ${skillId}: Missing or invalid frontmatter`,\n );\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(\n ` Warning: Skipping ${file}: Missing or invalid frontmatter`,\n );\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\nconst stackCache = new Map<string, StackConfig>();\n\n/**\n * @deprecated Use loadStackById from stacks-loader.ts instead.\n * This function loads legacy stack configs from src/stacks/{stackId}/config.yaml.\n * The new system uses config/stacks.yaml with agent-centric configuration\n * where skills are defined in each agent's agent.yaml file.\n *\n * Migration path:\n * 1. Use loadStackById() to get stack metadata (agents list)\n * 2. Skills come from agent.yaml files, not stack config\n *\n * @see src/cli/lib/stacks-loader.ts\n */\nexport async function loadStack(\n stackId: string,\n projectRoot: string,\n mode: CompileMode = \"dev\",\n): Promise<StackConfig> {\n const cacheKey = `${mode}:${stackId}`;\n const cached = stackCache.get(cacheKey);\n if (cached) return cached;\n\n const dirs = getDirs(mode);\n const stackPath = path.join(projectRoot, dirs.stacks, stackId, \"config.yaml\");\n\n try {\n const content = await readFile(stackPath);\n const stack = parseYaml(content) as StackConfig;\n stackCache.set(cacheKey, stack);\n verbose(`Loaded stack: ${stack.name} (${stackId})`);\n return stack;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load stack '${stackId}': ${errorMessage}. Expected config at: ${stackPath}`,\n );\n }\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport type { Stack, StacksConfig, StackAgentConfig } from \"../types-stacks\";\nimport type { SkillReference } from \"../types\";\n\nconst STACKS_FILE = \"config/stacks.yaml\";\n\nconst stacksCache = new Map<string, Stack[]>();\n\n/**\n * Load all stacks from config/stacks.yaml\n * Stacks are simple agent groupings without skill mappings\n */\nexport async function loadStacks(configDir: string): Promise<Stack[]> {\n const cacheKey = configDir;\n const cached = stacksCache.get(cacheKey);\n if (cached) return cached;\n\n const stacksPath = path.join(configDir, STACKS_FILE);\n\n if (!(await fileExists(stacksPath))) {\n verbose(`No stacks file found at ${stacksPath}`);\n return [];\n }\n\n try {\n const content = await readFile(stacksPath);\n const config = parseYaml(content) as StacksConfig;\n\n if (!config.stacks || !Array.isArray(config.stacks)) {\n verbose(`Invalid stacks.yaml format: missing stacks array`);\n return [];\n }\n\n stacksCache.set(cacheKey, config.stacks);\n verbose(`Loaded ${config.stacks.length} stacks from ${stacksPath}`);\n\n return config.stacks;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load stacks from '${stacksPath}': ${errorMessage}`,\n );\n }\n}\n\n/**\n * Load a specific stack by ID\n * Returns null if stack not found\n */\nexport async function loadStackById(\n stackId: string,\n configDir: string,\n): Promise<Stack | null> {\n const stacks = await loadStacks(configDir);\n const stack = stacks.find((s) => s.id === stackId);\n\n if (!stack) {\n verbose(`Stack '${stackId}' not found`);\n return null;\n }\n\n verbose(`Found stack: ${stack.name} (${stackId})`);\n return stack;\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 a single agent's technology config to skill references.\n * Looks up each technology alias in skill_aliases to get full skill ID.\n *\n * @param agentConfig - The agent's technology selections (subcategory -> alias)\n * @param skillAliases - Mapping from technology aliases to full skill IDs\n * @returns Array of SkillReference objects\n */\nexport function resolveAgentConfigToSkills(\n agentConfig: StackAgentConfig,\n skillAliases: Record<string, string>,\n): SkillReference[] {\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}' (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 return skillRefs;\n}\n\n/**\n * Resolve all agents in a stack to their skill references.\n * Takes a Stack and skill_aliases, returns a mapping of agent IDs to their resolved skills.\n *\n * @param stack - The stack definition with agent technology selections\n * @param skillAliases - Mapping from technology aliases to full skill IDs\n * @returns Record mapping agent IDs to their SkillReference arrays\n *\n * @example\n * ```typescript\n * const stack = {\n * id: 'nextjs-fullstack',\n * name: 'Next.js Fullstack',\n * agents: {\n * 'web-developer': { framework: 'react', styling: 'scss-modules' },\n * 'api-developer': { api: 'hono', database: 'drizzle' }\n * }\n * };\n *\n * const aliases = {\n * react: 'web/framework/react (@vince)',\n * hono: 'api/framework/hono (@vince)',\n * // ...\n * };\n *\n * const result = resolveStackSkillsFromAliases(stack, aliases);\n * // Returns:\n * // {\n * // 'web-developer': [{ id: 'web/framework/react (@vince)', usage: '...', preloaded: true }, ...],\n * // 'api-developer': [{ id: 'api/framework/hono (@vince)', usage: '...', preloaded: true }, ...]\n * // }\n * ```\n */\nexport function resolveStackSkillsFromAliases(\n stack: Stack,\n skillAliases: Record<string, string>,\n): Record<string, SkillReference[]> {\n const result: Record<string, SkillReference[]> = {};\n\n for (const [agentId, agentConfig] of Object.entries(stack.agents)) {\n // Empty config {} means agent has no technology-specific skills\n if (Object.keys(agentConfig).length === 0) {\n result[agentId] = [];\n continue;\n }\n\n result[agentId] = resolveAgentConfigToSkills(agentConfig, skillAliases);\n }\n\n verbose(\n `Resolved skills for ${Object.keys(result).length} agents in stack '${stack.id}'`,\n );\n\n return result;\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { glob, readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { DIRS } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type {\n SkillsMatrixConfig,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n SkillRelation,\n SkillRequirement,\n SkillAlternative,\n} from \"../types-matrix\";\n\ninterface RawMetadata {\n category: string;\n category_exclusive?: boolean;\n author: string;\n version: string;\n cli_name?: string;\n cli_description?: string;\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 async function loadSkillsMatrix(\n configPath: string,\n): Promise<SkillsMatrixConfig> {\n const content = await readFile(configPath);\n const config = parseYaml(content) as SkillsMatrixConfig;\n\n validateMatrixStructure(config, configPath);\n\n verbose(`Loaded skills matrix: ${configPath}`);\n return config;\n}\n\nfunction validateMatrixStructure(\n config: SkillsMatrixConfig,\n configPath: string,\n): void {\n // Note: suggested_stacks removed from required - stacks now defined in config/stacks.yaml (Phase 6)\n const requiredFields = [\n \"version\",\n \"categories\",\n \"relationships\",\n \"skill_aliases\",\n ];\n const missing = requiredFields.filter((field) => !(field in config));\n\n if (missing.length > 0) {\n throw new Error(\n `Skills matrix at ${configPath} is missing required fields: ${missing.join(\", \")}`,\n );\n }\n\n const relationshipFields = [\n \"conflicts\",\n \"recommends\",\n \"requires\",\n \"alternatives\",\n ];\n const missingRelationships = relationshipFields.filter(\n (field) => !config.relationships || !(field in config.relationships),\n );\n\n if (missingRelationships.length > 0) {\n throw new Error(\n `Skills matrix relationships missing required fields: ${missingRelationships.join(\", \")}`,\n );\n }\n\n for (const [categoryId, category] of Object.entries(config.categories)) {\n const requiredCategoryFields = [\n \"id\",\n \"name\",\n \"description\",\n \"exclusive\",\n \"required\",\n \"order\",\n ];\n const missingCategoryFields = requiredCategoryFields.filter(\n (field) => !(field in category),\n );\n\n if (missingCategoryFields.length > 0) {\n throw new Error(\n `Category \"${categoryId}\" missing required fields: ${missingCategoryFields.join(\", \")}`,\n );\n }\n }\n}\n\nexport async function extractAllSkills(\n skillsDir: string,\n): Promise<ExtractedSkillMetadata[]> {\n const skills: ExtractedSkillMetadata[] = [];\n const metadataFiles = await glob(\"**/metadata.yaml\", skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillDir = path.dirname(metadataFile);\n const skillMdPath = path.join(skillsDir, skillDir, \"SKILL.md\");\n const metadataPath = path.join(skillsDir, metadataFile);\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping ${metadataFile}: No SKILL.md found`);\n continue;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as RawMetadata;\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(`Skipping ${metadataFile}: Invalid SKILL.md frontmatter`);\n continue;\n }\n\n if (!metadata.cli_name) {\n throw new Error(\n `Skill at ${metadataFile} is missing required 'cli_name' field in metadata.yaml`,\n );\n }\n\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDir,\n name: metadata.cli_name,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: metadata.usage_guidance,\n category: metadata.category,\n categoryExclusive: metadata.category_exclusive ?? true,\n author: metadata.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: `skills/${skillDir}/`,\n };\n\n skills.push(extracted);\n verbose(`Extracted skill: ${skillId}`);\n }\n\n return skills;\n}\n\nfunction buildReverseAliases(\n aliases: Record<string, string>,\n): Record<string, string> {\n const reverse: Record<string, string> = {};\n for (const [alias, fullId] of Object.entries(aliases)) {\n reverse[fullId] = alias;\n }\n return reverse;\n}\n\n/**\n * Build a map from short names to actual skill IDs.\n *\n * This handles multiple formats used in skill metadata:\n * - \"react (@vince)\" -> \"web/framework/react (@vince)\"\n * - \"react\" -> \"web/framework/react (@vince)\"\n * - Old alias targets that may still exist in metadata files\n */\nfunction buildAliasTargetToSkillIdMap(\n aliases: Record<string, string>,\n skills: ExtractedSkillMetadata[],\n): Record<string, string> {\n const map: Record<string, string> = {};\n\n for (const skill of skills) {\n // Extract the \"short author\" form: last path segment with author\n // e.g., \"web/framework/react (@vince)\" -> \"react (@vince)\"\n const parts = skill.id.split(\"/\");\n const shortForm = parts[parts.length - 1];\n\n if (shortForm && shortForm !== skill.id) {\n map[shortForm] = skill.id;\n }\n\n // Also map directory name without author if different\n // e.g., \"web/framework/react\" -> \"web/framework/react (@vince)\"\n if (skill.directoryPath && skill.directoryPath !== skill.id) {\n map[skill.directoryPath] = skill.id;\n }\n }\n\n // Also include any old-style alias targets that might still be referenced\n const aliasTargets = new Set(Object.values(aliases));\n for (const skill of skills) {\n for (const aliasTarget of aliasTargets) {\n if (\n aliasTarget !== skill.id &&\n (skill.id.endsWith(`/${aliasTarget}`) || skill.id === aliasTarget)\n ) {\n map[aliasTarget] = skill.id;\n }\n }\n }\n\n return map;\n}\n\nfunction buildDirectoryPathToIdMap(\n skills: ExtractedSkillMetadata[],\n): Record<string, string> {\n const map: Record<string, string> = {};\n for (const skill of skills) {\n if (skill.directoryPath && skill.directoryPath !== skill.id) {\n map[skill.directoryPath] = skill.id;\n }\n }\n return map;\n}\n\nfunction resolveToCanonicalId(\n aliasOrId: string,\n aliases: Record<string, string>,\n directoryPathToId: Record<string, string> = {},\n aliasTargetToSkillId: Record<string, string> = {},\n): string {\n if (aliases[aliasOrId]) {\n return aliases[aliasOrId];\n }\n if (directoryPathToId[aliasOrId]) {\n return directoryPathToId[aliasOrId];\n }\n // Handle \"short author\" format like \"react (@vince)\" that maps to full ID\n if (aliasTargetToSkillId[aliasOrId]) {\n return aliasTargetToSkillId[aliasOrId];\n }\n return aliasOrId;\n}\n\nexport async function mergeMatrixWithSkills(\n matrix: SkillsMatrixConfig,\n skills: ExtractedSkillMetadata[],\n): Promise<MergedSkillsMatrix> {\n const aliases = matrix.skill_aliases;\n const aliasesReverse = buildReverseAliases(aliases);\n const directoryPathToId = buildDirectoryPathToIdMap(skills);\n const aliasTargetToSkillId = buildAliasTargetToSkillIdMap(aliases, skills);\n const resolvedSkills: Record<string, ResolvedSkill> = {};\n\n for (const skill of skills) {\n const resolved = buildResolvedSkill(\n skill,\n matrix,\n aliases,\n aliasesReverse,\n directoryPathToId,\n aliasTargetToSkillId,\n );\n resolvedSkills[skill.id] = resolved;\n }\n\n computeInverseRelationships(resolvedSkills);\n const suggestedStacks = resolveSuggestedStacks(\n matrix,\n aliases,\n aliasTargetToSkillId,\n );\n\n const merged: MergedSkillsMatrix = {\n version: matrix.version,\n categories: matrix.categories,\n skills: resolvedSkills,\n suggestedStacks,\n aliases,\n aliasesReverse,\n generatedAt: new Date().toISOString(),\n };\n\n return merged;\n}\n\nfunction buildResolvedSkill(\n skill: ExtractedSkillMetadata,\n matrix: SkillsMatrixConfig,\n aliases: Record<string, string>,\n aliasesReverse: Record<string, string>,\n directoryPathToId: Record<string, string>,\n aliasTargetToSkillId: Record<string, string>,\n): ResolvedSkill {\n const conflictsWith: SkillRelation[] = [];\n const recommends: SkillRelation[] = [];\n const requires: SkillRequirement[] = [];\n const alternatives: SkillAlternative[] = [];\n const discourages: SkillRelation[] = [];\n\n // Helper to resolve with all maps\n const resolve = (id: string) =>\n resolveToCanonicalId(id, aliases, directoryPathToId, aliasTargetToSkillId);\n\n for (const conflictRef of skill.conflictsWith) {\n const canonicalId = resolve(conflictRef);\n conflictsWith.push({\n skillId: canonicalId,\n reason: \"Defined in skill metadata\",\n });\n }\n\n for (const conflictRule of matrix.relationships.conflicts) {\n const resolvedSkills = conflictRule.skills.map(resolve);\n if (resolvedSkills.includes(skill.id)) {\n for (const otherSkill of resolvedSkills) {\n if (otherSkill !== skill.id) {\n if (!conflictsWith.some((c) => c.skillId === otherSkill)) {\n conflictsWith.push({\n skillId: otherSkill,\n reason: conflictRule.reason,\n });\n }\n }\n }\n }\n }\n\n for (const compatRef of skill.compatibleWith) {\n const canonicalId = resolve(compatRef);\n recommends.push({\n skillId: canonicalId,\n reason: \"Compatible with this skill\",\n });\n }\n\n for (const recommendRule of matrix.relationships.recommends) {\n const whenCanonicalId = resolve(recommendRule.when);\n if (whenCanonicalId === skill.id) {\n for (const suggested of recommendRule.suggest) {\n const canonicalId = resolve(suggested);\n if (!recommends.some((r) => r.skillId === canonicalId)) {\n recommends.push({\n skillId: canonicalId,\n reason: recommendRule.reason,\n });\n }\n }\n }\n }\n\n if (skill.requires.length > 0) {\n requires.push({\n skillIds: skill.requires.map(resolve),\n needsAny: false,\n reason: \"Defined in skill metadata\",\n });\n }\n\n for (const requireRule of matrix.relationships.requires) {\n const skillCanonicalId = resolve(requireRule.skill);\n if (skillCanonicalId === skill.id) {\n requires.push({\n skillIds: requireRule.needs.map(resolve),\n needsAny: requireRule.needs_any ?? false,\n reason: requireRule.reason,\n });\n }\n }\n\n for (const altGroup of matrix.relationships.alternatives) {\n const resolvedAlts = altGroup.skills.map(resolve);\n if (resolvedAlts.includes(skill.id)) {\n for (const altSkill of resolvedAlts) {\n if (altSkill !== skill.id) {\n alternatives.push({\n skillId: altSkill,\n purpose: altGroup.purpose,\n });\n }\n }\n }\n }\n\n if (matrix.relationships.discourages) {\n for (const discourageRule of matrix.relationships.discourages) {\n const resolvedSkills = discourageRule.skills.map(resolve);\n if (resolvedSkills.includes(skill.id)) {\n for (const otherSkill of resolvedSkills) {\n if (otherSkill !== skill.id) {\n if (!discourages.some((d) => d.skillId === otherSkill)) {\n discourages.push({\n skillId: otherSkill,\n reason: discourageRule.reason,\n });\n }\n }\n }\n }\n }\n }\n\n // Preserve compatibleWith as resolved skill IDs for framework-first filtering\n const compatibleWith = skill.compatibleWith.map(resolve);\n\n return {\n id: skill.id,\n alias: aliasesReverse[skill.id],\n name: skill.name,\n description: skill.description,\n usageGuidance: skill.usageGuidance,\n category: skill.category,\n categoryExclusive: skill.categoryExclusive,\n tags: skill.tags,\n author: skill.author,\n conflictsWith,\n recommends,\n recommendedBy: [],\n requires,\n requiredBy: [],\n alternatives,\n discourages,\n compatibleWith,\n requiresSetup: skill.requiresSetup.map(resolve),\n providesSetupFor: skill.providesSetupFor.map(resolve),\n path: skill.path,\n };\n}\n\nfunction computeInverseRelationships(\n skills: Record<string, ResolvedSkill>,\n): void {\n for (const skill of Object.values(skills)) {\n for (const recommend of skill.recommends) {\n const targetSkill = skills[recommend.skillId];\n if (targetSkill) {\n targetSkill.recommendedBy.push({\n skillId: skill.id,\n reason: recommend.reason,\n });\n }\n }\n\n for (const requirement of skill.requires) {\n for (const requiredId of requirement.skillIds) {\n const targetSkill = skills[requiredId];\n if (targetSkill) {\n targetSkill.requiredBy.push({\n skillId: skill.id,\n reason: requirement.reason,\n });\n }\n }\n }\n }\n}\n\nfunction resolveSuggestedStacks(\n matrix: SkillsMatrixConfig,\n aliases: Record<string, string>,\n aliasTargetToSkillId: Record<string, string>,\n): ResolvedStack[] {\n // Phase 6: suggested_stacks is now optional (stacks moved to config/stacks.yaml)\n if (!matrix.suggested_stacks) {\n return [];\n }\n return matrix.suggested_stacks.map((stack) => {\n const resolvedSkillsMap: Record<string, Record<string, string>> = {};\n const allSkillIds: string[] = [];\n\n for (const [category, subcategories] of Object.entries(stack.skills)) {\n resolvedSkillsMap[category] = {};\n for (const [subcategory, alias] of Object.entries(subcategories)) {\n // First resolve the alias to its target (e.g., \"react\" -> \"react (@vince)\")\n const aliasTarget = resolveToCanonicalId(alias, aliases);\n // Then check if the alias target needs to be mapped to a full skill ID\n // (e.g., \"react (@vince)\" -> \"web/framework/react (@vince)\")\n const canonicalId = aliasTargetToSkillId[aliasTarget] || aliasTarget;\n resolvedSkillsMap[category][subcategory] = canonicalId;\n allSkillIds.push(canonicalId);\n }\n }\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: stack.audience,\n skills: resolvedSkillsMap,\n allSkillIds,\n philosophy: stack.philosophy,\n };\n });\n}\n\nexport async function loadAndMergeSkillsMatrix(\n matrixPath: string,\n projectRoot: string,\n): Promise<MergedSkillsMatrix> {\n const matrix = await loadSkillsMatrix(matrixPath);\n const skillsDir = path.join(projectRoot, DIRS.skills);\n const skills = await extractAllSkills(skillsDir);\n return mergeMatrixWithSkills(matrix, skills);\n}\n"],"mappings":"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","names":["parseYaml","path","path","parseYaml","parseYaml","path","parseYaml","path"]}
|
package/dist/chunk-BDLUZVKU.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
init_esm_shims
|
|
4
|
-
} from "./chunk-DHET7RCE.js";
|
|
5
|
-
|
|
6
|
-
// src/cli/components/wizard/section-progress.tsx
|
|
7
|
-
init_esm_shims();
|
|
8
|
-
import { Box, Text } from "ink";
|
|
9
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
var SectionProgress = ({
|
|
11
|
-
label,
|
|
12
|
-
current,
|
|
13
|
-
index,
|
|
14
|
-
total,
|
|
15
|
-
next
|
|
16
|
-
}) => {
|
|
17
|
-
const isLast = index === total;
|
|
18
|
-
const rightText = isLast ? "Last step" : `Next: ${next}`;
|
|
19
|
-
return /* @__PURE__ */ jsxs(
|
|
20
|
-
Box,
|
|
21
|
-
{
|
|
22
|
-
flexDirection: "row",
|
|
23
|
-
justifyContent: "space-between",
|
|
24
|
-
paddingX: 2,
|
|
25
|
-
marginBottom: 1,
|
|
26
|
-
children: [
|
|
27
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
28
|
-
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
29
|
-
label,
|
|
30
|
-
":"
|
|
31
|
-
] }),
|
|
32
|
-
" ",
|
|
33
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: current })
|
|
34
|
-
] }),
|
|
35
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
36
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
37
|
-
"[",
|
|
38
|
-
index,
|
|
39
|
-
"/",
|
|
40
|
-
total,
|
|
41
|
-
"]"
|
|
42
|
-
] }),
|
|
43
|
-
" ",
|
|
44
|
-
/* @__PURE__ */ jsx(Text, { dimColor: isLast, children: rightText })
|
|
45
|
-
] })
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export {
|
|
52
|
-
SectionProgress
|
|
53
|
-
};
|
|
54
|
-
//# sourceMappingURL=chunk-BDLUZVKU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/wizard/section-progress.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport interface SectionProgressProps {\n /** Section label (e.g., \"Domain\" or \"Skill\") */\n label: string;\n /** Current item name (e.g., \"Web\" or \"react\") */\n current: string;\n /** 1-based index */\n index: number;\n /** Total count */\n total: number;\n /** Next item name, or undefined if last */\n next?: string;\n}\n\nexport const SectionProgress: React.FC<SectionProgressProps> = ({\n label,\n current,\n index,\n total,\n next,\n}) => {\n const isLast = index === total;\n const rightText = isLast ? \"Last step\" : `Next: ${next}`;\n\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n marginBottom={1}\n >\n <Text>\n <Text bold>{label}:</Text> <Text color=\"cyan\">{current}</Text>\n </Text>\n <Text>\n <Text dimColor>\n [{index}/{total}]\n </Text>{\" \"}\n <Text dimColor={isLast}>{rightText}</Text>\n </Text>\n </Box>\n );\n};\n"],"mappings":";;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAiClB,SAA2B,KAA3B;AAlBD,IAAM,kBAAkD,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,SAAS,UAAU;AACzB,QAAM,YAAY,SAAS,cAAc,SAAS,IAAI;AAEtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,MAEd;AAAA,6BAAC,QACC;AAAA,+BAAC,QAAK,MAAI,MAAE;AAAA;AAAA,YAAM;AAAA,aAAC;AAAA,UAAO;AAAA,UAAC,oBAAC,QAAK,OAAM,QAAQ,mBAAQ;AAAA,WACzD;AAAA,QACA,qBAAC,QACC;AAAA,+BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,YACX;AAAA,YAAM;AAAA,YAAE;AAAA,YAAM;AAAA,aAClB;AAAA,UAAQ;AAAA,UACR,oBAAC,QAAK,UAAU,QAAS,qBAAU;AAAA,WACrC;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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 from matrix.suggestedStacks\n * - Selecting a stack populates domainSelections and goes to stack-options\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 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\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst BACK_VALUE = \"_back\";\nconst CONTINUE_VALUE = \"_continue\";\n\n/** Available domains for scratch path */\nconst AVAILABLE_DOMAINS = [\n { id: \"web\", label: \"Web\", description: \"Frontend web applications\" },\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, goBack } = useWizardStore();\n\n // Build options from matrix.suggestedStacks\n const options = [\n { value: BACK_VALUE, label: \"\\u2190 Back\" },\n ...matrix.suggestedStacks.map((stack) => ({\n value: stack.id,\n label: `${stack.name} - ${stack.description}`,\n })),\n ];\n\n const handleSelect = (value: string) => {\n if (value === BACK_VALUE) {\n goBack();\n return;\n }\n\n const stack = matrix.suggestedStacks.find((s) => s.id === value);\n if (stack) {\n selectStack(stack.id);\n setStep(\"stack-options\");\n }\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Select a pre-built template:</Text>\n <Box marginTop={1}>\n <Select\n options={options}\n onChange={handleSelect}\n visibleOptionCount={options.length}\n />\n </Box>\n <Box marginTop={1}>\n <Text dimColor>\n {\"\\u2191\"}/{\"\\u2193\"} navigate ENTER select ESC back\n </Text>\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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/stores/wizard-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { DEFAULT_PRESELECTED_SKILLS } from \"../consts\";\n\n// Step types for the wizard\nexport type WizardStep =\n | \"approach\" // Choose stack template or build from scratch\n | \"stack\" // Select pre-built stack (if approach=stack) or domains (if approach=scratch)\n | \"stack-options\" // After stack selection: continue defaults or customize\n | \"build\" // CategoryGrid for technology selection\n | \"refine\" // Skill source selection\n | \"confirm\"; // Final confirmation\n\nexport interface WizardState {\n // ─────────────────────────────────────────────────────────────────\n // Current step\n // ─────────────────────────────────────────────────────────────────\n step: WizardStep;\n\n // ─────────────────────────────────────────────────────────────────\n // Flow tracking\n // ─────────────────────────────────────────────────────────────────\n approach: \"stack\" | \"scratch\" | null;\n selectedStackId: string | null;\n stackAction: \"defaults\" | \"customize\" | null; // For stack flow after selection\n\n // ─────────────────────────────────────────────────────────────────\n // Domain selection (scratch flow or customize flow)\n // ─────────────────────────────────────────────────────────────────\n selectedDomains: string[]; // ['web', 'api', 'cli', 'mobile']\n\n // ─────────────────────────────────────────────────────────────────\n // Build step state\n // ─────────────────────────────────────────────────────────────────\n currentDomainIndex: number; // Which domain we're configuring (0-based)\n domainSelections: Record<string, Record<string, string[]>>;\n // e.g., { web: { framework: ['react'], styling: ['scss-modules'] } }\n // Note: array supports multi-select categories\n\n // ─────────────────────────────────────────────────────────────────\n // Grid navigation state\n // ─────────────────────────────────────────────────────────────────\n focusedRow: number;\n focusedCol: number;\n\n // ─────────────────────────────────────────────────────────────────\n // Refine step state\n // ─────────────────────────────────────────────────────────────────\n currentRefineIndex: number; // Which skill we're refining\n skillSources: Record<string, string>; // technology -> selected skill ID\n refineAction: \"all-recommended\" | \"customize\" | null;\n\n // ─────────────────────────────────────────────────────────────────\n // UI state\n // ─────────────────────────────────────────────────────────────────\n showDescriptions: boolean;\n expertMode: boolean;\n\n // ─────────────────────────────────────────────────────────────────\n // Modes\n // ─────────────────────────────────────────────────────────────────\n installMode: \"plugin\" | \"local\";\n\n // ─────────────────────────────────────────────────────────────────\n // Navigation history\n // ─────────────────────────────────────────────────────────────────\n history: WizardStep[];\n\n // ─────────────────────────────────────────────────────────────────\n // Actions\n // ─────────────────────────────────────────────────────────────────\n setStep: (step: WizardStep) => void;\n setApproach: (approach: \"stack\" | \"scratch\") => void;\n selectStack: (stackId: string | null) => void;\n setStackAction: (action: \"defaults\" | \"customize\") => void;\n /** Pre-populate domainSelections from a stack's technology mappings */\n populateFromStack: (\n stack: { agents: Record<string, Record<string, string>> },\n categories: Record<string, { domain?: string }>,\n ) => void;\n toggleDomain: (domain: string) => void;\n setDomainSelection: (\n domain: string,\n subcategory: string,\n technologies: string[],\n ) => void;\n toggleTechnology: (\n domain: string,\n subcategory: string,\n technology: string,\n exclusive: boolean,\n ) => void;\n setCurrentDomainIndex: (index: number) => void;\n nextDomain: () => boolean; // Returns true if moved to next domain, false if at end\n prevDomain: () => boolean; // Returns true if moved to prev domain, false if at start\n setFocus: (row: number, col: number) => void;\n setRefineAction: (action: \"all-recommended\" | \"customize\") => void;\n setSkillSource: (technology: string, skillId: string) => void;\n setCurrentRefineIndex: (index: number) => void;\n toggleShowDescriptions: () => void;\n toggleExpertMode: () => void;\n toggleInstallMode: () => void;\n goBack: () => void;\n reset: () => void;\n\n // ─────────────────────────────────────────────────────────────────\n // Computed getters (derive from state)\n // ─────────────────────────────────────────────────────────────────\n getAllSelectedTechnologies: () => string[];\n getCurrentDomain: () => string | null;\n getSelectedSkills: () => string[]; // All selected skills including preselected\n}\n\nconst createInitialState = () => ({\n step: \"approach\" as WizardStep,\n approach: null as \"stack\" | \"scratch\" | null,\n selectedStackId: null as string | null,\n stackAction: null as \"defaults\" | \"customize\" | null,\n selectedDomains: [] as string[],\n currentDomainIndex: 0,\n domainSelections: {} as Record<string, Record<string, string[]>>,\n focusedRow: 0,\n focusedCol: 0,\n currentRefineIndex: 0,\n skillSources: {} as Record<string, string>,\n refineAction: null as \"all-recommended\" | \"customize\" | null,\n showDescriptions: false,\n expertMode: false,\n installMode: \"local\" as \"plugin\" | \"local\",\n history: [] as WizardStep[],\n});\n\nexport const useWizardStore = create<WizardState>((set, get) => ({\n ...createInitialState(),\n\n setStep: (step) =>\n set((state) => ({\n step,\n history: [...state.history, state.step],\n // Reset focus when changing steps\n focusedRow: 0,\n focusedCol: 0,\n })),\n\n setApproach: (approach) => set({ approach }),\n\n selectStack: (stackId) => set({ selectedStackId: stackId }),\n\n setStackAction: (action) => set({ stackAction: action }),\n\n populateFromStack: (stack, categories) =>\n set(() => {\n const domainSelections: Record<string, Record<string, string[]>> = {};\n const domains = new Set<string>();\n\n // Iterate through all agents in the stack\n for (const agentConfig of Object.values(stack.agents)) {\n // Each agent has subcategory -> technology alias mappings\n for (const [subcategoryId, technologyAlias] of Object.entries(\n agentConfig,\n )) {\n const category = categories[subcategoryId];\n const domain = category?.domain;\n\n if (!domain) {\n // Skip if subcategory doesn't have a domain (top-level categories)\n continue;\n }\n\n domains.add(domain);\n\n // Initialize domain if needed\n if (!domainSelections[domain]) {\n domainSelections[domain] = {};\n }\n\n // Initialize subcategory array if needed\n if (!domainSelections[domain][subcategoryId]) {\n domainSelections[domain][subcategoryId] = [];\n }\n\n // Add technology if not already present\n if (\n !domainSelections[domain][subcategoryId].includes(technologyAlias)\n ) {\n domainSelections[domain][subcategoryId].push(technologyAlias);\n }\n }\n }\n\n return {\n domainSelections,\n selectedDomains: Array.from(domains),\n };\n }),\n\n toggleDomain: (domain) =>\n set((state) => {\n const isSelected = state.selectedDomains.includes(domain);\n return {\n selectedDomains: isSelected\n ? state.selectedDomains.filter((d) => d !== domain)\n : [...state.selectedDomains, domain],\n };\n }),\n\n setDomainSelection: (domain, subcategory, technologies) =>\n set((state) => ({\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [subcategory]: technologies,\n },\n },\n })),\n\n toggleTechnology: (domain, subcategory, technology, exclusive) =>\n set((state) => {\n const currentSelections =\n state.domainSelections[domain]?.[subcategory] || [];\n const isSelected = currentSelections.includes(technology);\n\n let newSelections: string[];\n if (exclusive) {\n // For exclusive categories, toggle off if already selected, otherwise select only this one\n newSelections = isSelected ? [] : [technology];\n } else {\n // For multi-select categories, toggle the selection\n newSelections = isSelected\n ? currentSelections.filter((t) => t !== technology)\n : [...currentSelections, technology];\n }\n\n return {\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [subcategory]: newSelections,\n },\n },\n };\n }),\n\n setCurrentDomainIndex: (index) =>\n set({ currentDomainIndex: index, focusedRow: 0, focusedCol: 0 }),\n\n nextDomain: () => {\n const state = get();\n if (state.currentDomainIndex < state.selectedDomains.length - 1) {\n set({\n currentDomainIndex: state.currentDomainIndex + 1,\n focusedRow: 0,\n focusedCol: 0,\n });\n return true;\n }\n return false;\n },\n\n prevDomain: () => {\n const state = get();\n if (state.currentDomainIndex > 0) {\n set({\n currentDomainIndex: state.currentDomainIndex - 1,\n focusedRow: 0,\n focusedCol: 0,\n });\n return true;\n }\n return false;\n },\n\n setFocus: (row, col) => set({ focusedRow: row, focusedCol: col }),\n\n setRefineAction: (action) => set({ refineAction: action }),\n\n setSkillSource: (technology, skillId) =>\n set((state) => ({\n skillSources: {\n ...state.skillSources,\n [technology]: skillId,\n },\n })),\n\n setCurrentRefineIndex: (index) => set({ currentRefineIndex: index }),\n\n toggleShowDescriptions: () =>\n set((state) => ({ showDescriptions: !state.showDescriptions })),\n\n toggleExpertMode: () => set((state) => ({ expertMode: !state.expertMode })),\n\n toggleInstallMode: () =>\n set((state) => ({\n installMode: state.installMode === \"plugin\" ? \"local\" : \"plugin\",\n })),\n\n goBack: () =>\n set((state) => {\n const history = [...state.history];\n const previousStep = history.pop();\n return {\n step: previousStep || \"approach\",\n history,\n focusedRow: 0,\n focusedCol: 0,\n };\n }),\n\n reset: () => set(createInitialState()),\n\n // ─────────────────────────────────────────────────────────────────\n // Computed getters\n // ─────────────────────────────────────────────────────────────────\n getAllSelectedTechnologies: () => {\n const state = get();\n const technologies: string[] = [];\n for (const domain of Object.keys(state.domainSelections)) {\n for (const subcategory of Object.keys(state.domainSelections[domain])) {\n technologies.push(...state.domainSelections[domain][subcategory]);\n }\n }\n return technologies;\n },\n\n getCurrentDomain: () => {\n const state = get();\n return state.selectedDomains[state.currentDomainIndex] || null;\n },\n\n getSelectedSkills: () => {\n const state = get();\n // Include preselected methodology skills plus resolved skill sources\n const skillIds: string[] = [...DEFAULT_PRESELECTED_SKILLS];\n for (const skillId of Object.values(state.skillSources)) {\n if (!skillIds.includes(skillId)) {\n skillIds.push(skillId);\n }\n }\n return skillIds;\n },\n}));\n"],"mappings":"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","names":[]}
|
package/dist/chunk-DRXPNNPB.js
DELETED
|
@@ -1,393 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
generateStackPluginManifest,
|
|
4
|
-
getPluginManifestPath,
|
|
5
|
-
writePluginManifest
|
|
6
|
-
} from "./chunk-GDH553MV.js";
|
|
7
|
-
import {
|
|
8
|
-
createLiquidEngine,
|
|
9
|
-
resolveAgents,
|
|
10
|
-
stackToCompileConfig
|
|
11
|
-
} from "./chunk-I4TPKIYX.js";
|
|
12
|
-
import {
|
|
13
|
-
hashString
|
|
14
|
-
} from "./chunk-KAAEN2PO.js";
|
|
15
|
-
import {
|
|
16
|
-
loadAllAgents,
|
|
17
|
-
loadSkillsByIds,
|
|
18
|
-
loadSkillsMatrix,
|
|
19
|
-
loadStackById,
|
|
20
|
-
resolveAgentConfigToSkills
|
|
21
|
-
} from "./chunk-B7CCVP6Q.js";
|
|
22
|
-
import {
|
|
23
|
-
verbose
|
|
24
|
-
} from "./chunk-3U3R4NCG.js";
|
|
25
|
-
import {
|
|
26
|
-
copy,
|
|
27
|
-
directoryExists,
|
|
28
|
-
ensureDir,
|
|
29
|
-
fileExists,
|
|
30
|
-
readFile,
|
|
31
|
-
readFileOptional,
|
|
32
|
-
writeFile
|
|
33
|
-
} from "./chunk-TKFPKEV3.js";
|
|
34
|
-
import {
|
|
35
|
-
DEFAULT_VERSION,
|
|
36
|
-
DIRS,
|
|
37
|
-
PROJECT_ROOT,
|
|
38
|
-
SKILLS_MATRIX_PATH
|
|
39
|
-
} from "./chunk-76DWXGQE.js";
|
|
40
|
-
import {
|
|
41
|
-
init_esm_shims
|
|
42
|
-
} from "./chunk-DHET7RCE.js";
|
|
43
|
-
|
|
44
|
-
// src/cli/lib/stack-plugin-compiler.ts
|
|
45
|
-
init_esm_shims();
|
|
46
|
-
import path from "path";
|
|
47
|
-
var CONTENT_HASH_FILE = ".content-hash";
|
|
48
|
-
function parseMajorVersion(version) {
|
|
49
|
-
const match = version.match(/^(\d+)\./);
|
|
50
|
-
return match ? parseInt(match[1], 10) : 1;
|
|
51
|
-
}
|
|
52
|
-
function bumpMajorVersion(version) {
|
|
53
|
-
const major = parseMajorVersion(version);
|
|
54
|
-
return `${major + 1}.0.0`;
|
|
55
|
-
}
|
|
56
|
-
async function readExistingManifest(pluginDir) {
|
|
57
|
-
const manifestPath = getPluginManifestPath(pluginDir);
|
|
58
|
-
if (!await fileExists(manifestPath)) {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const content = await readFile(manifestPath);
|
|
63
|
-
const manifest = JSON.parse(content);
|
|
64
|
-
const hashFilePath = manifestPath.replace("plugin.json", CONTENT_HASH_FILE);
|
|
65
|
-
let contentHash;
|
|
66
|
-
if (await fileExists(hashFilePath)) {
|
|
67
|
-
contentHash = (await readFile(hashFilePath)).trim();
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
version: manifest.version ?? DEFAULT_VERSION,
|
|
71
|
-
contentHash
|
|
72
|
-
};
|
|
73
|
-
} catch {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function hashStackConfig(stack) {
|
|
78
|
-
const parts = [
|
|
79
|
-
`name:${stack.name}`,
|
|
80
|
-
`description:${stack.description ?? ""}`,
|
|
81
|
-
`skills:${(stack.skills || []).map((s) => s.id).sort().join(",")}`,
|
|
82
|
-
`agents:${Object.keys(stack.agents || {}).sort().join(",")}`
|
|
83
|
-
];
|
|
84
|
-
return hashString(parts.join("\n"));
|
|
85
|
-
}
|
|
86
|
-
async function determineStackVersion(stack, pluginDir) {
|
|
87
|
-
const newHash = hashStackConfig(stack);
|
|
88
|
-
const existing = await readExistingManifest(pluginDir);
|
|
89
|
-
if (!existing) {
|
|
90
|
-
return {
|
|
91
|
-
version: DEFAULT_VERSION,
|
|
92
|
-
contentHash: newHash
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
if (existing.contentHash !== newHash) {
|
|
96
|
-
return {
|
|
97
|
-
version: bumpMajorVersion(existing.version),
|
|
98
|
-
contentHash: newHash
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
version: existing.version,
|
|
103
|
-
contentHash: newHash
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
async function compileAgentForPlugin(name, agent, fallbackRoot, engine) {
|
|
107
|
-
verbose(`Compiling agent: ${name}`);
|
|
108
|
-
const agentSourceRoot = agent.sourceRoot || fallbackRoot;
|
|
109
|
-
const agentBaseDir = agent.agentBaseDir || DIRS.agents;
|
|
110
|
-
const agentDir = path.join(agentSourceRoot, agentBaseDir, agent.path || name);
|
|
111
|
-
const intro = await readFile(path.join(agentDir, "intro.md"));
|
|
112
|
-
const workflow = await readFile(path.join(agentDir, "workflow.md"));
|
|
113
|
-
const examples = await readFileOptional(
|
|
114
|
-
path.join(agentDir, "examples.md"),
|
|
115
|
-
"## Examples\n\n_No examples defined._"
|
|
116
|
-
);
|
|
117
|
-
const criticalRequirementsTop = await readFileOptional(
|
|
118
|
-
path.join(agentDir, "critical-requirements.md"),
|
|
119
|
-
""
|
|
120
|
-
);
|
|
121
|
-
const criticalReminders = await readFileOptional(
|
|
122
|
-
path.join(agentDir, "critical-reminders.md"),
|
|
123
|
-
""
|
|
124
|
-
);
|
|
125
|
-
const agentPath = agent.path || name;
|
|
126
|
-
const category = agentPath.split("/")[0];
|
|
127
|
-
const categoryDir = path.join(agentSourceRoot, agentBaseDir, category);
|
|
128
|
-
let outputFormat = await readFileOptional(
|
|
129
|
-
path.join(agentDir, "output-format.md"),
|
|
130
|
-
""
|
|
131
|
-
);
|
|
132
|
-
if (!outputFormat) {
|
|
133
|
-
outputFormat = await readFileOptional(
|
|
134
|
-
path.join(categoryDir, "output-format.md"),
|
|
135
|
-
""
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
const preloadedSkills = agent.skills.filter((s) => s.preloaded);
|
|
139
|
-
const dynamicSkills = agent.skills.filter((s) => !s.preloaded);
|
|
140
|
-
const preloadedSkillIds = preloadedSkills.map((s) => s.id);
|
|
141
|
-
verbose(
|
|
142
|
-
`Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`
|
|
143
|
-
);
|
|
144
|
-
const data = {
|
|
145
|
-
agent,
|
|
146
|
-
intro,
|
|
147
|
-
workflow,
|
|
148
|
-
examples,
|
|
149
|
-
criticalRequirementsTop,
|
|
150
|
-
criticalReminders,
|
|
151
|
-
outputFormat,
|
|
152
|
-
skills: agent.skills,
|
|
153
|
-
preloadedSkills,
|
|
154
|
-
dynamicSkills,
|
|
155
|
-
preloadedSkillIds
|
|
156
|
-
};
|
|
157
|
-
return engine.renderFile("agent", data);
|
|
158
|
-
}
|
|
159
|
-
function generateStackReadme(stackId, stack, agents, skillPlugins) {
|
|
160
|
-
const lines = [];
|
|
161
|
-
lines.push(`# ${stack.name}`);
|
|
162
|
-
lines.push("");
|
|
163
|
-
lines.push(stack.description || "A Claude Code stack plugin.");
|
|
164
|
-
lines.push("");
|
|
165
|
-
if (stack.tags && stack.tags.length > 0) {
|
|
166
|
-
lines.push("## Tags");
|
|
167
|
-
lines.push("");
|
|
168
|
-
lines.push(stack.tags.map((t) => `\`${t}\``).join(" "));
|
|
169
|
-
lines.push("");
|
|
170
|
-
}
|
|
171
|
-
lines.push("## Installation");
|
|
172
|
-
lines.push("");
|
|
173
|
-
lines.push("Add this plugin to your Claude Code configuration:");
|
|
174
|
-
lines.push("");
|
|
175
|
-
lines.push("```json");
|
|
176
|
-
lines.push(`{`);
|
|
177
|
-
lines.push(` "plugins": ["${stackId}"]`);
|
|
178
|
-
lines.push(`}`);
|
|
179
|
-
lines.push("```");
|
|
180
|
-
lines.push("");
|
|
181
|
-
lines.push("## Agents");
|
|
182
|
-
lines.push("");
|
|
183
|
-
lines.push("This stack includes the following agents:");
|
|
184
|
-
lines.push("");
|
|
185
|
-
for (const agent of agents) {
|
|
186
|
-
lines.push(`- \`${agent}\``);
|
|
187
|
-
}
|
|
188
|
-
lines.push("");
|
|
189
|
-
if (skillPlugins.length > 0) {
|
|
190
|
-
lines.push("## Included Skills");
|
|
191
|
-
lines.push("");
|
|
192
|
-
lines.push("This stack includes the following skills:");
|
|
193
|
-
lines.push("");
|
|
194
|
-
const uniqueSkills = [...new Set(skillPlugins)].sort();
|
|
195
|
-
for (const skill of uniqueSkills) {
|
|
196
|
-
lines.push(`- \`${skill}\``);
|
|
197
|
-
}
|
|
198
|
-
lines.push("");
|
|
199
|
-
}
|
|
200
|
-
if (stack.philosophy) {
|
|
201
|
-
lines.push("## Philosophy");
|
|
202
|
-
lines.push("");
|
|
203
|
-
lines.push(stack.philosophy);
|
|
204
|
-
lines.push("");
|
|
205
|
-
}
|
|
206
|
-
if (stack.principles && stack.principles.length > 0) {
|
|
207
|
-
lines.push("## Principles");
|
|
208
|
-
lines.push("");
|
|
209
|
-
for (const principle of stack.principles) {
|
|
210
|
-
lines.push(`- ${principle}`);
|
|
211
|
-
}
|
|
212
|
-
lines.push("");
|
|
213
|
-
}
|
|
214
|
-
lines.push("---");
|
|
215
|
-
lines.push("");
|
|
216
|
-
lines.push("*Generated by Claude Collective stack-plugin-compiler*");
|
|
217
|
-
lines.push("");
|
|
218
|
-
return lines.join("\n");
|
|
219
|
-
}
|
|
220
|
-
function stackHasHooks(stack) {
|
|
221
|
-
return stack.hooks !== void 0 && Object.keys(stack.hooks).length > 0;
|
|
222
|
-
}
|
|
223
|
-
function generateHooksJson(hooks) {
|
|
224
|
-
const output = { hooks };
|
|
225
|
-
return JSON.stringify(output, null, 2);
|
|
226
|
-
}
|
|
227
|
-
async function compileStackPlugin(options) {
|
|
228
|
-
const { stackId, outputDir, projectRoot, agentSourcePath } = options;
|
|
229
|
-
const localAgentRoot = agentSourcePath || projectRoot;
|
|
230
|
-
verbose(`Compiling stack plugin: ${stackId}`);
|
|
231
|
-
verbose(` Stack/skills source: ${projectRoot}`);
|
|
232
|
-
verbose(` Local agent source: ${localAgentRoot}`);
|
|
233
|
-
verbose(` CLI agent source: ${PROJECT_ROOT}`);
|
|
234
|
-
const cliAgents = await loadAllAgents(PROJECT_ROOT);
|
|
235
|
-
const localAgents = await loadAllAgents(localAgentRoot);
|
|
236
|
-
const agents = { ...cliAgents, ...localAgents };
|
|
237
|
-
verbose(
|
|
238
|
-
` Loaded ${Object.keys(localAgents).length} local agents, ${Object.keys(cliAgents).length} CLI agents`
|
|
239
|
-
);
|
|
240
|
-
const newStack = options.stack || await loadStackById(stackId, PROJECT_ROOT);
|
|
241
|
-
const matrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);
|
|
242
|
-
const matrix = await loadSkillsMatrix(matrixPath);
|
|
243
|
-
const skillAliases = matrix.skill_aliases || {};
|
|
244
|
-
let stack;
|
|
245
|
-
if (newStack) {
|
|
246
|
-
verbose(` Found stack: ${newStack.name}`);
|
|
247
|
-
const agentSkillIds = /* @__PURE__ */ new Set();
|
|
248
|
-
for (const agentName of Object.keys(newStack.agents)) {
|
|
249
|
-
const agentConfig = newStack.agents[agentName];
|
|
250
|
-
const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);
|
|
251
|
-
for (const ref of skillRefs) {
|
|
252
|
-
agentSkillIds.add(ref.id);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
stack = {
|
|
256
|
-
name: newStack.name,
|
|
257
|
-
version: "1.0.0",
|
|
258
|
-
author: "",
|
|
259
|
-
description: newStack.description,
|
|
260
|
-
skills: Array.from(agentSkillIds).map((id) => ({ id })),
|
|
261
|
-
agents: Object.keys(newStack.agents),
|
|
262
|
-
philosophy: newStack.philosophy
|
|
263
|
-
};
|
|
264
|
-
} else {
|
|
265
|
-
throw new Error(`Stack '${stackId}' not found in config/stacks.yaml`);
|
|
266
|
-
}
|
|
267
|
-
const skills = await loadSkillsByIds(stack.skills || [], projectRoot);
|
|
268
|
-
const compileConfig = stackToCompileConfig(stackId, stack);
|
|
269
|
-
const resolvedAgents = await resolveAgents(
|
|
270
|
-
agents,
|
|
271
|
-
skills,
|
|
272
|
-
compileConfig,
|
|
273
|
-
projectRoot,
|
|
274
|
-
newStack,
|
|
275
|
-
skillAliases
|
|
276
|
-
);
|
|
277
|
-
const pluginDir = path.join(outputDir, stackId);
|
|
278
|
-
const agentsDir = path.join(pluginDir, "agents");
|
|
279
|
-
await ensureDir(pluginDir);
|
|
280
|
-
await ensureDir(agentsDir);
|
|
281
|
-
const pluginSkillsDir = path.join(pluginDir, "skills");
|
|
282
|
-
await ensureDir(pluginSkillsDir);
|
|
283
|
-
const copiedSourcePaths = /* @__PURE__ */ new Set();
|
|
284
|
-
for (const [, resolvedSkill] of Object.entries(skills)) {
|
|
285
|
-
const sourceSkillDir = path.join(projectRoot, resolvedSkill.path);
|
|
286
|
-
if (copiedSourcePaths.has(resolvedSkill.path)) {
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
const destSkillDir = path.join(pluginSkillsDir, resolvedSkill.canonicalId);
|
|
290
|
-
if (await directoryExists(sourceSkillDir)) {
|
|
291
|
-
await copy(sourceSkillDir, destSkillDir);
|
|
292
|
-
copiedSourcePaths.add(resolvedSkill.path);
|
|
293
|
-
verbose(` Copied skill: ${resolvedSkill.canonicalId}`);
|
|
294
|
-
} else {
|
|
295
|
-
verbose(` Warning: Skill directory not found: ${sourceSkillDir}`);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
const engine = await createLiquidEngine();
|
|
299
|
-
const compiledAgentNames = [];
|
|
300
|
-
const allSkillPlugins = [];
|
|
301
|
-
for (const [name, agent] of Object.entries(resolvedAgents)) {
|
|
302
|
-
const output = await compileAgentForPlugin(
|
|
303
|
-
name,
|
|
304
|
-
agent,
|
|
305
|
-
PROJECT_ROOT,
|
|
306
|
-
engine
|
|
307
|
-
);
|
|
308
|
-
await writeFile(path.join(agentsDir, `${name}.md`), output);
|
|
309
|
-
compiledAgentNames.push(name);
|
|
310
|
-
for (const skill of agent.skills) {
|
|
311
|
-
allSkillPlugins.push(skill.id);
|
|
312
|
-
}
|
|
313
|
-
verbose(` Compiled agent: ${name}`);
|
|
314
|
-
}
|
|
315
|
-
const stackDir = path.join(projectRoot, DIRS.stacks, stackId);
|
|
316
|
-
const claudeMdPath = path.join(stackDir, "CLAUDE.md");
|
|
317
|
-
if (await fileExists(claudeMdPath)) {
|
|
318
|
-
const claudeContent = await readFile(claudeMdPath);
|
|
319
|
-
await writeFile(path.join(pluginDir, "CLAUDE.md"), claudeContent);
|
|
320
|
-
verbose(` Copied CLAUDE.md`);
|
|
321
|
-
}
|
|
322
|
-
const hasHooks = stackHasHooks(stack);
|
|
323
|
-
if (hasHooks && stack.hooks) {
|
|
324
|
-
const hooksDir = path.join(pluginDir, "hooks");
|
|
325
|
-
await ensureDir(hooksDir);
|
|
326
|
-
const hooksJson = generateHooksJson(stack.hooks);
|
|
327
|
-
await writeFile(path.join(hooksDir, "hooks.json"), hooksJson);
|
|
328
|
-
verbose(` Generated hooks/hooks.json`);
|
|
329
|
-
}
|
|
330
|
-
const { version, contentHash } = await determineStackVersion(
|
|
331
|
-
stack,
|
|
332
|
-
pluginDir
|
|
333
|
-
);
|
|
334
|
-
const uniqueSkillPlugins = [...new Set(allSkillPlugins)];
|
|
335
|
-
const manifest = generateStackPluginManifest({
|
|
336
|
-
stackName: stackId,
|
|
337
|
-
description: stack.description,
|
|
338
|
-
author: stack.author,
|
|
339
|
-
version,
|
|
340
|
-
keywords: stack.tags,
|
|
341
|
-
hasAgents: true,
|
|
342
|
-
hasHooks,
|
|
343
|
-
hasSkills: true
|
|
344
|
-
});
|
|
345
|
-
await writePluginManifest(pluginDir, manifest);
|
|
346
|
-
const hashFilePath = getPluginManifestPath(pluginDir).replace(
|
|
347
|
-
"plugin.json",
|
|
348
|
-
CONTENT_HASH_FILE
|
|
349
|
-
);
|
|
350
|
-
await writeFile(hashFilePath, contentHash);
|
|
351
|
-
verbose(` Wrote plugin.json (v${version})`);
|
|
352
|
-
const readme = generateStackReadme(
|
|
353
|
-
stackId,
|
|
354
|
-
stack,
|
|
355
|
-
compiledAgentNames,
|
|
356
|
-
uniqueSkillPlugins
|
|
357
|
-
);
|
|
358
|
-
await writeFile(path.join(pluginDir, "README.md"), readme);
|
|
359
|
-
verbose(` Generated README.md`);
|
|
360
|
-
return {
|
|
361
|
-
pluginPath: pluginDir,
|
|
362
|
-
manifest,
|
|
363
|
-
stackName: stack.name,
|
|
364
|
-
agents: compiledAgentNames,
|
|
365
|
-
skillPlugins: uniqueSkillPlugins,
|
|
366
|
-
hasHooks
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
function printStackCompilationSummary(result) {
|
|
370
|
-
console.log(`
|
|
371
|
-
Stack plugin compiled: ${result.stackName}`);
|
|
372
|
-
console.log(` Path: ${result.pluginPath}`);
|
|
373
|
-
console.log(` Agents: ${result.agents.length}`);
|
|
374
|
-
for (const agent of result.agents) {
|
|
375
|
-
console.log(` - ${agent}`);
|
|
376
|
-
}
|
|
377
|
-
if (result.skillPlugins.length > 0) {
|
|
378
|
-
console.log(` Skills included: ${result.skillPlugins.length}`);
|
|
379
|
-
for (const skill of result.skillPlugins) {
|
|
380
|
-
console.log(` - ${skill}`);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (result.hasHooks) {
|
|
384
|
-
console.log(` Hooks: enabled`);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export {
|
|
389
|
-
compileAgentForPlugin,
|
|
390
|
-
compileStackPlugin,
|
|
391
|
-
printStackCompilationSummary
|
|
392
|
-
};
|
|
393
|
-
//# sourceMappingURL=chunk-DRXPNNPB.js.map
|