@agents-inc/cli 0.32.1

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 (497) hide show
  1. package/CHANGELOG.md +462 -0
  2. package/LICENSE +21 -0
  3. package/README.md +179 -0
  4. package/config/skills-matrix.yaml +926 -0
  5. package/config/stacks.yaml +2186 -0
  6. package/dist/chunk-3ZOIOVKT.js +365 -0
  7. package/dist/chunk-3ZOIOVKT.js.map +1 -0
  8. package/dist/chunk-4RAY5AOI.js +78 -0
  9. package/dist/chunk-4RAY5AOI.js.map +1 -0
  10. package/dist/chunk-5PIKNCZX.js +234 -0
  11. package/dist/chunk-5PIKNCZX.js.map +1 -0
  12. package/dist/chunk-66UDJBF6.js +96 -0
  13. package/dist/chunk-66UDJBF6.js.map +1 -0
  14. package/dist/chunk-7SOPVGDV.js +24 -0
  15. package/dist/chunk-7SOPVGDV.js.map +1 -0
  16. package/dist/chunk-A27LOC4Z.js +95 -0
  17. package/dist/chunk-A27LOC4Z.js.map +1 -0
  18. package/dist/chunk-B2UBHA66.js +301 -0
  19. package/dist/chunk-B2UBHA66.js.map +1 -0
  20. package/dist/chunk-BZN2Z5P7.js +882 -0
  21. package/dist/chunk-BZN2Z5P7.js.map +1 -0
  22. package/dist/chunk-BZQBJP34.js +186 -0
  23. package/dist/chunk-BZQBJP34.js.map +1 -0
  24. package/dist/chunk-DC5AK3LW.js +105 -0
  25. package/dist/chunk-DC5AK3LW.js.map +1 -0
  26. package/dist/chunk-DHET7RCE.js +50 -0
  27. package/dist/chunk-DHET7RCE.js.map +1 -0
  28. package/dist/chunk-EMJ2ZKS7.js +346 -0
  29. package/dist/chunk-EMJ2ZKS7.js.map +1 -0
  30. package/dist/chunk-FJQRVFMB.js +48 -0
  31. package/dist/chunk-FJQRVFMB.js.map +1 -0
  32. package/dist/chunk-FZGYSLJL.js +85 -0
  33. package/dist/chunk-FZGYSLJL.js.map +1 -0
  34. package/dist/chunk-H566H3MQ.js +87 -0
  35. package/dist/chunk-H566H3MQ.js.map +1 -0
  36. package/dist/chunk-IYG2LAIM.js +90 -0
  37. package/dist/chunk-IYG2LAIM.js.map +1 -0
  38. package/dist/chunk-IZZ4IIEG.js +29 -0
  39. package/dist/chunk-IZZ4IIEG.js.map +1 -0
  40. package/dist/chunk-JMVWYAHT.js +63 -0
  41. package/dist/chunk-JMVWYAHT.js.map +1 -0
  42. package/dist/chunk-LAPCUV4D.js +191 -0
  43. package/dist/chunk-LAPCUV4D.js.map +1 -0
  44. package/dist/chunk-LGUI3PMO.js +109 -0
  45. package/dist/chunk-LGUI3PMO.js.map +1 -0
  46. package/dist/chunk-MM7NK5N2.js +4542 -0
  47. package/dist/chunk-MM7NK5N2.js.map +1 -0
  48. package/dist/chunk-N6S7ZRIL.js +31 -0
  49. package/dist/chunk-N6S7ZRIL.js.map +1 -0
  50. package/dist/chunk-O4D67NN7.js +24 -0
  51. package/dist/chunk-O4D67NN7.js.map +1 -0
  52. package/dist/chunk-ODUOU55D.js +56 -0
  53. package/dist/chunk-ODUOU55D.js.map +1 -0
  54. package/dist/chunk-OGJIZ6QH.js +497 -0
  55. package/dist/chunk-OGJIZ6QH.js.map +1 -0
  56. package/dist/chunk-OMV7TLWD.js +340 -0
  57. package/dist/chunk-OMV7TLWD.js.map +1 -0
  58. package/dist/chunk-PBEHPQLK.js +146 -0
  59. package/dist/chunk-PBEHPQLK.js.map +1 -0
  60. package/dist/chunk-QPTOIZAT.js +32 -0
  61. package/dist/chunk-QPTOIZAT.js.map +1 -0
  62. package/dist/chunk-R3XFQKPG.js +111 -0
  63. package/dist/chunk-R3XFQKPG.js.map +1 -0
  64. package/dist/chunk-R74PZWQS.js +69 -0
  65. package/dist/chunk-R74PZWQS.js.map +1 -0
  66. package/dist/chunk-SO22IQPY.js +45 -0
  67. package/dist/chunk-SO22IQPY.js.map +1 -0
  68. package/dist/chunk-T4EXUIBY.js +19 -0
  69. package/dist/chunk-T4EXUIBY.js.map +1 -0
  70. package/dist/chunk-U3IGFMCY.js +31 -0
  71. package/dist/chunk-U3IGFMCY.js.map +1 -0
  72. package/dist/chunk-UICL22RT.js +318 -0
  73. package/dist/chunk-UICL22RT.js.map +1 -0
  74. package/dist/chunk-UX2H2K2G.js +183 -0
  75. package/dist/chunk-UX2H2K2G.js.map +1 -0
  76. package/dist/chunk-W2ZSCZ2U.js +93 -0
  77. package/dist/chunk-W2ZSCZ2U.js.map +1 -0
  78. package/dist/chunk-WEUVWHMA.js +189 -0
  79. package/dist/chunk-WEUVWHMA.js.map +1 -0
  80. package/dist/chunk-XY3XDVMI.js +15599 -0
  81. package/dist/chunk-XY3XDVMI.js.map +1 -0
  82. package/dist/chunk-YND42IXK.js +233 -0
  83. package/dist/chunk-YND42IXK.js.map +1 -0
  84. package/dist/chunk-YZTWZVGX.js +41 -0
  85. package/dist/chunk-YZTWZVGX.js.map +1 -0
  86. package/dist/chunk-Z4TWOP3H.js +81 -0
  87. package/dist/chunk-Z4TWOP3H.js.map +1 -0
  88. package/dist/cli/defaults/agent-mappings.yaml +271 -0
  89. package/dist/commands/build/marketplace.js +252 -0
  90. package/dist/commands/build/marketplace.js.map +1 -0
  91. package/dist/commands/build/plugins.js +114 -0
  92. package/dist/commands/build/plugins.js.map +1 -0
  93. package/dist/commands/build/stack.js +153 -0
  94. package/dist/commands/build/stack.js.map +1 -0
  95. package/dist/commands/compile.js +354 -0
  96. package/dist/commands/compile.js.map +1 -0
  97. package/dist/commands/config/get.js +61 -0
  98. package/dist/commands/config/get.js.map +1 -0
  99. package/dist/commands/config/index.js +23 -0
  100. package/dist/commands/config/index.js.map +1 -0
  101. package/dist/commands/config/path.js +34 -0
  102. package/dist/commands/config/path.js.map +1 -0
  103. package/dist/commands/config/set-project.js +61 -0
  104. package/dist/commands/config/set-project.js.map +1 -0
  105. package/dist/commands/config/show.js +14 -0
  106. package/dist/commands/config/show.js.map +1 -0
  107. package/dist/commands/config/unset-project.js +57 -0
  108. package/dist/commands/config/unset-project.js.map +1 -0
  109. package/dist/commands/diff.js +742 -0
  110. package/dist/commands/diff.js.map +1 -0
  111. package/dist/commands/doctor.js +370 -0
  112. package/dist/commands/doctor.js.map +1 -0
  113. package/dist/commands/edit.js +301 -0
  114. package/dist/commands/edit.js.map +1 -0
  115. package/dist/commands/eject.js +262 -0
  116. package/dist/commands/eject.js.map +1 -0
  117. package/dist/commands/import/skill.js +361 -0
  118. package/dist/commands/import/skill.js.map +1 -0
  119. package/dist/commands/info.js +217 -0
  120. package/dist/commands/info.js.map +1 -0
  121. package/dist/commands/init.js +443 -0
  122. package/dist/commands/init.js.map +1 -0
  123. package/dist/commands/list.js +49 -0
  124. package/dist/commands/list.js.map +1 -0
  125. package/dist/commands/new/agent.js +224 -0
  126. package/dist/commands/new/agent.js.map +1 -0
  127. package/dist/commands/new/skill.js +199 -0
  128. package/dist/commands/new/skill.js.map +1 -0
  129. package/dist/commands/outdated.js +176 -0
  130. package/dist/commands/outdated.js.map +1 -0
  131. package/dist/commands/search.js +288 -0
  132. package/dist/commands/search.js.map +1 -0
  133. package/dist/commands/uninstall.js +302 -0
  134. package/dist/commands/uninstall.js.map +1 -0
  135. package/dist/commands/update.js +304 -0
  136. package/dist/commands/update.js.map +1 -0
  137. package/dist/commands/validate.js +389 -0
  138. package/dist/commands/validate.js.map +1 -0
  139. package/dist/commands/version/bump.js +79 -0
  140. package/dist/commands/version/bump.js.map +1 -0
  141. package/dist/commands/version/index.js +54 -0
  142. package/dist/commands/version/index.js.map +1 -0
  143. package/dist/commands/version/set.js +86 -0
  144. package/dist/commands/version/set.js.map +1 -0
  145. package/dist/commands/version/show.js +54 -0
  146. package/dist/commands/version/show.js.map +1 -0
  147. package/dist/components/common/confirm.js +9 -0
  148. package/dist/components/common/confirm.js.map +1 -0
  149. package/dist/components/common/confirm.test.js +203 -0
  150. package/dist/components/common/confirm.test.js.map +1 -0
  151. package/dist/components/common/message.js +20 -0
  152. package/dist/components/common/message.js.map +1 -0
  153. package/dist/components/common/spinner.js +14 -0
  154. package/dist/components/common/spinner.js.map +1 -0
  155. package/dist/components/skill-search/skill-search.js +12 -0
  156. package/dist/components/skill-search/skill-search.js.map +1 -0
  157. package/dist/components/wizard/category-grid.js +11 -0
  158. package/dist/components/wizard/category-grid.js.map +1 -0
  159. package/dist/components/wizard/category-grid.test.js +997 -0
  160. package/dist/components/wizard/category-grid.test.js.map +1 -0
  161. package/dist/components/wizard/domain-selection.js +14 -0
  162. package/dist/components/wizard/domain-selection.js.map +1 -0
  163. package/dist/components/wizard/help-modal.js +10 -0
  164. package/dist/components/wizard/help-modal.js.map +1 -0
  165. package/dist/components/wizard/menu-item.js +10 -0
  166. package/dist/components/wizard/menu-item.js.map +1 -0
  167. package/dist/components/wizard/search-modal.js +11 -0
  168. package/dist/components/wizard/search-modal.js.map +1 -0
  169. package/dist/components/wizard/search-modal.test.js +218 -0
  170. package/dist/components/wizard/search-modal.test.js.map +1 -0
  171. package/dist/components/wizard/section-progress.js +10 -0
  172. package/dist/components/wizard/section-progress.js.map +1 -0
  173. package/dist/components/wizard/section-progress.test.js +192 -0
  174. package/dist/components/wizard/section-progress.test.js.map +1 -0
  175. package/dist/components/wizard/source-grid.js +14 -0
  176. package/dist/components/wizard/source-grid.js.map +1 -0
  177. package/dist/components/wizard/source-grid.test.js +504 -0
  178. package/dist/components/wizard/source-grid.test.js.map +1 -0
  179. package/dist/components/wizard/stack-selection.js +17 -0
  180. package/dist/components/wizard/stack-selection.js.map +1 -0
  181. package/dist/components/wizard/step-build.js +17 -0
  182. package/dist/components/wizard/step-build.js.map +1 -0
  183. package/dist/components/wizard/step-build.test.js +600 -0
  184. package/dist/components/wizard/step-build.test.js.map +1 -0
  185. package/dist/components/wizard/step-confirm.js +12 -0
  186. package/dist/components/wizard/step-confirm.js.map +1 -0
  187. package/dist/components/wizard/step-confirm.test.js +366 -0
  188. package/dist/components/wizard/step-confirm.test.js.map +1 -0
  189. package/dist/components/wizard/step-refine.js +10 -0
  190. package/dist/components/wizard/step-refine.js.map +1 -0
  191. package/dist/components/wizard/step-refine.test.js +237 -0
  192. package/dist/components/wizard/step-refine.test.js.map +1 -0
  193. package/dist/components/wizard/step-settings.js +17 -0
  194. package/dist/components/wizard/step-settings.js.map +1 -0
  195. package/dist/components/wizard/step-settings.test.js +243 -0
  196. package/dist/components/wizard/step-settings.test.js.map +1 -0
  197. package/dist/components/wizard/step-sources.js +20 -0
  198. package/dist/components/wizard/step-sources.js.map +1 -0
  199. package/dist/components/wizard/step-sources.test.js +294 -0
  200. package/dist/components/wizard/step-sources.test.js.map +1 -0
  201. package/dist/components/wizard/step-stack.js +19 -0
  202. package/dist/components/wizard/step-stack.js.map +1 -0
  203. package/dist/components/wizard/step-stack.test.js +357 -0
  204. package/dist/components/wizard/step-stack.test.js.map +1 -0
  205. package/dist/components/wizard/view-title.js +10 -0
  206. package/dist/components/wizard/view-title.js.map +1 -0
  207. package/dist/components/wizard/wizard-layout.js +16 -0
  208. package/dist/components/wizard/wizard-layout.js.map +1 -0
  209. package/dist/components/wizard/wizard-tabs.js +14 -0
  210. package/dist/components/wizard/wizard-tabs.js.map +1 -0
  211. package/dist/components/wizard/wizard-tabs.test.js +294 -0
  212. package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
  213. package/dist/components/wizard/wizard.js +35 -0
  214. package/dist/components/wizard/wizard.js.map +1 -0
  215. package/dist/config/skills-matrix.yaml +926 -0
  216. package/dist/config/stacks.yaml +2186 -0
  217. package/dist/hooks/init.js +40 -0
  218. package/dist/hooks/init.js.map +1 -0
  219. package/dist/index.js +10 -0
  220. package/dist/index.js.map +1 -0
  221. package/dist/magic-string.es-RGXYGAW3.js +1316 -0
  222. package/dist/magic-string.es-RGXYGAW3.js.map +1 -0
  223. package/dist/source-manager-SBPPLOQQ.js +16 -0
  224. package/dist/source-manager-SBPPLOQQ.js.map +1 -0
  225. package/dist/src/agents/_templates/agent.liquid +140 -0
  226. package/dist/src/agents/developer/api-developer/agent.yaml +12 -0
  227. package/dist/src/agents/developer/api-developer/critical-reminders.md +23 -0
  228. package/dist/src/agents/developer/api-developer/critical-requirements.md +11 -0
  229. package/dist/src/agents/developer/api-developer/examples.md +72 -0
  230. package/dist/src/agents/developer/api-developer/intro.md +22 -0
  231. package/dist/src/agents/developer/api-developer/output-format.md +359 -0
  232. package/dist/src/agents/developer/api-developer/workflow.md +471 -0
  233. package/dist/src/agents/developer/cli-developer/agent.yaml +12 -0
  234. package/dist/src/agents/developer/cli-developer/critical-reminders.md +28 -0
  235. package/dist/src/agents/developer/cli-developer/critical-requirements.md +15 -0
  236. package/dist/src/agents/developer/cli-developer/examples.md +68 -0
  237. package/dist/src/agents/developer/cli-developer/intro.md +23 -0
  238. package/dist/src/agents/developer/cli-developer/output-format.md +216 -0
  239. package/dist/src/agents/developer/cli-developer/workflow.md +509 -0
  240. package/dist/src/agents/developer/web-architecture/agent.yaml +12 -0
  241. package/dist/src/agents/developer/web-architecture/critical-reminders.md +27 -0
  242. package/dist/src/agents/developer/web-architecture/critical-requirements.md +35 -0
  243. package/dist/src/agents/developer/web-architecture/examples.md +187 -0
  244. package/dist/src/agents/developer/web-architecture/intro.md +35 -0
  245. package/dist/src/agents/developer/web-architecture/output-format.md +261 -0
  246. package/dist/src/agents/developer/web-architecture/workflow.md +599 -0
  247. package/dist/src/agents/developer/web-developer/agent.yaml +12 -0
  248. package/dist/src/agents/developer/web-developer/critical-reminders.md +17 -0
  249. package/dist/src/agents/developer/web-developer/critical-requirements.md +15 -0
  250. package/dist/src/agents/developer/web-developer/examples.md +109 -0
  251. package/dist/src/agents/developer/web-developer/intro.md +5 -0
  252. package/dist/src/agents/developer/web-developer/output-format.md +213 -0
  253. package/dist/src/agents/developer/web-developer/workflow.md +459 -0
  254. package/dist/src/agents/meta/agent-summoner/agent.yaml +12 -0
  255. package/dist/src/agents/meta/agent-summoner/critical-reminders.md +31 -0
  256. package/dist/src/agents/meta/agent-summoner/critical-requirements.md +27 -0
  257. package/dist/src/agents/meta/agent-summoner/examples.md +176 -0
  258. package/dist/src/agents/meta/agent-summoner/intro.md +9 -0
  259. package/dist/src/agents/meta/agent-summoner/output-format.md +115 -0
  260. package/dist/src/agents/meta/agent-summoner/workflow.md +1540 -0
  261. package/dist/src/agents/meta/documentor/agent.yaml +11 -0
  262. package/dist/src/agents/meta/documentor/critical-reminders.md +23 -0
  263. package/dist/src/agents/meta/documentor/critical-requirements.md +13 -0
  264. package/dist/src/agents/meta/documentor/examples.md +147 -0
  265. package/dist/src/agents/meta/documentor/intro.md +11 -0
  266. package/dist/src/agents/meta/documentor/output-format.md +237 -0
  267. package/dist/src/agents/meta/documentor/workflow.md +1271 -0
  268. package/dist/src/agents/meta/skill-summoner/agent.yaml +13 -0
  269. package/dist/src/agents/meta/skill-summoner/critical-reminders.md +73 -0
  270. package/dist/src/agents/meta/skill-summoner/critical-requirements.md +62 -0
  271. package/dist/src/agents/meta/skill-summoner/examples.md +116 -0
  272. package/dist/src/agents/meta/skill-summoner/intro.md +5 -0
  273. package/dist/src/agents/meta/skill-summoner/output-format.md +279 -0
  274. package/dist/src/agents/meta/skill-summoner/workflow.md +1485 -0
  275. package/dist/src/agents/migration/cli-migrator/agent.yaml +12 -0
  276. package/dist/src/agents/migration/cli-migrator/anti-patterns.md +158 -0
  277. package/dist/src/agents/migration/cli-migrator/conversion-mappings.md +63 -0
  278. package/dist/src/agents/migration/cli-migrator/critical-reminders.md +17 -0
  279. package/dist/src/agents/migration/cli-migrator/critical-requirements.md +13 -0
  280. package/dist/src/agents/migration/cli-migrator/intro.md +15 -0
  281. package/dist/src/agents/migration/cli-migrator/output-format.md +164 -0
  282. package/dist/src/agents/migration/cli-migrator/workflow.md +230 -0
  283. package/dist/src/agents/pattern/pattern-scout/agent.yaml +10 -0
  284. package/dist/src/agents/pattern/pattern-scout/critical-reminders.md +58 -0
  285. package/dist/src/agents/pattern/pattern-scout/critical-requirements.md +17 -0
  286. package/dist/src/agents/pattern/pattern-scout/examples.md +93 -0
  287. package/dist/src/agents/pattern/pattern-scout/intro.md +3 -0
  288. package/dist/src/agents/pattern/pattern-scout/output-format.md +196 -0
  289. package/dist/src/agents/pattern/pattern-scout/workflow.md +1901 -0
  290. package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +12 -0
  291. package/dist/src/agents/pattern/web-pattern-critique/critical-reminders.md +13 -0
  292. package/dist/src/agents/pattern/web-pattern-critique/critical-requirements.md +11 -0
  293. package/dist/src/agents/pattern/web-pattern-critique/examples.md +56 -0
  294. package/dist/src/agents/pattern/web-pattern-critique/intro.md +5 -0
  295. package/dist/src/agents/pattern/web-pattern-critique/output-format.md +257 -0
  296. package/dist/src/agents/pattern/web-pattern-critique/workflow.md +674 -0
  297. package/dist/src/agents/planning/web-pm/agent.yaml +12 -0
  298. package/dist/src/agents/planning/web-pm/critical-reminders.md +21 -0
  299. package/dist/src/agents/planning/web-pm/critical-requirements.md +17 -0
  300. package/dist/src/agents/planning/web-pm/examples.md +85 -0
  301. package/dist/src/agents/planning/web-pm/intro.md +3 -0
  302. package/dist/src/agents/planning/web-pm/output-format.md +228 -0
  303. package/dist/src/agents/planning/web-pm/workflow.md +393 -0
  304. package/dist/src/agents/researcher/api-researcher/agent.yaml +10 -0
  305. package/dist/src/agents/researcher/api-researcher/critical-reminders.md +27 -0
  306. package/dist/src/agents/researcher/api-researcher/critical-requirements.md +13 -0
  307. package/dist/src/agents/researcher/api-researcher/examples.md +116 -0
  308. package/dist/src/agents/researcher/api-researcher/intro.md +32 -0
  309. package/dist/src/agents/researcher/api-researcher/output-format.md +135 -0
  310. package/dist/src/agents/researcher/api-researcher/workflow.md +261 -0
  311. package/dist/src/agents/researcher/web-researcher/agent.yaml +10 -0
  312. package/dist/src/agents/researcher/web-researcher/critical-reminders.md +23 -0
  313. package/dist/src/agents/researcher/web-researcher/critical-requirements.md +11 -0
  314. package/dist/src/agents/researcher/web-researcher/examples.md +126 -0
  315. package/dist/src/agents/researcher/web-researcher/intro.md +31 -0
  316. package/dist/src/agents/researcher/web-researcher/output-format.md +112 -0
  317. package/dist/src/agents/researcher/web-researcher/workflow.md +322 -0
  318. package/dist/src/agents/reviewer/api-reviewer/agent.yaml +12 -0
  319. package/dist/src/agents/reviewer/api-reviewer/critical-reminders.md +16 -0
  320. package/dist/src/agents/reviewer/api-reviewer/critical-requirements.md +13 -0
  321. package/dist/src/agents/reviewer/api-reviewer/examples.md +54 -0
  322. package/dist/src/agents/reviewer/api-reviewer/intro.md +22 -0
  323. package/dist/src/agents/reviewer/api-reviewer/output-format.md +288 -0
  324. package/dist/src/agents/reviewer/api-reviewer/workflow.md +369 -0
  325. package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +12 -0
  326. package/dist/src/agents/reviewer/cli-reviewer/critical-reminders.md +17 -0
  327. package/dist/src/agents/reviewer/cli-reviewer/critical-requirements.md +13 -0
  328. package/dist/src/agents/reviewer/cli-reviewer/examples.md +83 -0
  329. package/dist/src/agents/reviewer/cli-reviewer/intro.md +21 -0
  330. package/dist/src/agents/reviewer/cli-reviewer/output-format.md +330 -0
  331. package/dist/src/agents/reviewer/cli-reviewer/workflow.md +294 -0
  332. package/dist/src/agents/reviewer/web-reviewer/agent.yaml +12 -0
  333. package/dist/src/agents/reviewer/web-reviewer/critical-reminders.md +17 -0
  334. package/dist/src/agents/reviewer/web-reviewer/critical-requirements.md +11 -0
  335. package/dist/src/agents/reviewer/web-reviewer/examples.md +79 -0
  336. package/dist/src/agents/reviewer/web-reviewer/intro.md +20 -0
  337. package/dist/src/agents/reviewer/web-reviewer/output-format.md +253 -0
  338. package/dist/src/agents/reviewer/web-reviewer/workflow.md +228 -0
  339. package/dist/src/agents/tester/cli-tester/agent.yaml +12 -0
  340. package/dist/src/agents/tester/cli-tester/critical-reminders.md +19 -0
  341. package/dist/src/agents/tester/cli-tester/critical-requirements.md +17 -0
  342. package/dist/src/agents/tester/cli-tester/examples.md +80 -0
  343. package/dist/src/agents/tester/cli-tester/intro.md +19 -0
  344. package/dist/src/agents/tester/cli-tester/output-format.md +232 -0
  345. package/dist/src/agents/tester/cli-tester/workflow.md +304 -0
  346. package/dist/src/agents/tester/web-tester/agent.yaml +12 -0
  347. package/dist/src/agents/tester/web-tester/critical-reminders.md +15 -0
  348. package/dist/src/agents/tester/web-tester/critical-requirements.md +11 -0
  349. package/dist/src/agents/tester/web-tester/examples.md +68 -0
  350. package/dist/src/agents/tester/web-tester/intro.md +18 -0
  351. package/dist/src/agents/tester/web-tester/output-format.md +252 -0
  352. package/dist/src/agents/tester/web-tester/workflow.md +507 -0
  353. package/dist/stores/wizard-store.js +13 -0
  354. package/dist/stores/wizard-store.js.map +1 -0
  355. package/dist/stores/wizard-store.test.js +689 -0
  356. package/dist/stores/wizard-store.test.js.map +1 -0
  357. package/package.json +134 -0
  358. package/src/agents/_templates/agent.liquid +140 -0
  359. package/src/agents/developer/api-developer/agent.yaml +12 -0
  360. package/src/agents/developer/api-developer/critical-reminders.md +23 -0
  361. package/src/agents/developer/api-developer/critical-requirements.md +11 -0
  362. package/src/agents/developer/api-developer/examples.md +72 -0
  363. package/src/agents/developer/api-developer/intro.md +22 -0
  364. package/src/agents/developer/api-developer/output-format.md +359 -0
  365. package/src/agents/developer/api-developer/workflow.md +471 -0
  366. package/src/agents/developer/cli-developer/agent.yaml +12 -0
  367. package/src/agents/developer/cli-developer/critical-reminders.md +28 -0
  368. package/src/agents/developer/cli-developer/critical-requirements.md +15 -0
  369. package/src/agents/developer/cli-developer/examples.md +68 -0
  370. package/src/agents/developer/cli-developer/intro.md +23 -0
  371. package/src/agents/developer/cli-developer/output-format.md +216 -0
  372. package/src/agents/developer/cli-developer/workflow.md +509 -0
  373. package/src/agents/developer/web-architecture/agent.yaml +12 -0
  374. package/src/agents/developer/web-architecture/critical-reminders.md +27 -0
  375. package/src/agents/developer/web-architecture/critical-requirements.md +35 -0
  376. package/src/agents/developer/web-architecture/examples.md +187 -0
  377. package/src/agents/developer/web-architecture/intro.md +35 -0
  378. package/src/agents/developer/web-architecture/output-format.md +261 -0
  379. package/src/agents/developer/web-architecture/workflow.md +599 -0
  380. package/src/agents/developer/web-developer/agent.yaml +12 -0
  381. package/src/agents/developer/web-developer/critical-reminders.md +17 -0
  382. package/src/agents/developer/web-developer/critical-requirements.md +15 -0
  383. package/src/agents/developer/web-developer/examples.md +109 -0
  384. package/src/agents/developer/web-developer/intro.md +5 -0
  385. package/src/agents/developer/web-developer/output-format.md +213 -0
  386. package/src/agents/developer/web-developer/workflow.md +459 -0
  387. package/src/agents/meta/agent-summoner/agent.yaml +12 -0
  388. package/src/agents/meta/agent-summoner/critical-reminders.md +31 -0
  389. package/src/agents/meta/agent-summoner/critical-requirements.md +27 -0
  390. package/src/agents/meta/agent-summoner/examples.md +176 -0
  391. package/src/agents/meta/agent-summoner/intro.md +9 -0
  392. package/src/agents/meta/agent-summoner/output-format.md +115 -0
  393. package/src/agents/meta/agent-summoner/workflow.md +1540 -0
  394. package/src/agents/meta/documentor/agent.yaml +11 -0
  395. package/src/agents/meta/documentor/critical-reminders.md +23 -0
  396. package/src/agents/meta/documentor/critical-requirements.md +13 -0
  397. package/src/agents/meta/documentor/examples.md +147 -0
  398. package/src/agents/meta/documentor/intro.md +11 -0
  399. package/src/agents/meta/documentor/output-format.md +237 -0
  400. package/src/agents/meta/documentor/workflow.md +1271 -0
  401. package/src/agents/meta/skill-summoner/agent.yaml +13 -0
  402. package/src/agents/meta/skill-summoner/critical-reminders.md +73 -0
  403. package/src/agents/meta/skill-summoner/critical-requirements.md +62 -0
  404. package/src/agents/meta/skill-summoner/examples.md +116 -0
  405. package/src/agents/meta/skill-summoner/intro.md +5 -0
  406. package/src/agents/meta/skill-summoner/output-format.md +279 -0
  407. package/src/agents/meta/skill-summoner/workflow.md +1485 -0
  408. package/src/agents/migration/cli-migrator/agent.yaml +12 -0
  409. package/src/agents/migration/cli-migrator/anti-patterns.md +158 -0
  410. package/src/agents/migration/cli-migrator/conversion-mappings.md +63 -0
  411. package/src/agents/migration/cli-migrator/critical-reminders.md +17 -0
  412. package/src/agents/migration/cli-migrator/critical-requirements.md +13 -0
  413. package/src/agents/migration/cli-migrator/intro.md +15 -0
  414. package/src/agents/migration/cli-migrator/output-format.md +164 -0
  415. package/src/agents/migration/cli-migrator/workflow.md +230 -0
  416. package/src/agents/pattern/pattern-scout/agent.yaml +10 -0
  417. package/src/agents/pattern/pattern-scout/critical-reminders.md +58 -0
  418. package/src/agents/pattern/pattern-scout/critical-requirements.md +17 -0
  419. package/src/agents/pattern/pattern-scout/examples.md +93 -0
  420. package/src/agents/pattern/pattern-scout/intro.md +3 -0
  421. package/src/agents/pattern/pattern-scout/output-format.md +196 -0
  422. package/src/agents/pattern/pattern-scout/workflow.md +1901 -0
  423. package/src/agents/pattern/web-pattern-critique/agent.yaml +12 -0
  424. package/src/agents/pattern/web-pattern-critique/critical-reminders.md +13 -0
  425. package/src/agents/pattern/web-pattern-critique/critical-requirements.md +11 -0
  426. package/src/agents/pattern/web-pattern-critique/examples.md +56 -0
  427. package/src/agents/pattern/web-pattern-critique/intro.md +5 -0
  428. package/src/agents/pattern/web-pattern-critique/output-format.md +257 -0
  429. package/src/agents/pattern/web-pattern-critique/workflow.md +674 -0
  430. package/src/agents/planning/web-pm/agent.yaml +12 -0
  431. package/src/agents/planning/web-pm/critical-reminders.md +21 -0
  432. package/src/agents/planning/web-pm/critical-requirements.md +17 -0
  433. package/src/agents/planning/web-pm/examples.md +85 -0
  434. package/src/agents/planning/web-pm/intro.md +3 -0
  435. package/src/agents/planning/web-pm/output-format.md +228 -0
  436. package/src/agents/planning/web-pm/workflow.md +393 -0
  437. package/src/agents/researcher/api-researcher/agent.yaml +10 -0
  438. package/src/agents/researcher/api-researcher/critical-reminders.md +27 -0
  439. package/src/agents/researcher/api-researcher/critical-requirements.md +13 -0
  440. package/src/agents/researcher/api-researcher/examples.md +116 -0
  441. package/src/agents/researcher/api-researcher/intro.md +32 -0
  442. package/src/agents/researcher/api-researcher/output-format.md +135 -0
  443. package/src/agents/researcher/api-researcher/workflow.md +261 -0
  444. package/src/agents/researcher/web-researcher/agent.yaml +10 -0
  445. package/src/agents/researcher/web-researcher/critical-reminders.md +23 -0
  446. package/src/agents/researcher/web-researcher/critical-requirements.md +11 -0
  447. package/src/agents/researcher/web-researcher/examples.md +126 -0
  448. package/src/agents/researcher/web-researcher/intro.md +31 -0
  449. package/src/agents/researcher/web-researcher/output-format.md +112 -0
  450. package/src/agents/researcher/web-researcher/workflow.md +322 -0
  451. package/src/agents/reviewer/api-reviewer/agent.yaml +12 -0
  452. package/src/agents/reviewer/api-reviewer/critical-reminders.md +16 -0
  453. package/src/agents/reviewer/api-reviewer/critical-requirements.md +13 -0
  454. package/src/agents/reviewer/api-reviewer/examples.md +54 -0
  455. package/src/agents/reviewer/api-reviewer/intro.md +22 -0
  456. package/src/agents/reviewer/api-reviewer/output-format.md +288 -0
  457. package/src/agents/reviewer/api-reviewer/workflow.md +369 -0
  458. package/src/agents/reviewer/cli-reviewer/agent.yaml +12 -0
  459. package/src/agents/reviewer/cli-reviewer/critical-reminders.md +17 -0
  460. package/src/agents/reviewer/cli-reviewer/critical-requirements.md +13 -0
  461. package/src/agents/reviewer/cli-reviewer/examples.md +83 -0
  462. package/src/agents/reviewer/cli-reviewer/intro.md +21 -0
  463. package/src/agents/reviewer/cli-reviewer/output-format.md +330 -0
  464. package/src/agents/reviewer/cli-reviewer/workflow.md +294 -0
  465. package/src/agents/reviewer/web-reviewer/agent.yaml +12 -0
  466. package/src/agents/reviewer/web-reviewer/critical-reminders.md +17 -0
  467. package/src/agents/reviewer/web-reviewer/critical-requirements.md +11 -0
  468. package/src/agents/reviewer/web-reviewer/examples.md +79 -0
  469. package/src/agents/reviewer/web-reviewer/intro.md +20 -0
  470. package/src/agents/reviewer/web-reviewer/output-format.md +253 -0
  471. package/src/agents/reviewer/web-reviewer/workflow.md +228 -0
  472. package/src/agents/tester/cli-tester/agent.yaml +12 -0
  473. package/src/agents/tester/cli-tester/critical-reminders.md +19 -0
  474. package/src/agents/tester/cli-tester/critical-requirements.md +17 -0
  475. package/src/agents/tester/cli-tester/examples.md +80 -0
  476. package/src/agents/tester/cli-tester/intro.md +19 -0
  477. package/src/agents/tester/cli-tester/output-format.md +232 -0
  478. package/src/agents/tester/cli-tester/workflow.md +304 -0
  479. package/src/agents/tester/web-tester/agent.yaml +12 -0
  480. package/src/agents/tester/web-tester/critical-reminders.md +15 -0
  481. package/src/agents/tester/web-tester/critical-requirements.md +11 -0
  482. package/src/agents/tester/web-tester/examples.md +68 -0
  483. package/src/agents/tester/web-tester/intro.md +18 -0
  484. package/src/agents/tester/web-tester/output-format.md +252 -0
  485. package/src/agents/tester/web-tester/workflow.md +507 -0
  486. package/src/schemas/agent-frontmatter.schema.json +84 -0
  487. package/src/schemas/agent.schema.json +93 -0
  488. package/src/schemas/hooks.schema.json +47 -0
  489. package/src/schemas/marketplace.schema.json +119 -0
  490. package/src/schemas/metadata.schema.json +113 -0
  491. package/src/schemas/plugin.schema.json +130 -0
  492. package/src/schemas/project-config.schema.json +125 -0
  493. package/src/schemas/project-source-config.schema.json +81 -0
  494. package/src/schemas/skill-frontmatter.schema.json +42 -0
  495. package/src/schemas/skills-matrix.schema.json +467 -0
  496. package/src/schemas/stack.schema.json +191 -0
  497. package/src/schemas/stacks.schema.json +111 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/category-grid.tsx","../src/cli/components/hooks/use-virtual-scroll.ts","../src/cli/components/hooks/use-category-grid-input.ts"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\n\nimport { Box, Text } from \"ink\";\nimport { sortBy } from \"remeda\";\n\nimport type { SkillId, Subcategory } from \"../../types/index.js\";\nimport { CLI_COLORS, SCROLL_VIEWPORT, UI_SYMBOLS } from \"../../consts.js\";\nimport { useVirtualScroll } from \"../hooks/use-virtual-scroll.js\";\nimport {\n findValidStartColumn,\n isSectionLocked,\n useCategoryGridInput,\n} from \"../hooks/use-category-grid-input.js\";\nimport { useFocusedListItem } from \"../hooks/use-focused-list-item.js\";\n\nexport type OptionState = \"normal\" | \"recommended\" | \"discouraged\" | \"disabled\";\n\nexport type CategoryOption = {\n id: SkillId;\n label: string;\n state: OptionState;\n stateReason?: string;\n selected: boolean;\n local?: boolean;\n installed?: boolean;\n};\n\nexport type CategoryRow = {\n id: Subcategory;\n displayName: string;\n required: boolean;\n exclusive: boolean;\n options: CategoryOption[];\n};\n\nexport type CategoryGridProps = {\n categories: CategoryRow[];\n showDescriptions: boolean;\n expertMode: boolean;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n /** Optional initial focus row (default: 0). Use with React `key` to reset. */\n defaultFocusedRow?: number;\n /** Optional initial focus col (default: 0). Use with React `key` to reset. */\n defaultFocusedCol?: number;\n /** Optional callback fired whenever the focused position changes */\n onFocusChange?: (row: number, col: number) => void;\n /** Available height in terminal rows for the category list. When undefined, all categories render. */\n availableHeight?: number;\n /** Terminal width in columns, used for tag wrapping estimation. */\n terminalWidth?: number;\n};\n\nconst SYMBOL_REQUIRED = \"*\";\n\n// Recommended first, discouraged last. Expert mode preserves original order.\nconst sortOptions = (options: CategoryOption[], expertMode: boolean): CategoryOption[] => {\n if (expertMode) {\n return options;\n }\n\n const stateOrder: Record<OptionState, number> = {\n recommended: 0,\n normal: 1,\n discouraged: 2,\n disabled: 3,\n };\n\n return sortBy([...options], (o) => stateOrder[o.state]);\n};\n\nconst findNextValidOption = (\n options: CategoryOption[],\n currentIndex: number,\n direction: 1 | -1,\n wrap = true,\n): number => {\n const length = options.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += direction;\n\n if (wrap) {\n if (index < 0) index = length - 1;\n if (index >= length) index = 0;\n } else {\n if (index < 0) index = 0;\n if (index >= length) index = length - 1;\n }\n\n if (options[index] && options[index].state !== \"disabled\") {\n return index;\n }\n\n attempts++;\n }\n\n return currentIndex;\n};\n\ntype SkillTagProps = {\n option: CategoryOption;\n isFocused: boolean;\n isLocked: boolean;\n};\n\nconst getStateSuffix = (state: OptionState, isLocked: boolean): string | null => {\n if (isLocked || state === \"disabled\") return \"(disabled)\";\n if (state === \"recommended\") return \"(recommended)\";\n if (state === \"discouraged\") return \"(discouraged)\";\n return null;\n};\n\nconst getStateSymbol = (option: CategoryOption, isLocked: boolean): string => {\n if (isLocked || option.state === \"disabled\") return UI_SYMBOLS.DISABLED;\n if (option.selected) return UI_SYMBOLS.SELECTED;\n if (option.state === \"discouraged\") return UI_SYMBOLS.DISCOURAGED;\n return UI_SYMBOLS.UNSELECTED;\n};\n\nconst SkillTag: React.FC<SkillTagProps> = ({ option, isFocused, isLocked }) => {\n const getColor = (): { text: string; border: string } => {\n if (isLocked || option.state === \"disabled\") {\n return {\n text: CLI_COLORS.NEUTRAL,\n border: CLI_COLORS.NEUTRAL,\n };\n }\n if (option.selected) {\n return {\n text: CLI_COLORS.PRIMARY,\n border: CLI_COLORS.PRIMARY,\n };\n }\n if (option.state === \"recommended\") {\n return {\n text: CLI_COLORS.UNFOCUSED,\n border: CLI_COLORS.NEUTRAL,\n };\n }\n if (option.state === \"discouraged\") {\n return {\n text: CLI_COLORS.WARNING,\n border: CLI_COLORS.WARNING,\n };\n }\n // Normal unselected: muted color to clearly contrast with selected (cyan) skills\n return {\n text: CLI_COLORS.NEUTRAL,\n border: CLI_COLORS.NEUTRAL,\n };\n };\n\n const isBold = isFocused || option.selected;\n const isDimmed = isLocked || option.state === \"disabled\";\n const isBorderDimmed = isDimmed || (!option.selected && !isFocused);\n const focusBorderColor = option.selected ? CLI_COLORS.PRIMARY : CLI_COLORS.UNFOCUSED;\n const colors = getColor();\n const stateSuffix = getStateSuffix(option.state, isLocked);\n const stateSymbol = getStateSymbol(option, isLocked);\n\n return (\n <Box\n marginRight={1}\n borderColor={isFocused ? focusBorderColor : colors.border}\n borderStyle=\"single\"\n borderDimColor={isBorderDimmed}\n >\n <Text color={colors.text} bold={isBold} dimColor={false}>\n {\" \"}\n {option.local && (\n <>\n <Text backgroundColor={CLI_COLORS.NEUTRAL}> L </Text>{\" \"}\n </>\n )}\n {option.installed && <Text dimColor>{UI_SYMBOLS.SELECTED} </Text>}\n {!option.installed && <Text dimColor={isDimmed}>{stateSymbol} </Text>}\n {option.label}\n {stateSuffix && <Text dimColor> {stateSuffix}</Text>}{\" \"}\n </Text>\n </Box>\n );\n};\n\ntype CategorySectionProps = {\n category: CategoryRow;\n options: CategoryOption[];\n isLocked: boolean;\n isFocused: boolean;\n focusedOptionIndex: number;\n showDescriptions: boolean;\n};\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n category,\n options,\n isLocked,\n isFocused,\n focusedOptionIndex,\n showDescriptions,\n}) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text dimColor={isLocked}>{category.displayName}</Text>\n {category.required && (\n <Text color={isLocked ? CLI_COLORS.NEUTRAL : CLI_COLORS.ERROR} dimColor={isLocked}>\n {\" \"}\n {SYMBOL_REQUIRED}\n </Text>\n )}\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {options.map((option, index) => (\n <Box key={option.id} flexDirection=\"column\">\n <SkillTag\n option={option}\n isFocused={isFocused && index === focusedOptionIndex && !isLocked}\n isLocked={isLocked}\n />\n {showDescriptions && option.stateReason && !isLocked && (\n <Box marginLeft={1} marginBottom={0}>\n <Text dimColor wrap=\"truncate-end\">\n {option.stateReason}\n </Text>\n </Box>\n )}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\n/**\n * Estimate the rendered height of a category section in terminal rows.\n *\n * Each category consists of:\n * - 1 line for the category name (+ margin-top)\n * - N lines for the skill tags (based on count and terminal width wrapping)\n *\n * Tag wrapping: skill tags use flexWrap=\"wrap\". Each tag is approximately\n * AVG_TAG_WIDTH chars wide. The number of rows is ceil(tags * tagWidth / terminalWidth).\n */\nconst estimateCategoryHeight = (category: ProcessedCategory, terminalWidth: number): number => {\n const { CATEGORY_NAME_LINES, AVG_TAG_WIDTH, CATEGORY_MARGIN_LINES } = SCROLL_VIEWPORT;\n const optionCount = category.sortedOptions.length;\n const tagsPerRow = Math.max(1, Math.floor(terminalWidth / AVG_TAG_WIDTH));\n const tagRows = Math.ceil(optionCount / tagsPerRow);\n return CATEGORY_NAME_LINES + tagRows + CATEGORY_MARGIN_LINES;\n};\n\ntype ScrollIndicatorProps = {\n count: number;\n direction: \"above\" | \"below\";\n};\n\nconst ScrollIndicator: React.FC<ScrollIndicatorProps> = ({ count, direction }) => {\n if (count === 0) return null;\n\n const arrow = direction === \"above\" ? UI_SYMBOLS.SCROLL_UP : UI_SYMBOLS.SCROLL_DOWN;\n const label = `${arrow} ${count} more ${count === 1 ? \"category\" : \"categories\"} ${direction}`;\n\n return (\n <Box paddingLeft={1} marginTop={direction === \"below\" ? 1 : 0}>\n <Text dimColor>{label}</Text>\n </Box>\n );\n};\n\nconst DEFAULT_TERMINAL_WIDTH = 80;\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n showDescriptions,\n expertMode,\n onToggle,\n onToggleDescriptions,\n defaultFocusedRow = 0,\n defaultFocusedCol = 0,\n onFocusChange,\n availableHeight,\n terminalWidth,\n}) => {\n const processedCategories = useMemo(\n () =>\n categories.map((category) => ({\n ...category,\n sortedOptions: sortOptions(category.options, expertMode),\n })),\n [categories, expertMode],\n );\n\n const getColCount = useCallback(\n (row: number): number => processedCategories[row]?.sortedOptions.length ?? 0,\n [processedCategories],\n );\n\n const isRowLocked = useCallback(\n (row: number): boolean => {\n const cat = processedCategories[row];\n return cat ? isSectionLocked(cat.id, categories) : false;\n },\n [processedCategories, categories],\n );\n\n const findValidCol = useCallback(\n (row: number, currentCol: number, direction: 1 | -1): number => {\n const options = processedCategories[row]?.sortedOptions || [];\n const catId = processedCategories[row]?.id;\n if (catId && isSectionLocked(catId, categories)) return currentCol;\n return findNextValidOption(options, currentCol, direction, true);\n },\n [processedCategories, categories],\n );\n\n const adjustCol = useCallback(\n (row: number, clampedCol: number): number => {\n const options = processedCategories[row]?.sortedOptions || [];\n if (options[clampedCol]?.state === \"disabled\") {\n return findValidStartColumn(options);\n }\n return clampedCol;\n },\n [processedCategories],\n );\n\n const { focusedRow, focusedCol, setFocused, moveFocus } = useFocusedListItem(\n processedCategories.length,\n getColCount,\n {\n wrap: true,\n isRowLocked,\n findValidCol,\n adjustCol,\n onChange: onFocusChange,\n initialRow: defaultFocusedRow,\n initialCol: defaultFocusedCol,\n },\n );\n\n useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleDescriptions,\n });\n\n const { visibleItems, startIndex, hiddenAbove, hiddenBelow, isScrollable } = useVirtualScroll({\n items: processedCategories,\n availableHeight: availableHeight ?? Infinity,\n focusedIndex: focusedRow,\n estimateItemHeight: estimateCategoryHeight,\n terminalWidth: terminalWidth ?? DEFAULT_TERMINAL_WIDTH,\n });\n\n if (categories.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>No categories to display.</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {isScrollable && <ScrollIndicator count={hiddenAbove} direction=\"above\" />}\n\n {visibleItems.map((category, visibleIndex) => {\n const originalIndex = startIndex + visibleIndex;\n const isLocked = isSectionLocked(category.id, categories);\n\n return (\n <CategorySection\n key={category.id}\n category={category}\n options={category.sortedOptions}\n isLocked={isLocked}\n isFocused={originalIndex === focusedRow}\n focusedOptionIndex={focusedCol}\n showDescriptions={showDescriptions}\n />\n );\n })}\n\n {isScrollable && <ScrollIndicator count={hiddenBelow} direction=\"below\" />}\n </Box>\n );\n};\n","import { useMemo } from \"react\";\nimport { SCROLL_VIEWPORT } from \"../../consts.js\";\n\nexport type VirtualScrollOptions<T> = {\n /** All items to potentially display */\n items: T[];\n /** Maximum height in terminal rows for the scrollable area */\n availableHeight: number;\n /** Current focused item index (drives auto-scroll) */\n focusedIndex: number;\n /** Estimate the height of a single item in terminal rows */\n estimateItemHeight: (item: T, terminalWidth: number) => number;\n /** Current terminal width (for tag wrapping estimation) */\n terminalWidth: number;\n};\n\nexport type VirtualScrollResult<T> = {\n /** Items visible in the current viewport window */\n visibleItems: T[];\n /** Index of the first visible item in the original array */\n startIndex: number;\n /** Index past the last visible item in the original array */\n endIndex: number;\n /** Number of items hidden above the viewport */\n hiddenAbove: number;\n /** Number of items hidden below the viewport */\n hiddenBelow: number;\n /** Whether the content is scrollable (total items exceed viewport) */\n isScrollable: boolean;\n};\n\n/**\n * Pure computation for virtual scroll windowing.\n *\n * Computes a contiguous window of items that fits within `availableHeight`,\n * ensuring the `focusedIndex` item is always visible. When the focused item\n * moves outside the current window, the window shifts to include it.\n *\n * Height is estimated per-item via `estimateItemHeight` rather than measured\n * post-render, avoiding the chicken-and-egg measurement problem with Ink.\n */\nexport function computeVirtualScroll<T>({\n items,\n availableHeight,\n focusedIndex,\n estimateItemHeight,\n terminalWidth,\n}: VirtualScrollOptions<T>): VirtualScrollResult<T> {\n const totalItems = items.length;\n\n if (totalItems === 0) {\n return {\n visibleItems: [],\n startIndex: 0,\n endIndex: 0,\n hiddenAbove: 0,\n hiddenBelow: 0,\n isScrollable: false,\n };\n }\n\n // Compute heights for each item\n const heights = items.map((item) => estimateItemHeight(item, terminalWidth));\n const totalHeight = heights.reduce((sum, h) => sum + h, 0);\n\n // If everything fits, no scrolling needed\n if (totalHeight <= availableHeight) {\n return {\n visibleItems: items,\n startIndex: 0,\n endIndex: totalItems,\n hiddenAbove: 0,\n hiddenBelow: 0,\n isScrollable: false,\n };\n }\n\n // Reserve space for scroll indicators when content overflows\n const viewportHeight = Math.max(\n SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS,\n availableHeight - SCROLL_VIEWPORT.SCROLL_INDICATOR_HEIGHT * 2,\n );\n\n // Clamp focused index\n const safeFocused = Math.max(0, Math.min(focusedIndex, totalItems - 1));\n\n // Find a window that includes the focused item and fills the viewport.\n // Strategy: start from focused item and expand outward.\n let startIndex = safeFocused;\n let endIndex = safeFocused + 1;\n let usedHeight = heights[safeFocused] ?? 0;\n\n // Expand downward first\n while (endIndex < totalItems) {\n const nextHeight = heights[endIndex] ?? 0;\n if (usedHeight + nextHeight > viewportHeight) break;\n usedHeight += nextHeight;\n endIndex++;\n }\n\n // Expand upward with remaining space\n while (startIndex > 0) {\n const prevHeight = heights[startIndex - 1] ?? 0;\n if (usedHeight + prevHeight > viewportHeight) break;\n usedHeight += prevHeight;\n startIndex--;\n }\n\n // If we still have room after expanding up, try expanding down again\n while (endIndex < totalItems) {\n const nextHeight = heights[endIndex] ?? 0;\n if (usedHeight + nextHeight > viewportHeight) break;\n usedHeight += nextHeight;\n endIndex++;\n }\n\n return {\n visibleItems: items.slice(startIndex, endIndex),\n startIndex,\n endIndex,\n hiddenAbove: startIndex,\n hiddenBelow: totalItems - endIndex,\n isScrollable: true,\n };\n}\n\n/**\n * React hook wrapper around `computeVirtualScroll`.\n * Memoizes the result based on input changes.\n */\nexport function useVirtualScroll<T>(options: VirtualScrollOptions<T>): VirtualScrollResult<T> {\n const { items, availableHeight, focusedIndex, estimateItemHeight, terminalWidth } = options;\n return useMemo(\n () => computeVirtualScroll(options),\n [items, availableHeight, focusedIndex, estimateItemHeight, terminalWidth],\n );\n}\n","import { useCallback, useEffect } from \"react\";\nimport { useInput } from \"ink\";\n\nimport type { Subcategory, SkillId } from \"../../types/index.js\";\nimport type { CategoryOption, CategoryRow } from \"../wizard/category-grid.js\";\n\nconst FRAMEWORK_CATEGORY_ID = \"framework\";\n\n// Locked = non-framework section when no framework is selected\nexport const isSectionLocked = (categoryId: Subcategory, categories: CategoryRow[]): boolean => {\n if (categoryId === FRAMEWORK_CATEGORY_ID) {\n return false;\n }\n\n const frameworkCategory = categories.find((cat) => cat.id === FRAMEWORK_CATEGORY_ID);\n if (!frameworkCategory) return false;\n\n return !frameworkCategory.options.some((opt) => opt.selected);\n};\n\nexport const findValidStartColumn = (options: CategoryOption[]): number => {\n for (let i = 0; i < options.length; i++) {\n if (options[i] && options[i].state !== \"disabled\") {\n return i;\n }\n }\n return 0;\n};\n\n/** Find next unlocked section index (wrapping, direction: forward) */\nexport const findNextUnlockedIndex = (\n processed: { id: Subcategory; sortedOptions: CategoryOption[] }[],\n currentIndex: number,\n allCategories: CategoryRow[],\n): number => {\n const length = processed.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += 1;\n if (index >= length) index = 0;\n\n const category = processed[index];\n if (category && !isSectionLocked(category.id, allCategories)) {\n return index;\n }\n\n attempts++;\n }\n\n return currentIndex;\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\ntype UseCategoryGridInputOptions = {\n processedCategories: ProcessedCategory[];\n categories: CategoryRow[];\n focusedRow: number;\n focusedCol: number;\n setFocused: (row: number, col: number) => void;\n moveFocus: (direction: \"up\" | \"down\" | \"left\" | \"right\") => void;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n};\n\nexport function useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleDescriptions,\n}: UseCategoryGridInputOptions): void {\n const currentRow = processedCategories[focusedRow];\n const currentOptions = currentRow?.sortedOptions || [];\n const currentLocked = currentRow ? isSectionLocked(currentRow.id, categories) : false;\n\n // Adjust column when current row's options change externally (e.g. option becomes disabled)\n useEffect(() => {\n if (!currentRow) return;\n\n const maxCol = currentOptions.length - 1;\n if (focusedCol > maxCol) {\n const newCol = Math.max(0, maxCol);\n setFocused(focusedRow, newCol);\n } else if (currentOptions[focusedCol]?.state === \"disabled\") {\n const validCol = findValidStartColumn(currentOptions);\n if (validCol !== focusedCol) {\n setFocused(focusedRow, validCol);\n }\n }\n }, [focusedRow, currentOptions, focusedCol, setFocused, currentRow]);\n\n // Bounce off locked sections when a section becomes locked (e.g. framework deselected)\n useEffect(() => {\n if (currentRow && currentLocked) {\n const nextUnlocked = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextUnlocked !== focusedRow) {\n const newRowOptions = processedCategories[nextUnlocked]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextUnlocked, newCol);\n }\n }\n }, [currentRow, currentLocked, focusedRow, processedCategories, categories, setFocused]);\n\n useInput(\n useCallback(\n (\n input: string,\n key: {\n leftArrow: boolean;\n rightArrow: boolean;\n upArrow: boolean;\n downArrow: boolean;\n tab: boolean;\n shift: boolean;\n },\n ) => {\n if (key.tab && key.shift) {\n onToggleDescriptions();\n return;\n }\n\n if (key.tab && !key.shift) {\n const nextSection = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextSection !== focusedRow) {\n const newRowOptions = processedCategories[nextSection]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextSection, newCol);\n }\n return;\n }\n\n if (input === \"d\" || input === \"D\") {\n onToggleDescriptions();\n return;\n }\n\n if (input === \" \") {\n if (currentLocked) return;\n const currentOption = currentOptions[focusedCol];\n if (currentOption && currentOption.state !== \"disabled\") {\n onToggle(currentRow.id, currentOption.id);\n }\n return;\n }\n\n const isLeft = key.leftArrow || input === \"h\";\n const isRight = key.rightArrow || input === \"l\";\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isLeft) {\n if (currentLocked) return;\n moveFocus(\"left\");\n } else if (isRight) {\n if (currentLocked) return;\n moveFocus(\"right\");\n } else if (isUp) {\n moveFocus(\"up\");\n } else if (isDown) {\n moveFocus(\"down\");\n }\n },\n [\n focusedRow,\n focusedCol,\n currentOptions,\n currentRow,\n currentLocked,\n processedCategories,\n categories,\n onToggle,\n onToggleDescriptions,\n setFocused,\n moveFocus,\n ],\n ),\n );\n}\n"],"mappings":"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","names":["useCallback","useMemo","useMemo","useCallback"]}
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ViewTitle
4
+ } from "./chunk-O4D67NN7.js";
5
+ import {
6
+ getDomainDisplayName
7
+ } from "./chunk-SO22IQPY.js";
8
+ import {
9
+ CategoryGrid
10
+ } from "./chunk-OGJIZ6QH.js";
11
+ import {
12
+ getAvailableSkills,
13
+ resolveAlias
14
+ } from "./chunk-MM7NK5N2.js";
15
+ import {
16
+ CLI_COLORS,
17
+ SCROLL_VIEWPORT,
18
+ UI_SYMBOLS
19
+ } from "./chunk-LAPCUV4D.js";
20
+ import {
21
+ init_esm_shims
22
+ } from "./chunk-DHET7RCE.js";
23
+
24
+ // src/cli/components/wizard/step-build.tsx
25
+ init_esm_shims();
26
+ import { useState as useState3 } from "react";
27
+ import { Box, Text, useInput } from "ink";
28
+
29
+ // src/cli/lib/wizard/index.ts
30
+ init_esm_shims();
31
+
32
+ // src/cli/lib/wizard/build-step-logic.ts
33
+ init_esm_shims();
34
+ import { sortBy } from "remeda";
35
+ var FRAMEWORK_SUBCATEGORY_ID = "framework";
36
+ var WEB_DOMAIN_ID = "web";
37
+ function validateBuildStep(categories, selections) {
38
+ for (const category of categories) {
39
+ if (category.required) {
40
+ const categorySelections = selections[category.id] || [];
41
+ if (categorySelections.length === 0) {
42
+ return {
43
+ valid: false,
44
+ message: `Select at least one skill from the ${category.displayName} category. Use arrow keys to navigate, then SPACE to select.`
45
+ };
46
+ }
47
+ }
48
+ }
49
+ return { valid: true };
50
+ }
51
+ function computeOptionState(skill) {
52
+ if (skill.disabled) {
53
+ return "disabled";
54
+ }
55
+ if (skill.discouraged) {
56
+ return "discouraged";
57
+ }
58
+ if (skill.recommended) {
59
+ return "recommended";
60
+ }
61
+ return "normal";
62
+ }
63
+ function getSkillDisplayLabel(skill) {
64
+ return skill.displayName || skill.id;
65
+ }
66
+ function getStateReason(skill) {
67
+ if (skill.disabled && skill.disabledReason) {
68
+ return skill.disabledReason;
69
+ }
70
+ if (skill.discouraged && skill.discouragedReason) {
71
+ return skill.discouragedReason;
72
+ }
73
+ if (skill.recommended && skill.recommendedReason) {
74
+ return skill.recommendedReason;
75
+ }
76
+ return void 0;
77
+ }
78
+ function isFrameworkSelected(selections) {
79
+ const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];
80
+ return frameworkSelections.length > 0;
81
+ }
82
+ function getSelectedFrameworks(selections, matrix) {
83
+ const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];
84
+ return frameworkSelections.map((alias) => resolveAlias(alias, matrix));
85
+ }
86
+ function isCompatibleWithSelectedFrameworks(skillId, selectedFrameworkIds, matrix) {
87
+ const skill = matrix.skills[skillId];
88
+ if (!skill) return false;
89
+ if (skill.compatibleWith.length === 0) {
90
+ return true;
91
+ }
92
+ return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));
93
+ }
94
+ function buildCategoriesForDomain(domain, allSelections, matrix, expertMode, selections, parentDomainSelections, installedSkillIds) {
95
+ const frameworkSource = parentDomainSelections ?? selections;
96
+ const frameworkSelected = isFrameworkSelected(frameworkSource);
97
+ const selectedFrameworkIds = frameworkSelected ? getSelectedFrameworks(frameworkSource, matrix) : [];
98
+ const subcategories = sortBy(
99
+ Object.values(matrix.categories).filter((cat) => cat.domain === domain),
100
+ (cat) => cat.order ?? 0
101
+ );
102
+ const categoryRows = subcategories.map((cat) => {
103
+ const skillOptions = getAvailableSkills(cat.id, allSelections, matrix, {
104
+ expertMode
105
+ });
106
+ const useFrameworkFilter = (domain === WEB_DOMAIN_ID || parentDomainSelections !== void 0) && cat.id !== FRAMEWORK_SUBCATEGORY_ID && frameworkSelected;
107
+ const filteredSkillOptions = useFrameworkFilter ? skillOptions.filter(
108
+ (skill) => isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds, matrix)
109
+ ) : skillOptions;
110
+ const options = filteredSkillOptions.map((skill) => ({
111
+ id: skill.id,
112
+ label: getSkillDisplayLabel(skill),
113
+ state: computeOptionState(skill),
114
+ stateReason: getStateReason(skill),
115
+ selected: skill.selected,
116
+ local: matrix.skills[skill.id]?.local,
117
+ installed: installedSkillIds?.includes(skill.id) || false
118
+ }));
119
+ return {
120
+ id: cat.id,
121
+ displayName: cat.displayName,
122
+ required: cat.required ?? false,
123
+ exclusive: cat.exclusive ?? true,
124
+ options
125
+ };
126
+ });
127
+ return categoryRows.filter((row) => row.options.length > 0);
128
+ }
129
+
130
+ // src/cli/components/hooks/use-framework-filtering.ts
131
+ init_esm_shims();
132
+ import { useMemo } from "react";
133
+ function useFrameworkFiltering({
134
+ domain,
135
+ allSelections,
136
+ matrix,
137
+ expertMode,
138
+ selections,
139
+ parentDomainSelections,
140
+ installedSkillIds
141
+ }) {
142
+ return useMemo(
143
+ () => buildCategoriesForDomain(
144
+ domain,
145
+ allSelections,
146
+ matrix,
147
+ expertMode,
148
+ selections,
149
+ parentDomainSelections,
150
+ installedSkillIds
151
+ ),
152
+ [
153
+ domain,
154
+ allSelections,
155
+ matrix,
156
+ expertMode,
157
+ selections,
158
+ parentDomainSelections,
159
+ installedSkillIds
160
+ ]
161
+ );
162
+ }
163
+
164
+ // src/cli/components/hooks/use-terminal-dimensions.ts
165
+ init_esm_shims();
166
+ import { useState, useEffect } from "react";
167
+ import { useStdout } from "ink";
168
+ var DEFAULT_COLUMNS = 80;
169
+ var DEFAULT_ROWS = 24;
170
+ function useTerminalDimensions() {
171
+ const { stdout } = useStdout();
172
+ const [dimensions, setDimensions] = useState(() => ({
173
+ columns: stdout.columns || DEFAULT_COLUMNS,
174
+ rows: stdout.rows || DEFAULT_ROWS
175
+ }));
176
+ useEffect(() => {
177
+ const handleResize = () => {
178
+ setDimensions({
179
+ columns: stdout.columns || DEFAULT_COLUMNS,
180
+ rows: stdout.rows || DEFAULT_ROWS
181
+ });
182
+ };
183
+ stdout.on("resize", handleResize);
184
+ return () => {
185
+ stdout.off("resize", handleResize);
186
+ };
187
+ }, [stdout]);
188
+ return dimensions;
189
+ }
190
+
191
+ // src/cli/components/hooks/use-measured-height.ts
192
+ init_esm_shims();
193
+ import { useRef, useState as useState2, useEffect as useEffect2 } from "react";
194
+ import { measureElement, useStdout as useStdout2 } from "ink";
195
+ function useMeasuredHeight() {
196
+ const ref = useRef(null);
197
+ const [measuredHeight, setMeasuredHeight] = useState2(0);
198
+ const { stdout } = useStdout2();
199
+ useEffect2(() => {
200
+ const measure = () => {
201
+ if (ref.current) {
202
+ const { height } = measureElement(ref.current);
203
+ setMeasuredHeight((prev) => prev !== height ? height : prev);
204
+ }
205
+ };
206
+ measure();
207
+ stdout.on("resize", measure);
208
+ return () => {
209
+ stdout.off("resize", measure);
210
+ };
211
+ }, [stdout]);
212
+ return { ref, measuredHeight };
213
+ }
214
+
215
+ // src/cli/components/wizard/step-build.tsx
216
+ import { jsx, jsxs } from "react/jsx-runtime";
217
+ var Footer = ({ validationError }) => {
218
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: validationError && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
219
+ /* @__PURE__ */ jsx(Text, { color: CLI_COLORS.WARNING, children: validationError }),
220
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press ESC to go back, or select a skill and press ENTER to continue." })
221
+ ] }) });
222
+ };
223
+ var LegendRow = () => {
224
+ return /* @__PURE__ */ jsxs(Box, { paddingLeft: 1, columnGap: 2, children: [
225
+ /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.PRIMARY, children: [
226
+ UI_SYMBOLS.SELECTED,
227
+ " active"
228
+ ] }),
229
+ /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.UNFOCUSED, children: [
230
+ UI_SYMBOLS.UNSELECTED,
231
+ " recommended"
232
+ ] }),
233
+ /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.WARNING, children: [
234
+ UI_SYMBOLS.DISCOURAGED,
235
+ " discouraged"
236
+ ] }),
237
+ /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.NEUTRAL, children: [
238
+ UI_SYMBOLS.DISABLED,
239
+ " disabled"
240
+ ] })
241
+ ] });
242
+ };
243
+ var StepBuild = ({
244
+ matrix,
245
+ domain: activeDomain,
246
+ selectedDomains,
247
+ selections,
248
+ allSelections,
249
+ showDescriptions,
250
+ expertMode,
251
+ parentDomainSelections,
252
+ installedSkillIds,
253
+ onToggle,
254
+ onToggleDescriptions,
255
+ onContinue,
256
+ onBack
257
+ }) => {
258
+ const [validationError, setValidationError] = useState3(void 0);
259
+ const { columns } = useTerminalDimensions();
260
+ const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();
261
+ const categories = useFrameworkFiltering({
262
+ domain: activeDomain,
263
+ allSelections,
264
+ matrix,
265
+ expertMode,
266
+ selections,
267
+ parentDomainSelections,
268
+ installedSkillIds
269
+ });
270
+ const availableHeight = gridHeight > 0 ? Math.max(SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS, gridHeight) : Infinity;
271
+ useInput((_input, key) => {
272
+ if (key.return) {
273
+ const validation = validateBuildStep(categories, selections);
274
+ if (validation.valid) {
275
+ setValidationError(void 0);
276
+ onContinue();
277
+ } else {
278
+ setValidationError(validation.message);
279
+ }
280
+ } else if (key.escape) {
281
+ setValidationError(void 0);
282
+ onBack();
283
+ }
284
+ });
285
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", flexGrow: 1, children: [
286
+ /* @__PURE__ */ jsxs(
287
+ Box,
288
+ {
289
+ columnGap: 2,
290
+ flexDirection: "row",
291
+ justifyContent: "space-between",
292
+ marginBottom: 1,
293
+ paddingRight: 1,
294
+ marginTop: -1,
295
+ borderTop: false,
296
+ borderRight: false,
297
+ borderLeft: false,
298
+ borderColor: CLI_COLORS.NEUTRAL,
299
+ borderStyle: "single",
300
+ children: [
301
+ /* @__PURE__ */ jsx(Box, { columnGap: 2, flexDirection: "row", children: selectedDomains.map((domain) => {
302
+ const isActive = domain === activeDomain;
303
+ return /* @__PURE__ */ jsxs(Text, { color: isActive ? CLI_COLORS.PRIMARY : void 0, children: [
304
+ isActive ? UI_SYMBOLS.CURRENT : UI_SYMBOLS.UNSELECTED,
305
+ " ",
306
+ getDomainDisplayName(domain)
307
+ ] }, domain);
308
+ }) }),
309
+ /* @__PURE__ */ jsx(LegendRow, {})
310
+ ]
311
+ }
312
+ ),
313
+ /* @__PURE__ */ jsxs(ViewTitle, { children: [
314
+ "Customize your ",
315
+ getDomainDisplayName(activeDomain),
316
+ " stack"
317
+ ] }),
318
+ /* @__PURE__ */ jsx(Box, { ref: gridRef, flexGrow: 1, children: /* @__PURE__ */ jsx(
319
+ CategoryGrid,
320
+ {
321
+ categories,
322
+ expertMode,
323
+ showDescriptions,
324
+ onToggle,
325
+ onToggleDescriptions,
326
+ availableHeight,
327
+ terminalWidth: columns
328
+ },
329
+ activeDomain
330
+ ) }),
331
+ /* @__PURE__ */ jsx(Footer, { validationError })
332
+ ] });
333
+ };
334
+
335
+ export {
336
+ validateBuildStep,
337
+ getSkillDisplayLabel,
338
+ StepBuild
339
+ };
340
+ //# sourceMappingURL=chunk-OMV7TLWD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/step-build.tsx","../src/cli/lib/wizard/index.ts","../src/cli/lib/wizard/build-step-logic.ts","../src/cli/components/hooks/use-framework-filtering.ts","../src/cli/components/hooks/use-terminal-dimensions.ts","../src/cli/components/hooks/use-measured-height.ts"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n Subcategory,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { validateBuildStep } from \"../../lib/wizard/index.js\";\nimport { CLI_COLORS, SCROLL_VIEWPORT, UI_SYMBOLS } from \"../../consts.js\";\nimport { useFrameworkFiltering } from \"../hooks/use-framework-filtering.js\";\nimport { useTerminalDimensions } from \"../hooks/use-terminal-dimensions.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { CategoryGrid } from \"./category-grid.js\";\nimport { ViewTitle } from \"./view-title.js\";\nimport { getDomainDisplayName } from \"./utils.js\";\n\nexport type StepBuildProps = {\n matrix: MergedSkillsMatrix;\n domain: Domain;\n selectedDomains: Domain[];\n selections: SubcategorySelections;\n allSelections: SkillId[];\n showDescriptions: boolean;\n expertMode: boolean;\n /** For framework-first filtering on sub-domains (e.g., web-extras inherits from web) */\n parentDomainSelections?: SubcategorySelections;\n /** Skill IDs already installed on disk, shown with a dimmed checkmark */\n installedSkillIds?: SkillId[];\n onToggle: (subcategoryId: Subcategory, technologyId: SkillId) => void;\n onToggleDescriptions: () => void;\n onContinue: () => void;\n onBack: () => void;\n};\n\ntype FooterProps = {\n validationError?: string;\n};\n\nconst Footer: React.FC<FooterProps> = ({ validationError }) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {validationError && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color={CLI_COLORS.WARNING}>{validationError}</Text>\n <Text dimColor>Press ESC to go back, or select a skill and press ENTER to continue.</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nconst LegendRow: React.FC = () => {\n return (\n <Box paddingLeft={1} columnGap={2}>\n <Text color={CLI_COLORS.PRIMARY}>{UI_SYMBOLS.SELECTED} active</Text>\n <Text color={CLI_COLORS.UNFOCUSED}>{UI_SYMBOLS.UNSELECTED} recommended</Text>\n <Text color={CLI_COLORS.WARNING}>{UI_SYMBOLS.DISCOURAGED} discouraged</Text>\n <Text color={CLI_COLORS.NEUTRAL}>{UI_SYMBOLS.DISABLED} disabled</Text>\n </Box>\n );\n};\n\nexport const StepBuild: React.FC<StepBuildProps> = ({\n matrix,\n domain: activeDomain,\n selectedDomains,\n selections,\n allSelections,\n showDescriptions,\n expertMode,\n parentDomainSelections,\n installedSkillIds,\n onToggle,\n onToggleDescriptions,\n onContinue,\n onBack,\n}) => {\n const [validationError, setValidationError] = useState<string | undefined>(undefined);\n const { columns } = useTerminalDimensions();\n const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();\n\n const categories = useFrameworkFiltering({\n domain: activeDomain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n });\n\n const availableHeight =\n gridHeight > 0 ? Math.max(SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS, gridHeight) : Infinity;\n\n useInput((_input, key) => {\n if (key.return) {\n const validation = validateBuildStep(categories, selections);\n if (validation.valid) {\n setValidationError(undefined);\n onContinue();\n } else {\n setValidationError(validation.message);\n }\n } else if (key.escape) {\n setValidationError(undefined);\n onBack();\n }\n });\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" flexGrow={1}>\n <Box\n columnGap={2}\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginBottom={1}\n paddingRight={1}\n marginTop={-1}\n borderTop={false}\n borderRight={false}\n borderLeft={false}\n borderColor={CLI_COLORS.NEUTRAL}\n borderStyle=\"single\"\n >\n <Box columnGap={2} flexDirection=\"row\">\n {selectedDomains.map((domain) => {\n const isActive = domain === activeDomain;\n return (\n <Text key={domain} color={isActive ? CLI_COLORS.PRIMARY : undefined}>\n {isActive ? UI_SYMBOLS.CURRENT : UI_SYMBOLS.UNSELECTED}{\" \"}\n {getDomainDisplayName(domain)}\n </Text>\n );\n })}\n </Box>\n <LegendRow />\n </Box>\n <ViewTitle>Customize your {getDomainDisplayName(activeDomain)} stack</ViewTitle>\n\n <Box ref={gridRef} flexGrow={1}>\n <CategoryGrid\n key={activeDomain}\n categories={categories}\n expertMode={expertMode}\n showDescriptions={showDescriptions}\n onToggle={onToggle}\n onToggleDescriptions={onToggleDescriptions}\n availableHeight={availableHeight}\n terminalWidth={columns}\n />\n </Box>\n\n <Footer validationError={validationError} />\n </Box>\n );\n};\n","export {\n type BuildStepValidation,\n validateBuildStep,\n computeOptionState,\n getSkillDisplayLabel,\n buildCategoriesForDomain,\n} from \"./build-step-logic\";\n","import { sortBy } from \"remeda\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { getAvailableSkills, resolveAlias } from \"../matrix/index.js\";\nimport type {\n CategoryRow,\n CategoryOption,\n OptionState,\n} from \"../../components/wizard/category-grid.js\";\n\nconst FRAMEWORK_SUBCATEGORY_ID = \"framework\";\nconst WEB_DOMAIN_ID = \"web\";\n\nexport type BuildStepValidation = {\n valid: boolean;\n message?: string;\n};\n\nexport function validateBuildStep(\n categories: CategoryRow[],\n selections: SubcategorySelections,\n): BuildStepValidation {\n for (const category of categories) {\n if (category.required) {\n const categorySelections = selections[category.id] || [];\n if (categorySelections.length === 0) {\n return {\n valid: false,\n message: `Select at least one skill from the ${category.displayName} category. Use arrow keys to navigate, then SPACE to select.`,\n };\n }\n }\n }\n return { valid: true };\n}\n\nexport function computeOptionState(skill: {\n disabled: boolean;\n discouraged: boolean;\n recommended: boolean;\n}): OptionState {\n if (skill.disabled) {\n return \"disabled\";\n }\n if (skill.discouraged) {\n return \"discouraged\";\n }\n if (skill.recommended) {\n return \"recommended\";\n }\n return \"normal\";\n}\n\nexport function getSkillDisplayLabel(skill: { displayName?: string; id: string }): string {\n return skill.displayName || skill.id;\n}\n\nfunction getStateReason(skill: {\n disabled: boolean;\n disabledReason?: string;\n discouraged: boolean;\n discouragedReason?: string;\n recommended: boolean;\n recommendedReason?: string;\n}): string | undefined {\n if (skill.disabled && skill.disabledReason) {\n return skill.disabledReason;\n }\n if (skill.discouraged && skill.discouragedReason) {\n return skill.discouragedReason;\n }\n if (skill.recommended && skill.recommendedReason) {\n return skill.recommendedReason;\n }\n return undefined;\n}\n\nfunction isFrameworkSelected(selections: SubcategorySelections): boolean {\n const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];\n return frameworkSelections.length > 0;\n}\n\nfunction getSelectedFrameworks(\n selections: SubcategorySelections,\n matrix: MergedSkillsMatrix,\n): SkillId[] {\n const frameworkSelections = selections[FRAMEWORK_SUBCATEGORY_ID] ?? [];\n return frameworkSelections.map((alias) => resolveAlias(alias, matrix));\n}\n\nfunction isCompatibleWithSelectedFrameworks(\n skillId: SkillId,\n selectedFrameworkIds: SkillId[],\n matrix: MergedSkillsMatrix,\n): boolean {\n const skill = matrix.skills[skillId];\n if (!skill) return false;\n\n // No compatibleWith = compatible with all (allows legacy skills to appear)\n if (skill.compatibleWith.length === 0) {\n return true;\n }\n\n return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));\n}\n\n// Build CategoryRow[] from matrix for a domain, with framework-first filtering for web\nexport function buildCategoriesForDomain(\n domain: Domain,\n allSelections: SkillId[],\n matrix: MergedSkillsMatrix,\n expertMode: boolean,\n selections: SubcategorySelections,\n parentDomainSelections?: SubcategorySelections,\n installedSkillIds?: SkillId[],\n): CategoryRow[] {\n const frameworkSource = parentDomainSelections ?? selections;\n const frameworkSelected = isFrameworkSelected(frameworkSource);\n const selectedFrameworkIds = frameworkSelected\n ? getSelectedFrameworks(frameworkSource, matrix)\n : [];\n\n const subcategories = sortBy(\n Object.values(matrix.categories).filter((cat) => cat.domain === domain),\n (cat) => cat.order ?? 0,\n );\n\n const categoryRows: CategoryRow[] = subcategories.map((cat) => {\n const skillOptions = getAvailableSkills(cat.id, allSelections, matrix, {\n expertMode,\n });\n\n const useFrameworkFilter =\n (domain === WEB_DOMAIN_ID || parentDomainSelections !== undefined) &&\n cat.id !== FRAMEWORK_SUBCATEGORY_ID &&\n frameworkSelected;\n const filteredSkillOptions = useFrameworkFilter\n ? skillOptions.filter((skill) =>\n isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds, matrix),\n )\n : skillOptions;\n\n const options: CategoryOption[] = filteredSkillOptions.map((skill) => ({\n id: skill.id,\n label: getSkillDisplayLabel(skill),\n state: computeOptionState(skill),\n stateReason: getStateReason(skill),\n selected: skill.selected,\n local: matrix.skills[skill.id]?.local,\n installed: installedSkillIds?.includes(skill.id) || false,\n }));\n\n return {\n id: cat.id,\n displayName: cat.displayName,\n required: cat.required ?? false,\n exclusive: cat.exclusive ?? true,\n options,\n };\n });\n\n return categoryRows.filter((row) => row.options.length > 0);\n}\n","import { useMemo } from \"react\";\nimport type {\n Domain,\n MergedSkillsMatrix,\n SkillId,\n SubcategorySelections,\n} from \"../../types/index.js\";\nimport { buildCategoriesForDomain } from \"../../lib/wizard/index.js\";\nimport type { CategoryRow } from \"../wizard/category-grid.js\";\n\ntype UseFrameworkFilteringOptions = {\n domain: Domain;\n allSelections: SkillId[];\n matrix: MergedSkillsMatrix;\n expertMode: boolean;\n selections: SubcategorySelections;\n parentDomainSelections?: SubcategorySelections;\n installedSkillIds?: SkillId[];\n};\n\nexport function useFrameworkFiltering({\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n}: UseFrameworkFilteringOptions): CategoryRow[] {\n return useMemo(\n () =>\n buildCategoriesForDomain(\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n ),\n [\n domain,\n allSelections,\n matrix,\n expertMode,\n selections,\n parentDomainSelections,\n installedSkillIds,\n ],\n );\n}\n","import { useState, useEffect } from \"react\";\nimport { useStdout } from \"ink\";\n\nconst DEFAULT_COLUMNS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport type TerminalDimensions = {\n /** Terminal width in columns */\n columns: number;\n /** Terminal height in rows */\n rows: number;\n};\n\n/**\n * Tracks terminal dimensions reactively. Re-renders on resize.\n *\n * Falls back to DEFAULT_COLUMNS x DEFAULT_ROWS when stdout is not a TTY\n * (e.g., piped output, CI environments, tests).\n */\nexport function useTerminalDimensions(): TerminalDimensions {\n const { stdout } = useStdout();\n\n const [dimensions, setDimensions] = useState<TerminalDimensions>(() => ({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n }));\n\n useEffect(() => {\n const handleResize = () => {\n setDimensions({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n });\n };\n\n stdout.on(\"resize\", handleResize);\n return () => {\n stdout.off(\"resize\", handleResize);\n };\n }, [stdout]);\n\n return dimensions;\n}\n","import { useRef, useState, useEffect } from \"react\";\nimport { type DOMElement, measureElement, useStdout } from \"ink\";\n\n/**\n * Measures the computed height of a Box element using Ink's Yoga layout engine.\n *\n * Returns a ref to attach to a Box with `flexGrow={1}` and the measured height.\n * The Box must be inside a parent chain with a constrained height (e.g., an\n * explicit `height` prop on an ancestor) so Yoga can compute the remaining space.\n *\n * Returns 0 before the first layout pass. Re-measures on terminal resize.\n */\nexport function useMeasuredHeight(): {\n ref: React.Ref<DOMElement>;\n measuredHeight: number;\n} {\n const ref = useRef<DOMElement>(null);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n const { stdout } = useStdout();\n\n useEffect(() => {\n const measure = () => {\n if (ref.current) {\n const { height } = measureElement(ref.current);\n setMeasuredHeight((prev) => (prev !== height ? height : prev));\n }\n };\n\n measure();\n\n stdout.on(\"resize\", measure);\n return () => {\n stdout.off(\"resize\", measure);\n };\n }, [stdout]);\n\n return { ref, measuredHeight };\n}\n"],"mappings":"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","names":["useState","useState","useEffect","useStdout","useState"]}
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ WIZARD_STEPS,
4
+ WizardTabs
5
+ } from "./chunk-IYG2LAIM.js";
6
+ import {
7
+ HelpModal
8
+ } from "./chunk-FZGYSLJL.js";
9
+ import {
10
+ useWizardStore
11
+ } from "./chunk-3ZOIOVKT.js";
12
+ import {
13
+ CLI_COLORS
14
+ } from "./chunk-LAPCUV4D.js";
15
+ import {
16
+ init_esm_shims
17
+ } from "./chunk-DHET7RCE.js";
18
+
19
+ // src/cli/components/wizard/wizard-layout.tsx
20
+ init_esm_shims();
21
+ import { Fragment } from "react";
22
+ import { Box, Text } from "ink";
23
+ import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
24
+ import { createElement } from "react";
25
+ var DefinitionItem = ({
26
+ isVisible = true,
27
+ isActive = false,
28
+ label,
29
+ values
30
+ }) => {
31
+ if (!isVisible) {
32
+ return null;
33
+ }
34
+ return /* @__PURE__ */ jsxs(Text, { children: [
35
+ values.map((value) => /* @__PURE__ */ jsxs(Fragment, { children: [
36
+ /* @__PURE__ */ jsxs(Text, { backgroundColor: "black", color: CLI_COLORS.UNFOCUSED, children: [
37
+ " ",
38
+ value,
39
+ " "
40
+ ] }),
41
+ " "
42
+ ] }, value)),
43
+ /* @__PURE__ */ jsx(Text, { color: isActive ? CLI_COLORS.PRIMARY : void 0, children: label })
44
+ ] });
45
+ };
46
+ var HOT_KEYS = [
47
+ { label: "navigate", values: ["\u2190/\u2192", "\u2191/\u2193"] },
48
+ { label: "select", values: ["SPACE"] },
49
+ { label: "continue", values: ["ENTER"] },
50
+ { label: "back", values: ["ESC"] }
51
+ ];
52
+ var WizardFooter = () => {
53
+ const store = useWizardStore();
54
+ return /* @__PURE__ */ jsxs(
55
+ Box,
56
+ {
57
+ columnGap: 2,
58
+ borderTop: true,
59
+ borderRight: false,
60
+ borderBottom: true,
61
+ borderLeft: false,
62
+ borderColor: "blackBright",
63
+ borderStyle: "single",
64
+ paddingLeft: 1,
65
+ paddingRight: 1,
66
+ children: [
67
+ /* @__PURE__ */ jsx(
68
+ DefinitionItem,
69
+ {
70
+ label: "Accept defaults",
71
+ values: ["A"],
72
+ isVisible: store.step === "build" && !!store.selectedStackId
73
+ }
74
+ ),
75
+ HOT_KEYS.map((hotkey) => /* @__PURE__ */ createElement(DefinitionItem, { ...hotkey, key: hotkey.label }))
76
+ ]
77
+ }
78
+ );
79
+ };
80
+ var WizardLayout = ({
81
+ version,
82
+ marketplaceLabel,
83
+ brandingName,
84
+ terminalHeight,
85
+ children
86
+ }) => {
87
+ const store = useWizardStore();
88
+ const { completedSteps, skippedSteps } = store.getStepProgress();
89
+ const constrainedHeight = store.step === "build" ? terminalHeight : void 0;
90
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, height: constrainedHeight, children: [
91
+ /* @__PURE__ */ jsx(
92
+ WizardTabs,
93
+ {
94
+ steps: WIZARD_STEPS,
95
+ currentStep: store.step,
96
+ completedSteps,
97
+ skippedSteps,
98
+ version,
99
+ brandingName
100
+ }
101
+ ),
102
+ marketplaceLabel && /* @__PURE__ */ jsxs(Box, { paddingLeft: 1, marginTop: 1, children: [
103
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Marketplace: " }),
104
+ /* @__PURE__ */ jsx(Text, { bold: true, children: marketplaceLabel })
105
+ ] }),
106
+ store.showHelp ? /* @__PURE__ */ jsx(HelpModal, { currentStep: store.step }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
107
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1, marginTop: 1, children }),
108
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, columnGap: 2, marginTop: 2, children: [
109
+ /* @__PURE__ */ jsx(DefinitionItem, { label: "Expert mode", values: ["E"], isActive: store.expertMode }),
110
+ /* @__PURE__ */ jsx(
111
+ DefinitionItem,
112
+ {
113
+ label: "Descriptions",
114
+ values: ["D"],
115
+ isVisible: store.step === "build",
116
+ isActive: store.showDescriptions
117
+ }
118
+ ),
119
+ /* @__PURE__ */ jsx(
120
+ DefinitionItem,
121
+ {
122
+ label: "Plugin mode",
123
+ values: ["P"],
124
+ isActive: store.installMode === "plugin"
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx(
128
+ DefinitionItem,
129
+ {
130
+ label: "Settings",
131
+ values: ["G"],
132
+ isVisible: store.step === "sources",
133
+ isActive: store.showSettings
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(DefinitionItem, { label: "Help", values: ["?"] })
137
+ ] }),
138
+ /* @__PURE__ */ jsx(WizardFooter, {})
139
+ ] })
140
+ ] });
141
+ };
142
+
143
+ export {
144
+ WizardLayout
145
+ };
146
+ //# sourceMappingURL=chunk-PBEHPQLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/wizard-layout.tsx"],"sourcesContent":["import React, { Fragment } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { WizardTabs, WIZARD_STEPS } from \"./wizard-tabs.js\";\nimport { HelpModal } from \"./help-modal.js\";\n\ntype KeyHintProps = {\n isVisible?: boolean;\n isActive?: boolean;\n label: string;\n values: string[];\n};\n\nconst DefinitionItem: React.FC<KeyHintProps> = ({\n isVisible = true,\n isActive = false,\n label,\n values,\n}) => {\n if (!isVisible) {\n return null;\n }\n\n return (\n <Text>\n {values.map((value) => (\n <Fragment key={value}>\n <Text backgroundColor=\"black\" color={CLI_COLORS.UNFOCUSED}>\n {\" \"}\n {value}{\" \"}\n </Text>{\" \"}\n </Fragment>\n ))}\n <Text color={isActive ? CLI_COLORS.PRIMARY : undefined}>{label}</Text>\n </Text>\n );\n};\n\nconst HOT_KEYS: { label: string; values: string[] }[] = [\n { label: \"navigate\", values: [\"\\u2190/\\u2192\", \"\\u2191/\\u2193\"] },\n { label: \"select\", values: [\"SPACE\"] },\n { label: \"continue\", values: [\"ENTER\"] },\n { label: \"back\", values: [\"ESC\"] },\n];\n\nconst WizardFooter = () => {\n const store = useWizardStore();\n\n return (\n <Box\n columnGap={2}\n borderTop\n borderRight={false}\n borderBottom\n borderLeft={false}\n borderColor=\"blackBright\"\n borderStyle=\"single\"\n paddingLeft={1}\n paddingRight={1}\n >\n <DefinitionItem\n label=\"Accept defaults\"\n values={[\"A\"]}\n isVisible={store.step === \"build\" && !!store.selectedStackId}\n />\n {HOT_KEYS.map((hotkey) => (\n <DefinitionItem {...hotkey} key={hotkey.label} />\n ))}\n </Box>\n );\n};\n\ntype WizardLayoutProps = {\n version?: string;\n marketplaceLabel?: string;\n brandingName?: string;\n /** Terminal height in rows, used to constrain the layout for flexGrow measurement */\n terminalHeight: number;\n children: React.ReactNode;\n};\n\nexport const WizardLayout: React.FC<WizardLayoutProps> = ({\n version,\n marketplaceLabel,\n brandingName,\n terminalHeight,\n children,\n}) => {\n const store = useWizardStore();\n const { completedSteps, skippedSteps } = store.getStepProgress();\n\n // Constrain height only during the build step so flexGrow-based measurement\n // can determine the grid area. Other steps grow to fit their content.\n const constrainedHeight = store.step === \"build\" ? terminalHeight : undefined;\n\n return (\n <Box flexDirection=\"column\" paddingX={1} height={constrainedHeight}>\n <WizardTabs\n steps={WIZARD_STEPS}\n currentStep={store.step}\n completedSteps={completedSteps}\n skippedSteps={skippedSteps}\n version={version}\n brandingName={brandingName}\n />\n {marketplaceLabel && (\n <Box paddingLeft={1} marginTop={1}>\n <Text dimColor>Marketplace: </Text>\n <Text bold>{marketplaceLabel}</Text>\n </Box>\n )}\n {store.showHelp ? (\n <HelpModal currentStep={store.step} />\n ) : (\n <>\n <Box flexGrow={1} marginTop={1}>\n {children}\n </Box>\n <Box paddingX={1} columnGap={2} marginTop={2}>\n <DefinitionItem label=\"Expert mode\" values={[\"E\"]} isActive={store.expertMode} />\n <DefinitionItem\n label=\"Descriptions\"\n values={[\"D\"]}\n isVisible={store.step === \"build\"}\n isActive={store.showDescriptions}\n />\n <DefinitionItem\n label=\"Plugin mode\"\n values={[\"P\"]}\n isActive={store.installMode === \"plugin\"}\n />\n <DefinitionItem\n label=\"Settings\"\n values={[\"G\"]}\n isVisible={store.step === \"sources\"}\n isActive={store.showSettings}\n />\n <DefinitionItem label=\"Help\" values={[\"?\"]} />\n </Box>\n <WizardFooter />\n </>\n )}\n </Box>\n );\n};\n"],"mappings":"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","names":["Fragment"]}
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CLI_COLORS,
4
+ UI_SYMBOLS
5
+ } from "./chunk-LAPCUV4D.js";
6
+ import {
7
+ init_esm_shims
8
+ } from "./chunk-DHET7RCE.js";
9
+
10
+ // src/cli/components/wizard/menu-item.tsx
11
+ init_esm_shims();
12
+ import { Box, Text } from "ink";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ var { CHEVRON, CHEVRON_SPACER } = UI_SYMBOLS;
15
+ var MenuItem = ({
16
+ label,
17
+ description,
18
+ isFocused = false,
19
+ isActive = false
20
+ }) => {
21
+ const showCyan = isFocused || isActive;
22
+ return /* @__PURE__ */ jsxs(Box, { columnGap: 1, children: [
23
+ /* @__PURE__ */ jsx(Text, { color: isFocused ? CLI_COLORS.PRIMARY : void 0, children: isFocused ? CHEVRON : CHEVRON_SPACER }),
24
+ /* @__PURE__ */ jsx(Text, { bold: isFocused, color: showCyan ? CLI_COLORS.PRIMARY : void 0, children: label }),
25
+ isFocused && description && /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${description}` })
26
+ ] });
27
+ };
28
+
29
+ export {
30
+ MenuItem
31
+ };
32
+ //# sourceMappingURL=chunk-QPTOIZAT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/components/wizard/menu-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\n\nconst { CHEVRON, CHEVRON_SPACER } = UI_SYMBOLS;\n\ntype MenuItemProps = {\n label: string;\n description?: string;\n isFocused?: boolean;\n isActive?: boolean;\n};\n\nexport const MenuItem: React.FC<MenuItemProps> = ({\n label,\n description,\n isFocused = false,\n isActive = false,\n}) => {\n const showCyan = isFocused || isActive;\n\n return (\n <Box columnGap={1}>\n <Text color={isFocused ? CLI_COLORS.PRIMARY : undefined}>\n {isFocused ? CHEVRON : CHEVRON_SPACER}\n </Text>\n <Text bold={isFocused} color={showCyan ? CLI_COLORS.PRIMARY : undefined}>\n {label}\n </Text>\n {isFocused && description && <Text dimColor>{` ${description}`}</Text>}\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAqBtB,SACE,KADF;AAlBJ,IAAM,EAAE,SAAS,eAAe,IAAI;AAS7B,IAAM,WAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,WAAW;AACb,MAAM;AACJ,QAAM,WAAW,aAAa;AAE9B,SACE,qBAAC,OAAI,WAAW,GACd;AAAA,wBAAC,QAAK,OAAO,YAAY,WAAW,UAAU,QAC3C,sBAAY,UAAU,gBACzB;AAAA,IACA,oBAAC,QAAK,MAAM,WAAW,OAAO,WAAW,WAAW,UAAU,QAC3D,iBACH;AAAA,IACC,aAAa,eAAe,oBAAC,QAAK,UAAQ,MAAE,cAAI,WAAW,IAAG;AAAA,KACjE;AAEJ;","names":[]}