@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
@@ -8,7 +8,7 @@ import {
8
8
  RENDER_DELAY_MS,
9
9
  TAB,
10
10
  delay
11
- } from "../../chunk-6LS7XO3H.js";
11
+ } from "../../chunk-6Q3Y7KVB.js";
12
12
  import {
13
13
  render
14
14
  } from "../../chunk-66UDJBF6.js";
@@ -21,12 +21,12 @@ import {
21
21
  } from "../../chunk-XY3XDVMI.js";
22
22
  import {
23
23
  CategoryGrid
24
- } from "../../chunk-PPNTD5LO.js";
24
+ } from "../../chunk-Z7G4B5HJ.js";
25
25
  import {
26
26
  init_esm_shims
27
27
  } from "../../chunk-DHET7RCE.js";
28
28
 
29
- // src/cli-v2/components/wizard/category-grid.test.tsx
29
+ // src/cli/components/wizard/category-grid.test.tsx
30
30
  init_esm_shims();
31
31
  import { jsx } from "react/jsx-runtime";
32
32
  var createOption = (id, label, overrides = {}) => ({
@@ -49,13 +49,13 @@ var defaultCategories = [
49
49
  "framework",
50
50
  "Framework",
51
51
  [
52
- createOption("react", "react", {
52
+ createOption("react", "React", {
53
53
  state: "recommended",
54
54
  stateReason: "Popular choice"
55
55
  }),
56
- createOption("vue", "vue"),
57
- createOption("angular", "angular"),
58
- createOption("svelte", "svelte")
56
+ createOption("vue", "Vue"),
57
+ createOption("angular", "Angular"),
58
+ createOption("svelte", "Svelte")
59
59
  ],
60
60
  { required: true }
61
61
  ),
@@ -63,29 +63,64 @@ var defaultCategories = [
63
63
  "styling",
64
64
  "Styling",
65
65
  [
66
- createOption("scss-mod", "scss-mod", { selected: true }),
67
- createOption("tailwind", "tailwind", { state: "recommended" }),
68
- createOption("styled", "styled"),
69
- createOption("vanilla", "vanilla")
66
+ createOption("scss-mod", "SCSS Modules", { selected: true }),
67
+ createOption("tailwind", "Tailwind", { state: "recommended" }),
68
+ createOption("styled", "Styled Components"),
69
+ createOption("vanilla", "Vanilla CSS")
70
70
  ],
71
71
  { required: true }
72
72
  ),
73
73
  createCategory("client-state", "Client State", [
74
- createOption("zustand", "zustand", { state: "recommended" }),
75
- createOption("jotai", "jotai"),
76
- createOption("redux", "redux", {
74
+ createOption("zustand", "Zustand", { state: "recommended" }),
75
+ createOption("jotai", "Jotai"),
76
+ createOption("redux", "Redux", {
77
77
  state: "discouraged",
78
78
  stateReason: "Complex for most apps"
79
79
  }),
80
- createOption("mobx", "mobx")
80
+ createOption("mobx", "MobX")
81
81
  ]),
82
82
  createCategory("server-state", "Server State", [
83
- createOption("react-query", "react-query", { selected: true }),
84
- createOption("swr", "swr"),
85
- createOption("apollo", "apollo")
83
+ createOption("react-query", "React Query", { selected: true }),
84
+ createOption("swr", "SWR"),
85
+ createOption("apollo", "Apollo")
86
86
  ]),
87
87
  createCategory("analytics", "Analytics", [
88
- createOption("posthog", "posthog")
88
+ createOption("posthog", "PostHog")
89
+ ])
90
+ ];
91
+ var categoriesWithFramework = [
92
+ createCategory(
93
+ "framework",
94
+ "Framework",
95
+ [
96
+ createOption("react", "React", {
97
+ state: "recommended",
98
+ stateReason: "Popular choice",
99
+ selected: true
100
+ // Framework selected
101
+ }),
102
+ createOption("vue", "Vue"),
103
+ createOption("angular", "Angular"),
104
+ createOption("svelte", "Svelte")
105
+ ],
106
+ { required: true }
107
+ ),
108
+ createCategory(
109
+ "styling",
110
+ "Styling",
111
+ [
112
+ createOption("scss-mod", "SCSS Modules"),
113
+ createOption("tailwind", "Tailwind", { state: "recommended" }),
114
+ createOption("styled", "Styled Components"),
115
+ createOption("vanilla", "Vanilla CSS")
116
+ ],
117
+ { required: true }
118
+ ),
119
+ createCategory("client-state", "Client State", [
120
+ createOption("zustand", "Zustand", { state: "recommended" }),
121
+ createOption("jotai", "Jotai"),
122
+ createOption("redux", "Redux", { state: "discouraged" }),
123
+ createOption("mobx", "MobX")
89
124
  ])
90
125
  ];
91
126
  var defaultProps = {
@@ -110,7 +145,7 @@ describe("CategoryGrid component", () => {
110
145
  vi.clearAllMocks();
111
146
  });
112
147
  describe("rendering", () => {
113
- it("should render all categories", () => {
148
+ it("should render all categories as sections", () => {
114
149
  const { lastFrame, unmount } = renderGrid();
115
150
  cleanup = unmount;
116
151
  const output = lastFrame();
@@ -124,12 +159,12 @@ describe("CategoryGrid component", () => {
124
159
  const { lastFrame, unmount } = renderGrid();
125
160
  cleanup = unmount;
126
161
  const output = lastFrame();
127
- globalExpect(output).toContain("react");
128
- globalExpect(output).toContain("vue");
129
- globalExpect(output).toContain("angular");
130
- globalExpect(output).toContain("svelte");
131
- globalExpect(output).toContain("scss-mod");
132
- globalExpect(output).toContain("tailwind");
162
+ globalExpect(output).toContain("React");
163
+ globalExpect(output).toContain("Vue");
164
+ globalExpect(output).toContain("Angular");
165
+ globalExpect(output).toContain("Svelte");
166
+ globalExpect(output).toContain("SCSS Modules");
167
+ globalExpect(output).toContain("Tailwind");
133
168
  });
134
169
  it("should show required indicator (*) for required categories", () => {
135
170
  const { lastFrame, unmount } = renderGrid();
@@ -137,13 +172,13 @@ describe("CategoryGrid component", () => {
137
172
  const output = lastFrame();
138
173
  globalExpect(output).toContain("*");
139
174
  });
140
- it("should show (optional) for non-required categories", () => {
175
+ it("should NOT show (optional) for non-required categories", () => {
141
176
  const { lastFrame, unmount } = renderGrid();
142
177
  cleanup = unmount;
143
178
  const output = lastFrame();
144
- globalExpect(output).toContain("(optional)");
179
+ globalExpect(output).not.toContain("(optional)");
145
180
  });
146
- it("should render legend row", () => {
181
+ it("should render legend row with visual states", () => {
147
182
  const { lastFrame, unmount } = renderGrid();
148
183
  cleanup = unmount;
149
184
  const output = lastFrame();
@@ -157,7 +192,7 @@ describe("CategoryGrid component", () => {
157
192
  const { lastFrame, unmount } = renderGrid();
158
193
  cleanup = unmount;
159
194
  const output = lastFrame();
160
- globalExpect(output).toContain("[Tab] Show descriptions");
195
+ globalExpect(output).toContain("[d] Descriptions");
161
196
  globalExpect(output).toContain("[e] Expert Mode");
162
197
  });
163
198
  it("should handle empty categories array", () => {
@@ -166,33 +201,41 @@ describe("CategoryGrid component", () => {
166
201
  const output = lastFrame();
167
202
  globalExpect(output).toContain("No categories to display");
168
203
  });
204
+ it("should render section underlines", () => {
205
+ const { lastFrame, unmount } = renderGrid();
206
+ cleanup = unmount;
207
+ const output = lastFrame();
208
+ globalExpect(output).toContain("\u2500");
209
+ });
169
210
  });
170
211
  describe("visual states", () => {
171
- it("should show selected symbol for selected options", () => {
212
+ it("should show selected options with label text", () => {
172
213
  const { lastFrame, unmount } = renderGrid();
173
214
  cleanup = unmount;
174
215
  const output = lastFrame();
175
- globalExpect(output).toContain("\u25CF");
216
+ globalExpect(output).toContain("SCSS Modules");
217
+ globalExpect(output).toContain("React Query");
176
218
  });
177
- it("should show unselected symbol for unselected options", () => {
219
+ it("should show unselected options with label text", () => {
178
220
  const { lastFrame, unmount } = renderGrid();
179
221
  cleanup = unmount;
180
222
  const output = lastFrame();
181
- globalExpect(output).toContain("\u25CB");
223
+ globalExpect(output).toContain("Vue");
224
+ globalExpect(output).toContain("Angular");
182
225
  });
183
- it("should show recommended indicator for recommended options", () => {
226
+ it("should NOT show star indicator for recommended options (uses background instead)", () => {
184
227
  const { lastFrame, unmount } = renderGrid();
185
228
  cleanup = unmount;
186
229
  const output = lastFrame();
187
- globalExpect(output).toContain("\u2B50");
230
+ globalExpect(output).not.toContain("\u2B50");
188
231
  });
189
- it("should show discouraged indicator for discouraged options", () => {
232
+ it("should NOT show warning indicator for discouraged options (uses color instead)", () => {
190
233
  const { lastFrame, unmount } = renderGrid();
191
234
  cleanup = unmount;
192
235
  const output = lastFrame();
193
- globalExpect(output).toContain("\u26A0");
236
+ globalExpect(output).not.toContain("\u26A0");
194
237
  });
195
- it("should show disabled symbol for disabled options", () => {
238
+ it("should show disabled options with dimmed styling", () => {
196
239
  const categories = [
197
240
  createCategory("test", "Test", [
198
241
  createOption("opt1", "Option 1"),
@@ -202,37 +245,76 @@ describe("CategoryGrid component", () => {
202
245
  const { lastFrame, unmount } = renderGrid({ categories });
203
246
  cleanup = unmount;
204
247
  const output = lastFrame();
205
- globalExpect(output).toContain("\u2717");
248
+ globalExpect(output).toContain("Option 2");
249
+ });
250
+ });
251
+ describe("locked sections", () => {
252
+ it("should show all categories including locked ones", () => {
253
+ const { lastFrame, unmount } = renderGrid();
254
+ cleanup = unmount;
255
+ const output = lastFrame();
256
+ globalExpect(output).toContain("Framework");
257
+ globalExpect(output).toContain("Styling");
258
+ globalExpect(output).toContain("Client State");
259
+ });
260
+ it("should unlock sections when framework is selected", () => {
261
+ const { lastFrame, unmount } = renderGrid({
262
+ categories: categoriesWithFramework
263
+ });
264
+ cleanup = unmount;
265
+ const output = lastFrame();
266
+ globalExpect(output).toContain("Framework");
267
+ globalExpect(output).toContain("Styling");
268
+ globalExpect(output).toContain("Client State");
269
+ });
270
+ it("should not lock any sections when no framework category exists", () => {
271
+ const categoriesNoFramework = [
272
+ createCategory("styling", "Styling", [
273
+ createOption("scss", "SCSS"),
274
+ createOption("tailwind", "Tailwind")
275
+ ]),
276
+ createCategory("state", "State", [createOption("zustand", "Zustand")])
277
+ ];
278
+ const { lastFrame, unmount } = renderGrid({
279
+ categories: categoriesNoFramework
280
+ });
281
+ cleanup = unmount;
282
+ const output = lastFrame();
283
+ globalExpect(output).toContain("Styling");
284
+ globalExpect(output).toContain("State");
206
285
  });
207
286
  });
208
287
  describe("focus indicator", () => {
209
- it("should show focus indicator (>) on focused option", () => {
288
+ it("should render focused option with label text", () => {
210
289
  const { lastFrame, unmount } = renderGrid({
211
290
  focusedRow: 0,
212
291
  focusedCol: 0
213
292
  });
214
293
  cleanup = unmount;
215
294
  const output = lastFrame();
216
- globalExpect(output).toContain(">");
295
+ globalExpect(output).toContain("React");
217
296
  });
218
- it("should update focus indicator when focusedRow changes", () => {
297
+ it("should render correctly when focusedRow changes", () => {
219
298
  const { lastFrame: frame1, unmount: unmount1 } = renderGrid({
299
+ categories: categoriesWithFramework,
220
300
  focusedRow: 0,
221
301
  focusedCol: 0
222
302
  });
223
303
  const output1 = frame1();
224
304
  unmount1();
225
305
  const { lastFrame: frame2, unmount: unmount2 } = renderGrid({
306
+ categories: categoriesWithFramework,
226
307
  focusedRow: 1,
227
308
  focusedCol: 0
228
309
  });
229
310
  cleanup = unmount2;
230
311
  const output2 = frame2();
231
- globalExpect(output1).toContain(">");
232
- globalExpect(output2).toContain(">");
312
+ globalExpect(output1).toContain("Framework");
313
+ globalExpect(output2).toContain("Styling");
233
314
  });
234
315
  it("should highlight focused category name", () => {
235
316
  const { lastFrame, unmount } = renderGrid({
317
+ categories: categoriesWithFramework,
236
318
  focusedRow: 1,
237
319
  focusedCol: 0
238
320
  });
@@ -268,10 +350,10 @@ describe("CategoryGrid component", () => {
268
350
  await delay(INPUT_DELAY_MS);
269
351
  globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
270
352
  });
271
- it("should call onFocusChange when pressing up arrow", async () => {
353
+ it("should call onFocusChange when pressing up arrow (wraps to framework when locked)", async () => {
272
354
  const onFocusChange = vi.fn();
273
355
  const { stdin, unmount } = renderGrid({
274
- focusedRow: 1,
356
+ focusedRow: 0,
275
357
  focusedCol: 0,
276
358
  onFocusChange
277
359
  });
@@ -281,9 +363,10 @@ describe("CategoryGrid component", () => {
281
363
  await delay(INPUT_DELAY_MS);
282
364
  globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
283
365
  });
284
- it("should call onFocusChange when pressing down arrow", async () => {
366
+ it("should navigate between sections when unlocked", async () => {
285
367
  const onFocusChange = vi.fn();
286
368
  const { stdin, unmount } = renderGrid({
369
+ categories: categoriesWithFramework,
287
370
  focusedRow: 0,
288
371
  focusedCol: 0,
289
372
  onFocusChange
@@ -321,9 +404,10 @@ describe("CategoryGrid component", () => {
321
404
  await delay(INPUT_DELAY_MS);
322
405
  globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
323
406
  });
324
- it("should wrap vertically when pressing up at first row", async () => {
407
+ it("should wrap vertically when all sections are unlocked", async () => {
325
408
  const onFocusChange = vi.fn();
326
409
  const { stdin, unmount } = renderGrid({
410
+ categories: categoriesWithFramework,
327
411
  focusedRow: 0,
328
412
  focusedCol: 0,
329
413
  onFocusChange
@@ -332,21 +416,7 @@ describe("CategoryGrid component", () => {
332
416
  await delay(RENDER_DELAY_MS);
333
417
  await stdin.write(ARROW_UP);
334
418
  await delay(INPUT_DELAY_MS);
335
- globalExpect(onFocusChange).toHaveBeenCalledWith(4, 0);
336
- });
337
- it("should wrap vertically when pressing down at last row", async () => {
338
- const onFocusChange = vi.fn();
339
- const { stdin, unmount } = renderGrid({
340
- focusedRow: 4,
341
- // Last category (analytics)
342
- focusedCol: 0,
343
- onFocusChange
344
- });
345
- cleanup = unmount;
346
- await delay(RENDER_DELAY_MS);
347
- await stdin.write(ARROW_DOWN);
348
- await delay(INPUT_DELAY_MS);
349
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
419
+ globalExpect(onFocusChange).toHaveBeenCalledWith(2, 0);
350
420
  });
351
421
  });
352
422
  describe("keyboard navigation - vim keys", () => {
@@ -379,6 +449,7 @@ describe("CategoryGrid component", () => {
379
449
  it("should move up with k key", async () => {
380
450
  const onFocusChange = vi.fn();
381
451
  const { stdin, unmount } = renderGrid({
452
+ categories: categoriesWithFramework,
382
453
  focusedRow: 1,
383
454
  focusedCol: 0,
384
455
  onFocusChange
@@ -392,6 +463,7 @@ describe("CategoryGrid component", () => {
392
463
  it("should move down with j key", async () => {
393
464
  const onFocusChange = vi.fn();
394
465
  const { stdin, unmount } = renderGrid({
466
+ categories: categoriesWithFramework,
395
467
  focusedRow: 0,
396
468
  focusedCol: 0,
397
469
  onFocusChange
@@ -420,10 +492,22 @@ describe("CategoryGrid component", () => {
420
492
  });
421
493
  it("should call onToggle when pressing space on a selected option", async () => {
422
494
  const onToggle = vi.fn();
495
+ const categories = [
496
+ createCategory(
497
+ "framework",
498
+ "Framework",
499
+ [
500
+ createOption("react", "React", { selected: true }),
501
+ createOption("vue", "Vue")
502
+ ],
503
+ { required: true }
504
+ )
505
+ ];
423
506
  const { stdin, unmount } = renderGrid({
424
- focusedRow: 1,
507
+ categories,
508
+ focusedRow: 0,
425
509
  focusedCol: 0,
426
- // scss-mod (selected) - first in expert mode
510
+ // react (selected)
427
511
  expertMode: true,
428
512
  onToggle
429
513
  });
@@ -431,7 +515,7 @@ describe("CategoryGrid component", () => {
431
515
  await delay(RENDER_DELAY_MS);
432
516
  await stdin.write(" ");
433
517
  await delay(INPUT_DELAY_MS);
434
- globalExpect(onToggle).toHaveBeenCalledWith("styling", "scss-mod");
518
+ globalExpect(onToggle).toHaveBeenCalledWith("framework", "react");
435
519
  });
436
520
  it("should NOT call onToggle when pressing space on a disabled option", async () => {
437
521
  const onToggle = vi.fn();
@@ -455,6 +539,20 @@ describe("CategoryGrid component", () => {
455
539
  await delay(INPUT_DELAY_MS);
456
540
  globalExpect(onToggle).not.toHaveBeenCalled();
457
541
  });
542
+ it("should NOT call onToggle when section is locked", async () => {
543
+ const onToggle = vi.fn();
544
+ const { stdin, unmount } = renderGrid({
545
+ focusedRow: 1,
546
+ // Styling (locked)
547
+ focusedCol: 0,
548
+ onToggle
549
+ });
550
+ cleanup = unmount;
551
+ await delay(RENDER_DELAY_MS);
552
+ await stdin.write(" ");
553
+ await delay(INPUT_DELAY_MS);
554
+ globalExpect(onToggle).not.toHaveBeenCalled();
555
+ });
458
556
  });
459
557
  describe("disabled options navigation", () => {
460
558
  it("should skip disabled options when navigating right", async () => {
@@ -532,15 +630,44 @@ describe("CategoryGrid component", () => {
532
630
  globalExpect(output).toContain("Framework");
533
631
  });
534
632
  });
633
+ describe("tab navigation", () => {
634
+ it("should jump to next section when pressing Tab", async () => {
635
+ const onFocusChange = vi.fn();
636
+ const { stdin, unmount } = renderGrid({
637
+ categories: categoriesWithFramework,
638
+ focusedRow: 0,
639
+ focusedCol: 0,
640
+ onFocusChange
641
+ });
642
+ cleanup = unmount;
643
+ await delay(RENDER_DELAY_MS);
644
+ await stdin.write(TAB);
645
+ await delay(INPUT_DELAY_MS);
646
+ globalExpect(onFocusChange).toHaveBeenCalledWith(1, 0);
647
+ });
648
+ it("should only jump to unlocked sections", async () => {
649
+ const onFocusChange = vi.fn();
650
+ const { stdin, unmount } = renderGrid({
651
+ focusedRow: 0,
652
+ focusedCol: 0,
653
+ onFocusChange
654
+ });
655
+ cleanup = unmount;
656
+ await delay(RENDER_DELAY_MS);
657
+ await stdin.write(TAB);
658
+ await delay(INPUT_DELAY_MS);
659
+ globalExpect(onFocusChange).not.toHaveBeenCalled();
660
+ });
661
+ });
535
662
  describe("show descriptions toggle", () => {
536
- it("should call onToggleDescriptions when pressing Tab", async () => {
663
+ it("should call onToggleDescriptions when pressing d key", async () => {
537
664
  const onToggleDescriptions = vi.fn();
538
665
  const { stdin, unmount } = renderGrid({
539
666
  onToggleDescriptions
540
667
  });
541
668
  cleanup = unmount;
542
669
  await delay(RENDER_DELAY_MS);
543
- await stdin.write(TAB);
670
+ await stdin.write("d");
544
671
  await delay(INPUT_DELAY_MS);
545
672
  globalExpect(onToggleDescriptions).toHaveBeenCalled();
546
673
  });
@@ -567,8 +694,8 @@ describe("CategoryGrid component", () => {
567
694
  });
568
695
  cleanup = unmount2;
569
696
  const output2 = frame2();
570
- globalExpect(output1).toContain("Show descriptions: OFF");
571
- globalExpect(output2).toContain("Show descriptions: ON");
697
+ globalExpect(output1).toContain("Descriptions: OFF");
698
+ globalExpect(output2).toContain("Descriptions: ON");
572
699
  });
573
700
  });
574
701
  describe("expert mode toggle", () => {
@@ -647,7 +774,7 @@ describe("CategoryGrid component", () => {
647
774
  const output = lastFrame();
648
775
  globalExpect(output).toContain("Only Option");
649
776
  });
650
- it("should handle category with many options", () => {
777
+ it("should handle category with many options (flows naturally)", () => {
651
778
  const options = Array.from(
652
779
  { length: 10 },
653
780
  (_, i) => createOption(`opt${i}`, `Option ${i}`)
@@ -665,14 +792,14 @@ describe("CategoryGrid component", () => {
665
792
  it("should handle long option labels", () => {
666
793
  const categories = [
667
794
  createCategory("long", "Long Labels", [
668
- createOption("long1", "very-long-option-name-here"),
669
- createOption("long2", "another-very-long-option")
795
+ createOption("long1", "Very Long Option Name"),
796
+ createOption("long2", "Another Long Name")
670
797
  ])
671
798
  ];
672
799
  const { lastFrame, unmount } = renderGrid({ categories });
673
800
  cleanup = unmount;
674
801
  const output = lastFrame();
675
- globalExpect(output).toContain("very-long-option-name-here");
802
+ globalExpect(output).toContain("Very Long Option Name");
676
803
  });
677
804
  it("should handle categories with different option counts", () => {
678
805
  const categories = [
@@ -701,11 +828,17 @@ describe("CategoryGrid component", () => {
701
828
  it("should adjust focusedCol when changing to row with fewer options", async () => {
702
829
  const onFocusChange = vi.fn();
703
830
  const categories = [
704
- createCategory("cat1", "Category 1", [
705
- createOption("opt1", "Option 1"),
706
- createOption("opt2", "Option 2"),
707
- createOption("opt3", "Option 3")
708
- ]),
831
+ createCategory(
832
+ "framework",
833
+ "Framework",
834
+ [
835
+ createOption("opt1", "Option 1", { selected: true }),
836
+ // Framework selected
837
+ createOption("opt2", "Option 2"),
838
+ createOption("opt3", "Option 3")
839
+ ],
840
+ { required: true }
841
+ ),
709
842
  createCategory("cat2", "Category 2", [
710
843
  createOption("opt4", "Option 4")
711
844
  ])