agents-inc 0.151.0 → 0.152.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 (253) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/{chunk-YA4QQKKE.js → chunk-5GUOIJSG.js} +3 -7
  3. package/dist/{chunk-YA4QQKKE.js.map → chunk-5GUOIJSG.js.map} +1 -1
  4. package/dist/{chunk-44LLPS2N.js → chunk-5UWKOOIS.js} +6 -26
  5. package/dist/chunk-5UWKOOIS.js.map +1 -0
  6. package/dist/{chunk-O5ASLZ2K.js → chunk-76ADG7LQ.js} +1 -5
  7. package/dist/{chunk-O5ASLZ2K.js.map → chunk-76ADG7LQ.js.map} +1 -1
  8. package/dist/{chunk-WK4J2CHH.js → chunk-BNSRA6HL.js} +13 -18
  9. package/dist/{chunk-WK4J2CHH.js.map → chunk-BNSRA6HL.js.map} +1 -1
  10. package/dist/{chunk-FYPUUYSG.js → chunk-DTSG5XZB.js} +3 -7
  11. package/dist/{chunk-FYPUUYSG.js.map → chunk-DTSG5XZB.js.map} +1 -1
  12. package/dist/{chunk-NGLQ5W7U.js → chunk-E5X6RJ4E.js} +5 -15
  13. package/dist/chunk-E5X6RJ4E.js.map +1 -0
  14. package/dist/{chunk-TVHRMRD3.js → chunk-EEPELKOM.js} +4008 -4084
  15. package/dist/chunk-EEPELKOM.js.map +1 -0
  16. package/dist/{chunk-NIKUMXE7.js → chunk-F7T5AFFN.js} +1 -5
  17. package/dist/{chunk-NIKUMXE7.js.map → chunk-F7T5AFFN.js.map} +1 -1
  18. package/dist/{chunk-LAXAQ3PZ.js → chunk-FVDKAVOL.js} +10 -14
  19. package/dist/{chunk-LAXAQ3PZ.js.map → chunk-FVDKAVOL.js.map} +1 -1
  20. package/dist/{chunk-BNE4HHIH.js → chunk-GRVKW3CC.js} +2 -6
  21. package/dist/{chunk-BNE4HHIH.js.map → chunk-GRVKW3CC.js.map} +1 -1
  22. package/dist/{chunk-3XFUQ6OL.js → chunk-IHUY4M22.js} +4 -8
  23. package/dist/{chunk-3XFUQ6OL.js.map → chunk-IHUY4M22.js.map} +1 -1
  24. package/dist/{chunk-OZZGXBCN.js → chunk-IUQBOCSU.js} +1 -5
  25. package/dist/{chunk-OZZGXBCN.js.map → chunk-IUQBOCSU.js.map} +1 -1
  26. package/dist/{chunk-LYYXX2W5.js → chunk-J27W6TXS.js} +4 -6
  27. package/dist/{chunk-LYYXX2W5.js.map → chunk-J27W6TXS.js.map} +1 -1
  28. package/dist/chunk-JFLVEFFP.js +16 -0
  29. package/dist/chunk-JFLVEFFP.js.map +1 -0
  30. package/dist/{chunk-PV2HNW4I.js → chunk-KFB5CRXZ.js} +7 -12
  31. package/dist/{chunk-PV2HNW4I.js.map → chunk-KFB5CRXZ.js.map} +1 -1
  32. package/dist/{chunk-SYUOXSPU.js → chunk-KR65TPKC.js} +168 -14
  33. package/dist/chunk-KR65TPKC.js.map +1 -0
  34. package/dist/{chunk-KOPEM3Q7.js → chunk-KXYVJGJP.js} +2 -6
  35. package/dist/{chunk-KOPEM3Q7.js.map → chunk-KXYVJGJP.js.map} +1 -1
  36. package/dist/{chunk-TYJLR32W.js → chunk-L7SZXUBJ.js} +9 -14
  37. package/dist/{chunk-TYJLR32W.js.map → chunk-L7SZXUBJ.js.map} +1 -1
  38. package/dist/{chunk-NHCGC6DG.js → chunk-LASI35KT.js} +4 -9
  39. package/dist/{chunk-NHCGC6DG.js.map → chunk-LASI35KT.js.map} +1 -1
  40. package/dist/{chunk-VG2TVBFN.js → chunk-LDP5ASDM.js} +2 -6
  41. package/dist/{chunk-VG2TVBFN.js.map → chunk-LDP5ASDM.js.map} +1 -1
  42. package/dist/{chunk-5V2O6C3T.js → chunk-LZ52XEPR.js} +4 -8
  43. package/dist/{chunk-5V2O6C3T.js.map → chunk-LZ52XEPR.js.map} +1 -1
  44. package/dist/{chunk-WFWCZEMS.js → chunk-M7HO7NBK.js} +4 -8
  45. package/dist/{chunk-WFWCZEMS.js.map → chunk-M7HO7NBK.js.map} +1 -1
  46. package/dist/{chunk-XA57SX4T.js → chunk-MJ2KHG24.js} +4 -8
  47. package/dist/{chunk-XA57SX4T.js.map → chunk-MJ2KHG24.js.map} +1 -1
  48. package/dist/{chunk-DAG2ULNF.js → chunk-MM7CTTAV.js} +2 -6
  49. package/dist/chunk-MM7CTTAV.js.map +1 -0
  50. package/dist/{chunk-UFURYGD3.js → chunk-MQ7FLIYS.js} +2 -6
  51. package/dist/{chunk-UFURYGD3.js.map → chunk-MQ7FLIYS.js.map} +1 -1
  52. package/dist/{chunk-SI5FOARI.js → chunk-MVR3SYMN.js} +6 -8
  53. package/dist/chunk-MVR3SYMN.js.map +1 -0
  54. package/dist/{chunk-UTFN6UJS.js → chunk-MWG4VU64.js} +12 -17
  55. package/dist/{chunk-UTFN6UJS.js.map → chunk-MWG4VU64.js.map} +1 -1
  56. package/dist/{chunk-ES3NJZON.js → chunk-NR3OZGL4.js} +1 -5
  57. package/dist/{chunk-ES3NJZON.js.map → chunk-NR3OZGL4.js.map} +1 -1
  58. package/dist/{chunk-GYG5SE2D.js → chunk-ODNDXQH2.js} +2 -6
  59. package/dist/{chunk-GYG5SE2D.js.map → chunk-ODNDXQH2.js.map} +1 -1
  60. package/dist/{chunk-2RSNKBXC.js → chunk-P44SXVH3.js} +6 -10
  61. package/dist/{chunk-2RSNKBXC.js.map → chunk-P44SXVH3.js.map} +1 -1
  62. package/dist/{chunk-3LIU2ZEF.js → chunk-PMM2MYMA.js} +3 -16
  63. package/dist/{chunk-3LIU2ZEF.js.map → chunk-PMM2MYMA.js.map} +1 -1
  64. package/dist/{chunk-QTFQEYDA.js → chunk-PZIZNMHK.js} +24 -36
  65. package/dist/chunk-PZIZNMHK.js.map +1 -0
  66. package/dist/{chunk-C55DN7GE.js → chunk-Q2KG7UV3.js} +3 -5
  67. package/dist/chunk-Q2KG7UV3.js.map +1 -0
  68. package/dist/{chunk-QQLRX4KI.js → chunk-Q45ZU6HD.js} +2 -6
  69. package/dist/{chunk-QQLRX4KI.js.map → chunk-Q45ZU6HD.js.map} +1 -1
  70. package/dist/{chunk-6RBQBOBS.js → chunk-QRDTLVXG.js} +9 -14
  71. package/dist/{chunk-6RBQBOBS.js.map → chunk-QRDTLVXG.js.map} +1 -1
  72. package/dist/{chunk-YBVA7GPW.js → chunk-QZZJFYUQ.js} +3 -7
  73. package/dist/{chunk-YBVA7GPW.js.map → chunk-QZZJFYUQ.js.map} +1 -1
  74. package/dist/{chunk-OJIESW5B.js → chunk-R5NOI2LP.js} +13 -17
  75. package/dist/{chunk-OJIESW5B.js.map → chunk-R5NOI2LP.js.map} +1 -1
  76. package/dist/{chunk-DUVWGO6E.js → chunk-RNJWAKMO.js} +3 -7
  77. package/dist/{chunk-DUVWGO6E.js.map → chunk-RNJWAKMO.js.map} +1 -1
  78. package/dist/{chunk-4R6PGHQQ.js → chunk-SBHBBZKF.js} +7 -23
  79. package/dist/chunk-SBHBBZKF.js.map +1 -0
  80. package/dist/{chunk-NM3EDGB5.js → chunk-SKQWRUPX.js} +10 -14
  81. package/dist/{chunk-NM3EDGB5.js.map → chunk-SKQWRUPX.js.map} +1 -1
  82. package/dist/{chunk-Y4CXDA3I.js → chunk-STMHDOZD.js} +4 -21
  83. package/dist/chunk-STMHDOZD.js.map +1 -0
  84. package/dist/{chunk-SHHOMVWC.js → chunk-SX5H6TSC.js} +7 -11
  85. package/dist/chunk-SX5H6TSC.js.map +1 -0
  86. package/dist/{chunk-RBHYLCUB.js → chunk-TJJPWUMA.js} +2 -6
  87. package/dist/{chunk-RBHYLCUB.js.map → chunk-TJJPWUMA.js.map} +1 -1
  88. package/dist/{chunk-IOJR5TOY.js → chunk-TSIU7DME.js} +1 -5
  89. package/dist/{chunk-IOJR5TOY.js.map → chunk-TSIU7DME.js.map} +1 -1
  90. package/dist/{chunk-EVXG3X6G.js → chunk-TUPYW2IQ.js} +3 -7
  91. package/dist/{chunk-EVXG3X6G.js.map → chunk-TUPYW2IQ.js.map} +1 -1
  92. package/dist/{chunk-YU2VGX5R.js → chunk-UBEDZ4FD.js} +1 -8
  93. package/dist/{chunk-YU2VGX5R.js.map → chunk-UBEDZ4FD.js.map} +1 -1
  94. package/dist/{chunk-VEP23B5W.js → chunk-VASLW636.js} +1 -5
  95. package/dist/{chunk-VEP23B5W.js.map → chunk-VASLW636.js.map} +1 -1
  96. package/dist/{chunk-PG4G4IIK.js → chunk-VY6MNOXL.js} +2 -6
  97. package/dist/{chunk-PG4G4IIK.js.map → chunk-VY6MNOXL.js.map} +1 -1
  98. package/dist/{chunk-IHO75PMZ.js → chunk-WBCPLH66.js} +15 -13
  99. package/dist/chunk-WBCPLH66.js.map +1 -0
  100. package/dist/{chunk-DG2NGZ7S.js → chunk-WKTHWQKM.js} +2 -7
  101. package/dist/{chunk-DG2NGZ7S.js.map → chunk-WKTHWQKM.js.map} +1 -1
  102. package/dist/{chunk-EZ7STXUV.js → chunk-XHUODHZ4.js} +19 -25
  103. package/dist/{chunk-EZ7STXUV.js.map → chunk-XHUODHZ4.js.map} +1 -1
  104. package/dist/{chunk-KIR7VYQD.js → chunk-XVAQG2CV.js} +1 -5
  105. package/dist/{chunk-KIR7VYQD.js.map → chunk-XVAQG2CV.js.map} +1 -1
  106. package/dist/{chunk-P3PN5SVI.js → chunk-ZL7PFNHN.js} +2 -6
  107. package/dist/{chunk-P3PN5SVI.js.map → chunk-ZL7PFNHN.js.map} +1 -1
  108. package/dist/{chunk-3YGUHWLR.js → chunk-ZPPHXXAP.js} +9 -15
  109. package/dist/{chunk-3YGUHWLR.js.map → chunk-ZPPHXXAP.js.map} +1 -1
  110. package/dist/commands/build/marketplace.js +10 -15
  111. package/dist/commands/build/marketplace.js.map +1 -1
  112. package/dist/commands/build/plugins.js +9 -14
  113. package/dist/commands/build/plugins.js.map +1 -1
  114. package/dist/commands/compile.js +14 -19
  115. package/dist/commands/compile.js.map +1 -1
  116. package/dist/commands/doctor.js +13 -18
  117. package/dist/commands/doctor.js.map +1 -1
  118. package/dist/commands/edit.js +51 -55
  119. package/dist/commands/edit.js.map +1 -1
  120. package/dist/commands/eject.js +13 -18
  121. package/dist/commands/eject.js.map +1 -1
  122. package/dist/commands/import/skill.js +9 -14
  123. package/dist/commands/import/skill.js.map +1 -1
  124. package/dist/commands/init.js +50 -51
  125. package/dist/commands/list.js +14 -16
  126. package/dist/commands/list.js.map +1 -1
  127. package/dist/commands/new/agent.js +12 -16
  128. package/dist/commands/new/agent.js.map +1 -1
  129. package/dist/commands/new/marketplace.js +15 -20
  130. package/dist/commands/new/marketplace.js.map +1 -1
  131. package/dist/commands/new/skill.js +11 -13
  132. package/dist/commands/search.js +14 -19
  133. package/dist/commands/search.js.map +1 -1
  134. package/dist/commands/uninstall.js +17 -21
  135. package/dist/commands/uninstall.js.map +1 -1
  136. package/dist/commands/update.js +17 -21
  137. package/dist/commands/update.js.map +1 -1
  138. package/dist/commands/validate.js +10 -16
  139. package/dist/commands/validate.js.map +1 -1
  140. package/dist/components/common/confirm.js +1 -2
  141. package/dist/components/common/prompt-confirm.js +2 -2
  142. package/dist/components/common/select-list.js +3 -4
  143. package/dist/components/common/spinner.js +1 -2
  144. package/dist/components/wizard/category-grid.js +8 -9
  145. package/dist/components/wizard/checkbox-grid.js +6 -7
  146. package/dist/components/wizard/domain-selection.js +14 -15
  147. package/dist/components/wizard/run-wizard-session.js +40 -40
  148. package/dist/components/wizard/scroll-affordance.js +2 -3
  149. package/dist/components/wizard/search-modal.js +6 -7
  150. package/dist/components/wizard/selection-card.js +2 -3
  151. package/dist/components/wizard/skill-agent-summary.js +8 -9
  152. package/dist/components/wizard/source-grid.js +13 -14
  153. package/dist/components/wizard/stack-selection.js +12 -13
  154. package/dist/components/wizard/step-agents.js +14 -15
  155. package/dist/components/wizard/step-build.js +14 -15
  156. package/dist/components/wizard/step-confirm.js +13 -14
  157. package/dist/components/wizard/step-settings.js +11 -12
  158. package/dist/components/wizard/step-sources.js +20 -21
  159. package/dist/components/wizard/step-stack.js +13 -14
  160. package/dist/components/wizard/summary-panel.js +12 -13
  161. package/dist/components/wizard/toast.js +2 -3
  162. package/dist/components/wizard/wizard-layout.js +18 -19
  163. package/dist/components/wizard/wizard-tabs.js +8 -9
  164. package/dist/components/wizard/wizard.js +38 -39
  165. package/dist/config-exports.js +1 -7
  166. package/dist/config-exports.js.map +1 -1
  167. package/dist/copy-local-skills-6EMVN7RB.js +14 -0
  168. package/dist/hooks/init.js +50 -54
  169. package/dist/hooks/init.js.map +1 -1
  170. package/dist/index.js +0 -4
  171. package/dist/index.js.map +1 -1
  172. package/dist/load-agent-defs-BWOUVEAR.js +15 -0
  173. package/dist/{loader-E2ERJYVA.js → loader-5JP4S7CJ.js} +4 -5
  174. package/dist/recompile-project-agents-6DL45TDI.js +19 -0
  175. package/dist/{source-loader-5UNRU7EZ.js → source-loader-MZYCPL2S.js} +7 -8
  176. package/dist/stores/wizard-store.js +7 -8
  177. package/package.json +15 -14
  178. package/dist/chunk-44LLPS2N.js.map +0 -1
  179. package/dist/chunk-4R6PGHQQ.js.map +0 -1
  180. package/dist/chunk-7QIHKQL5.js +0 -181
  181. package/dist/chunk-7QIHKQL5.js.map +0 -1
  182. package/dist/chunk-C55DN7GE.js.map +0 -1
  183. package/dist/chunk-DAG2ULNF.js.map +0 -1
  184. package/dist/chunk-DIBCRIMR.js +0 -36
  185. package/dist/chunk-DIBCRIMR.js.map +0 -1
  186. package/dist/chunk-EKWAUOQB.js +0 -96
  187. package/dist/chunk-EKWAUOQB.js.map +0 -1
  188. package/dist/chunk-I3XKEGHM.js +0 -16383
  189. package/dist/chunk-I3XKEGHM.js.map +0 -1
  190. package/dist/chunk-IHO75PMZ.js.map +0 -1
  191. package/dist/chunk-K3OU6TGX.js +0 -77
  192. package/dist/chunk-K3OU6TGX.js.map +0 -1
  193. package/dist/chunk-KSZ6PCY4.js +0 -43
  194. package/dist/chunk-KSZ6PCY4.js.map +0 -1
  195. package/dist/chunk-NGLQ5W7U.js.map +0 -1
  196. package/dist/chunk-P56WJ5FA.js +0 -50
  197. package/dist/chunk-P56WJ5FA.js.map +0 -1
  198. package/dist/chunk-QTFQEYDA.js.map +0 -1
  199. package/dist/chunk-SHHOMVWC.js.map +0 -1
  200. package/dist/chunk-SI5FOARI.js.map +0 -1
  201. package/dist/chunk-SYUOXSPU.js.map +0 -1
  202. package/dist/chunk-THKIOI32.js +0 -939
  203. package/dist/chunk-THKIOI32.js.map +0 -1
  204. package/dist/chunk-TVHRMRD3.js.map +0 -1
  205. package/dist/chunk-V7QOSGQA.js +0 -298
  206. package/dist/chunk-V7QOSGQA.js.map +0 -1
  207. package/dist/chunk-Y4CXDA3I.js.map +0 -1
  208. package/dist/components/common/confirm.test.js +0 -203
  209. package/dist/components/common/confirm.test.js.map +0 -1
  210. package/dist/components/wizard/category-grid.test.js +0 -1253
  211. package/dist/components/wizard/category-grid.test.js.map +0 -1
  212. package/dist/components/wizard/checkbox-grid.test.js +0 -264
  213. package/dist/components/wizard/checkbox-grid.test.js.map +0 -1
  214. package/dist/components/wizard/search-modal.test.js +0 -212
  215. package/dist/components/wizard/search-modal.test.js.map +0 -1
  216. package/dist/components/wizard/source-grid.test.js +0 -1094
  217. package/dist/components/wizard/source-grid.test.js.map +0 -1
  218. package/dist/components/wizard/step-agents.test.js +0 -204
  219. package/dist/components/wizard/step-agents.test.js.map +0 -1
  220. package/dist/components/wizard/step-build.test.js +0 -552
  221. package/dist/components/wizard/step-build.test.js.map +0 -1
  222. package/dist/components/wizard/step-confirm.test.js +0 -744
  223. package/dist/components/wizard/step-confirm.test.js.map +0 -1
  224. package/dist/components/wizard/step-settings.test.js +0 -244
  225. package/dist/components/wizard/step-settings.test.js.map +0 -1
  226. package/dist/components/wizard/step-sources.test.js +0 -155
  227. package/dist/components/wizard/step-sources.test.js.map +0 -1
  228. package/dist/components/wizard/step-stack.test.js +0 -262
  229. package/dist/components/wizard/step-stack.test.js.map +0 -1
  230. package/dist/components/wizard/summary-panel.test.js +0 -317
  231. package/dist/components/wizard/summary-panel.test.js.map +0 -1
  232. package/dist/components/wizard/wizard-layout.test.js +0 -200
  233. package/dist/components/wizard/wizard-layout.test.js.map +0 -1
  234. package/dist/components/wizard/wizard-tabs.test.js +0 -290
  235. package/dist/components/wizard/wizard-tabs.test.js.map +0 -1
  236. package/dist/copy-local-skills-UPA2GUZV.js +0 -15
  237. package/dist/dist-VNJNNJK7.js +0 -550
  238. package/dist/dist-VNJNNJK7.js.map +0 -1
  239. package/dist/load-agent-defs-SB4XAOVB.js +0 -16
  240. package/dist/magic-string.es-5TV73NJD.js +0 -1316
  241. package/dist/magic-string.es-5TV73NJD.js.map +0 -1
  242. package/dist/recompile-project-agents-U4ZY2GDX.js +0 -20
  243. package/dist/source-manager-3O54SIIB.js +0 -18
  244. package/dist/source-manager-3O54SIIB.js.map +0 -1
  245. package/dist/stores/d227-same-scope-tombstone-duplicate.test.js +0 -118
  246. package/dist/stores/d227-same-scope-tombstone-duplicate.test.js.map +0 -1
  247. package/dist/stores/wizard-store.test.js +0 -3053
  248. package/dist/stores/wizard-store.test.js.map +0 -1
  249. /package/dist/{copy-local-skills-UPA2GUZV.js.map → copy-local-skills-6EMVN7RB.js.map} +0 -0
  250. /package/dist/{load-agent-defs-SB4XAOVB.js.map → load-agent-defs-BWOUVEAR.js.map} +0 -0
  251. /package/dist/{loader-E2ERJYVA.js.map → loader-5JP4S7CJ.js.map} +0 -0
  252. /package/dist/{recompile-project-agents-U4ZY2GDX.js.map → recompile-project-agents-6DL45TDI.js.map} +0 -0
  253. /package/dist/{source-loader-5UNRU7EZ.js.map → source-loader-MZYCPL2S.js.map} +0 -0
@@ -1,3053 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- buildAgentConfigs,
4
- buildSkillConfigs
5
- } from "../chunk-DIBCRIMR.js";
6
- import {
7
- ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX,
8
- ALL_SKILLS_TEST_CATEGORIES_MATRIX,
9
- ALL_SKILLS_WEB_AND_API_MATRIX,
10
- REACT_HONO_FRAMEWORK_API_MATRIX,
11
- REACT_HONO_WEB_API_DOMAINS_MATRIX
12
- } from "../chunk-THKIOI32.js";
13
- import "../chunk-K3OU6TGX.js";
14
- import {
15
- SKILLS,
16
- TEST_CATEGORIES,
17
- createMockMatrix
18
- } from "../chunk-V7QOSGQA.js";
19
- import {
20
- beforeEach,
21
- describe,
22
- globalExpect,
23
- it
24
- } from "../chunk-I3XKEGHM.js";
25
- import "../chunk-EZ7STXUV.js";
26
- import "../chunk-UTFN6UJS.js";
27
- import "../chunk-EVXG3X6G.js";
28
- import "../chunk-OJIESW5B.js";
29
- import "../chunk-UFURYGD3.js";
30
- import "../chunk-RBHYLCUB.js";
31
- import "../chunk-LAXAQ3PZ.js";
32
- import "../chunk-NM3EDGB5.js";
33
- import "../chunk-NHCGC6DG.js";
34
- import "../chunk-BNE4HHIH.js";
35
- import "../chunk-TYJLR32W.js";
36
- import "../chunk-IOJR5TOY.js";
37
- import "../chunk-3YGUHWLR.js";
38
- import "../chunk-QQLRX4KI.js";
39
- import "../chunk-WK4J2CHH.js";
40
- import "../chunk-NIKUMXE7.js";
41
- import "../chunk-KOPEM3Q7.js";
42
- import "../chunk-2RSNKBXC.js";
43
- import "../chunk-DUVWGO6E.js";
44
- import "../chunk-KIR7VYQD.js";
45
- import "../chunk-6RBQBOBS.js";
46
- import "../chunk-LYYXX2W5.js";
47
- import "../chunk-SHHOMVWC.js";
48
- import "../chunk-YA4QQKKE.js";
49
- import "../chunk-XA57SX4T.js";
50
- import "../chunk-FYPUUYSG.js";
51
- import "../chunk-DAG2ULNF.js";
52
- import "../chunk-VG2TVBFN.js";
53
- import "../chunk-IHO75PMZ.js";
54
- import "../chunk-5V2O6C3T.js";
55
- import {
56
- hydrateWizardStore,
57
- useWizardStore
58
- } from "../chunk-44LLPS2N.js";
59
- import "../chunk-P3PN5SVI.js";
60
- import "../chunk-TVHRMRD3.js";
61
- import "../chunk-3LIU2ZEF.js";
62
- import {
63
- initializeMatrix
64
- } from "../chunk-DG2NGZ7S.js";
65
- import {
66
- typedKeys
67
- } from "../chunk-VEP23B5W.js";
68
- import "../chunk-O5ASLZ2K.js";
69
- import "../chunk-YU2VGX5R.js";
70
- import {
71
- init_esm_shims
72
- } from "../chunk-P56WJ5FA.js";
73
-
74
- // src/cli/stores/wizard-store.test.ts
75
- init_esm_shims();
76
-
77
- // src/cli/lib/__tests__/expected-values.ts
78
- init_esm_shims();
79
- var EXPECTED_AGENTS = {
80
- WEB: [
81
- "web-architecture",
82
- "web-developer",
83
- "web-pm",
84
- "web-researcher",
85
- "web-reviewer",
86
- "web-tester"
87
- ],
88
- API: ["api-developer", "api-researcher", "api-reviewer"],
89
- CLI: ["cli-developer", "cli-reviewer", "cli-tester"],
90
- get WEB_AND_API() {
91
- return [...this.API, ...this.WEB].sort();
92
- },
93
- get ALL() {
94
- return [...this.API, ...this.CLI, ...this.WEB].sort();
95
- }
96
- };
97
-
98
- // src/cli/stores/wizard-store.test.ts
99
- describe("WizardStore", () => {
100
- beforeEach(() => {
101
- initializeMatrix(ALL_SKILLS_TEST_CATEGORIES_MATRIX);
102
- });
103
- describe("initial state", () => {
104
- it("should start at stack step", () => {
105
- const { step } = useWizardStore.getState();
106
- globalExpect(step).toBe("stack");
107
- });
108
- it("should have no approach selected", () => {
109
- const { approach } = useWizardStore.getState();
110
- globalExpect(approach).toBeNull();
111
- });
112
- it("should have no selected stack", () => {
113
- const { selectedStackId } = useWizardStore.getState();
114
- globalExpect(selectedStackId).toBeNull();
115
- });
116
- it("should have empty skillConfigs", () => {
117
- const { skillConfigs } = useWizardStore.getState();
118
- globalExpect(skillConfigs).toStrictEqual([]);
119
- });
120
- it("should have null focusedSkillId", () => {
121
- const { focusedSkillId } = useWizardStore.getState();
122
- globalExpect(focusedSkillId).toBeNull();
123
- });
124
- it("should have empty unresolvableSkillIds", () => {
125
- const { unresolvableSkillIds } = useWizardStore.getState();
126
- globalExpect(unresolvableSkillIds).toStrictEqual([]);
127
- });
128
- it("should have empty navigation history", () => {
129
- const { history } = useWizardStore.getState();
130
- globalExpect(history).toStrictEqual([]);
131
- });
132
- it("should have empty selected domains", () => {
133
- const { selectedDomains } = useWizardStore.getState();
134
- globalExpect(selectedDomains).toStrictEqual([]);
135
- });
136
- it("should have empty domain selections", () => {
137
- const { domainSelections } = useWizardStore.getState();
138
- globalExpect(domainSelections).toStrictEqual({});
139
- });
140
- });
141
- describe("step navigation", () => {
142
- it("should update step with setStep", () => {
143
- const store = useWizardStore.getState();
144
- store.setStep("stack");
145
- const { step } = useWizardStore.getState();
146
- globalExpect(step).toBe("stack");
147
- });
148
- it("should track navigation history when setting step", () => {
149
- const store = useWizardStore.getState();
150
- store.setStep("build");
151
- store.setStep("confirm");
152
- const { history } = useWizardStore.getState();
153
- globalExpect(history).toStrictEqual(["stack", "build"]);
154
- });
155
- it("should go back through history", () => {
156
- const store = useWizardStore.getState();
157
- store.setStep("build");
158
- store.setStep("confirm");
159
- store.goBack();
160
- const { step, history } = useWizardStore.getState();
161
- globalExpect(step).toBe("build");
162
- globalExpect(history).toStrictEqual(["stack"]);
163
- });
164
- it("when goBack is called with empty history, should no-op", () => {
165
- const store = useWizardStore.getState();
166
- store.setStep("build");
167
- store.goBack();
168
- const afterFirstGoBack = useWizardStore.getState();
169
- globalExpect(afterFirstGoBack.step).toBe("stack");
170
- globalExpect(afterFirstGoBack.history).toStrictEqual([]);
171
- store.goBack();
172
- const afterSecondGoBack = useWizardStore.getState();
173
- globalExpect(afterSecondGoBack.step).toBe("stack");
174
- globalExpect(afterSecondGoBack.history).toStrictEqual([]);
175
- });
176
- it("goBack from a mid-wizard step with empty history is a no-op", () => {
177
- useWizardStore.setState({ step: "build", history: [] });
178
- useWizardStore.getState().goBack();
179
- const { step, history } = useWizardStore.getState();
180
- globalExpect(step).toBe("build");
181
- globalExpect(history).toStrictEqual([]);
182
- });
183
- });
184
- describe("approach selection", () => {
185
- it("should set approach to stack", () => {
186
- const store = useWizardStore.getState();
187
- store.setApproach("stack");
188
- const { approach } = useWizardStore.getState();
189
- globalExpect(approach).toBe("stack");
190
- });
191
- it("should set approach to scratch", () => {
192
- const store = useWizardStore.getState();
193
- store.setApproach("scratch");
194
- const { approach } = useWizardStore.getState();
195
- globalExpect(approach).toBe("scratch");
196
- });
197
- });
198
- describe("stack selection", () => {
199
- it("should select stack by id", () => {
200
- const store = useWizardStore.getState();
201
- store.selectStack("nextjs-fullstack");
202
- const state = useWizardStore.getState();
203
- globalExpect(state.selectedStackId).toBe("nextjs-fullstack");
204
- globalExpect(state.domainSelections).toStrictEqual({});
205
- globalExpect(state.selectedDomains).toStrictEqual([]);
206
- globalExpect(state.skillConfigs).toStrictEqual([]);
207
- globalExpect(state.selectedAgents).toStrictEqual([]);
208
- globalExpect(state.boundSkills).toStrictEqual([]);
209
- globalExpect(state.stackAction).toBeNull();
210
- });
211
- it("when selectStack is called with null, should clear previously selected stack and selections", () => {
212
- const store = useWizardStore.getState();
213
- store.selectStack("nextjs-fullstack");
214
- store.toggleDomain("web");
215
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
216
- store.selectStack(null);
217
- const state = useWizardStore.getState();
218
- globalExpect(state.selectedStackId).toBeNull();
219
- globalExpect(state.domainSelections).toStrictEqual({});
220
- globalExpect(state.selectedDomains).toStrictEqual([]);
221
- globalExpect(state.skillConfigs).toStrictEqual([]);
222
- globalExpect(state.selectedAgents).toStrictEqual([]);
223
- globalExpect(state.boundSkills).toStrictEqual([]);
224
- globalExpect(state.currentDomainIndex).toBe(0);
225
- globalExpect(state.stackAction).toBeNull();
226
- });
227
- it("should clear previous selections when changing from one stack to another", () => {
228
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
229
- const store = useWizardStore.getState();
230
- store.populateFromSkillIds(["web-framework-react", "api-framework-hono"]);
231
- const stateAfterFirst = useWizardStore.getState();
232
- globalExpect(typedKeys(stateAfterFirst.domainSelections)).toStrictEqual(["web", "api"]);
233
- store.selectStack(null);
234
- const stateAfterClear = useWizardStore.getState();
235
- globalExpect(stateAfterClear.selectedStackId).toBeNull();
236
- globalExpect(stateAfterClear.domainSelections).toStrictEqual({});
237
- globalExpect(stateAfterClear.selectedDomains).toStrictEqual([]);
238
- globalExpect(stateAfterClear.skillConfigs).toStrictEqual([]);
239
- globalExpect(stateAfterClear.selectedAgents).toStrictEqual([]);
240
- globalExpect(stateAfterClear.boundSkills).toStrictEqual([]);
241
- globalExpect(stateAfterClear.stackAction).toBeNull();
242
- });
243
- });
244
- describe("domain selection", () => {
245
- it("should toggle domain on", () => {
246
- const store = useWizardStore.getState();
247
- store.toggleDomain("web");
248
- const { selectedDomains, domainSelections } = useWizardStore.getState();
249
- globalExpect(selectedDomains).toStrictEqual(["web"]);
250
- globalExpect(domainSelections).toStrictEqual({});
251
- });
252
- it("should toggle domain off", () => {
253
- const store = useWizardStore.getState();
254
- store.toggleDomain("web");
255
- store.toggleDomain("web");
256
- const { selectedDomains, domainSelections, skillConfigs } = useWizardStore.getState();
257
- globalExpect(selectedDomains).toStrictEqual([]);
258
- globalExpect(domainSelections).toStrictEqual({});
259
- globalExpect(skillConfigs).toStrictEqual([]);
260
- });
261
- it("should allow multiple domain selection", () => {
262
- const store = useWizardStore.getState();
263
- store.toggleDomain("web");
264
- store.toggleDomain("api");
265
- store.toggleDomain("cli");
266
- const { selectedDomains } = useWizardStore.getState();
267
- globalExpect(selectedDomains).toStrictEqual(["web", "api", "cli"]);
268
- });
269
- it("should remove skills from deselected domain", () => {
270
- const store = useWizardStore.getState();
271
- store.toggleDomain("web");
272
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
273
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
274
- store.toggleDomain("web");
275
- const { domainSelections, selectedDomains, skillConfigs } = useWizardStore.getState();
276
- globalExpect(domainSelections.web).toBeUndefined();
277
- globalExpect(selectedDomains).toStrictEqual([]);
278
- globalExpect(skillConfigs).toStrictEqual([]);
279
- globalExpect(store.getAllSelectedTechnologies()).toStrictEqual([]);
280
- globalExpect(store.getTechnologyCount()).toBe(0);
281
- });
282
- it("should not affect skills in other domains when deselecting a domain", () => {
283
- const store = useWizardStore.getState();
284
- store.toggleDomain("web");
285
- store.toggleDomain("api");
286
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
287
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
288
- store.toggleDomain("web");
289
- const { domainSelections, selectedDomains, skillConfigs } = useWizardStore.getState();
290
- globalExpect(selectedDomains).toStrictEqual(["api"]);
291
- globalExpect(domainSelections.web).toBeUndefined();
292
- globalExpect(domainSelections.api["api-api"]).toStrictEqual(["api-framework-hono"]);
293
- globalExpect(skillConfigs).toStrictEqual(
294
- buildSkillConfigs(["api-framework-hono"], { scope: "global", source: "agents-inc" })
295
- );
296
- globalExpect(store.getAllSelectedTechnologies()).toStrictEqual(["api-framework-hono"]);
297
- });
298
- it("should not auto-select skills when toggling domain on", () => {
299
- const store = useWizardStore.getState();
300
- store.toggleDomain("web");
301
- const { domainSelections, skillConfigs } = useWizardStore.getState();
302
- globalExpect(domainSelections.web).toBeUndefined();
303
- globalExpect(skillConfigs).toStrictEqual([]);
304
- globalExpect(store.getAllSelectedTechnologies()).toStrictEqual([]);
305
- });
306
- it("should reflect correct technology count after domain deselection", () => {
307
- const store = useWizardStore.getState();
308
- store.toggleDomain("web");
309
- store.toggleDomain("api");
310
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
311
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
312
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
313
- globalExpect(store.getTechnologyCount()).toBe(3);
314
- store.toggleDomain("web");
315
- globalExpect(store.getTechnologyCount()).toBe(1);
316
- globalExpect(store.getAllSelectedTechnologies()).toStrictEqual(["api-framework-hono"]);
317
- });
318
- it("should restore stack skills when re-toggling a domain ON after populateFromSkillIds", () => {
319
- const store = useWizardStore.getState();
320
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
321
- store.populateFromSkillIds(["web-framework-react", "api-framework-hono"]);
322
- store.toggleDomain("web");
323
- globalExpect(useWizardStore.getState().domainSelections.web).toBeUndefined();
324
- store.toggleDomain("web");
325
- const { domainSelections } = useWizardStore.getState();
326
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
327
- });
328
- it("should not restore skills when no stack was populated", () => {
329
- const store = useWizardStore.getState();
330
- store.toggleDomain("web");
331
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
332
- store.toggleDomain("web");
333
- store.toggleDomain("web");
334
- const { domainSelections } = useWizardStore.getState();
335
- globalExpect(domainSelections.web).toBeUndefined();
336
- globalExpect(store.getAllSelectedTechnologies()).toStrictEqual([]);
337
- });
338
- });
339
- describe("technology selection", () => {
340
- it("should toggle technology in exclusive mode", () => {
341
- const store = useWizardStore.getState();
342
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
343
- const { domainSelections, skillConfigs } = useWizardStore.getState();
344
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
345
- globalExpect(skillConfigs).toStrictEqual(
346
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
347
- );
348
- });
349
- it("should replace technology in exclusive mode", () => {
350
- const store = useWizardStore.getState();
351
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
352
- store.toggleTechnology("web", "web-framework", "web-framework-vue-composition-api", true);
353
- const { domainSelections, skillConfigs } = useWizardStore.getState();
354
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual([
355
- "web-framework-vue-composition-api"
356
- ]);
357
- globalExpect(skillConfigs).toStrictEqual(
358
- buildSkillConfigs(["web-framework-vue-composition-api"], {
359
- scope: "global",
360
- source: "agents-inc"
361
- })
362
- );
363
- });
364
- it("should toggle off technology in exclusive mode", () => {
365
- const store = useWizardStore.getState();
366
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
367
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
368
- const { domainSelections, skillConfigs } = useWizardStore.getState();
369
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual([]);
370
- globalExpect(skillConfigs).toStrictEqual([]);
371
- });
372
- it("should allow multiple selections in non-exclusive mode", () => {
373
- const store = useWizardStore.getState();
374
- store.toggleTechnology("web", "web-testing", "web-testing-vitest", false);
375
- store.toggleTechnology("web", "web-testing", "web-testing-playwright-e2e", false);
376
- const { domainSelections, skillConfigs } = useWizardStore.getState();
377
- globalExpect(domainSelections.web["web-testing"]).toStrictEqual([
378
- "web-testing-vitest",
379
- "web-testing-playwright-e2e"
380
- ]);
381
- globalExpect(skillConfigs).toStrictEqual(
382
- buildSkillConfigs(["web-testing-vitest", "web-testing-playwright-e2e"], {
383
- scope: "global",
384
- source: "agents-inc"
385
- })
386
- );
387
- });
388
- it("should toggle off technology in non-exclusive mode", () => {
389
- const store = useWizardStore.getState();
390
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", false);
391
- store.toggleTechnology("web", "web-styling", "web-styling-tailwind", false);
392
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", false);
393
- const { domainSelections, skillConfigs } = useWizardStore.getState();
394
- globalExpect(domainSelections.web["web-styling"]).toStrictEqual(["web-styling-tailwind"]);
395
- globalExpect(skillConfigs).toStrictEqual(
396
- buildSkillConfigs(["web-styling-tailwind"], { scope: "global", source: "agents-inc" })
397
- );
398
- });
399
- it("should block toggling globally installed skills from project scope and set toastMessage", () => {
400
- const store = useWizardStore.getState();
401
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
402
- useWizardStore.setState({
403
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], { scope: "global" }),
404
- isEditingFromGlobalScope: false,
405
- isInitMode: false
406
- });
407
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
408
- const { domainSelections, toastMessage } = useWizardStore.getState();
409
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
410
- globalExpect(toastMessage).toBe("Global skills cannot be changed from project scope");
411
- });
412
- it("should block toggling globally installed skills in init mode too, with the same toastMessage", () => {
413
- const store = useWizardStore.getState();
414
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
415
- useWizardStore.setState({
416
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], { scope: "global" }),
417
- isEditingFromGlobalScope: false,
418
- isInitMode: true
419
- });
420
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
421
- const { domainSelections, skillConfigs, toastMessage } = useWizardStore.getState();
422
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
423
- globalExpect(
424
- skillConfigs,
425
- "a blocked deselect must leave the global entry active \u2014 no tombstone"
426
- ).toStrictEqual(
427
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
428
- );
429
- globalExpect(toastMessage).toBe("Global skills cannot be changed from project scope");
430
- });
431
- it("should block selecting a different skill in an exclusive category when it would implicitly deselect a global skill", () => {
432
- const store = useWizardStore.getState();
433
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", true);
434
- useWizardStore.setState({
435
- installedSkillConfigs: buildSkillConfigs(["web-state-zustand"], { scope: "global" }),
436
- isEditingFromGlobalScope: false,
437
- isInitMode: false
438
- });
439
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", true);
440
- const { domainSelections, toastMessage } = useWizardStore.getState();
441
- globalExpect(domainSelections.web["web-client-state"]).toStrictEqual(["web-state-zustand"]);
442
- globalExpect(toastMessage).toBe("Global skills cannot be changed from project scope");
443
- });
444
- it("should allow selecting a different skill in an exclusive category when editing from global scope", () => {
445
- const store = useWizardStore.getState();
446
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", true);
447
- useWizardStore.setState({
448
- installedSkillConfigs: buildSkillConfigs(["web-state-zustand"], { scope: "global" }),
449
- isEditingFromGlobalScope: true,
450
- isInitMode: false
451
- });
452
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", true);
453
- const { domainSelections, toastMessage } = useWizardStore.getState();
454
- globalExpect(domainSelections.web["web-client-state"]).toStrictEqual(["web-state-pinia"]);
455
- globalExpect(toastMessage).toBeNull();
456
- });
457
- it("should block deselecting the only skill in an exclusive+required category", () => {
458
- const m = createMockMatrix(...Object.values(SKILLS));
459
- m.categories["api-api"] = { ...TEST_CATEGORIES.api, required: true };
460
- initializeMatrix(m);
461
- const store = useWizardStore.getState();
462
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
463
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
464
- const { domainSelections, toastMessage } = useWizardStore.getState();
465
- globalExpect(domainSelections.api["api-api"]).toStrictEqual(["api-framework-hono"]);
466
- globalExpect(toastMessage).toBe("Cannot deselect the only skill in this category");
467
- });
468
- it("should allow deselecting the only skill in a non-required category", () => {
469
- const store = useWizardStore.getState();
470
- store.toggleTechnology("web", "web-testing", "web-testing-vitest", false);
471
- store.toggleTechnology("web", "web-testing", "web-testing-vitest", false);
472
- const { domainSelections, toastMessage } = useWizardStore.getState();
473
- globalExpect(domainSelections.web["web-testing"]).toStrictEqual([]);
474
- globalExpect(toastMessage).toBeNull();
475
- });
476
- it("should allow deselecting in a category with multiple skills", () => {
477
- const store = useWizardStore.getState();
478
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
479
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
480
- const { domainSelections, toastMessage } = useWizardStore.getState();
481
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual([]);
482
- globalExpect(toastMessage).toBeNull();
483
- });
484
- it("should allow selecting in a single-skill category", () => {
485
- const store = useWizardStore.getState();
486
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
487
- const { domainSelections, toastMessage } = useWizardStore.getState();
488
- globalExpect(domainSelections.api["api-api"]).toStrictEqual(["api-framework-hono"]);
489
- globalExpect(toastMessage).toBeNull();
490
- });
491
- });
492
- describe("domain navigation", () => {
493
- it("should move to next domain", () => {
494
- const store = useWizardStore.getState();
495
- store.toggleDomain("web");
496
- store.toggleDomain("api");
497
- const result = store.nextDomain();
498
- const { currentDomainIndex } = useWizardStore.getState();
499
- globalExpect(result).toBe(true);
500
- globalExpect(currentDomainIndex).toBe(1);
501
- });
502
- it("when already at the last domain, should return false from nextDomain", () => {
503
- const store = useWizardStore.getState();
504
- store.toggleDomain("web");
505
- const result = store.nextDomain();
506
- globalExpect(result).toBe(false);
507
- });
508
- it("should move to previous domain", () => {
509
- const store = useWizardStore.getState();
510
- store.toggleDomain("web");
511
- store.toggleDomain("api");
512
- store.nextDomain();
513
- const result = store.prevDomain();
514
- const { currentDomainIndex } = useWizardStore.getState();
515
- globalExpect(result).toBe(true);
516
- globalExpect(currentDomainIndex).toBe(0);
517
- });
518
- it("when already at the first domain, should return false from prevDomain", () => {
519
- const store = useWizardStore.getState();
520
- store.toggleDomain("web");
521
- const result = store.prevDomain();
522
- globalExpect(result).toBe(false);
523
- });
524
- it("should get current domain", () => {
525
- const store = useWizardStore.getState();
526
- store.toggleDomain("web");
527
- store.toggleDomain("api");
528
- store.nextDomain();
529
- const domain = store.getCurrentDomain();
530
- globalExpect(domain).toBe("api");
531
- });
532
- it("should return null when no domains selected", () => {
533
- const store = useWizardStore.getState();
534
- const domain = store.getCurrentDomain();
535
- globalExpect(domain).toBeNull();
536
- });
537
- });
538
- describe("seedFocusedSkillForActiveDomain", () => {
539
- beforeEach(() => {
540
- initializeMatrix(REACT_HONO_WEB_API_DOMAINS_MATRIX);
541
- });
542
- it("seeds focusedSkillId to the active domain's first grid option on build-step entry", () => {
543
- const store = useWizardStore.getState();
544
- store.toggleDomain("web");
545
- store.toggleDomain("api");
546
- store.setStep("build");
547
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
548
- });
549
- it("re-seeds focusedSkillId to the new domain's first grid option on domain advance", () => {
550
- const store = useWizardStore.getState();
551
- store.toggleDomain("web");
552
- store.toggleDomain("api");
553
- store.setStep("build");
554
- store.nextDomain();
555
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("api-framework-hono");
556
- });
557
- it("re-seeds focusedSkillId back to the previous domain's first grid option on domain retreat", () => {
558
- const store = useWizardStore.getState();
559
- store.toggleDomain("web");
560
- store.toggleDomain("api");
561
- store.setStep("build");
562
- store.nextDomain();
563
- store.prevDomain();
564
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
565
- });
566
- it("seeds the fallback domain's first grid option when no domains are selected", () => {
567
- const store = useWizardStore.getState();
568
- store.seedFocusedSkillForActiveDomain();
569
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
570
- });
571
- });
572
- describe("mode toggles", () => {
573
- it("should toggle show labels", () => {
574
- const store = useWizardStore.getState();
575
- store.toggleShowLabels();
576
- const { showLabels } = useWizardStore.getState();
577
- globalExpect(showLabels).toBe(true);
578
- });
579
- it("should toggle info on", () => {
580
- const store = useWizardStore.getState();
581
- store.toggleInfo();
582
- const { showInfo } = useWizardStore.getState();
583
- globalExpect(showInfo).toBe(true);
584
- });
585
- it("should toggle info off (show then hide)", () => {
586
- const store = useWizardStore.getState();
587
- store.toggleInfo();
588
- store.toggleInfo();
589
- const { showInfo } = useWizardStore.getState();
590
- globalExpect(showInfo).toBe(false);
591
- });
592
- it("should toggle settings on", () => {
593
- const store = useWizardStore.getState();
594
- store.toggleSettings();
595
- const { showSettings } = useWizardStore.getState();
596
- globalExpect(showSettings).toBe(true);
597
- });
598
- it("should toggle settings off (show then hide)", () => {
599
- const store = useWizardStore.getState();
600
- store.toggleSettings();
601
- store.toggleSettings();
602
- const { showSettings } = useWizardStore.getState();
603
- globalExpect(showSettings).toBe(false);
604
- });
605
- it("should start with showInfo false", () => {
606
- const { showInfo } = useWizardStore.getState();
607
- globalExpect(showInfo).toBe(false);
608
- });
609
- it("should start with showSettings false", () => {
610
- const { showSettings } = useWizardStore.getState();
611
- globalExpect(showSettings).toBe(false);
612
- });
613
- it("should reset showInfo to false after reset", () => {
614
- const store = useWizardStore.getState();
615
- store.toggleInfo();
616
- store.reset();
617
- const { showInfo } = useWizardStore.getState();
618
- globalExpect(showInfo).toBe(false);
619
- });
620
- it("should reset showSettings to false after reset", () => {
621
- const store = useWizardStore.getState();
622
- store.toggleSettings();
623
- store.reset();
624
- const { showSettings } = useWizardStore.getState();
625
- globalExpect(showSettings).toBe(false);
626
- });
627
- });
628
- describe("skillConfigs and per-skill scope", () => {
629
- it("should sync skillConfigs when toggling a technology on", () => {
630
- const store = useWizardStore.getState();
631
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
632
- const { skillConfigs } = useWizardStore.getState();
633
- globalExpect(skillConfigs).toHaveLength(1);
634
- globalExpect(skillConfigs[0]).toStrictEqual(
635
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })[0]
636
- );
637
- });
638
- it("should remove global skill when toggling off during fresh init (no installed configs)", () => {
639
- const store = useWizardStore.getState();
640
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
641
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
642
- const { skillConfigs } = useWizardStore.getState();
643
- globalExpect(skillConfigs).toHaveLength(0);
644
- });
645
- it("removes a global skill cleanly (no tombstone) when toggled off while editing from global scope", () => {
646
- const store = useWizardStore.getState();
647
- useWizardStore.setState({
648
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
649
- scope: "global",
650
- source: "agents-inc"
651
- }),
652
- isEditingFromGlobalScope: true
653
- });
654
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
655
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
656
- const { skillConfigs } = useWizardStore.getState();
657
- globalExpect(skillConfigs).toStrictEqual([]);
658
- });
659
- it("should remove old global skill in exclusive mode during fresh init and add new skill", () => {
660
- const store = useWizardStore.getState();
661
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
662
- store.toggleTechnology("web", "web-framework", "web-framework-vue-composition-api", true);
663
- const { skillConfigs } = useWizardStore.getState();
664
- globalExpect(skillConfigs).toStrictEqual(
665
- buildSkillConfigs(["web-framework-vue-composition-api"], {
666
- scope: "global",
667
- source: "agents-inc"
668
- })
669
- );
670
- });
671
- it("removes the old global skill cleanly (no tombstone) in exclusive mode while editing from global scope and adds the new skill", () => {
672
- const store = useWizardStore.getState();
673
- useWizardStore.setState({
674
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
675
- scope: "global",
676
- source: "agents-inc"
677
- }),
678
- isEditingFromGlobalScope: true
679
- });
680
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
681
- store.toggleTechnology("web", "web-framework", "web-framework-vue-composition-api", true);
682
- const { skillConfigs } = useWizardStore.getState();
683
- globalExpect(skillConfigs).toStrictEqual(
684
- buildSkillConfigs(["web-framework-vue-composition-api"], {
685
- scope: "global",
686
- source: "agents-inc"
687
- })
688
- );
689
- });
690
- it("cleanly re-adds a global skill when re-selected while editing from global scope", () => {
691
- const store = useWizardStore.getState();
692
- useWizardStore.setState({
693
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
694
- scope: "global",
695
- source: "agents-inc"
696
- }),
697
- isEditingFromGlobalScope: true
698
- });
699
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
700
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
701
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual([]);
702
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
703
- const { skillConfigs } = useWizardStore.getState();
704
- globalExpect(skillConfigs).toStrictEqual(
705
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
706
- );
707
- });
708
- it("restores the persisted project scope and eject source when a project-only skill is deselected and re-selected in one session", () => {
709
- const store = useWizardStore.getState();
710
- const persisted = buildSkillConfigs(["web-framework-react"], {
711
- scope: "project",
712
- source: "eject"
713
- });
714
- useWizardStore.setState({
715
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
716
- skillConfigs: persisted,
717
- installedSkillConfigs: persisted,
718
- isEditingFromGlobalScope: false,
719
- isInitMode: false
720
- });
721
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
722
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual([]);
723
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
724
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual(persisted);
725
- });
726
- it("adds a genuinely new skill at wizard defaults when the hydration snapshot has no entry for it", () => {
727
- const store = useWizardStore.getState();
728
- useWizardStore.setState({
729
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
730
- scope: "project",
731
- source: "eject"
732
- }),
733
- isEditingFromGlobalScope: false,
734
- isInitMode: false
735
- });
736
- store.toggleTechnology("web", "web-testing", "web-testing-vitest", false);
737
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual(
738
- buildSkillConfigs(["web-testing-vitest"], { scope: "global", source: "agents-inc" })
739
- );
740
- });
741
- describe("dual-scope selection toggle", () => {
742
- const dualScopeConfigs = () => [
743
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
744
- ...buildSkillConfigs(["web-framework-react"], {
745
- scope: "global",
746
- source: "agents-inc",
747
- excluded: true
748
- })
749
- ];
750
- it("leaves a dual-scope skill untouched when the selection key is pressed and emits the global-locked toast", () => {
751
- const store = useWizardStore.getState();
752
- useWizardStore.setState({
753
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
754
- skillConfigs: dualScopeConfigs(),
755
- installedSkillConfigs: dualScopeConfigs(),
756
- isEditingFromGlobalScope: false,
757
- isInitMode: false
758
- });
759
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
760
- const { skillConfigs, domainSelections, toastMessage } = useWizardStore.getState();
761
- globalExpect(toastMessage).toBe("Global skills cannot be changed from project scope");
762
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
763
- globalExpect(skillConfigs).toStrictEqual(dualScopeConfigs());
764
- });
765
- it("leaves a dual-scope skill untouched when an exclusive-category sibling would replace it", () => {
766
- const store = useWizardStore.getState();
767
- useWizardStore.setState({
768
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
769
- skillConfigs: dualScopeConfigs(),
770
- installedSkillConfigs: dualScopeConfigs(),
771
- isEditingFromGlobalScope: false,
772
- isInitMode: false
773
- });
774
- store.toggleTechnology("web", "web-framework", "web-framework-vue-composition-api", true);
775
- const { skillConfigs, domainSelections, toastMessage } = useWizardStore.getState();
776
- globalExpect(toastMessage).toBe("Global skills cannot be changed from project scope");
777
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
778
- globalExpect(skillConfigs).toStrictEqual(dualScopeConfigs());
779
- });
780
- it("restores [P][G] when re-selecting an inherited-global row (fresh project entry AND tombstone)", () => {
781
- const store = useWizardStore.getState();
782
- useWizardStore.setState({
783
- domainSelections: { web: { "web-framework": [] } },
784
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
785
- scope: "global",
786
- source: "agents-inc"
787
- }),
788
- installedSkillConfigs: dualScopeConfigs(),
789
- isEditingFromGlobalScope: false,
790
- isInitMode: false
791
- });
792
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
793
- const { skillConfigs, domainSelections, toastMessage } = useWizardStore.getState();
794
- globalExpect(toastMessage).toBeNull();
795
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
796
- globalExpect(skillConfigs).toStrictEqual(dualScopeConfigs());
797
- });
798
- it("restores [P][G] cleanly (no two active entries) via `s` after the collapse is saved and re-opened", () => {
799
- const store = useWizardStore.getState();
800
- useWizardStore.setState({
801
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
802
- skillConfigs: dualScopeConfigs(),
803
- installedSkillConfigs: dualScopeConfigs(),
804
- isEditingFromGlobalScope: false,
805
- isInitMode: false
806
- });
807
- store.toggleSkillScope("web-framework-react");
808
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual(
809
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
810
- );
811
- useWizardStore.setState({
812
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
813
- scope: "global",
814
- source: "agents-inc"
815
- }),
816
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
817
- scope: "global",
818
- source: "agents-inc"
819
- })
820
- });
821
- store.toggleSkillScope("web-framework-react");
822
- const { skillConfigs } = useWizardStore.getState();
823
- const activeEntries = skillConfigs.filter((sc) => !sc.excluded);
824
- globalExpect(activeEntries).toStrictEqual(
825
- buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" })
826
- );
827
- globalExpect(skillConfigs.filter((sc) => sc.excluded)).toStrictEqual(
828
- buildSkillConfigs(["web-framework-react"], {
829
- scope: "global",
830
- source: "agents-inc",
831
- excluded: true
832
- })
833
- );
834
- });
835
- it("removes a global-scope skill entirely when deselected from a global-context edit (Scenario C setup)", () => {
836
- const store = useWizardStore.getState();
837
- useWizardStore.setState({
838
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
839
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
840
- scope: "global",
841
- source: "agents-inc"
842
- }),
843
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
844
- scope: "global",
845
- source: "agents-inc"
846
- }),
847
- isEditingFromGlobalScope: true,
848
- isInitMode: false
849
- });
850
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
851
- const { skillConfigs, domainSelections, toastMessage } = useWizardStore.getState();
852
- globalExpect(toastMessage).toBeNull();
853
- globalExpect(domainSelections.web["web-framework"]).toStrictEqual([]);
854
- globalExpect(skillConfigs).toStrictEqual([]);
855
- });
856
- });
857
- it("should accumulate skillConfigs in non-exclusive mode", () => {
858
- const store = useWizardStore.getState();
859
- store.toggleTechnology("web", "web-testing", "web-testing-vitest", false);
860
- store.toggleTechnology("web", "web-testing", "web-testing-playwright-e2e", false);
861
- const { skillConfigs } = useWizardStore.getState();
862
- globalExpect(skillConfigs).toHaveLength(2);
863
- globalExpect(skillConfigs.map((sc) => sc.id)).toStrictEqual([
864
- "web-testing-vitest",
865
- "web-testing-playwright-e2e"
866
- ]);
867
- });
868
- it("should toggle skill scope between global and project", () => {
869
- const store = useWizardStore.getState();
870
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
871
- store.toggleSkillScope("web-framework-react");
872
- const { skillConfigs } = useWizardStore.getState();
873
- globalExpect(skillConfigs[0].scope).toBe("project");
874
- });
875
- it("should toggle skill scope back to global", () => {
876
- const store = useWizardStore.getState();
877
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
878
- store.toggleSkillScope("web-framework-react");
879
- store.toggleSkillScope("web-framework-react");
880
- const { skillConfigs } = useWizardStore.getState();
881
- globalExpect(skillConfigs[0].scope).toBe("global");
882
- });
883
- it("should block project eject to global when global eject already exists and set toastMessage", () => {
884
- const store = useWizardStore.getState();
885
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
886
- useWizardStore.setState({
887
- skillConfigs: buildSkillConfigs(["web-framework-react"]),
888
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
889
- scope: "global",
890
- source: "eject"
891
- })
892
- });
893
- store.toggleSkillScope("web-framework-react");
894
- const { skillConfigs, toastMessage } = useWizardStore.getState();
895
- globalExpect(skillConfigs).toStrictEqual(buildSkillConfigs(["web-framework-react"]));
896
- globalExpect(toastMessage).toBe("Already exists as ejected skill at global scope");
897
- });
898
- it("should allow global eject to project when global eject is installed", () => {
899
- const store = useWizardStore.getState();
900
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
901
- useWizardStore.setState({
902
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
903
- scope: "global",
904
- source: "eject"
905
- }),
906
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
907
- scope: "global",
908
- source: "eject"
909
- })
910
- });
911
- store.toggleSkillScope("web-framework-react");
912
- const { skillConfigs, toastMessage } = useWizardStore.getState();
913
- globalExpect(skillConfigs[0].scope).toBe("project");
914
- globalExpect(toastMessage).toBeNull();
915
- });
916
- it("should allow project eject to global when no global eject exists", () => {
917
- const store = useWizardStore.getState();
918
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
919
- useWizardStore.setState({
920
- skillConfigs: buildSkillConfigs(["web-framework-react"]),
921
- globalPreselections: []
922
- });
923
- store.toggleSkillScope("web-framework-react");
924
- const { skillConfigs, toastMessage } = useWizardStore.getState();
925
- globalExpect(skillConfigs[0].scope).toBe("global");
926
- globalExpect(toastMessage).toBeNull();
927
- });
928
- it("should not toggle skill scope when isEditingFromGlobalScope is true", () => {
929
- const store = useWizardStore.getState();
930
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
931
- useWizardStore.setState({ isEditingFromGlobalScope: true });
932
- store.toggleSkillScope("web-framework-react");
933
- const { skillConfigs } = useWizardStore.getState();
934
- globalExpect(skillConfigs[0].scope).toBe("global");
935
- });
936
- it("should add excluded global entry when toggling previously-installed global skill to project", () => {
937
- const store = useWizardStore.getState();
938
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
939
- useWizardStore.setState({
940
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
941
- scope: "global",
942
- source: "agents-inc"
943
- })
944
- });
945
- store.toggleSkillScope("web-framework-react");
946
- const { skillConfigs } = useWizardStore.getState();
947
- globalExpect(skillConfigs).toStrictEqual([
948
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
949
- ...buildSkillConfigs(["web-framework-react"], {
950
- scope: "global",
951
- source: "agents-inc",
952
- excluded: true
953
- })
954
- ]);
955
- });
956
- it("should remove excluded global entry when toggling back from project to global", () => {
957
- const store = useWizardStore.getState();
958
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
959
- useWizardStore.setState({
960
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
961
- scope: "global",
962
- source: "agents-inc"
963
- })
964
- });
965
- store.toggleSkillScope("web-framework-react");
966
- store.toggleSkillScope("web-framework-react");
967
- const { skillConfigs } = useWizardStore.getState();
968
- globalExpect(skillConfigs).toStrictEqual(
969
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
970
- );
971
- });
972
- it("should not add excluded entry when toggling scope during fresh init", () => {
973
- const store = useWizardStore.getState();
974
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
975
- store.toggleSkillScope("web-framework-react");
976
- const { skillConfigs } = useWizardStore.getState();
977
- globalExpect(skillConfigs).toHaveLength(1);
978
- globalExpect(skillConfigs[0].scope).toBe("project");
979
- });
980
- it("should allow P\u2192G reverse toggle for ejected skills after G\u2192P toggle (round-trip)", () => {
981
- const store = useWizardStore.getState();
982
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
983
- useWizardStore.setState({
984
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
985
- scope: "global",
986
- source: "eject"
987
- }),
988
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
989
- scope: "global",
990
- source: "eject"
991
- })
992
- });
993
- store.toggleSkillScope("web-framework-react");
994
- const afterGtoP = useWizardStore.getState();
995
- globalExpect(afterGtoP.skillConfigs).toStrictEqual([
996
- ...buildSkillConfigs(["web-framework-react"], { source: "eject" }),
997
- ...buildSkillConfigs(["web-framework-react"], {
998
- scope: "global",
999
- source: "eject",
1000
- excluded: true
1001
- })
1002
- ]);
1003
- globalExpect(afterGtoP.toastMessage).toBeNull();
1004
- store.toggleSkillScope("web-framework-react");
1005
- const afterPtoG = useWizardStore.getState();
1006
- globalExpect(afterPtoG.skillConfigs).toStrictEqual(
1007
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "eject" })
1008
- );
1009
- globalExpect(afterPtoG.toastMessage).toBeNull();
1010
- });
1011
- it("round-trips a persisted dual-scope skill row with `s`: collapse to [G], then restore [P][G]", () => {
1012
- const dualScope = () => [
1013
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1014
- ...buildSkillConfigs(["web-framework-react"], {
1015
- scope: "global",
1016
- source: "agents-inc",
1017
- excluded: true
1018
- })
1019
- ];
1020
- const store = useWizardStore.getState();
1021
- useWizardStore.setState({
1022
- skillConfigs: dualScope(),
1023
- installedSkillConfigs: dualScope(),
1024
- isEditingFromGlobalScope: false,
1025
- isInitMode: false,
1026
- toastMessage: null
1027
- });
1028
- store.toggleSkillScope("web-framework-react");
1029
- const first = useWizardStore.getState();
1030
- globalExpect(first.skillConfigs).toStrictEqual(
1031
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
1032
- );
1033
- globalExpect(first.toastMessage).toBeNull();
1034
- store.toggleSkillScope("web-framework-react");
1035
- const second = useWizardStore.getState();
1036
- globalExpect(second.skillConfigs).toStrictEqual(dualScope());
1037
- globalExpect(second.toastMessage).toBeNull();
1038
- });
1039
- it("runs the full in-session blocked-space \u2192 s-collapse \u2192 blocked-space \u2192 s-restore sequence on a persisted [P][G] skill", () => {
1040
- const dualScope = () => [
1041
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1042
- ...buildSkillConfigs(["web-framework-react"], {
1043
- scope: "global",
1044
- source: "agents-inc",
1045
- excluded: true
1046
- })
1047
- ];
1048
- const plainGlobal = () => buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" });
1049
- const store = useWizardStore.getState();
1050
- useWizardStore.setState({
1051
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
1052
- skillConfigs: dualScope(),
1053
- installedSkillConfigs: dualScope(),
1054
- isEditingFromGlobalScope: false,
1055
- isInitMode: false,
1056
- toastMessage: null
1057
- });
1058
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1059
- const afterBlockedSpace = useWizardStore.getState();
1060
- globalExpect(afterBlockedSpace.skillConfigs).toStrictEqual(dualScope());
1061
- globalExpect(afterBlockedSpace.domainSelections.web["web-framework"]).toStrictEqual([
1062
- "web-framework-react"
1063
- ]);
1064
- globalExpect(afterBlockedSpace.toastMessage).toBe(
1065
- "Global skills cannot be changed from project scope"
1066
- );
1067
- useWizardStore.setState({ toastMessage: null });
1068
- store.toggleSkillScope("web-framework-react");
1069
- const afterCollapse = useWizardStore.getState();
1070
- globalExpect(afterCollapse.skillConfigs).toStrictEqual(plainGlobal());
1071
- globalExpect(afterCollapse.domainSelections.web["web-framework"]).toStrictEqual([
1072
- "web-framework-react"
1073
- ]);
1074
- globalExpect(afterCollapse.toastMessage).toBeNull();
1075
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1076
- const afterBlocked = useWizardStore.getState();
1077
- globalExpect(afterBlocked.skillConfigs).toStrictEqual(plainGlobal());
1078
- globalExpect(afterBlocked.toastMessage).toBe("Global skills cannot be changed from project scope");
1079
- useWizardStore.setState({ toastMessage: null });
1080
- store.toggleSkillScope("web-framework-react");
1081
- const afterRestore = useWizardStore.getState();
1082
- globalExpect(afterRestore.skillConfigs).toStrictEqual(dualScope());
1083
- globalExpect(afterRestore.toastMessage).toBeNull();
1084
- store.toggleSkillScope("web-framework-react");
1085
- const afterFlip = useWizardStore.getState();
1086
- globalExpect(afterFlip.skillConfigs).toStrictEqual(plainGlobal());
1087
- globalExpect(afterFlip.toastMessage).toBeNull();
1088
- store.toggleSkillScope("web-framework-react");
1089
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual(dualScope());
1090
- });
1091
- it("writes no tombstone when a project skill re-scoped to global in-session is then deselected", () => {
1092
- const store = useWizardStore.getState();
1093
- useWizardStore.setState({
1094
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1095
- scope: "project",
1096
- source: "agents-inc"
1097
- }),
1098
- isEditingFromGlobalScope: false,
1099
- isInitMode: false,
1100
- toastMessage: null
1101
- });
1102
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1103
- store.toggleSkillScope("web-framework-react");
1104
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual(
1105
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
1106
- );
1107
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1108
- const { skillConfigs } = useWizardStore.getState();
1109
- globalExpect(
1110
- skillConfigs.filter((sc) => sc.excluded),
1111
- "a skill never installed globally must not gain a global tombstone"
1112
- ).toStrictEqual([]);
1113
- globalExpect(skillConfigs).toStrictEqual(
1114
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
1115
- );
1116
- });
1117
- it("should set and clear focusedSkillId", () => {
1118
- const store = useWizardStore.getState();
1119
- store.setFocusedSkillId("web-framework-react");
1120
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
1121
- store.setFocusedSkillId(null);
1122
- globalExpect(useWizardStore.getState().focusedSkillId).toBeNull();
1123
- });
1124
- it("should update source via setSourceSelection on skillConfigs", () => {
1125
- const store = useWizardStore.getState();
1126
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1127
- store.setSourceSelection("web-framework-react", "eject", "global");
1128
- const { skillConfigs } = useWizardStore.getState();
1129
- globalExpect(skillConfigs[0].source).toBe("eject");
1130
- });
1131
- it("should populate skillConfigs from populateFromSkillIds", () => {
1132
- const store = useWizardStore.getState();
1133
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
1134
- store.populateFromSkillIds(["web-framework-react", "api-framework-hono"]);
1135
- const { skillConfigs } = useWizardStore.getState();
1136
- globalExpect(skillConfigs).toHaveLength(2);
1137
- globalExpect(skillConfigs.map((sc) => sc.id)).toStrictEqual([
1138
- "web-framework-react",
1139
- "api-framework-hono"
1140
- ]);
1141
- globalExpect(useWizardStore.getState().unresolvableSkillIds).toStrictEqual([]);
1142
- });
1143
- it("records the ids of installed skills that could not be resolved from the loaded matrix", () => {
1144
- const store = useWizardStore.getState();
1145
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
1146
- store.populateFromSkillIds(["web-framework-react", "web-styling-tailwind"]);
1147
- const state = useWizardStore.getState();
1148
- globalExpect(state.unresolvableSkillIds).toStrictEqual(["web-styling-tailwind"]);
1149
- globalExpect(state.skillConfigs.map((sc) => sc.id)).toStrictEqual(["web-framework-react"]);
1150
- });
1151
- it("should preserve excluded entries from saved configs in populateFromSkillIds", () => {
1152
- const store = useWizardStore.getState();
1153
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
1154
- const savedConfigs = [
1155
- ...buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" }),
1156
- ...buildSkillConfigs(["web-testing-vitest"], {
1157
- scope: "global",
1158
- source: "agents-inc",
1159
- excluded: true
1160
- })
1161
- ];
1162
- store.populateFromSkillIds(["web-framework-react", "api-framework-hono"], savedConfigs);
1163
- const { skillConfigs } = useWizardStore.getState();
1164
- const activeConfigs = skillConfigs.filter((sc) => !sc.excluded);
1165
- const excludedConfigs = skillConfigs.filter((sc) => sc.excluded);
1166
- globalExpect(activeConfigs).toHaveLength(2);
1167
- globalExpect(excludedConfigs).toHaveLength(1);
1168
- globalExpect(excludedConfigs[0].id).toBe("web-testing-vitest");
1169
- globalExpect(excludedConfigs[0].excluded).toBe(true);
1170
- });
1171
- it("preserves excluded tombstone when active entry exists for same skill at different scope", () => {
1172
- const store = useWizardStore.getState();
1173
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
1174
- const savedConfigs = [
1175
- ...buildSkillConfigs(["web-framework-react"]),
1176
- ...buildSkillConfigs(["web-framework-react"], {
1177
- scope: "global",
1178
- excluded: true,
1179
- source: "agents-inc"
1180
- })
1181
- ];
1182
- store.populateFromSkillIds(["web-framework-react", "api-framework-hono"], savedConfigs);
1183
- const { skillConfigs } = useWizardStore.getState();
1184
- const reactConfigs = skillConfigs.filter((sc) => sc.id === "web-framework-react");
1185
- globalExpect(reactConfigs).toHaveLength(2);
1186
- const active = reactConfigs.find((sc) => !sc.excluded);
1187
- const tombstone = reactConfigs.find((sc) => sc.excluded);
1188
- globalExpect(active?.scope).toBe("project");
1189
- globalExpect(tombstone?.scope).toBe("global");
1190
- globalExpect(tombstone?.excluded).toBe(true);
1191
- });
1192
- it("should prefer project-scoped entry when savedConfigs has duplicate skill with both scopes", () => {
1193
- const store = useWizardStore.getState();
1194
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
1195
- const savedConfigs = [
1196
- ...buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" }),
1197
- ...buildSkillConfigs(["web-framework-react"])
1198
- ];
1199
- store.populateFromSkillIds(["web-framework-react"], savedConfigs);
1200
- const { skillConfigs } = useWizardStore.getState();
1201
- const reactConfigs = skillConfigs.filter((sc) => sc.id === "web-framework-react");
1202
- globalExpect(reactConfigs).toHaveLength(1);
1203
- globalExpect(reactConfigs[0]).toStrictEqual(buildSkillConfigs(["web-framework-react"])[0]);
1204
- });
1205
- it("should remove global skillConfigs when domain is deselected during fresh init", () => {
1206
- const store = useWizardStore.getState();
1207
- store.toggleDomain("web");
1208
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1209
- globalExpect(useWizardStore.getState().skillConfigs).toHaveLength(1);
1210
- store.toggleDomain("web");
1211
- const { skillConfigs } = useWizardStore.getState();
1212
- globalExpect(skillConfigs).toHaveLength(0);
1213
- });
1214
- it("removes global skillConfigs cleanly (no tombstone) when a domain is deselected while editing from global scope", () => {
1215
- const store = useWizardStore.getState();
1216
- useWizardStore.setState({
1217
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1218
- scope: "global",
1219
- source: "agents-inc"
1220
- }),
1221
- isEditingFromGlobalScope: true
1222
- });
1223
- store.toggleDomain("web");
1224
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1225
- globalExpect(useWizardStore.getState().skillConfigs).toHaveLength(1);
1226
- store.toggleDomain("web");
1227
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual([]);
1228
- });
1229
- it("should remove project skillConfigs when domain is deselected", () => {
1230
- const store = useWizardStore.getState();
1231
- store.toggleDomain("web");
1232
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1233
- useWizardStore.setState({
1234
- skillConfigs: buildSkillConfigs(["web-framework-react"])
1235
- });
1236
- store.toggleDomain("web");
1237
- globalExpect(useWizardStore.getState().skillConfigs).toHaveLength(0);
1238
- });
1239
- it("should remove project-scoped skill from skillConfigs when toggling off", () => {
1240
- const store = useWizardStore.getState();
1241
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1242
- useWizardStore.setState({
1243
- skillConfigs: buildSkillConfigs(["web-framework-react"])
1244
- });
1245
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1246
- const { skillConfigs } = useWizardStore.getState();
1247
- globalExpect(skillConfigs).toHaveLength(0);
1248
- });
1249
- it("should remove both global and project skills when deselecting domain during fresh init", () => {
1250
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
1251
- const store = useWizardStore.getState();
1252
- store.toggleDomain("web");
1253
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1254
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
1255
- useWizardStore.setState({
1256
- skillConfigs: [
1257
- ...buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" }),
1258
- ...buildSkillConfigs(["web-state-zustand"])
1259
- ]
1260
- });
1261
- store.toggleDomain("web");
1262
- const { skillConfigs } = useWizardStore.getState();
1263
- globalExpect(skillConfigs).toHaveLength(0);
1264
- });
1265
- it("removes both global and project skills cleanly when a domain is deselected while editing from global scope", () => {
1266
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
1267
- const store = useWizardStore.getState();
1268
- useWizardStore.setState({
1269
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1270
- scope: "global",
1271
- source: "agents-inc"
1272
- }),
1273
- isEditingFromGlobalScope: true
1274
- });
1275
- store.toggleDomain("web");
1276
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1277
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
1278
- useWizardStore.setState({
1279
- skillConfigs: [
1280
- ...buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" }),
1281
- ...buildSkillConfigs(["web-state-zustand"])
1282
- ]
1283
- });
1284
- store.toggleDomain("web");
1285
- globalExpect(useWizardStore.getState().skillConfigs).toStrictEqual([]);
1286
- });
1287
- it("leaves every globally installed entry untouched when a domain is deselected at project scope", () => {
1288
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
1289
- const store = useWizardStore.getState();
1290
- store.toggleDomain("web");
1291
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1292
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
1293
- useWizardStore.setState({
1294
- skillConfigs: [
1295
- ...buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" }),
1296
- ...buildSkillConfigs(["web-state-zustand"], { scope: "project", source: "agents-inc" })
1297
- ],
1298
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1299
- scope: "global",
1300
- source: "agents-inc"
1301
- }),
1302
- isEditingFromGlobalScope: false,
1303
- isInitMode: false
1304
- });
1305
- const globalEntriesBefore = useWizardStore.getState().skillConfigs.filter((sc) => sc.scope === "global");
1306
- store.toggleDomain("web");
1307
- const { skillConfigs, selectedDomains, domainSelections } = useWizardStore.getState();
1308
- globalExpect(
1309
- skillConfigs.filter((sc) => sc.scope === "global"),
1310
- "global entries must survive a project-scope domain deselect byte-identical"
1311
- ).toStrictEqual(globalEntriesBefore);
1312
- globalExpect(skillConfigs, "only the domain's project-scoped entries are dropped").toStrictEqual(
1313
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
1314
- );
1315
- globalExpect(selectedDomains).toStrictEqual([]);
1316
- globalExpect(domainSelections.web).toBeUndefined();
1317
- });
1318
- it("collapses a dual-scope pair to one inherited global entry when its domain is deselected", () => {
1319
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
1320
- const dualScope = () => [
1321
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1322
- ...buildSkillConfigs(["web-framework-react"], {
1323
- scope: "global",
1324
- source: "agents-inc",
1325
- excluded: true
1326
- })
1327
- ];
1328
- const store = useWizardStore.getState();
1329
- store.toggleDomain("web");
1330
- useWizardStore.setState({
1331
- domainSelections: { web: { "web-framework": ["web-framework-react"] } },
1332
- skillConfigs: dualScope(),
1333
- installedSkillConfigs: dualScope(),
1334
- isEditingFromGlobalScope: false,
1335
- isInitMode: false
1336
- });
1337
- store.toggleDomain("web");
1338
- const { skillConfigs, selectedDomains, domainSelections } = useWizardStore.getState();
1339
- globalExpect(
1340
- skillConfigs,
1341
- "both halves of the pair are dropped and the still-live global install re-surfaces"
1342
- ).toStrictEqual(
1343
- buildSkillConfigs(["web-framework-react"], { scope: "global", source: "agents-inc" })
1344
- );
1345
- globalExpect(selectedDomains).toStrictEqual([]);
1346
- globalExpect(domainSelections.web).toBeUndefined();
1347
- });
1348
- it("should reset skillConfigs and focusedSkillId on reset", () => {
1349
- const store = useWizardStore.getState();
1350
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1351
- store.setFocusedSkillId("web-framework-react");
1352
- store.reset();
1353
- const state = useWizardStore.getState();
1354
- globalExpect(state.skillConfigs).toStrictEqual([]);
1355
- globalExpect(state.focusedSkillId).toBeNull();
1356
- });
1357
- it("should set all sources to eject via setAllSourcesEject", () => {
1358
- const store = useWizardStore.getState();
1359
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1360
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
1361
- store.setAllSourcesEject();
1362
- const { skillConfigs } = useWizardStore.getState();
1363
- globalExpect(skillConfigs.every((sc) => sc.source === "eject")).toBe(true);
1364
- });
1365
- it("should set all sources to plugin via setAllSourcesPlugin", () => {
1366
- const store = useWizardStore.getState();
1367
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1368
- store.setSourceSelection("web-framework-react", "eject", "global");
1369
- initializeMatrix(
1370
- createMockMatrix({
1371
- ...SKILLS.react,
1372
- availableSources: [{ name: "Acme Corp", type: "private", installed: false }]
1373
- })
1374
- );
1375
- store.setAllSourcesPlugin();
1376
- const { skillConfigs } = useWizardStore.getState();
1377
- globalExpect(skillConfigs[0].source).toBe("Acme Corp");
1378
- });
1379
- it("flips the active entry but leaves an excluded global tombstone's source intact via setAllSourcesEject", () => {
1380
- const store = useWizardStore.getState();
1381
- useWizardStore.setState({
1382
- skillConfigs: [
1383
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1384
- ...buildSkillConfigs(["web-framework-react"], {
1385
- scope: "global",
1386
- source: "agents-inc",
1387
- excluded: true
1388
- })
1389
- ]
1390
- });
1391
- store.setAllSourcesEject();
1392
- const { skillConfigs } = useWizardStore.getState();
1393
- globalExpect(skillConfigs).toStrictEqual([
1394
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "eject" }),
1395
- ...buildSkillConfigs(["web-framework-react"], {
1396
- scope: "global",
1397
- source: "agents-inc",
1398
- excluded: true
1399
- })
1400
- ]);
1401
- });
1402
- it("flips the active entry but leaves an excluded global tombstone's source intact via setAllSourcesPlugin", () => {
1403
- const store = useWizardStore.getState();
1404
- useWizardStore.setState({
1405
- skillConfigs: [
1406
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "eject" }),
1407
- ...buildSkillConfigs(["web-framework-react"], {
1408
- scope: "global",
1409
- source: "agents-inc",
1410
- excluded: true
1411
- })
1412
- ]
1413
- });
1414
- initializeMatrix(
1415
- createMockMatrix({
1416
- ...SKILLS.react,
1417
- availableSources: [{ name: "Acme Corp", type: "private", installed: false }]
1418
- })
1419
- );
1420
- store.setAllSourcesPlugin();
1421
- const { skillConfigs } = useWizardStore.getState();
1422
- globalExpect(skillConfigs).toStrictEqual([
1423
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "Acme Corp" }),
1424
- ...buildSkillConfigs(["web-framework-react"], {
1425
- scope: "global",
1426
- source: "agents-inc",
1427
- excluded: true
1428
- })
1429
- ]);
1430
- });
1431
- });
1432
- describe("computed getters", () => {
1433
- it("should get all selected technologies", () => {
1434
- const store = useWizardStore.getState();
1435
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1436
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
1437
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
1438
- const technologies = store.getAllSelectedTechnologies();
1439
- globalExpect(technologies).toStrictEqual([
1440
- "web-framework-react",
1441
- "web-styling-scss-modules",
1442
- "api-framework-hono"
1443
- ]);
1444
- });
1445
- it("should get selected technologies per domain", () => {
1446
- const store = useWizardStore.getState();
1447
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1448
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
1449
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
1450
- const perDomain = store.getSelectedTechnologiesPerDomain();
1451
- globalExpect(perDomain.web).toStrictEqual(["web-framework-react", "web-styling-scss-modules"]);
1452
- globalExpect(perDomain.api).toStrictEqual(["api-framework-hono"]);
1453
- globalExpect(perDomain.cli).toBeUndefined();
1454
- });
1455
- it("should return empty object for getSelectedTechnologiesPerDomain with no selections", () => {
1456
- const store = useWizardStore.getState();
1457
- const perDomain = store.getSelectedTechnologiesPerDomain();
1458
- globalExpect(perDomain).toStrictEqual({});
1459
- });
1460
- it("should omit domains with empty category arrays from getSelectedTechnologiesPerDomain", () => {
1461
- const store = useWizardStore.getState();
1462
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1463
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1464
- const perDomain = store.getSelectedTechnologiesPerDomain();
1465
- globalExpect(perDomain.web).toBeUndefined();
1466
- });
1467
- it("should get technology count", () => {
1468
- const store = useWizardStore.getState();
1469
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1470
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
1471
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
1472
- globalExpect(store.getTechnologyCount()).toBe(3);
1473
- });
1474
- it("should return 0 for getTechnologyCount with no selections", () => {
1475
- const store = useWizardStore.getState();
1476
- globalExpect(store.getTechnologyCount()).toBe(0);
1477
- });
1478
- });
1479
- describe("navigation guards", () => {
1480
- it("canGoToNextDomain should return true when not at last domain", () => {
1481
- const store = useWizardStore.getState();
1482
- store.toggleDomain("web");
1483
- store.toggleDomain("api");
1484
- globalExpect(store.canGoToNextDomain()).toBe(true);
1485
- });
1486
- it("canGoToNextDomain should return false when at last domain", () => {
1487
- const store = useWizardStore.getState();
1488
- store.toggleDomain("web");
1489
- globalExpect(store.canGoToNextDomain()).toBe(false);
1490
- });
1491
- it("canGoToNextDomain should return false with no domains", () => {
1492
- const store = useWizardStore.getState();
1493
- globalExpect(store.canGoToNextDomain()).toBe(false);
1494
- });
1495
- it("canGoToPreviousDomain should return false when at first domain", () => {
1496
- const store = useWizardStore.getState();
1497
- store.toggleDomain("web");
1498
- store.toggleDomain("api");
1499
- globalExpect(store.canGoToPreviousDomain()).toBe(false);
1500
- });
1501
- it("canGoToPreviousDomain should return true when past first domain", () => {
1502
- const store = useWizardStore.getState();
1503
- store.toggleDomain("web");
1504
- store.toggleDomain("api");
1505
- store.nextDomain();
1506
- globalExpect(store.canGoToPreviousDomain()).toBe(true);
1507
- });
1508
- it("canGoToPreviousDomain should return false with no domains", () => {
1509
- const store = useWizardStore.getState();
1510
- globalExpect(store.canGoToPreviousDomain()).toBe(false);
1511
- });
1512
- });
1513
- describe("reset", () => {
1514
- it("should reset to initial state", () => {
1515
- const store = useWizardStore.getState();
1516
- store.setStep("stack");
1517
- store.setApproach("scratch");
1518
- store.selectStack("nextjs-fullstack");
1519
- store.toggleDomain("web");
1520
- store.reset();
1521
- const state = useWizardStore.getState();
1522
- globalExpect(state.step).toBe("stack");
1523
- globalExpect(state.approach).toBeNull();
1524
- globalExpect(state.selectedStackId).toBeNull();
1525
- globalExpect(state.selectedDomains).toStrictEqual([]);
1526
- globalExpect(state.history).toStrictEqual([]);
1527
- });
1528
- });
1529
- describe("complex flows", () => {
1530
- it("should handle complete stack selection flow", () => {
1531
- const store = useWizardStore.getState();
1532
- store.setApproach("stack");
1533
- store.selectStack("nextjs-fullstack");
1534
- store.setStackAction("customize");
1535
- store.setStep("build");
1536
- store.setStep("confirm");
1537
- const state = useWizardStore.getState();
1538
- globalExpect(state.step).toBe("confirm");
1539
- globalExpect(state.approach).toBe("stack");
1540
- globalExpect(state.selectedStackId).toBe("nextjs-fullstack");
1541
- globalExpect(state.stackAction).toBe("customize");
1542
- globalExpect(state.history).toStrictEqual(["stack", "build"]);
1543
- });
1544
- it("should handle complete scratch flow", () => {
1545
- const store = useWizardStore.getState();
1546
- store.setApproach("scratch");
1547
- store.toggleDomain("web");
1548
- store.toggleDomain("api");
1549
- store.setStep("build");
1550
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1551
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
1552
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
1553
- store.setStep("confirm");
1554
- const state = useWizardStore.getState();
1555
- globalExpect(state.step).toBe("confirm");
1556
- globalExpect(state.approach).toBe("scratch");
1557
- globalExpect(state.selectedDomains).toStrictEqual(["web", "api"]);
1558
- globalExpect(state.domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
1559
- globalExpect(state.domainSelections.web["web-styling"]).toStrictEqual([
1560
- "web-styling-scss-modules"
1561
- ]);
1562
- globalExpect(state.domainSelections.api["api-api"]).toStrictEqual(["api-framework-hono"]);
1563
- });
1564
- it("should preserve selections when going back", () => {
1565
- const store = useWizardStore.getState();
1566
- store.setApproach("scratch");
1567
- store.toggleDomain("web");
1568
- store.setStep("build");
1569
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1570
- store.goBack();
1571
- const state = useWizardStore.getState();
1572
- globalExpect(state.selectedDomains).toContain("web");
1573
- globalExpect(state.domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
1574
- });
1575
- });
1576
- describe("buildSourceRows sort order", () => {
1577
- function makeSource(overrides) {
1578
- return {
1579
- type: "private",
1580
- installed: false,
1581
- ...overrides
1582
- };
1583
- }
1584
- it("should sort local sources before scoped marketplace sources", () => {
1585
- const store = useWizardStore.getState();
1586
- const skill = {
1587
- ...SKILLS.react,
1588
- availableSources: [
1589
- makeSource({ name: "Acme Corp", type: "private", primary: true }),
1590
- makeSource({ name: "eject", type: "local", installed: true, installMode: "eject" })
1591
- ]
1592
- };
1593
- initializeMatrix(createMockMatrix(skill));
1594
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1595
- const rows = store.buildSourceRows();
1596
- globalExpect(rows).toHaveLength(1);
1597
- globalExpect(rows[0].options[0].id).toBe("eject");
1598
- globalExpect(rows[0].options[1].id).toBe("Acme Corp");
1599
- });
1600
- it("should sort scoped marketplace before default public marketplace", () => {
1601
- const store = useWizardStore.getState();
1602
- const skill = {
1603
- ...SKILLS.react,
1604
- availableSources: [
1605
- makeSource({ name: "agents-inc", type: "public" }),
1606
- makeSource({ name: "Acme Corp", type: "private", primary: true })
1607
- ]
1608
- };
1609
- initializeMatrix(createMockMatrix(skill));
1610
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1611
- const rows = store.buildSourceRows();
1612
- globalExpect(rows).toHaveLength(1);
1613
- globalExpect(rows[0].options[0].id).toBe("eject");
1614
- globalExpect(rows[0].options[1].id).toBe("Acme Corp");
1615
- globalExpect(rows[0].options[2].id).toBe("agents-inc");
1616
- });
1617
- it("should sort default public marketplace before third-party sources", () => {
1618
- const store = useWizardStore.getState();
1619
- const skill = {
1620
- ...SKILLS.react,
1621
- availableSources: [
1622
- makeSource({ name: "Extra Corp", type: "private" }),
1623
- makeSource({ name: "agents-inc", type: "public" })
1624
- ]
1625
- };
1626
- initializeMatrix(createMockMatrix(skill));
1627
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1628
- const rows = store.buildSourceRows();
1629
- globalExpect(rows).toHaveLength(1);
1630
- globalExpect(rows[0].options[0].id).toBe("eject");
1631
- globalExpect(rows[0].options[1].id).toBe("agents-inc");
1632
- globalExpect(rows[0].options[2].id).toBe("Extra Corp");
1633
- });
1634
- it("should sort all four tiers in correct order", () => {
1635
- const store = useWizardStore.getState();
1636
- const skill = {
1637
- ...SKILLS.react,
1638
- availableSources: [
1639
- makeSource({ name: "Extra Corp", type: "private" }),
1640
- makeSource({ name: "agents-inc", type: "public" }),
1641
- makeSource({ name: "Acme Corp", type: "private", primary: true }),
1642
- makeSource({ name: "eject", type: "local", installed: true, installMode: "eject" })
1643
- ]
1644
- };
1645
- initializeMatrix(createMockMatrix(skill));
1646
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1647
- const rows = store.buildSourceRows();
1648
- globalExpect(rows).toHaveLength(1);
1649
- const sourceNames = rows[0].options.map((opt) => opt.id);
1650
- globalExpect(sourceNames).toStrictEqual(["eject", "Acme Corp", "agents-inc", "Extra Corp"]);
1651
- });
1652
- });
1653
- describe("buildSourceRows scope", () => {
1654
- it("should include scope from skillConfigs", () => {
1655
- const store = useWizardStore.getState();
1656
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1657
- const rows = store.buildSourceRows();
1658
- globalExpect(rows).toHaveLength(1);
1659
- globalExpect(rows[0].scope).toBe("global");
1660
- store.toggleSkillScope("web-framework-react");
1661
- const updatedRows = store.buildSourceRows();
1662
- globalExpect(updatedRows[0].scope).toBe("project");
1663
- });
1664
- it("should return undefined scope for skills not in skillConfigs", () => {
1665
- initializeMatrix(ALL_SKILLS_WEB_AND_API_MATRIX);
1666
- const store = useWizardStore.getState();
1667
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1668
- useWizardStore.setState({ skillConfigs: [] });
1669
- const rows = store.buildSourceRows();
1670
- globalExpect(rows).toHaveLength(1);
1671
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1672
- globalExpect(rows[0].scope).toBeUndefined();
1673
- });
1674
- it("should mark global-scoped skills as readOnly when previously installed globally", () => {
1675
- const store = useWizardStore.getState();
1676
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1677
- useWizardStore.setState({
1678
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1679
- scope: "global",
1680
- source: "eject"
1681
- })
1682
- });
1683
- const rows = store.buildSourceRows();
1684
- globalExpect(rows).toHaveLength(1);
1685
- globalExpect(rows[0].readOnly).toBe(true);
1686
- });
1687
- it("should not mark global-scoped skills as readOnly when not previously installed", () => {
1688
- const store = useWizardStore.getState();
1689
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1690
- const rows = store.buildSourceRows();
1691
- globalExpect(rows).toHaveLength(1);
1692
- globalExpect(rows[0].readOnly).toBeUndefined();
1693
- });
1694
- it("should not mark global-scoped skills as readOnly when editing from global scope", () => {
1695
- const store = useWizardStore.getState();
1696
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1697
- useWizardStore.setState({
1698
- isEditingFromGlobalScope: true,
1699
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1700
- scope: "global",
1701
- source: "eject"
1702
- })
1703
- });
1704
- const rows = store.buildSourceRows();
1705
- globalExpect(rows).toHaveLength(1);
1706
- globalExpect(rows[0].readOnly).toBeUndefined();
1707
- });
1708
- it("should not mark project-scoped skills as readOnly when previously installed as project", () => {
1709
- const store = useWizardStore.getState();
1710
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1711
- useWizardStore.setState({
1712
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1713
- scope: "project",
1714
- source: "eject"
1715
- }),
1716
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1717
- scope: "project",
1718
- source: "eject"
1719
- })
1720
- });
1721
- const rows = store.buildSourceRows();
1722
- globalExpect(rows).toHaveLength(1);
1723
- globalExpect(rows[0].scope).toBe("project");
1724
- globalExpect(rows[0].readOnly).toBeUndefined();
1725
- });
1726
- it("should emit both global locked and project editable rows for re-scoped skills", () => {
1727
- const store = useWizardStore.getState();
1728
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1729
- useWizardStore.setState({
1730
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1731
- scope: "global",
1732
- source: "agents-inc"
1733
- }),
1734
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1735
- scope: "project",
1736
- source: "agents-inc"
1737
- })
1738
- });
1739
- const rows = store.buildSourceRows();
1740
- globalExpect(rows).toHaveLength(2);
1741
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1742
- globalExpect(rows[0].scope).toBe("global");
1743
- globalExpect(rows[0].readOnly).toBe(true);
1744
- globalExpect(rows[1].skillId).toBe("web-framework-react");
1745
- globalExpect(rows[1].scope).toBe("project");
1746
- globalExpect(rows[1].readOnly).toBeUndefined();
1747
- });
1748
- it("should not mark new global skills as readOnly when not previously installed", () => {
1749
- const store = useWizardStore.getState();
1750
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1751
- useWizardStore.setState({
1752
- installedSkillConfigs: [],
1753
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1754
- scope: "global",
1755
- source: "agents-inc"
1756
- })
1757
- });
1758
- const rows = store.buildSourceRows();
1759
- globalExpect(rows).toHaveLength(1);
1760
- globalExpect(rows[0].scope).toBe("global");
1761
- globalExpect(rows[0].readOnly).toBeUndefined();
1762
- });
1763
- it("should emit single locked row for skill that remains global-scoped", () => {
1764
- const store = useWizardStore.getState();
1765
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1766
- useWizardStore.setState({
1767
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1768
- scope: "global",
1769
- source: "agents-inc"
1770
- }),
1771
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1772
- scope: "global",
1773
- source: "agents-inc"
1774
- })
1775
- });
1776
- const rows = store.buildSourceRows();
1777
- globalExpect(rows).toHaveLength(1);
1778
- globalExpect(rows[0].scope).toBe("global");
1779
- globalExpect(rows[0].readOnly).toBe(true);
1780
- });
1781
- it("should show excluded global skills as locked rows", () => {
1782
- const store = useWizardStore.getState();
1783
- useWizardStore.setState({
1784
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1785
- scope: "global",
1786
- source: "agents-inc"
1787
- }),
1788
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1789
- scope: "global",
1790
- source: "agents-inc",
1791
- excluded: true
1792
- })
1793
- });
1794
- const rows = store.buildSourceRows();
1795
- globalExpect(rows).toHaveLength(1);
1796
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1797
- globalExpect(rows[0].scope).toBe("global");
1798
- globalExpect(rows[0].readOnly).toBe(true);
1799
- });
1800
- it("should not duplicate rows for re-scoped skills with excluded tombstone", () => {
1801
- const store = useWizardStore.getState();
1802
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1803
- useWizardStore.setState({
1804
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1805
- scope: "global",
1806
- source: "agents-inc"
1807
- }),
1808
- skillConfigs: [
1809
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1810
- ...buildSkillConfigs(["web-framework-react"], {
1811
- scope: "global",
1812
- source: "agents-inc",
1813
- excluded: true
1814
- })
1815
- ]
1816
- });
1817
- const rows = store.buildSourceRows();
1818
- globalExpect(rows).toHaveLength(2);
1819
- globalExpect(rows[0].scope).toBe("global");
1820
- globalExpect(rows[0].readOnly).toBe(true);
1821
- globalExpect(rows[1].scope).toBe("project");
1822
- globalExpect(rows[1].readOnly).toBeUndefined();
1823
- });
1824
- it("should emit single editable row for new project-scoped skill", () => {
1825
- const store = useWizardStore.getState();
1826
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1827
- useWizardStore.setState({
1828
- installedSkillConfigs: [],
1829
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1830
- scope: "project",
1831
- source: "agents-inc"
1832
- })
1833
- });
1834
- const rows = store.buildSourceRows();
1835
- globalExpect(rows).toHaveLength(1);
1836
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1837
- globalExpect(rows[0].scope).toBe("project");
1838
- globalExpect(rows[0].readOnly).toBeUndefined();
1839
- });
1840
- it("should produce correct rows for mixed re-scoped and excluded skills", () => {
1841
- const store = useWizardStore.getState();
1842
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1843
- useWizardStore.setState({
1844
- installedSkillConfigs: buildSkillConfigs(["web-framework-react", "web-testing-vitest"], {
1845
- scope: "global",
1846
- source: "agents-inc"
1847
- }),
1848
- skillConfigs: [
1849
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
1850
- ...buildSkillConfigs(["web-framework-react", "web-testing-vitest"], {
1851
- scope: "global",
1852
- source: "agents-inc",
1853
- excluded: true
1854
- })
1855
- ]
1856
- });
1857
- const rows = store.buildSourceRows();
1858
- globalExpect(rows).toHaveLength(3);
1859
- const reactRows = rows.filter((r) => r.skillId === "web-framework-react");
1860
- const vitestRows = rows.filter((r) => r.skillId === "web-testing-vitest");
1861
- globalExpect(reactRows).toHaveLength(2);
1862
- globalExpect(reactRows[0].scope).toBe("global");
1863
- globalExpect(reactRows[0].readOnly).toBe(true);
1864
- globalExpect(reactRows[1].scope).toBe("project");
1865
- globalExpect(reactRows[1].readOnly).toBeUndefined();
1866
- globalExpect(vitestRows).toHaveLength(1);
1867
- globalExpect(vitestRows[0].scope).toBe("global");
1868
- globalExpect(vitestRows[0].readOnly).toBe(true);
1869
- });
1870
- it("should keep a deselected saved project skill visible as a disabled row", () => {
1871
- const store = useWizardStore.getState();
1872
- useWizardStore.setState({
1873
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1874
- scope: "project",
1875
- source: "eject"
1876
- }),
1877
- skillConfigs: []
1878
- });
1879
- const rows = store.buildSourceRows();
1880
- globalExpect(rows).toHaveLength(1);
1881
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1882
- globalExpect(rows[0].disabled).toBe(true);
1883
- globalExpect(rows[0].readOnly).toBeUndefined();
1884
- globalExpect(rows[0].scope).toBe("project");
1885
- });
1886
- it("should show the persisted source on a deselected saved project skill", () => {
1887
- const store = useWizardStore.getState();
1888
- useWizardStore.setState({
1889
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1890
- scope: "project",
1891
- source: "eject"
1892
- }),
1893
- skillConfigs: []
1894
- });
1895
- const rows = store.buildSourceRows();
1896
- globalExpect(rows[0].options.filter((o) => o.selected).map((o) => o.id)).toStrictEqual(["eject"]);
1897
- });
1898
- it("should not surface a never-saved skill as a disabled row during init", () => {
1899
- const store = useWizardStore.getState();
1900
- useWizardStore.setState({ installedSkillConfigs: null, skillConfigs: [] });
1901
- globalExpect(store.buildSourceRows()).toStrictEqual([]);
1902
- });
1903
- it("should surface a deselected saved skill as a disabled row when editing from global scope", () => {
1904
- const store = useWizardStore.getState();
1905
- useWizardStore.setState({
1906
- isEditingFromGlobalScope: true,
1907
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
1908
- scope: "global",
1909
- source: "eject"
1910
- }),
1911
- skillConfigs: []
1912
- });
1913
- const rows = store.buildSourceRows();
1914
- globalExpect(rows).toHaveLength(1);
1915
- globalExpect(rows[0].skillId).toBe("web-framework-react");
1916
- globalExpect(rows[0].disabled).toBe(true);
1917
- globalExpect(rows[0].scope).toBe("global");
1918
- globalExpect(rows[0].readOnly).toBeUndefined();
1919
- });
1920
- it("should skip a saved skill the marketplace no longer carries instead of throwing", () => {
1921
- const store = useWizardStore.getState();
1922
- initializeMatrix(createMockMatrix(SKILLS.react));
1923
- useWizardStore.setState({
1924
- installedSkillConfigs: buildSkillConfigs(["web-testing-vitest"], {
1925
- scope: "project",
1926
- source: "eject"
1927
- }),
1928
- skillConfigs: []
1929
- });
1930
- globalExpect(store.buildSourceRows()).toStrictEqual([]);
1931
- });
1932
- it("should render a collapsed dual-scope skill as a locked global row plus a project pending-removal row", () => {
1933
- const store = useWizardStore.getState();
1934
- useWizardStore.setState({
1935
- installedSkillConfigs: [
1936
- ...buildSkillConfigs(["web-framework-react"], {
1937
- scope: "project",
1938
- source: "agents-inc"
1939
- }),
1940
- ...buildSkillConfigs(["web-framework-react"], {
1941
- scope: "global",
1942
- source: "agents-inc"
1943
- })
1944
- ],
1945
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1946
- scope: "global",
1947
- source: "agents-inc"
1948
- })
1949
- });
1950
- const rows = store.buildSourceRows();
1951
- globalExpect(rows.map((r) => r.skillId)).toStrictEqual([
1952
- "web-framework-react",
1953
- "web-framework-react"
1954
- ]);
1955
- globalExpect(rows.map((r) => r.scope)).toStrictEqual(["global", "project"]);
1956
- globalExpect(rows[0].readOnly).toBe(true);
1957
- globalExpect(rows[0].disabled).toBeUndefined();
1958
- globalExpect(rows[1].disabled).toBe(true);
1959
- globalExpect(rows[1].readOnly).toBeUndefined();
1960
- globalExpect(rows.map((r) => r.added)).toStrictEqual([void 0, void 0]);
1961
- });
1962
- it("should render a pending-removal row inline after the still-selected rows of its scope", () => {
1963
- const store = useWizardStore.getState();
1964
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1965
- useWizardStore.setState({
1966
- installedSkillConfigs: [
1967
- ...buildSkillConfigs(["web-framework-react"], {
1968
- scope: "project",
1969
- source: "eject"
1970
- }),
1971
- ...buildSkillConfigs(["web-testing-vitest"], { scope: "project", source: "eject" })
1972
- ],
1973
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
1974
- scope: "project",
1975
- source: "eject"
1976
- })
1977
- });
1978
- const rows = store.buildSourceRows();
1979
- globalExpect(rows.map((r) => r.skillId)).toStrictEqual([
1980
- "web-framework-react",
1981
- "web-testing-vitest"
1982
- ]);
1983
- globalExpect(rows.map((r) => r.scope)).toStrictEqual(["project", "project"]);
1984
- globalExpect(rows[0].disabled).toBeUndefined();
1985
- globalExpect(rows[1].disabled).toBe(true);
1986
- });
1987
- it("should mark every row added when there is no installation snapshot", () => {
1988
- const store = useWizardStore.getState();
1989
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1990
- useWizardStore.setState({ installedSkillConfigs: null });
1991
- const rows = store.buildSourceRows();
1992
- globalExpect(rows).toHaveLength(1);
1993
- globalExpect(rows[0].added).toBe(true);
1994
- });
1995
- it("should mark every row added when the installation snapshot is empty", () => {
1996
- const store = useWizardStore.getState();
1997
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
1998
- useWizardStore.setState({ installedSkillConfigs: [] });
1999
- const rows = store.buildSourceRows();
2000
- globalExpect(rows).toHaveLength(1);
2001
- globalExpect(rows[0].added).toBe(true);
2002
- });
2003
- it("should mark only the project half of an adopted global skill as added", () => {
2004
- const store = useWizardStore.getState();
2005
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2006
- useWizardStore.setState({
2007
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
2008
- scope: "global",
2009
- source: "agents-inc"
2010
- }),
2011
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
2012
- scope: "project",
2013
- source: "agents-inc"
2014
- })
2015
- });
2016
- const rows = store.buildSourceRows();
2017
- globalExpect(rows.map((r) => r.scope)).toStrictEqual(["global", "project"]);
2018
- globalExpect(rows[0].added).toBeUndefined();
2019
- globalExpect(rows[1].added).toBe(true);
2020
- });
2021
- it("should render a collapsed persisted dual-scope pair as an unmarked global row plus a project pending-removal row", () => {
2022
- const store = useWizardStore.getState();
2023
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2024
- useWizardStore.setState({
2025
- installedSkillConfigs: [
2026
- ...buildSkillConfigs(["web-framework-react"], { scope: "project", source: "agents-inc" }),
2027
- ...buildSkillConfigs(["web-framework-react"], {
2028
- scope: "global",
2029
- source: "agents-inc",
2030
- excluded: true
2031
- })
2032
- ],
2033
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
2034
- scope: "global",
2035
- source: "agents-inc"
2036
- })
2037
- });
2038
- const rows = store.buildSourceRows();
2039
- globalExpect(rows.map((r) => r.skillId)).toStrictEqual([
2040
- "web-framework-react",
2041
- "web-framework-react"
2042
- ]);
2043
- globalExpect(rows.map((r) => r.scope)).toStrictEqual(["global", "project"]);
2044
- globalExpect(rows[0].added).toBeUndefined();
2045
- globalExpect(rows[0].disabled).toBeUndefined();
2046
- globalExpect(rows[1].disabled).toBe(true);
2047
- globalExpect(rows[1].readOnly).toBeUndefined();
2048
- globalExpect(rows[1].added).toBeUndefined();
2049
- });
2050
- it("should render a project-to-global migration as an added global row plus a project pending-removal row", () => {
2051
- const store = useWizardStore.getState();
2052
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2053
- useWizardStore.setState({
2054
- installedSkillConfigs: buildSkillConfigs(["web-framework-react"], {
2055
- scope: "project",
2056
- source: "agents-inc"
2057
- }),
2058
- skillConfigs: buildSkillConfigs(["web-framework-react"], {
2059
- scope: "global",
2060
- source: "agents-inc"
2061
- })
2062
- });
2063
- const rows = store.buildSourceRows();
2064
- globalExpect(rows.map((r) => r.skillId)).toStrictEqual([
2065
- "web-framework-react",
2066
- "web-framework-react"
2067
- ]);
2068
- globalExpect(rows.map((r) => r.scope)).toStrictEqual(["global", "project"]);
2069
- globalExpect(rows[0].added).toBe(true);
2070
- globalExpect(rows[0].disabled).toBeUndefined();
2071
- globalExpect(rows[0].readOnly).toBeUndefined();
2072
- globalExpect(rows[1].disabled).toBe(true);
2073
- globalExpect(rows[1].added).toBeUndefined();
2074
- globalExpect(rows[1].readOnly).toBeUndefined();
2075
- });
2076
- });
2077
- describe("agent selection", () => {
2078
- it("should start with empty selectedAgents", () => {
2079
- const { selectedAgents } = useWizardStore.getState();
2080
- globalExpect(selectedAgents).toStrictEqual([]);
2081
- });
2082
- it("should toggle agent on", () => {
2083
- const store = useWizardStore.getState();
2084
- store.toggleAgent("web-developer");
2085
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2086
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2087
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2088
- });
2089
- it("should block toggling globally installed agents from project scope and set toastMessage", () => {
2090
- const store = useWizardStore.getState();
2091
- store.toggleAgent("web-developer");
2092
- useWizardStore.setState({
2093
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2094
- isEditingFromGlobalScope: false,
2095
- isInitMode: false
2096
- });
2097
- store.toggleAgent("web-developer");
2098
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2099
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2100
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2101
- globalExpect(toastMessage).toBe("Global agents cannot be changed from project scope");
2102
- });
2103
- it("should block toggling globally installed agents in init mode too, with the same toastMessage", () => {
2104
- const store = useWizardStore.getState();
2105
- store.toggleAgent("web-developer");
2106
- useWizardStore.setState({
2107
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2108
- isEditingFromGlobalScope: false,
2109
- isInitMode: true
2110
- });
2111
- store.toggleAgent("web-developer");
2112
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2113
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2114
- globalExpect(
2115
- agentConfigs,
2116
- "a blocked agent toggle must leave the global entry active \u2014 no tombstone"
2117
- ).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2118
- globalExpect(toastMessage).toBe("Global agents cannot be changed from project scope");
2119
- });
2120
- it("should allow toggling globally installed agents from global scope (clean removal, no toast)", () => {
2121
- const store = useWizardStore.getState();
2122
- store.toggleAgent("web-developer");
2123
- useWizardStore.setState({
2124
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2125
- isEditingFromGlobalScope: true,
2126
- isInitMode: false
2127
- });
2128
- store.toggleAgent("web-developer");
2129
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2130
- globalExpect(selectedAgents).toStrictEqual([]);
2131
- globalExpect(agentConfigs).toStrictEqual([]);
2132
- globalExpect(toastMessage).toBeNull();
2133
- });
2134
- it("should toggle agent off", () => {
2135
- const store = useWizardStore.getState();
2136
- store.toggleAgent("web-developer");
2137
- store.toggleAgent("web-developer");
2138
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2139
- globalExpect(selectedAgents).toStrictEqual([]);
2140
- globalExpect(agentConfigs).toStrictEqual([]);
2141
- });
2142
- it("should allow multiple agents to be selected", () => {
2143
- const store = useWizardStore.getState();
2144
- store.toggleAgent("web-developer");
2145
- store.toggleAgent("api-developer");
2146
- store.toggleAgent("web-reviewer");
2147
- const { selectedAgents } = useWizardStore.getState();
2148
- globalExpect(selectedAgents).toStrictEqual(["web-developer", "api-developer", "web-reviewer"]);
2149
- });
2150
- it("should reset selectedAgents on reset", () => {
2151
- const store = useWizardStore.getState();
2152
- store.toggleAgent("web-developer");
2153
- store.reset();
2154
- const { selectedAgents } = useWizardStore.getState();
2155
- globalExpect(selectedAgents).toStrictEqual([]);
2156
- });
2157
- });
2158
- describe("agentConfigs and scope management", () => {
2159
- it("should have empty agentConfigs initially", () => {
2160
- const { agentConfigs } = useWizardStore.getState();
2161
- globalExpect(agentConfigs).toStrictEqual([]);
2162
- });
2163
- it("should sync agentConfigs when toggleAgent is called", () => {
2164
- const store = useWizardStore.getState();
2165
- store.toggleAgent("web-developer");
2166
- const { agentConfigs } = useWizardStore.getState();
2167
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2168
- });
2169
- it("should remove global agent from agentConfigs when toggled off during fresh init", () => {
2170
- const store = useWizardStore.getState();
2171
- store.toggleAgent("web-developer");
2172
- store.toggleAgent("web-developer");
2173
- const { agentConfigs } = useWizardStore.getState();
2174
- globalExpect(agentConfigs).toStrictEqual([]);
2175
- });
2176
- it("removes a global agent from agentConfigs when toggled off while editing from global scope", () => {
2177
- const store = useWizardStore.getState();
2178
- useWizardStore.setState({
2179
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2180
- isEditingFromGlobalScope: true
2181
- });
2182
- store.toggleAgent("web-developer");
2183
- store.toggleAgent("web-developer");
2184
- const { agentConfigs } = useWizardStore.getState();
2185
- globalExpect(agentConfigs).toStrictEqual([]);
2186
- });
2187
- it("should remove project agent from agentConfigs when toggled off", () => {
2188
- const store = useWizardStore.getState();
2189
- store.toggleAgent("web-developer");
2190
- useWizardStore.setState({
2191
- agentConfigs: buildAgentConfigs(["web-developer"])
2192
- });
2193
- store.toggleAgent("web-developer");
2194
- const { agentConfigs } = useWizardStore.getState();
2195
- globalExpect(agentConfigs).toStrictEqual([]);
2196
- });
2197
- it("should toggle agent scope between global and project", () => {
2198
- const store = useWizardStore.getState();
2199
- store.toggleAgent("web-developer");
2200
- store.toggleAgentScope("web-developer");
2201
- const { agentConfigs } = useWizardStore.getState();
2202
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"]));
2203
- store.toggleAgentScope("web-developer");
2204
- globalExpect(useWizardStore.getState().agentConfigs).toStrictEqual(
2205
- buildAgentConfigs(["web-developer"], { scope: "global" })
2206
- );
2207
- });
2208
- it("round-trips a persisted dual-scope agent row with `s`: collapse to [G], then restore [P][G]", () => {
2209
- const dualScope = () => [
2210
- ...buildAgentConfigs(["web-developer"], { scope: "project" }),
2211
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2212
- ];
2213
- const store = useWizardStore.getState();
2214
- useWizardStore.setState({
2215
- agentConfigs: dualScope(),
2216
- installedAgentConfigs: dualScope(),
2217
- isEditingFromGlobalScope: false,
2218
- isInitMode: false,
2219
- toastMessage: null
2220
- });
2221
- store.toggleAgentScope("web-developer");
2222
- const first = useWizardStore.getState();
2223
- globalExpect(first.agentConfigs).toStrictEqual(
2224
- buildAgentConfigs(["web-developer"], { scope: "global" })
2225
- );
2226
- globalExpect(first.toastMessage).toBeNull();
2227
- store.toggleAgentScope("web-developer");
2228
- const second = useWizardStore.getState();
2229
- globalExpect(second.agentConfigs).toStrictEqual(dualScope());
2230
- globalExpect(second.toastMessage).toBeNull();
2231
- });
2232
- it("runs the full in-session blocked-toggle \u2192 s-collapse \u2192 blocked-toggle \u2192 s-restore sequence on a persisted [P][G] agent", () => {
2233
- const dualScope = () => [
2234
- ...buildAgentConfigs(["web-developer"], { scope: "project" }),
2235
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2236
- ];
2237
- const plainGlobal = () => buildAgentConfigs(["web-developer"], { scope: "global" });
2238
- const store = useWizardStore.getState();
2239
- useWizardStore.setState({
2240
- selectedAgents: ["web-developer"],
2241
- agentConfigs: dualScope(),
2242
- installedAgentConfigs: dualScope(),
2243
- isEditingFromGlobalScope: false,
2244
- isInitMode: false,
2245
- toastMessage: null
2246
- });
2247
- store.toggleAgent("web-developer");
2248
- const afterBlockedToggle = useWizardStore.getState();
2249
- globalExpect(afterBlockedToggle.agentConfigs).toStrictEqual(dualScope());
2250
- globalExpect(afterBlockedToggle.selectedAgents).toStrictEqual(["web-developer"]);
2251
- globalExpect(afterBlockedToggle.toastMessage).toBe(
2252
- "Global agents cannot be changed from project scope"
2253
- );
2254
- useWizardStore.setState({ toastMessage: null });
2255
- store.toggleAgentScope("web-developer");
2256
- const afterCollapse = useWizardStore.getState();
2257
- globalExpect(afterCollapse.agentConfigs).toStrictEqual(plainGlobal());
2258
- globalExpect(afterCollapse.selectedAgents).toStrictEqual(["web-developer"]);
2259
- globalExpect(afterCollapse.toastMessage).toBeNull();
2260
- store.toggleAgent("web-developer");
2261
- const afterBlocked = useWizardStore.getState();
2262
- globalExpect(afterBlocked.agentConfigs).toStrictEqual(plainGlobal());
2263
- globalExpect(afterBlocked.toastMessage).toBe("Global agents cannot be changed from project scope");
2264
- useWizardStore.setState({ toastMessage: null });
2265
- store.toggleAgentScope("web-developer");
2266
- const afterRestore = useWizardStore.getState();
2267
- globalExpect(afterRestore.agentConfigs).toStrictEqual(dualScope());
2268
- globalExpect(afterRestore.toastMessage).toBeNull();
2269
- store.toggleAgentScope("web-developer");
2270
- const afterFlip = useWizardStore.getState();
2271
- globalExpect(afterFlip.agentConfigs).toStrictEqual(plainGlobal());
2272
- globalExpect(afterFlip.toastMessage).toBeNull();
2273
- store.toggleAgentScope("web-developer");
2274
- globalExpect(useWizardStore.getState().agentConfigs).toStrictEqual(dualScope());
2275
- });
2276
- it("writes no tombstone when a project agent re-scoped to global in-session is then deselected", () => {
2277
- const store = useWizardStore.getState();
2278
- useWizardStore.setState({
2279
- selectedAgents: ["web-developer"],
2280
- agentConfigs: buildAgentConfigs(["web-developer"], { scope: "project" }),
2281
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "project" }),
2282
- isEditingFromGlobalScope: false,
2283
- isInitMode: false,
2284
- toastMessage: null
2285
- });
2286
- store.toggleAgentScope("web-developer");
2287
- globalExpect(useWizardStore.getState().agentConfigs).toStrictEqual(
2288
- buildAgentConfigs(["web-developer"], { scope: "global" })
2289
- );
2290
- store.toggleAgent("web-developer");
2291
- const { agentConfigs, selectedAgents } = useWizardStore.getState();
2292
- globalExpect(
2293
- agentConfigs.filter((ac) => ac.excluded),
2294
- "an agent never installed globally must not gain a global tombstone"
2295
- ).toStrictEqual([]);
2296
- globalExpect(agentConfigs).toStrictEqual([]);
2297
- globalExpect(selectedAgents).toStrictEqual([]);
2298
- });
2299
- it("should set and clear focusedAgentId", () => {
2300
- const store = useWizardStore.getState();
2301
- store.setFocusedAgentId("web-developer");
2302
- globalExpect(useWizardStore.getState().focusedAgentId).toBe("web-developer");
2303
- store.setFocusedAgentId(null);
2304
- globalExpect(useWizardStore.getState().focusedAgentId).toBeNull();
2305
- });
2306
- it("should remove global agent when deselected during fresh init", () => {
2307
- const store = useWizardStore.getState();
2308
- store.toggleAgent("web-developer");
2309
- store.toggleAgent("web-developer");
2310
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2311
- globalExpect(selectedAgents).toStrictEqual([]);
2312
- globalExpect(agentConfigs).toStrictEqual([]);
2313
- });
2314
- it("removes a global agent cleanly (no tombstone, dropped from selectedAgents) when deselected while editing from global scope", () => {
2315
- const store = useWizardStore.getState();
2316
- useWizardStore.setState({
2317
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2318
- isEditingFromGlobalScope: true
2319
- });
2320
- store.toggleAgent("web-developer");
2321
- store.toggleAgent("web-developer");
2322
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2323
- globalExpect(selectedAgents).toStrictEqual([]);
2324
- globalExpect(agentConfigs).toStrictEqual([]);
2325
- });
2326
- it("cleanly re-adds a global agent when re-selected while editing from global scope", () => {
2327
- const store = useWizardStore.getState();
2328
- useWizardStore.setState({
2329
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2330
- isEditingFromGlobalScope: true
2331
- });
2332
- store.toggleAgent("web-developer");
2333
- store.toggleAgent("web-developer");
2334
- store.toggleAgent("web-developer");
2335
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2336
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2337
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2338
- });
2339
- it("drops a global agent from selectedAgents when toggled off while editing from global scope", () => {
2340
- const store = useWizardStore.getState();
2341
- store.toggleAgent("web-developer");
2342
- useWizardStore.setState({
2343
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2344
- isEditingFromGlobalScope: true
2345
- });
2346
- store.toggleAgent("web-developer");
2347
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2348
- globalExpect(selectedAgents).not.toContain("web-developer");
2349
- globalExpect(agentConfigs.some((ac) => ac.name === "web-developer")).toBe(false);
2350
- });
2351
- it("should remove non-installed agent from selectedAgents when toggled off", () => {
2352
- const store = useWizardStore.getState();
2353
- store.toggleAgent("web-developer");
2354
- store.toggleAgent("web-developer");
2355
- const { selectedAgents } = useWizardStore.getState();
2356
- globalExpect(selectedAgents).not.toContain("web-developer");
2357
- });
2358
- it("should restore excluded global agent when toggled back on", () => {
2359
- const store = useWizardStore.getState();
2360
- store.toggleAgent("web-developer");
2361
- useWizardStore.setState({
2362
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" })
2363
- });
2364
- store.toggleAgent("web-developer");
2365
- store.toggleAgent("web-developer");
2366
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2367
- globalExpect(selectedAgents).toContain("web-developer");
2368
- globalExpect(agentConfigs).not.toContainEqual(
2369
- globalExpect.objectContaining({ name: "web-developer", excluded: true })
2370
- );
2371
- });
2372
- describe("dual-scope selection toggle (agents)", () => {
2373
- const dualScopeAgents = () => [
2374
- ...buildAgentConfigs(["web-developer"], { scope: "project" }),
2375
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2376
- ];
2377
- it("leaves a dual-scope agent untouched when the selection key is pressed and emits the global-locked toast", () => {
2378
- const store = useWizardStore.getState();
2379
- useWizardStore.setState({
2380
- selectedAgents: ["web-developer"],
2381
- agentConfigs: dualScopeAgents(),
2382
- installedAgentConfigs: dualScopeAgents(),
2383
- isEditingFromGlobalScope: false,
2384
- isInitMode: false
2385
- });
2386
- store.toggleAgent("web-developer");
2387
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2388
- globalExpect(toastMessage).toBe("Global agents cannot be changed from project scope");
2389
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2390
- globalExpect(agentConfigs).toStrictEqual(dualScopeAgents());
2391
- });
2392
- it("restores [P][G] when re-selecting an inherited-global agent row (fresh project entry AND tombstone)", () => {
2393
- const store = useWizardStore.getState();
2394
- useWizardStore.setState({
2395
- selectedAgents: [],
2396
- agentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2397
- installedAgentConfigs: dualScopeAgents(),
2398
- isEditingFromGlobalScope: false,
2399
- isInitMode: false
2400
- });
2401
- store.toggleAgent("web-developer");
2402
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2403
- globalExpect(toastMessage).toBeNull();
2404
- globalExpect(selectedAgents).toStrictEqual(["web-developer"]);
2405
- globalExpect(agentConfigs).toStrictEqual(dualScopeAgents());
2406
- });
2407
- it("restores [P][G] cleanly (no two active entries) via `s` after the collapse is saved and re-opened", () => {
2408
- const store = useWizardStore.getState();
2409
- useWizardStore.setState({
2410
- selectedAgents: ["web-developer"],
2411
- agentConfigs: dualScopeAgents(),
2412
- installedAgentConfigs: dualScopeAgents(),
2413
- isEditingFromGlobalScope: false,
2414
- isInitMode: false
2415
- });
2416
- store.toggleAgentScope("web-developer");
2417
- globalExpect(useWizardStore.getState().agentConfigs).toStrictEqual(
2418
- buildAgentConfigs(["web-developer"], { scope: "global" })
2419
- );
2420
- useWizardStore.setState({
2421
- agentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2422
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" })
2423
- });
2424
- store.toggleAgentScope("web-developer");
2425
- const { agentConfigs } = useWizardStore.getState();
2426
- const activeEntries = agentConfigs.filter((ac) => !ac.excluded);
2427
- globalExpect(activeEntries).toStrictEqual(
2428
- buildAgentConfigs(["web-developer"], { scope: "project" })
2429
- );
2430
- globalExpect(agentConfigs.filter((ac) => ac.excluded)).toStrictEqual(
2431
- buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2432
- );
2433
- });
2434
- it("removes a global-scope agent entirely when deselected from a global-context edit (Scenario C setup)", () => {
2435
- const store = useWizardStore.getState();
2436
- useWizardStore.setState({
2437
- selectedAgents: ["web-developer"],
2438
- agentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2439
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" }),
2440
- isEditingFromGlobalScope: true,
2441
- isInitMode: false
2442
- });
2443
- store.toggleAgent("web-developer");
2444
- const { selectedAgents, agentConfigs, toastMessage } = useWizardStore.getState();
2445
- globalExpect(toastMessage).toBeNull();
2446
- globalExpect(selectedAgents).toStrictEqual([]);
2447
- globalExpect(agentConfigs).toStrictEqual([]);
2448
- });
2449
- });
2450
- it("should not toggle agent scope when isEditingFromGlobalScope is true", () => {
2451
- const store = useWizardStore.getState();
2452
- store.toggleAgent("web-developer");
2453
- useWizardStore.setState({ isEditingFromGlobalScope: true });
2454
- store.toggleAgentScope("web-developer");
2455
- const { agentConfigs } = useWizardStore.getState();
2456
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2457
- });
2458
- it("should add excluded global entry when toggling previously-installed global agent to project", () => {
2459
- const store = useWizardStore.getState();
2460
- store.toggleAgent("web-developer");
2461
- useWizardStore.setState({
2462
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" })
2463
- });
2464
- store.toggleAgentScope("web-developer");
2465
- const { agentConfigs } = useWizardStore.getState();
2466
- globalExpect(agentConfigs).toStrictEqual([
2467
- ...buildAgentConfigs(["web-developer"]),
2468
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2469
- ]);
2470
- });
2471
- it("should remove excluded global entry when toggling agent back from project to global", () => {
2472
- const store = useWizardStore.getState();
2473
- store.toggleAgent("web-developer");
2474
- useWizardStore.setState({
2475
- installedAgentConfigs: buildAgentConfigs(["web-developer"], { scope: "global" })
2476
- });
2477
- store.toggleAgentScope("web-developer");
2478
- store.toggleAgentScope("web-developer");
2479
- const { agentConfigs } = useWizardStore.getState();
2480
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"], { scope: "global" }));
2481
- });
2482
- it("should not add excluded entry when toggling agent scope during fresh init", () => {
2483
- const store = useWizardStore.getState();
2484
- store.toggleAgent("web-developer");
2485
- store.toggleAgentScope("web-developer");
2486
- const { agentConfigs } = useWizardStore.getState();
2487
- globalExpect(agentConfigs).toStrictEqual(buildAgentConfigs(["web-developer"]));
2488
- });
2489
- });
2490
- describe("preselectAgentsFromDomains", () => {
2491
- it("should preselect web-related agents when web domain is selected", () => {
2492
- const store = useWizardStore.getState();
2493
- store.toggleDomain("web");
2494
- store.preselectAgentsFromDomains();
2495
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2496
- globalExpect(selectedAgents).toStrictEqual([...EXPECTED_AGENTS.WEB]);
2497
- globalExpect(agentConfigs).toStrictEqual(
2498
- EXPECTED_AGENTS.WEB.map((name) => ({ name, scope: "global" }))
2499
- );
2500
- });
2501
- it("should preselect api-related agents when api domain is selected", () => {
2502
- const store = useWizardStore.getState();
2503
- store.toggleDomain("api");
2504
- store.preselectAgentsFromDomains();
2505
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2506
- globalExpect(selectedAgents).toStrictEqual([...EXPECTED_AGENTS.API]);
2507
- globalExpect(agentConfigs).toStrictEqual(
2508
- EXPECTED_AGENTS.API.map((name) => ({ name, scope: "global" }))
2509
- );
2510
- });
2511
- it("should preselect cli agents when cli domain is selected", () => {
2512
- const store = useWizardStore.getState();
2513
- store.toggleDomain("cli");
2514
- store.preselectAgentsFromDomains();
2515
- const { selectedAgents, agentConfigs } = useWizardStore.getState();
2516
- globalExpect(selectedAgents).toStrictEqual([...EXPECTED_AGENTS.CLI]);
2517
- globalExpect(agentConfigs).toStrictEqual(
2518
- EXPECTED_AGENTS.CLI.map((name) => ({ name, scope: "global" }))
2519
- );
2520
- });
2521
- it("should never include optional agents regardless of domains", () => {
2522
- const store = useWizardStore.getState();
2523
- store.toggleDomain("web");
2524
- store.toggleDomain("api");
2525
- store.toggleDomain("cli");
2526
- store.preselectAgentsFromDomains();
2527
- const { selectedAgents } = useWizardStore.getState();
2528
- globalExpect(selectedAgents).toStrictEqual([...EXPECTED_AGENTS.ALL]);
2529
- });
2530
- it("should return empty agents when no domains are selected", () => {
2531
- const store = useWizardStore.getState();
2532
- store.preselectAgentsFromDomains();
2533
- const { selectedAgents } = useWizardStore.getState();
2534
- globalExpect(selectedAgents).toStrictEqual([]);
2535
- });
2536
- it("should produce union of agents for multiple domains", () => {
2537
- const store = useWizardStore.getState();
2538
- store.toggleDomain("web");
2539
- store.toggleDomain("api");
2540
- store.preselectAgentsFromDomains();
2541
- const { selectedAgents } = useWizardStore.getState();
2542
- globalExpect(selectedAgents).toContain("web-developer");
2543
- globalExpect(selectedAgents).toContain("api-developer");
2544
- globalExpect(selectedAgents).toContain("web-reviewer");
2545
- globalExpect(selectedAgents).toContain("api-reviewer");
2546
- });
2547
- it("should not preselect api agents when only web domain is selected", () => {
2548
- const store = useWizardStore.getState();
2549
- store.toggleDomain("web");
2550
- store.preselectAgentsFromDomains();
2551
- const { selectedAgents } = useWizardStore.getState();
2552
- globalExpect(selectedAgents).toContain("web-developer");
2553
- globalExpect(selectedAgents).not.toContain("api-developer");
2554
- globalExpect(selectedAgents).not.toContain("api-reviewer");
2555
- });
2556
- it("should return sorted agents", () => {
2557
- const store = useWizardStore.getState();
2558
- store.toggleDomain("web");
2559
- store.toggleDomain("api");
2560
- store.preselectAgentsFromDomains();
2561
- const { selectedAgents } = useWizardStore.getState();
2562
- const sorted = [...selectedAgents].sort();
2563
- globalExpect(selectedAgents).toStrictEqual(sorted);
2564
- });
2565
- it("should replace previous agent selection", () => {
2566
- const store = useWizardStore.getState();
2567
- store.toggleAgent("codex-keeper");
2568
- store.toggleDomain("web");
2569
- store.preselectAgentsFromDomains();
2570
- const { selectedAgents } = useWizardStore.getState();
2571
- globalExpect(selectedAgents).not.toContain("codex-keeper");
2572
- });
2573
- it("should retain a globally installed agent that no selected domain rosters", () => {
2574
- const store = useWizardStore.getState();
2575
- useWizardStore.setState({
2576
- agentConfigs: buildAgentConfigs(["cli-developer"], { scope: "global" }),
2577
- installedAgentConfigs: buildAgentConfigs(["cli-developer"], { scope: "global" }),
2578
- isEditingFromGlobalScope: false,
2579
- isInitMode: false
2580
- });
2581
- store.toggleDomain("web");
2582
- store.preselectAgentsFromDomains();
2583
- const { agentConfigs, selectedAgents } = useWizardStore.getState();
2584
- globalExpect(
2585
- agentConfigs.filter((ac) => ac.name === "cli-developer"),
2586
- "a globally installed agent outside the domain roster must survive preselection"
2587
- ).toStrictEqual(buildAgentConfigs(["cli-developer"], { scope: "global" }));
2588
- globalExpect(
2589
- agentConfigs.filter((ac) => ac.name !== "cli-developer"),
2590
- "the domain roster is still preselected alongside the retained global agent"
2591
- ).toStrictEqual(EXPECTED_AGENTS.WEB.map((name) => ({ name, scope: "global" })));
2592
- globalExpect(selectedAgents).toContain("web-developer");
2593
- });
2594
- it("should preserve a saved agent's model and effort through the roster rebuild", () => {
2595
- const store = useWizardStore.getState();
2596
- useWizardStore.setState({
2597
- agentConfigs: buildAgentConfigs(["web-developer"], {
2598
- scope: "project",
2599
- model: "haiku",
2600
- effort: "xhigh"
2601
- })
2602
- });
2603
- store.toggleDomain("web");
2604
- store.preselectAgentsFromDomains();
2605
- const { agentConfigs } = useWizardStore.getState();
2606
- globalExpect(agentConfigs.filter((ac) => ac.name === "web-developer")).toStrictEqual(
2607
- buildAgentConfigs(["web-developer"], {
2608
- scope: "project",
2609
- model: "haiku",
2610
- effort: "xhigh"
2611
- })
2612
- );
2613
- });
2614
- it("should preserve excluded agent configs", () => {
2615
- const store = useWizardStore.getState();
2616
- useWizardStore.setState({
2617
- agentConfigs: buildAgentConfigs(["codex-keeper"], { scope: "global", excluded: true })
2618
- });
2619
- store.toggleDomain("web");
2620
- store.preselectAgentsFromDomains();
2621
- const { agentConfigs } = useWizardStore.getState();
2622
- const excludedConfig = agentConfigs.find((ac) => ac.name === "codex-keeper");
2623
- globalExpect(excludedConfig?.excluded).toBe(true);
2624
- const webDevConfig = agentConfigs.find((ac) => ac.name === "web-developer");
2625
- globalExpect(webDevConfig?.name).toBe("web-developer");
2626
- });
2627
- it("should clear excluded flag when re-including previously excluded agent via domain preselection", () => {
2628
- const store = useWizardStore.getState();
2629
- useWizardStore.setState({
2630
- agentConfigs: buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2631
- });
2632
- store.toggleDomain("web");
2633
- store.preselectAgentsFromDomains();
2634
- const { agentConfigs } = useWizardStore.getState();
2635
- const webDevConfig = agentConfigs.find((ac) => ac.name === "web-developer");
2636
- globalExpect(webDevConfig?.excluded).toBeUndefined();
2637
- });
2638
- it("preserves excluded tombstone when active agent entry exists for same agent at different scope", () => {
2639
- const store = useWizardStore.getState();
2640
- useWizardStore.setState({
2641
- agentConfigs: [
2642
- ...buildAgentConfigs(["web-developer"]),
2643
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2644
- ]
2645
- });
2646
- store.toggleDomain("web");
2647
- store.preselectAgentsFromDomains();
2648
- const { agentConfigs } = useWizardStore.getState();
2649
- const webDevConfigs = agentConfigs.filter((ac) => ac.name === "web-developer");
2650
- globalExpect(webDevConfigs).toHaveLength(2);
2651
- const active = webDevConfigs.find((ac) => !ac.excluded);
2652
- const tombstone = webDevConfigs.find((ac) => ac.excluded);
2653
- globalExpect(active?.scope).toBe("project");
2654
- globalExpect(tombstone?.scope).toBe("global");
2655
- globalExpect(tombstone?.excluded).toBe(true);
2656
- });
2657
- it("preserves excluded tombstone in preselectAgentsFromStack when active entry exists at different scope", () => {
2658
- const store = useWizardStore.getState();
2659
- useWizardStore.setState({
2660
- globalAgentPreselections: {
2661
- agents: ["web-developer"],
2662
- configs: [
2663
- ...buildAgentConfigs(["web-developer"]),
2664
- ...buildAgentConfigs(["web-developer"], { scope: "global", excluded: true })
2665
- ]
2666
- }
2667
- });
2668
- store.preselectAgentsFromStack(["web-developer"]);
2669
- const { agentConfigs } = useWizardStore.getState();
2670
- const webDevConfigs = agentConfigs.filter((ac) => ac.name === "web-developer");
2671
- globalExpect(webDevConfigs).toHaveLength(2);
2672
- const active = webDevConfigs.find((ac) => !ac.excluded);
2673
- const tombstone = webDevConfigs.find((ac) => ac.excluded);
2674
- globalExpect(active?.scope).toBe("project");
2675
- globalExpect(tombstone?.scope).toBe("global");
2676
- globalExpect(tombstone?.excluded).toBe(true);
2677
- });
2678
- });
2679
- describe("step progress with agents step", () => {
2680
- it("should include agents in completed steps when on confirm", () => {
2681
- const store = useWizardStore.getState();
2682
- store.setApproach("scratch");
2683
- store.setStep("domains");
2684
- store.setStep("build");
2685
- store.setStep("sources");
2686
- store.setStep("agents");
2687
- store.setStep("confirm");
2688
- const { completedSteps } = store.getStepProgress();
2689
- globalExpect(completedSteps).toContain("stack");
2690
- globalExpect(completedSteps).toContain("domains");
2691
- globalExpect(completedSteps).toContain("agents");
2692
- globalExpect(completedSteps).toContain("sources");
2693
- globalExpect(completedSteps).toContain("build");
2694
- });
2695
- it("should include sources in completed steps when on agents step", () => {
2696
- const store = useWizardStore.getState();
2697
- store.setApproach("scratch");
2698
- store.setStep("domains");
2699
- store.setStep("build");
2700
- store.setStep("sources");
2701
- store.setStep("agents");
2702
- const { completedSteps } = store.getStepProgress();
2703
- globalExpect(completedSteps).toContain("stack");
2704
- globalExpect(completedSteps).toContain("domains");
2705
- globalExpect(completedSteps).toContain("build");
2706
- globalExpect(completedSteps).toContain("sources");
2707
- globalExpect(completedSteps).not.toContain("agents");
2708
- });
2709
- it("should skip agents step when using stack defaults", () => {
2710
- const store = useWizardStore.getState();
2711
- store.setApproach("stack");
2712
- store.selectStack("nextjs-fullstack");
2713
- store.setStackAction("defaults");
2714
- store.setStep("confirm");
2715
- const { skippedSteps } = store.getStepProgress();
2716
- globalExpect(skippedSteps).toContain("agents");
2717
- globalExpect(skippedSteps).toContain("build");
2718
- globalExpect(skippedSteps).toContain("sources");
2719
- });
2720
- });
2721
- describe("deriveInstallMode", () => {
2722
- it("should return 'plugin' when all skills have default marketplace source", () => {
2723
- const store = useWizardStore.getState();
2724
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2725
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", true);
2726
- const result = store.deriveInstallMode();
2727
- globalExpect(result).toBe("plugin");
2728
- });
2729
- it("should return 'eject' when all skills are set to eject", () => {
2730
- const store = useWizardStore.getState();
2731
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2732
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
2733
- store.setSourceSelection("web-framework-react", "eject", "global");
2734
- store.setSourceSelection("api-framework-hono", "eject", "global");
2735
- const result = store.deriveInstallMode();
2736
- globalExpect(result).toBe("eject");
2737
- });
2738
- it("should return 'mixed' when some skills are local and some are not", () => {
2739
- const store = useWizardStore.getState();
2740
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2741
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
2742
- store.setSourceSelection("web-framework-react", "eject", "global");
2743
- store.setSourceSelection("api-framework-hono", "agents-inc", "global");
2744
- const result = store.deriveInstallMode();
2745
- globalExpect(result).toBe("mixed");
2746
- });
2747
- it("should return 'local' when no skills are configured", () => {
2748
- const store = useWizardStore.getState();
2749
- const result = store.deriveInstallMode();
2750
- globalExpect(result).toBe("eject");
2751
- });
2752
- it("should handle single skill as local", () => {
2753
- const store = useWizardStore.getState();
2754
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2755
- store.setSourceSelection("web-framework-react", "eject", "global");
2756
- const result = store.deriveInstallMode();
2757
- globalExpect(result).toBe("eject");
2758
- });
2759
- it("should handle single skill as plugin", () => {
2760
- const store = useWizardStore.getState();
2761
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2762
- const result = store.deriveInstallMode();
2763
- globalExpect(result).toBe("plugin");
2764
- });
2765
- });
2766
- describe("toggleFilterIncompatible", () => {
2767
- it("should deselect framework-incompatible skills from web categories when enabling filter", () => {
2768
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2769
- const store = useWizardStore.getState();
2770
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2771
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2772
- globalExpect(useWizardStore.getState().domainSelections.web["web-client-state"]).toContain(
2773
- "web-state-pinia"
2774
- );
2775
- store.toggleFilterIncompatible();
2776
- const state = useWizardStore.getState();
2777
- globalExpect(state.filterIncompatible).toBe(true);
2778
- globalExpect(state.domainSelections.web["web-client-state"]).not.toContain("web-state-pinia");
2779
- });
2780
- it("should NOT deselect framework-compatible skills when enabling filter", () => {
2781
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2782
- const store = useWizardStore.getState();
2783
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2784
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
2785
- store.toggleFilterIncompatible();
2786
- const state = useWizardStore.getState();
2787
- globalExpect(state.filterIncompatible).toBe(true);
2788
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-zustand");
2789
- });
2790
- it("should NOT deselect skills in non-web domains when enabling filter", () => {
2791
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2792
- const store = useWizardStore.getState();
2793
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2794
- store.toggleTechnology("api", "api-api", "api-framework-hono", true);
2795
- store.toggleFilterIncompatible();
2796
- const state = useWizardStore.getState();
2797
- globalExpect(state.domainSelections.api["api-api"]).toStrictEqual(["api-framework-hono"]);
2798
- });
2799
- it("should NOT deselect the framework category itself when enabling filter", () => {
2800
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2801
- const store = useWizardStore.getState();
2802
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2803
- store.toggleFilterIncompatible();
2804
- const state = useWizardStore.getState();
2805
- globalExpect(state.domainSelections.web["web-framework"]).toStrictEqual(["web-framework-react"]);
2806
- });
2807
- it("should skip excluded skills when filtering incompatible", () => {
2808
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2809
- const store = useWizardStore.getState();
2810
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2811
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2812
- useWizardStore.setState({
2813
- skillConfigs: useWizardStore.getState().skillConfigs.map((sc) => sc.id === "web-state-pinia" ? { ...sc, excluded: true } : sc)
2814
- });
2815
- store.toggleFilterIncompatible();
2816
- const state = useWizardStore.getState();
2817
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-pinia");
2818
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-pinia")).toBe(true);
2819
- });
2820
- it("should NOT deselect anything when disabling filter", () => {
2821
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2822
- const store = useWizardStore.getState();
2823
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2824
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
2825
- store.toggleFilterIncompatible();
2826
- store.toggleFilterIncompatible();
2827
- const state = useWizardStore.getState();
2828
- globalExpect(state.filterIncompatible).toBe(false);
2829
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-zustand");
2830
- });
2831
- it("should remove global incompatible skills from skillConfigs during fresh init", () => {
2832
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2833
- const store = useWizardStore.getState();
2834
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2835
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2836
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
2837
- globalExpect(useWizardStore.getState().skillConfigs.some((sc) => sc.id === "web-state-pinia")).toBe(
2838
- true
2839
- );
2840
- globalExpect(
2841
- useWizardStore.getState().skillConfigs.some((sc) => sc.id === "web-state-zustand")
2842
- ).toBe(true);
2843
- store.toggleFilterIncompatible();
2844
- const state = useWizardStore.getState();
2845
- globalExpect(state.domainSelections.web["web-client-state"]).not.toContain("web-state-pinia");
2846
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-pinia")).toBe(false);
2847
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-zustand");
2848
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-zustand")).toBe(true);
2849
- });
2850
- it("removes global incompatible skills cleanly (no tombstone) while editing from global scope", () => {
2851
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2852
- const store = useWizardStore.getState();
2853
- useWizardStore.setState({
2854
- installedSkillConfigs: buildSkillConfigs(["web-state-pinia"], {
2855
- scope: "global",
2856
- source: "agents-inc"
2857
- }),
2858
- isEditingFromGlobalScope: true
2859
- });
2860
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2861
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2862
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
2863
- store.toggleFilterIncompatible();
2864
- const state = useWizardStore.getState();
2865
- globalExpect(state.domainSelections.web["web-client-state"]).not.toContain("web-state-pinia");
2866
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-pinia")).toBe(false);
2867
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-zustand");
2868
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-zustand")).toBe(true);
2869
- });
2870
- it("should just toggle the boolean when no frameworks are selected", () => {
2871
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2872
- const store = useWizardStore.getState();
2873
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2874
- store.toggleFilterIncompatible();
2875
- const state = useWizardStore.getState();
2876
- globalExpect(state.filterIncompatible).toBe(true);
2877
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-pinia");
2878
- });
2879
- it("should not deselect skills with empty compatibleWith when enabling filter", () => {
2880
- initializeMatrix(ALL_SKILLS_TEST_CATEGORIES_MATRIX);
2881
- const store = useWizardStore.getState();
2882
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2883
- store.toggleTechnology("web", "web-styling", "web-styling-scss-modules", false);
2884
- store.toggleFilterIncompatible();
2885
- const state = useWizardStore.getState();
2886
- globalExpect(state.domainSelections.web["web-styling"]).toContain("web-styling-scss-modules");
2887
- });
2888
- it("refuses to uninstall an actively-installed global skill from project scope", () => {
2889
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2890
- const store = useWizardStore.getState();
2891
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2892
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2893
- store.toggleTechnology("web", "web-client-state", "web-state-zustand", false);
2894
- useWizardStore.setState({
2895
- installedSkillConfigs: buildSkillConfigs(["web-state-pinia"], {
2896
- scope: "global",
2897
- source: "eject"
2898
- }),
2899
- isEditingFromGlobalScope: false,
2900
- isInitMode: false
2901
- });
2902
- store.toggleFilterIncompatible();
2903
- const state = useWizardStore.getState();
2904
- globalExpect(state.toastMessage).toBe("Global skills cannot be changed from project scope");
2905
- globalExpect(state.filterIncompatible).toBe(false);
2906
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-pinia");
2907
- globalExpect(state.skillConfigs.some((sc) => sc.id === "web-state-pinia")).toBe(true);
2908
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-zustand");
2909
- });
2910
- it("refuses the filter when a stale global tombstone has collapsed to an active global entry", () => {
2911
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2912
- const store = useWizardStore.getState();
2913
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2914
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2915
- useWizardStore.setState({
2916
- skillConfigs: buildSkillConfigs(["web-state-pinia"], {
2917
- scope: "global",
2918
- source: "eject"
2919
- }),
2920
- installedSkillConfigs: [
2921
- ...buildSkillConfigs(["web-state-pinia"], { scope: "project", source: "eject" }),
2922
- ...buildSkillConfigs(["web-state-pinia"], {
2923
- scope: "global",
2924
- source: "eject",
2925
- excluded: true
2926
- })
2927
- ],
2928
- isEditingFromGlobalScope: false,
2929
- isInitMode: false
2930
- });
2931
- store.toggleFilterIncompatible();
2932
- const state = useWizardStore.getState();
2933
- globalExpect(state.toastMessage).toBe("Global skills cannot be changed from project scope");
2934
- globalExpect(state.filterIncompatible).toBe(false);
2935
- globalExpect(state.skillConfigs).toStrictEqual(
2936
- buildSkillConfigs(["web-state-pinia"], { scope: "global", source: "eject" })
2937
- );
2938
- });
2939
- it("refuses to uninstall an actively-installed global skill in init mode too", () => {
2940
- initializeMatrix(ALL_SKILLS_FULLSTACK_CATEGORIES_MATRIX);
2941
- const store = useWizardStore.getState();
2942
- store.toggleTechnology("web", "web-framework", "web-framework-react", true);
2943
- store.toggleTechnology("web", "web-client-state", "web-state-pinia", false);
2944
- useWizardStore.setState({
2945
- installedSkillConfigs: buildSkillConfigs(["web-state-pinia"], {
2946
- scope: "global",
2947
- source: "eject"
2948
- }),
2949
- isInitMode: true
2950
- });
2951
- const skillConfigsBefore = [...useWizardStore.getState().skillConfigs];
2952
- store.toggleFilterIncompatible();
2953
- const state = useWizardStore.getState();
2954
- globalExpect(state.toastMessage).toBe("Global skills cannot be changed from project scope");
2955
- globalExpect(state.filterIncompatible).toBe(false);
2956
- globalExpect(state.domainSelections.web["web-client-state"]).toContain("web-state-pinia");
2957
- globalExpect(
2958
- state.skillConfigs,
2959
- "a refused filter must leave skillConfigs untouched"
2960
- ).toStrictEqual(skillConfigsBefore);
2961
- });
2962
- });
2963
- describe("setToastMessage", () => {
2964
- it("should set and clear toast message", () => {
2965
- const store = useWizardStore.getState();
2966
- store.setToastMessage("hello");
2967
- globalExpect(useWizardStore.getState().toastMessage).toBe("hello");
2968
- store.setToastMessage(null);
2969
- globalExpect(useWizardStore.getState().toastMessage).toBeNull();
2970
- });
2971
- });
2972
- describe("hydrateWizardStore", () => {
2973
- beforeEach(() => {
2974
- initializeMatrix(REACT_HONO_FRAMEWORK_API_MATRIX);
2975
- });
2976
- it("sets edit-mode state when initialStep is provided", () => {
2977
- hydrateWizardStore({
2978
- initialStep: "build",
2979
- initialDomains: ["web"],
2980
- installedSkillIds: ["web-framework-react"]
2981
- });
2982
- const state = useWizardStore.getState();
2983
- globalExpect(state.step).toBe("build");
2984
- globalExpect(state.history).toStrictEqual([]);
2985
- globalExpect(state.approach).toBe("scratch");
2986
- globalExpect(state.selectedDomains).toStrictEqual(["web"]);
2987
- globalExpect(state.isInitMode).toBe(false);
2988
- });
2989
- it("sets init-mode defaults when no options are provided", () => {
2990
- hydrateWizardStore({});
2991
- const state = useWizardStore.getState();
2992
- globalExpect(state.step).toBe("stack");
2993
- globalExpect(state.history).toStrictEqual([]);
2994
- globalExpect(state.isInitMode).toBe(true);
2995
- });
2996
- it("populates installedSkillConfigs for diff rendering", () => {
2997
- const skillConfigs = [
2998
- { id: "web-framework-react", scope: "global", source: "eject" }
2999
- ];
3000
- hydrateWizardStore({
3001
- initialStep: "build",
3002
- installedSkillConfigs: skillConfigs
3003
- });
3004
- const state = useWizardStore.getState();
3005
- globalExpect(state.installedSkillConfigs).toStrictEqual(skillConfigs);
3006
- });
3007
- it("sets isEditingFromGlobalScope when flag is true", () => {
3008
- hydrateWizardStore({
3009
- initialStep: "build",
3010
- isEditingFromGlobalScope: true
3011
- });
3012
- globalExpect(useWizardStore.getState().isEditingFromGlobalScope).toBe(true);
3013
- });
3014
- it("resets prior store state before applying new hydration", () => {
3015
- useWizardStore.setState({ step: "confirm", selectedDomains: ["api"] });
3016
- hydrateWizardStore({
3017
- initialStep: "build",
3018
- initialDomains: ["web"]
3019
- });
3020
- const state = useWizardStore.getState();
3021
- globalExpect(state.step).toBe("build");
3022
- globalExpect(state.selectedDomains).toStrictEqual(["web"]);
3023
- });
3024
- it("stores globalPreselections in init flow when installedSkillConfigs provided", () => {
3025
- const skillConfigs = [
3026
- { id: "web-framework-react", scope: "global", source: "eject" }
3027
- ];
3028
- hydrateWizardStore({
3029
- installedSkillConfigs: skillConfigs
3030
- });
3031
- const state = useWizardStore.getState();
3032
- globalExpect(state.isInitMode).toBe(true);
3033
- globalExpect(state.globalPreselections).toStrictEqual(skillConfigs);
3034
- });
3035
- it("seeds focusedSkillId to the active domain's first grid option (edit flow)", () => {
3036
- hydrateWizardStore({
3037
- initialStep: "build",
3038
- initialDomains: ["web"],
3039
- installedSkillIds: ["web-framework-react"]
3040
- });
3041
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
3042
- });
3043
- it("seeds focusedSkillId to the active domain's first grid option (init flow)", () => {
3044
- hydrateWizardStore({ initialDomains: ["web"] });
3045
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
3046
- });
3047
- it("seeds focusedSkillId to the fallback domain's first grid option when no domains are selected", () => {
3048
- hydrateWizardStore({});
3049
- globalExpect(useWizardStore.getState().focusedSkillId).toBe("web-framework-react");
3050
- });
3051
- });
3052
- });
3053
- //# sourceMappingURL=wizard-store.test.js.map