@astryxdesign/cli 0.6.4 → 0.6.5-canary.01972bc

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 (405) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +103 -95
  3. package/api/build/_adapter.d.mts +36 -2
  4. package/api/build/_adapter.mjs +41 -10
  5. package/api/build/build.doc.mjs +8 -3
  6. package/api/build/build.test.mjs +60 -2
  7. package/api/build/kit/kit.mjs +109 -26
  8. package/api/build/kit/rank.d.mts +24 -8
  9. package/api/build/kit/rank.mjs +277 -97
  10. package/api/build/kit/rank.test.mjs +231 -48
  11. package/api/component/_adapter.d.mts +25 -0
  12. package/api/component/_adapter.mjs +59 -5
  13. package/api/component/component.d.mts +6 -3
  14. package/api/component/component.doc.mjs +37 -17
  15. package/api/component/component.mjs +249 -9
  16. package/api/component/component.type.d.mts +25 -0
  17. package/api/component/component.type.mjs +44 -0
  18. package/api/discover/_adapter.d.mts +114 -6
  19. package/api/discover/_adapter.mjs +372 -17
  20. package/api/discover/_adapter.test.mjs +215 -0
  21. package/api/discover/_catalog-view.d.mts +115 -0
  22. package/api/discover/_catalog-view.mjs +203 -0
  23. package/api/discover/_catalog-view.test.mjs +128 -0
  24. package/api/discover/detail/detail.d.mts +18 -6
  25. package/api/discover/detail/detail.mjs +67 -13
  26. package/api/discover/detail/detail.test.mjs +85 -0
  27. package/api/discover/detail/item/item.d.mts +26 -0
  28. package/api/discover/detail/item/item.mjs +78 -0
  29. package/api/discover/detail/item/item.test.mjs +73 -0
  30. package/api/discover/discover.d.mts +3 -9
  31. package/api/discover/discover.doc.mjs +61 -18
  32. package/api/discover/discover.mjs +220 -36
  33. package/api/discover/discover.test.mjs +11 -2
  34. package/api/discover/discover.type.d.mts +147 -8
  35. package/api/discover/discover.type.mjs +102 -12
  36. package/api/discover/list/list.d.mts +20 -6
  37. package/api/discover/list/list.mjs +45 -12
  38. package/api/discover/list/list.test.mjs +46 -0
  39. package/api/discover/search/search.d.mts +18 -16
  40. package/api/discover/search/search.mjs +102 -56
  41. package/api/discover/search/search.test.mjs +144 -10
  42. package/api/docs/_adapter.d.mts +8 -3
  43. package/api/docs/_adapter.mjs +14 -6
  44. package/api/docs/docOverlays.test.mjs +27 -1
  45. package/api/docs/docs.doc.mjs +2 -2
  46. package/api/docs/docs.test.mjs +54 -18
  47. package/api/docs/integration-tree.test.mjs +17 -0
  48. package/api/docs/integrationDocs.test.mjs +27 -5
  49. package/api/doctor/doctor.d.mts +8 -3
  50. package/api/doctor/doctor.doc.mjs +17 -8
  51. package/api/doctor/doctor.mjs +90 -9
  52. package/api/doctor/doctor.test.mjs +122 -10
  53. package/api/doctor/doctor.type.d.mts +1 -1
  54. package/api/doctor/doctor.type.mjs +1 -1
  55. package/api/error.d.mts +22 -0
  56. package/api/error.mjs +42 -0
  57. package/api/gap-report/gap-report.doc.mjs +19 -10
  58. package/api/hook/hook.doc.mjs +6 -3
  59. package/api/index.d.mts +1 -0
  60. package/api/index.mjs +5 -3
  61. package/api/init/init.doc.mjs +17 -12
  62. package/api/integration/add-contribution.d.mts +2 -1
  63. package/api/integration/add-contribution.mjs +7 -3
  64. package/api/integration/add-contribution.test.mjs +3 -3
  65. package/api/integration/add-helpers.d.mts +5 -2
  66. package/api/integration/add-helpers.mjs +36 -9
  67. package/api/integration/add-theme.mjs +266 -23
  68. package/api/integration/add-theme.test.mjs +247 -0
  69. package/api/integration/authoring-checks.mjs +12 -9
  70. package/api/integration/authoring-checks.type.d.mts +8 -0
  71. package/api/integration/authoring-checks.type.mjs +7 -3
  72. package/api/integration/integration-authoring.type.d.mts +4 -1
  73. package/api/integration/integration-authoring.type.mjs +6 -1
  74. package/api/integration/integrationAdd.doc.mjs +6 -0
  75. package/api/integration/integrationAddTheme.doc.mjs +10 -0
  76. package/api/integration/integrationComponentConflicts.doc.mjs +1 -1
  77. package/api/integration/integrationDocConflicts.doc.mjs +1 -1
  78. package/api/integration/integrationPackCheck.doc.mjs +3 -3
  79. package/api/integration/integrationTemplateConflicts.doc.mjs +1 -1
  80. package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
  81. package/api/integration/pack-check.mjs +92 -10
  82. package/api/integration/pack-check.test.mjs +140 -1
  83. package/api/integration/pack-check.type.mjs +1 -1
  84. package/api/integration/validate-integration.d.mts +4 -2
  85. package/api/integration/validate-integration.mjs +7 -2
  86. package/api/integration/validate-integration.test.mjs +55 -0
  87. package/api/integration/validate-integration.type.d.mts +5 -0
  88. package/api/integration/validate-integration.type.mjs +5 -1
  89. package/api/integration/validateIntegration.doc.mjs +1 -1
  90. package/api/json/assertResponse.doc.mjs +1 -1
  91. package/api/json/isError.doc.mjs +1 -1
  92. package/api/layout/expand/expand.mjs +12 -7
  93. package/api/layout/expand/expand.receipt.test.mjs +74 -0
  94. package/api/layout/layout.type.d.mts +1 -0
  95. package/api/layout/layout.type.mjs +1 -0
  96. package/api/layout/layoutExpand.doc.mjs +1 -1
  97. package/api/search/search.d.mts +51 -1
  98. package/api/search/search.doc.mjs +2 -2
  99. package/api/search/search.mjs +299 -17
  100. package/api/search/search.test.mjs +216 -18
  101. package/api/swizzle/copy/copy.mjs +66 -3
  102. package/api/swizzle/swizzle.doc.mjs +11 -5
  103. package/api/template/copy/copy.mjs +15 -9
  104. package/api/template/copy/copy.receipt.test.mjs +77 -0
  105. package/api/template/copy/copy.test.mjs +9 -0
  106. package/api/template/show/show.mjs +15 -4
  107. package/api/template/show/show.test.mjs +76 -0
  108. package/api/template/template-integration.test.mjs +14 -0
  109. package/api/template/template.d.mts +1 -1
  110. package/api/template/template.doc.mjs +8 -3
  111. package/api/template/template.mjs +1 -0
  112. package/api/template/template.type.d.mts +2 -0
  113. package/api/template/template.type.mjs +2 -0
  114. package/api/theme/add/add.mjs +17 -25
  115. package/api/theme/add/add.rollback.test.mjs +158 -0
  116. package/api/theme/add/add.staging.test.mjs +40 -23
  117. package/api/theme/build/build.d.mts +24 -0
  118. package/api/theme/build/build.family.test.mjs +7 -12
  119. package/api/theme/build/build.mjs +243 -26
  120. package/api/theme/build/build.project-core.test.mjs +165 -0
  121. package/api/theme/build/build.rollback.test.mjs +148 -0
  122. package/api/theme/generateTonalPalette.doc.mjs +1 -2
  123. package/api/theme/listThemes.doc.mjs +1 -1
  124. package/api/theme/themeAdd.doc.mjs +9 -10
  125. package/api/theme/themeBuild.doc.mjs +13 -13
  126. package/api/theme/themeList.doc.mjs +1 -1
  127. package/api/theme/themeListAvailable.doc.mjs +2 -1
  128. package/api/theme/themePaletteGenerate.doc.mjs +15 -8
  129. package/api/theme/themeTargets.doc.mjs +3 -2
  130. package/api/theme/themeTemplate.doc.mjs +2 -1
  131. package/api/upgrade/run/files-changed.test.mjs +111 -0
  132. package/api/upgrade/run/run.mjs +25 -6
  133. package/api/upgrade/run/run.test.mjs +45 -1
  134. package/api/upgrade/upgrade.doc.mjs +24 -22
  135. package/api/upgrade/upgrade.type.d.mts +1 -0
  136. package/api/upgrade/upgrade.type.mjs +3 -2
  137. package/assets/codemods/__tests__/runner.test.mjs +3 -1
  138. package/assets/codemods/file-count.test.mjs +163 -0
  139. package/assets/codemods/integration-runner.mjs +3 -3
  140. package/assets/codemods/runner.mjs +5 -4
  141. package/assets/docs/README.md +4 -2
  142. package/assets/docs/browser-support.doc.mjs +11 -11
  143. package/assets/docs/color.doc.mjs +8 -2
  144. package/assets/docs/elevation.doc.mjs +6 -4
  145. package/assets/docs/getting-started.doc.mjs +5 -16
  146. package/assets/docs/icons.doc.mjs +3 -21
  147. package/assets/docs/illustrations.doc.mjs +7 -15
  148. package/assets/docs/internationalization.doc.mjs +7 -5
  149. package/assets/docs/layout.doc.dense.mjs +130 -82
  150. package/assets/docs/layout.doc.mjs +133 -77
  151. package/assets/docs/migration.doc.mjs +19 -21
  152. package/assets/docs/motion.doc.mjs +16 -3
  153. package/assets/docs/principles.doc.dense.mjs +5 -5
  154. package/assets/docs/principles.doc.mjs +8 -0
  155. package/assets/docs/principles.doc.zh.mjs +6 -6
  156. package/assets/docs/shape.doc.mjs +8 -3
  157. package/assets/docs/spacing.doc.mjs +7 -2
  158. package/assets/docs/styling-libraries.doc.mjs +6 -2
  159. package/assets/docs/styling.doc.mjs +19 -23
  160. package/assets/docs/theme.doc.dense.mjs +58 -18
  161. package/assets/docs/theme.doc.mjs +57 -47
  162. package/assets/docs/theme.doc.zh.mjs +9 -8
  163. package/assets/docs/tokens.doc.dense.mjs +2 -2
  164. package/assets/docs/tokens.doc.mjs +389 -8
  165. package/assets/docs/tokens.doc.zh.mjs +2 -2
  166. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  167. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  168. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  169. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  170. package/assets/docs/tree/block-template.doc.mjs +130 -0
  171. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  172. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  173. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  174. package/assets/docs/tree/checks.doc.mjs +119 -0
  175. package/assets/docs/tree/codemods.doc.mjs +147 -0
  176. package/assets/docs/tree/component-family.doc.mjs +113 -0
  177. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  178. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  179. package/assets/docs/tree/components.doc.mjs +23 -0
  180. package/assets/docs/tree/configuration.doc.mjs +23 -0
  181. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  182. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  183. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  184. package/assets/docs/tree/docs.doc.mjs +21 -0
  185. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  186. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  187. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  188. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  189. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  190. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  191. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  192. package/assets/docs/tree/help.doc.mjs +16 -0
  193. package/assets/docs/tree/integrations.doc.mjs +25 -451
  194. package/assets/docs/tree/links.doc.mjs +98 -0
  195. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  196. package/assets/docs/tree/page-template.doc.mjs +71 -0
  197. package/assets/docs/tree/publishing.doc.mjs +111 -0
  198. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  199. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  200. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  201. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  202. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  203. package/assets/docs/tree/ship.doc.mjs +16 -0
  204. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  205. package/assets/docs/tree/single-component.doc.mjs +165 -0
  206. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  207. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  208. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  209. package/assets/docs/tree/template-doc-overview.doc.mjs +121 -0
  210. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  211. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  212. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  213. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  214. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  215. package/assets/docs/tree/templates.doc.mjs +34 -0
  216. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  217. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  218. package/assets/docs/tree/themes.doc.mjs +39 -0
  219. package/assets/docs/tree/troubleshooting.doc.mjs +153 -0
  220. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  221. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  222. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  223. package/assets/docs/tree/versioning.doc.mjs +162 -0
  224. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  225. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  226. package/assets/docs/typography.doc.mjs +24 -4
  227. package/assets/docs/working-with-ai.doc.mjs +30 -22
  228. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  229. package/assets/templates/pages/ai-chat/template.doc.mjs +16 -1
  230. package/assets/templates/pages/ai-chat-landing/template.doc.mjs +9 -1
  231. package/assets/templates/pages/blank/template.doc.mjs +3 -1
  232. package/assets/templates/pages/canvas-editor/template.doc.mjs +9 -1
  233. package/assets/templates/pages/centered-hero/template.doc.mjs +3 -1
  234. package/assets/templates/pages/checkout-wizard/template.doc.mjs +1 -0
  235. package/assets/templates/pages/classic-gallery/template.doc.mjs +3 -1
  236. package/assets/templates/pages/contact-form/template.doc.mjs +16 -1
  237. package/assets/templates/pages/dashboard/template.doc.mjs +15 -1
  238. package/assets/templates/pages/dashboard-alert-rail/template.doc.mjs +23 -1
  239. package/assets/templates/pages/dashboard-cohort-funnel/template.doc.mjs +10 -1
  240. package/assets/templates/pages/dashboard-comparison/template.doc.mjs +9 -1
  241. package/assets/templates/pages/dashboard-composition/template.doc.mjs +10 -1
  242. package/assets/templates/pages/dashboard-progress/template.doc.mjs +17 -1
  243. package/assets/templates/pages/dashboard-scorecard/template.doc.mjs +2 -1
  244. package/assets/templates/pages/detail-page/template.doc.mjs +8 -0
  245. package/assets/templates/pages/documentation/template.doc.mjs +10 -1
  246. package/assets/templates/pages/documentation-design/template.doc.mjs +10 -1
  247. package/assets/templates/pages/documentation-technical/template.doc.mjs +10 -1
  248. package/assets/templates/pages/editor/template.doc.mjs +9 -1
  249. package/assets/templates/pages/file-explorer/template.doc.mjs +3 -1
  250. package/assets/templates/pages/form-two-column/template.doc.mjs +17 -1
  251. package/assets/templates/pages/form-wizard/template.doc.mjs +14 -1
  252. package/assets/templates/pages/form-wizard-dialog/template.doc.mjs +1 -0
  253. package/assets/templates/pages/gallery-hero/template.doc.mjs +10 -1
  254. package/assets/templates/pages/ide/template.doc.mjs +9 -1
  255. package/assets/templates/pages/incident-console/template.doc.mjs +10 -1
  256. package/assets/templates/pages/kanban-board/template.doc.mjs +11 -1
  257. package/assets/templates/pages/library/template.doc.mjs +15 -1
  258. package/assets/templates/pages/login/template.doc.mjs +10 -1
  259. package/assets/templates/pages/login-card/template.doc.mjs +11 -1
  260. package/assets/templates/pages/login-split/template.doc.mjs +10 -1
  261. package/assets/templates/pages/login-sso/template.doc.mjs +10 -1
  262. package/assets/templates/pages/messaging-shell/template.doc.mjs +11 -1
  263. package/assets/templates/pages/mixed-gallery/template.doc.mjs +10 -1
  264. package/assets/templates/pages/payment-form/template.doc.mjs +3 -1
  265. package/assets/templates/pages/product-detail/template.doc.mjs +9 -1
  266. package/assets/templates/pages/product-gallery/template.doc.mjs +10 -1
  267. package/assets/templates/pages/settings/template.doc.mjs +3 -1
  268. package/assets/templates/pages/settings-dialog/template.doc.mjs +9 -1
  269. package/assets/templates/pages/settings-sidebar/template.doc.mjs +9 -1
  270. package/assets/templates/pages/shell-nav/template.doc.mjs +10 -1
  271. package/assets/templates/pages/shell-side-nav/template.doc.mjs +14 -1
  272. package/assets/templates/pages/shell-top-nav/template.doc.mjs +11 -1
  273. package/assets/templates/pages/side-gallery/template.doc.mjs +3 -1
  274. package/assets/templates/pages/table/template.doc.mjs +11 -1
  275. package/assets/templates/pages/table-filter/template.doc.mjs +21 -1
  276. package/assets/templates/pages/table-grouped/template.doc.mjs +15 -1
  277. package/assets/templates/pages/table-inbox/template.doc.mjs +18 -6
  278. package/assets/templates/pages/table-page/template.doc.mjs +20 -1
  279. package/assets/templates/pages/table-tree/template.doc.mjs +14 -1
  280. package/assets/templates/pages/theme-showcase/template.doc.mjs +10 -1
  281. package/assets/templates/pages/work-item-detail/template.doc.mjs +10 -0
  282. package/assets/templates/themes/butter/icons.tsx +2 -0
  283. package/assets/templates/themes/chocolate/icons.tsx +2 -0
  284. package/assets/templates/themes/gothic/icons.tsx +2 -0
  285. package/assets/templates/themes/matcha/icons.tsx +2 -0
  286. package/assets/templates/themes/neutral/icons.tsx +2 -0
  287. package/assets/templates/themes/stone/icons.tsx +2 -0
  288. package/assets/templates/themes/y2k/icons.tsx +2 -0
  289. package/authoring/config/config.doc.mjs +9 -1
  290. package/authoring/config/parse.d.mts +2 -0
  291. package/authoring/config/parse.mjs +19 -0
  292. package/authoring/config/parse.test.mjs +8 -0
  293. package/authoring/config/type.ts +11 -0
  294. package/authoring/discover/discover.doc.d.mts +13 -0
  295. package/authoring/discover/discover.doc.mjs +138 -0
  296. package/authoring/discover/parse.d.mts +24 -0
  297. package/authoring/discover/parse.mjs +128 -0
  298. package/authoring/discover/parse.test.mjs +124 -0
  299. package/authoring/discover/type.ts +87 -0
  300. package/authoring/doctypes/_schema.d.mts +3 -2
  301. package/authoring/doctypes/_schema.mjs +6 -0
  302. package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
  303. package/authoring/doctypes/base/type.ts +4 -2
  304. package/authoring/doctypes/component/component.doc.mjs +6 -0
  305. package/authoring/doctypes/component/type.ts +8 -0
  306. package/authoring/doctypes/reference/reference.doc.mjs +7 -0
  307. package/authoring/doctypes/reference/type.ts +5 -0
  308. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  309. package/authoring/doctypes/template/parse.d.mts +2 -0
  310. package/authoring/doctypes/template/parse.mjs +1 -0
  311. package/authoring/doctypes/template/parse.test.mjs +21 -0
  312. package/authoring/doctypes/template/template.doc.mjs +7 -1
  313. package/authoring/doctypes/template/type.ts +12 -2
  314. package/authoring/index.d.mts +1 -0
  315. package/authoring/index.d.ts +10 -0
  316. package/authoring/index.mjs +1 -0
  317. package/authoring/integration/integration.doc.mjs +12 -10
  318. package/clients/cli/commands/component/index.mjs +152 -55
  319. package/clients/cli/commands/component-batch.test.mjs +341 -0
  320. package/clients/cli/commands/component-ownership.test.mjs +89 -0
  321. package/clients/cli/commands/component.doc.mjs +27 -9
  322. package/clients/cli/commands/discover.doc.mjs +53 -9
  323. package/clients/cli/commands/discover.mjs +393 -118
  324. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  325. package/clients/cli/commands/docs.doc.mjs +1 -1
  326. package/clients/cli/commands/docs.mjs +60 -17
  327. package/clients/cli/commands/docs.test.mjs +113 -24
  328. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -2
  329. package/clients/cli/commands/doctor-integration.test.mjs +53 -0
  330. package/clients/cli/commands/doctor.doc.mjs +3 -1
  331. package/clients/cli/commands/doctor.mjs +53 -9
  332. package/clients/cli/commands/gap-report.doc.mjs +10 -9
  333. package/clients/cli/commands/init.doc.mjs +9 -6
  334. package/clients/cli/commands/integration-add.doc.mjs +17 -7
  335. package/clients/cli/commands/integration-authoring.test.mjs +70 -9
  336. package/clients/cli/commands/integration-pack.doc.mjs +5 -9
  337. package/clients/cli/commands/integration-real-world.test.mjs +1 -1
  338. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  339. package/clients/cli/commands/integration.doc.mjs +4 -4
  340. package/clients/cli/commands/integration.mjs +76 -43
  341. package/clients/cli/commands/layout-expand.doc.mjs +3 -1
  342. package/clients/cli/commands/layout.expand-receipt.test.mjs +94 -0
  343. package/clients/cli/commands/layout.mjs +16 -0
  344. package/clients/cli/commands/manifest.doc.mjs +1 -1
  345. package/clients/cli/commands/search.doc.mjs +10 -3
  346. package/clients/cli/commands/search.mjs +21 -2
  347. package/clients/cli/commands/search.test.mjs +21 -4
  348. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  349. package/clients/cli/commands/template.copy-receipt.test.mjs +60 -0
  350. package/clients/cli/commands/template.doc.mjs +1 -1
  351. package/clients/cli/commands/template.mjs +19 -5
  352. package/clients/cli/commands/template.show-media.test.mjs +62 -0
  353. package/clients/cli/commands/text-json-parity.test.mjs +7 -1
  354. package/clients/cli/commands/theme-add.doc.mjs +1 -1
  355. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -2
  356. package/clients/cli/commands/theme-palette.doc.mjs +1 -2
  357. package/clients/cli/commands/theme-targets.doc.mjs +2 -2
  358. package/clients/cli/commands/theme.doc.mjs +2 -1
  359. package/clients/cli/commands/upgrade.ascii-output.test.mjs +14 -0
  360. package/clients/cli/commands/upgrade.doc.mjs +62 -3
  361. package/clients/cli/commands/write-failure.test.mjs +175 -0
  362. package/clients/cli/index.mjs +28 -6
  363. package/clients/cli/lib/define-command.mjs +28 -4
  364. package/clients/cli/lib/define-command.test.mjs +54 -0
  365. package/clients/cli/lib/exit-codes.test.mjs +17 -1
  366. package/clients/cli/lib/json-shim.mjs +24 -14
  367. package/clients/cli/lib/manifest.mjs +48 -156
  368. package/clients/cli/lib/manifest.test.mjs +103 -9
  369. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  370. package/foundation/agent-docs/agent-docs.mjs +1 -1
  371. package/foundation/agent-docs/agent-docs.test.mjs +3 -2
  372. package/foundation/discovery/authoring-self-docs.mjs +1 -0
  373. package/foundation/discovery/authoring-self-docs.test.mjs +6 -2
  374. package/foundation/discovery/cli-self-docs.mjs +16 -2
  375. package/foundation/discovery/cli-self-docs.test.mjs +20 -0
  376. package/foundation/discovery/docs-discovery.mjs +5 -1
  377. package/foundation/discovery/docs-discovery.test.mjs +21 -0
  378. package/foundation/discovery/docs-section-key.d.mts +1 -1
  379. package/foundation/discovery/docs-section-key.mjs +1 -1
  380. package/foundation/discovery/template-adapter.d.mts +14 -0
  381. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +37 -1
  382. package/foundation/discovery/template-adapter.mjs +21 -1
  383. package/foundation/doc-compiler/doc-loads.test.mjs +5 -4
  384. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  385. package/foundation/doc-compiler/tree.d.mts +4 -0
  386. package/foundation/doc-compiler/tree.mjs +6 -1
  387. package/foundation/doc-compiler/tree.test.mjs +65 -14
  388. package/foundation/integrations/cli-requirement.d.mts +75 -11
  389. package/foundation/integrations/cli-requirement.mjs +120 -23
  390. package/foundation/integrations/cli-requirement.test.mjs +141 -9
  391. package/foundation/integrations/contribution-inventory.mjs +1 -1
  392. package/foundation/integrations/integrations.d.mts +14 -1
  393. package/foundation/integrations/integrations.mjs +41 -1
  394. package/foundation/integrations/integrations.test.mjs +31 -0
  395. package/foundation/response/batch.type.d.mts +33 -0
  396. package/foundation/response/batch.type.mjs +34 -0
  397. package/foundation/response/error-codes.doc.mjs +6 -8
  398. package/foundation/response/error-codes.test.mjs +30 -5
  399. package/foundation/response/response-types.doc.d.mts +5 -4
  400. package/foundation/response/response-types.doc.mjs +49 -19
  401. package/foundation/response/response-types.doc.test.mjs +23 -0
  402. package/foundation/response/response.doc.mjs +11 -10
  403. package/package.json +9 -9
  404. package/assets/docs/tree/integrations.test.mjs +0 -62
  405. package/assets/docs/tree/writing-docs.doc.mjs +0 -286
@@ -2,14 +2,15 @@
2
2
 
3
3
  /**
4
4
  * @file Tests for build's page ranker: long ideas, head nouns, family bases,
5
- * rare-word weighting, and family words taken from the templates themselves.
5
+ * rare-word weighting, keywords, family words taken from the templates
6
+ * themselves, and parts told from pages by the system's own components.
6
7
  */
7
8
 
8
9
  import {describe, it, expect} from 'vitest';
9
10
  import * as path from 'node:path';
10
11
  import {fileURLToPath} from 'node:url';
11
- import {pickStart, rankPages} from './rank.mjs';
12
- import {loadPageTemplates} from '../_adapter.mjs';
12
+ import {ideaKind, pickStart, rankPages} from './rank.mjs';
13
+ import {loadComponents, loadPageTemplates} from '../_adapter.mjs';
13
14
 
14
15
  // api/build/kit/ -> up 5 = repo root (has packages/core and the templates).
15
16
  const REPO = path.resolve(
@@ -17,14 +18,24 @@ const REPO = path.resolve(
17
18
  '../../../../..',
18
19
  );
19
20
 
20
- /** @param {string} name @param {string} category @param {string} description */
21
- const page = (name, category, description) => ({
21
+ /**
22
+ * @param {string} name
23
+ * @param {string} category
24
+ * @param {string} description
25
+ * @param {string[]} [keywords]
26
+ */
27
+ const page = (name, category, description, keywords = []) => ({
22
28
  name,
23
29
  displayName: name,
24
30
  category,
25
31
  description,
32
+ keywords,
33
+ command: `astryx template ${name} --type page`,
26
34
  });
27
35
 
36
+ /** @param {string} name @param {string[]} [keywords] */
37
+ const component = (name, keywords = []) => ({name, keywords});
38
+
28
39
  describe('rankPages on the shipped page templates', () => {
29
40
  /** @param {string} query */
30
41
  const start = async query =>
@@ -49,6 +60,19 @@ describe('rankPages on the shipped page templates', () => {
49
60
  );
50
61
  });
51
62
 
63
+ it('keeps the family base when a variant shares one incidental word', async () => {
64
+ // "comparison" and "cohort" name dashboard variants, but here each is one
65
+ // small part of a general dashboard.
66
+ expect(
67
+ await start(
68
+ 'support dashboard with ticket volume charts and a small comparison note',
69
+ ),
70
+ ).toBe('dashboard');
71
+ expect(
72
+ await start('sales dashboard with a cohort filter and weekly charts'),
73
+ ).toBe('dashboard');
74
+ });
75
+
52
76
  it('lets the head noun decide between families', async () => {
53
77
  // Both ideas mention a table and summary numbers; the head says which
54
78
  // page it is.
@@ -64,6 +88,14 @@ describe('rankPages on the shipped page templates', () => {
64
88
  ).toMatch(/^table-/);
65
89
  });
66
90
 
91
+ it('keeps a variant that leads when its family base cannot start alone', async () => {
92
+ // The dashboard base matches only the family word here; the funnel
93
+ // dashboard matches the idea.
94
+ expect(await start('a funnel for a dashboard')).toBe(
95
+ 'dashboard-cohort-funnel',
96
+ );
97
+ });
98
+
67
99
  it('does not start from one rare word', async () => {
68
100
  // "board" is the kanban board's own word; a game board is not a kanban.
69
101
  expect(
@@ -75,11 +107,10 @@ describe('rankPages on the shipped page templates', () => {
75
107
  describe('rankPages on any catalog', () => {
76
108
  it('ranks only the templates it is given', () => {
77
109
  const ranked = rankPages('dashboard', [
78
- page(
110
+ page('dashboard', 'Dashboard - Analytics', 'Tiles, charts, tables.', [
79
111
  'dashboard',
80
- 'Dashboard - Analytics',
81
- 'Tiles, charts, tables. Dashboard, metrics.',
82
- ),
112
+ 'metrics',
113
+ ]),
83
114
  ]);
84
115
  expect(ranked.map(r => r.name)).toEqual(['dashboard']);
85
116
  });
@@ -88,17 +119,14 @@ describe('rankPages on any catalog', () => {
88
119
  // An integration's family: its word is in two of its ids, so an idea
89
120
  // naming it picks the family, and its base template leads it.
90
121
  const catalog = [
91
- page(
122
+ page('dashboard', 'Dashboard - Analytics', 'Tiles, charts, tables.', [
92
123
  'dashboard',
93
- 'Dashboard - Analytics',
94
- 'Tiles, charts, tables. Dashboard, metrics.',
95
- ),
96
- page('widget', 'Widget - Basic', 'One compact card. Widget, tile.'),
97
- page(
98
- 'widget-grid',
99
- 'Widget - Grid',
100
- 'Many compact cards in a grid. Widget wall.',
101
- ),
124
+ 'metrics',
125
+ ]),
126
+ page('widget', 'Widget - Basic', 'One compact card.', ['widget', 'tile']),
127
+ page('widget-grid', 'Widget - Grid', 'Many compact cards in a grid.', [
128
+ 'widget wall',
129
+ ]),
102
130
  ];
103
131
  const ranked = rankPages('weather widget with charts', catalog);
104
132
  expect(ranked[0].name).toBe('widget');
@@ -106,15 +134,41 @@ describe('rankPages on any catalog', () => {
106
134
  expect(pickStart(ranked)?.name).toBe('widget');
107
135
  });
108
136
 
137
+ it("counts a template's keywords above words in its description", () => {
138
+ // Both mention uptime; only one names it as an idea it serves.
139
+ const catalog = [
140
+ page('ops', 'Dashboard - Ops', 'Uptime strips beside alert rows.'),
141
+ page('health', 'Dashboard - Health', 'Status tiles over time charts.', [
142
+ 'uptime',
143
+ ]),
144
+ ];
145
+ expect(rankPages('uptime overview', catalog)[0].name).toBe('health');
146
+ });
147
+
148
+ it("lets a variant displace its family's base only with two words of its own", () => {
149
+ const catalog = [
150
+ page('widget', 'Widget - Basic', 'One compact card.', ['widget']),
151
+ page('widget-weather', 'Widget - Weather', 'A forecast card.', [
152
+ 'weather',
153
+ 'forecast',
154
+ 'radar',
155
+ ]),
156
+ ];
157
+ // One word of the variant's own: still the family's base.
158
+ expect(rankPages('weather widget', catalog)[0].name).toBe('widget');
159
+ // Two: the variant.
160
+ expect(rankPages('weather widget with radar', catalog)[0].name).toBe(
161
+ 'widget-weather',
162
+ );
163
+ });
164
+
109
165
  it('weighs a word by how rare it is among page templates', () => {
110
166
  const catalog = [
111
- page('alpha', 'Dashboard - Alpha', 'Status tiles. Status overview.'),
112
- page('beta', 'Dashboard - Beta', 'Status rows. Status list.'),
113
- page(
114
- 'gamma',
115
- 'Dashboard - Gamma',
116
- 'Funnel of stages. Funnel conversion.',
117
- ),
167
+ page('alpha', 'Dashboard - Alpha', 'Status tiles.', ['status overview']),
168
+ page('beta', 'Dashboard - Beta', 'Status rows.', ['status list']),
169
+ page('gamma', 'Dashboard - Gamma', 'Funnel of stages.', [
170
+ 'funnel conversion',
171
+ ]),
118
172
  ];
119
173
  // "status" is on two templates, "funnel" on one: the rare word wins.
120
174
  const ranked = rankPages('status funnel', catalog);
@@ -127,22 +181,24 @@ describe('rankPages structure signals', () => {
127
181
  page(
128
182
  'dialog-panel',
129
183
  'Settings - Dialog',
130
- 'Preferences inside a modal container. Settings, or modal dialog.',
131
- ),
132
- page(
133
- 'tree-table',
134
- 'Table - Tree',
135
- 'Nested rows under parents. Tree, nested rows, file browser.',
136
- ),
137
- page(
138
- 'item-detail',
139
- 'Content - Item Detail',
140
- 'One item with its media. Product, listing, or item detail.',
184
+ 'Preferences inside a modal container.',
185
+ ['settings', 'modal dialog'],
141
186
  ),
187
+ page('tree-table', 'Table - Tree', 'Nested rows under parents.', [
188
+ 'tree',
189
+ 'nested rows',
190
+ 'file browser',
191
+ ]),
192
+ page('item-detail', 'Content - Item Detail', 'One item with its media.', [
193
+ 'product',
194
+ 'listing',
195
+ 'item detail',
196
+ ]),
142
197
  page(
143
198
  'docs-catalog',
144
199
  'Content - Documentation Catalog',
145
- 'A grid of category cards. Documentation, docs, or API index.',
200
+ 'A grid of category cards.',
201
+ ['documentation', 'docs', 'api index'],
146
202
  ),
147
203
  ];
148
204
 
@@ -179,18 +235,145 @@ describe('rankPages structure signals', () => {
179
235
  it('does not treat a synonym as a family name', () => {
180
236
  // "landing" is a synonym of "hero" in search, not a family word here.
181
237
  const heroes = [
182
- page(
183
- 'hero-centered',
184
- 'Gallery - Hero',
185
- 'A centered hero. Hero, banner, or landing.',
186
- ),
187
- page(
188
- 'hero-split',
189
- 'Gallery - Hero Split',
190
- 'A split hero. Hero or splash.',
191
- ),
238
+ page('hero-centered', 'Gallery - Hero', 'A centered hero.', [
239
+ 'hero',
240
+ 'banner',
241
+ 'landing',
242
+ ]),
243
+ page('hero-split', 'Gallery - Hero Split', 'A split hero.', [
244
+ 'hero',
245
+ 'splash',
246
+ ]),
192
247
  ];
193
248
  const ranked = rankPages('internal landing page', heroes);
194
249
  expect(ranked.every(r => !r.familyNamed)).toBe(true);
195
250
  });
196
251
  });
252
+
253
+ describe('ideaKind: a part of a page, told by the components the system ships', () => {
254
+ const pages = [
255
+ page('table', 'Table - Basic', 'Rows of records.'),
256
+ page('table-filter', 'Table - Filtering', 'Rows narrowed by filters.'),
257
+ page('settings', 'Settings', 'Grouped preferences.'),
258
+ ];
259
+ const components = [
260
+ component('DateRangeInput', ['date picker']),
261
+ component('Tooltip'),
262
+ component('Calendar'),
263
+ component('Table'),
264
+ component('Dialog', ['modal']),
265
+ ];
266
+ /** @param {string} idea @param {object[]} [using] */
267
+ const kind = (idea, using = components) => ideaKind(idea, pages, using);
268
+
269
+ it('takes a part from a component name or keyword at the head', () => {
270
+ expect(kind('a date range input')).toBe('part');
271
+ expect(kind('a date picker with presets')).toBe('part');
272
+ expect(kind('a tooltip')).toBe('part');
273
+ });
274
+
275
+ it('takes a page word or a family word at the head as a page', () => {
276
+ expect(kind('a calendar')).toBe('part');
277
+ expect(kind('a team calendar page')).toBe('page');
278
+ // Table is a component, but table is also a family of page templates.
279
+ expect(kind('a data table with filters')).toBe('page');
280
+ });
281
+
282
+ it("reads parts from the project's own components", () => {
283
+ // An integration's component joins the vocabulary by existing.
284
+ expect(kind('a revenue gauge')).toBe('page');
285
+ expect(
286
+ kind('a revenue gauge', [...components, component('AcmeGauge')]),
287
+ ).toBe('part');
288
+ });
289
+
290
+ it("takes an idea that lists a page's worth of pieces as a page", () => {
291
+ expect(kind('a calendar with a tooltip')).toBe('part');
292
+ expect(kind('a calendar, a tooltip, and a date range input')).toBe('page');
293
+ });
294
+
295
+ it('takes the frame of a container phrase as the frame, not the head', () => {
296
+ expect(kind('a dialog')).toBe('part');
297
+ expect(kind('saved drafts in a modal')).toBe('page');
298
+ });
299
+
300
+ it('takes a change to an existing page or part as an edit', () => {
301
+ expect(kind('add a sort toggle to the existing reports table')).toBe(
302
+ 'edit',
303
+ );
304
+ expect(kind('reuse the existing tooltip on the chart')).toBe('edit');
305
+ });
306
+
307
+ it('does not take "existing" that names no page or part as an edit', () => {
308
+ expect(kind('a new settings page inspired by the existing one')).toBe(
309
+ 'page',
310
+ );
311
+ expect(kind('show existing users in a settings page')).toBe('page');
312
+ });
313
+
314
+ it('does not take a request for a new page as an edit', () => {
315
+ expect(
316
+ kind('a new settings page based on the existing settings page'),
317
+ ).toBe('page');
318
+ expect(kind('clone the existing table as a new page')).toBe('page');
319
+ // "A new column" asks for a part, so the change stays a change.
320
+ expect(kind('add a new column to the existing reports table')).toBe('edit');
321
+ });
322
+ });
323
+
324
+ describe('pickStart on parts and edits (spec:AST-048/FR3)', () => {
325
+ const shipped = Promise.all([loadPageTemplates(REPO), loadComponents(REPO)]);
326
+ /** @param {string} query */
327
+ const start = async query => {
328
+ const [catalog, components] = await shipped;
329
+ const kind = ideaKind(query, catalog, components);
330
+ return pickStart(rankPages(query, catalog), kind)?.name ?? null;
331
+ };
332
+
333
+ it('starts a part from the page it names, else from the app shell', async () => {
334
+ expect(await start('an empty state for a settings page')).toBe('settings');
335
+ expect(await start('a date range picker')).toBeNull();
336
+ expect(await start('compact status pill with a tooltip')).toBeNull();
337
+ });
338
+
339
+ it('starts an edit of an existing page or part from the app shell', async () => {
340
+ for (const idea of [
341
+ 'add a sparkline column to the existing incidents table',
342
+ 'add a sort toggle to the existing reports dashboard',
343
+ 'swap the existing banner for a toast',
344
+ ]) {
345
+ expect(await start(idea)).toBeNull();
346
+ }
347
+ });
348
+
349
+ it('starts a new page that mentions something existing from its template', async () => {
350
+ expect(await start('a new dashboard inspired by the existing one')).toBe(
351
+ 'dashboard',
352
+ );
353
+ expect(await start('show existing users in a table page')).toMatch(
354
+ /^table/,
355
+ );
356
+ });
357
+
358
+ it('starts a new page that names an existing one from its template', async () => {
359
+ for (const idea of [
360
+ 'a new dashboard based on the existing dashboard',
361
+ 'a new dashboard like the existing dashboard',
362
+ 'clone the existing dashboard as a new page',
363
+ ]) {
364
+ expect(await start(idea)).toBe('dashboard');
365
+ }
366
+ });
367
+
368
+ it('reads a bare "existing" phrase that names a page as the builder\'s page', async () => {
369
+ expect(
370
+ await start('existing reports dashboard with a date filter'),
371
+ ).toBeNull();
372
+ });
373
+
374
+ it('still starts a whole page from its template', async () => {
375
+ expect(
376
+ await start('saved drafts in a modal with resume and delete row actions'),
377
+ ).toBe('settings-dialog');
378
+ });
379
+ });
@@ -68,6 +68,16 @@ export function requireCoreDir(cwd: string): string;
68
68
  * @returns {Promise<import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]>}
69
69
  */
70
70
  export function loadIntegrationsSafely(cwd: string): Promise<import("../../foundation/integrations/integrations.mjs").LoadedIntegration[]>;
71
+ /**
72
+ * Read the exact installed version available to a package-qualified component
73
+ * selector. Legacy docs packages do not expose a reliable version here, so a
74
+ * version-qualified lookup never falls through to them.
75
+ * @param {string} coreDir
76
+ * @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]} loadedIntegrations
77
+ * @param {string} packageName
78
+ * @returns {string|null}
79
+ */
80
+ export function installedComponentPackageVersion(coreDir: string, loadedIntegrations: import("../../foundation/integrations/integrations.mjs").LoadedIntegration[], packageName: string): string | null;
71
81
  /**
72
82
  * Build the set of OWNER packages that provide a component with this name
73
83
  * across core + every loaded integration. This is what lets the CLI
@@ -180,6 +190,20 @@ export function scopeSubComponent(docs: LoadedComponentDoc, dirName: string, cor
180
190
  matchingComponent: any;
181
191
  } | null;
182
192
  export { CORE_PACKAGE };
193
+ /**
194
+ * Internal ambiguity marker. Single-component callers still receive the same
195
+ * AstryxError code, message, and suggestions; batch callers can additionally
196
+ * project every installed candidate without parsing prose.
197
+ */
198
+ export class ComponentAmbiguityError extends AstryxError {
199
+ /**
200
+ * @param {ComponentOwner[]} owners
201
+ * @param {string} dirName
202
+ */
203
+ constructor(owners: ComponentOwner[], dirName: string);
204
+ /** @type {import('./component.type.mjs').ComponentBatchCandidate[]} */
205
+ candidates: import("./component.type.mjs").ComponentBatchCandidate[];
206
+ }
183
207
  /**
184
208
  * A loaded component doc. The shared validated loader accepts stamped and legacy
185
209
  * component docs; this loose view captures the fields the API reads across both.
@@ -258,3 +282,4 @@ export type ResolvedUnscopedDoc = {
258
282
  resolvedSourcePath: string | null;
259
283
  };
260
284
  import { CORE_PACKAGE } from '../../foundation/discovery/component-discovery.mjs';
285
+ import { AstryxError } from '../error.mjs';
@@ -18,6 +18,8 @@
18
18
  * deduped, so each leaf stays a thin projection.
19
19
  */
20
20
 
21
+ import * as fs from 'node:fs';
22
+ import * as path from 'node:path';
21
23
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
22
24
  import {
23
25
  findCoreDir,
@@ -146,6 +148,34 @@ function findLoadedIntegration(loadedIntegrations, packageName) {
146
148
  return loadedIntegrations.find(i => i.name === packageName) ?? null;
147
149
  }
148
150
 
151
+ /**
152
+ * Read the exact installed version available to a package-qualified component
153
+ * selector. Legacy docs packages do not expose a reliable version here, so a
154
+ * version-qualified lookup never falls through to them.
155
+ * @param {string} coreDir
156
+ * @param {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]} loadedIntegrations
157
+ * @param {string} packageName
158
+ * @returns {string|null}
159
+ */
160
+ export function installedComponentPackageVersion(
161
+ coreDir,
162
+ loadedIntegrations,
163
+ packageName,
164
+ ) {
165
+ if (packageName === CORE_PACKAGE) {
166
+ try {
167
+ const pkg = JSON.parse(
168
+ fs.readFileSync(path.join(coreDir, 'package.json'), 'utf8'),
169
+ );
170
+ return typeof pkg.version === 'string' ? pkg.version : null;
171
+ } catch {
172
+ return null;
173
+ }
174
+ }
175
+ const integration = findLoadedIntegration(loadedIntegrations, packageName);
176
+ return typeof integration?.version === 'string' ? integration.version : null;
177
+ }
178
+
149
179
  /**
150
180
  * Resolve an external package by name from the discovered externals list.
151
181
  * @param {string} packageName - e.g. '@acme/xds-widgets'
@@ -244,6 +274,34 @@ export function classifyScope(
244
274
  return {kind: 'legacy', ext};
245
275
  }
246
276
 
277
+ /**
278
+ * Internal ambiguity marker. Single-component callers still receive the same
279
+ * AstryxError code, message, and suggestions; batch callers can additionally
280
+ * project every installed candidate without parsing prose.
281
+ */
282
+ export class ComponentAmbiguityError extends AstryxError {
283
+ /** @type {import('./component.type.mjs').ComponentBatchCandidate[]} */
284
+ candidates;
285
+
286
+ /**
287
+ * @param {ComponentOwner[]} owners
288
+ * @param {string} dirName
289
+ */
290
+ constructor(owners, dirName) {
291
+ super(
292
+ `Component "${dirName}" is provided by multiple packages. Re-run with --package <pkg> to choose one.`,
293
+ owners.map(o => ({name: o.package, reason: 'provides this component'})),
294
+ ERROR_CODES.ERR_UNKNOWN_COMPONENT,
295
+ );
296
+ this.candidates = owners.map(owner => ({
297
+ package: owner.package,
298
+ component: dirName,
299
+ kind: 'component',
300
+ installed: true,
301
+ }));
302
+ }
303
+ }
304
+
247
305
  /**
248
306
  * Refuse to guess when the name is owned by MORE THAN ONE package (core and/or
249
307
  * integrations) and the caller did not scope with --package. Legacy
@@ -254,11 +312,7 @@ export function classifyScope(
254
312
  */
255
313
  export function assertUnambiguousOwners(owners, dirName) {
256
314
  if (owners.length > 1) {
257
- throw new AstryxError(
258
- `Component "${dirName}" is provided by multiple packages. Re-run with --package <pkg> to choose one.`,
259
- owners.map(o => ({name: o.package, reason: 'provides this component'})),
260
- ERROR_CODES.ERR_UNKNOWN_COMPONENT,
261
- );
315
+ throw new ComponentAmbiguityError(owners, dirName);
262
316
  }
263
317
  }
264
318
 
@@ -2,7 +2,7 @@
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
4
  /**
5
- * @param {string} [name]
5
+ * @param {string|string[]} [name]
6
6
  * @param {object} [options]
7
7
  * @param {string} [options.cwd]
8
8
  * @param {boolean} [options.list]
@@ -18,6 +18,7 @@
18
18
  * @param {boolean} [options.dense]
19
19
  * @returns {Promise<(
20
20
  * import('./component.type.mjs').ComponentListResponse
21
+ * | import('./component.type.mjs').ComponentBatchResponse
21
22
  * | import('./component.type.mjs').ComponentDetailResponse
22
23
  * | import('./component.type.mjs').ComponentDetailPropsResponse
23
24
  * | import('./component.type.mjs').ComponentDetailSourceResponse
@@ -25,7 +26,7 @@
25
26
  * | import('./component.type.mjs').ComponentDetailBlocksResponse
26
27
  * )>}
27
28
  */
28
- export function component(name?: string, options?: {
29
+ export function component(name?: string | string[], options?: {
29
30
  cwd?: string | undefined;
30
31
  list?: boolean | undefined;
31
32
  category?: string | undefined;
@@ -38,4 +39,6 @@ export function component(name?: string, options?: {
38
39
  lang?: string | undefined;
39
40
  zh?: boolean | undefined;
40
41
  dense?: boolean | undefined;
41
- }): Promise<(import("./component.type.mjs").ComponentListResponse | import("./component.type.mjs").ComponentDetailResponse | import("./component.type.mjs").ComponentDetailPropsResponse | import("./component.type.mjs").ComponentDetailSourceResponse | import("./component.type.mjs").ComponentDetailShowcaseResponse | import("./component.type.mjs").ComponentDetailBlocksResponse)>;
42
+ }): Promise<(import("./component.type.mjs").ComponentListResponse | import("./component.type.mjs").ComponentBatchResponse | import("./component.type.mjs").ComponentDetailResponse | import("./component.type.mjs").ComponentDetailPropsResponse | import("./component.type.mjs").ComponentDetailSourceResponse | import("./component.type.mjs").ComponentDetailShowcaseResponse | import("./component.type.mjs").ComponentDetailBlocksResponse)>;
43
+ /** Maximum selectors accepted before any component resolution starts. */
44
+ export const COMPONENT_BATCH_SELECTOR_LIMIT: 100;
@@ -15,16 +15,16 @@ export const doc = {
15
15
  namespace: 'cli/api',
16
16
  displayName: 'component()',
17
17
  summary:
18
- 'Resolve a component by name, or list the catalog, with optional focused slices (props, source, showcase, blocks).',
18
+ 'Resolve one or several components by name, or list the catalog, with optional focused slices (props, source, showcase, blocks).',
19
19
  description:
20
- 'Routes on its arguments: a name resolves that component across core and ' +
21
- 'integration packages and returns its authored ComponentDoc plus ownership ' +
22
- 'metadata; no name (or `list`/`category`) returns the catalog grouped by ' +
23
- 'category. Boolean flags narrow a single component to just its props, ' +
24
- 'source, showcase, or example blocks.',
20
+ 'Routes on its arguments: one string resolves that component across core and ' +
21
+ 'integration packages; an array returns one ordered result row per selector at ' +
22
+ 'every array length; and no name returns the catalog grouped by category. ' +
23
+ 'Boolean flags narrow each resolved component to just its props, source, ' +
24
+ 'showcase, or example blocks.',
25
25
  importPath: '@astryxdesign/cli/api',
26
26
  signature:
27
- 'component(name?: string, options?: ComponentOptions): Promise<ComponentListResponse | ComponentDetailResponse | ComponentDetailPropsResponse | ComponentDetailSourceResponse | ComponentDetailShowcaseResponse | ComponentDetailBlocksResponse>',
27
+ 'component(name?: string | string[], options?: ComponentOptions): Promise<ComponentListResponse | ComponentBatchResponse | ComponentDetailResponse | ComponentDetailPropsResponse | ComponentDetailSourceResponse | ComponentDetailShowcaseResponse | ComponentDetailBlocksResponse>',
28
28
  keywords: [
29
29
  'component',
30
30
  'components',
@@ -37,14 +37,15 @@ export const doc = {
37
37
  params: [
38
38
  {
39
39
  name: 'name',
40
- type: 'string',
40
+ type: 'string | string[]',
41
41
  description:
42
- "Component name to resolve (e.g. 'Button'). Omit to list the catalog.",
42
+ "Pass one selector string for the existing single-result response, or an array of at most 100 selectors for an ordered component.batch response. The limit counts duplicates in every projection mode. An array always requests a batch, including [] and ['Button']. Use 'Button', 'widgets/Button', '@acme/widgets/Button', or '@acme/widgets@1.2.3/Button'. A version applies to the package and must match the installed version. Omit the argument to list the catalog.",
43
43
  },
44
44
  {
45
45
  name: 'options.cwd',
46
46
  type: 'string',
47
47
  description: 'Directory to resolve @astryxdesign/core from.',
48
+ default: 'process.cwd()',
48
49
  },
49
50
  {
50
51
  name: 'options.list',
@@ -54,13 +55,14 @@ export const doc = {
54
55
  {
55
56
  name: 'options.category',
56
57
  type: 'string',
57
- description: 'List only components in this category.',
58
+ description:
59
+ "List only the components in this group: a key of the unfiltered list (each component's group field), such as 'Layout' or 'Button'. It is not the category field of a component detail.",
58
60
  },
59
61
  {
60
62
  name: 'options.package',
61
63
  type: 'string',
62
64
  description:
63
- "Scope lookup to a specific external package (e.g. '@acme/xds-widgets').",
65
+ "Scope lookup to a specific external package (e.g. '@acme/widgets').",
64
66
  },
65
67
  {
66
68
  name: 'options.props',
@@ -87,7 +89,8 @@ export const doc = {
87
89
  name: 'options.detail',
88
90
  type: "'full' | 'compact' | 'brief'",
89
91
  description: 'Detail level for list views.',
90
- default: "'full' for a named component, 'brief' for list views",
92
+ default:
93
+ "'full' for a named component; 'brief' for lists (returned as data.detail: 'names')",
91
94
  },
92
95
  {
93
96
  name: 'options.lang',
@@ -110,7 +113,12 @@ export const doc = {
110
113
  {
111
114
  type: 'component.list',
112
115
  description:
113
- "The catalog grouped by category. data.detail is the level ('names' | 'compact' | 'full') and data.components is the grouped map: names entries with name, package, and an optional canonical import for integration and legacy package components; brief entries; or full ComponentDoc entries.",
116
+ "The catalog grouped by component group. data.detail is the level ('names' | 'compact' | 'full') and data.components is the grouped map: names entries with name, package, and an optional canonical import for integration and legacy package components; brief entries; or full ComponentDoc entries.",
117
+ },
118
+ {
119
+ type: 'component.batch',
120
+ description:
121
+ 'An explicit selector array returns one ordered receipt at every array length: count and one results row per selector, including duplicates. ComponentBatchResponse specializes the shared BatchResponse and BatchRow types. Each row carries selector and status (found, not_found, ambiguous, or error); found rows carry the single-selector result, ambiguous rows carry installed candidates ({package, component, kind, installed}), and failed rows carry code, error, and optional suggestions.',
114
122
  },
115
123
  {
116
124
  type: 'component.detail',
@@ -137,6 +145,10 @@ export const doc = {
137
145
  },
138
146
  ],
139
147
  throws: [
148
+ {
149
+ code: 'ERR_INVALID_ARGUMENT',
150
+ when: 'a selector array has more than 100 entries, a package-shaped selector has no component item, or its package conflicts with options.package',
151
+ },
140
152
  {
141
153
  code: 'ERR_INVALID_DETAIL',
142
154
  when: "options.detail is not 'full', 'compact', or 'brief'",
@@ -151,7 +163,7 @@ export const doc = {
151
163
  },
152
164
  {
153
165
  code: 'ERR_UNKNOWN_CATEGORY',
154
- when: 'options.category is not a string or matches no known category',
166
+ when: 'options.category is not a string or matches no component group',
155
167
  },
156
168
  {
157
169
  code: 'ERR_UNKNOWN_COMPONENT',
@@ -159,12 +171,16 @@ export const doc = {
159
171
  },
160
172
  {
161
173
  code: 'ERR_UNKNOWN_PACKAGE',
162
- when: 'options.package names a legacy external package that cannot be found',
174
+ when: 'options.package names a legacy external package that cannot be found, or a package-qualified selector requests a version that is not installed',
163
175
  },
164
176
  {
165
177
  code: 'ERR_NO_DOC',
166
178
  when: 'the resolved component has no .doc.mjs typed doc file',
167
179
  },
180
+ {
181
+ code: 'ERR_INVALID_DOC',
182
+ when: "the resolved component's .doc.mjs fails to load or validate",
183
+ },
168
184
  {
169
185
  code: 'ERR_NO_SOURCE',
170
186
  when: 'options.source is set but the component has no source file',
@@ -179,10 +195,14 @@ export const doc = {
179
195
  label: 'Look up a component',
180
196
  code: "const r = await component('Button');",
181
197
  },
198
+ {
199
+ label: 'Look up several components',
200
+ code: "await component(['Button', 'Badge']);",
201
+ },
182
202
  {label: 'Props only', code: "await component('Button', {props: true});"},
183
203
  {
184
- label: 'Browse a category',
185
- code: "await component(undefined, {category: 'Form', detail: 'compact'});",
204
+ label: 'Browse one group',
205
+ code: "await component(undefined, {category: 'Layout', detail: 'compact'});",
186
206
  },
187
207
  ],
188
208
  command: 'component',