@claude-collective/cli 0.8.0 → 0.13.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 (217) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +26 -9
  3. package/dist/{chunk-TOPAIL5W.js → chunk-3U3R4NCG.js} +2 -2
  4. package/dist/chunk-3U3R4NCG.js.map +1 -0
  5. package/dist/{chunk-YKXBGCFD.js → chunk-57Y5RALO.js} +10 -10
  6. package/dist/chunk-57Y5RALO.js.map +1 -0
  7. package/dist/{chunk-ED73HCW2.js → chunk-6DCSSORF.js} +37 -88
  8. package/dist/chunk-6DCSSORF.js.map +1 -0
  9. package/dist/{chunk-6LS7XO3H.js → chunk-6Q3Y7KVB.js} +2 -2
  10. package/dist/chunk-6Q3Y7KVB.js.map +1 -0
  11. package/dist/{chunk-A3J6IAXK.js → chunk-76DWXGQE.js} +4 -2
  12. package/dist/chunk-76DWXGQE.js.map +1 -0
  13. package/dist/{chunk-Q6DR5QUH.js → chunk-7Q44DMSP.js} +62 -27
  14. package/dist/chunk-7Q44DMSP.js.map +1 -0
  15. package/dist/chunk-ACNBKXXJ.js +321 -0
  16. package/dist/chunk-ACNBKXXJ.js.map +1 -0
  17. package/dist/{chunk-QGGSLMO3.js → chunk-B7CCVP6Q.js} +41 -9
  18. package/dist/chunk-B7CCVP6Q.js.map +1 -0
  19. package/dist/{chunk-LVKRVFYR.js → chunk-BDLUZVKU.js} +2 -2
  20. package/dist/chunk-BDLUZVKU.js.map +1 -0
  21. package/dist/{chunk-HNDT5QRB.js → chunk-CDX4W4DM.js} +3 -3
  22. package/dist/chunk-CDX4W4DM.js.map +1 -0
  23. package/dist/{chunk-MYAVQ23U.js → chunk-CJEHB4TB.js} +23 -9
  24. package/dist/chunk-CJEHB4TB.js.map +1 -0
  25. package/dist/{chunk-DKGL77IY.js → chunk-CPZOTVCI.js} +15 -14
  26. package/dist/chunk-CPZOTVCI.js.map +1 -0
  27. package/dist/{chunk-K7PTOVX4.js → chunk-D237EVNB.js} +32 -3
  28. package/dist/chunk-D237EVNB.js.map +1 -0
  29. package/dist/{chunk-Q2LH2DAB.js → chunk-DRXPNNPB.js} +19 -18
  30. package/dist/chunk-DRXPNNPB.js.map +1 -0
  31. package/dist/{chunk-Y3V43XCU.js → chunk-E3FJH4TF.js} +12 -8
  32. package/dist/chunk-E3FJH4TF.js.map +1 -0
  33. package/dist/{chunk-3HBTELJN.js → chunk-ED4E6Q2T.js} +10 -10
  34. package/dist/chunk-ED4E6Q2T.js.map +1 -0
  35. package/dist/{chunk-SYQ7R2JO.js → chunk-EHS3TWWP.js} +3 -3
  36. package/dist/chunk-EHS3TWWP.js.map +1 -0
  37. package/dist/{chunk-LQTST4WY.js → chunk-GDH553MV.js} +6 -6
  38. package/dist/chunk-GDH553MV.js.map +1 -0
  39. package/dist/{chunk-A65SBAAJ.js → chunk-HLJX2FTL.js} +31 -5
  40. package/dist/chunk-HLJX2FTL.js.map +1 -0
  41. package/dist/chunk-I2DSLOXZ.js +75 -0
  42. package/dist/chunk-I2DSLOXZ.js.map +1 -0
  43. package/dist/{chunk-SEBPPFUW.js → chunk-I4TPKIYX.js} +33 -18
  44. package/dist/chunk-I4TPKIYX.js.map +1 -0
  45. package/dist/{chunk-NGBFJJ7Q.js → chunk-IMDW5ZUP.js} +19 -11
  46. package/dist/chunk-IMDW5ZUP.js.map +1 -0
  47. package/dist/{chunk-U4VYHKPM.js → chunk-JIPWV2FX.js} +6 -6
  48. package/dist/chunk-JIPWV2FX.js.map +1 -0
  49. package/dist/{chunk-G2FBJOZG.js → chunk-K7EVM5LY.js} +4 -4
  50. package/dist/chunk-K7EVM5LY.js.map +1 -0
  51. package/dist/{chunk-MJSFR562.js → chunk-KAAEN2PO.js} +3 -3
  52. package/dist/chunk-KAAEN2PO.js.map +1 -0
  53. package/dist/{chunk-FNOYEXUE.js → chunk-LE6IY6IT.js} +22 -17
  54. package/dist/chunk-LE6IY6IT.js.map +1 -0
  55. package/dist/{chunk-CIY5UBRB.js → chunk-NDY25DTL.js} +6 -6
  56. package/dist/chunk-NDY25DTL.js.map +1 -0
  57. package/dist/{chunk-OLBOTK3O.js → chunk-P26A2K5N.js} +7 -7
  58. package/dist/chunk-P26A2K5N.js.map +1 -0
  59. package/dist/{chunk-DHFFRMF6.js → chunk-RTE64SJA.js} +2 -2
  60. package/dist/chunk-RTE64SJA.js.map +1 -0
  61. package/dist/{chunk-3ZCB5K33.js → chunk-SGJ23HIP.js} +14 -11
  62. package/dist/chunk-SGJ23HIP.js.map +1 -0
  63. package/dist/{chunk-C4ZTIYFR.js → chunk-SVYPSDWY.js} +10 -10
  64. package/dist/chunk-SVYPSDWY.js.map +1 -0
  65. package/dist/{chunk-MMDXNZPF.js → chunk-TKFPKEV3.js} +2 -2
  66. package/dist/chunk-TKFPKEV3.js.map +1 -0
  67. package/dist/{chunk-M7YCPFIX.js → chunk-UQTEPWU7.js} +2 -2
  68. package/dist/chunk-UQTEPWU7.js.map +1 -0
  69. package/dist/{chunk-QESUUPOE.js → chunk-V46GGCCI.js} +80 -27
  70. package/dist/chunk-V46GGCCI.js.map +1 -0
  71. package/dist/{chunk-UOWHJ6BE.js → chunk-X6QONICW.js} +6 -3
  72. package/dist/chunk-X6QONICW.js.map +1 -0
  73. package/dist/chunk-Y2LW7R3Y.js +23 -0
  74. package/dist/chunk-Y2LW7R3Y.js.map +1 -0
  75. package/dist/chunk-Z2CWURZ6.js +78 -0
  76. package/dist/chunk-Z2CWURZ6.js.map +1 -0
  77. package/dist/chunk-Z7G4B5HJ.js +377 -0
  78. package/dist/chunk-Z7G4B5HJ.js.map +1 -0
  79. package/dist/{chunk-XKEG3SCV.js → chunk-ZENYS6KW.js} +13 -9
  80. package/dist/chunk-ZENYS6KW.js.map +1 -0
  81. package/dist/{cli-v2 → cli}/defaults/agent-mappings.yaml +5 -5
  82. package/dist/commands/build/marketplace.js +9 -9
  83. package/dist/commands/build/marketplace.js.map +1 -1
  84. package/dist/commands/build/plugins.js +12 -12
  85. package/dist/commands/build/plugins.js.map +1 -1
  86. package/dist/commands/build/stack.js +15 -15
  87. package/dist/commands/build/stack.js.map +1 -1
  88. package/dist/commands/compile.js +21 -21
  89. package/dist/commands/compile.js.map +1 -1
  90. package/dist/commands/config/get.js +9 -8
  91. package/dist/commands/config/get.js.map +1 -1
  92. package/dist/commands/config/index.js +7 -6
  93. package/dist/commands/config/index.js.map +1 -1
  94. package/dist/commands/config/path.js +8 -7
  95. package/dist/commands/config/path.js.map +1 -1
  96. package/dist/commands/config/set-project.js +9 -8
  97. package/dist/commands/config/set-project.js.map +1 -1
  98. package/dist/commands/config/set.js +9 -8
  99. package/dist/commands/config/set.js.map +1 -1
  100. package/dist/commands/config/show.js +6 -5
  101. package/dist/commands/config/unset-project.js +9 -8
  102. package/dist/commands/config/unset-project.js.map +1 -1
  103. package/dist/commands/config/unset.js +9 -8
  104. package/dist/commands/config/unset.js.map +1 -1
  105. package/dist/commands/diff.js +12 -12
  106. package/dist/commands/diff.js.map +1 -1
  107. package/dist/commands/doctor.js +10 -10
  108. package/dist/commands/doctor.js.map +1 -1
  109. package/dist/commands/edit.js +52 -49
  110. package/dist/commands/edit.js.map +1 -1
  111. package/dist/commands/eject.js +180 -97
  112. package/dist/commands/eject.js.map +1 -1
  113. package/dist/commands/import/skill.js +339 -0
  114. package/dist/commands/import/skill.js.map +1 -0
  115. package/dist/commands/info.js +9 -9
  116. package/dist/commands/info.js.map +1 -1
  117. package/dist/commands/init.js +205 -78
  118. package/dist/commands/init.js.map +1 -1
  119. package/dist/commands/list.js +9 -9
  120. package/dist/commands/list.js.map +1 -1
  121. package/dist/commands/new/agent.js +19 -21
  122. package/dist/commands/new/agent.js.map +1 -1
  123. package/dist/commands/new/skill.js +11 -12
  124. package/dist/commands/new/skill.js.map +1 -1
  125. package/dist/commands/outdated.js +12 -12
  126. package/dist/commands/outdated.js.map +1 -1
  127. package/dist/commands/search.js +205 -17
  128. package/dist/commands/search.js.map +1 -1
  129. package/dist/commands/test-imports.js +18 -18
  130. package/dist/commands/test-imports.js.map +1 -1
  131. package/dist/commands/uninstall.js +58 -78
  132. package/dist/commands/uninstall.js.map +1 -1
  133. package/dist/commands/update.js +21 -21
  134. package/dist/commands/update.js.map +1 -1
  135. package/dist/commands/validate.js +9 -9
  136. package/dist/commands/validate.js.map +1 -1
  137. package/dist/commands/version/bump.js +8 -8
  138. package/dist/commands/version/bump.js.map +1 -1
  139. package/dist/commands/version/index.js +8 -8
  140. package/dist/commands/version/index.js.map +1 -1
  141. package/dist/commands/version/set.js +7 -7
  142. package/dist/commands/version/set.js.map +1 -1
  143. package/dist/commands/version/show.js +8 -8
  144. package/dist/commands/version/show.js.map +1 -1
  145. package/dist/components/common/confirm.js +1 -1
  146. package/dist/components/common/message.js +1 -1
  147. package/dist/components/common/message.js.map +1 -1
  148. package/dist/components/common/spinner.js +1 -1
  149. package/dist/components/common/spinner.js.map +1 -1
  150. package/dist/components/skill-search/skill-search.js +10 -0
  151. package/dist/components/skill-search/skill-search.js.map +1 -0
  152. package/dist/components/wizard/category-grid.js +1 -1
  153. package/dist/components/wizard/category-grid.test.js +213 -80
  154. package/dist/components/wizard/category-grid.test.js.map +1 -1
  155. package/dist/components/wizard/section-progress.js +1 -1
  156. package/dist/components/wizard/section-progress.test.js +2 -2
  157. package/dist/components/wizard/section-progress.test.js.map +1 -1
  158. package/dist/components/wizard/step-approach.js +4 -3
  159. package/dist/components/wizard/step-build.js +4 -3
  160. package/dist/components/wizard/step-build.test.js +29 -17
  161. package/dist/components/wizard/step-build.test.js.map +1 -1
  162. package/dist/components/wizard/step-confirm.js +2 -1
  163. package/dist/components/wizard/step-refine.js +2 -1
  164. package/dist/components/wizard/step-refine.test.js +4 -3
  165. package/dist/components/wizard/step-refine.test.js.map +1 -1
  166. package/dist/components/wizard/step-stack-options.js +3 -3
  167. package/dist/components/wizard/step-stack.js +3 -3
  168. package/dist/components/wizard/wizard-footer.js +9 -0
  169. package/dist/components/wizard/wizard-footer.js.map +1 -0
  170. package/dist/components/wizard/wizard-tabs.js +1 -1
  171. package/dist/components/wizard/wizard.js +14 -12
  172. package/dist/hooks/init.js +5 -4
  173. package/dist/hooks/init.js.map +1 -1
  174. package/dist/index.js +1 -1
  175. package/dist/index.js.map +1 -1
  176. package/dist/stores/wizard-store.js +2 -2
  177. package/dist/stores/wizard-store.test.js +3 -3
  178. package/dist/stores/wizard-store.test.js.map +1 -1
  179. package/package.json +3 -2
  180. package/dist/chunk-3HBTELJN.js.map +0 -1
  181. package/dist/chunk-3ZCB5K33.js.map +0 -1
  182. package/dist/chunk-6LS7XO3H.js.map +0 -1
  183. package/dist/chunk-A3J6IAXK.js.map +0 -1
  184. package/dist/chunk-A65SBAAJ.js.map +0 -1
  185. package/dist/chunk-ALEPJ6YN.js +0 -80
  186. package/dist/chunk-ALEPJ6YN.js.map +0 -1
  187. package/dist/chunk-C4ZTIYFR.js.map +0 -1
  188. package/dist/chunk-CIY5UBRB.js.map +0 -1
  189. package/dist/chunk-DHFFRMF6.js.map +0 -1
  190. package/dist/chunk-DKGL77IY.js.map +0 -1
  191. package/dist/chunk-ED73HCW2.js.map +0 -1
  192. package/dist/chunk-FNOYEXUE.js.map +0 -1
  193. package/dist/chunk-G2FBJOZG.js.map +0 -1
  194. package/dist/chunk-HNDT5QRB.js.map +0 -1
  195. package/dist/chunk-K7PTOVX4.js.map +0 -1
  196. package/dist/chunk-LQTST4WY.js.map +0 -1
  197. package/dist/chunk-LVKRVFYR.js.map +0 -1
  198. package/dist/chunk-M7YCPFIX.js.map +0 -1
  199. package/dist/chunk-MJSFR562.js.map +0 -1
  200. package/dist/chunk-MMDXNZPF.js.map +0 -1
  201. package/dist/chunk-MYAVQ23U.js.map +0 -1
  202. package/dist/chunk-NGBFJJ7Q.js.map +0 -1
  203. package/dist/chunk-OLBOTK3O.js.map +0 -1
  204. package/dist/chunk-PPNTD5LO.js +0 -330
  205. package/dist/chunk-PPNTD5LO.js.map +0 -1
  206. package/dist/chunk-Q2LH2DAB.js.map +0 -1
  207. package/dist/chunk-Q6DR5QUH.js.map +0 -1
  208. package/dist/chunk-QESUUPOE.js.map +0 -1
  209. package/dist/chunk-QGGSLMO3.js.map +0 -1
  210. package/dist/chunk-SEBPPFUW.js.map +0 -1
  211. package/dist/chunk-SYQ7R2JO.js.map +0 -1
  212. package/dist/chunk-TOPAIL5W.js.map +0 -1
  213. package/dist/chunk-U4VYHKPM.js.map +0 -1
  214. package/dist/chunk-UOWHJ6BE.js.map +0 -1
  215. package/dist/chunk-XKEG3SCV.js.map +0 -1
  216. package/dist/chunk-Y3V43XCU.js.map +0 -1
  217. package/dist/chunk-YKXBGCFD.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/components/wizard/step-stack.tsx"],"sourcesContent":["/**\n * StepStack component - Dual-purpose step for stack selection or domain selection.\n *\n * Stack path (approach === \"stack\"):\n * - Shows list of pre-built stacks from matrix.suggestedStacks\n * - Selecting a stack populates domainSelections and goes to stack-options\n *\n * Scratch path (approach === \"scratch\"):\n * - Shows multi-select of domains (Web, API, CLI, Mobile)\n * - User selects which domains to configure\n * - Continue goes to build step for first selected domain\n */\nimport React from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { Select } from \"@inkjs/ui\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst BACK_VALUE = \"_back\";\nconst CONTINUE_VALUE = \"_continue\";\n\n/** Available domains for scratch path */\nconst AVAILABLE_DOMAINS = [\n { id: \"web\", label: \"Web\", description: \"Frontend web applications\" },\n { id: \"api\", label: \"API\", description: \"Backend APIs and services\" },\n { id: \"cli\", label: \"CLI\", description: \"Command-line tools\" },\n { id: \"mobile\", label: \"Mobile\", description: \"Mobile applications\" },\n];\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface StepStackProps {\n matrix: MergedSkillsMatrix;\n}\n\n// =============================================================================\n// Stack Selection Sub-component\n// =============================================================================\n\ninterface StackSelectionProps {\n matrix: MergedSkillsMatrix;\n}\n\nconst StackSelection: React.FC<StackSelectionProps> = ({ matrix }) => {\n const { selectStack, setStep, goBack } = useWizardStore();\n\n // Build options from matrix.suggestedStacks\n const options = [\n { value: BACK_VALUE, label: \"\\u2190 Back\" },\n ...matrix.suggestedStacks.map((stack) => ({\n value: stack.id,\n label: `${stack.name} - ${stack.description}`,\n })),\n ];\n\n const handleSelect = (value: string) => {\n if (value === BACK_VALUE) {\n goBack();\n return;\n }\n\n const stack = matrix.suggestedStacks.find((s) => s.id === value);\n if (stack) {\n selectStack(stack.id);\n setStep(\"stack-options\");\n }\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Select a pre-built template:</Text>\n <Box marginTop={1}>\n <Select\n options={options}\n onChange={handleSelect}\n visibleOptionCount={options.length}\n />\n </Box>\n <Box marginTop={1}>\n <Text dimColor>\n {\"\\u2191\"}/{\"\\u2193\"} navigate ENTER select ESC back\n </Text>\n </Box>\n </Box>\n );\n};\n\n// =============================================================================\n// Domain Selection Sub-component\n// =============================================================================\n\nconst DomainSelection: React.FC = () => {\n const { selectedDomains, toggleDomain, setStep, goBack } = useWizardStore();\n\n // Build options with checkboxes showing selection state\n const domainOptions = AVAILABLE_DOMAINS.map((domain) => {\n const isSelected = selectedDomains.includes(domain.id);\n const checkbox = isSelected ? \"[\\u2713]\" : \"[ ]\";\n return {\n value: domain.id,\n label: `${checkbox} ${domain.label} - ${domain.description}`,\n };\n });\n\n const options = [\n { value: BACK_VALUE, label: \"\\u2190 Back\" },\n ...domainOptions,\n ...(selectedDomains.length > 0\n ? [\n {\n value: CONTINUE_VALUE,\n label: `\\u2192 Continue with ${selectedDomains.length} domain(s)`,\n },\n ]\n : []),\n ];\n\n const handleSelect = (value: string) => {\n if (value === BACK_VALUE) {\n goBack();\n return;\n }\n\n if (value === CONTINUE_VALUE) {\n if (selectedDomains.length > 0) {\n setStep(\"build\");\n }\n return;\n }\n\n // Toggle domain selection\n toggleDomain(value);\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Select domains to configure:</Text>\n <Text dimColor>Select one or more domains, then continue</Text>\n <Box marginTop={1}>\n <Select options={options} onChange={handleSelect} />\n </Box>\n {selectedDomains.length > 0 ? (\n <Box marginTop={1}>\n <Text>\n Selected: <Text color=\"cyan\">{selectedDomains.join(\", \")}</Text>\n </Text>\n </Box>\n ) : (\n <Box marginTop={1}>\n <Text color=\"yellow\">Please select at least one domain</Text>\n </Box>\n )}\n <Box marginTop={1}>\n <Text dimColor>\n {\"\\u2191\"}/{\"\\u2193\"} navigate ENTER toggle/select ESC back\n </Text>\n </Box>\n </Box>\n );\n};\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const StepStack: React.FC<StepStackProps> = ({ matrix }) => {\n const { approach } = useWizardStore();\n\n if (approach === \"stack\") {\n return <StackSelection matrix={matrix} />;\n }\n\n // approach === \"scratch\"\n return <DomainSelection />;\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/stores/wizard-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { DEFAULT_PRESELECTED_SKILLS } from \"../consts\";\n\n// Step types for the wizard\nexport type WizardStep =\n | \"approach\" // Choose stack template or build from scratch\n | \"stack\" // Select pre-built stack (if approach=stack) or domains (if approach=scratch)\n | \"stack-options\" // After stack selection: continue defaults or customize\n | \"build\" // CategoryGrid for technology selection\n | \"refine\" // Skill source selection\n | \"confirm\"; // Final confirmation\n\nexport interface WizardState {\n // ─────────────────────────────────────────────────────────────────\n // Current step\n // ─────────────────────────────────────────────────────────────────\n step: WizardStep;\n\n // ─────────────────────────────────────────────────────────────────\n // Flow tracking\n // ─────────────────────────────────────────────────────────────────\n approach: \"stack\" | \"scratch\" | null;\n selectedStackId: string | null;\n stackAction: \"defaults\" | \"customize\" | null; // For stack flow after selection\n\n // ─────────────────────────────────────────────────────────────────\n // Domain selection (scratch flow or customize flow)\n // ─────────────────────────────────────────────────────────────────\n selectedDomains: string[]; // ['web', 'api', 'cli', 'mobile']\n\n // ─────────────────────────────────────────────────────────────────\n // Build step state\n // ─────────────────────────────────────────────────────────────────\n currentDomainIndex: number; // Which domain we're configuring (0-based)\n domainSelections: Record<string, Record<string, string[]>>;\n // e.g., { web: { framework: ['react'], styling: ['scss-modules'] } }\n // Note: array supports multi-select categories\n\n // ─────────────────────────────────────────────────────────────────\n // Grid navigation state\n // ─────────────────────────────────────────────────────────────────\n focusedRow: number;\n focusedCol: number;\n\n // ─────────────────────────────────────────────────────────────────\n // Refine step state\n // ─────────────────────────────────────────────────────────────────\n currentRefineIndex: number; // Which skill we're refining\n skillSources: Record<string, string>; // technology -> selected skill ID\n refineAction: \"all-recommended\" | \"customize\" | null;\n\n // ─────────────────────────────────────────────────────────────────\n // UI state\n // ─────────────────────────────────────────────────────────────────\n showDescriptions: boolean;\n expertMode: boolean;\n\n // ─────────────────────────────────────────────────────────────────\n // Modes\n // ─────────────────────────────────────────────────────────────────\n installMode: \"plugin\" | \"local\";\n\n // ─────────────────────────────────────────────────────────────────\n // Navigation history\n // ─────────────────────────────────────────────────────────────────\n history: WizardStep[];\n\n // ─────────────────────────────────────────────────────────────────\n // Actions\n // ─────────────────────────────────────────────────────────────────\n setStep: (step: WizardStep) => void;\n setApproach: (approach: \"stack\" | \"scratch\") => void;\n selectStack: (stackId: string | null) => void;\n setStackAction: (action: \"defaults\" | \"customize\") => void;\n toggleDomain: (domain: string) => void;\n setDomainSelection: (\n domain: string,\n subcategory: string,\n technologies: string[],\n ) => void;\n toggleTechnology: (\n domain: string,\n subcategory: string,\n technology: string,\n exclusive: boolean,\n ) => void;\n setCurrentDomainIndex: (index: number) => void;\n nextDomain: () => boolean; // Returns true if moved to next domain, false if at end\n prevDomain: () => boolean; // Returns true if moved to prev domain, false if at start\n setFocus: (row: number, col: number) => void;\n setRefineAction: (action: \"all-recommended\" | \"customize\") => void;\n setSkillSource: (technology: string, skillId: string) => void;\n setCurrentRefineIndex: (index: number) => void;\n toggleShowDescriptions: () => void;\n toggleExpertMode: () => void;\n toggleInstallMode: () => void;\n goBack: () => void;\n reset: () => void;\n\n // ─────────────────────────────────────────────────────────────────\n // Computed getters (derive from state)\n // ─────────────────────────────────────────────────────────────────\n getAllSelectedTechnologies: () => string[];\n getCurrentDomain: () => string | null;\n getSelectedSkills: () => string[]; // All selected skills including preselected\n}\n\nconst createInitialState = () => ({\n step: \"approach\" as WizardStep,\n approach: null as \"stack\" | \"scratch\" | null,\n selectedStackId: null as string | null,\n stackAction: null as \"defaults\" | \"customize\" | null,\n selectedDomains: [] as string[],\n currentDomainIndex: 0,\n domainSelections: {} as Record<string, Record<string, string[]>>,\n focusedRow: 0,\n focusedCol: 0,\n currentRefineIndex: 0,\n skillSources: {} as Record<string, string>,\n refineAction: null as \"all-recommended\" | \"customize\" | null,\n showDescriptions: false,\n expertMode: false,\n installMode: \"local\" as \"plugin\" | \"local\",\n history: [] as WizardStep[],\n});\n\nexport const useWizardStore = create<WizardState>((set, get) => ({\n ...createInitialState(),\n\n setStep: (step) =>\n set((state) => ({\n step,\n history: [...state.history, state.step],\n // Reset focus when changing steps\n focusedRow: 0,\n focusedCol: 0,\n })),\n\n setApproach: (approach) => set({ approach }),\n\n selectStack: (stackId) => set({ selectedStackId: stackId }),\n\n setStackAction: (action) => set({ stackAction: action }),\n\n toggleDomain: (domain) =>\n set((state) => {\n const isSelected = state.selectedDomains.includes(domain);\n return {\n selectedDomains: isSelected\n ? state.selectedDomains.filter((d) => d !== domain)\n : [...state.selectedDomains, domain],\n };\n }),\n\n setDomainSelection: (domain, subcategory, technologies) =>\n set((state) => ({\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [subcategory]: technologies,\n },\n },\n })),\n\n toggleTechnology: (domain, subcategory, technology, exclusive) =>\n set((state) => {\n const currentSelections =\n state.domainSelections[domain]?.[subcategory] || [];\n const isSelected = currentSelections.includes(technology);\n\n let newSelections: string[];\n if (exclusive) {\n // For exclusive categories, toggle off if already selected, otherwise select only this one\n newSelections = isSelected ? [] : [technology];\n } else {\n // For multi-select categories, toggle the selection\n newSelections = isSelected\n ? currentSelections.filter((t) => t !== technology)\n : [...currentSelections, technology];\n }\n\n return {\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [subcategory]: newSelections,\n },\n },\n };\n }),\n\n setCurrentDomainIndex: (index) =>\n set({ currentDomainIndex: index, focusedRow: 0, focusedCol: 0 }),\n\n nextDomain: () => {\n const state = get();\n if (state.currentDomainIndex < state.selectedDomains.length - 1) {\n set({\n currentDomainIndex: state.currentDomainIndex + 1,\n focusedRow: 0,\n focusedCol: 0,\n });\n return true;\n }\n return false;\n },\n\n prevDomain: () => {\n const state = get();\n if (state.currentDomainIndex > 0) {\n set({\n currentDomainIndex: state.currentDomainIndex - 1,\n focusedRow: 0,\n focusedCol: 0,\n });\n return true;\n }\n return false;\n },\n\n setFocus: (row, col) => set({ focusedRow: row, focusedCol: col }),\n\n setRefineAction: (action) => set({ refineAction: action }),\n\n setSkillSource: (technology, skillId) =>\n set((state) => ({\n skillSources: {\n ...state.skillSources,\n [technology]: skillId,\n },\n })),\n\n setCurrentRefineIndex: (index) => set({ currentRefineIndex: index }),\n\n toggleShowDescriptions: () =>\n set((state) => ({ showDescriptions: !state.showDescriptions })),\n\n toggleExpertMode: () => set((state) => ({ expertMode: !state.expertMode })),\n\n toggleInstallMode: () =>\n set((state) => ({\n installMode: state.installMode === \"plugin\" ? \"local\" : \"plugin\",\n })),\n\n goBack: () =>\n set((state) => {\n const history = [...state.history];\n const previousStep = history.pop();\n return {\n step: previousStep || \"approach\",\n history,\n focusedRow: 0,\n focusedCol: 0,\n };\n }),\n\n reset: () => set(createInitialState()),\n\n // ─────────────────────────────────────────────────────────────────\n // Computed getters\n // ─────────────────────────────────────────────────────────────────\n getAllSelectedTechnologies: () => {\n const state = get();\n const technologies: string[] = [];\n for (const domain of Object.keys(state.domainSelections)) {\n for (const subcategory of Object.keys(state.domainSelections[domain])) {\n technologies.push(...state.domainSelections[domain][subcategory]);\n }\n }\n return technologies;\n },\n\n getCurrentDomain: () => {\n const state = get();\n return state.selectedDomains[state.currentDomainIndex] || null;\n },\n\n getSelectedSkills: () => {\n const state = get();\n // Include preselected methodology skills plus resolved skill sources\n const skillIds: string[] = [...DEFAULT_PRESELECTED_SKILLS];\n for (const skillId of Object.values(state.skillSources)) {\n if (!skillIds.includes(skillId)) {\n skillIds.push(skillId);\n }\n }\n return skillIds;\n },\n}));\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/lib/plugin-manifest.ts"],"sourcesContent":["import path from \"path\";\nimport { ensureDir, writeFile } from \"../utils/fs\";\nimport { DEFAULT_VERSION } from \"../consts\";\nimport type { PluginManifest, PluginAuthor } from \"../../types\";\n\nconst DEFAULT_LICENSE = \"MIT\";\nconst PLUGIN_DIR_NAME = \".claude-plugin\";\nconst PLUGIN_MANIFEST_FILE = \"plugin.json\";\nconst SKILL_PLUGIN_PREFIX = \"skill-\";\n\nexport interface SkillPluginOptions {\n skillName: string;\n description?: string;\n author?: string;\n authorEmail?: string;\n version?: string;\n keywords?: string[];\n}\n\nexport interface StackPluginOptions {\n stackName: string;\n description?: string;\n author?: string;\n authorEmail?: string;\n version?: string;\n keywords?: string[];\n hasSkills?: boolean;\n hasAgents?: boolean;\n hasHooks?: boolean;\n}\n\nfunction buildAuthor(name?: string, email?: string): PluginAuthor | undefined {\n if (!name) {\n return undefined;\n }\n const author: PluginAuthor = { name };\n if (email) {\n author.email = email;\n }\n return author;\n}\n\nexport function generateSkillPluginManifest(\n options: SkillPluginOptions,\n): PluginManifest {\n const manifest: PluginManifest = {\n name: `${SKILL_PLUGIN_PREFIX}${options.skillName}`,\n version: options.version ?? DEFAULT_VERSION,\n license: DEFAULT_LICENSE,\n skills: \"./skills/\",\n };\n\n if (options.description) {\n manifest.description = options.description;\n }\n\n const author = buildAuthor(options.author, options.authorEmail);\n if (author) {\n manifest.author = author;\n }\n\n if (options.keywords && options.keywords.length > 0) {\n manifest.keywords = options.keywords;\n }\n\n return manifest;\n}\n\nexport function generateStackPluginManifest(\n options: StackPluginOptions,\n): PluginManifest {\n const manifest: PluginManifest = {\n name: options.stackName,\n version: options.version ?? DEFAULT_VERSION,\n license: DEFAULT_LICENSE,\n };\n\n if (options.hasSkills) {\n manifest.skills = \"./skills/\";\n }\n\n if (options.description) {\n manifest.description = options.description;\n }\n\n const author = buildAuthor(options.author, options.authorEmail);\n if (author) {\n manifest.author = author;\n }\n\n if (options.keywords && options.keywords.length > 0) {\n manifest.keywords = options.keywords;\n }\n\n // Note: Claude Code plugins don't support agents field in manifest\n // Agents are discovered from ./agents/ directory automatically\n\n if (options.hasHooks) {\n manifest.hooks = \"./hooks/hooks.json\";\n }\n\n return manifest;\n}\n\nexport async function writePluginManifest(\n outputDir: string,\n manifest: PluginManifest,\n): Promise<string> {\n const pluginDir = path.join(outputDir, PLUGIN_DIR_NAME);\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);\n\n await ensureDir(pluginDir);\n\n const content = JSON.stringify(manifest, null, 2);\n await writeFile(manifestPath, content);\n\n return manifestPath;\n}\n\nexport function getPluginDir(outputDir: string): string {\n return path.join(outputDir, PLUGIN_DIR_NAME);\n}\n\nexport function getPluginManifestPath(outputDir: string): string {\n return path.join(outputDir, PLUGIN_DIR_NAME, PLUGIN_MANIFEST_FILE);\n}\n"],"mappings":";;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAKjB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAuB5B,SAAS,YAAY,MAAe,OAA0C;AAC5E,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,QAAM,SAAuB,EAAE,KAAK;AACpC,MAAI,OAAO;AACT,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAEO,SAAS,4BACd,SACgB;AAChB,QAAM,WAA2B;AAAA,IAC/B,MAAM,GAAG,mBAAmB,GAAG,QAAQ,SAAS;AAAA,IAChD,SAAS,QAAQ,WAAW;AAAA,IAC5B,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AAEA,MAAI,QAAQ,aAAa;AACvB,aAAS,cAAc,QAAQ;AAAA,EACjC;AAEA,QAAM,SAAS,YAAY,QAAQ,QAAQ,QAAQ,WAAW;AAC9D,MAAI,QAAQ;AACV,aAAS,SAAS;AAAA,EACpB;AAEA,MAAI,QAAQ,YAAY,QAAQ,SAAS,SAAS,GAAG;AACnD,aAAS,WAAW,QAAQ;AAAA,EAC9B;AAEA,SAAO;AACT;AAEO,SAAS,4BACd,SACgB;AAChB,QAAM,WAA2B;AAAA,IAC/B,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ,WAAW;AAAA,IAC5B,SAAS;AAAA,EACX;AAEA,MAAI,QAAQ,WAAW;AACrB,aAAS,SAAS;AAAA,EACpB;AAEA,MAAI,QAAQ,aAAa;AACvB,aAAS,cAAc,QAAQ;AAAA,EACjC;AAEA,QAAM,SAAS,YAAY,QAAQ,QAAQ,QAAQ,WAAW;AAC9D,MAAI,QAAQ;AACV,aAAS,SAAS;AAAA,EACpB;AAEA,MAAI,QAAQ,YAAY,QAAQ,SAAS,SAAS,GAAG;AACnD,aAAS,WAAW,QAAQ;AAAA,EAC9B;AAKA,MAAI,QAAQ,UAAU;AACpB,aAAS,QAAQ;AAAA,EACnB;AAEA,SAAO;AACT;AAEA,eAAsB,oBACpB,WACA,UACiB;AACjB,QAAM,YAAY,KAAK,KAAK,WAAW,eAAe;AACtD,QAAM,eAAe,KAAK,KAAK,WAAW,oBAAoB;AAE9D,QAAM,UAAU,SAAS;AAEzB,QAAM,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC;AAChD,QAAM,UAAU,cAAc,OAAO;AAErC,SAAO;AACT;AAMO,SAAS,sBAAsB,WAA2B;AAC/D,SAAO,KAAK,KAAK,WAAW,iBAAiB,oBAAoB;AACnE;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/components/wizard/section-progress.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport interface SectionProgressProps {\n /** Section label (e.g., \"Domain\" or \"Skill\") */\n label: string;\n /** Current item name (e.g., \"Web\" or \"react\") */\n current: string;\n /** 1-based index */\n index: number;\n /** Total count */\n total: number;\n /** Next item name, or undefined if last */\n next?: string;\n}\n\nexport const SectionProgress: React.FC<SectionProgressProps> = ({\n label,\n current,\n index,\n total,\n next,\n}) => {\n const isLast = index === total;\n const rightText = isLast ? \"Last step\" : `Next: ${next}`;\n\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n marginBottom={1}\n >\n <Text>\n <Text bold>{label}:</Text> <Text color=\"cyan\">{current}</Text>\n </Text>\n <Text>\n <Text dimColor>\n [{index}/{total}]\n </Text>{\" \"}\n <Text dimColor={isLast}>{rightText}</Text>\n </Text>\n </Box>\n );\n};\n"],"mappings":";;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAiClB,SAA2B,KAA3B;AAlBD,IAAM,kBAAkD,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,SAAS,UAAU;AACzB,QAAM,YAAY,SAAS,cAAc,SAAS,IAAI;AAEtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,MAEd;AAAA,6BAAC,QACC;AAAA,+BAAC,QAAK,MAAI,MAAE;AAAA;AAAA,YAAM;AAAA,aAAC;AAAA,UAAO;AAAA,UAAC,oBAAC,QAAK,OAAM,QAAQ,mBAAQ;AAAA,WACzD;AAAA,QACA,qBAAC,QACC;AAAA,+BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,YACX;AAAA,YAAM;AAAA,YAAE;AAAA,YAAM;AAAA,aAClB;AAAA,UAAQ;AAAA,UACR,oBAAC,QAAK,UAAU,QAAS,qBAAU;AAAA,WACrC;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/utils/exec.ts"],"sourcesContent":["import { spawn } from \"child_process\";\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command and return the result\n */\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Install a plugin using the native claude CLI\n */\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Check if the claude CLI is available\n */\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport interface MarketplaceInfo {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n}\n\n/**\n * List configured marketplaces in Claude Code\n */\nexport async function claudePluginMarketplaceList(): Promise<\n MarketplaceInfo[]\n> {\n try {\n const result = await execCommand(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n {},\n );\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n return JSON.parse(result.stdout);\n } catch {\n // Returns empty array if claude CLI is not available or parsing fails\n return [];\n }\n}\n\n/**\n * Check if a marketplace with the given name exists\n */\nexport async function claudePluginMarketplaceExists(\n name: string,\n): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\n/**\n * Add a marketplace to Claude Code from a GitHub repository\n */\nexport async function claudePluginMarketplaceAdd(\n githubRepo: string,\n name: string,\n): Promise<void> {\n const args = [\"plugin\", \"marketplace\", \"add\", githubRepo, \"--name\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(\n `Failed to add marketplace: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n );\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Uninstall a plugin using the native claude CLI\n */\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (\n errorMessage.includes(\"not installed\") ||\n errorMessage.includes(\"not found\")\n ) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/lib/versioning.ts"],"sourcesContent":["import { createHash } from \"crypto\";\nimport path from \"path\";\nimport { stringify as stringifyYaml, parse as parseYaml } from \"yaml\";\nimport { readFile, writeFile, glob, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\n\nconst HASH_PREFIX_LENGTH = 7;\n\nconst METADATA_FILE_NAME = \"metadata.yaml\";\n\nconst HASHABLE_FILES = [\"SKILL.md\", \"reference.md\"];\n\nconst HASHABLE_DIRS = [\"examples\", \"scripts\"];\n\ninterface VersionedMetadata {\n version: number;\n content_hash?: string;\n updated?: string;\n [key: string]: unknown;\n}\n\nexport interface VersionCheckResult {\n skillPath: string;\n previousVersion: number;\n newVersion: number;\n previousHash: string | undefined;\n newHash: string;\n changed: boolean;\n}\n\nexport function getCurrentDate(): string {\n return new Date().toISOString().split(\"T\")[0];\n}\n\nexport function hashString(content: string): string {\n const hash = createHash(\"sha256\");\n hash.update(content);\n return hash.digest(\"hex\").slice(0, HASH_PREFIX_LENGTH);\n}\n\nexport async function hashFile(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return hashString(content);\n}\n\nexport async function hashSkillFolder(skillPath: string): Promise<string> {\n const contents: string[] = [];\n\n for (const fileName of HASHABLE_FILES) {\n const filePath = path.join(skillPath, fileName);\n if (await fileExists(filePath)) {\n const content = await readFile(filePath);\n contents.push(`${fileName}:${content}`);\n }\n }\n\n for (const dirName of HASHABLE_DIRS) {\n const dirPath = path.join(skillPath, dirName);\n if (await fileExists(dirPath)) {\n const files = await glob(\"**/*\", dirPath);\n for (const file of files.sort()) {\n const filePath = path.join(dirPath, file);\n const content = await readFile(filePath);\n contents.push(`${dirName}/${file}:${content}`);\n }\n }\n }\n\n const combined = contents.join(\"\\n---\\n\");\n return hashString(combined);\n}\n\nasync function readMetadata(\n skillPath: string,\n): Promise<{ metadata: VersionedMetadata; schemaComment: string }> {\n const metadataPath = path.join(skillPath, METADATA_FILE_NAME);\n const rawContent = await readFile(metadataPath);\n\n const lines = rawContent.split(\"\\n\");\n let schemaComment = \"\";\n let yamlContent = rawContent;\n\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n schemaComment = lines[0] + \"\\n\";\n yamlContent = lines.slice(1).join(\"\\n\");\n }\n\n const metadata = parseYaml(yamlContent) as VersionedMetadata;\n return { metadata, schemaComment };\n}\n\nasync function writeMetadata(\n skillPath: string,\n metadata: VersionedMetadata,\n schemaComment: string,\n): Promise<void> {\n const metadataPath = path.join(skillPath, METADATA_FILE_NAME);\n const yamlContent = stringifyYaml(metadata, { lineWidth: 0 });\n await writeFile(metadataPath, schemaComment + yamlContent);\n}\n\nexport async function versionSkill(\n skillPath: string,\n): Promise<VersionCheckResult> {\n const newHash = await hashSkillFolder(skillPath);\n\n const { metadata, schemaComment } = await readMetadata(skillPath);\n const previousVersion = metadata.version;\n const previousHash = metadata.content_hash;\n\n const changed = previousHash !== newHash;\n\n if (changed) {\n metadata.version = previousVersion + 1;\n metadata.content_hash = newHash;\n metadata.updated = getCurrentDate();\n\n await writeMetadata(skillPath, metadata, schemaComment);\n\n verbose(\n ` Version bumped: ${skillPath} (v${previousVersion} -> v${metadata.version})`,\n );\n }\n\n return {\n skillPath,\n previousVersion,\n newVersion: changed ? previousVersion + 1 : previousVersion,\n previousHash,\n newHash,\n changed,\n };\n}\n\nexport async function versionAllSkills(\n skillsDir: string,\n): Promise<VersionCheckResult[]> {\n const results: VersionCheckResult[] = [];\n\n const metadataFiles = await glob(\"**/metadata.yaml\", skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillPath = path.join(skillsDir, path.dirname(metadataFile));\n\n try {\n const result = await versionSkill(skillPath);\n results.push(result);\n } catch (error) {\n console.warn(\n ` Warning: Failed to version skill at ${skillPath}: ${error}`,\n );\n }\n }\n\n return results;\n}\n\nexport function printVersionResults(results: VersionCheckResult[]): void {\n const changed = results.filter((r) => r.changed);\n const unchanged = results.filter((r) => !r.changed);\n\n if (changed.length > 0) {\n console.log(`\\n Version Updates:`);\n for (const result of changed) {\n const skillName = path.basename(result.skillPath);\n console.log(\n ` ✓ ${skillName}: v${result.previousVersion} -> v${result.newVersion}`,\n );\n }\n }\n\n console.log(\n `\\n Summary: ${changed.length} updated, ${unchanged.length} unchanged`,\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA;AAAA,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,aAAa,eAAe,SAAS,iBAAiB;AAI/D,IAAM,qBAAqB;AAI3B,IAAM,iBAAiB,CAAC,YAAY,cAAc;AAElD,IAAM,gBAAgB,CAAC,YAAY,SAAS;AAsBrC,SAAS,WAAW,SAAyB;AAClD,QAAM,OAAO,WAAW,QAAQ;AAChC,OAAK,OAAO,OAAO;AACnB,SAAO,KAAK,OAAO,KAAK,EAAE,MAAM,GAAG,kBAAkB;AACvD;AAEA,eAAsB,SAAS,UAAmC;AAChE,QAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,SAAO,WAAW,OAAO;AAC3B;AAEA,eAAsB,gBAAgB,WAAoC;AACxE,QAAM,WAAqB,CAAC;AAE5B,aAAW,YAAY,gBAAgB;AACrC,UAAM,WAAW,KAAK,KAAK,WAAW,QAAQ;AAC9C,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC9B,YAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,eAAS,KAAK,GAAG,QAAQ,IAAI,OAAO,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,aAAW,WAAW,eAAe;AACnC,UAAM,UAAU,KAAK,KAAK,WAAW,OAAO;AAC5C,QAAI,MAAM,WAAW,OAAO,GAAG;AAC7B,YAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO;AACxC,iBAAW,QAAQ,MAAM,KAAK,GAAG;AAC/B,cAAM,WAAW,KAAK,KAAK,SAAS,IAAI;AACxC,cAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,iBAAS,KAAK,GAAG,OAAO,IAAI,IAAI,IAAI,OAAO,EAAE;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,KAAK,SAAS;AACxC,SAAO,WAAW,QAAQ;AAC5B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/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(\n filePath: string,\n fallback = \"\",\n): 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(\n filePath: string,\n content: string,\n): 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,iBACpB,UACA,WAAW,IACM;AACjB,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,UACpB,UACA,SACe;AACf,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 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/lib/project-config.ts"],"sourcesContent":["import path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport type {\n ProjectConfig,\n StackConfig,\n SkillAssignment,\n SkillEntry,\n AgentSkillConfig,\n ValidationResult,\n CustomAgentConfig,\n} from \"../../types\";\n\nconst CONFIG_PATH = \".claude/config.yaml\";\n\nexport interface LoadedProjectConfig {\n config: ProjectConfig;\n configPath: string;\n /** true if was StackConfig format (legacy) */\n isLegacy: boolean;\n}\n\n/**\n * Load project config from .claude/config.yaml\n */\nexport async function loadProjectConfig(\n projectDir: string,\n): Promise<LoadedProjectConfig | null> {\n const configPath = path.join(projectDir, CONFIG_PATH);\n\n if (!(await fileExists(configPath))) {\n verbose(`Project config not found at ${configPath}`);\n return null;\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n\n if (!parsed || typeof parsed !== \"object\") {\n verbose(`Invalid project config structure at ${configPath}`);\n return null;\n }\n\n // Detect if this is legacy StackConfig format\n const isLegacy = isLegacyStackConfig(parsed);\n\n if (isLegacy) {\n verbose(`Detected legacy StackConfig format at ${configPath}`);\n const normalized = normalizeStackConfig(parsed as StackConfig);\n return {\n config: normalized,\n configPath,\n isLegacy: true,\n };\n }\n\n verbose(`Loaded project config from ${configPath}`);\n return {\n config: parsed as ProjectConfig,\n configPath,\n isLegacy: false,\n };\n } catch (error) {\n verbose(`Failed to parse project config: ${error}`);\n return null;\n }\n}\n\n/**\n * Check if a config object is in legacy StackConfig format.\n * Detection logic:\n * - If version is semver (e.g., \"1.0.0\") -> legacy\n * - If version is \"1\" -> new format\n * - If has 'id' field -> legacy\n * - If has 'created' or 'updated' fields -> legacy\n */\nexport function isLegacyStackConfig(config: unknown): boolean {\n if (!config || typeof config !== \"object\") return false;\n\n const obj = config as Record<string, unknown>;\n\n // If version looks like semver (x.y.z), it's legacy\n if (typeof obj.version === \"string\" && obj.version.includes(\".\")) {\n return true;\n }\n\n // If has legacy-only fields, it's legacy\n if (\n obj.id !== undefined ||\n obj.created !== undefined ||\n obj.updated !== undefined\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Normalize StackConfig to ProjectConfig (for backward compatibility)\n */\nexport function normalizeStackConfig(stackConfig: StackConfig): ProjectConfig {\n const config: ProjectConfig = {\n name: stackConfig.name,\n agents: stackConfig.agents,\n };\n\n // Copy optional fields\n if (stackConfig.description) {\n config.description = stackConfig.description;\n }\n\n if (stackConfig.skills && stackConfig.skills.length > 0) {\n config.skills = stackConfig.skills;\n }\n\n if (stackConfig.agent_skills) {\n // StackConfig agent_skills is always categorized format\n config.agent_skills = stackConfig.agent_skills;\n }\n\n if (stackConfig.hooks) {\n config.hooks = stackConfig.hooks;\n }\n\n if (stackConfig.author) {\n config.author = stackConfig.author;\n }\n\n if (stackConfig.framework) {\n config.framework = stackConfig.framework;\n }\n\n if (stackConfig.philosophy) {\n config.philosophy = stackConfig.philosophy;\n }\n\n if (stackConfig.principles && stackConfig.principles.length > 0) {\n config.principles = stackConfig.principles;\n }\n\n if (stackConfig.tags && stackConfig.tags.length > 0) {\n config.tags = stackConfig.tags;\n }\n\n return config;\n}\n\n/**\n * Validate project config structure.\n * Returns validation result with errors and warnings.\n */\nexport function validateProjectConfig(config: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!config || typeof config !== \"object\") {\n return { valid: false, errors: [\"Config must be an object\"], warnings: [] };\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: name\n if (!c.name || typeof c.name !== \"string\") {\n errors.push(\"name is required and must be a string\");\n }\n\n // Required: agents (for compilation)\n if (!c.agents || !Array.isArray(c.agents)) {\n errors.push(\"agents is required and must be an array\");\n } else {\n for (const agent of c.agents) {\n if (typeof agent !== \"string\") {\n errors.push(`agents must contain strings, found: ${typeof agent}`);\n }\n }\n }\n\n // Optional: version\n if (c.version !== undefined && c.version !== \"1\") {\n errors.push('version must be \"1\" (or omitted for default)');\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(\"skills must be an array\");\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(skillError);\n }\n }\n }\n }\n\n // Optional: agent_skills\n if (c.agent_skills !== undefined) {\n if (typeof c.agent_skills !== \"object\" || c.agent_skills === null) {\n errors.push(\"agent_skills must be an object\");\n } else {\n for (const [agentName, agentSkills] of Object.entries(c.agent_skills)) {\n const agentSkillsError = validateAgentSkillConfig(\n agentName,\n agentSkills,\n );\n if (agentSkillsError) {\n errors.push(agentSkillsError);\n }\n }\n }\n }\n\n // Optional: preload_patterns\n if (c.preload_patterns !== undefined) {\n if (typeof c.preload_patterns !== \"object\" || c.preload_patterns === null) {\n errors.push(\"preload_patterns must be an object\");\n } else {\n for (const [agentName, patterns] of Object.entries(c.preload_patterns)) {\n if (!Array.isArray(patterns)) {\n errors.push(\n `preload_patterns.${agentName} must be an array of strings`,\n );\n } else {\n for (const pattern of patterns) {\n if (typeof pattern !== \"string\") {\n errors.push(\n `preload_patterns.${agentName} must contain only strings`,\n );\n break;\n }\n }\n }\n }\n }\n }\n\n // Optional: custom_agents\n if (c.custom_agents !== undefined) {\n const customAgentsErrors = validateCustomAgents(c.custom_agents, c.agents);\n errors.push(...customAgentsErrors);\n }\n\n // Warnings for deprecated patterns\n if (c.id !== undefined) {\n warnings.push(\"id field is deprecated in project config\");\n }\n if (c.created !== undefined) {\n warnings.push(\"created field is deprecated in project config\");\n }\n if (c.updated !== undefined) {\n warnings.push(\"updated field is deprecated in project config\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/** Maximum number of custom agents allowed per project */\nconst MAX_CUSTOM_AGENTS = 20;\n\n/** Valid model values for custom agents */\nconst VALID_MODELS = [\"sonnet\", \"opus\", \"haiku\", \"inherit\"];\n\n/** Valid permission modes for custom agents */\nconst VALID_PERMISSION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"dontAsk\",\n \"bypassPermissions\",\n \"plan\",\n \"delegate\",\n];\n\n/**\n * Validate custom_agents section of config\n */\nfunction validateCustomAgents(\n customAgents: unknown,\n agents: unknown,\n): string[] {\n const errors: string[] = [];\n\n if (typeof customAgents !== \"object\" || customAgents === null) {\n errors.push(\"custom_agents must be an object\");\n return errors;\n }\n\n const customAgentEntries = Object.entries(customAgents);\n\n // Check maximum limit\n if (customAgentEntries.length > MAX_CUSTOM_AGENTS) {\n errors.push(\n `custom_agents cannot exceed ${MAX_CUSTOM_AGENTS} agents (found ${customAgentEntries.length})`,\n );\n }\n\n // Collect custom agent names for circular reference check\n const customAgentNames = new Set(customAgentEntries.map(([name]) => name));\n\n for (const [agentName, agentConfig] of customAgentEntries) {\n const agentErrors = validateCustomAgentConfig(\n agentName,\n agentConfig,\n customAgentNames,\n );\n errors.push(...agentErrors);\n }\n\n return errors;\n}\n\n/**\n * Validate a single custom agent configuration\n */\nfunction validateCustomAgentConfig(\n agentName: string,\n config: unknown,\n customAgentNames: Set<string>,\n): string[] {\n const errors: string[] = [];\n const prefix = `custom_agents.${agentName}`;\n\n if (typeof config !== \"object\" || config === null) {\n errors.push(`${prefix} must be an object`);\n return errors;\n }\n\n const c = config as Record<string, unknown>;\n\n // Required: title\n if (!c.title || typeof c.title !== \"string\") {\n errors.push(`${prefix}.title is required and must be a string`);\n }\n\n // Required: description\n if (!c.description || typeof c.description !== \"string\") {\n errors.push(`${prefix}.description is required and must be a string`);\n }\n\n // Optional: extends\n if (c.extends !== undefined) {\n if (typeof c.extends !== \"string\") {\n errors.push(`${prefix}.extends must be a string`);\n } else if (customAgentNames.has(c.extends)) {\n // Custom agents cannot extend other custom agents\n errors.push(\n `${prefix}.extends cannot reference another custom agent \"${c.extends}\"`,\n );\n }\n }\n\n // Optional: model\n if (c.model !== undefined) {\n if (typeof c.model !== \"string\" || !VALID_MODELS.includes(c.model)) {\n errors.push(`${prefix}.model must be one of: ${VALID_MODELS.join(\", \")}`);\n }\n }\n\n // Optional: tools\n if (c.tools !== undefined) {\n if (!Array.isArray(c.tools)) {\n errors.push(`${prefix}.tools must be an array`);\n } else {\n for (const tool of c.tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: disallowed_tools\n if (c.disallowed_tools !== undefined) {\n if (!Array.isArray(c.disallowed_tools)) {\n errors.push(`${prefix}.disallowed_tools must be an array`);\n } else {\n for (const tool of c.disallowed_tools) {\n if (typeof tool !== \"string\") {\n errors.push(`${prefix}.disallowed_tools must contain only strings`);\n break;\n }\n }\n }\n }\n\n // Optional: permission_mode\n if (c.permission_mode !== undefined) {\n if (\n typeof c.permission_mode !== \"string\" ||\n !VALID_PERMISSION_MODES.includes(c.permission_mode)\n ) {\n errors.push(\n `${prefix}.permission_mode must be one of: ${VALID_PERMISSION_MODES.join(\", \")}`,\n );\n }\n }\n\n // Optional: skills\n if (c.skills !== undefined) {\n if (!Array.isArray(c.skills)) {\n errors.push(`${prefix}.skills must be an array`);\n } else {\n for (const skill of c.skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n errors.push(`${prefix}.skills: ${skillError}`);\n }\n }\n }\n }\n\n // Optional: hooks\n if (c.hooks !== undefined) {\n if (typeof c.hooks !== \"object\" || c.hooks === null) {\n errors.push(`${prefix}.hooks must be an object`);\n }\n // Note: Detailed hook validation could be added later if needed\n }\n\n return errors;\n}\n\n/**\n * Validate a single skill entry\n */\nfunction validateSkillEntry(skill: unknown): string | null {\n if (typeof skill === \"string\") {\n return null; // String skill IDs are valid\n }\n\n if (typeof skill !== \"object\" || skill === null) {\n return \"skills must be strings or objects\";\n }\n\n const s = skill as Record<string, unknown>;\n\n if (!s.id || typeof s.id !== \"string\") {\n return \"skill object must have an id string\";\n }\n\n if (s.local === true && !s.path) {\n return `local skill \"${s.id}\" must have a path`;\n }\n\n if (s.preloaded !== undefined && typeof s.preloaded !== \"boolean\") {\n return `skill \"${s.id}\" preloaded must be a boolean`;\n }\n\n if (s.local !== undefined && typeof s.local !== \"boolean\") {\n return `skill \"${s.id}\" local must be a boolean`;\n }\n\n if (s.path !== undefined && typeof s.path !== \"string\") {\n return `skill \"${s.id}\" path must be a string`;\n }\n\n return null;\n}\n\n/**\n * Validate agent skill config (can be simple list or categorized)\n */\nfunction validateAgentSkillConfig(\n agentName: string,\n agentSkills: unknown,\n): string | null {\n // Check if it's a simple list (array)\n if (Array.isArray(agentSkills)) {\n for (const skill of agentSkills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}: ${skillError}`;\n }\n }\n return null;\n }\n\n // Check if it's categorized (object with array values)\n if (typeof agentSkills === \"object\" && agentSkills !== null) {\n for (const [category, skills] of Object.entries(agentSkills)) {\n if (!Array.isArray(skills)) {\n return `agent_skills.${agentName}.${category} must be an array`;\n }\n for (const skill of skills) {\n const skillError = validateSkillEntry(skill);\n if (skillError) {\n return `agent_skills.${agentName}.${category}: ${skillError}`;\n }\n }\n }\n return null;\n }\n\n return `agent_skills.${agentName} must be an array or object`;\n}\n\n/**\n * Check if agent_skills value is in simple list format (array)\n */\nexport function isSimpleAgentSkills(value: unknown): value is SkillEntry[] {\n return Array.isArray(value);\n}\n\n/**\n * Normalize a skill entry to SkillAssignment\n */\nexport function normalizeSkillEntry(entry: SkillEntry): SkillAssignment {\n if (typeof entry === \"string\") {\n return { id: entry };\n }\n return entry;\n}\n\n/**\n * Normalize agent_skills to always be categorized format for internal use.\n * Simple lists are placed under an \"uncategorized\" key.\n */\nexport function normalizeAgentSkills(\n agentSkills: Record<string, AgentSkillConfig>,\n): Record<string, Record<string, SkillAssignment[]>> {\n const result: Record<string, Record<string, SkillAssignment[]>> = {};\n\n for (const [agentName, skills] of Object.entries(agentSkills)) {\n if (isSimpleAgentSkills(skills)) {\n // Simple list -> put under \"uncategorized\"\n result[agentName] = {\n uncategorized: skills.map(normalizeSkillEntry),\n };\n } else {\n // Already categorized -> normalize entries\n result[agentName] = {};\n for (const [category, categorySkills] of Object.entries(skills)) {\n result[agentName][category] = categorySkills.map(normalizeSkillEntry);\n }\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/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\n .replace(/:/g, \"-\")\n .replace(/[\\/]/g, \"-\")\n .replace(/--+/g, \"-\")\n .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(\n source: string,\n subdir?: string,\n): Promise<FetchResult> {\n const fullPath = subdir ? path.join(source, subdir) : source;\n const absolutePath = path.isAbsolute(fullPath)\n ? fullPath\n : 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(\n source: string,\n options: FetchOptions,\n): 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 await ensureDir(path.dirname(cacheDir));\n\n try {\n const result = await downloadTemplate(fullSource, {\n dir: cacheDir,\n force: forceRefresh,\n offline: false,\n preferOffline: !forceRefresh,\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(\n result.path,\n \".claude-plugin\",\n \"marketplace.json\",\n );\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":";;;;;;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AACjB,SAAS,wBAAwB;AAkB1B,SAAS,uBAAuB,QAAwB;AAC7D,SAAO,OACJ,QAAQ,MAAM,GAAG,EACjB,QAAQ,SAAS,GAAG,EACpB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,UAAU,EAAE;AACzB;AAEA,SAAS,YAAY,QAAwB;AAC3C,QAAM,YAAY,uBAAuB,MAAM;AAC/C,SAAO,KAAK,KAAK,WAAW,WAAW,SAAS;AAClD;AAEA,eAAsB,gBACpB,QACA,UAAwB,CAAC,GACH;AACtB,QAAM,EAAE,eAAe,OAAO,OAAO,IAAI;AAEzC,MAAI,cAAc,MAAM,GAAG;AACzB,WAAO,qBAAqB,QAAQ,MAAM;AAAA,EAC5C;AAEA,SAAO,sBAAsB,QAAQ,EAAE,cAAc,OAAO,CAAC;AAC/D;AAEA,eAAe,qBACb,QACA,QACsB;AACtB,QAAM,WAAW,SAAS,KAAK,KAAK,QAAQ,MAAM,IAAI;AACtD,QAAM,eAAe,KAAK,WAAW,QAAQ,IACzC,WACA,KAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AAExC,MAAI,CAAE,MAAM,gBAAgB,YAAY,GAAI;AAC1C,UAAM,IAAI,MAAM,2BAA2B,YAAY,EAAE;AAAA,EAC3D;AAEA,UAAQ,uBAAuB,YAAY,EAAE;AAE7C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW;AAAA,IACX;AAAA,EACF;AACF;AAEA,eAAe,sBACb,QACA,SACsB;AACtB,QAAM,EAAE,eAAe,OAAO,OAAO,IAAI;AACzC,QAAM,WAAW,YAAY,MAAM;AAEnC,QAAM,aAAa,SAAS,GAAG,MAAM,IAAI,MAAM,KAAK;AAEpD,UAAQ,yBAAyB,UAAU,EAAE;AAC7C,UAAQ,oBAAoB,QAAQ,EAAE;AAEtC,QAAM,UAAU,KAAK,QAAQ,QAAQ,CAAC;AAEtC,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB,YAAY;AAAA,MAChD,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,MACT,eAAe,CAAC;AAAA,IAClB,CAAC;AAED,YAAQ,kBAAkB,OAAO,GAAG,EAAE;AAEtC,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,WAAW;AAAA,MACX,QAAQ;AAAA,IACV;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,OAAO,MAAM;AAAA,EACpC;AACF;AAEA,SAAS,eAAe,OAAgB,QAAuB;AAC7D,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAErE,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,WAAW,GAAG;AAC5D,WAAO,IAAI;AAAA,MACT,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOjC;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,cAAc,GAAG;AAC/D,WAAO,IAAI;AAAA,MACT,gCAAgC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKxC;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,WAAW,GAAG;AAC5D,WAAO,IAAI;AAAA,MACT,qBAAqB,MAAM;AAAA;AAAA;AAAA;AAAA,IAG7B;AAAA,EACF;AAEA,MACE,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,SAAS,GAC1B;AACA,WAAO,IAAI;AAAA,MACT,2BAA2B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnC;AAAA,EACF;AAEA,SAAO,IAAI,MAAM,mBAAmB,MAAM,KAAK,OAAO,EAAE;AAC1D;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/lib/plugin-version.ts"],"sourcesContent":["import path from \"path\";\nimport { readFile, writeFile } from \"../utils/fs\";\nimport {\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n DEFAULT_VERSION,\n} from \"../consts\";\nimport type { PluginManifest } from \"../../types\";\n\nexport type VersionBumpType = \"major\" | \"minor\" | \"patch\";\n\nfunction parseVersion(version: string): [number, number, number] {\n const parts = version.split(\".\").map(Number);\n return [parts[0] || 1, parts[1] || 0, parts[2] || 0];\n}\n\nexport async function bumpPluginVersion(\n pluginDir: string,\n type: VersionBumpType,\n): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n\n const [major, minor, patch] = parseVersion(\n manifest.version || DEFAULT_VERSION,\n );\n\n let newVersion: string;\n switch (type) {\n case \"major\":\n newVersion = `${major + 1}.0.0`;\n break;\n case \"minor\":\n newVersion = `${major}.${minor + 1}.0`;\n break;\n case \"patch\":\n newVersion = `${major}.${minor}.${patch + 1}`;\n break;\n }\n\n manifest.version = newVersion;\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n\n return newVersion;\n}\n\nexport async function getPluginVersion(pluginDir: string): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n return manifest.version || DEFAULT_VERSION;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAWjB,SAAS,aAAa,SAA2C;AAC/D,QAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AAC3C,SAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AACrD;AAEA,eAAsB,kBACpB,WACA,MACiB;AACjB,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AAEnC,QAAM,CAAC,OAAO,OAAO,KAAK,IAAI;AAAA,IAC5B,SAAS,WAAW;AAAA,EACtB;AAEA,MAAI;AACJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,mBAAa,GAAG,QAAQ,CAAC;AACzB;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,QAAQ,CAAC;AAClC;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,KAAK,IAAI,QAAQ,CAAC;AAC3C;AAAA,EACJ;AAEA,WAAS,UAAU;AACnB,QAAM,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAE/D,SAAO;AACT;AAEA,eAAsB,iBAAiB,WAAoC;AACzE,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AACnC,SAAO,SAAS,WAAW;AAC7B;","names":[]}
@@ -1,330 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- init_esm_shims
4
- } from "./chunk-DHET7RCE.js";
5
-
6
- // src/cli-v2/components/wizard/category-grid.tsx
7
- init_esm_shims();
8
- import { useCallback, useEffect } from "react";
9
- import { Box, Text, useInput } from "ink";
10
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
- var SYMBOL_SELECTED = "\u25CF";
12
- var SYMBOL_UNSELECTED = "\u25CB";
13
- var SYMBOL_DISABLED = "\u2717";
14
- var SYMBOL_RECOMMENDED = "\u2B50";
15
- var SYMBOL_DISCOURAGED = "\u26A0";
16
- var SYMBOL_FOCUS = ">";
17
- var SYMBOL_REQUIRED = "*";
18
- var MIN_OPTION_WIDTH = 12;
19
- var getOptionSymbol = (option) => {
20
- if (option.state === "disabled") {
21
- return SYMBOL_DISABLED;
22
- }
23
- return option.selected ? SYMBOL_SELECTED : SYMBOL_UNSELECTED;
24
- };
25
- var getStateIndicator = (option) => {
26
- if (option.state === "recommended") {
27
- return SYMBOL_RECOMMENDED;
28
- }
29
- if (option.state === "discouraged") {
30
- return SYMBOL_DISCOURAGED;
31
- }
32
- return null;
33
- };
34
- var getSymbolColor = (option) => {
35
- if (option.state === "disabled") {
36
- return "gray";
37
- }
38
- if (option.selected) {
39
- return "green";
40
- }
41
- return void 0;
42
- };
43
- var getLabelColor = (option, isFocused) => {
44
- if (option.state === "disabled") {
45
- return "gray";
46
- }
47
- if (isFocused) {
48
- return "cyan";
49
- }
50
- if (option.state === "recommended") {
51
- return "green";
52
- }
53
- if (option.state === "discouraged") {
54
- return "yellow";
55
- }
56
- return void 0;
57
- };
58
- var sortOptions = (options, expertMode) => {
59
- if (expertMode) {
60
- return options;
61
- }
62
- const stateOrder = {
63
- recommended: 0,
64
- normal: 1,
65
- discouraged: 2,
66
- disabled: 3
67
- };
68
- return [...options].sort((a, b) => {
69
- return stateOrder[a.state] - stateOrder[b.state];
70
- });
71
- };
72
- var findNextValidOption = (options, currentIndex, direction, wrap = true) => {
73
- const length = options.length;
74
- if (length === 0) return currentIndex;
75
- let index = currentIndex;
76
- let attempts = 0;
77
- while (attempts < length) {
78
- index += direction;
79
- if (wrap) {
80
- if (index < 0) index = length - 1;
81
- if (index >= length) index = 0;
82
- } else {
83
- if (index < 0) index = 0;
84
- if (index >= length) index = length - 1;
85
- }
86
- if (options[index] && options[index].state !== "disabled") {
87
- return index;
88
- }
89
- attempts++;
90
- }
91
- return currentIndex;
92
- };
93
- var findValidStartColumn = (options) => {
94
- for (let i = 0; i < options.length; i++) {
95
- if (options[i] && options[i].state !== "disabled") {
96
- return i;
97
- }
98
- }
99
- return 0;
100
- };
101
- var HeaderRow = ({
102
- showDescriptions,
103
- expertMode
104
- }) => {
105
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", justifyContent: "flex-end", marginBottom: 1, gap: 2, children: [
106
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
107
- "[Tab] Show descriptions: ",
108
- showDescriptions ? "ON" : "OFF"
109
- ] }),
110
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
111
- "[e] Expert Mode: ",
112
- expertMode ? "ON" : "OFF"
113
- ] })
114
- ] });
115
- };
116
- var OptionCell = ({
117
- option,
118
- isFocused,
119
- showDescription
120
- }) => {
121
- const symbol = getOptionSymbol(option);
122
- const symbolColor = getSymbolColor(option);
123
- const labelColor = getLabelColor(option, isFocused);
124
- const stateIndicator = getStateIndicator(option);
125
- const isDimmed = option.state === "disabled" || option.state === "discouraged";
126
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", minWidth: MIN_OPTION_WIDTH, marginRight: 1, children: [
127
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
128
- /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: isFocused ? SYMBOL_FOCUS : " " }),
129
- /* @__PURE__ */ jsx(Text, { children: " " }),
130
- /* @__PURE__ */ jsx(
131
- Text,
132
- {
133
- color: symbolColor,
134
- dimColor: isDimmed && option.state === "discouraged",
135
- children: symbol
136
- }
137
- ),
138
- /* @__PURE__ */ jsx(Text, { children: " " }),
139
- /* @__PURE__ */ jsx(
140
- Text,
141
- {
142
- color: labelColor,
143
- dimColor: option.state === "disabled",
144
- bold: isFocused,
145
- strikethrough: option.state === "disabled",
146
- children: option.label
147
- }
148
- ),
149
- stateIndicator && /* @__PURE__ */ jsxs(Fragment, { children: [
150
- /* @__PURE__ */ jsx(Text, { children: " " }),
151
- /* @__PURE__ */ jsx(Text, { color: option.state === "recommended" ? "green" : "yellow", children: stateIndicator })
152
- ] })
153
- ] }),
154
- showDescription && option.stateReason && /* @__PURE__ */ jsx(Box, { marginLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: option.stateReason }) })
155
- ] });
156
- };
157
- var CategoryRowComponent = ({
158
- category,
159
- options,
160
- focusedCol,
161
- isRowFocused,
162
- showDescriptions
163
- }) => {
164
- return /* @__PURE__ */ jsxs(
165
- Box,
166
- {
167
- flexDirection: "row",
168
- alignItems: "flex-start",
169
- marginBottom: showDescriptions ? 1 : 0,
170
- children: [
171
- /* @__PURE__ */ jsx(Box, { minWidth: 16, marginRight: 2, children: /* @__PURE__ */ jsxs(Text, { bold: isRowFocused, color: isRowFocused ? "cyan" : void 0, children: [
172
- category.name,
173
- category.required && /* @__PURE__ */ jsxs(Text, { color: "red", children: [
174
- " ",
175
- SYMBOL_REQUIRED
176
- ] })
177
- ] }) }),
178
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", flexWrap: "wrap", children: options.map((option, index) => /* @__PURE__ */ jsx(
179
- OptionCell,
180
- {
181
- option,
182
- isFocused: isRowFocused && index === focusedCol,
183
- showDescription: showDescriptions
184
- },
185
- option.id
186
- )) }),
187
- !category.required && /* @__PURE__ */ jsx(Box, { marginLeft: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(optional)" }) })
188
- ]
189
- }
190
- );
191
- };
192
- var LegendRow = () => {
193
- return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
194
- "Legend: ",
195
- /* @__PURE__ */ jsx(Text, { color: "green", children: SYMBOL_SELECTED }),
196
- " selected",
197
- " ",
198
- /* @__PURE__ */ jsx(Text, { color: "green", children: SYMBOL_RECOMMENDED }),
199
- " recommended",
200
- " ",
201
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: SYMBOL_DISCOURAGED }),
202
- " discouraged",
203
- " ",
204
- /* @__PURE__ */ jsx(Text, { color: "gray", children: SYMBOL_DISABLED }),
205
- " disabled"
206
- ] }) });
207
- };
208
- var CategoryGrid = ({
209
- categories,
210
- focusedRow,
211
- focusedCol,
212
- showDescriptions,
213
- expertMode,
214
- onToggle,
215
- onFocusChange,
216
- onToggleDescriptions,
217
- onToggleExpertMode
218
- }) => {
219
- const processedCategories = categories.map((category) => ({
220
- ...category,
221
- sortedOptions: sortOptions(category.options, expertMode)
222
- }));
223
- const currentRow = processedCategories[focusedRow];
224
- const currentOptions = currentRow?.sortedOptions || [];
225
- useEffect(() => {
226
- if (!currentRow) return;
227
- const maxCol = currentOptions.length - 1;
228
- if (focusedCol > maxCol) {
229
- const newCol = Math.max(0, maxCol);
230
- onFocusChange(focusedRow, newCol);
231
- } else if (currentOptions[focusedCol]?.state === "disabled") {
232
- const validCol = findValidStartColumn(currentOptions);
233
- if (validCol !== focusedCol) {
234
- onFocusChange(focusedRow, validCol);
235
- }
236
- }
237
- }, [focusedRow, currentOptions, focusedCol, onFocusChange, currentRow]);
238
- useInput(
239
- useCallback(
240
- (input, key) => {
241
- if (key.tab) {
242
- onToggleDescriptions();
243
- return;
244
- }
245
- if (input === "e" || input === "E") {
246
- onToggleExpertMode();
247
- return;
248
- }
249
- if (input === " ") {
250
- const currentOption = currentOptions[focusedCol];
251
- if (currentOption && currentOption.state !== "disabled") {
252
- onToggle(currentRow.id, currentOption.id);
253
- }
254
- return;
255
- }
256
- const isLeft = key.leftArrow || input === "h";
257
- const isRight = key.rightArrow || input === "l";
258
- const isUp = key.upArrow || input === "k";
259
- const isDown = key.downArrow || input === "j";
260
- if (isLeft) {
261
- const newCol = findNextValidOption(
262
- currentOptions,
263
- focusedCol,
264
- -1,
265
- true
266
- );
267
- onFocusChange(focusedRow, newCol);
268
- } else if (isRight) {
269
- const newCol = findNextValidOption(
270
- currentOptions,
271
- focusedCol,
272
- 1,
273
- true
274
- );
275
- onFocusChange(focusedRow, newCol);
276
- } else if (isUp) {
277
- const newRow = focusedRow <= 0 ? processedCategories.length - 1 : focusedRow - 1;
278
- const newRowOptions = processedCategories[newRow]?.sortedOptions || [];
279
- let newCol = Math.min(focusedCol, newRowOptions.length - 1);
280
- if (newRowOptions[newCol]?.state === "disabled") {
281
- newCol = findValidStartColumn(newRowOptions);
282
- }
283
- onFocusChange(newRow, newCol);
284
- } else if (isDown) {
285
- const newRow = focusedRow >= processedCategories.length - 1 ? 0 : focusedRow + 1;
286
- const newRowOptions = processedCategories[newRow]?.sortedOptions || [];
287
- let newCol = Math.min(focusedCol, newRowOptions.length - 1);
288
- if (newRowOptions[newCol]?.state === "disabled") {
289
- newCol = findValidStartColumn(newRowOptions);
290
- }
291
- onFocusChange(newRow, newCol);
292
- }
293
- },
294
- [
295
- focusedRow,
296
- focusedCol,
297
- currentOptions,
298
- currentRow,
299
- processedCategories,
300
- onToggle,
301
- onFocusChange,
302
- onToggleDescriptions,
303
- onToggleExpertMode
304
- ]
305
- )
306
- );
307
- if (categories.length === 0) {
308
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No categories to display." }) });
309
- }
310
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
311
- /* @__PURE__ */ jsx(HeaderRow, { showDescriptions, expertMode }),
312
- processedCategories.map((category, rowIndex) => /* @__PURE__ */ jsx(
313
- CategoryRowComponent,
314
- {
315
- category,
316
- options: category.sortedOptions,
317
- focusedCol,
318
- isRowFocused: rowIndex === focusedRow,
319
- showDescriptions
320
- },
321
- category.id
322
- )),
323
- /* @__PURE__ */ jsx(LegendRow, {})
324
- ] });
325
- };
326
-
327
- export {
328
- CategoryGrid
329
- };
330
- //# sourceMappingURL=chunk-PPNTD5LO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-v2/components/wizard/category-grid.tsx"],"sourcesContent":["/**\n * CategoryGrid component - 2D grid selection for wizard Build step.\n *\n * Displays categories as rows with technology options as columns.\n * Supports keyboard navigation (arrows, vim keys) and visual states.\n *\n * Visual states:\n * - ● selected (green)\n * - ⭐ recommended (green text, shows hint)\n * - ⚠ discouraged (yellow/dim, shows warning)\n * - ✗ disabled (gray + strikethrough-like)\n * - ○ normal (white)\n * - > focus indicator (cyan/bold)\n */\nimport React, { useCallback, useEffect } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\n\n// =============================================================================\n// Types\n// =============================================================================\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}\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 */\n focusedRow: number;\n /** Focused column index */\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 /** Called when expert mode is toggled */\n onToggleExpertMode: () => void;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Symbol for selected option */\nconst SYMBOL_SELECTED = \"\\u25CF\"; // ●\n\n/** Symbol for unselected option */\nconst SYMBOL_UNSELECTED = \"\\u25CB\"; // ○\n\n/** Symbol for disabled option */\nconst SYMBOL_DISABLED = \"\\u2717\"; // ✗\n\n/** Symbol for recommended option */\nconst SYMBOL_RECOMMENDED = \"\\u2B50\"; // ⭐\n\n/** Symbol for discouraged option */\nconst SYMBOL_DISCOURAGED = \"\\u26A0\"; // ⚠\n\n/** Focus indicator */\nconst SYMBOL_FOCUS = \">\";\n\n/** Required indicator */\nconst SYMBOL_REQUIRED = \"*\";\n\n/** Minimum column width for option labels */\nconst MIN_OPTION_WIDTH = 12;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Get the visual symbol for an option based on its state and selection.\n */\nconst getOptionSymbol = (option: CategoryOption): string => {\n if (option.state === \"disabled\") {\n return SYMBOL_DISABLED;\n }\n return option.selected ? SYMBOL_SELECTED : SYMBOL_UNSELECTED;\n};\n\n/**\n * Get the state indicator symbol (if any) for an option.\n */\nconst getStateIndicator = (option: CategoryOption): string | null => {\n if (option.state === \"recommended\") {\n return SYMBOL_RECOMMENDED;\n }\n if (option.state === \"discouraged\") {\n return SYMBOL_DISCOURAGED;\n }\n return null;\n};\n\n/**\n * Get the color for the option symbol based on state and selection.\n */\nconst getSymbolColor = (option: CategoryOption): string | undefined => {\n if (option.state === \"disabled\") {\n return \"gray\";\n }\n if (option.selected) {\n return \"green\";\n }\n return undefined;\n};\n\n/**\n * Get the color for the option label based on state.\n */\nconst getLabelColor = (\n option: CategoryOption,\n isFocused: boolean,\n): string | undefined => {\n if (option.state === \"disabled\") {\n return \"gray\";\n }\n if (isFocused) {\n return \"cyan\";\n }\n if (option.state === \"recommended\") {\n return \"green\";\n }\n if (option.state === \"discouraged\") {\n return \"yellow\";\n }\n return undefined;\n};\n\n/**\n * Sort options based on state (recommended first, discouraged last).\n * In expert mode, returns options as-is.\n */\nconst sortOptions = (\n options: CategoryOption[],\n expertMode: boolean,\n): 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// Sub-Components\n// =============================================================================\n\ninterface HeaderRowProps {\n showDescriptions: boolean;\n expertMode: boolean;\n}\n\nconst HeaderRow: React.FC<HeaderRowProps> = ({\n showDescriptions,\n expertMode,\n}) => {\n return (\n <Box flexDirection=\"row\" justifyContent=\"flex-end\" marginBottom={1} gap={2}>\n <Text dimColor>\n [Tab] Show descriptions: {showDescriptions ? \"ON\" : \"OFF\"}\n </Text>\n <Text dimColor>[e] Expert Mode: {expertMode ? \"ON\" : \"OFF\"}</Text>\n </Box>\n );\n};\n\ninterface OptionCellProps {\n option: CategoryOption;\n isFocused: boolean;\n showDescription: boolean;\n}\n\nconst OptionCell: React.FC<OptionCellProps> = ({\n option,\n isFocused,\n showDescription,\n}) => {\n const symbol = getOptionSymbol(option);\n const symbolColor = getSymbolColor(option);\n const labelColor = getLabelColor(option, isFocused);\n const stateIndicator = getStateIndicator(option);\n const isDimmed =\n option.state === \"disabled\" || option.state === \"discouraged\";\n\n return (\n <Box flexDirection=\"column\" minWidth={MIN_OPTION_WIDTH} marginRight={1}>\n <Box flexDirection=\"row\">\n {/* Focus indicator */}\n <Text color=\"cyan\" bold>\n {isFocused ? SYMBOL_FOCUS : \" \"}\n </Text>\n <Text> </Text>\n\n {/* Selection symbol */}\n <Text\n color={symbolColor}\n dimColor={isDimmed && option.state === \"discouraged\"}\n >\n {symbol}\n </Text>\n <Text> </Text>\n\n {/* Label */}\n <Text\n color={labelColor}\n dimColor={option.state === \"disabled\"}\n bold={isFocused}\n strikethrough={option.state === \"disabled\"}\n >\n {option.label}\n </Text>\n\n {/* State indicator */}\n {stateIndicator && (\n <>\n <Text> </Text>\n <Text color={option.state === \"recommended\" ? \"green\" : \"yellow\"}>\n {stateIndicator}\n </Text>\n </>\n )}\n </Box>\n\n {/* Description/reason (shown when descriptions enabled) */}\n {showDescription && option.stateReason && (\n <Box marginLeft={4}>\n <Text dimColor wrap=\"truncate-end\">\n {option.stateReason}\n </Text>\n </Box>\n )}\n </Box>\n );\n};\n\ninterface CategoryRowComponentProps {\n category: CategoryRow;\n options: CategoryOption[];\n focusedCol: number;\n isRowFocused: boolean;\n showDescriptions: boolean;\n}\n\nconst CategoryRowComponent: React.FC<CategoryRowComponentProps> = ({\n category,\n options,\n focusedCol,\n isRowFocused,\n showDescriptions,\n}) => {\n return (\n <Box\n flexDirection=\"row\"\n alignItems=\"flex-start\"\n marginBottom={showDescriptions ? 1 : 0}\n >\n {/* Category name column */}\n <Box minWidth={16} marginRight={2}>\n <Text bold={isRowFocused} color={isRowFocused ? \"cyan\" : undefined}>\n {category.name}\n {category.required && <Text color=\"red\"> {SYMBOL_REQUIRED}</Text>}\n </Text>\n </Box>\n\n {/* Options */}\n <Box flexDirection=\"row\" flexWrap=\"wrap\">\n {options.map((option, index) => (\n <OptionCell\n key={option.id}\n option={option}\n isFocused={isRowFocused && index === focusedCol}\n showDescription={showDescriptions}\n />\n ))}\n </Box>\n\n {/* Optional indicator */}\n {!category.required && (\n <Box marginLeft={1}>\n <Text dimColor>(optional)</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nconst LegendRow: React.FC = () => {\n return (\n <Box marginTop={1}>\n <Text dimColor>\n Legend: <Text color=\"green\">{SYMBOL_SELECTED}</Text> selected{\" \"}\n <Text color=\"green\">{SYMBOL_RECOMMENDED}</Text> recommended{\" \"}\n <Text color=\"yellow\">{SYMBOL_DISCOURAGED}</Text> discouraged{\" \"}\n <Text color=\"gray\">{SYMBOL_DISABLED}</Text> disabled\n </Text>\n </Box>\n );\n};\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n focusedRow,\n focusedCol,\n showDescriptions,\n expertMode,\n onToggle,\n onFocusChange,\n onToggleDescriptions,\n onToggleExpertMode,\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\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 // 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 },\n ) => {\n // Toggle descriptions with Tab\n if (key.tab) {\n onToggleDescriptions();\n return;\n }\n\n // Toggle expert mode with 'e'\n if (input === \"e\" || input === \"E\") {\n onToggleExpertMode();\n return;\n }\n\n // Toggle selection with Space\n if (input === \" \") {\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 const newCol = findNextValidOption(\n currentOptions,\n focusedCol,\n -1,\n true,\n );\n onFocusChange(focusedRow, newCol);\n } else if (isRight) {\n const newCol = findNextValidOption(\n currentOptions,\n focusedCol,\n 1,\n true,\n );\n onFocusChange(focusedRow, newCol);\n } else if (isUp) {\n // Move to previous row\n const newRow =\n focusedRow <= 0 ? processedCategories.length - 1 : focusedRow - 1;\n const newRowOptions =\n 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 row\n const newRow =\n focusedRow >= processedCategories.length - 1 ? 0 : focusedRow + 1;\n const newRowOptions =\n 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 processedCategories,\n onToggle,\n onFocusChange,\n onToggleDescriptions,\n onToggleExpertMode,\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 {/* Header with toggles */}\n <HeaderRow showDescriptions={showDescriptions} expertMode={expertMode} />\n\n {/* Category rows */}\n {processedCategories.map((category, rowIndex) => (\n <CategoryRowComponent\n key={category.id}\n category={category}\n options={category.sortedOptions}\n focusedCol={focusedCol}\n isRowFocused={rowIndex === focusedRow}\n showDescriptions={showDescriptions}\n />\n ))}\n\n {/* Legend */}\n <LegendRow />\n </Box>\n );\n};\n"],"mappings":"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","names":[]}