@claude-collective/cli 0.21.0 → 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.
Files changed (292) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/README.md +41 -27
  3. package/config/skills-matrix.yaml +38 -37
  4. package/config/stacks.yaml +8 -14
  5. package/dist/{chunk-ZNIDWLL5.js → chunk-3X5D7RM5.js} +4 -3
  6. package/dist/chunk-3X5D7RM5.js.map +1 -0
  7. package/dist/chunk-4S4FCAA2.js +100 -0
  8. package/dist/chunk-4S4FCAA2.js.map +1 -0
  9. package/dist/chunk-4WGN6SUE.js +197 -0
  10. package/dist/chunk-4WGN6SUE.js.map +1 -0
  11. package/dist/{chunk-DHET7RCE.js → chunk-AWKZ5BDL.js} +9 -2
  12. package/dist/{chunk-DHET7RCE.js.map → chunk-AWKZ5BDL.js.map} +1 -1
  13. package/dist/{chunk-6Q3Y7KVB.js → chunk-DBRUQQUF.js} +8 -2
  14. package/dist/chunk-DBRUQQUF.js.map +1 -0
  15. package/dist/{chunk-OQYYMQJR.js → chunk-ETCVEV3S.js} +8 -11
  16. package/dist/chunk-ETCVEV3S.js.map +1 -0
  17. package/dist/{chunk-ZSVMS677.js → chunk-F4RD5FYM.js} +2 -2
  18. package/dist/chunk-F4RD5FYM.js.map +1 -0
  19. package/dist/{chunk-5KXUDHAB.js → chunk-GGFOD5PK.js} +6 -9
  20. package/dist/chunk-GGFOD5PK.js.map +1 -0
  21. package/dist/{chunk-UMORK7OK.js → chunk-H7SSBSPR.js} +2 -2
  22. package/dist/chunk-H7SSBSPR.js.map +1 -0
  23. package/dist/chunk-HWD32NP7.js +19 -0
  24. package/dist/chunk-HWD32NP7.js.map +1 -0
  25. package/dist/{chunk-HGCBZUH5.js → chunk-IAYAE6MG.js} +9 -10
  26. package/dist/chunk-IAYAE6MG.js.map +1 -0
  27. package/dist/{chunk-RTE64SJA.js → chunk-IXBCRT3F.js} +2 -2
  28. package/dist/chunk-IXBCRT3F.js.map +1 -0
  29. package/dist/{chunk-WFEFICFM.js → chunk-KWYO3M5Q.js} +5 -5
  30. package/dist/chunk-KWYO3M5Q.js.map +1 -0
  31. package/dist/{chunk-HEOHU5EZ.js → chunk-MCTSHLAF.js} +22 -11
  32. package/dist/chunk-MCTSHLAF.js.map +1 -0
  33. package/dist/chunk-MH66WDFV.js +251 -0
  34. package/dist/chunk-MH66WDFV.js.map +1 -0
  35. package/dist/{chunk-2LSGX6R4.js → chunk-MTPM7BX5.js} +83 -25
  36. package/dist/chunk-MTPM7BX5.js.map +1 -0
  37. package/dist/chunk-NQJ47R4N.js +1092 -0
  38. package/dist/chunk-NQJ47R4N.js.map +1 -0
  39. package/dist/chunk-NRC7XYCI.js +211 -0
  40. package/dist/chunk-NRC7XYCI.js.map +1 -0
  41. package/dist/{chunk-FJFEKPXF.js → chunk-O6ZTD7ZI.js} +14 -3
  42. package/dist/chunk-O6ZTD7ZI.js.map +1 -0
  43. package/dist/chunk-OBXAY23Y.js +56 -0
  44. package/dist/chunk-OBXAY23Y.js.map +1 -0
  45. package/dist/{chunk-XY3XDVMI.js → chunk-QR2EBWL2.js} +3 -3
  46. package/dist/{chunk-66UDJBF6.js → chunk-REJGRCVQ.js} +2 -2
  47. package/dist/{chunk-CBLPAMZO.js → chunk-TMED5DQ2.js} +68 -42
  48. package/dist/chunk-TMED5DQ2.js.map +1 -0
  49. package/dist/{chunk-Q3J43SF3.js → chunk-U7HFKR74.js} +2 -2
  50. package/dist/chunk-U7HFKR74.js.map +1 -0
  51. package/dist/{chunk-3EHUF54X.js → chunk-UEMRJI2K.js} +17 -4
  52. package/dist/chunk-UEMRJI2K.js.map +1 -0
  53. package/dist/{chunk-Z2CWURZ6.js → chunk-UNN7523L.js} +2 -2
  54. package/dist/chunk-V2ZIH7HV.js +29 -0
  55. package/dist/chunk-V2ZIH7HV.js.map +1 -0
  56. package/dist/{chunk-ZEI3ZUDU.js → chunk-VVYNZZUX.js} +7 -15
  57. package/dist/chunk-VVYNZZUX.js.map +1 -0
  58. package/dist/chunk-WXS4S3MA.js +220 -0
  59. package/dist/chunk-WXS4S3MA.js.map +1 -0
  60. package/dist/{chunk-A46TPNBJ.js → chunk-XENOESJZ.js} +7 -16
  61. package/dist/chunk-XENOESJZ.js.map +1 -0
  62. package/dist/chunk-YDBSSAJ6.js +4207 -0
  63. package/dist/chunk-YDBSSAJ6.js.map +1 -0
  64. package/dist/chunk-ZDREFYD2.js +696 -0
  65. package/dist/chunk-ZDREFYD2.js.map +1 -0
  66. package/dist/chunk-ZW2PELOH.js +197 -0
  67. package/dist/chunk-ZW2PELOH.js.map +1 -0
  68. package/dist/cli/defaults/agent-mappings.yaml +0 -1
  69. package/dist/commands/build/marketplace.js +15 -13
  70. package/dist/commands/build/marketplace.js.map +1 -1
  71. package/dist/commands/build/plugins.js +13 -229
  72. package/dist/commands/build/plugins.js.map +1 -1
  73. package/dist/commands/build/stack.js +11 -18
  74. package/dist/commands/build/stack.js.map +1 -1
  75. package/dist/commands/compile.js +36 -58
  76. package/dist/commands/compile.js.map +1 -1
  77. package/dist/commands/config/get.js +8 -8
  78. package/dist/commands/config/get.js.map +1 -1
  79. package/dist/commands/config/index.js +7 -7
  80. package/dist/commands/config/index.js.map +1 -1
  81. package/dist/commands/config/path.js +6 -6
  82. package/dist/commands/config/path.js.map +1 -1
  83. package/dist/commands/config/set-project.js +8 -8
  84. package/dist/commands/config/set-project.js.map +1 -1
  85. package/dist/commands/config/show.js +7 -7
  86. package/dist/commands/config/unset-project.js +8 -8
  87. package/dist/commands/config/unset-project.js.map +1 -1
  88. package/dist/commands/diff.js +10 -16
  89. package/dist/commands/diff.js.map +1 -1
  90. package/dist/commands/doctor.js +18 -51
  91. package/dist/commands/doctor.js.map +1 -1
  92. package/dist/commands/edit.js +87 -57
  93. package/dist/commands/edit.js.map +1 -1
  94. package/dist/commands/eject.js +17 -49
  95. package/dist/commands/eject.js.map +1 -1
  96. package/dist/commands/import/skill.js +26 -26
  97. package/dist/commands/import/skill.js.map +1 -1
  98. package/dist/commands/info.js +15 -17
  99. package/dist/commands/info.js.map +1 -1
  100. package/dist/commands/init.js +45 -722
  101. package/dist/commands/init.js.map +1 -1
  102. package/dist/commands/list.js +8 -87
  103. package/dist/commands/list.js.map +1 -1
  104. package/dist/commands/new/agent.js +8 -12
  105. package/dist/commands/new/agent.js.map +1 -1
  106. package/dist/commands/new/skill.js +6 -6
  107. package/dist/commands/new/skill.js.map +1 -1
  108. package/dist/commands/outdated.js +15 -19
  109. package/dist/commands/outdated.js.map +1 -1
  110. package/dist/commands/search.js +21 -34
  111. package/dist/commands/search.js.map +1 -1
  112. package/dist/commands/uninstall.js +15 -14
  113. package/dist/commands/uninstall.js.map +1 -1
  114. package/dist/commands/update.js +13 -24
  115. package/dist/commands/update.js.map +1 -1
  116. package/dist/commands/validate.js +44 -487
  117. package/dist/commands/validate.js.map +1 -1
  118. package/dist/commands/version/bump.js +11 -11
  119. package/dist/commands/version/bump.js.map +1 -1
  120. package/dist/commands/version/index.js +9 -10
  121. package/dist/commands/version/index.js.map +1 -1
  122. package/dist/commands/version/set.js +10 -8
  123. package/dist/commands/version/set.js.map +1 -1
  124. package/dist/commands/version/show.js +9 -10
  125. package/dist/commands/version/show.js.map +1 -1
  126. package/dist/components/common/confirm.js +2 -2
  127. package/dist/components/common/confirm.test.js +203 -0
  128. package/dist/components/common/confirm.test.js.map +1 -0
  129. package/dist/components/common/message.js +1 -1
  130. package/dist/components/common/spinner.js +1 -1
  131. package/dist/components/common/spinner.js.map +1 -1
  132. package/dist/components/skill-search/skill-search.js +3 -3
  133. package/dist/components/wizard/category-grid.js +2 -2
  134. package/dist/components/wizard/category-grid.test.js +132 -78
  135. package/dist/components/wizard/category-grid.test.js.map +1 -1
  136. package/dist/components/wizard/menu-item.js +2 -2
  137. package/dist/components/wizard/search-modal.js +9 -0
  138. package/dist/components/wizard/search-modal.js.map +1 -0
  139. package/dist/components/wizard/search-modal.test.js +216 -0
  140. package/dist/components/wizard/search-modal.test.js.map +1 -0
  141. package/dist/components/wizard/section-progress.js +2 -2
  142. package/dist/components/wizard/section-progress.test.js +4 -4
  143. package/dist/components/wizard/section-progress.test.js.map +1 -1
  144. package/dist/components/wizard/source-grid.js +10 -0
  145. package/dist/components/wizard/source-grid.js.map +1 -0
  146. package/dist/components/wizard/source-grid.test.js +500 -0
  147. package/dist/components/wizard/source-grid.test.js.map +1 -0
  148. package/dist/components/wizard/step-approach.js +7 -6
  149. package/dist/components/wizard/step-approach.test.js +115 -0
  150. package/dist/components/wizard/step-approach.test.js.map +1 -0
  151. package/dist/components/wizard/step-build.js +9 -4
  152. package/dist/components/wizard/step-build.test.js +103 -122
  153. package/dist/components/wizard/step-build.test.js.map +1 -1
  154. package/dist/components/wizard/step-confirm.js +3 -2
  155. package/dist/components/wizard/step-confirm.test.js +364 -0
  156. package/dist/components/wizard/step-confirm.test.js.map +1 -0
  157. package/dist/components/wizard/step-refine.js +2 -2
  158. package/dist/components/wizard/step-refine.test.js +19 -13
  159. package/dist/components/wizard/step-refine.test.js.map +1 -1
  160. package/dist/components/wizard/step-settings.js +14 -0
  161. package/dist/components/wizard/step-settings.js.map +1 -0
  162. package/dist/components/wizard/step-settings.test.js +240 -0
  163. package/dist/components/wizard/step-settings.test.js.map +1 -0
  164. package/dist/components/wizard/step-sources.js +17 -0
  165. package/dist/components/wizard/step-sources.js.map +1 -0
  166. package/dist/components/wizard/step-sources.test.js +290 -0
  167. package/dist/components/wizard/step-sources.test.js.map +1 -0
  168. package/dist/components/wizard/step-stack.js +7 -6
  169. package/dist/components/wizard/step-stack.test.js +344 -0
  170. package/dist/components/wizard/step-stack.test.js.map +1 -0
  171. package/dist/components/wizard/view-title.js +2 -2
  172. package/dist/components/wizard/wizard-layout.js +6 -5
  173. package/dist/components/wizard/wizard-tabs.js +2 -2
  174. package/dist/components/wizard/wizard-tabs.test.js +292 -0
  175. package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
  176. package/dist/components/wizard/wizard.js +22 -14
  177. package/dist/config/skills-matrix.yaml +38 -37
  178. package/dist/config/stacks.yaml +8 -14
  179. package/dist/hooks/init.js +5 -5
  180. package/dist/hooks/init.js.map +1 -1
  181. package/dist/index.js +1 -1
  182. package/dist/index.js.map +1 -1
  183. package/dist/{magic-string.es-RGXYGAW3.js → magic-string.es-PAH2SOTR.js} +2 -2
  184. package/dist/source-manager-DSYZEVGZ.js +16 -0
  185. package/dist/source-manager-DSYZEVGZ.js.map +1 -0
  186. package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
  187. package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
  188. package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
  189. package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
  190. package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
  191. package/dist/src/agents/meta/documentor/agent.yaml +1 -1
  192. package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
  193. package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
  194. package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  195. package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  196. package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
  197. package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
  198. package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
  199. package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  200. package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  201. package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  202. package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
  203. package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
  204. package/dist/stores/wizard-store.js +4 -3
  205. package/dist/stores/wizard-store.test.js +51 -82
  206. package/dist/stores/wizard-store.test.js.map +1 -1
  207. package/package.json +5 -3
  208. package/src/agents/developer/api-developer/agent.yaml +1 -1
  209. package/src/agents/developer/cli-developer/agent.yaml +1 -1
  210. package/src/agents/developer/web-architecture/agent.yaml +1 -1
  211. package/src/agents/developer/web-developer/agent.yaml +1 -1
  212. package/src/agents/meta/agent-summoner/agent.yaml +1 -1
  213. package/src/agents/meta/documentor/agent.yaml +1 -1
  214. package/src/agents/meta/skill-summoner/agent.yaml +1 -1
  215. package/src/agents/migration/cli-migrator/agent.yaml +1 -1
  216. package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  217. package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  218. package/src/agents/planning/web-pm/agent.yaml +1 -1
  219. package/src/agents/researcher/api-researcher/agent.yaml +1 -1
  220. package/src/agents/researcher/web-researcher/agent.yaml +1 -1
  221. package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  222. package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  223. package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  224. package/src/agents/tester/cli-tester/agent.yaml +1 -1
  225. package/src/agents/tester/web-tester/agent.yaml +1 -1
  226. package/dist/chunk-2LSGX6R4.js.map +0 -1
  227. package/dist/chunk-2OKUEELH.js +0 -32
  228. package/dist/chunk-2OKUEELH.js.map +0 -1
  229. package/dist/chunk-374JNMR6.js +0 -212
  230. package/dist/chunk-374JNMR6.js.map +0 -1
  231. package/dist/chunk-3EHUF54X.js.map +0 -1
  232. package/dist/chunk-3XR4PALU.js +0 -529
  233. package/dist/chunk-3XR4PALU.js.map +0 -1
  234. package/dist/chunk-5K2ZLUO5.js +0 -57
  235. package/dist/chunk-5K2ZLUO5.js.map +0 -1
  236. package/dist/chunk-5KXUDHAB.js.map +0 -1
  237. package/dist/chunk-6Q3Y7KVB.js.map +0 -1
  238. package/dist/chunk-7SLV7CMF.js +0 -615
  239. package/dist/chunk-7SLV7CMF.js.map +0 -1
  240. package/dist/chunk-A46TPNBJ.js.map +0 -1
  241. package/dist/chunk-AL74GBW4.js +0 -69
  242. package/dist/chunk-AL74GBW4.js.map +0 -1
  243. package/dist/chunk-BQX23RBV.js +0 -191
  244. package/dist/chunk-BQX23RBV.js.map +0 -1
  245. package/dist/chunk-CA4LH4LI.js +0 -132
  246. package/dist/chunk-CA4LH4LI.js.map +0 -1
  247. package/dist/chunk-CBLPAMZO.js.map +0 -1
  248. package/dist/chunk-CKPQHGXR.js +0 -417
  249. package/dist/chunk-CKPQHGXR.js.map +0 -1
  250. package/dist/chunk-CXOFOJCN.js +0 -80
  251. package/dist/chunk-CXOFOJCN.js.map +0 -1
  252. package/dist/chunk-EHGD7HIE.js +0 -104
  253. package/dist/chunk-EHGD7HIE.js.map +0 -1
  254. package/dist/chunk-EHS3TWWP.js +0 -95
  255. package/dist/chunk-EHS3TWWP.js.map +0 -1
  256. package/dist/chunk-FJFEKPXF.js.map +0 -1
  257. package/dist/chunk-HEOHU5EZ.js.map +0 -1
  258. package/dist/chunk-HGCBZUH5.js.map +0 -1
  259. package/dist/chunk-HPGFY5ZN.js +0 -114
  260. package/dist/chunk-HPGFY5ZN.js.map +0 -1
  261. package/dist/chunk-INJ2EFRW.js +0 -127
  262. package/dist/chunk-INJ2EFRW.js.map +0 -1
  263. package/dist/chunk-IOBFMF6X.js +0 -61
  264. package/dist/chunk-IOBFMF6X.js.map +0 -1
  265. package/dist/chunk-KH3HA7J7.js +0 -116
  266. package/dist/chunk-KH3HA7J7.js.map +0 -1
  267. package/dist/chunk-N6JNE326.js +0 -261
  268. package/dist/chunk-N6JNE326.js.map +0 -1
  269. package/dist/chunk-NAGU7TVZ.js +0 -36
  270. package/dist/chunk-NAGU7TVZ.js.map +0 -1
  271. package/dist/chunk-OQYYMQJR.js.map +0 -1
  272. package/dist/chunk-PLZOUVDD.js +0 -419
  273. package/dist/chunk-PLZOUVDD.js.map +0 -1
  274. package/dist/chunk-Q3J43SF3.js.map +0 -1
  275. package/dist/chunk-RTE64SJA.js.map +0 -1
  276. package/dist/chunk-T25OEQFI.js +0 -26
  277. package/dist/chunk-T25OEQFI.js.map +0 -1
  278. package/dist/chunk-UMORK7OK.js.map +0 -1
  279. package/dist/chunk-VFHWU7JU.js +0 -287
  280. package/dist/chunk-VFHWU7JU.js.map +0 -1
  281. package/dist/chunk-VS4GVTZE.js +0 -91
  282. package/dist/chunk-VS4GVTZE.js.map +0 -1
  283. package/dist/chunk-WFEFICFM.js.map +0 -1
  284. package/dist/chunk-WG6KIAPK.js +0 -54
  285. package/dist/chunk-WG6KIAPK.js.map +0 -1
  286. package/dist/chunk-ZEI3ZUDU.js.map +0 -1
  287. package/dist/chunk-ZNIDWLL5.js.map +0 -1
  288. package/dist/chunk-ZSVMS677.js.map +0 -1
  289. /package/dist/{chunk-XY3XDVMI.js.map → chunk-QR2EBWL2.js.map} +0 -0
  290. /package/dist/{chunk-66UDJBF6.js.map → chunk-REJGRCVQ.js.map} +0 -0
  291. /package/dist/{chunk-Z2CWURZ6.js.map → chunk-UNN7523L.js.map} +0 -0
  292. /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/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 +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 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":[]}
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- init_esm_shims
4
- } from "./chunk-DHET7RCE.js";
5
-
6
- // src/cli/utils/fs.ts
7
- init_esm_shims();
8
- import fs from "fs-extra";
9
- import fg from "fast-glob";
10
- import path from "path";
11
- async function readFile(filePath) {
12
- return fs.readFile(filePath, "utf-8");
13
- }
14
- async function readFileOptional(filePath, fallback = "") {
15
- try {
16
- return await fs.readFile(filePath, "utf-8");
17
- } catch {
18
- return fallback;
19
- }
20
- }
21
- async function fileExists(filePath) {
22
- return fs.pathExists(filePath);
23
- }
24
- async function directoryExists(dirPath) {
25
- try {
26
- const stat = await fs.stat(dirPath);
27
- return stat.isDirectory();
28
- } catch {
29
- return false;
30
- }
31
- }
32
- async function listDirectories(dirPath) {
33
- try {
34
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
35
- return entries.filter((e) => e.isDirectory()).map((e) => e.name);
36
- } catch {
37
- return [];
38
- }
39
- }
40
- async function glob(pattern, cwd) {
41
- return fg(pattern, { cwd, onlyFiles: true });
42
- }
43
- async function writeFile(filePath, content) {
44
- await fs.ensureDir(path.dirname(filePath));
45
- await fs.writeFile(filePath, content, "utf-8");
46
- }
47
- async function ensureDir(dirPath) {
48
- await fs.ensureDir(dirPath);
49
- }
50
- async function remove(filePath) {
51
- await fs.remove(filePath);
52
- }
53
- async function copy(src, dest) {
54
- await fs.copy(src, dest);
55
- }
56
-
57
- export {
58
- readFile,
59
- readFileOptional,
60
- fileExists,
61
- directoryExists,
62
- listDirectories,
63
- glob,
64
- writeFile,
65
- ensureDir,
66
- remove,
67
- copy
68
- };
69
- //# sourceMappingURL=chunk-AL74GBW4.js.map
@@ -1 +0,0 @@
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":[]}
@@ -1,191 +0,0 @@
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
@@ -1 +0,0 @@
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,132 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- isLocalSource
4
- } from "./chunk-374JNMR6.js";
5
- import {
6
- verbose
7
- } from "./chunk-T25OEQFI.js";
8
- import {
9
- directoryExists,
10
- ensureDir
11
- } from "./chunk-AL74GBW4.js";
12
- import {
13
- CACHE_DIR
14
- } from "./chunk-FJFEKPXF.js";
15
- import {
16
- init_esm_shims
17
- } from "./chunk-DHET7RCE.js";
18
-
19
- // src/cli/lib/source-fetcher.ts
20
- init_esm_shims();
21
- import path from "path";
22
- import { downloadTemplate } from "giget";
23
- function sanitizeSourceForCache(source) {
24
- return source.replace(/:/g, "-").replace(/[\/]/g, "-").replace(/--+/g, "-").replace(/^-|-$/g, "");
25
- }
26
- function getCacheDir(source) {
27
- const sanitized = sanitizeSourceForCache(source);
28
- return path.join(CACHE_DIR, "sources", sanitized);
29
- }
30
- async function fetchFromSource(source, options = {}) {
31
- const { forceRefresh = false, subdir } = options;
32
- if (isLocalSource(source)) {
33
- return fetchFromLocalSource(source, subdir);
34
- }
35
- return fetchFromRemoteSource(source, { forceRefresh, subdir });
36
- }
37
- async function fetchFromLocalSource(source, subdir) {
38
- const fullPath = subdir ? path.join(source, subdir) : source;
39
- const absolutePath = path.isAbsolute(fullPath) ? fullPath : path.resolve(process.cwd(), fullPath);
40
- if (!await directoryExists(absolutePath)) {
41
- throw new Error(`Local source not found: ${absolutePath}`);
42
- }
43
- verbose(`Using local source: ${absolutePath}`);
44
- return {
45
- path: absolutePath,
46
- fromCache: false,
47
- source
48
- };
49
- }
50
- async function fetchFromRemoteSource(source, options) {
51
- const { forceRefresh = false, subdir } = options;
52
- const cacheDir = getCacheDir(source);
53
- const fullSource = subdir ? `${source}/${subdir}` : source;
54
- verbose(`Fetching from remote: ${fullSource}`);
55
- verbose(`Cache directory: ${cacheDir}`);
56
- if (!forceRefresh && await directoryExists(cacheDir)) {
57
- verbose(`Using cached source: ${cacheDir}`);
58
- return {
59
- path: cacheDir,
60
- fromCache: true,
61
- source: fullSource
62
- };
63
- }
64
- await ensureDir(path.dirname(cacheDir));
65
- try {
66
- const result = await downloadTemplate(fullSource, {
67
- dir: cacheDir,
68
- force: true,
69
- // Always force when downloading to avoid "already exists" error
70
- offline: false
71
- });
72
- verbose(`Downloaded to: ${result.dir}`);
73
- return {
74
- path: result.dir,
75
- fromCache: false,
76
- source: fullSource
77
- };
78
- } catch (error) {
79
- throw wrapGigetError(error, source);
80
- }
81
- }
82
- function wrapGigetError(error, source) {
83
- const message = error instanceof Error ? error.message : String(error);
84
- if (message.includes("404") || message.includes("Not Found")) {
85
- return new Error(
86
- `Repository not found: ${source}
87
-
88
- This could mean:
89
- - The repository doesn't exist
90
- - The repository is private and you need to set authentication
91
- - There's a typo in the URL
92
-
93
- For private repositories, set the GIGET_AUTH environment variable:
94
- export GIGET_AUTH=ghp_your_github_token`
95
- );
96
- }
97
- if (message.includes("401") || message.includes("Unauthorized")) {
98
- return new Error(
99
- `Authentication required for: ${source}
100
-
101
- Set the GIGET_AUTH environment variable with a GitHub token:
102
- export GIGET_AUTH=ghp_your_github_token
103
-
104
- Create a token at: https://github.com/settings/tokens
105
- Required scope: repo (for private repos) or public_repo (for public)`
106
- );
107
- }
108
- if (message.includes("403") || message.includes("Forbidden")) {
109
- return new Error(
110
- `Access denied to: ${source}
111
-
112
- Your token may not have sufficient permissions.
113
- Ensure your GIGET_AUTH token has the 'repo' scope for private repositories.`
114
- );
115
- }
116
- if (message.includes("ENOTFOUND") || message.includes("ETIMEDOUT") || message.includes("network")) {
117
- return new Error(
118
- `Network error fetching: ${source}
119
-
120
- Please check your internet connection.
121
- If you're behind a corporate proxy, you may need to set:
122
- export HTTPS_PROXY=http://your-proxy:port
123
- export FORCE_NODE_FETCH=true # Required for Node 20+`
124
- );
125
- }
126
- return new Error(`Failed to fetch ${source}: ${message}`);
127
- }
128
-
129
- export {
130
- fetchFromSource
131
- };
132
- //# sourceMappingURL=chunk-CA4LH4LI.js.map
@@ -1 +0,0 @@
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 +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/** All available domains that the build step should cycle through */\nconst ALL_DOMAINS = [\"web\", \"web-extras\", \"api\", \"cli\", \"mobile\", \"shared\"];\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 | \"build\" // CategoryGrid for technology 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 // Skill source state\n // ─────────────────────────────────────────────────────────────────\n currentRefineIndex: number; // Which skill we're refining\n skillSources: Record<string, string>; // technology -> selected skill ID\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: (domain: string, subcategory: string, technologies: string[]) => 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 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 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(agentConfig)) {\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 (!domainSelections[domain][subcategoryId].includes(technologyAlias)) {\n domainSelections[domain][subcategoryId].push(technologyAlias);\n }\n }\n }\n\n return {\n domainSelections,\n selectedDomains: ALL_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 = 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 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: () => 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":[]}