agents-inc 0.150.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 (255) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/{chunk-FWT3CBLL.js → chunk-5GUOIJSG.js} +3 -7
  3. package/dist/{chunk-FWT3CBLL.js.map → chunk-5GUOIJSG.js.map} +1 -1
  4. package/dist/{chunk-MC5DUZ3V.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-7URSGJLE.js → chunk-BNSRA6HL.js} +13 -18
  9. package/dist/{chunk-7URSGJLE.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-YKKIJHZB.js → chunk-E5X6RJ4E.js} +5 -15
  13. package/dist/chunk-E5X6RJ4E.js.map +1 -0
  14. package/dist/{chunk-KH7MOIM5.js → chunk-EEPELKOM.js} +3665 -3737
  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-4GL2F5AB.js → chunk-FVDKAVOL.js} +57 -48
  19. package/dist/chunk-FVDKAVOL.js.map +1 -0
  20. package/dist/{chunk-UZRISDBZ.js → chunk-GRVKW3CC.js} +2 -6
  21. package/dist/{chunk-UZRISDBZ.js.map → chunk-GRVKW3CC.js.map} +1 -1
  22. package/dist/{chunk-CDMHSHBN.js → chunk-IHUY4M22.js} +4 -8
  23. package/dist/{chunk-CDMHSHBN.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-4LPJZNT7.js → chunk-KFB5CRXZ.js} +7 -12
  31. package/dist/{chunk-4LPJZNT7.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-ZHTXPFDK.js → chunk-L7SZXUBJ.js} +9 -14
  37. package/dist/{chunk-ZHTXPFDK.js.map → chunk-L7SZXUBJ.js.map} +1 -1
  38. package/dist/{chunk-LRYNF3J7.js → chunk-LASI35KT.js} +4 -9
  39. package/dist/{chunk-LRYNF3J7.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-GRPSDKIS.js → chunk-LZ52XEPR.js} +4 -8
  43. package/dist/{chunk-GRPSDKIS.js.map → chunk-LZ52XEPR.js.map} +1 -1
  44. package/dist/{chunk-CFQT72MJ.js → chunk-M7HO7NBK.js} +4 -8
  45. package/dist/{chunk-CFQT72MJ.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-F3756A5B.js → chunk-MQ7FLIYS.js} +2 -6
  51. package/dist/{chunk-F3756A5B.js.map → chunk-MQ7FLIYS.js.map} +1 -1
  52. package/dist/{chunk-NUIZ6ZUO.js → chunk-MVR3SYMN.js} +6 -8
  53. package/dist/chunk-MVR3SYMN.js.map +1 -0
  54. package/dist/{chunk-ZKJAJWK6.js → chunk-MWG4VU64.js} +12 -17
  55. package/dist/{chunk-ZKJAJWK6.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-6I6RZHYP.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-HIPGKIT3.js → chunk-QRDTLVXG.js} +9 -14
  71. package/dist/{chunk-HIPGKIT3.js.map → chunk-QRDTLVXG.js.map} +1 -1
  72. package/dist/{chunk-VIFZ6NFH.js → chunk-QZZJFYUQ.js} +3 -7
  73. package/dist/{chunk-VIFZ6NFH.js.map → chunk-QZZJFYUQ.js.map} +1 -1
  74. package/dist/{chunk-E4FT2KFV.js → chunk-R5NOI2LP.js} +13 -17
  75. package/dist/{chunk-E4FT2KFV.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-N4IZ6GBO.js → chunk-SBHBBZKF.js} +7 -23
  79. package/dist/chunk-SBHBBZKF.js.map +1 -0
  80. package/dist/{chunk-EN2GCPW7.js → chunk-SKQWRUPX.js} +10 -14
  81. package/dist/{chunk-EN2GCPW7.js.map → chunk-SKQWRUPX.js.map} +1 -1
  82. package/dist/{chunk-DDG4F3FE.js → chunk-STMHDOZD.js} +4 -21
  83. package/dist/chunk-STMHDOZD.js.map +1 -0
  84. package/dist/{chunk-5K5RBRTD.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-RP7R73JO.js → chunk-TUPYW2IQ.js} +3 -7
  91. package/dist/{chunk-RP7R73JO.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-DJAZE4PD.js → chunk-WKTHWQKM.js} +297 -302
  101. package/dist/chunk-WKTHWQKM.js.map +1 -0
  102. package/dist/{chunk-RJN7W2C7.js → chunk-XHUODHZ4.js} +19 -25
  103. package/dist/{chunk-RJN7W2C7.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-ZDLTLNU2.js → chunk-ZPPHXXAP.js} +9 -15
  109. package/dist/{chunk-ZDLTLNU2.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-VVHMQEX5.js → source-loader-MZYCPL2S.js} +7 -8
  176. package/dist/stores/wizard-store.js +7 -8
  177. package/package.json +22 -21
  178. package/dist/chunk-4GL2F5AB.js.map +0 -1
  179. package/dist/chunk-5K5RBRTD.js.map +0 -1
  180. package/dist/chunk-6I6RZHYP.js.map +0 -1
  181. package/dist/chunk-C55DN7GE.js.map +0 -1
  182. package/dist/chunk-DAG2ULNF.js.map +0 -1
  183. package/dist/chunk-DDG4F3FE.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-DJAZE4PD.js.map +0 -1
  187. package/dist/chunk-EKWAUOQB.js +0 -96
  188. package/dist/chunk-EKWAUOQB.js.map +0 -1
  189. package/dist/chunk-I3XKEGHM.js +0 -16383
  190. package/dist/chunk-I3XKEGHM.js.map +0 -1
  191. package/dist/chunk-IHO75PMZ.js.map +0 -1
  192. package/dist/chunk-K3OU6TGX.js +0 -77
  193. package/dist/chunk-K3OU6TGX.js.map +0 -1
  194. package/dist/chunk-KH7MOIM5.js.map +0 -1
  195. package/dist/chunk-KSZ6PCY4.js +0 -43
  196. package/dist/chunk-KSZ6PCY4.js.map +0 -1
  197. package/dist/chunk-MC5DUZ3V.js.map +0 -1
  198. package/dist/chunk-N4IZ6GBO.js.map +0 -1
  199. package/dist/chunk-NUIZ6ZUO.js.map +0 -1
  200. package/dist/chunk-OA5SUEQD.js +0 -181
  201. package/dist/chunk-OA5SUEQD.js.map +0 -1
  202. package/dist/chunk-P56WJ5FA.js +0 -50
  203. package/dist/chunk-P56WJ5FA.js.map +0 -1
  204. package/dist/chunk-SYUOXSPU.js.map +0 -1
  205. package/dist/chunk-THKIOI32.js +0 -939
  206. package/dist/chunk-THKIOI32.js.map +0 -1
  207. package/dist/chunk-V7QOSGQA.js +0 -298
  208. package/dist/chunk-V7QOSGQA.js.map +0 -1
  209. package/dist/chunk-YKKIJHZB.js.map +0 -1
  210. package/dist/components/common/confirm.test.js +0 -203
  211. package/dist/components/common/confirm.test.js.map +0 -1
  212. package/dist/components/wizard/category-grid.test.js +0 -1253
  213. package/dist/components/wizard/category-grid.test.js.map +0 -1
  214. package/dist/components/wizard/checkbox-grid.test.js +0 -264
  215. package/dist/components/wizard/checkbox-grid.test.js.map +0 -1
  216. package/dist/components/wizard/search-modal.test.js +0 -212
  217. package/dist/components/wizard/search-modal.test.js.map +0 -1
  218. package/dist/components/wizard/source-grid.test.js +0 -1094
  219. package/dist/components/wizard/source-grid.test.js.map +0 -1
  220. package/dist/components/wizard/step-agents.test.js +0 -204
  221. package/dist/components/wizard/step-agents.test.js.map +0 -1
  222. package/dist/components/wizard/step-build.test.js +0 -552
  223. package/dist/components/wizard/step-build.test.js.map +0 -1
  224. package/dist/components/wizard/step-confirm.test.js +0 -744
  225. package/dist/components/wizard/step-confirm.test.js.map +0 -1
  226. package/dist/components/wizard/step-settings.test.js +0 -244
  227. package/dist/components/wizard/step-settings.test.js.map +0 -1
  228. package/dist/components/wizard/step-sources.test.js +0 -155
  229. package/dist/components/wizard/step-sources.test.js.map +0 -1
  230. package/dist/components/wizard/step-stack.test.js +0 -262
  231. package/dist/components/wizard/step-stack.test.js.map +0 -1
  232. package/dist/components/wizard/summary-panel.test.js +0 -317
  233. package/dist/components/wizard/summary-panel.test.js.map +0 -1
  234. package/dist/components/wizard/wizard-layout.test.js +0 -200
  235. package/dist/components/wizard/wizard-layout.test.js.map +0 -1
  236. package/dist/components/wizard/wizard-tabs.test.js +0 -290
  237. package/dist/components/wizard/wizard-tabs.test.js.map +0 -1
  238. package/dist/copy-local-skills-CA7P73RZ.js +0 -15
  239. package/dist/dist-VNJNNJK7.js +0 -550
  240. package/dist/dist-VNJNNJK7.js.map +0 -1
  241. package/dist/load-agent-defs-6MAY5ABI.js +0 -16
  242. package/dist/magic-string.es-5TV73NJD.js +0 -1316
  243. package/dist/magic-string.es-5TV73NJD.js.map +0 -1
  244. package/dist/recompile-project-agents-VYQJ6UZB.js +0 -20
  245. package/dist/source-manager-TPDXV5FO.js +0 -18
  246. package/dist/source-manager-TPDXV5FO.js.map +0 -1
  247. package/dist/stores/d227-same-scope-tombstone-duplicate.test.js +0 -118
  248. package/dist/stores/d227-same-scope-tombstone-duplicate.test.js.map +0 -1
  249. package/dist/stores/wizard-store.test.js +0 -3053
  250. package/dist/stores/wizard-store.test.js.map +0 -1
  251. /package/dist/{copy-local-skills-CA7P73RZ.js.map → copy-local-skills-6EMVN7RB.js.map} +0 -0
  252. /package/dist/{load-agent-defs-6MAY5ABI.js.map → load-agent-defs-BWOUVEAR.js.map} +0 -0
  253. /package/dist/{loader-E2ERJYVA.js.map → loader-5JP4S7CJ.js.map} +0 -0
  254. /package/dist/{recompile-project-agents-VYQJ6UZB.js.map → recompile-project-agents-6DL45TDI.js.map} +0 -0
  255. /package/dist/{source-loader-VVHMQEX5.js.map → source-loader-MZYCPL2S.js.map} +0 -0
@@ -1,1094 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- ARROW_DOWN,
4
- ARROW_LEFT,
5
- ARROW_RIGHT,
6
- ARROW_UP,
7
- ENTER,
8
- ESCAPE,
9
- INPUT_DELAY_MS,
10
- RENDER_DELAY_MS,
11
- SPACE,
12
- delay
13
- } from "../../chunk-KSZ6PCY4.js";
14
- import {
15
- render
16
- } from "../../chunk-EKWAUOQB.js";
17
- import {
18
- WEB_TRIO_MATRIX
19
- } from "../../chunk-THKIOI32.js";
20
- import "../../chunk-K3OU6TGX.js";
21
- import {
22
- createMockMatrix,
23
- createMockSkill
24
- } from "../../chunk-V7QOSGQA.js";
25
- import {
26
- afterEach,
27
- beforeEach,
28
- describe,
29
- globalExpect,
30
- it,
31
- vi
32
- } from "../../chunk-I3XKEGHM.js";
33
- import {
34
- SourceGrid
35
- } from "../../chunk-7URSGJLE.js";
36
- import "../../chunk-NIKUMXE7.js";
37
- import "../../chunk-KOPEM3Q7.js";
38
- import "../../chunk-2RSNKBXC.js";
39
- import "../../chunk-DUVWGO6E.js";
40
- import "../../chunk-KIR7VYQD.js";
41
- import "../../chunk-LYYXX2W5.js";
42
- import "../../chunk-DAG2ULNF.js";
43
- import "../../chunk-VG2TVBFN.js";
44
- import "../../chunk-IHO75PMZ.js";
45
- import {
46
- source_default
47
- } from "../../chunk-SYUOXSPU.js";
48
- import {
49
- BUILT_IN_MATRIX,
50
- getSkillById,
51
- initializeMatrix
52
- } from "../../chunk-DJAZE4PD.js";
53
- import "../../chunk-VEP23B5W.js";
54
- import {
55
- CLI_COLORS,
56
- UI_SYMBOLS
57
- } from "../../chunk-O5ASLZ2K.js";
58
- import {
59
- init_esm_shims
60
- } from "../../chunk-P56WJ5FA.js";
61
-
62
- // src/cli/components/wizard/source-grid.test.tsx
63
- init_esm_shims();
64
- import { jsx } from "react/jsx-runtime";
65
- var TRUECOLOR_CHALK_LEVEL = 3;
66
- var createSourceOption = (id, overrides = {}) => ({
67
- id,
68
- selected: false,
69
- installed: false,
70
- ...overrides
71
- });
72
- var createSourceRow = (skillId, options, scope, readOnly) => ({
73
- skillId,
74
- options,
75
- scope,
76
- ...readOnly ? { readOnly } : {}
77
- });
78
- var createRemovedRow = (skillId, options, scope) => ({
79
- ...createSourceRow(skillId, options, scope),
80
- disabled: true
81
- });
82
- var createAddedRow = (skillId, options, scope) => ({
83
- ...createSourceRow(skillId, options, scope),
84
- added: true
85
- });
86
- var defaultRows = [
87
- createSourceRow("web-framework-react", [createSourceOption("public", { selected: true })]),
88
- createSourceRow("web-state-zustand", [createSourceOption("public", { selected: true })]),
89
- createSourceRow("web-testing-vitest", [createSourceOption("public", { selected: true })])
90
- ];
91
- var multiSourceRows = [
92
- createSourceRow("web-framework-react", [
93
- createSourceOption("public", { selected: true }),
94
- createSourceOption("acme-corp")
95
- ]),
96
- createSourceRow("web-state-zustand", [
97
- createSourceOption("public", { selected: true }),
98
- createSourceOption("acme-corp"),
99
- createSourceOption("internal")
100
- ])
101
- ];
102
- var defaultProps = {
103
- rows: defaultRows,
104
- defaultFocusedRow: 0,
105
- defaultFocusedCol: 0,
106
- onSelect: vi.fn(),
107
- onFocusChange: vi.fn()
108
- };
109
- var renderGrid = (props = {}) => {
110
- return render(/* @__PURE__ */ jsx(SourceGrid, { ...defaultProps, ...props }));
111
- };
112
- describe("SourceGrid component", () => {
113
- let cleanup;
114
- beforeEach(() => {
115
- initializeMatrix(WEB_TRIO_MATRIX);
116
- });
117
- afterEach(() => {
118
- cleanup?.();
119
- cleanup = void 0;
120
- initializeMatrix(BUILT_IN_MATRIX);
121
- });
122
- describe("rendering", () => {
123
- it("should render all skill rows", () => {
124
- const { lastFrame, unmount } = renderGrid();
125
- cleanup = unmount;
126
- const output = lastFrame();
127
- globalExpect(output).toContain("React");
128
- globalExpect(output).toContain("Zustand");
129
- globalExpect(output).toContain("Vitest");
130
- });
131
- it("should render source option labels", () => {
132
- const { lastFrame, unmount } = renderGrid();
133
- cleanup = unmount;
134
- const output = lastFrame();
135
- globalExpect(output).toContain("Public");
136
- });
137
- it("should render multiple source options per row", () => {
138
- const { lastFrame, unmount } = renderGrid({ rows: multiSourceRows });
139
- cleanup = unmount;
140
- const output = lastFrame();
141
- globalExpect(output).toContain("Public");
142
- globalExpect(output).toContain("acme-corp");
143
- });
144
- it("should handle empty rows array", () => {
145
- const { lastFrame, unmount } = renderGrid({ rows: [] });
146
- cleanup = unmount;
147
- const output = lastFrame();
148
- globalExpect(output).toContain("No skills to display");
149
- });
150
- it("should render single row", () => {
151
- const rows = [
152
- createSourceRow("web-framework-react", [createSourceOption("public", { selected: true })])
153
- ];
154
- const { lastFrame, unmount } = renderGrid({ rows });
155
- cleanup = unmount;
156
- const output = lastFrame();
157
- globalExpect(output).toContain("React");
158
- globalExpect(output).toContain("Public");
159
- });
160
- });
161
- describe("scope-grouped rendering", () => {
162
- it("should head each scope block with its own row header and caption no column", () => {
163
- const rows = [
164
- createSourceRow(
165
- "web-framework-react",
166
- [createSourceOption("public", { selected: true })],
167
- "global"
168
- ),
169
- createSourceRow(
170
- "web-state-zustand",
171
- [createSourceOption("public", { selected: true })],
172
- "project"
173
- )
174
- ];
175
- const { lastFrame, unmount } = renderGrid({ rows });
176
- cleanup = unmount;
177
- const output = lastFrame();
178
- globalExpect(output).toContain("React");
179
- globalExpect(output).toContain("Zustand");
180
- globalExpect(output).toContain("Global");
181
- globalExpect(output).toContain("Project");
182
- globalExpect(output).not.toContain("Scope");
183
- });
184
- it("should show global rows before project rows", () => {
185
- const rows = [
186
- createSourceRow(
187
- "web-state-zustand",
188
- [createSourceOption("public", { selected: true })],
189
- "project"
190
- ),
191
- createSourceRow(
192
- "web-framework-react",
193
- [createSourceOption("public", { selected: true })],
194
- "global"
195
- )
196
- ];
197
- const { lastFrame, unmount } = renderGrid({ rows });
198
- cleanup = unmount;
199
- const output = lastFrame();
200
- const globalPos = output.indexOf("React");
201
- const projectPos = output.indexOf("Zustand");
202
- globalExpect(globalPos).toBeGreaterThan(-1);
203
- globalExpect(projectPos).toBeGreaterThan(-1);
204
- globalExpect(globalPos).toBeLessThan(projectPos);
205
- });
206
- it("heads each block in the gutter and lines the source captions up with their cells", () => {
207
- const rows = [
208
- createSourceRow(
209
- "web-framework-react",
210
- [createSourceOption("eject"), createSourceOption("agents-inc", { selected: true })],
211
- "global"
212
- ),
213
- createSourceRow(
214
- "web-state-zustand",
215
- [createSourceOption("eject", { selected: true }), createSourceOption("agents-inc")],
216
- "project"
217
- )
218
- ];
219
- const { lastFrame, unmount } = renderGrid({ rows });
220
- cleanup = unmount;
221
- globalExpect(lastFrame()).toMatchInlineSnapshot(`
222
- " Local Plugin
223
-
224
- Global React \u276F Eject Agents Inc
225
-
226
- Project Zustand Eject Agents Inc"
227
- `);
228
- });
229
- it("renders one unseparated block in the flat layout", () => {
230
- const rows = [
231
- createSourceRow(
232
- "web-framework-react",
233
- [createSourceOption("eject"), createSourceOption("agents-inc", { selected: true })],
234
- "project"
235
- ),
236
- createSourceRow(
237
- "web-state-zustand",
238
- [createSourceOption("eject", { selected: true }), createSourceOption("agents-inc")],
239
- "project"
240
- )
241
- ];
242
- const { lastFrame, unmount } = renderGrid({ rows });
243
- cleanup = unmount;
244
- globalExpect(lastFrame()).toMatchInlineSnapshot(`
245
- " Local Plugin
246
-
247
- React \u276F Eject Agents Inc
248
- Zustand Eject Agents Inc"
249
- `);
250
- });
251
- it("renders one unseparated block when no row has a scope", () => {
252
- const rows = [
253
- createSourceRow("web-framework-react", [
254
- createSourceOption("eject"),
255
- createSourceOption("agents-inc", { selected: true })
256
- ]),
257
- createSourceRow("web-state-zustand", [
258
- createSourceOption("eject", { selected: true }),
259
- createSourceOption("agents-inc")
260
- ])
261
- ];
262
- const { lastFrame, unmount } = renderGrid({ rows });
263
- cleanup = unmount;
264
- globalExpect(lastFrame()).toMatchInlineSnapshot(`
265
- " Local Plugin
266
-
267
- React \u276F Eject Agents Inc
268
- Zustand Eject Agents Inc"
269
- `);
270
- });
271
- });
272
- describe("keyboard navigation - vertical", () => {
273
- it("should move down with arrow down", async () => {
274
- const onFocusChange = vi.fn();
275
- const { stdin, unmount } = renderGrid({
276
- defaultFocusedRow: 0,
277
- defaultFocusedCol: 0,
278
- onFocusChange
279
- });
280
- cleanup = unmount;
281
- await delay(RENDER_DELAY_MS);
282
- stdin.write(ARROW_DOWN);
283
- await delay(INPUT_DELAY_MS);
284
- globalExpect(onFocusChange).toHaveBeenCalledWith(1, 0);
285
- });
286
- it("should move up with arrow up", async () => {
287
- const onFocusChange = vi.fn();
288
- const { stdin, unmount } = renderGrid({
289
- defaultFocusedRow: 1,
290
- defaultFocusedCol: 0,
291
- onFocusChange
292
- });
293
- cleanup = unmount;
294
- await delay(RENDER_DELAY_MS);
295
- stdin.write(ARROW_UP);
296
- await delay(INPUT_DELAY_MS);
297
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
298
- });
299
- it("should wrap down to first row from last row", async () => {
300
- const onFocusChange = vi.fn();
301
- const { stdin, unmount } = renderGrid({
302
- defaultFocusedRow: 2,
303
- // Last row (Vitest)
304
- defaultFocusedCol: 0,
305
- onFocusChange
306
- });
307
- cleanup = unmount;
308
- await delay(RENDER_DELAY_MS);
309
- stdin.write(ARROW_DOWN);
310
- await delay(INPUT_DELAY_MS);
311
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
312
- });
313
- it("should wrap up to last row from first row", async () => {
314
- const onFocusChange = vi.fn();
315
- const { stdin, unmount } = renderGrid({
316
- defaultFocusedRow: 0,
317
- defaultFocusedCol: 0,
318
- onFocusChange
319
- });
320
- cleanup = unmount;
321
- await delay(RENDER_DELAY_MS);
322
- stdin.write(ARROW_UP);
323
- await delay(INPUT_DELAY_MS);
324
- globalExpect(onFocusChange).toHaveBeenCalledWith(2, 0);
325
- });
326
- it("should clamp column when moving to row with fewer options", async () => {
327
- const onFocusChange = vi.fn();
328
- const { stdin, unmount } = renderGrid({
329
- rows: multiSourceRows,
330
- defaultFocusedRow: 1,
331
- // Zustand has 3 options
332
- defaultFocusedCol: 2,
333
- // Internal (index 2)
334
- onFocusChange
335
- });
336
- cleanup = unmount;
337
- await delay(RENDER_DELAY_MS);
338
- stdin.write(ARROW_UP);
339
- await delay(INPUT_DELAY_MS);
340
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
341
- });
342
- });
343
- describe("keyboard navigation - horizontal", () => {
344
- it("should move right with arrow right", async () => {
345
- const onFocusChange = vi.fn();
346
- const { stdin, unmount } = renderGrid({
347
- rows: multiSourceRows,
348
- defaultFocusedRow: 0,
349
- defaultFocusedCol: 0,
350
- onFocusChange
351
- });
352
- cleanup = unmount;
353
- await delay(RENDER_DELAY_MS);
354
- stdin.write(ARROW_RIGHT);
355
- await delay(INPUT_DELAY_MS);
356
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
357
- });
358
- it("should move left with arrow left", async () => {
359
- const onFocusChange = vi.fn();
360
- const { stdin, unmount } = renderGrid({
361
- rows: multiSourceRows,
362
- defaultFocusedRow: 0,
363
- defaultFocusedCol: 1,
364
- onFocusChange
365
- });
366
- cleanup = unmount;
367
- await delay(RENDER_DELAY_MS);
368
- stdin.write(ARROW_LEFT);
369
- await delay(INPUT_DELAY_MS);
370
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
371
- });
372
- it("should wrap right to first column from last column", async () => {
373
- const onFocusChange = vi.fn();
374
- const { stdin, unmount } = renderGrid({
375
- rows: multiSourceRows,
376
- defaultFocusedRow: 0,
377
- defaultFocusedCol: 1,
378
- // Last option in React row
379
- onFocusChange
380
- });
381
- cleanup = unmount;
382
- await delay(RENDER_DELAY_MS);
383
- stdin.write(ARROW_RIGHT);
384
- await delay(INPUT_DELAY_MS);
385
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
386
- });
387
- it("should wrap left to last column from first column", async () => {
388
- const onFocusChange = vi.fn();
389
- const { stdin, unmount } = renderGrid({
390
- rows: multiSourceRows,
391
- defaultFocusedRow: 0,
392
- defaultFocusedCol: 0,
393
- onFocusChange
394
- });
395
- cleanup = unmount;
396
- await delay(RENDER_DELAY_MS);
397
- stdin.write(ARROW_LEFT);
398
- await delay(INPUT_DELAY_MS);
399
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
400
- });
401
- });
402
- describe("selection", () => {
403
- it("should call onSelect when pressing space", async () => {
404
- const onSelect = vi.fn();
405
- const { stdin, unmount } = renderGrid({
406
- defaultFocusedRow: 0,
407
- defaultFocusedCol: 0,
408
- onSelect
409
- });
410
- cleanup = unmount;
411
- await delay(RENDER_DELAY_MS);
412
- stdin.write(" ");
413
- await delay(INPUT_DELAY_MS);
414
- globalExpect(onSelect).toHaveBeenCalledWith("web-framework-react", "public");
415
- });
416
- it("should call onSelect with correct skill and source IDs", async () => {
417
- const onSelect = vi.fn();
418
- const { stdin, unmount } = renderGrid({
419
- rows: multiSourceRows,
420
- defaultFocusedRow: 0,
421
- defaultFocusedCol: 1,
422
- // Acme Corp
423
- onSelect
424
- });
425
- cleanup = unmount;
426
- await delay(RENDER_DELAY_MS);
427
- stdin.write(" ");
428
- await delay(INPUT_DELAY_MS);
429
- globalExpect(onSelect).toHaveBeenCalledWith("web-framework-react", "acme-corp");
430
- });
431
- it("should call onSelect on second row", async () => {
432
- const onSelect = vi.fn();
433
- const { stdin, unmount } = renderGrid({
434
- rows: multiSourceRows,
435
- defaultFocusedRow: 1,
436
- defaultFocusedCol: 2,
437
- // Internal
438
- onSelect
439
- });
440
- cleanup = unmount;
441
- await delay(RENDER_DELAY_MS);
442
- stdin.write(" ");
443
- await delay(INPUT_DELAY_MS);
444
- globalExpect(onSelect).toHaveBeenCalledWith("web-state-zustand", "internal");
445
- });
446
- });
447
- describe("edge cases", () => {
448
- it("should handle single option per row", async () => {
449
- const onFocusChange = vi.fn();
450
- const { stdin, unmount } = renderGrid({
451
- defaultFocusedRow: 0,
452
- defaultFocusedCol: 0,
453
- onFocusChange
454
- });
455
- cleanup = unmount;
456
- await delay(RENDER_DELAY_MS);
457
- stdin.write(ARROW_RIGHT);
458
- await delay(INPUT_DELAY_MS);
459
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
460
- });
461
- it("should handle many rows", () => {
462
- const skillIds = [
463
- "web-framework-react",
464
- "web-framework-vue-composition-api",
465
- "web-styling-tailwind",
466
- "web-styling-scss-modules",
467
- "web-state-zustand",
468
- "web-state-mobx",
469
- "web-testing-vitest",
470
- "web-testing-playwright-e2e",
471
- "web-server-state-react-query",
472
- "web-tooling-vite"
473
- ];
474
- const skills = Object.fromEntries(skillIds.map((id) => [id, createMockSkill(id)]));
475
- initializeMatrix(createMockMatrix(skills));
476
- const rows = skillIds.map(
477
- (id) => createSourceRow(id, [createSourceOption("public", { selected: true })])
478
- );
479
- const { lastFrame, unmount } = renderGrid({ rows });
480
- cleanup = unmount;
481
- const output = lastFrame();
482
- globalExpect(output).toContain("React");
483
- globalExpect(output).toContain("Vite");
484
- });
485
- });
486
- describe("search pill", () => {
487
- const mockSearch = vi.fn();
488
- const mockBind = vi.fn();
489
- const mockSearchStateChange = vi.fn();
490
- const searchCandidates = [
491
- {
492
- id: "web-framework-react-pro",
493
- sourceUrl: "github:awesome-dev/skills",
494
- sourceName: "awesome-dev",
495
- alias: "react"
496
- },
497
- {
498
- id: "web-framework-react-strict",
499
- sourceUrl: "github:team-xyz/skills",
500
- sourceName: "team-xyz",
501
- alias: "react"
502
- }
503
- ];
504
- afterEach(() => {
505
- mockSearch.mockReset();
506
- mockBind.mockReset();
507
- mockSearchStateChange.mockReset();
508
- });
509
- it("should render search pill at end of each row when onSearch is provided", () => {
510
- const { lastFrame, unmount } = renderGrid({
511
- onSearch: mockSearch
512
- });
513
- cleanup = unmount;
514
- const output = lastFrame();
515
- globalExpect(output).toContain("Search");
516
- });
517
- it("should not render search pill when onSearch is not provided", () => {
518
- const { lastFrame, unmount } = renderGrid();
519
- cleanup = unmount;
520
- const output = lastFrame();
521
- globalExpect(output).not.toContain("Search");
522
- });
523
- it("should navigate to search pill with arrow right", async () => {
524
- const onFocusChange = vi.fn();
525
- const { stdin, unmount } = renderGrid({
526
- rows: defaultRows,
527
- defaultFocusedRow: 0,
528
- defaultFocusedCol: 0,
529
- // On the only option (Public)
530
- onFocusChange,
531
- onSearch: mockSearch
532
- });
533
- cleanup = unmount;
534
- await delay(RENDER_DELAY_MS);
535
- stdin.write(ARROW_RIGHT);
536
- await delay(INPUT_DELAY_MS);
537
- globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
538
- });
539
- it("should not call onSelect when space is pressed on search pill", async () => {
540
- const onSelect = vi.fn();
541
- const { stdin, unmount } = renderGrid({
542
- rows: defaultRows,
543
- defaultFocusedRow: 0,
544
- defaultFocusedCol: 1,
545
- // Search pill position (after Public)
546
- onSelect,
547
- onSearch: mockSearch
548
- });
549
- cleanup = unmount;
550
- await delay(RENDER_DELAY_MS);
551
- stdin.write(" ");
552
- await delay(INPUT_DELAY_MS);
553
- globalExpect(onSelect).not.toHaveBeenCalled();
554
- });
555
- it("should trigger search on Space when search pill is focused", async () => {
556
- mockSearch.mockResolvedValue(searchCandidates);
557
- const { stdin, unmount } = renderGrid({
558
- rows: defaultRows,
559
- defaultFocusedRow: 0,
560
- defaultFocusedCol: 1,
561
- // Search pill position
562
- onSearch: mockSearch,
563
- onSearchStateChange: mockSearchStateChange
564
- });
565
- cleanup = unmount;
566
- await delay(RENDER_DELAY_MS);
567
- stdin.write(SPACE);
568
- await delay(INPUT_DELAY_MS);
569
- globalExpect(mockSearch).toHaveBeenCalledWith("react");
570
- globalExpect(mockSearchStateChange).toHaveBeenCalledWith(true);
571
- });
572
- it("should render modal with results after search completes", async () => {
573
- mockSearch.mockResolvedValue(searchCandidates);
574
- const { stdin, lastFrame, unmount } = renderGrid({
575
- rows: defaultRows,
576
- defaultFocusedRow: 0,
577
- defaultFocusedCol: 1,
578
- onSearch: mockSearch
579
- });
580
- cleanup = unmount;
581
- await delay(RENDER_DELAY_MS);
582
- stdin.write(SPACE);
583
- await delay(RENDER_DELAY_MS);
584
- const output = lastFrame();
585
- globalExpect(output).toContain("react");
586
- globalExpect(output).toContain("awesome-dev");
587
- globalExpect(output).toContain("team-xyz");
588
- });
589
- it("should close modal on Escape without binding", async () => {
590
- mockSearch.mockResolvedValue(searchCandidates);
591
- const { stdin, lastFrame, unmount } = renderGrid({
592
- rows: defaultRows,
593
- defaultFocusedRow: 0,
594
- defaultFocusedCol: 1,
595
- onSearch: mockSearch,
596
- onBind: mockBind,
597
- onSearchStateChange: mockSearchStateChange
598
- });
599
- cleanup = unmount;
600
- await delay(RENDER_DELAY_MS);
601
- stdin.write(SPACE);
602
- await delay(RENDER_DELAY_MS);
603
- stdin.write(ESCAPE);
604
- await delay(INPUT_DELAY_MS);
605
- globalExpect(mockBind).not.toHaveBeenCalled();
606
- globalExpect(mockSearchStateChange).toHaveBeenLastCalledWith(false);
607
- const output = lastFrame();
608
- globalExpect(output).not.toContain("awesome-dev");
609
- });
610
- it("should not respond to grid navigation while modal is open", async () => {
611
- mockSearch.mockResolvedValue(searchCandidates);
612
- const onFocusChange = vi.fn();
613
- const { stdin, unmount } = renderGrid({
614
- rows: defaultRows,
615
- defaultFocusedRow: 0,
616
- defaultFocusedCol: 1,
617
- onSearch: mockSearch,
618
- onFocusChange
619
- });
620
- cleanup = unmount;
621
- await delay(RENDER_DELAY_MS);
622
- stdin.write(SPACE);
623
- await delay(RENDER_DELAY_MS);
624
- onFocusChange.mockClear();
625
- stdin.write(ARROW_LEFT);
626
- await delay(INPUT_DELAY_MS);
627
- stdin.write(ARROW_RIGHT);
628
- await delay(INPUT_DELAY_MS);
629
- globalExpect(onFocusChange).not.toHaveBeenCalled();
630
- });
631
- it("should bind result on Enter in modal", async () => {
632
- mockSearch.mockResolvedValue(searchCandidates);
633
- const { stdin, unmount } = renderGrid({
634
- rows: defaultRows,
635
- defaultFocusedRow: 0,
636
- defaultFocusedCol: 1,
637
- onSearch: mockSearch,
638
- onBind: mockBind,
639
- onSearchStateChange: mockSearchStateChange
640
- });
641
- cleanup = unmount;
642
- await delay(RENDER_DELAY_MS);
643
- stdin.write(SPACE);
644
- await delay(RENDER_DELAY_MS);
645
- stdin.write(ENTER);
646
- await delay(INPUT_DELAY_MS);
647
- globalExpect(mockBind).toHaveBeenCalledWith(searchCandidates[0]);
648
- globalExpect(mockSearchStateChange).toHaveBeenLastCalledWith(false);
649
- });
650
- });
651
- describe("read-only rows", () => {
652
- const readOnlyRows = [
653
- createSourceRow(
654
- "web-framework-react",
655
- [createSourceOption("public", { selected: true }), createSourceOption("eject")],
656
- "global",
657
- true
658
- ),
659
- createSourceRow(
660
- "web-state-zustand",
661
- [createSourceOption("public", { selected: true })],
662
- "project"
663
- )
664
- ];
665
- it("should render read-only rows with lock indicator", () => {
666
- const { lastFrame, unmount } = renderGrid({ rows: readOnlyRows });
667
- cleanup = unmount;
668
- const output = lastFrame();
669
- globalExpect(output).toContain(UI_SYMBOLS.LOCK);
670
- });
671
- it("should render read-only rows with dimmed styling", () => {
672
- const { lastFrame, unmount } = renderGrid({ rows: readOnlyRows });
673
- cleanup = unmount;
674
- const output = lastFrame();
675
- globalExpect(output).toContain("React");
676
- globalExpect(output).toContain("Zustand");
677
- });
678
- it("should not fire onSelect for read-only rows (defense-in-depth guard)", async () => {
679
- const onSelect = vi.fn();
680
- const { stdin, unmount } = renderGrid({
681
- rows: readOnlyRows,
682
- defaultFocusedRow: 0,
683
- defaultFocusedCol: 0,
684
- onSelect
685
- });
686
- cleanup = unmount;
687
- await delay(RENDER_DELAY_MS);
688
- stdin.write(SPACE);
689
- await delay(INPUT_DELAY_MS);
690
- globalExpect(onSelect).toHaveBeenCalledWith("web-state-zustand", "public");
691
- });
692
- it("should skip read-only rows during navigation", async () => {
693
- const threeRows = [
694
- createSourceRow(
695
- "web-framework-react",
696
- [createSourceOption("public", { selected: true })],
697
- "global",
698
- true
699
- ),
700
- createSourceRow(
701
- "web-state-zustand",
702
- [createSourceOption("public", { selected: true })],
703
- "project"
704
- ),
705
- createSourceRow(
706
- "web-testing-vitest",
707
- [createSourceOption("public", { selected: true })],
708
- "global",
709
- true
710
- )
711
- ];
712
- const onFocusChange = vi.fn();
713
- const { stdin, unmount } = renderGrid({
714
- rows: threeRows,
715
- defaultFocusedRow: 0,
716
- defaultFocusedCol: 0,
717
- onFocusChange
718
- });
719
- cleanup = unmount;
720
- await delay(RENDER_DELAY_MS);
721
- stdin.write(ARROW_DOWN);
722
- await delay(INPUT_DELAY_MS);
723
- globalExpect(onFocusChange).toHaveBeenLastCalledWith(1, 0);
724
- });
725
- it("should allow selection on non-read-only rows after navigating past read-only", async () => {
726
- const onSelect = vi.fn();
727
- const { stdin, unmount } = renderGrid({
728
- rows: readOnlyRows,
729
- defaultFocusedRow: 1,
730
- defaultFocusedCol: 0,
731
- onSelect
732
- });
733
- cleanup = unmount;
734
- await delay(RENDER_DELAY_MS);
735
- stdin.write(SPACE);
736
- await delay(INPUT_DELAY_MS);
737
- globalExpect(onSelect).toHaveBeenCalledWith("web-state-zustand", "public");
738
- });
739
- it("should not show search pill on read-only rows", () => {
740
- const mockSearch = vi.fn();
741
- const { lastFrame, unmount } = renderGrid({
742
- rows: [
743
- createSourceRow(
744
- "web-framework-react",
745
- [createSourceOption("public", { selected: true })],
746
- "global",
747
- true
748
- )
749
- ],
750
- onSearch: mockSearch
751
- });
752
- cleanup = unmount;
753
- const output = lastFrame();
754
- globalExpect(output).toContain("React");
755
- globalExpect(output).not.toContain("Search");
756
- });
757
- it("should not show focus highlight on read-only rows", () => {
758
- const allReadOnlyRows = [
759
- createSourceRow(
760
- "web-framework-react",
761
- [createSourceOption("public", { selected: true })],
762
- "global",
763
- true
764
- ),
765
- createSourceRow(
766
- "web-state-zustand",
767
- [createSourceOption("public", { selected: true })],
768
- "global",
769
- true
770
- )
771
- ];
772
- const { lastFrame, unmount } = renderGrid({
773
- rows: allReadOnlyRows,
774
- defaultFocusedRow: 0,
775
- defaultFocusedCol: 0
776
- });
777
- cleanup = unmount;
778
- const output = lastFrame();
779
- globalExpect(output).not.toContain(UI_SYMBOLS.CHEVRON);
780
- });
781
- it("should render re-scoped skill once per scope group", () => {
782
- const reSccopedRows = [
783
- createSourceRow(
784
- "web-framework-react",
785
- [createSourceOption("eject"), createSourceOption("public", { selected: true })],
786
- "global",
787
- true
788
- ),
789
- createSourceRow(
790
- "web-framework-react",
791
- [createSourceOption("eject"), createSourceOption("public", { selected: true })],
792
- "project"
793
- )
794
- ];
795
- const { lastFrame, unmount } = renderGrid({ rows: reSccopedRows });
796
- cleanup = unmount;
797
- const output = lastFrame();
798
- const reactMatches = output.split("React").length - 1;
799
- globalExpect(reactMatches).toBe(2);
800
- globalExpect(output).toContain(UI_SYMBOLS.LOCK);
801
- });
802
- });
803
- describe("removed (disabled) rows", () => {
804
- const removedRows = [
805
- createSourceRow(
806
- "web-framework-react",
807
- [createSourceOption("public", { selected: true })],
808
- "project"
809
- ),
810
- createRemovedRow(
811
- "web-testing-vitest",
812
- [createSourceOption("eject", { selected: true }), createSourceOption("public")],
813
- "project"
814
- )
815
- ];
816
- it("should keep the removed skill visible", () => {
817
- const { lastFrame, unmount } = renderGrid({ rows: removedRows });
818
- cleanup = unmount;
819
- globalExpect(lastFrame()).toContain("Vitest");
820
- });
821
- it("should mark the removed skill with the pending-removal marker and no lock", () => {
822
- const { lastFrame, unmount } = renderGrid({ rows: removedRows });
823
- cleanup = unmount;
824
- const output = lastFrame();
825
- globalExpect(output).toContain(`${UI_SYMBOLS.REMOVED} Vitest`);
826
- globalExpect(output).not.toContain(UI_SYMBOLS.LOCK);
827
- });
828
- it("should not fire onSelect when space is pressed with a removed row focused", async () => {
829
- const onSelect = vi.fn();
830
- const { stdin, unmount } = renderGrid({
831
- rows: [removedRows[1]],
832
- defaultFocusedRow: 0,
833
- defaultFocusedCol: 0,
834
- onSelect
835
- });
836
- cleanup = unmount;
837
- await delay(RENDER_DELAY_MS);
838
- stdin.write(SPACE);
839
- await delay(INPUT_DELAY_MS);
840
- globalExpect(onSelect).not.toHaveBeenCalled();
841
- });
842
- it("should skip removed rows during navigation", async () => {
843
- const onFocusChange = vi.fn();
844
- const { stdin, unmount } = renderGrid({
845
- rows: removedRows,
846
- defaultFocusedRow: 0,
847
- defaultFocusedCol: 0,
848
- onFocusChange
849
- });
850
- cleanup = unmount;
851
- await delay(RENDER_DELAY_MS);
852
- stdin.write(ARROW_DOWN);
853
- await delay(INPUT_DELAY_MS);
854
- globalExpect(onFocusChange).toHaveBeenLastCalledWith(0, 0);
855
- });
856
- it("should not focus a removed row when it is the default focus target", async () => {
857
- const onSelect = vi.fn();
858
- const { stdin, unmount } = renderGrid({
859
- rows: removedRows,
860
- defaultFocusedRow: 1,
861
- // The removed row — focus must fall back to the editable row.
862
- defaultFocusedCol: 0,
863
- onSelect
864
- });
865
- cleanup = unmount;
866
- await delay(RENDER_DELAY_MS);
867
- stdin.write(SPACE);
868
- await delay(INPUT_DELAY_MS);
869
- globalExpect(onSelect).toHaveBeenCalledWith("web-framework-react", "public");
870
- });
871
- it("should not show search pill on removed rows", () => {
872
- const mockSearch = vi.fn();
873
- const { lastFrame, unmount } = renderGrid({
874
- rows: [removedRows[1]],
875
- onSearch: mockSearch
876
- });
877
- cleanup = unmount;
878
- const output = lastFrame();
879
- globalExpect(output).toContain("Vitest");
880
- globalExpect(output).not.toContain("Search");
881
- });
882
- it("should not show focus highlight on removed rows", () => {
883
- const { lastFrame, unmount } = renderGrid({
884
- rows: [removedRows[1]],
885
- defaultFocusedRow: 0,
886
- defaultFocusedCol: 0
887
- });
888
- cleanup = unmount;
889
- globalExpect(lastFrame()).not.toContain(UI_SYMBOLS.CHEVRON);
890
- });
891
- describe("collapsed dual-scope pair", () => {
892
- const COLLAPSED_SKILL_ID = "web-framework-react";
893
- const UNTOUCHED_SKILL_ID = "web-state-zustand";
894
- const collapsedPairRows = [
895
- createSourceRow(
896
- COLLAPSED_SKILL_ID,
897
- [createSourceOption("public", { selected: true })],
898
- "global",
899
- true
900
- ),
901
- createRemovedRow(
902
- COLLAPSED_SKILL_ID,
903
- [createSourceOption("public", { selected: true })],
904
- "project"
905
- )
906
- ];
907
- let previousChalkLevel;
908
- beforeEach(() => {
909
- previousChalkLevel = source_default.level;
910
- source_default.level = TRUECOLOR_CHALK_LEVEL;
911
- });
912
- afterEach(() => {
913
- source_default.level = previousChalkLevel;
914
- });
915
- it("should render the same skill in both scope sections, locked at global and pending removal at project", () => {
916
- const { lastFrame, unmount } = renderGrid({ rows: collapsedPairRows });
917
- cleanup = unmount;
918
- const output = lastFrame();
919
- const skillName = getSkillById(COLLAPSED_SKILL_ID).displayName;
920
- globalExpect(
921
- output,
922
- `the surviving global install must keep its lock. Frame:
923
- ${JSON.stringify(output)}`
924
- ).toContain(`${UI_SYMBOLS.LOCK} ${skillName}`);
925
- globalExpect(
926
- output,
927
- `the emptied project slot must carry the removal marker. Frame:
928
- ${JSON.stringify(output)}`
929
- ).toContain(`${UI_SYMBOLS.REMOVED} ${skillName}`);
930
- globalExpect(output).not.toContain(`${UI_SYMBOLS.ADDED} ${skillName}`);
931
- });
932
- it("should render the project instance of the pair in the removed-diff colour", () => {
933
- const { lastFrame, unmount } = renderGrid({ rows: collapsedPairRows });
934
- cleanup = unmount;
935
- const output = lastFrame();
936
- const skillName = getSkillById(COLLAPSED_SKILL_ID).displayName;
937
- globalExpect(
938
- output,
939
- `the pending-removal row must render in the removed-diff colour. Frame:
940
- ${JSON.stringify(output)}`
941
- ).toContain(source_default.hex(CLI_COLORS.ERROR)(`${UI_SYMBOLS.REMOVED} ${skillName}`));
942
- });
943
- it("should not fire onSelect when space is pressed on an all-inert collapsed pair", async () => {
944
- const onSelect = vi.fn();
945
- const { stdin, unmount } = renderGrid({
946
- rows: collapsedPairRows,
947
- defaultFocusedRow: 0,
948
- defaultFocusedCol: 0,
949
- onSelect
950
- });
951
- cleanup = unmount;
952
- await delay(RENDER_DELAY_MS);
953
- stdin.write(SPACE);
954
- await delay(INPUT_DELAY_MS);
955
- globalExpect(onSelect).not.toHaveBeenCalled();
956
- });
957
- it("should not show focus highlight on either row of the collapsed pair", () => {
958
- const { lastFrame, unmount } = renderGrid({
959
- rows: collapsedPairRows,
960
- defaultFocusedRow: 0,
961
- defaultFocusedCol: 0
962
- });
963
- cleanup = unmount;
964
- globalExpect(lastFrame()).not.toContain(UI_SYMBOLS.CHEVRON);
965
- });
966
- it("should skip both rows of the collapsed pair and act on the editable row instead", async () => {
967
- const onSelect = vi.fn();
968
- const { stdin, unmount } = renderGrid({
969
- rows: [
970
- ...collapsedPairRows,
971
- createSourceRow(
972
- UNTOUCHED_SKILL_ID,
973
- [createSourceOption("public", { selected: true })],
974
- "project"
975
- )
976
- ],
977
- // The locked half of the pair — focus must fall through it AND the pending-removal row.
978
- defaultFocusedRow: 0,
979
- defaultFocusedCol: 0,
980
- onSelect
981
- });
982
- cleanup = unmount;
983
- await delay(RENDER_DELAY_MS);
984
- stdin.write(SPACE);
985
- await delay(INPUT_DELAY_MS);
986
- globalExpect(onSelect).toHaveBeenCalledWith(UNTOUCHED_SKILL_ID, "public");
987
- globalExpect(onSelect).not.toHaveBeenCalledWith(COLLAPSED_SKILL_ID, "public");
988
- });
989
- });
990
- });
991
- describe("added rows", () => {
992
- const ADDED_SKILL_ID = "web-framework-react";
993
- const addedRows = [
994
- createAddedRow(ADDED_SKILL_ID, [createSourceOption("public", { selected: true })], "project"),
995
- createSourceRow(
996
- "web-state-zustand",
997
- [createSourceOption("public", { selected: true })],
998
- "project"
999
- )
1000
- ];
1001
- let previousChalkLevel;
1002
- beforeEach(() => {
1003
- previousChalkLevel = source_default.level;
1004
- source_default.level = TRUECOLOR_CHALK_LEVEL;
1005
- });
1006
- afterEach(() => {
1007
- source_default.level = previousChalkLevel;
1008
- });
1009
- it("should mark the added skill with the added marker", () => {
1010
- const { lastFrame, unmount } = renderGrid({
1011
- rows: addedRows,
1012
- defaultFocusedRow: 1,
1013
- defaultFocusedCol: 0
1014
- });
1015
- cleanup = unmount;
1016
- const output = lastFrame();
1017
- globalExpect(output).toContain(`${UI_SYMBOLS.ADDED} ${getSkillById(ADDED_SKILL_ID).displayName}`);
1018
- });
1019
- it("should keep the added-diff colour on the added row while it is focused", () => {
1020
- const { lastFrame, unmount } = renderGrid({
1021
- rows: addedRows,
1022
- defaultFocusedRow: 0,
1023
- defaultFocusedCol: 0
1024
- });
1025
- cleanup = unmount;
1026
- const focusedLabel = `${UI_SYMBOLS.ADDED} ${getSkillById(ADDED_SKILL_ID).displayName} `;
1027
- const output = lastFrame();
1028
- globalExpect(
1029
- output,
1030
- `a focused added row must keep its added-diff colour. Frame:
1031
- ${JSON.stringify(output)}`
1032
- ).toContain(source_default.bgHex(CLI_COLORS.LABEL_BG)(source_default.hex(CLI_COLORS.SUCCESS)(focusedLabel)));
1033
- globalExpect(
1034
- output,
1035
- "a focused added row must not fall back to the plain white label colour"
1036
- ).not.toContain(source_default.bgHex(CLI_COLORS.LABEL_BG)(source_default.hex(CLI_COLORS.WHITE)(focusedLabel)));
1037
- });
1038
- });
1039
- describe("inert row source selection", () => {
1040
- const LOCKED_ROW = createSourceRow(
1041
- "web-framework-react",
1042
- [createSourceOption("public", { selected: true }), createSourceOption("eject")],
1043
- "global",
1044
- true
1045
- );
1046
- const REMOVAL_ROW = createRemovedRow(
1047
- "web-testing-vitest",
1048
- [createSourceOption("eject", { selected: true }), createSourceOption("public")],
1049
- "project"
1050
- );
1051
- const INERT_PREFIX = `${UI_SYMBOLS.CHEVRON_SPACER} `;
1052
- let previousChalkLevel;
1053
- beforeEach(() => {
1054
- previousChalkLevel = source_default.level;
1055
- source_default.level = TRUECOLOR_CHALK_LEVEL;
1056
- });
1057
- afterEach(() => {
1058
- source_default.level = previousChalkLevel;
1059
- });
1060
- it("should carry the locked row's selection in weight and brightness, not a check", () => {
1061
- const { lastFrame, unmount } = renderGrid({ rows: [LOCKED_ROW] });
1062
- cleanup = unmount;
1063
- const output = lastFrame();
1064
- globalExpect(
1065
- output,
1066
- `the locked row's selected source must render bold. Frame:
1067
- ${JSON.stringify(output)}`
1068
- ).toContain(source_default.bold(`${INERT_PREFIX}Public`));
1069
- globalExpect(
1070
- output,
1071
- `the locked row's unselected sources must stay dimmed. Frame:
1072
- ${JSON.stringify(output)}`
1073
- ).toContain(source_default.dim(`${INERT_PREFIX}Eject`));
1074
- globalExpect(output).not.toContain(UI_SYMBOLS.SELECTED);
1075
- });
1076
- it("should carry the pending-removal row's selection in weight while keeping its removal colour", () => {
1077
- const { lastFrame, unmount } = renderGrid({ rows: [REMOVAL_ROW] });
1078
- cleanup = unmount;
1079
- const output = lastFrame();
1080
- globalExpect(
1081
- output,
1082
- `the removal row's selected source must render bold in the removal colour. Frame:
1083
- ${JSON.stringify(output)}`
1084
- ).toContain(source_default.bold(source_default.hex(CLI_COLORS.ERROR)(`${INERT_PREFIX}Eject`)));
1085
- globalExpect(
1086
- output,
1087
- `the removal row's unselected sources must keep the removal colour unbolded. Frame:
1088
- ${JSON.stringify(output)}`
1089
- ).toContain(source_default.hex(CLI_COLORS.ERROR)(`${INERT_PREFIX}Public`));
1090
- globalExpect(output).not.toContain(UI_SYMBOLS.SELECTED);
1091
- });
1092
- });
1093
- });
1094
- //# sourceMappingURL=source-grid.test.js.map