@agents-inc/cli 0.32.1 → 0.35.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 (225) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +7 -7
  3. package/config/skills-matrix.yaml +10 -10
  4. package/config/stacks.yaml +9 -9
  5. package/dist/{chunk-IZZ4IIEG.js → chunk-5LPPIT6H.js} +4 -4
  6. package/dist/{chunk-Z4TWOP3H.js → chunk-5YNZJ5TP.js} +2 -2
  7. package/dist/chunk-AQQVSNUX.js +33 -0
  8. package/dist/chunk-AQQVSNUX.js.map +1 -0
  9. package/dist/{chunk-ODUOU55D.js → chunk-BLLXNFWP.js} +2 -2
  10. package/dist/{chunk-YND42IXK.js → chunk-BPD4VUAU.js} +12 -10
  11. package/dist/chunk-BPD4VUAU.js.map +1 -0
  12. package/dist/{chunk-4RAY5AOI.js → chunk-CEWNZQMH.js} +3 -3
  13. package/dist/{chunk-WEUVWHMA.js → chunk-CXWPUVA7.js} +16 -11
  14. package/dist/chunk-CXWPUVA7.js.map +1 -0
  15. package/dist/{chunk-R74PZWQS.js → chunk-GGHH3KR2.js} +5 -5
  16. package/dist/chunk-GGHH3KR2.js.map +1 -0
  17. package/dist/chunk-HTTPKSL6.js +31 -0
  18. package/dist/chunk-HTTPKSL6.js.map +1 -0
  19. package/dist/{chunk-A27LOC4Z.js → chunk-IG7CUREJ.js} +3 -3
  20. package/dist/{chunk-FJQRVFMB.js → chunk-JXMRTHDT.js} +2 -2
  21. package/dist/{chunk-JMVWYAHT.js → chunk-KUV24B5M.js} +4 -4
  22. package/dist/chunk-KUV24B5M.js.map +1 -0
  23. package/dist/{chunk-B2UBHA66.js → chunk-KWF6D7ZP.js} +38 -36
  24. package/dist/chunk-KWF6D7ZP.js.map +1 -0
  25. package/dist/{chunk-IYG2LAIM.js → chunk-LFHZBF6N.js} +5 -17
  26. package/dist/chunk-LFHZBF6N.js.map +1 -0
  27. package/dist/{chunk-SO22IQPY.js → chunk-MZB3GGOH.js} +2 -2
  28. package/dist/chunk-MZB3GGOH.js.map +1 -0
  29. package/dist/{chunk-W2ZSCZ2U.js → chunk-NJ775OJ4.js} +4 -4
  30. package/dist/chunk-NVQEHRJY.js +120 -0
  31. package/dist/chunk-NVQEHRJY.js.map +1 -0
  32. package/dist/{chunk-LGUI3PMO.js → chunk-OGJ7DFCL.js} +9 -9
  33. package/dist/chunk-OGJ7DFCL.js.map +1 -0
  34. package/dist/{chunk-3ZOIOVKT.js → chunk-OGXSTJP2.js} +4 -4
  35. package/dist/chunk-OGXSTJP2.js.map +1 -0
  36. package/dist/{chunk-BZN2Z5P7.js → chunk-OI4WBRC7.js} +12 -3
  37. package/dist/chunk-OI4WBRC7.js.map +1 -0
  38. package/dist/{chunk-OGJIZ6QH.js → chunk-OKILA27U.js} +122 -232
  39. package/dist/chunk-OKILA27U.js.map +1 -0
  40. package/dist/{chunk-PBEHPQLK.js → chunk-PKUIO2Z7.js} +57 -21
  41. package/dist/chunk-PKUIO2Z7.js.map +1 -0
  42. package/dist/{chunk-5PIKNCZX.js → chunk-U36YCEBK.js} +79 -39
  43. package/dist/chunk-U36YCEBK.js.map +1 -0
  44. package/dist/{chunk-OMV7TLWD.js → chunk-UFUQUFV6.js} +23 -107
  45. package/dist/chunk-UFUQUFV6.js.map +1 -0
  46. package/dist/{chunk-R3XFQKPG.js → chunk-VEZ2GZEK.js} +2 -2
  47. package/dist/{chunk-MM7NK5N2.js → chunk-WMVGRAFB.js} +2896 -2945
  48. package/dist/chunk-WMVGRAFB.js.map +1 -0
  49. package/dist/{chunk-UX2H2K2G.js → chunk-XNQJBQ5X.js} +2 -2
  50. package/dist/{chunk-EMJ2ZKS7.js → chunk-XYCN2GCV.js} +3 -3
  51. package/dist/{chunk-LAPCUV4D.js → chunk-YCS7GF6Y.js} +2 -4
  52. package/dist/chunk-YCS7GF6Y.js.map +1 -0
  53. package/dist/{chunk-UICL22RT.js → chunk-YIKBNGE3.js} +4 -4
  54. package/dist/{chunk-BZQBJP34.js → chunk-YN35L5NE.js} +2 -2
  55. package/dist/chunk-YN35L5NE.js.map +1 -0
  56. package/dist/{chunk-QPTOIZAT.js → chunk-YPJKOM42.js} +2 -2
  57. package/dist/{chunk-FZGYSLJL.js → chunk-ZE355C6C.js} +2 -2
  58. package/dist/commands/build/marketplace.js +3 -3
  59. package/dist/commands/build/plugins.js +5 -5
  60. package/dist/commands/build/stack.js +5 -5
  61. package/dist/commands/compile.js +20 -9
  62. package/dist/commands/compile.js.map +1 -1
  63. package/dist/commands/config/get.js +4 -4
  64. package/dist/commands/config/index.js +5 -5
  65. package/dist/commands/config/path.js +4 -4
  66. package/dist/commands/config/set-project.js +4 -4
  67. package/dist/commands/config/show.js +5 -5
  68. package/dist/commands/config/unset-project.js +4 -4
  69. package/dist/commands/diff.js +5 -5
  70. package/dist/commands/diff.js.map +1 -1
  71. package/dist/commands/doctor.js +7 -7
  72. package/dist/commands/doctor.js.map +1 -1
  73. package/dist/commands/edit.js +35 -32
  74. package/dist/commands/edit.js.map +1 -1
  75. package/dist/commands/eject.js +5 -5
  76. package/dist/commands/eject.js.map +1 -1
  77. package/dist/commands/import/skill.js +5 -5
  78. package/dist/commands/info.js +6 -6
  79. package/dist/commands/info.js.map +1 -1
  80. package/dist/commands/init.js +37 -41
  81. package/dist/commands/init.js.map +1 -1
  82. package/dist/commands/list.js +5 -5
  83. package/dist/commands/list.js.map +1 -1
  84. package/dist/commands/new/agent.js +5 -5
  85. package/dist/commands/new/skill.js +5 -5
  86. package/dist/commands/new/skill.js.map +1 -1
  87. package/dist/commands/outdated.js +5 -5
  88. package/dist/commands/outdated.js.map +1 -1
  89. package/dist/commands/search.js +7 -7
  90. package/dist/commands/uninstall.js +105 -28
  91. package/dist/commands/uninstall.js.map +1 -1
  92. package/dist/commands/update.js +7 -7
  93. package/dist/commands/update.js.map +1 -1
  94. package/dist/commands/validate.js +5 -5
  95. package/dist/commands/version/bump.js +4 -4
  96. package/dist/commands/version/index.js +4 -4
  97. package/dist/commands/version/set.js +4 -4
  98. package/dist/commands/version/show.js +4 -4
  99. package/dist/components/skill-search/skill-search.js +3 -3
  100. package/dist/components/wizard/category-grid.js +2 -2
  101. package/dist/components/wizard/category-grid.test.js +34 -66
  102. package/dist/components/wizard/category-grid.test.js.map +1 -1
  103. package/dist/components/wizard/domain-selection.js +5 -5
  104. package/dist/components/wizard/help-modal.js +2 -2
  105. package/dist/components/wizard/menu-item.js +2 -2
  106. package/dist/components/wizard/search-modal.js +3 -3
  107. package/dist/components/wizard/search-modal.test.js +3 -3
  108. package/dist/components/wizard/section-progress.js +2 -2
  109. package/dist/components/wizard/section-progress.test.js +2 -2
  110. package/dist/components/wizard/source-grid.js +4 -4
  111. package/dist/components/wizard/source-grid.test.js +4 -4
  112. package/dist/components/wizard/stack-selection.js +8 -8
  113. package/dist/components/wizard/step-build.js +8 -7
  114. package/dist/components/wizard/step-build.test.js +18 -17
  115. package/dist/components/wizard/step-build.test.js.map +1 -1
  116. package/dist/components/wizard/step-confirm.js +3 -3
  117. package/dist/components/wizard/step-confirm.test.js +6 -6
  118. package/dist/components/wizard/step-refine.js +2 -2
  119. package/dist/components/wizard/step-refine.test.js +2 -2
  120. package/dist/components/wizard/step-settings.js +6 -6
  121. package/dist/components/wizard/step-settings.test.js +13 -13
  122. package/dist/components/wizard/step-settings.test.js.map +1 -1
  123. package/dist/components/wizard/step-sources.js +10 -9
  124. package/dist/components/wizard/step-sources.test.js +11 -10
  125. package/dist/components/wizard/step-sources.test.js.map +1 -1
  126. package/dist/components/wizard/step-stack.js +10 -10
  127. package/dist/components/wizard/step-stack.test.js +19 -23
  128. package/dist/components/wizard/step-stack.test.js.map +1 -1
  129. package/dist/components/wizard/view-title.js +2 -2
  130. package/dist/components/wizard/wizard-layout.js +7 -7
  131. package/dist/components/wizard/wizard-tabs.js +2 -2
  132. package/dist/components/wizard/wizard-tabs.test.js +7 -8
  133. package/dist/components/wizard/wizard-tabs.test.js.map +1 -1
  134. package/dist/components/wizard/wizard.js +24 -23
  135. package/dist/config/skills-matrix.yaml +10 -10
  136. package/dist/config/stacks.yaml +9 -9
  137. package/dist/hooks/init.js +5 -3
  138. package/dist/hooks/init.js.map +1 -1
  139. package/dist/{source-manager-SBPPLOQQ.js → source-manager-PTK4P6BF.js} +4 -4
  140. package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
  141. package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
  142. package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
  143. package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
  144. package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
  145. package/dist/src/agents/meta/agent-summoner/critical-reminders.md +1 -1
  146. package/dist/src/agents/meta/agent-summoner/critical-requirements.md +1 -1
  147. package/dist/src/agents/meta/agent-summoner/examples.md +2 -2
  148. package/dist/src/agents/meta/agent-summoner/workflow.md +3 -3
  149. package/dist/src/agents/meta/documentor/agent.yaml +1 -1
  150. package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
  151. package/dist/src/agents/meta/skill-summoner/output-format.md +1 -1
  152. package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
  153. package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  154. package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  155. package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
  156. package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
  157. package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
  158. package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  159. package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  160. package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  161. package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
  162. package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
  163. package/dist/stores/wizard-store.js +4 -4
  164. package/dist/stores/wizard-store.test.js +5 -5
  165. package/package.json +8 -8
  166. package/src/agents/developer/api-developer/agent.yaml +1 -1
  167. package/src/agents/developer/cli-developer/agent.yaml +1 -1
  168. package/src/agents/developer/web-architecture/agent.yaml +1 -1
  169. package/src/agents/developer/web-developer/agent.yaml +1 -1
  170. package/src/agents/meta/agent-summoner/agent.yaml +1 -1
  171. package/src/agents/meta/agent-summoner/critical-reminders.md +1 -1
  172. package/src/agents/meta/agent-summoner/critical-requirements.md +1 -1
  173. package/src/agents/meta/agent-summoner/examples.md +2 -2
  174. package/src/agents/meta/agent-summoner/workflow.md +3 -3
  175. package/src/agents/meta/documentor/agent.yaml +1 -1
  176. package/src/agents/meta/skill-summoner/agent.yaml +1 -1
  177. package/src/agents/meta/skill-summoner/output-format.md +1 -1
  178. package/src/agents/migration/cli-migrator/agent.yaml +1 -1
  179. package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  180. package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  181. package/src/agents/planning/web-pm/agent.yaml +1 -1
  182. package/src/agents/researcher/api-researcher/agent.yaml +1 -1
  183. package/src/agents/researcher/web-researcher/agent.yaml +1 -1
  184. package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  185. package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  186. package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  187. package/src/agents/tester/cli-tester/agent.yaml +1 -1
  188. package/src/agents/tester/web-tester/agent.yaml +1 -1
  189. package/src/schemas/project-config.schema.json +3 -0
  190. package/src/schemas/project-source-config.schema.json +12 -0
  191. package/dist/chunk-3ZOIOVKT.js.map +0 -1
  192. package/dist/chunk-5PIKNCZX.js.map +0 -1
  193. package/dist/chunk-B2UBHA66.js.map +0 -1
  194. package/dist/chunk-BZN2Z5P7.js.map +0 -1
  195. package/dist/chunk-BZQBJP34.js.map +0 -1
  196. package/dist/chunk-H566H3MQ.js +0 -87
  197. package/dist/chunk-H566H3MQ.js.map +0 -1
  198. package/dist/chunk-IYG2LAIM.js.map +0 -1
  199. package/dist/chunk-JMVWYAHT.js.map +0 -1
  200. package/dist/chunk-LAPCUV4D.js.map +0 -1
  201. package/dist/chunk-LGUI3PMO.js.map +0 -1
  202. package/dist/chunk-MM7NK5N2.js.map +0 -1
  203. package/dist/chunk-O4D67NN7.js +0 -24
  204. package/dist/chunk-O4D67NN7.js.map +0 -1
  205. package/dist/chunk-OGJIZ6QH.js.map +0 -1
  206. package/dist/chunk-OMV7TLWD.js.map +0 -1
  207. package/dist/chunk-PBEHPQLK.js.map +0 -1
  208. package/dist/chunk-R74PZWQS.js.map +0 -1
  209. package/dist/chunk-SO22IQPY.js.map +0 -1
  210. package/dist/chunk-WEUVWHMA.js.map +0 -1
  211. package/dist/chunk-YND42IXK.js.map +0 -1
  212. /package/dist/{chunk-IZZ4IIEG.js.map → chunk-5LPPIT6H.js.map} +0 -0
  213. /package/dist/{chunk-Z4TWOP3H.js.map → chunk-5YNZJ5TP.js.map} +0 -0
  214. /package/dist/{chunk-ODUOU55D.js.map → chunk-BLLXNFWP.js.map} +0 -0
  215. /package/dist/{chunk-4RAY5AOI.js.map → chunk-CEWNZQMH.js.map} +0 -0
  216. /package/dist/{chunk-A27LOC4Z.js.map → chunk-IG7CUREJ.js.map} +0 -0
  217. /package/dist/{chunk-FJQRVFMB.js.map → chunk-JXMRTHDT.js.map} +0 -0
  218. /package/dist/{chunk-W2ZSCZ2U.js.map → chunk-NJ775OJ4.js.map} +0 -0
  219. /package/dist/{chunk-R3XFQKPG.js.map → chunk-VEZ2GZEK.js.map} +0 -0
  220. /package/dist/{chunk-UX2H2K2G.js.map → chunk-XNQJBQ5X.js.map} +0 -0
  221. /package/dist/{chunk-EMJ2ZKS7.js.map → chunk-XYCN2GCV.js.map} +0 -0
  222. /package/dist/{chunk-UICL22RT.js.map → chunk-YIKBNGE3.js.map} +0 -0
  223. /package/dist/{chunk-QPTOIZAT.js.map → chunk-YPJKOM42.js.map} +0 -0
  224. /package/dist/{chunk-FZGYSLJL.js.map → chunk-ZE355C6C.js.map} +0 -0
  225. /package/dist/{source-manager-SBPPLOQQ.js.map → source-manager-PTK4P6BF.js.map} +0 -0
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- CLI_COLORS
4
- } from "./chunk-LAPCUV4D.js";
5
- import {
6
- init_esm_shims
7
- } from "./chunk-DHET7RCE.js";
8
-
9
- // src/cli/components/wizard/view-title.tsx
10
- init_esm_shims();
11
- import { Text } from "ink";
12
- import { jsxs } from "react/jsx-runtime";
13
- var ViewTitle = ({ children }) => {
14
- return /* @__PURE__ */ jsxs(Text, { backgroundColor: CLI_COLORS.WARNING, bold: true, color: "#000", children: [
15
- " ",
16
- children,
17
- " "
18
- ] });
19
- };
20
-
21
- export {
22
- ViewTitle
23
- };
24
- //# sourceMappingURL=chunk-O4D67NN7.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/view-title.tsx"],"sourcesContent":["import React from \"react\";\nimport { Text } from \"ink\";\nimport { CLI_COLORS } from \"../../consts.js\";\n\ntype ViewTitleProps = {\n children: React.ReactNode;\n};\n\nexport const ViewTitle: React.FC<ViewTitleProps> = ({ children }) => {\n return (\n <Text backgroundColor={CLI_COLORS.WARNING} bold color=\"#000\">\n {\" \"}\n {children}{\" \"}\n </Text>\n );\n};\n"],"mappings":";;;;;;;;;AAAA;AACA,SAAS,YAAY;AASjB;AAFG,IAAM,YAAsC,CAAC,EAAE,SAAS,MAAM;AACnE,SACE,qBAAC,QAAK,iBAAiB,WAAW,SAAS,MAAI,MAAC,OAAM,QACnD;AAAA;AAAA,IACA;AAAA,IAAU;AAAA,KACb;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/category-grid.tsx","../src/cli/components/hooks/use-virtual-scroll.ts","../src/cli/components/hooks/use-category-grid-input.ts"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\n\nimport { Box, Text } from \"ink\";\nimport { sortBy } from \"remeda\";\n\nimport type { SkillId, Subcategory } from \"../../types/index.js\";\nimport { CLI_COLORS, SCROLL_VIEWPORT, UI_SYMBOLS } from \"../../consts.js\";\nimport { useVirtualScroll } from \"../hooks/use-virtual-scroll.js\";\nimport {\n findValidStartColumn,\n isSectionLocked,\n useCategoryGridInput,\n} from \"../hooks/use-category-grid-input.js\";\nimport { useFocusedListItem } from \"../hooks/use-focused-list-item.js\";\n\nexport type OptionState = \"normal\" | \"recommended\" | \"discouraged\" | \"disabled\";\n\nexport type CategoryOption = {\n id: SkillId;\n label: string;\n state: OptionState;\n stateReason?: string;\n selected: boolean;\n local?: boolean;\n installed?: boolean;\n};\n\nexport type CategoryRow = {\n id: Subcategory;\n displayName: string;\n required: boolean;\n exclusive: boolean;\n options: CategoryOption[];\n};\n\nexport type CategoryGridProps = {\n categories: CategoryRow[];\n showDescriptions: boolean;\n expertMode: boolean;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n /** Optional initial focus row (default: 0). Use with React `key` to reset. */\n defaultFocusedRow?: number;\n /** Optional initial focus col (default: 0). Use with React `key` to reset. */\n defaultFocusedCol?: number;\n /** Optional callback fired whenever the focused position changes */\n onFocusChange?: (row: number, col: number) => void;\n /** Available height in terminal rows for the category list. When undefined, all categories render. */\n availableHeight?: number;\n /** Terminal width in columns, used for tag wrapping estimation. */\n terminalWidth?: number;\n};\n\nconst SYMBOL_REQUIRED = \"*\";\n\n// Recommended first, discouraged last. Expert mode preserves original order.\nconst sortOptions = (options: CategoryOption[], expertMode: boolean): CategoryOption[] => {\n if (expertMode) {\n return options;\n }\n\n const stateOrder: Record<OptionState, number> = {\n recommended: 0,\n normal: 1,\n discouraged: 2,\n disabled: 3,\n };\n\n return sortBy([...options], (o) => stateOrder[o.state]);\n};\n\nconst findNextValidOption = (\n options: CategoryOption[],\n currentIndex: number,\n direction: 1 | -1,\n wrap = 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 if (index < 0) index = length - 1;\n if (index >= length) index = 0;\n } else {\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 return currentIndex;\n};\n\ntype SkillTagProps = {\n option: CategoryOption;\n isFocused: boolean;\n isLocked: boolean;\n};\n\nconst getStateSuffix = (state: OptionState, isLocked: boolean): string | null => {\n if (isLocked || state === \"disabled\") return \"(disabled)\";\n if (state === \"recommended\") return \"(recommended)\";\n if (state === \"discouraged\") return \"(discouraged)\";\n return null;\n};\n\nconst getStateSymbol = (option: CategoryOption, isLocked: boolean): string => {\n if (isLocked || option.state === \"disabled\") return UI_SYMBOLS.DISABLED;\n if (option.selected) return UI_SYMBOLS.SELECTED;\n if (option.state === \"discouraged\") return UI_SYMBOLS.DISCOURAGED;\n return UI_SYMBOLS.UNSELECTED;\n};\n\nconst SkillTag: React.FC<SkillTagProps> = ({ option, isFocused, isLocked }) => {\n const getColor = (): { text: string; border: string } => {\n if (isLocked || option.state === \"disabled\") {\n return {\n text: CLI_COLORS.NEUTRAL,\n border: CLI_COLORS.NEUTRAL,\n };\n }\n if (option.selected) {\n return {\n text: CLI_COLORS.PRIMARY,\n border: CLI_COLORS.PRIMARY,\n };\n }\n if (option.state === \"recommended\") {\n return {\n text: CLI_COLORS.UNFOCUSED,\n border: CLI_COLORS.NEUTRAL,\n };\n }\n if (option.state === \"discouraged\") {\n return {\n text: CLI_COLORS.WARNING,\n border: CLI_COLORS.WARNING,\n };\n }\n // Normal unselected: muted color to clearly contrast with selected (cyan) skills\n return {\n text: CLI_COLORS.NEUTRAL,\n border: CLI_COLORS.NEUTRAL,\n };\n };\n\n const isBold = isFocused || option.selected;\n const isDimmed = isLocked || option.state === \"disabled\";\n const isBorderDimmed = isDimmed || (!option.selected && !isFocused);\n const focusBorderColor = option.selected ? CLI_COLORS.PRIMARY : CLI_COLORS.UNFOCUSED;\n const colors = getColor();\n const stateSuffix = getStateSuffix(option.state, isLocked);\n const stateSymbol = getStateSymbol(option, isLocked);\n\n return (\n <Box\n marginRight={1}\n borderColor={isFocused ? focusBorderColor : colors.border}\n borderStyle=\"single\"\n borderDimColor={isBorderDimmed}\n >\n <Text color={colors.text} bold={isBold} dimColor={false}>\n {\" \"}\n {option.local && (\n <>\n <Text backgroundColor={CLI_COLORS.NEUTRAL}> L </Text>{\" \"}\n </>\n )}\n {option.installed && <Text dimColor>{UI_SYMBOLS.SELECTED} </Text>}\n {!option.installed && <Text dimColor={isDimmed}>{stateSymbol} </Text>}\n {option.label}\n {stateSuffix && <Text dimColor> {stateSuffix}</Text>}{\" \"}\n </Text>\n </Box>\n );\n};\n\ntype CategorySectionProps = {\n category: CategoryRow;\n options: CategoryOption[];\n isLocked: boolean;\n isFocused: boolean;\n focusedOptionIndex: number;\n showDescriptions: boolean;\n};\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n category,\n options,\n isLocked,\n isFocused,\n focusedOptionIndex,\n showDescriptions,\n}) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text dimColor={isLocked}>{category.displayName}</Text>\n {category.required && (\n <Text color={isLocked ? CLI_COLORS.NEUTRAL : CLI_COLORS.ERROR} dimColor={isLocked}>\n {\" \"}\n {SYMBOL_REQUIRED}\n </Text>\n )}\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {options.map((option, index) => (\n <Box key={option.id} flexDirection=\"column\">\n <SkillTag\n option={option}\n isFocused={isFocused && index === focusedOptionIndex && !isLocked}\n isLocked={isLocked}\n />\n {showDescriptions && option.stateReason && !isLocked && (\n <Box marginLeft={1} marginBottom={0}>\n <Text dimColor wrap=\"truncate-end\">\n {option.stateReason}\n </Text>\n </Box>\n )}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\n/**\n * Estimate the rendered height of a category section in terminal rows.\n *\n * Each category consists of:\n * - 1 line for the category name (+ margin-top)\n * - N lines for the skill tags (based on count and terminal width wrapping)\n *\n * Tag wrapping: skill tags use flexWrap=\"wrap\". Each tag is approximately\n * AVG_TAG_WIDTH chars wide. The number of rows is ceil(tags * tagWidth / terminalWidth).\n */\nconst estimateCategoryHeight = (category: ProcessedCategory, terminalWidth: number): number => {\n const { CATEGORY_NAME_LINES, AVG_TAG_WIDTH, CATEGORY_MARGIN_LINES } = SCROLL_VIEWPORT;\n const optionCount = category.sortedOptions.length;\n const tagsPerRow = Math.max(1, Math.floor(terminalWidth / AVG_TAG_WIDTH));\n const tagRows = Math.ceil(optionCount / tagsPerRow);\n return CATEGORY_NAME_LINES + tagRows + CATEGORY_MARGIN_LINES;\n};\n\ntype ScrollIndicatorProps = {\n count: number;\n direction: \"above\" | \"below\";\n};\n\nconst ScrollIndicator: React.FC<ScrollIndicatorProps> = ({ count, direction }) => {\n if (count === 0) return null;\n\n const arrow = direction === \"above\" ? UI_SYMBOLS.SCROLL_UP : UI_SYMBOLS.SCROLL_DOWN;\n const label = `${arrow} ${count} more ${count === 1 ? \"category\" : \"categories\"} ${direction}`;\n\n return (\n <Box paddingLeft={1} marginTop={direction === \"below\" ? 1 : 0}>\n <Text dimColor>{label}</Text>\n </Box>\n );\n};\n\nconst DEFAULT_TERMINAL_WIDTH = 80;\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n showDescriptions,\n expertMode,\n onToggle,\n onToggleDescriptions,\n defaultFocusedRow = 0,\n defaultFocusedCol = 0,\n onFocusChange,\n availableHeight,\n terminalWidth,\n}) => {\n const processedCategories = useMemo(\n () =>\n categories.map((category) => ({\n ...category,\n sortedOptions: sortOptions(category.options, expertMode),\n })),\n [categories, expertMode],\n );\n\n const getColCount = useCallback(\n (row: number): number => processedCategories[row]?.sortedOptions.length ?? 0,\n [processedCategories],\n );\n\n const isRowLocked = useCallback(\n (row: number): boolean => {\n const cat = processedCategories[row];\n return cat ? isSectionLocked(cat.id, categories) : false;\n },\n [processedCategories, categories],\n );\n\n const findValidCol = useCallback(\n (row: number, currentCol: number, direction: 1 | -1): number => {\n const options = processedCategories[row]?.sortedOptions || [];\n const catId = processedCategories[row]?.id;\n if (catId && isSectionLocked(catId, categories)) return currentCol;\n return findNextValidOption(options, currentCol, direction, true);\n },\n [processedCategories, categories],\n );\n\n const adjustCol = useCallback(\n (row: number, clampedCol: number): number => {\n const options = processedCategories[row]?.sortedOptions || [];\n if (options[clampedCol]?.state === \"disabled\") {\n return findValidStartColumn(options);\n }\n return clampedCol;\n },\n [processedCategories],\n );\n\n const { focusedRow, focusedCol, setFocused, moveFocus } = useFocusedListItem(\n processedCategories.length,\n getColCount,\n {\n wrap: true,\n isRowLocked,\n findValidCol,\n adjustCol,\n onChange: onFocusChange,\n initialRow: defaultFocusedRow,\n initialCol: defaultFocusedCol,\n },\n );\n\n useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleDescriptions,\n });\n\n const { visibleItems, startIndex, hiddenAbove, hiddenBelow, isScrollable } = useVirtualScroll({\n items: processedCategories,\n availableHeight: availableHeight ?? Infinity,\n focusedIndex: focusedRow,\n estimateItemHeight: estimateCategoryHeight,\n terminalWidth: terminalWidth ?? DEFAULT_TERMINAL_WIDTH,\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 {isScrollable && <ScrollIndicator count={hiddenAbove} direction=\"above\" />}\n\n {visibleItems.map((category, visibleIndex) => {\n const originalIndex = startIndex + visibleIndex;\n const isLocked = isSectionLocked(category.id, categories);\n\n return (\n <CategorySection\n key={category.id}\n category={category}\n options={category.sortedOptions}\n isLocked={isLocked}\n isFocused={originalIndex === focusedRow}\n focusedOptionIndex={focusedCol}\n showDescriptions={showDescriptions}\n />\n );\n })}\n\n {isScrollable && <ScrollIndicator count={hiddenBelow} direction=\"below\" />}\n </Box>\n );\n};\n","import { useMemo } from \"react\";\nimport { SCROLL_VIEWPORT } from \"../../consts.js\";\n\nexport type VirtualScrollOptions<T> = {\n /** All items to potentially display */\n items: T[];\n /** Maximum height in terminal rows for the scrollable area */\n availableHeight: number;\n /** Current focused item index (drives auto-scroll) */\n focusedIndex: number;\n /** Estimate the height of a single item in terminal rows */\n estimateItemHeight: (item: T, terminalWidth: number) => number;\n /** Current terminal width (for tag wrapping estimation) */\n terminalWidth: number;\n};\n\nexport type VirtualScrollResult<T> = {\n /** Items visible in the current viewport window */\n visibleItems: T[];\n /** Index of the first visible item in the original array */\n startIndex: number;\n /** Index past the last visible item in the original array */\n endIndex: number;\n /** Number of items hidden above the viewport */\n hiddenAbove: number;\n /** Number of items hidden below the viewport */\n hiddenBelow: number;\n /** Whether the content is scrollable (total items exceed viewport) */\n isScrollable: boolean;\n};\n\n/**\n * Pure computation for virtual scroll windowing.\n *\n * Computes a contiguous window of items that fits within `availableHeight`,\n * ensuring the `focusedIndex` item is always visible. When the focused item\n * moves outside the current window, the window shifts to include it.\n *\n * Height is estimated per-item via `estimateItemHeight` rather than measured\n * post-render, avoiding the chicken-and-egg measurement problem with Ink.\n */\nexport function computeVirtualScroll<T>({\n items,\n availableHeight,\n focusedIndex,\n estimateItemHeight,\n terminalWidth,\n}: VirtualScrollOptions<T>): VirtualScrollResult<T> {\n const totalItems = items.length;\n\n if (totalItems === 0) {\n return {\n visibleItems: [],\n startIndex: 0,\n endIndex: 0,\n hiddenAbove: 0,\n hiddenBelow: 0,\n isScrollable: false,\n };\n }\n\n // Compute heights for each item\n const heights = items.map((item) => estimateItemHeight(item, terminalWidth));\n const totalHeight = heights.reduce((sum, h) => sum + h, 0);\n\n // If everything fits, no scrolling needed\n if (totalHeight <= availableHeight) {\n return {\n visibleItems: items,\n startIndex: 0,\n endIndex: totalItems,\n hiddenAbove: 0,\n hiddenBelow: 0,\n isScrollable: false,\n };\n }\n\n // Reserve space for scroll indicators when content overflows\n const viewportHeight = Math.max(\n SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS,\n availableHeight - SCROLL_VIEWPORT.SCROLL_INDICATOR_HEIGHT * 2,\n );\n\n // Clamp focused index\n const safeFocused = Math.max(0, Math.min(focusedIndex, totalItems - 1));\n\n // Find a window that includes the focused item and fills the viewport.\n // Strategy: start from focused item and expand outward.\n let startIndex = safeFocused;\n let endIndex = safeFocused + 1;\n let usedHeight = heights[safeFocused] ?? 0;\n\n // Expand downward first\n while (endIndex < totalItems) {\n const nextHeight = heights[endIndex] ?? 0;\n if (usedHeight + nextHeight > viewportHeight) break;\n usedHeight += nextHeight;\n endIndex++;\n }\n\n // Expand upward with remaining space\n while (startIndex > 0) {\n const prevHeight = heights[startIndex - 1] ?? 0;\n if (usedHeight + prevHeight > viewportHeight) break;\n usedHeight += prevHeight;\n startIndex--;\n }\n\n // If we still have room after expanding up, try expanding down again\n while (endIndex < totalItems) {\n const nextHeight = heights[endIndex] ?? 0;\n if (usedHeight + nextHeight > viewportHeight) break;\n usedHeight += nextHeight;\n endIndex++;\n }\n\n return {\n visibleItems: items.slice(startIndex, endIndex),\n startIndex,\n endIndex,\n hiddenAbove: startIndex,\n hiddenBelow: totalItems - endIndex,\n isScrollable: true,\n };\n}\n\n/**\n * React hook wrapper around `computeVirtualScroll`.\n * Memoizes the result based on input changes.\n */\nexport function useVirtualScroll<T>(options: VirtualScrollOptions<T>): VirtualScrollResult<T> {\n const { items, availableHeight, focusedIndex, estimateItemHeight, terminalWidth } = options;\n return useMemo(\n () => computeVirtualScroll(options),\n [items, availableHeight, focusedIndex, estimateItemHeight, terminalWidth],\n );\n}\n","import { useCallback, useEffect } from \"react\";\nimport { useInput } from \"ink\";\n\nimport type { Subcategory, SkillId } from \"../../types/index.js\";\nimport type { CategoryOption, CategoryRow } from \"../wizard/category-grid.js\";\n\nconst FRAMEWORK_CATEGORY_ID = \"framework\";\n\n// Locked = non-framework section when no framework is selected\nexport const isSectionLocked = (categoryId: Subcategory, categories: CategoryRow[]): boolean => {\n if (categoryId === FRAMEWORK_CATEGORY_ID) {\n return false;\n }\n\n const frameworkCategory = categories.find((cat) => cat.id === FRAMEWORK_CATEGORY_ID);\n if (!frameworkCategory) return false;\n\n return !frameworkCategory.options.some((opt) => opt.selected);\n};\n\nexport const 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/** Find next unlocked section index (wrapping, direction: forward) */\nexport const findNextUnlockedIndex = (\n processed: { id: Subcategory; sortedOptions: CategoryOption[] }[],\n currentIndex: number,\n allCategories: CategoryRow[],\n): number => {\n const length = processed.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += 1;\n if (index >= length) index = 0;\n\n const category = processed[index];\n if (category && !isSectionLocked(category.id, allCategories)) {\n return index;\n }\n\n attempts++;\n }\n\n return currentIndex;\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\ntype UseCategoryGridInputOptions = {\n processedCategories: ProcessedCategory[];\n categories: CategoryRow[];\n focusedRow: number;\n focusedCol: number;\n setFocused: (row: number, col: number) => void;\n moveFocus: (direction: \"up\" | \"down\" | \"left\" | \"right\") => void;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n};\n\nexport function useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleDescriptions,\n}: UseCategoryGridInputOptions): void {\n const currentRow = processedCategories[focusedRow];\n const currentOptions = currentRow?.sortedOptions || [];\n const currentLocked = currentRow ? isSectionLocked(currentRow.id, categories) : false;\n\n // Adjust column when current row's options change externally (e.g. option becomes disabled)\n useEffect(() => {\n if (!currentRow) return;\n\n const maxCol = currentOptions.length - 1;\n if (focusedCol > maxCol) {\n const newCol = Math.max(0, maxCol);\n setFocused(focusedRow, newCol);\n } else if (currentOptions[focusedCol]?.state === \"disabled\") {\n const validCol = findValidStartColumn(currentOptions);\n if (validCol !== focusedCol) {\n setFocused(focusedRow, validCol);\n }\n }\n }, [focusedRow, currentOptions, focusedCol, setFocused, currentRow]);\n\n // Bounce off locked sections when a section becomes locked (e.g. framework deselected)\n useEffect(() => {\n if (currentRow && currentLocked) {\n const nextUnlocked = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextUnlocked !== focusedRow) {\n const newRowOptions = processedCategories[nextUnlocked]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextUnlocked, newCol);\n }\n }\n }, [currentRow, currentLocked, focusedRow, processedCategories, categories, setFocused]);\n\n useInput(\n useCallback(\n (\n input: string,\n key: {\n leftArrow: boolean;\n rightArrow: boolean;\n upArrow: boolean;\n downArrow: boolean;\n tab: boolean;\n shift: boolean;\n },\n ) => {\n if (key.tab && key.shift) {\n onToggleDescriptions();\n return;\n }\n\n if (key.tab && !key.shift) {\n const nextSection = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextSection !== focusedRow) {\n const newRowOptions = processedCategories[nextSection]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextSection, newCol);\n }\n return;\n }\n\n if (input === \"d\" || input === \"D\") {\n onToggleDescriptions();\n return;\n }\n\n if (input === \" \") {\n if (currentLocked) return;\n const currentOption = currentOptions[focusedCol];\n if (currentOption && currentOption.state !== \"disabled\") {\n onToggle(currentRow.id, currentOption.id);\n }\n return;\n }\n\n const isLeft = key.leftArrow || input === \"h\";\n const isRight = key.rightArrow || input === \"l\";\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isLeft) {\n if (currentLocked) return;\n moveFocus(\"left\");\n } else if (isRight) {\n if (currentLocked) return;\n moveFocus(\"right\");\n } else if (isUp) {\n moveFocus(\"up\");\n } else if (isDown) {\n moveFocus(\"down\");\n }\n },\n [\n focusedRow,\n focusedCol,\n currentOptions,\n currentRow,\n currentLocked,\n processedCategories,\n categories,\n onToggle,\n onToggleDescriptions,\n setFocused,\n moveFocus,\n ],\n ),\n );\n}\n"],"mappings":"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","names":["useCallback","useMemo","useMemo","useCallback"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/step-build.tsx","../src/cli/lib/wizard/index.ts","../src/cli/lib/wizard/build-step-logic.ts","../src/cli/components/hooks/use-framework-filtering.ts","../src/cli/components/hooks/use-terminal-dimensions.ts","../src/cli/components/hooks/use-measured-height.ts"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n Subcategory,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { validateBuildStep } from \"../../lib/wizard/index.js\";\nimport { CLI_COLORS, SCROLL_VIEWPORT, UI_SYMBOLS } from \"../../consts.js\";\nimport { useFrameworkFiltering } from \"../hooks/use-framework-filtering.js\";\nimport { useTerminalDimensions } from \"../hooks/use-terminal-dimensions.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { CategoryGrid } from \"./category-grid.js\";\nimport { ViewTitle } from \"./view-title.js\";\nimport { getDomainDisplayName } from \"./utils.js\";\n\nexport type StepBuildProps = {\n matrix: MergedSkillsMatrix;\n domain: Domain;\n selectedDomains: Domain[];\n selections: SubcategorySelections;\n allSelections: SkillId[];\n showDescriptions: boolean;\n expertMode: boolean;\n /** For framework-first filtering on sub-domains (e.g., web-extras inherits from web) */\n parentDomainSelections?: SubcategorySelections;\n /** Skill IDs already installed on disk, shown with a dimmed checkmark */\n installedSkillIds?: SkillId[];\n onToggle: (subcategoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n onContinue: () => void;\n onBack: () => void;\n};\n\ntype FooterProps = {\n validationError?: string;\n};\n\nconst Footer: React.FC<FooterProps> = ({ validationError }) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {validationError && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color={CLI_COLORS.WARNING}>{validationError}</Text>\n <Text dimColor>Press ESC to go back, or select a skill and press ENTER to continue.</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nconst LegendRow: React.FC = () => {\n return (\n <Box paddingLeft={1} columnGap={2}>\n <Text color={CLI_COLORS.PRIMARY}>{UI_SYMBOLS.SELECTED} active</Text>\n <Text color={CLI_COLORS.UNFOCUSED}>{UI_SYMBOLS.UNSELECTED} recommended</Text>\n <Text color={CLI_COLORS.WARNING}>{UI_SYMBOLS.DISCOURAGED} discouraged</Text>\n <Text color={CLI_COLORS.NEUTRAL}>{UI_SYMBOLS.DISABLED} disabled</Text>\n </Box>\n );\n};\n\nexport const StepBuild: React.FC<StepBuildProps> = ({\n matrix,\n domain: activeDomain,\n selectedDomains,\n selections,\n allSelections,\n showDescriptions,\n expertMode,\n parentDomainSelections,\n installedSkillIds,\n onToggle,\n onToggleDescriptions,\n onContinue,\n onBack,\n}) => {\n const [validationError, setValidationError] = useState<string | undefined>(undefined);\n const { columns } = useTerminalDimensions();\n const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();\n\n const categories = useFrameworkFiltering({\n domain: activeDomain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n });\n\n const availableHeight =\n gridHeight > 0 ? Math.max(SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS, gridHeight) : Infinity;\n\n useInput((_input, key) => {\n if (key.return) {\n const validation = validateBuildStep(categories, selections);\n if (validation.valid) {\n setValidationError(undefined);\n onContinue();\n } else {\n setValidationError(validation.message);\n }\n } else if (key.escape) {\n setValidationError(undefined);\n onBack();\n }\n });\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" flexGrow={1}>\n <Box\n columnGap={2}\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginBottom={1}\n paddingRight={1}\n marginTop={-1}\n borderTop={false}\n borderRight={false}\n borderLeft={false}\n borderColor={CLI_COLORS.NEUTRAL}\n borderStyle=\"single\"\n >\n <Box columnGap={2} flexDirection=\"row\">\n {selectedDomains.map((domain) => {\n const isActive = domain === activeDomain;\n return (\n <Text key={domain} color={isActive ? CLI_COLORS.PRIMARY : undefined}>\n {isActive ? UI_SYMBOLS.CURRENT : UI_SYMBOLS.UNSELECTED}{\" \"}\n {getDomainDisplayName(domain)}\n </Text>\n );\n })}\n </Box>\n <LegendRow />\n </Box>\n <ViewTitle>Customize your {getDomainDisplayName(activeDomain)} stack</ViewTitle>\n\n <Box ref={gridRef} flexGrow={1}>\n <CategoryGrid\n key={activeDomain}\n categories={categories}\n expertMode={expertMode}\n showDescriptions={showDescriptions}\n onToggle={onToggle}\n onToggleDescriptions={onToggleDescriptions}\n availableHeight={availableHeight}\n terminalWidth={columns}\n />\n </Box>\n\n <Footer validationError={validationError} />\n </Box>\n );\n};\n","export {\n type BuildStepValidation,\n validateBuildStep,\n computeOptionState,\n getSkillDisplayLabel,\n buildCategoriesForDomain,\n} from \"./build-step-logic\";\n","import { sortBy } from \"remeda\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { getAvailableSkills, resolveAlias } from \"../matrix/index.js\";\nimport type {\n CategoryRow,\n CategoryOption,\n OptionState,\n} from \"../../components/wizard/category-grid.js\";\n\nconst FRAMEWORK_SUBCATEGORY_ID = \"framework\";\nconst WEB_DOMAIN_ID = \"web\";\n\nexport type BuildStepValidation = {\n valid: boolean;\n message?: string;\n};\n\nexport function validateBuildStep(\n categories: CategoryRow[],\n selections: SubcategorySelections,\n): BuildStepValidation {\n for (const category of categories) {\n if (category.required) {\n const categorySelections = selections[category.id] || [];\n if (categorySelections.length === 0) {\n return {\n valid: false,\n message: `Select at least one skill from the ${category.displayName} category. Use arrow keys to navigate, then SPACE to select.`,\n };\n }\n }\n }\n return { valid: true };\n}\n\nexport function computeOptionState(skill: {\n disabled: boolean;\n discouraged: boolean;\n recommended: boolean;\n}): OptionState {\n if (skill.disabled) {\n return \"disabled\";\n }\n if (skill.discouraged) {\n return \"discouraged\";\n }\n if (skill.recommended) {\n return \"recommended\";\n }\n return \"normal\";\n}\n\nexport function getSkillDisplayLabel(skill: { displayName?: string; id: string }): string {\n return skill.displayName || skill.id;\n}\n\nfunction getStateReason(skill: {\n disabled: boolean;\n disabledReason?: string;\n discouraged: boolean;\n discouragedReason?: string;\n recommended: boolean;\n recommendedReason?: string;\n}): string | undefined {\n if (skill.disabled && skill.disabledReason) {\n return skill.disabledReason;\n }\n if (skill.discouraged && skill.discouragedReason) {\n return skill.discouragedReason;\n }\n if (skill.recommended && skill.recommendedReason) {\n return skill.recommendedReason;\n }\n return undefined;\n}\n\nfunction isFrameworkSelected(selections: SubcategorySelections): boolean {\n const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];\n return frameworkSelections.length > 0;\n}\n\nfunction getSelectedFrameworks(\n selections: SubcategorySelections,\n matrix: MergedSkillsMatrix,\n): SkillId[] {\n const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];\n return frameworkSelections.map((alias) => resolveAlias(alias, matrix));\n}\n\nfunction isCompatibleWithSelectedFrameworks(\n skillId: SkillId,\n selectedFrameworkIds: SkillId[],\n matrix: MergedSkillsMatrix,\n): boolean {\n const skill = matrix.skills[skillId];\n if (!skill) return false;\n\n // No compatibleWith = compatible with all (allows legacy skills to appear)\n if (skill.compatibleWith.length === 0) {\n return true;\n }\n\n return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));\n}\n\n// Build CategoryRow[] from matrix for a domain, with framework-first filtering for web\nexport function buildCategoriesForDomain(\n domain: Domain,\n allSelections: SkillId[],\n matrix: MergedSkillsMatrix,\n expertMode: boolean,\n selections: SubcategorySelections,\n parentDomainSelections?: SubcategorySelections,\n installedSkillIds?: SkillId[],\n): CategoryRow[] {\n const frameworkSource = parentDomainSelections ?? selections;\n const frameworkSelected = isFrameworkSelected(frameworkSource);\n const selectedFrameworkIds = frameworkSelected\n ? getSelectedFrameworks(frameworkSource, matrix)\n : [];\n\n const subcategories = sortBy(\n Object.values(matrix.categories).filter((cat) => cat.domain === domain),\n (cat) => cat.order ?? 0,\n );\n\n const categoryRows: CategoryRow[] = subcategories.map((cat) => {\n const skillOptions = getAvailableSkills(cat.id, allSelections, matrix, {\n expertMode,\n });\n\n const useFrameworkFilter =\n (domain === WEB_DOMAIN_ID || parentDomainSelections !== undefined) &&\n cat.id !== FRAMEWORK_SUBCATEGORY_ID &&\n frameworkSelected;\n const filteredSkillOptions = useFrameworkFilter\n ? skillOptions.filter((skill) =>\n isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds, matrix),\n )\n : skillOptions;\n\n const options: CategoryOption[] = filteredSkillOptions.map((skill) => ({\n id: skill.id,\n label: getSkillDisplayLabel(skill),\n state: computeOptionState(skill),\n stateReason: getStateReason(skill),\n selected: skill.selected,\n local: matrix.skills[skill.id]?.local,\n installed: installedSkillIds?.includes(skill.id) || false,\n }));\n\n return {\n id: cat.id,\n displayName: cat.displayName,\n required: cat.required ?? false,\n exclusive: cat.exclusive ?? true,\n options,\n };\n });\n\n return categoryRows.filter((row) => row.options.length > 0);\n}\n","import { useMemo } from \"react\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { buildCategoriesForDomain } from \"../../lib/wizard/index.js\";\nimport type { CategoryRow } from \"../wizard/category-grid.js\";\n\ntype UseFrameworkFilteringOptions = {\n domain: Domain;\n allSelections: SkillId[];\n matrix: MergedSkillsMatrix;\n expertMode: boolean;\n selections: SubcategorySelections;\n parentDomainSelections?: SubcategorySelections;\n installedSkillIds?: SkillId[];\n};\n\nexport function useFrameworkFiltering({\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n}: UseFrameworkFilteringOptions): CategoryRow[] {\n return useMemo(\n () =>\n buildCategoriesForDomain(\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n ),\n [\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n ],\n );\n}\n","import { useState, useEffect } from \"react\";\nimport { useStdout } from \"ink\";\n\nconst DEFAULT_COLUMNS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport type TerminalDimensions = {\n /** Terminal width in columns */\n columns: number;\n /** Terminal height in rows */\n rows: number;\n};\n\n/**\n * Tracks terminal dimensions reactively. Re-renders on resize.\n *\n * Falls back to DEFAULT_COLUMNS x DEFAULT_ROWS when stdout is not a TTY\n * (e.g., piped output, CI environments, tests).\n */\nexport function useTerminalDimensions(): TerminalDimensions {\n const { stdout } = useStdout();\n\n const [dimensions, setDimensions] = useState<TerminalDimensions>(() => ({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n }));\n\n useEffect(() => {\n const handleResize = () => {\n setDimensions({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n });\n };\n\n stdout.on(\"resize\", handleResize);\n return () => {\n stdout.off(\"resize\", handleResize);\n };\n }, [stdout]);\n\n return dimensions;\n}\n","import { useRef, useState, useEffect } from \"react\";\nimport { type DOMElement, measureElement, useStdout } from \"ink\";\n\n/**\n * Measures the computed height of a Box element using Ink's Yoga layout engine.\n *\n * Returns a ref to attach to a Box with `flexGrow={1}` and the measured height.\n * The Box must be inside a parent chain with a constrained height (e.g., an\n * explicit `height` prop on an ancestor) so Yoga can compute the remaining space.\n *\n * Returns 0 before the first layout pass. Re-measures on terminal resize.\n */\nexport function useMeasuredHeight(): {\n ref: React.Ref<DOMElement>;\n measuredHeight: number;\n} {\n const ref = useRef<DOMElement>(null);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n const { stdout } = useStdout();\n\n useEffect(() => {\n const measure = () => {\n if (ref.current) {\n const { height } = measureElement(ref.current);\n setMeasuredHeight((prev) => (prev !== height ? height : prev));\n }\n };\n\n measure();\n\n stdout.on(\"resize\", measure);\n return () => {\n stdout.off(\"resize\", measure);\n };\n }, [stdout]);\n\n return { ref, measuredHeight };\n}\n"],"mappings":"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","names":["useState","useState","useEffect","useStdout","useState"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/wizard-layout.tsx"],"sourcesContent":["import React, { Fragment } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { WizardTabs, WIZARD_STEPS } from \"./wizard-tabs.js\";\nimport { HelpModal } from \"./help-modal.js\";\n\ntype KeyHintProps = {\n isVisible?: boolean;\n isActive?: boolean;\n label: string;\n values: string[];\n};\n\nconst DefinitionItem: React.FC<KeyHintProps> = ({\n isVisible = true,\n isActive = false,\n label,\n values,\n}) => {\n if (!isVisible) {\n return null;\n }\n\n return (\n <Text>\n {values.map((value) => (\n <Fragment key={value}>\n <Text backgroundColor=\"black\" color={CLI_COLORS.UNFOCUSED}>\n {\" \"}\n {value}{\" \"}\n </Text>{\" \"}\n </Fragment>\n ))}\n <Text color={isActive ? CLI_COLORS.PRIMARY : undefined}>{label}</Text>\n </Text>\n );\n};\n\nconst HOT_KEYS: { label: string; values: string[] }[] = [\n { label: \"navigate\", values: [\"\\u2190/\\u2192\", \"\\u2191/\\u2193\"] },\n { label: \"select\", values: [\"SPACE\"] },\n { label: \"continue\", values: [\"ENTER\"] },\n { label: \"back\", values: [\"ESC\"] },\n];\n\nconst WizardFooter = () => {\n const store = useWizardStore();\n\n return (\n <Box\n columnGap={2}\n borderTop\n borderRight={false}\n borderBottom\n borderLeft={false}\n borderColor=\"blackBright\"\n borderStyle=\"single\"\n paddingLeft={1}\n paddingRight={1}\n >\n <DefinitionItem\n label=\"Accept defaults\"\n values={[\"A\"]}\n isVisible={store.step === \"build\" && !!store.selectedStackId}\n />\n {HOT_KEYS.map((hotkey) => (\n <DefinitionItem {...hotkey} key={hotkey.label} />\n ))}\n </Box>\n );\n};\n\ntype WizardLayoutProps = {\n version?: string;\n marketplaceLabel?: string;\n brandingName?: string;\n /** Terminal height in rows, used to constrain the layout for flexGrow measurement */\n terminalHeight: number;\n children: React.ReactNode;\n};\n\nexport const WizardLayout: React.FC<WizardLayoutProps> = ({\n version,\n marketplaceLabel,\n brandingName,\n terminalHeight,\n children,\n}) => {\n const store = useWizardStore();\n const { completedSteps, skippedSteps } = store.getStepProgress();\n\n // Constrain height only during the build step so flexGrow-based measurement\n // can determine the grid area. Other steps grow to fit their content.\n const constrainedHeight = store.step === \"build\" ? terminalHeight : undefined;\n\n return (\n <Box flexDirection=\"column\" paddingX={1} height={constrainedHeight}>\n <WizardTabs\n steps={WIZARD_STEPS}\n currentStep={store.step}\n completedSteps={completedSteps}\n skippedSteps={skippedSteps}\n version={version}\n brandingName={brandingName}\n />\n {marketplaceLabel && (\n <Box paddingLeft={1} marginTop={1}>\n <Text dimColor>Marketplace: </Text>\n <Text bold>{marketplaceLabel}</Text>\n </Box>\n )}\n {store.showHelp ? (\n <HelpModal currentStep={store.step} />\n ) : (\n <>\n <Box flexGrow={1} marginTop={1}>\n {children}\n </Box>\n <Box paddingX={1} columnGap={2} marginTop={2}>\n <DefinitionItem label=\"Expert mode\" values={[\"E\"]} isActive={store.expertMode} />\n <DefinitionItem\n label=\"Descriptions\"\n values={[\"D\"]}\n isVisible={store.step === \"build\"}\n isActive={store.showDescriptions}\n />\n <DefinitionItem\n label=\"Plugin mode\"\n values={[\"P\"]}\n isActive={store.installMode === \"plugin\"}\n />\n <DefinitionItem\n label=\"Settings\"\n values={[\"G\"]}\n isVisible={store.step === \"sources\"}\n isActive={store.showSettings}\n />\n <DefinitionItem label=\"Help\" values={[\"?\"]} />\n </Box>\n <WizardFooter />\n </>\n )}\n </Box>\n );\n};\n"],"mappings":"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","names":["Fragment"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/utils/messages.ts"],"sourcesContent":["import { DEFAULT_BRANDING } from \"../consts.js\";\n\nexport const ERROR_MESSAGES = {\n UNKNOWN_ERROR: \"Unknown error occurred\",\n UNKNOWN_ERROR_SHORT: \"Unknown error\",\n NO_INSTALLATION: `No installation found. Run 'cc init' first to set up ${DEFAULT_BRANDING.NAME}`,\n NO_LOCAL_SKILLS: \"No local skills found. Run `cc init` or `cc edit` first.\",\n NO_SKILLS_FOUND: \"No skills found\",\n VALIDATION_FAILED: \"Validation failed\",\n FAILED_RESOLVE_SOURCE: \"Failed to resolve source\",\n FAILED_LOAD_AGENT_PARTIALS: \"Failed to load agent partials\",\n FAILED_COMPILE_AGENTS: \"Failed to compile agents\",\n SKILL_NOT_FOUND: \"Skill not found\",\n} as const;\n\nexport const SUCCESS_MESSAGES = {\n IMPORT_COMPLETE: \"Import complete!\",\n UNINSTALL_COMPLETE: \"Uninstall complete!\",\n INIT_SUCCESS: `${DEFAULT_BRANDING.NAME} initialized successfully!`,\n PLUGIN_COMPILE_COMPLETE: \"Plugin compile complete!\",\n CUSTOM_COMPILE_COMPLETE: \"Custom output compile complete!\",\n ALL_SKILLS_UP_TO_DATE: \"All skills are up to date.\",\n} as const;\n\nexport const STATUS_MESSAGES = {\n LOADING_SKILLS: \"Loading skills...\",\n LOADING_MARKETPLACE_SOURCE: \"Loading marketplace source...\",\n RECOMPILING_AGENTS: \"Recompiling agents...\",\n COMPILING_AGENTS: \"Compiling agents...\",\n DISCOVERING_SKILLS: \"Discovering skills...\",\n RESOLVING_SOURCE: \"Resolving source...\",\n RESOLVING_MARKETPLACE_SOURCE: \"Resolving marketplace source...\",\n FETCHING_AGENT_PARTIALS: \"Fetching agent partials...\",\n LOADING_AGENT_PARTIALS: \"Loading agent partials...\",\n FETCHING_REPOSITORY: \"Fetching repository...\",\n COPYING_SKILLS: \"Copying skills...\",\n UPDATING_PLUGIN_SKILLS: \"Updating plugin skills...\",\n} as const;\n\nexport const INFO_MESSAGES = {\n NO_CHANGES_MADE: \"No changes made.\",\n RUN_COMPILE: \"Run 'cc compile' to include imported skills in your agents.\",\n NO_AGENTS_TO_RECOMPILE: \"No agents to recompile\",\n NO_AGENTS_TO_COMPILE: \"No agents to compile\",\n NO_PLUGIN_INSTALLATION: \"No plugin installation found.\",\n NO_LOCAL_INSTALLATION: \"No local installation found.\",\n NOT_INSTALLED: `${DEFAULT_BRANDING.NAME} is not installed in this project.`,\n} as const;\n\nexport const DRY_RUN_MESSAGES = {\n PREVIEW_NO_FILES_REMOVED: \"[dry-run] Preview mode - no files will be removed\",\n PREVIEW_NO_FILES_CREATED: \"[dry-run] Preview mode - no files will be created\",\n COMPLETE_NO_FILES_REMOVED: \"[dry-run] Preview complete - no files were removed\",\n COMPLETE_NO_FILES_WRITTEN: \"[dry-run] Preview complete - no files were written\",\n COMPLETE_NO_FILES_CREATED: \"[dry-run] Preview complete - no files were created\",\n} as const;\n"],"mappings":";;;;;;;;;AAAA;AAEO,IAAM,iBAAiB;AAAA,EAC5B,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,iBAAiB,wDAAwD,iBAAiB,IAAI;AAAA,EAC9F,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,4BAA4B;AAAA,EAC5B,uBAAuB;AAAA,EACvB,iBAAiB;AACnB;AAEO,IAAM,mBAAmB;AAAA,EAC9B,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,cAAc,GAAG,iBAAiB,IAAI;AAAA,EACtC,yBAAyB;AAAA,EACzB,yBAAyB;AAAA,EACzB,uBAAuB;AACzB;AAEO,IAAM,kBAAkB;AAAA,EAC7B,gBAAgB;AAAA,EAChB,4BAA4B;AAAA,EAC5B,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,8BAA8B;AAAA,EAC9B,yBAAyB;AAAA,EACzB,wBAAwB;AAAA,EACxB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,wBAAwB;AAC1B;AAEO,IAAM,gBAAgB;AAAA,EAC3B,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,eAAe,GAAG,iBAAiB,IAAI;AACzC;AAEO,IAAM,mBAAmB;AAAA,EAC9B,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,2BAA2B;AAAA,EAC3B,2BAA2B;AAC7B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/utils.ts"],"sourcesContent":["import { unique } from \"remeda\";\nimport type { CategoryMap, Domain, MergedSkillsMatrix, ResolvedStack } from \"../../types/index.js\";\nimport { typedKeys } from \"../../utils/typed-object.js\";\n\nexport function getDomainDisplayName(domain: Domain): string {\n const displayNames: Record<Domain, string> = {\n web: \"Web\",\n \"web-extras\": \"Web Extras\",\n api: \"API\",\n cli: \"CLI\",\n mobile: \"Mobile\",\n shared: \"Shared\",\n };\n return displayNames[domain] || domain.charAt(0).toUpperCase() + domain.slice(1);\n}\n\nexport function getStackName(\n stackId: string | null,\n matrix: MergedSkillsMatrix,\n): string | undefined {\n if (!stackId) return undefined;\n const stack = matrix.suggestedStacks.find((s) => s.id === stackId);\n return stack?.name;\n}\n\n/** Extract unique domains from a stack's agent-to-skill mappings. */\nexport function getDomainsFromStack(stack: ResolvedStack, categories: CategoryMap): Domain[] {\n const subcategories = Object.values(stack.skills).flatMap((config) =>\n config ? typedKeys(config) : [],\n );\n return unique(\n subcategories.flatMap((sub) => {\n const d = categories[sub]?.domain;\n return d ? [d] : [];\n }),\n ).sort();\n}\n"],"mappings":";;;;;;;;;AAAA;AAAA,SAAS,cAAc;AAIhB,SAAS,qBAAqB,QAAwB;AAC3D,QAAM,eAAuC;AAAA,IAC3C,KAAK;AAAA,IACL,cAAc;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,SAAO,aAAa,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,MAAM,CAAC;AAChF;AAEO,SAAS,aACd,SACA,QACoB;AACpB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,OAAO,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AACjE,SAAO,OAAO;AAChB;AAGO,SAAS,oBAAoB,OAAsB,YAAmC;AAC3F,QAAM,gBAAgB,OAAO,OAAO,MAAM,MAAM,EAAE;AAAA,IAAQ,CAAC,WACzD,SAAS,UAAU,MAAM,IAAI,CAAC;AAAA,EAChC;AACA,SAAO;AAAA,IACL,cAAc,QAAQ,CAAC,QAAQ;AAC7B,YAAM,IAAI,WAAW,GAAG,GAAG;AAC3B,aAAO,IAAI,CAAC,CAAC,IAAI,CAAC;AAAA,IACpB,CAAC;AAAA,EACH,EAAE,KAAK;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/step-sources.tsx"],"sourcesContent":["import React, { useState, useCallback } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type {\n BoundSkillCandidate,\n MergedSkillsMatrix,\n SkillAlias,\n SkillId,\n} from \"../../types/index.js\";\nimport { CLI_COLORS, DEFAULT_BRANDING } from \"../../consts.js\";\nimport { SourceGrid } from \"./source-grid.js\";\nimport { ViewTitle } from \"./view-title.js\";\nimport { searchExtraSources } from \"../../lib/loading/multi-source-loader.js\";\nimport { resolveAllSources } from \"../../lib/configuration/index.js\";\n\nexport type StepSourcesProps = {\n matrix: MergedSkillsMatrix;\n projectDir?: string;\n onContinue: () => void;\n onBack: () => void;\n};\n\ntype SourcesView = \"choice\" | \"customize\";\n\nexport const StepSources: React.FC<StepSourcesProps> = ({\n matrix,\n projectDir,\n onContinue,\n onBack,\n}) => {\n const store = useWizardStore();\n const [view, setView] = useState<SourcesView>(\"choice\");\n const [choiceIndex, setChoiceIndex] = useState(0);\n const [isGridSearching, setIsGridSearching] = useState(false);\n\n const handleGridSelect = useCallback(\n (skillId: SkillId, sourceId: string) => {\n store.setSourceSelection(skillId, sourceId);\n },\n [store],\n );\n\n const handleSearch = useCallback(\n async (alias: SkillAlias): Promise<BoundSkillCandidate[]> => {\n if (!projectDir) return [];\n try {\n const sources = await resolveAllSources(projectDir);\n return await searchExtraSources(alias, sources.extras);\n } catch {\n return [];\n }\n },\n [projectDir],\n );\n\n const handleBind = useCallback(\n (candidate: BoundSkillCandidate) => {\n store.bindSkill({\n id: candidate.id,\n sourceUrl: candidate.sourceUrl,\n sourceName: candidate.sourceName,\n boundTo: candidate.alias,\n description: candidate.description,\n });\n },\n [store],\n );\n\n const handleSearchStateChange = useCallback((active: boolean) => {\n setIsGridSearching(active);\n }, []);\n\n useInput((_input, key) => {\n if (view === \"choice\") {\n if (key.return) {\n if (choiceIndex === 0) {\n onContinue();\n } else {\n store.setCustomizeSources(true);\n setView(\"customize\");\n }\n }\n if (key.escape) {\n onBack();\n }\n if (key.upArrow || key.downArrow) {\n setChoiceIndex((prev) => (prev === 0 ? 1 : 0));\n }\n } else if (view === \"customize\") {\n if (isGridSearching) return;\n\n if (key.return) {\n onContinue();\n }\n if (key.escape) {\n store.setCustomizeSources(false);\n setView(\"choice\");\n }\n }\n });\n\n if (view === \"customize\") {\n const rows = store.buildSourceRows(matrix);\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n <ViewTitle>Customize skill sources</ViewTitle>\n <SourceGrid\n rows={rows}\n onSelect={handleGridSelect}\n onSearch={handleSearch}\n onBind={handleBind}\n onSearchStateChange={handleSearchStateChange}\n />\n </Box>\n );\n }\n\n const selectedTechnologies = store.getAllSelectedTechnologies();\n const rows = store.buildSourceRows(matrix);\n const isRecommendedSelected = choiceIndex === 0;\n const hasLocalSkills = rows.some((row) =>\n row.options.some((o) => o.installed && o.id === \"local\"),\n );\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <Text>\n Your stack includes{\" \"}\n <Text color={CLI_COLORS.PRIMARY} bold>\n {selectedTechnologies.length}\n </Text>{\" \"}\n technologies.\n </Text>\n <Text> </Text>\n\n <Box\n borderStyle=\"round\"\n borderColor={isRecommendedSelected ? CLI_COLORS.SUCCESS : CLI_COLORS.NEUTRAL}\n paddingX={2}\n paddingY={1}\n marginBottom={1}\n >\n <Box flexDirection=\"column\">\n <Text\n color={isRecommendedSelected ? CLI_COLORS.SUCCESS : undefined}\n bold={isRecommendedSelected}\n >\n {isRecommendedSelected ? \">\" : \"\\u25CB\"}{\" \"}\n {hasLocalSkills\n ? \"Use installed skill sources\"\n : \"Use all recommended skills (verified)\"}\n </Text>\n <Text> </Text>\n <Text dimColor>\n {hasLocalSkills\n ? \"Keep your current local and public skill selections.\"\n : \"This is the fastest option. All skills are verified and\"}\n </Text>\n {!hasLocalSkills && <Text dimColor>maintained by {DEFAULT_BRANDING.NAME}</Text>}\n </Box>\n </Box>\n\n <Box\n borderStyle=\"round\"\n borderColor={!isRecommendedSelected ? CLI_COLORS.SUCCESS : CLI_COLORS.NEUTRAL}\n paddingX={2}\n paddingY={1}\n >\n <Box flexDirection=\"column\">\n <Text\n color={!isRecommendedSelected ? CLI_COLORS.SUCCESS : undefined}\n bold={!isRecommendedSelected}\n >\n {!isRecommendedSelected ? \">\" : \"\\u25CB\"} Customize skill sources\n </Text>\n <Text> </Text>\n <Text dimColor>Choose alternative skills for each technology</Text>\n </Box>\n </Box>\n </Box>\n );\n};\n"],"mappings":"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","names":["rows"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/step-settings.tsx","../src/cli/components/hooks/use-source-operations.ts"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { ViewTitle } from \"./view-title.js\";\nimport { getSourceSummary, type SourceSummary } from \"../../lib/configuration/source-manager.js\";\nimport { DEFAULT_SOURCE } from \"../../lib/configuration/config.js\";\nimport { useKeyboardNavigation } from \"../hooks/use-keyboard-navigation.js\";\nimport { useModalState } from \"../hooks/use-modal-state.js\";\nimport { useSourceOperations } from \"../hooks/use-source-operations.js\";\nimport { useTextInput } from \"../hooks/use-text-input.js\";\n\nconst DEFAULT_SOURCE_NAME = \"public\";\n\nexport type StepSettingsProps = {\n projectDir: string;\n onClose: () => void;\n};\n\nexport const StepSettings: React.FC<StepSettingsProps> = ({ projectDir, onClose }) => {\n const [summary, setSummary] = useState<SourceSummary | null>(null);\n const addModal = useModalState();\n const {\n value: addSourceInput,\n setValue: setAddSourceInput,\n handleInput: handleTextInput,\n } = useTextInput(\"\");\n const [isLoading, setIsLoading] = useState(true);\n\n const loadSummary = useCallback(async () => {\n try {\n const result = await getSourceSummary(projectDir);\n setSummary(result);\n } catch {\n setSummary({\n sources: [{ name: DEFAULT_SOURCE_NAME, url: DEFAULT_SOURCE, enabled: true }],\n localSkillCount: 0,\n pluginSkillCount: 0,\n });\n }\n setIsLoading(false);\n }, [projectDir]);\n\n useEffect(() => {\n void loadSummary();\n }, [loadSummary]);\n\n const { handleAdd, handleRemove, statusMessage, clearStatus } = useSourceOperations(\n projectDir,\n loadSummary,\n );\n\n const sourceCount = summary?.sources.length ?? 0;\n\n const { focusedIndex, setFocusedIndex } = useKeyboardNavigation(\n sourceCount,\n { onEscape: onClose },\n { wrap: false, vimKeys: false, active: !addModal.isOpen },\n );\n\n useInput((input, key) => {\n if (statusMessage) {\n clearStatus();\n }\n\n if (addModal.isOpen) {\n if (key.escape) {\n addModal.close();\n setAddSourceInput(\"\");\n return;\n }\n\n if (key.return) {\n if (addSourceInput.trim()) {\n addModal.close();\n setAddSourceInput(\"\");\n void handleAdd(addSourceInput.trim());\n }\n return;\n }\n\n handleTextInput(input, key);\n return;\n }\n\n if (key.return) {\n // Toggle enabled/disabled is a placeholder for future enabledSources store integration\n return;\n }\n\n if (key.backspace || key.delete) {\n if (summary?.sources[focusedIndex]) {\n const source = summary.sources[focusedIndex];\n if (source.name !== DEFAULT_SOURCE_NAME) {\n void handleRemove(source.name).then((success) => {\n if (success) {\n setFocusedIndex((prev) => Math.max(0, prev - 1));\n }\n });\n }\n }\n return;\n }\n\n if (input === \"a\" || input === \"A\") {\n addModal.open(true);\n setAddSourceInput(\"\");\n }\n });\n\n if (isLoading) {\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <ViewTitle>Skill Sources</ViewTitle>\n <Text dimColor>Loading sources...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <ViewTitle>Skill Sources</ViewTitle>\n <Box marginTop={1} />\n\n <Text bold>Configured marketplaces:</Text>\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={CLI_COLORS.NEUTRAL}\n paddingX={1}\n marginTop={1}\n >\n {summary?.sources.map((source, index) => {\n const isFocused = index === focusedIndex && !addModal.isOpen;\n const isDefault = source.name === DEFAULT_SOURCE_NAME;\n const checkmark = source.enabled ? \"\\u2713\" : \" \";\n const displayName = isDefault ? \"Public\" : source.name;\n const suffix = isDefault ? \" (default)\" : \"\";\n\n return (\n <Box key={source.name}>\n <Text color={isFocused ? CLI_COLORS.PRIMARY : undefined} bold={isFocused}>\n {isFocused ? \">\" : \" \"} {checkmark} {displayName}\n </Text>\n <Text dimColor>\n {\" \"}\n {source.url}\n {suffix}\n </Text>\n </Box>\n );\n })}\n </Box>\n\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={addModal.isOpen ? CLI_COLORS.PRIMARY : CLI_COLORS.NEUTRAL}\n paddingX={1}\n marginTop={1}\n >\n <Text color={addModal.isOpen ? CLI_COLORS.PRIMARY : undefined}>\n + Add source: {addModal.isOpen ? addSourceInput : \"\"}\n {addModal.isOpen ? \"\\u2588\" : \"\"}\n </Text>\n </Box>\n\n {statusMessage && (\n <Box marginTop={1}>\n <Text color={statusMessage.color as \"red\" | \"green\"}>{statusMessage.text}</Text>\n </Box>\n )}\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text dimColor>Local skills: {summary?.localSkillCount ?? 0} in .claude/skills/</Text>\n <Text dimColor>Plugins: {summary?.pluginSkillCount ?? 0} from installed plugins</Text>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n {addModal.isOpen ? \"ENTER submit ESC cancel\" : \"A add DEL remove ESC or G to close\"}\n </Text>\n </Box>\n </Box>\n );\n};\n","import { useState, useCallback } from \"react\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { addSource, removeSource } from \"../../lib/configuration/source-manager.js\";\n\ntype StatusMessage = { text: string; color: string } | null;\n\ntype UseSourceOperationsResult = {\n handleAdd: (url: string) => Promise<void>;\n handleRemove: (name: string) => Promise<boolean>;\n statusMessage: StatusMessage;\n clearStatus: () => void;\n};\n\nexport function useSourceOperations(\n projectDir: string,\n onReload: () => Promise<void>,\n): UseSourceOperationsResult {\n const [statusMessage, setStatusMessage] = useState<StatusMessage>(null);\n\n const handleAdd = useCallback(\n async (url: string) => {\n try {\n const result = await addSource(projectDir, url);\n setStatusMessage({\n text: `Added \"${result.name}\" (${result.skillCount} skills)`,\n color: CLI_COLORS.SUCCESS,\n });\n await onReload();\n } catch (error) {\n const message = getErrorMessage(error);\n setStatusMessage({ text: `Failed to add source: ${message}`, color: CLI_COLORS.ERROR });\n }\n },\n [projectDir, onReload],\n );\n\n const handleRemove = useCallback(\n async (name: string): Promise<boolean> => {\n try {\n await removeSource(projectDir, name);\n setStatusMessage({ text: `Removed \"${name}\"`, color: CLI_COLORS.SUCCESS });\n await onReload();\n return true;\n } catch (error) {\n const message = getErrorMessage(error);\n setStatusMessage({ text: `Failed to remove: ${message}`, color: CLI_COLORS.ERROR });\n return false;\n }\n },\n [projectDir, onReload],\n );\n\n const clearStatus = useCallback(() => {\n setStatusMessage(null);\n }, []);\n\n return { handleAdd, handleRemove, statusMessage, clearStatus };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAgB,YAAAA,WAAU,WAAW,eAAAC,oBAAmB;AACxD,SAAS,KAAK,MAAM,gBAAgB;;;ACDpC;AAAA,SAAS,UAAU,mBAAmB;AAc/B,SAAS,oBACd,YACA,UAC2B;AAC3B,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB,IAAI;AAEtE,QAAM,YAAY;AAAA,IAChB,OAAO,QAAgB;AACrB,UAAI;AACF,cAAM,SAAS,MAAM,UAAU,YAAY,GAAG;AAC9C,yBAAiB;AAAA,UACf,MAAM,UAAU,OAAO,IAAI,MAAM,OAAO,UAAU;AAAA,UAClD,OAAO,WAAW;AAAA,QACpB,CAAC;AACD,cAAM,SAAS;AAAA,MACjB,SAAS,OAAO;AACd,cAAM,UAAU,gBAAgB,KAAK;AACrC,yBAAiB,EAAE,MAAM,yBAAyB,OAAO,IAAI,OAAO,WAAW,MAAM,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,IACA,CAAC,YAAY,QAAQ;AAAA,EACvB;AAEA,QAAM,eAAe;AAAA,IACnB,OAAO,SAAmC;AACxC,UAAI;AACF,cAAM,aAAa,YAAY,IAAI;AACnC,yBAAiB,EAAE,MAAM,YAAY,IAAI,KAAK,OAAO,WAAW,QAAQ,CAAC;AACzE,cAAM,SAAS;AACf,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,UAAU,gBAAgB,KAAK;AACrC,yBAAiB,EAAE,MAAM,qBAAqB,OAAO,IAAI,OAAO,WAAW,MAAM,CAAC;AAClF,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,CAAC,YAAY,QAAQ;AAAA,EACvB;AAEA,QAAM,cAAc,YAAY,MAAM;AACpC,qBAAiB,IAAI;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,cAAc,eAAe,YAAY;AAC/D;;;ADqDM,SACE,KADF;AApGN,IAAM,sBAAsB;AAOrB,IAAM,eAA4C,CAAC,EAAE,YAAY,QAAQ,MAAM;AACpF,QAAM,CAAC,SAAS,UAAU,IAAIC,UAA+B,IAAI;AACjE,QAAM,WAAW,cAAc;AAC/B,QAAM;AAAA,IACJ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,aAAa;AAAA,EACf,IAAI,aAAa,EAAE;AACnB,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,IAAI;AAE/C,QAAM,cAAcC,aAAY,YAAY;AAC1C,QAAI;AACF,YAAM,SAAS,MAAM,iBAAiB,UAAU;AAChD,iBAAW,MAAM;AAAA,IACnB,QAAQ;AACN,iBAAW;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,qBAAqB,KAAK,gBAAgB,SAAS,KAAK,CAAC;AAAA,QAC3E,iBAAiB;AAAA,QACjB,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AACA,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,UAAU,CAAC;AAEf,YAAU,MAAM;AACd,SAAK,YAAY;AAAA,EACnB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,EAAE,WAAW,cAAc,eAAe,YAAY,IAAI;AAAA,IAC9D;AAAA,IACA;AAAA,EACF;AAEA,QAAM,cAAc,SAAS,QAAQ,UAAU;AAE/C,QAAM,EAAE,cAAc,gBAAgB,IAAI;AAAA,IACxC;AAAA,IACA,EAAE,UAAU,QAAQ;AAAA,IACpB,EAAE,MAAM,OAAO,SAAS,OAAO,QAAQ,CAAC,SAAS,OAAO;AAAA,EAC1D;AAEA,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,eAAe;AACjB,kBAAY;AAAA,IACd;AAEA,QAAI,SAAS,QAAQ;AACnB,UAAI,IAAI,QAAQ;AACd,iBAAS,MAAM;AACf,0BAAkB,EAAE;AACpB;AAAA,MACF;AAEA,UAAI,IAAI,QAAQ;AACd,YAAI,eAAe,KAAK,GAAG;AACzB,mBAAS,MAAM;AACf,4BAAkB,EAAE;AACpB,eAAK,UAAU,eAAe,KAAK,CAAC;AAAA,QACtC;AACA;AAAA,MACF;AAEA,sBAAgB,OAAO,GAAG;AAC1B;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AAEd;AAAA,IACF;AAEA,QAAI,IAAI,aAAa,IAAI,QAAQ;AAC/B,UAAI,SAAS,QAAQ,YAAY,GAAG;AAClC,cAAM,SAAS,QAAQ,QAAQ,YAAY;AAC3C,YAAI,OAAO,SAAS,qBAAqB;AACvC,eAAK,aAAa,OAAO,IAAI,EAAE,KAAK,CAAC,YAAY;AAC/C,gBAAI,SAAS;AACX,8BAAgB,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,YACjD;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,UAAU,OAAO,UAAU,KAAK;AAClC,eAAS,KAAK,IAAI;AAClB,wBAAkB,EAAE;AAAA,IACtB;AAAA,EACF,CAAC;AAED,MAAI,WAAW;AACb,WACE,qBAAC,OAAI,eAAc,UAAS,UAAU,GACpC;AAAA,0BAAC,aAAU,2BAAa;AAAA,MACxB,oBAAC,QAAK,UAAQ,MAAC,gCAAkB;AAAA,OACnC;AAAA,EAEJ;AAEA,SACE,qBAAC,OAAI,eAAc,UAAS,UAAU,GACpC;AAAA,wBAAC,aAAU,2BAAa;AAAA,IACxB,oBAAC,OAAI,WAAW,GAAG;AAAA,IAEnB,oBAAC,QAAK,MAAI,MAAC,sCAAwB;AAAA,IACnC;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACd,aAAY;AAAA,QACZ,aAAa,WAAW;AAAA,QACxB,UAAU;AAAA,QACV,WAAW;AAAA,QAEV,mBAAS,QAAQ,IAAI,CAAC,QAAQ,UAAU;AACvC,gBAAM,YAAY,UAAU,gBAAgB,CAAC,SAAS;AACtD,gBAAM,YAAY,OAAO,SAAS;AAClC,gBAAM,YAAY,OAAO,UAAU,WAAW;AAC9C,gBAAM,cAAc,YAAY,WAAW,OAAO;AAClD,gBAAM,SAAS,YAAY,eAAe;AAE1C,iBACE,qBAAC,OACC;AAAA,iCAAC,QAAK,OAAO,YAAY,WAAW,UAAU,QAAW,MAAM,WAC5D;AAAA,0BAAY,MAAM;AAAA,cAAI;AAAA,cAAE;AAAA,cAAU;AAAA,cAAE;AAAA,eACvC;AAAA,YACA,qBAAC,QAAK,UAAQ,MACX;AAAA;AAAA,cACA,OAAO;AAAA,cACP;AAAA,eACH;AAAA,eARQ,OAAO,IASjB;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACd,aAAY;AAAA,QACZ,aAAa,SAAS,SAAS,WAAW,UAAU,WAAW;AAAA,QAC/D,UAAU;AAAA,QACV,WAAW;AAAA,QAEX,+BAAC,QAAK,OAAO,SAAS,SAAS,WAAW,UAAU,QAAW;AAAA;AAAA,UAC9C,SAAS,SAAS,iBAAiB;AAAA,UACjD,SAAS,SAAS,WAAW;AAAA,WAChC;AAAA;AAAA,IACF;AAAA,IAEC,iBACC,oBAAC,OAAI,WAAW,GACd,8BAAC,QAAK,OAAO,cAAc,OAA2B,wBAAc,MAAK,GAC3E;AAAA,IAGF,qBAAC,OAAI,WAAW,GAAG,eAAc,UAC/B;AAAA,2BAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QAAe,SAAS,mBAAmB;AAAA,QAAE;AAAA,SAAmB;AAAA,MAC/E,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QAAU,SAAS,oBAAoB;AAAA,QAAE;AAAA,SAAuB;AAAA,OACjF;AAAA,IAEA,oBAAC,OAAI,WAAW,GACd,8BAAC,QAAK,UAAQ,MACX,mBAAS,SAAS,6BAA6B,wCAClD,GACF;AAAA,KACF;AAEJ;","names":["useState","useCallback","useState","useCallback"]}