@claude-collective/cli 0.13.4 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/CHANGELOG.md +183 -0
  2. package/config/skills-matrix.yaml +180 -113
  3. package/config/stacks.yaml +6 -6
  4. package/dist/{chunk-K3NB6DSG.js → chunk-2LSGX6R4.js} +54 -114
  5. package/dist/chunk-2LSGX6R4.js.map +1 -0
  6. package/dist/chunk-2OKUEELH.js +32 -0
  7. package/dist/chunk-2OKUEELH.js.map +1 -0
  8. package/dist/{chunk-V46GGCCI.js → chunk-374JNMR6.js} +14 -96
  9. package/dist/chunk-374JNMR6.js.map +1 -0
  10. package/dist/chunk-3EHUF54X.js +133 -0
  11. package/dist/chunk-3EHUF54X.js.map +1 -0
  12. package/dist/{chunk-7Q44DMSP.js → chunk-3XR4PALU.js} +92 -145
  13. package/dist/chunk-3XR4PALU.js.map +1 -0
  14. package/dist/{chunk-IAUAQJQ2.js → chunk-5K2ZLUO5.js} +5 -5
  15. package/dist/{chunk-IAUAQJQ2.js.map → chunk-5K2ZLUO5.js.map} +1 -1
  16. package/dist/{chunk-ACNBKXXJ.js → chunk-5KXUDHAB.js} +8 -36
  17. package/dist/chunk-5KXUDHAB.js.map +1 -0
  18. package/dist/chunk-7SLV7CMF.js +615 -0
  19. package/dist/chunk-7SLV7CMF.js.map +1 -0
  20. package/dist/{chunk-CDX4W4DM.js → chunk-A46TPNBJ.js} +61 -32
  21. package/dist/chunk-A46TPNBJ.js.map +1 -0
  22. package/dist/{chunk-TKFPKEV3.js → chunk-AL74GBW4.js} +1 -1
  23. package/dist/chunk-AL74GBW4.js.map +1 -0
  24. package/dist/chunk-BQX23RBV.js +191 -0
  25. package/dist/chunk-BQX23RBV.js.map +1 -0
  26. package/dist/{chunk-IMDW5ZUP.js → chunk-CA4LH4LI.js} +5 -5
  27. package/dist/chunk-CA4LH4LI.js.map +1 -0
  28. package/dist/{chunk-D237EVNB.js → chunk-CBLPAMZO.js} +5 -8
  29. package/dist/chunk-CBLPAMZO.js.map +1 -0
  30. package/dist/{chunk-B7CCVP6Q.js → chunk-CKPQHGXR.js} +52 -274
  31. package/dist/chunk-CKPQHGXR.js.map +1 -0
  32. package/dist/{chunk-SVYPSDWY.js → chunk-CXOFOJCN.js} +6 -10
  33. package/dist/chunk-CXOFOJCN.js.map +1 -0
  34. package/dist/{chunk-UQTEPWU7.js → chunk-EHGD7HIE.js} +2 -6
  35. package/dist/chunk-EHGD7HIE.js.map +1 -0
  36. package/dist/{chunk-76DWXGQE.js → chunk-FJFEKPXF.js} +1 -1
  37. package/dist/chunk-FJFEKPXF.js.map +1 -0
  38. package/dist/{chunk-E3FJH4TF.js → chunk-HEOHU5EZ.js} +2 -13
  39. package/dist/chunk-HEOHU5EZ.js.map +1 -0
  40. package/dist/{chunk-JIPWV2FX.js → chunk-HGCBZUH5.js} +6 -27
  41. package/dist/chunk-HGCBZUH5.js.map +1 -0
  42. package/dist/{chunk-ED4E6Q2T.js → chunk-HPGFY5ZN.js} +4 -4
  43. package/dist/chunk-HPGFY5ZN.js.map +1 -0
  44. package/dist/chunk-INJ2EFRW.js +127 -0
  45. package/dist/chunk-INJ2EFRW.js.map +1 -0
  46. package/dist/{chunk-KAAEN2PO.js → chunk-IOBFMF6X.js} +6 -2
  47. package/dist/{chunk-KAAEN2PO.js.map → chunk-IOBFMF6X.js.map} +1 -1
  48. package/dist/{chunk-K7EVM5LY.js → chunk-KH3HA7J7.js} +8 -33
  49. package/dist/chunk-KH3HA7J7.js.map +1 -0
  50. package/dist/{chunk-4K4ZXQRM.js → chunk-N6JNE326.js} +38 -94
  51. package/dist/chunk-N6JNE326.js.map +1 -0
  52. package/dist/chunk-NAGU7TVZ.js +36 -0
  53. package/dist/chunk-NAGU7TVZ.js.map +1 -0
  54. package/dist/{chunk-Z7G4B5HJ.js → chunk-OQYYMQJR.js} +68 -142
  55. package/dist/chunk-OQYYMQJR.js.map +1 -0
  56. package/dist/{chunk-RFTSZDHV.js → chunk-PLZOUVDD.js} +159 -53
  57. package/dist/chunk-PLZOUVDD.js.map +1 -0
  58. package/dist/chunk-Q3J43SF3.js +21 -0
  59. package/dist/chunk-Q3J43SF3.js.map +1 -0
  60. package/dist/{chunk-3U3R4NCG.js → chunk-T25OEQFI.js} +6 -2
  61. package/dist/chunk-T25OEQFI.js.map +1 -0
  62. package/dist/chunk-UMORK7OK.js +29 -0
  63. package/dist/chunk-UMORK7OK.js.map +1 -0
  64. package/dist/{chunk-ZFPSUQOU.js → chunk-VFHWU7JU.js} +12 -121
  65. package/dist/chunk-VFHWU7JU.js.map +1 -0
  66. package/dist/{chunk-GDH553MV.js → chunk-VS4GVTZE.js} +3 -3
  67. package/dist/chunk-VS4GVTZE.js.map +1 -0
  68. package/dist/chunk-WFEFICFM.js +67 -0
  69. package/dist/chunk-WFEFICFM.js.map +1 -0
  70. package/dist/{chunk-P26A2K5N.js → chunk-WG6KIAPK.js} +6 -16
  71. package/dist/chunk-WG6KIAPK.js.map +1 -0
  72. package/dist/{chunk-X6QONICW.js → chunk-ZEI3ZUDU.js} +3 -7
  73. package/dist/chunk-ZEI3ZUDU.js.map +1 -0
  74. package/dist/chunk-ZNIDWLL5.js +68 -0
  75. package/dist/chunk-ZNIDWLL5.js.map +1 -0
  76. package/dist/chunk-ZSVMS677.js +45 -0
  77. package/dist/chunk-ZSVMS677.js.map +1 -0
  78. package/dist/cli/defaults/agent-mappings.yaml +13 -13
  79. package/dist/commands/build/marketplace.js +8 -14
  80. package/dist/commands/build/marketplace.js.map +1 -1
  81. package/dist/commands/build/plugins.js +10 -21
  82. package/dist/commands/build/plugins.js.map +1 -1
  83. package/dist/commands/build/stack.js +13 -18
  84. package/dist/commands/build/stack.js.map +1 -1
  85. package/dist/commands/compile.js +25 -40
  86. package/dist/commands/compile.js.map +1 -1
  87. package/dist/commands/config/get.js +7 -7
  88. package/dist/commands/config/get.js.map +1 -1
  89. package/dist/commands/config/index.js +6 -6
  90. package/dist/commands/config/index.js.map +1 -1
  91. package/dist/commands/config/path.js +5 -7
  92. package/dist/commands/config/path.js.map +1 -1
  93. package/dist/commands/config/set-project.js +8 -9
  94. package/dist/commands/config/set-project.js.map +1 -1
  95. package/dist/commands/config/show.js +5 -5
  96. package/dist/commands/config/unset-project.js +8 -9
  97. package/dist/commands/config/unset-project.js.map +1 -1
  98. package/dist/commands/diff.js +17 -40
  99. package/dist/commands/diff.js.map +1 -1
  100. package/dist/commands/doctor.js +14 -25
  101. package/dist/commands/doctor.js.map +1 -1
  102. package/dist/commands/edit.js +41 -54
  103. package/dist/commands/edit.js.map +1 -1
  104. package/dist/commands/eject.js +24 -44
  105. package/dist/commands/eject.js.map +1 -1
  106. package/dist/commands/import/skill.js +19 -39
  107. package/dist/commands/import/skill.js.map +1 -1
  108. package/dist/commands/info.js +10 -15
  109. package/dist/commands/info.js.map +1 -1
  110. package/dist/commands/init.js +452 -451
  111. package/dist/commands/init.js.map +1 -1
  112. package/dist/commands/list.js +85 -9
  113. package/dist/commands/list.js.map +1 -1
  114. package/dist/commands/new/agent.js +9 -10
  115. package/dist/commands/new/agent.js.map +1 -1
  116. package/dist/commands/new/skill.js +12 -16
  117. package/dist/commands/new/skill.js.map +1 -1
  118. package/dist/commands/outdated.js +12 -89
  119. package/dist/commands/outdated.js.map +1 -1
  120. package/dist/commands/search.js +12 -18
  121. package/dist/commands/search.js.map +1 -1
  122. package/dist/commands/uninstall.js +12 -21
  123. package/dist/commands/uninstall.js.map +1 -1
  124. package/dist/commands/update.js +26 -146
  125. package/dist/commands/update.js.map +1 -1
  126. package/dist/commands/validate.js +407 -15
  127. package/dist/commands/validate.js.map +1 -1
  128. package/dist/commands/version/bump.js +7 -23
  129. package/dist/commands/version/bump.js.map +1 -1
  130. package/dist/commands/version/index.js +6 -21
  131. package/dist/commands/version/index.js.map +1 -1
  132. package/dist/commands/version/set.js +6 -23
  133. package/dist/commands/version/set.js.map +1 -1
  134. package/dist/commands/version/show.js +6 -21
  135. package/dist/commands/version/show.js.map +1 -1
  136. package/dist/components/common/message.js +2 -6
  137. package/dist/components/common/message.js.map +1 -1
  138. package/dist/components/common/spinner.js.map +1 -1
  139. package/dist/components/skill-search/skill-search.js +1 -1
  140. package/dist/components/wizard/category-grid.js +1 -1
  141. package/dist/components/wizard/category-grid.test.js +20 -92
  142. package/dist/components/wizard/category-grid.test.js.map +1 -1
  143. package/dist/components/wizard/menu-item.js +9 -0
  144. package/dist/components/wizard/section-progress.js +1 -1
  145. package/dist/components/wizard/section-progress.test.js +13 -103
  146. package/dist/components/wizard/section-progress.test.js.map +1 -1
  147. package/dist/components/wizard/step-approach.js +5 -4
  148. package/dist/components/wizard/step-build.js +3 -4
  149. package/dist/components/wizard/step-build.test.js +81 -186
  150. package/dist/components/wizard/step-build.test.js.map +1 -1
  151. package/dist/components/wizard/step-confirm.js +1 -2
  152. package/dist/components/wizard/step-refine.js +1 -2
  153. package/dist/components/wizard/step-refine.test.js +6 -14
  154. package/dist/components/wizard/step-refine.test.js.map +1 -1
  155. package/dist/components/wizard/step-stack.js +5 -3
  156. package/dist/components/wizard/view-title.js +9 -0
  157. package/dist/components/wizard/wizard-layout.js +16 -0
  158. package/dist/components/wizard/wizard-layout.js.map +1 -0
  159. package/dist/components/wizard/wizard-tabs.js +1 -1
  160. package/dist/components/wizard/wizard.js +12 -13
  161. package/dist/config/skills-matrix.yaml +180 -113
  162. package/dist/config/stacks.yaml +6 -6
  163. package/dist/hooks/init.js +5 -7
  164. package/dist/hooks/init.js.map +1 -1
  165. package/dist/src/agents/developer/web-developer/examples.md +1 -6
  166. package/dist/src/agents/meta/documentor/workflow.md +1 -5
  167. package/dist/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
  168. package/dist/src/agents/tester/web-tester/output-format.md +1 -3
  169. package/dist/stores/wizard-store.js +2 -2
  170. package/dist/stores/wizard-store.test.js +60 -23
  171. package/dist/stores/wizard-store.test.js.map +1 -1
  172. package/package.json +1 -1
  173. package/src/agents/developer/web-developer/examples.md +1 -6
  174. package/src/agents/meta/documentor/workflow.md +1 -5
  175. package/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
  176. package/src/agents/tester/web-tester/output-format.md +1 -3
  177. package/dist/chunk-3U3R4NCG.js.map +0 -1
  178. package/dist/chunk-4K4ZXQRM.js.map +0 -1
  179. package/dist/chunk-76DWXGQE.js.map +0 -1
  180. package/dist/chunk-7Q44DMSP.js.map +0 -1
  181. package/dist/chunk-ACNBKXXJ.js.map +0 -1
  182. package/dist/chunk-B7CCVP6Q.js.map +0 -1
  183. package/dist/chunk-BDLUZVKU.js +0 -54
  184. package/dist/chunk-BDLUZVKU.js.map +0 -1
  185. package/dist/chunk-CDX4W4DM.js.map +0 -1
  186. package/dist/chunk-D237EVNB.js.map +0 -1
  187. package/dist/chunk-DRXPNNPB.js +0 -393
  188. package/dist/chunk-DRXPNNPB.js.map +0 -1
  189. package/dist/chunk-E3FJH4TF.js.map +0 -1
  190. package/dist/chunk-ED4E6Q2T.js.map +0 -1
  191. package/dist/chunk-GDH553MV.js.map +0 -1
  192. package/dist/chunk-HLJX2FTL.js +0 -95
  193. package/dist/chunk-HLJX2FTL.js.map +0 -1
  194. package/dist/chunk-I2DSLOXZ.js +0 -75
  195. package/dist/chunk-I2DSLOXZ.js.map +0 -1
  196. package/dist/chunk-I4TPKIYX.js +0 -493
  197. package/dist/chunk-I4TPKIYX.js.map +0 -1
  198. package/dist/chunk-IBE7JIAG.js +0 -129
  199. package/dist/chunk-IBE7JIAG.js.map +0 -1
  200. package/dist/chunk-IMDW5ZUP.js.map +0 -1
  201. package/dist/chunk-JIPWV2FX.js.map +0 -1
  202. package/dist/chunk-K3NB6DSG.js.map +0 -1
  203. package/dist/chunk-K7EVM5LY.js.map +0 -1
  204. package/dist/chunk-NDY25DTL.js +0 -453
  205. package/dist/chunk-NDY25DTL.js.map +0 -1
  206. package/dist/chunk-P26A2K5N.js.map +0 -1
  207. package/dist/chunk-RFTSZDHV.js.map +0 -1
  208. package/dist/chunk-SVYPSDWY.js.map +0 -1
  209. package/dist/chunk-TKFPKEV3.js.map +0 -1
  210. package/dist/chunk-UQTEPWU7.js.map +0 -1
  211. package/dist/chunk-V46GGCCI.js.map +0 -1
  212. package/dist/chunk-X6QONICW.js.map +0 -1
  213. package/dist/chunk-Y2LW7R3Y.js +0 -23
  214. package/dist/chunk-Y2LW7R3Y.js.map +0 -1
  215. package/dist/chunk-Z7G4B5HJ.js.map +0 -1
  216. package/dist/chunk-ZENYS6KW.js +0 -90
  217. package/dist/chunk-ZENYS6KW.js.map +0 -1
  218. package/dist/chunk-ZFPSUQOU.js.map +0 -1
  219. package/dist/commands/config/set.js +0 -61
  220. package/dist/commands/config/set.js.map +0 -1
  221. package/dist/commands/config/unset.js +0 -57
  222. package/dist/commands/config/unset.js.map +0 -1
  223. package/dist/commands/test-imports.js +0 -92
  224. package/dist/commands/test-imports.js.map +0 -1
  225. package/dist/components/wizard/step-stack-options.js +0 -11
  226. package/dist/components/wizard/wizard-footer.js +0 -9
  227. /package/dist/components/wizard/{step-stack-options.js.map → menu-item.js.map} +0 -0
  228. /package/dist/components/wizard/{wizard-footer.js.map → view-title.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/category-grid.tsx"],"sourcesContent":["/**\n * CategoryGrid component - Section-based selection for wizard Build step.\n *\n * Displays categories as sections with technology options as horizontal tags.\n * Supports keyboard navigation (arrows, vim keys) and visual states.\n *\n * Visual states:\n * - Selected: cyan background + black text\n * - Recommended: cyan text (no background)\n * - Focused: gray background\n * - Disabled: dimmed text\n * - Normal: plain text\n * - Locked section: visible but dimmed, not navigable\n *\n * Section layout: Each category is a section with header, underline, and flowing tags.\n */\nimport React, { useCallback, useEffect } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\n\n// Types\n\nexport type OptionState = \"normal\" | \"recommended\" | \"discouraged\" | \"disabled\";\n\nexport interface CategoryOption {\n id: string;\n label: string;\n state: OptionState;\n stateReason?: string;\n selected: boolean;\n local?: boolean;\n}\n\nexport interface CategoryRow {\n id: string;\n name: string;\n required: boolean;\n exclusive: boolean;\n options: CategoryOption[];\n}\n\nexport interface CategoryGridProps {\n /** Categories to display (filtered by domain from matrix) */\n categories: CategoryRow[];\n /** Focused row index (section index) */\n focusedRow: number;\n /** Focused column index (option index within section) */\n focusedCol: number;\n /** Show descriptions under each technology */\n showDescriptions: boolean;\n /** Expert mode - shows all options, disables smart ordering */\n expertMode: boolean;\n /** Called when user toggles a technology */\n onToggle: (categoryId: string, technologyId: string) => void;\n /** Called when focus changes */\n onFocusChange: (row: number, col: number) => void;\n /** Called when show descriptions is toggled */\n onToggleDescriptions: () => void;\n}\n\n// Constants\n\n/** Required indicator */\nconst SYMBOL_REQUIRED = \"*\";\n\n/** Background colors for different states */\nconst BG_SELECTED = \"cyan\"; // Cyan background for selected\nconst BG_FOCUSED = \"#333\"; // Dark gray for focused\n\n/** Framework category ID for locking logic */\nconst FRAMEWORK_CATEGORY_ID = \"framework\";\n\n// Helper Functions\n\n/**\n * Sort options based on state (recommended first, discouraged last).\n * In expert mode, returns options as-is.\n */\nconst sortOptions = (options: CategoryOption[], expertMode: boolean): CategoryOption[] => {\n if (expertMode) {\n return options;\n }\n\n const stateOrder: Record<OptionState, number> = {\n recommended: 0,\n normal: 1,\n discouraged: 2,\n disabled: 3,\n };\n\n return [...options].sort((a, b) => {\n return stateOrder[a.state] - stateOrder[b.state];\n });\n};\n\n/**\n * Find the next non-disabled option index in a direction.\n * Returns current index if no valid option found.\n */\nconst findNextValidOption = (\n options: CategoryOption[],\n currentIndex: number,\n direction: 1 | -1,\n wrap: boolean = true,\n): number => {\n const length = options.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += direction;\n\n if (wrap) {\n // Wrap around\n if (index < 0) index = length - 1;\n if (index >= length) index = 0;\n } else {\n // Clamp to bounds\n if (index < 0) index = 0;\n if (index >= length) index = length - 1;\n }\n\n if (options[index] && options[index].state !== \"disabled\") {\n return index;\n }\n\n attempts++;\n }\n\n // All options are disabled, return current\n return currentIndex;\n};\n\n/**\n * Find a valid starting column for a row.\n * Returns 0 if all options are disabled.\n */\nconst findValidStartColumn = (options: CategoryOption[]): number => {\n for (let i = 0; i < options.length; i++) {\n if (options[i] && options[i].state !== \"disabled\") {\n return i;\n }\n }\n return 0;\n};\n\n/**\n * Check if a section is locked (for framework-first flow).\n * A section is locked if:\n * - It's not the framework section\n * - No framework has been selected yet\n */\nconst isSectionLocked = (categoryId: string, categories: CategoryRow[]): boolean => {\n // Framework section is never locked\n if (categoryId === FRAMEWORK_CATEGORY_ID) {\n return false;\n }\n\n // Find framework category and check if any option is selected\n const frameworkCategory = categories.find((cat) => cat.id === FRAMEWORK_CATEGORY_ID);\n\n if (!frameworkCategory) {\n // No framework category exists, nothing is locked\n return false;\n }\n\n // Check if any framework option is selected\n const hasFrameworkSelected = frameworkCategory.options.some((opt) => opt.selected);\n\n // Lock if no framework is selected\n return !hasFrameworkSelected;\n};\n\n/**\n * Find the next unlocked section index in a direction.\n */\nconst findNextUnlockedSection = (\n categories: { id: string; sortedOptions: CategoryOption[] }[],\n currentIndex: number,\n direction: 1 | -1,\n allCategories: CategoryRow[],\n): number => {\n const length = categories.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += direction;\n\n // Wrap around\n if (index < 0) index = length - 1;\n if (index >= length) index = 0;\n\n const category = categories[index];\n if (category && !isSectionLocked(category.id, allCategories)) {\n return index;\n }\n\n attempts++;\n }\n\n // All sections are locked (shouldn't happen), return current\n return currentIndex;\n};\n\ninterface SkillTagProps {\n option: CategoryOption;\n isFocused: boolean;\n isLocked: boolean;\n}\n\nconst SkillTag: React.FC<SkillTagProps> = ({ option, isFocused, isLocked }) => {\n const getColor = (): { text: string; border: string } | undefined => {\n if (isLocked || option.state === \"disabled\") {\n return {\n text: \"gray\",\n border: \"gray\",\n };\n }\n if (option.selected) {\n return {\n text: \"cyan\",\n border: \"cyan\",\n };\n }\n if (option.state === \"recommended\") {\n return {\n text: \"white\",\n border: \"gray\",\n };\n }\n if (option.state === \"discouraged\") {\n return {\n text: \"yellow\",\n border: \"yellow\",\n };\n }\n return undefined;\n };\n\n const isBold = isFocused || option.selected;\n const isDimmed = isLocked || option.state === \"disabled\";\n const focusBorderColor = option.selected ? \"cyan\" : \"white\";\n\n return (\n <Box\n marginRight={1}\n borderColor={isFocused ? focusBorderColor : getColor()?.border}\n borderStyle=\"single\"\n borderDimColor={isDimmed}\n >\n <Text color={getColor()?.text} bold={isBold} dimColor={false}>\n {\" \"}\n {option.local && (\n <>\n <Text backgroundColor=\"gray\"> L </Text>{\" \"}\n </>\n )}\n {option.label}{\" \"}\n </Text>\n </Box>\n );\n};\n\ninterface CategorySectionProps {\n category: CategoryRow;\n options: CategoryOption[];\n isLocked: boolean;\n isFocused: boolean;\n focusedOptionIndex: number;\n showDescriptions: boolean;\n}\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n category,\n options,\n isLocked,\n isFocused,\n focusedOptionIndex,\n showDescriptions,\n}) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text dimColor={isLocked}>{category.name}</Text>\n {category.required && (\n <Text color={isLocked ? \"gray\" : \"red\"} dimColor={isLocked}>\n {\" \"}\n {SYMBOL_REQUIRED}\n </Text>\n )}\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {options.map((option, index) => (\n <Box key={option.id} flexDirection=\"column\">\n <SkillTag\n option={option}\n isFocused={isFocused && index === focusedOptionIndex && !isLocked}\n isLocked={isLocked}\n />\n {showDescriptions && option.stateReason && !isLocked && (\n <Box marginLeft={1} marginBottom={0}>\n <Text dimColor wrap=\"truncate-end\">\n {option.stateReason}\n </Text>\n </Box>\n )}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\n// Main Component\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n focusedRow,\n focusedCol,\n showDescriptions,\n expertMode,\n onToggle,\n onFocusChange,\n onToggleDescriptions,\n}) => {\n // Process categories with sorted options\n const processedCategories = categories.map((category) => ({\n ...category,\n sortedOptions: sortOptions(category.options, expertMode),\n }));\n\n // Get current row and its options\n const currentRow = processedCategories[focusedRow];\n const currentOptions = currentRow?.sortedOptions || [];\n const currentLocked = currentRow ? isSectionLocked(currentRow.id, categories) : false;\n\n // Ensure focusedCol is valid when row changes or options change\n useEffect(() => {\n if (!currentRow) return;\n\n const maxCol = currentOptions.length - 1;\n if (focusedCol > maxCol) {\n // Clamp to max column\n const newCol = Math.max(0, maxCol);\n onFocusChange(focusedRow, newCol);\n } else if (currentOptions[focusedCol]?.state === \"disabled\") {\n // Current option is disabled, find a valid one\n const validCol = findValidStartColumn(currentOptions);\n if (validCol !== focusedCol) {\n onFocusChange(focusedRow, validCol);\n }\n }\n }, [focusedRow, currentOptions, focusedCol, onFocusChange, currentRow]);\n\n // If current section is locked, move to first unlocked section\n useEffect(() => {\n if (currentRow && currentLocked) {\n const unlockedIndex = findNextUnlockedSection(processedCategories, focusedRow, 1, categories);\n if (unlockedIndex !== focusedRow) {\n const newRowOptions = processedCategories[unlockedIndex]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n onFocusChange(unlockedIndex, newCol);\n }\n }\n }, [currentRow, currentLocked, focusedRow, processedCategories, categories, onFocusChange]);\n\n // Handle keyboard navigation\n useInput(\n useCallback(\n (\n input: string,\n key: {\n leftArrow: boolean;\n rightArrow: boolean;\n upArrow: boolean;\n downArrow: boolean;\n tab: boolean;\n shift: boolean;\n },\n ) => {\n // Toggle descriptions with Shift+Tab (Tab now jumps sections)\n if (key.tab && key.shift) {\n onToggleDescriptions();\n return;\n }\n\n // Tab jumps to next unlocked section\n if (key.tab && !key.shift) {\n const nextSection = findNextUnlockedSection(\n processedCategories,\n focusedRow,\n 1,\n categories,\n );\n if (nextSection !== focusedRow) {\n const newRowOptions = processedCategories[nextSection]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n onFocusChange(nextSection, newCol);\n }\n return;\n }\n\n // Toggle descriptions with 'd'\n if (input === \"d\" || input === \"D\") {\n onToggleDescriptions();\n return;\n }\n\n // Toggle selection with Space (only if section is unlocked)\n if (input === \" \") {\n if (currentLocked) return;\n const currentOption = currentOptions[focusedCol];\n if (currentOption && currentOption.state !== \"disabled\") {\n onToggle(currentRow.id, currentOption.id);\n }\n return;\n }\n\n // Navigation\n const isLeft = key.leftArrow || input === \"h\";\n const isRight = key.rightArrow || input === \"l\";\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isLeft) {\n if (currentLocked) return;\n const newCol = findNextValidOption(currentOptions, focusedCol, -1, true);\n onFocusChange(focusedRow, newCol);\n } else if (isRight) {\n if (currentLocked) return;\n const newCol = findNextValidOption(currentOptions, focusedCol, 1, true);\n onFocusChange(focusedRow, newCol);\n } else if (isUp) {\n // Move to previous unlocked section\n const newRow = findNextUnlockedSection(processedCategories, focusedRow, -1, categories);\n const newRowOptions = processedCategories[newRow]?.sortedOptions || [];\n // Try to keep same column, or find valid one\n let newCol = Math.min(focusedCol, newRowOptions.length - 1);\n if (newRowOptions[newCol]?.state === \"disabled\") {\n newCol = findValidStartColumn(newRowOptions);\n }\n onFocusChange(newRow, newCol);\n } else if (isDown) {\n // Move to next unlocked section\n const newRow = findNextUnlockedSection(processedCategories, focusedRow, 1, categories);\n const newRowOptions = processedCategories[newRow]?.sortedOptions || [];\n // Try to keep same column, or find valid one\n let newCol = Math.min(focusedCol, newRowOptions.length - 1);\n if (newRowOptions[newCol]?.state === \"disabled\") {\n newCol = findValidStartColumn(newRowOptions);\n }\n onFocusChange(newRow, newCol);\n }\n },\n [\n focusedRow,\n focusedCol,\n currentOptions,\n currentRow,\n currentLocked,\n processedCategories,\n categories,\n onToggle,\n onFocusChange,\n onToggleDescriptions,\n ],\n ),\n );\n\n if (categories.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>No categories to display.</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {processedCategories.map((category, rowIndex) => {\n const isLocked = isSectionLocked(category.id, categories);\n\n return (\n <CategorySection\n key={category.id}\n category={category}\n options={category.sortedOptions}\n isLocked={isLocked}\n isFocused={rowIndex === focusedRow}\n focusedOptionIndex={focusedCol}\n showDescriptions={showDescriptions}\n />\n );\n })}\n </Box>\n );\n};\n"],"mappings":"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","names":[]}
@@ -4,31 +4,34 @@ import {
4
4
  loadSkillsMatrix,
5
5
  loadStacks,
6
6
  mergeMatrixWithSkills,
7
- parseFrontmatter,
8
7
  resolveAgentConfigToSkills
9
- } from "./chunk-B7CCVP6Q.js";
8
+ } from "./chunk-CKPQHGXR.js";
10
9
  import {
11
10
  fetchFromSource
12
- } from "./chunk-IMDW5ZUP.js";
11
+ } from "./chunk-CA4LH4LI.js";
12
+ import {
13
+ parseFrontmatter
14
+ } from "./chunk-BQX23RBV.js";
13
15
  import {
14
16
  isLocalSource,
15
17
  resolveSource
16
- } from "./chunk-V46GGCCI.js";
18
+ } from "./chunk-374JNMR6.js";
17
19
  import {
18
- verbose
19
- } from "./chunk-3U3R4NCG.js";
20
+ verbose,
21
+ warn
22
+ } from "./chunk-T25OEQFI.js";
20
23
  import {
21
24
  directoryExists,
22
25
  fileExists,
23
26
  listDirectories,
24
27
  readFile
25
- } from "./chunk-TKFPKEV3.js";
28
+ } from "./chunk-AL74GBW4.js";
26
29
  import {
27
30
  LOCAL_SKILLS_PATH,
28
31
  PROJECT_ROOT,
29
32
  SKILLS_DIR_PATH,
30
33
  SKILLS_MATRIX_PATH
31
- } from "./chunk-76DWXGQE.js";
34
+ } from "./chunk-FJFEKPXF.js";
32
35
  import {
33
36
  init_esm_shims
34
37
  } from "./chunk-DHET7RCE.js";
@@ -74,22 +77,23 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
74
77
  const metadataContent = await readFile(metadataPath);
75
78
  const metadata = parseYaml(metadataContent);
76
79
  if (!metadata.cli_name) {
77
- verbose(
78
- `Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`
79
- );
80
+ verbose(`Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`);
80
81
  return null;
81
82
  }
82
83
  const skillMdContent = await readFile(skillMdPath);
83
84
  const frontmatter = parseFrontmatter(skillMdContent);
84
85
  if (!frontmatter) {
85
- verbose(
86
- `Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`
87
- );
86
+ verbose(`Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`);
88
87
  return null;
89
88
  }
90
89
  const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;
91
90
  const skillId = frontmatter.name;
92
91
  const category = metadata.category || LOCAL_CATEGORY;
92
+ if (!metadata.category) {
93
+ warn(
94
+ `Local skill '${skillDirName}' has no category in metadata.yaml \u2014 defaulting to '${LOCAL_CATEGORY}' (will not appear in wizard domain views)`
95
+ );
96
+ }
93
97
  const extracted = {
94
98
  id: skillId,
95
99
  directoryPath: skillDirName,
@@ -116,13 +120,143 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
116
120
  // src/cli/lib/source-loader.ts
117
121
  init_esm_shims();
118
122
  import path2 from "path";
123
+
124
+ // src/cli/lib/matrix-health-check.ts
125
+ init_esm_shims();
126
+ function checkMatrixHealth(matrix) {
127
+ const issues = [];
128
+ const skillIds = new Set(Object.keys(matrix.skills));
129
+ checkRelationshipTargets(matrix, skillIds, issues);
130
+ checkSubcategoryDomains(matrix, issues);
131
+ checkSkillCategories(matrix, issues);
132
+ checkCompatibleWithTargets(matrix, skillIds, issues);
133
+ checkStackSkillIds(matrix, skillIds, issues);
134
+ for (const issue of issues) {
135
+ warn(`[matrix] ${issue.details}`);
136
+ }
137
+ return issues;
138
+ }
139
+ function checkRelationshipTargets(matrix, skillIds, issues) {
140
+ for (const [skillId, skill] of Object.entries(matrix.skills)) {
141
+ for (const conflict of skill.conflictsWith) {
142
+ if (!skillIds.has(conflict.skillId)) {
143
+ issues.push({
144
+ severity: "warning",
145
+ finding: "ghost-relationship-target",
146
+ details: `Skill '${skillId}' conflicts with '${conflict.skillId}' which does not exist in the matrix`
147
+ });
148
+ }
149
+ }
150
+ for (const recommend of skill.recommends) {
151
+ if (!skillIds.has(recommend.skillId)) {
152
+ issues.push({
153
+ severity: "warning",
154
+ finding: "ghost-relationship-target",
155
+ details: `Skill '${skillId}' recommends '${recommend.skillId}' which does not exist in the matrix`
156
+ });
157
+ }
158
+ }
159
+ for (const requirement of skill.requires) {
160
+ for (const reqId of requirement.skillIds) {
161
+ if (!skillIds.has(reqId)) {
162
+ issues.push({
163
+ severity: "error",
164
+ finding: "ghost-requirement-target",
165
+ details: `Skill '${skillId}' requires '${reqId}' which does not exist in the matrix`
166
+ });
167
+ }
168
+ }
169
+ }
170
+ for (const alt of skill.alternatives) {
171
+ if (!skillIds.has(alt.skillId)) {
172
+ issues.push({
173
+ severity: "warning",
174
+ finding: "ghost-alternative-target",
175
+ details: `Skill '${skillId}' lists alternative '${alt.skillId}' which does not exist in the matrix`
176
+ });
177
+ }
178
+ }
179
+ for (const discourage of skill.discourages) {
180
+ if (!skillIds.has(discourage.skillId)) {
181
+ issues.push({
182
+ severity: "warning",
183
+ finding: "ghost-relationship-target",
184
+ details: `Skill '${skillId}' discourages '${discourage.skillId}' which does not exist in the matrix`
185
+ });
186
+ }
187
+ }
188
+ for (const setupId of skill.requiresSetup) {
189
+ if (!skillIds.has(setupId)) {
190
+ issues.push({
191
+ severity: "warning",
192
+ finding: "ghost-setup-target",
193
+ details: `Skill '${skillId}' requiresSetup '${setupId}' which does not exist in the matrix`
194
+ });
195
+ }
196
+ }
197
+ for (const providesId of skill.providesSetupFor) {
198
+ if (!skillIds.has(providesId)) {
199
+ issues.push({
200
+ severity: "warning",
201
+ finding: "ghost-setup-target",
202
+ details: `Skill '${skillId}' providesSetupFor '${providesId}' which does not exist in the matrix`
203
+ });
204
+ }
205
+ }
206
+ }
207
+ }
208
+ function checkSubcategoryDomains(matrix, issues) {
209
+ for (const [catId, cat] of Object.entries(matrix.categories)) {
210
+ if (!cat.domain) {
211
+ issues.push({
212
+ severity: "warning",
213
+ finding: "category-missing-domain",
214
+ details: `Category '${catId}' has no domain \u2014 it won't appear in any wizard domain view`
215
+ });
216
+ }
217
+ }
218
+ }
219
+ function checkSkillCategories(matrix, issues) {
220
+ for (const [skillId, skill] of Object.entries(matrix.skills)) {
221
+ if (!matrix.categories[skill.category]) {
222
+ issues.push({
223
+ severity: "warning",
224
+ finding: "skill-unknown-category",
225
+ details: `Skill '${skillId}' references category '${skill.category}' which does not exist in the matrix`
226
+ });
227
+ }
228
+ }
229
+ }
230
+ function checkCompatibleWithTargets(matrix, skillIds, issues) {
231
+ for (const [skillId, skill] of Object.entries(matrix.skills)) {
232
+ for (const compatId of skill.compatibleWith) {
233
+ if (!skillIds.has(compatId)) {
234
+ issues.push({
235
+ severity: "warning",
236
+ finding: "ghost-compatible-with-target",
237
+ details: `Skill '${skillId}' has compatibleWith '${compatId}' which does not exist in the matrix`
238
+ });
239
+ }
240
+ }
241
+ }
242
+ }
243
+ function checkStackSkillIds(matrix, skillIds, issues) {
244
+ for (const stack of matrix.suggestedStacks) {
245
+ for (const stackSkillId of stack.allSkillIds) {
246
+ if (!skillIds.has(stackSkillId)) {
247
+ issues.push({
248
+ severity: "warning",
249
+ finding: "stack-ghost-skill",
250
+ details: `Stack '${stack.id}' references skill '${stackSkillId}' which does not exist in the matrix`
251
+ });
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ // src/cli/lib/source-loader.ts
119
258
  async function loadSkillsMatrixFromSource(options = {}) {
120
- const {
121
- sourceFlag,
122
- projectDir,
123
- forceRefresh = false,
124
- devMode = false
125
- } = options;
259
+ const { sourceFlag, projectDir, forceRefresh = false, devMode = false } = options;
126
260
  const sourceConfig = await resolveSource(sourceFlag, projectDir);
127
261
  const { source } = sourceConfig;
128
262
  verbose(`Loading skills from source: ${source}`);
@@ -139,11 +273,9 @@ async function loadSkillsMatrixFromSource(options = {}) {
139
273
  verbose(
140
274
  `Found ${localSkillsResult.skills.length} local skill(s) in ${localSkillsResult.localSkillsPath}`
141
275
  );
142
- result.matrix = mergeLocalSkillsIntoMatrix(
143
- result.matrix,
144
- localSkillsResult
145
- );
276
+ result.matrix = mergeLocalSkillsIntoMatrix(result.matrix, localSkillsResult);
146
277
  }
278
+ checkMatrixHealth(result.matrix);
147
279
  return result;
148
280
  }
149
281
  async function loadFromLocal(source, sourceConfig) {
@@ -232,9 +364,7 @@ function stackToResolvedStack(stack, skillAliases) {
232
364
  }
233
365
  }
234
366
  const agentCount = Object.keys(stack.agents).length;
235
- verbose(
236
- `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`
237
- );
367
+ verbose(`Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`);
238
368
  return {
239
369
  id: stack.id,
240
370
  name: stack.name,
@@ -247,34 +377,10 @@ function stackToResolvedStack(stack, skillAliases) {
247
377
  philosophy: stack.philosophy || ""
248
378
  };
249
379
  }
250
- var LOCAL_CATEGORY_TOP = {
251
- id: "local",
252
- name: "Local Skills",
253
- description: "Project-specific skills from .claude/skills/",
254
- exclusive: false,
255
- required: false,
256
- order: 0
257
- };
258
- var LOCAL_CATEGORY_CUSTOM = {
259
- id: "local/custom",
260
- name: "Custom",
261
- description: "Your project-specific skills",
262
- exclusive: false,
263
- required: false,
264
- order: 0,
265
- parent: "local"
266
- };
267
380
  function mergeLocalSkillsIntoMatrix(matrix, localResult) {
268
- if (!matrix.categories["local"]) {
269
- matrix.categories["local"] = LOCAL_CATEGORY_TOP;
270
- }
271
- if (!matrix.categories["local/custom"]) {
272
- matrix.categories["local/custom"] = LOCAL_CATEGORY_CUSTOM;
273
- }
274
381
  for (const metadata of localResult.skills) {
275
- const hasOriginalCategory = metadata.category !== "local" && matrix.categories[metadata.category];
276
- const category = hasOriginalCategory ? metadata.category : "local/custom";
277
382
  const existingSkill = matrix.skills[metadata.id];
383
+ const category = existingSkill?.category ?? metadata.category;
278
384
  const alias = existingSkill?.alias ?? matrix.aliasesReverse[metadata.id];
279
385
  const resolvedSkill = {
280
386
  id: metadata.id,
@@ -310,4 +416,4 @@ export {
310
416
  discoverLocalSkills,
311
417
  loadSkillsMatrixFromSource
312
418
  };
313
- //# sourceMappingURL=chunk-RFTSZDHV.js.map
419
+ //# sourceMappingURL=chunk-PLZOUVDD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/local-skill-loader.ts","../src/cli/lib/source-loader.ts","../src/cli/lib/matrix-health-check.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { directoryExists, listDirectories, fileExists, readFile } from \"../utils/fs\";\nimport { verbose, warn } from \"../utils/logger\";\nimport { LOCAL_SKILLS_PATH } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type { ExtractedSkillMetadata } from \"../types-matrix\";\n\nconst LOCAL_CATEGORY = \"local\";\nconst LOCAL_AUTHOR = \"@local\";\n\ninterface LocalRawMetadata {\n cli_name: string;\n cli_description?: string;\n /** Original skill category from source (e.g., \"framework\", \"styling\", \"api\") */\n category?: string;\n category_exclusive?: boolean;\n usage_guidance?: string;\n tags?: string[];\n compatible_with?: string[];\n conflicts_with?: string[];\n requires?: string[];\n requires_setup?: string[];\n provides_setup_for?: string[];\n}\n\nexport interface LocalSkillDiscoveryResult {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n}\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skills: ExtractedSkillMetadata[] = [];\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const skillDirName of skillDirs) {\n const skill = await extractLocalSkill(localSkillsPath, skillDirName);\n if (skill) {\n skills.push(skill);\n }\n }\n\n verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as LocalRawMetadata;\n\n if (!metadata.cli_name) {\n verbose(`Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`);\n return null;\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(`Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`);\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const skillId = frontmatter.name;\n\n // Use category from metadata.yaml if available (preserved from source skill),\n // otherwise fall back to generic \"local\" category\n const category = metadata.category || LOCAL_CATEGORY;\n\n if (!metadata.category) {\n warn(\n `Local skill '${skillDirName}' has no category in metadata.yaml — defaulting to '${LOCAL_CATEGORY}' (will not appear in wizard domain views)`,\n );\n }\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: metadata.usage_guidance,\n category,\n categoryExclusive: metadata.category_exclusive ?? false,\n author: LOCAL_AUTHOR,\n tags: metadata.tags ?? [],\n compatibleWith: metadata.compatible_with ?? [],\n conflictsWith: metadata.conflicts_with ?? [],\n requires: metadata.requires ?? [],\n requiresSetup: metadata.requires_setup ?? [],\n providesSetupFor: metadata.provides_setup_for ?? [],\n path: relativePath,\n local: true,\n localPath: relativePath,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import path from \"path\";\nimport { PROJECT_ROOT, SKILLS_DIR_PATH, SKILLS_MATRIX_PATH } from \"../consts\";\nimport type { MergedSkillsMatrix, ResolvedSkill, ResolvedStack } from \"../types-matrix\";\nimport type { Stack } from \"../types-stacks\";\nimport { fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { isLocalSource, resolveSource, type ResolvedConfig } from \"./config\";\nimport { discoverLocalSkills, type LocalSkillDiscoveryResult } from \"./local-skill-loader\";\nimport { checkMatrixHealth } from \"./matrix-health-check\";\nimport { extractAllSkills, loadSkillsMatrix, mergeMatrixWithSkills } from \"./matrix-loader\";\nimport { fetchFromSource } from \"./source-fetcher\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"./stacks-loader\";\n\nexport interface SourceLoadOptions {\n sourceFlag?: string;\n projectDir?: string;\n forceRefresh?: boolean;\n devMode?: boolean;\n}\n\nexport interface SourceLoadResult {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n}\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const { sourceFlag, projectDir, forceRefresh = false, devMode = false } = options;\n\n const sourceConfig = await resolveSource(sourceFlag, projectDir);\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const isLocal = isLocalSource(source) || devMode === true;\n\n let result: SourceLoadResult;\n if (isLocal) {\n result = await loadFromLocal(source, sourceConfig);\n } else {\n result = await loadFromRemote(source, sourceConfig, forceRefresh);\n }\n\n const resolvedProjectDir = projectDir || process.cwd();\n const localSkillsResult = await discoverLocalSkills(resolvedProjectDir);\n\n if (localSkillsResult && localSkillsResult.skills.length > 0) {\n verbose(\n `Found ${localSkillsResult.skills.length} local skill(s) in ${localSkillsResult.localSkillsPath}`,\n );\n result.matrix = mergeLocalSkillsIntoMatrix(result.matrix, localSkillsResult);\n }\n\n // Run matrix health check to surface referential integrity issues\n checkMatrixHealth(result.matrix);\n\n return result;\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n): Promise<SourceLoadResult> {\n let skillsPath: string;\n\n if (isLocalSource(source)) {\n skillsPath = path.isAbsolute(source) ? source : path.resolve(process.cwd(), source);\n } else {\n skillsPath = PROJECT_ROOT;\n }\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(skillsPath, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(skillsPath, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n marketplace: sourceConfig.marketplace,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source, { forceRefresh });\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(fetchResult.path, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(fetchResult.path, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n marketplace: sourceConfig.marketplace,\n };\n}\n\n/**\n * Convert a Stack (from config/stacks.yaml) to ResolvedStack format\n * for compatibility with the wizard.\n *\n * Phase 7: Skills are defined in stacks per agent (subcategory -> technology alias).\n * Uses skill_aliases from the matrix to resolve aliases to full skill IDs.\n */\nfunction stackToResolvedStack(stack: Stack, skillAliases: Record<string, string>): ResolvedStack {\n // Collect all unique skill IDs from agent configs in this stack\n const allSkillIds: string[] = [];\n const seenSkillIds = new Set<string>();\n\n // stack.agents is Record<string, StackAgentConfig> - iterate over agent IDs\n for (const agentId of Object.keys(stack.agents)) {\n const agentConfig = stack.agents[agentId];\n\n // Resolve this agent's technology selections to skill IDs\n const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);\n\n for (const ref of skillRefs) {\n if (!seenSkillIds.has(ref.id)) {\n seenSkillIds.add(ref.id);\n allSkillIds.push(ref.id);\n }\n }\n }\n\n const agentCount = Object.keys(stack.agents).length;\n verbose(`Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`);\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: [], // Not used in new format\n skills: {}, // Skills come from stack agent configs, resolved at runtime\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\nfunction mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n for (const metadata of localResult.skills) {\n // Preserve alias and category from existing matrix entry (if skill was in source)\n const existingSkill = matrix.skills[metadata.id];\n\n // If overwriting an existing remote skill, inherit its category unconditionally.\n // Otherwise, use whatever the local skill declared in its metadata.yaml.\n const category = existingSkill?.category ?? metadata.category;\n const alias = existingSkill?.alias ?? matrix.aliasesReverse[metadata.id];\n\n const resolvedSkill: ResolvedSkill = {\n id: metadata.id,\n alias,\n name: metadata.name,\n description: metadata.description,\n usageGuidance: metadata.usageGuidance,\n\n category,\n categoryExclusive: metadata.categoryExclusive,\n tags: metadata.tags ?? [],\n\n author: \"@local\",\n\n conflictsWith: existingSkill?.conflictsWith ?? [],\n recommends: existingSkill?.recommends ?? [],\n recommendedBy: existingSkill?.recommendedBy ?? [],\n requires: existingSkill?.requires ?? [],\n requiredBy: existingSkill?.requiredBy ?? [],\n alternatives: existingSkill?.alternatives ?? [],\n discourages: existingSkill?.discourages ?? [],\n compatibleWith: existingSkill?.compatibleWith ?? [],\n\n requiresSetup: existingSkill?.requiresSetup ?? [],\n providesSetupFor: existingSkill?.providesSetupFor ?? [],\n\n path: metadata.path,\n\n local: true,\n localPath: metadata.localPath,\n };\n\n matrix.skills[metadata.id] = resolvedSkill;\n verbose(`Added local skill: ${metadata.id} (category: ${category})`);\n }\n\n return matrix;\n}\n","import { warn } from \"../utils/logger\";\nimport type { MergedSkillsMatrix } from \"../types-matrix\";\n\nexport interface MatrixHealthIssue {\n severity: \"warning\" | \"error\";\n finding: string;\n details: string;\n}\n\n/**\n * Validate referential integrity of a merged skills matrix.\n *\n * Checks for:\n * - Skill IDs in relationships that don't resolve to existing skills (ghost IDs)\n * - Categories missing a `domain` field (invisible in wizard)\n * - Skills referencing categories that don't exist in the matrix\n * - `compatibleWith` entries that reference non-existent skill IDs\n * - Stack `allSkillIds` entries that reference non-existent skill IDs\n *\n * Returns a list of issues found. Also logs warnings for each issue.\n */\nexport function checkMatrixHealth(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n const issues: MatrixHealthIssue[] = [];\n const skillIds = new Set(Object.keys(matrix.skills));\n\n checkRelationshipTargets(matrix, skillIds, issues);\n checkSubcategoryDomains(matrix, issues);\n checkSkillCategories(matrix, issues);\n checkCompatibleWithTargets(matrix, skillIds, issues);\n checkStackSkillIds(matrix, skillIds, issues);\n\n for (const issue of issues) {\n warn(`[matrix] ${issue.details}`);\n }\n\n return issues;\n}\n\n/**\n * Check that all skill IDs referenced in relationships point to real skills.\n */\nfunction checkRelationshipTargets(\n matrix: MergedSkillsMatrix,\n skillIds: Set<string>,\n issues: MatrixHealthIssue[],\n): void {\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n for (const conflict of skill.conflictsWith) {\n if (!skillIds.has(conflict.skillId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-relationship-target\",\n details: `Skill '${skillId}' conflicts with '${conflict.skillId}' which does not exist in the matrix`,\n });\n }\n }\n\n for (const recommend of skill.recommends) {\n if (!skillIds.has(recommend.skillId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-relationship-target\",\n details: `Skill '${skillId}' recommends '${recommend.skillId}' which does not exist in the matrix`,\n });\n }\n }\n\n for (const requirement of skill.requires) {\n for (const reqId of requirement.skillIds) {\n if (!skillIds.has(reqId)) {\n issues.push({\n severity: \"error\",\n finding: \"ghost-requirement-target\",\n details: `Skill '${skillId}' requires '${reqId}' which does not exist in the matrix`,\n });\n }\n }\n }\n\n for (const alt of skill.alternatives) {\n if (!skillIds.has(alt.skillId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-alternative-target\",\n details: `Skill '${skillId}' lists alternative '${alt.skillId}' which does not exist in the matrix`,\n });\n }\n }\n\n for (const discourage of skill.discourages) {\n if (!skillIds.has(discourage.skillId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-relationship-target\",\n details: `Skill '${skillId}' discourages '${discourage.skillId}' which does not exist in the matrix`,\n });\n }\n }\n\n for (const setupId of skill.requiresSetup) {\n if (!skillIds.has(setupId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-setup-target\",\n details: `Skill '${skillId}' requiresSetup '${setupId}' which does not exist in the matrix`,\n });\n }\n }\n\n for (const providesId of skill.providesSetupFor) {\n if (!skillIds.has(providesId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-setup-target\",\n details: `Skill '${skillId}' providesSetupFor '${providesId}' which does not exist in the matrix`,\n });\n }\n }\n }\n}\n\n/**\n * Check that all categories have a domain field.\n * Categories without a domain won't appear in any wizard domain view.\n */\nfunction checkSubcategoryDomains(matrix: MergedSkillsMatrix, issues: MatrixHealthIssue[]): void {\n for (const [catId, cat] of Object.entries(matrix.categories)) {\n if (!cat.domain) {\n issues.push({\n severity: \"warning\",\n finding: \"category-missing-domain\",\n details: `Category '${catId}' has no domain — it won't appear in any wizard domain view`,\n });\n }\n }\n}\n\n/**\n * Check that all skills reference categories that exist in the matrix.\n */\nfunction checkSkillCategories(matrix: MergedSkillsMatrix, issues: MatrixHealthIssue[]): void {\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n if (!matrix.categories[skill.category]) {\n issues.push({\n severity: \"warning\",\n finding: \"skill-unknown-category\",\n details: `Skill '${skillId}' references category '${skill.category}' which does not exist in the matrix`,\n });\n }\n }\n}\n\n/**\n * Check that all compatibleWith entries reference real skill IDs.\n */\nfunction checkCompatibleWithTargets(\n matrix: MergedSkillsMatrix,\n skillIds: Set<string>,\n issues: MatrixHealthIssue[],\n): void {\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n for (const compatId of skill.compatibleWith) {\n if (!skillIds.has(compatId)) {\n issues.push({\n severity: \"warning\",\n finding: \"ghost-compatible-with-target\",\n details: `Skill '${skillId}' has compatibleWith '${compatId}' which does not exist in the matrix`,\n });\n }\n }\n }\n}\n\n/**\n * Check that all stack allSkillIds reference real skills in the matrix.\n */\nfunction checkStackSkillIds(\n matrix: MergedSkillsMatrix,\n skillIds: Set<string>,\n issues: MatrixHealthIssue[],\n): void {\n for (const stack of matrix.suggestedStacks) {\n for (const stackSkillId of stack.allSkillIds) {\n if (!skillIds.has(stackSkillId)) {\n issues.push({\n severity: \"warning\",\n finding: \"stack-ghost-skill\",\n details: `Stack '${stack.id}' references skill '${stackSkillId}' which does not exist in the matrix`,\n });\n }\n }\n }\n}\n"],"mappings":"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","names":["path","path"]}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-DHET7RCE.js";
5
+
6
+ // src/cli/components/wizard/view-title.tsx
7
+ init_esm_shims();
8
+ import { Text } from "ink";
9
+ import { jsxs } from "react/jsx-runtime";
10
+ var ViewTitle = ({ children }) => {
11
+ return /* @__PURE__ */ jsxs(Text, { backgroundColor: "yellow", bold: true, color: "#000", children: [
12
+ " ",
13
+ children,
14
+ " "
15
+ ] });
16
+ };
17
+
18
+ export {
19
+ ViewTitle
20
+ };
21
+ //# sourceMappingURL=chunk-Q3J43SF3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/view-title.tsx"],"sourcesContent":["import React from \"react\";\nimport { Text } from \"ink\";\n\nexport interface ViewTitleProps {\n children: React.ReactNode;\n}\n\nexport const ViewTitle: React.FC<ViewTitleProps> = ({ children }) => {\n return (\n <Text backgroundColor=\"yellow\" bold color=\"#000\">\n {\" \"}\n {children}{\" \"}\n </Text>\n );\n};\n"],"mappings":";;;;;;AAAA;AACA,SAAS,YAAY;AAQjB;AAFG,IAAM,YAAsC,CAAC,EAAE,SAAS,MAAM;AACnE,SACE,qBAAC,QAAK,iBAAgB,UAAS,MAAI,MAAC,OAAM,QACvC;AAAA;AAAA,IACA;AAAA,IAAU;AAAA,KACb;AAEJ;","names":[]}
@@ -14,9 +14,13 @@ function verbose(msg) {
14
14
  console.log(` ${msg}`);
15
15
  }
16
16
  }
17
+ function warn(msg) {
18
+ console.warn(` Warning: ${msg}`);
19
+ }
17
20
 
18
21
  export {
19
22
  setVerbose,
20
- verbose
23
+ verbose,
24
+ warn
21
25
  };
22
- //# sourceMappingURL=chunk-3U3R4NCG.js.map
26
+ //# sourceMappingURL=chunk-T25OEQFI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/utils/logger.ts"],"sourcesContent":["/**\n * Verbose logging utility.\n * Used by lib/ modules that don't have access to oclif command context.\n * In oclif commands, prefer using this.log() instead.\n */\n\nlet verboseMode = false;\n\nexport function setVerbose(enabled: boolean): void {\n verboseMode = enabled;\n}\n\nexport function verbose(msg: string): void {\n if (verboseMode) {\n console.log(` ${msg}`);\n }\n}\n\n/**\n * Log a warning that is always visible (not gated by verbose mode).\n * Used for issues the user should know about, like unresolved references.\n */\nexport function warn(msg: string): void {\n console.warn(` Warning: ${msg}`);\n}\n"],"mappings":";;;;;;AAAA;AAMA,IAAI,cAAc;AAEX,SAAS,WAAW,SAAwB;AACjD,gBAAc;AAChB;AAEO,SAAS,QAAQ,KAAmB;AACzC,MAAI,aAAa;AACf,YAAQ,IAAI,KAAK,GAAG,EAAE;AAAA,EACxB;AACF;AAMO,SAAS,KAAK,KAAmB;AACtC,UAAQ,KAAK,cAAc,GAAG,EAAE;AAClC;","names":[]}
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-DHET7RCE.js";
5
+
6
+ // src/cli/components/wizard/menu-item.tsx
7
+ init_esm_shims();
8
+ import { Box, Text } from "ink";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var CHEVRON = "\u276F";
11
+ var CHEVRON_SPACER = " ";
12
+ var MenuItem = ({
13
+ label,
14
+ description,
15
+ isFocused = false,
16
+ isActive = false
17
+ }) => {
18
+ const showCyan = isFocused || isActive;
19
+ return /* @__PURE__ */ jsxs(Box, { columnGap: 1, children: [
20
+ /* @__PURE__ */ jsx(Text, { color: isFocused ? "cyan" : void 0, children: isFocused ? CHEVRON : CHEVRON_SPACER }),
21
+ /* @__PURE__ */ jsx(Text, { bold: isFocused, color: showCyan ? "cyan" : void 0, children: label }),
22
+ isFocused && description && /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${description}` })
23
+ ] });
24
+ };
25
+
26
+ export {
27
+ MenuItem
28
+ };
29
+ //# sourceMappingURL=chunk-UMORK7OK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/menu-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\n\nconst CHEVRON = \"\\u276F\";\nconst CHEVRON_SPACER = \" \";\n\nexport interface MenuItemProps {\n label: string;\n description?: string;\n isFocused?: boolean;\n isActive?: boolean;\n}\n\nexport const MenuItem: React.FC<MenuItemProps> = ({\n label,\n description,\n isFocused = false,\n isActive = false,\n}) => {\n const showCyan = isFocused || isActive;\n\n return (\n <Box columnGap={1}>\n <Text color={isFocused ? \"cyan\" : undefined}>{isFocused ? CHEVRON : CHEVRON_SPACER}</Text>\n <Text bold={isFocused} color={showCyan ? \"cyan\" : undefined}>\n {label}\n </Text>\n {isFocused && description && <Text dimColor>{` ${description}`}</Text>}\n </Box>\n );\n};\n"],"mappings":";;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAqBtB,SACE,KADF;AAnBJ,IAAM,UAAU;AAChB,IAAM,iBAAiB;AAShB,IAAM,WAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,WAAW;AACb,MAAM;AACJ,QAAM,WAAW,aAAa;AAE9B,SACE,qBAAC,OAAI,WAAW,GACd;AAAA,wBAAC,QAAK,OAAO,YAAY,SAAS,QAAY,sBAAY,UAAU,gBAAe;AAAA,IACnF,oBAAC,QAAK,MAAM,WAAW,OAAO,WAAW,SAAS,QAC/C,iBACH;AAAA,IACC,aAAa,eAAe,oBAAC,QAAK,UAAQ,MAAE,cAAI,WAAW,IAAG;AAAA,KACjE;AAEJ;","names":[]}