@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
@@ -10,7 +10,7 @@
10
10
  export const doc = {
11
11
  type: 'schema',
12
12
  name: 'config',
13
- displayName: 'Astryx Config',
13
+ displayName: 'astryx.config',
14
14
  namespace: 'authoring',
15
15
  description:
16
16
  'The optional astryx.config.* file at your project root. Declares which ' +
@@ -60,6 +60,14 @@ export const doc = {
60
60
  example:
61
61
  "{ audience: 'internal', async handle(report, {signal}) { return sendGap(report, {signal}); } }",
62
62
  },
63
+ {
64
+ name: 'discover',
65
+ type: 'DiscoverSource',
66
+ description:
67
+ 'Tell `astryx discover` which integrations this project could add: an async function that returns a catalog. An integration can provide one too, as a `discover` named export from its manifest. Discover calls every source, yours first, and one that fails never hides the others. Discover only reads; your package manager installs.',
68
+ example:
69
+ "async ({signal, package: name, version}) => fetchCatalog({signal, name, version})",
70
+ },
63
71
  {
64
72
  name: 'experimental',
65
73
  type: '{ xle?: { components?: Record<string, XleComponent> } }',
@@ -30,6 +30,7 @@ export type XleComponent = import("./type.js").XleComponent;
30
30
  export type DebugConfig = import("./type.js").DebugConfig;
31
31
  export type DebugEventHandler = import("../debug/type.js").DebugEventHandler;
32
32
  export type GapReportHandler = import("../gap-report/type.js").GapReportHandler;
33
+ export type DiscoverSource = import("../discover/type.js").DiscoverSource;
33
34
  import { z } from 'zod';
34
35
  declare const configSchema: z.ZodObject<{
35
36
  integrations: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -48,6 +49,7 @@ declare const configSchema: z.ZodObject<{
48
49
  }, z.core.$strict>>;
49
50
  debug: z.ZodOptional<z.ZodType<import("../debug/type.js").DebugEventHandler, any, z.core.$ZodTypeInternals<import("../debug/type.js").DebugEventHandler, any>>>;
50
51
  gapReport: z.ZodOptional<z.ZodType<import("../gap-report/type.js").GapReportHandler, any, z.core.$ZodTypeInternals<import("../gap-report/type.js").GapReportHandler, any>>>;
52
+ discover: z.ZodOptional<z.ZodType<import("../discover/type.js").DiscoverSource, any, z.core.$ZodTypeInternals<import("../discover/type.js").DiscoverSource, any>>>;
51
53
  experimental: z.ZodOptional<z.ZodObject<{
52
54
  xle: z.ZodOptional<z.ZodObject<{
53
55
  components: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -12,6 +12,7 @@
12
12
  import {z} from 'zod';
13
13
  import {formatZodError} from '../_shared/errors.mjs';
14
14
  import {parseGapReportHandler} from '../gap-report/parse.mjs';
15
+ import {parseDiscoverSource} from '../discover/parse.mjs';
15
16
 
16
17
  /** @typedef {import('./type.js').AstryxConfig} AstryxConfig */
17
18
  /** @typedef {import('./type.js').PostCodemodHook} PostCodemodHook */
@@ -19,6 +20,7 @@ import {parseGapReportHandler} from '../gap-report/parse.mjs';
19
20
  /** @typedef {import('./type.js').DebugConfig} DebugConfig */
20
21
  /** @typedef {import('../debug/type.js').DebugEventHandler} DebugEventHandler */
21
22
  /** @typedef {import('../gap-report/type.js').GapReportHandler} GapReportHandler */
23
+ /** @typedef {import('../discover/type.js').DiscoverSource} DiscoverSource */
22
24
 
23
25
  // Typed `z.custom` so `z.infer` reproduces the real function type (not `unknown`).
24
26
  const buildCommand = /** @type {z.ZodType<PostCodemodHook['buildCommand']>} */ (
@@ -66,6 +68,22 @@ const gapReportHandlerSchema = /** @type {z.ZodType<GapReportHandler>} */ (
66
68
  )
67
69
  );
68
70
 
71
+ // The same check an integration's `discover` named export passes. Typed
72
+ // z.custom preserves the public function type.
73
+ const discoverSourceSchema = /** @type {z.ZodType<DiscoverSource>} */ (
74
+ z.custom(
75
+ value => {
76
+ try {
77
+ parseDiscoverSource(value, 'discover');
78
+ return true;
79
+ } catch {
80
+ return false;
81
+ }
82
+ },
83
+ {message: 'Expected a discover source function'},
84
+ )
85
+ );
86
+
69
87
  const configSchema = z
70
88
  .object({
71
89
  integrations: z.array(z.string()).optional(),
@@ -76,6 +94,7 @@ const configSchema = z
76
94
  .optional(),
77
95
  debug: debugSchema.optional(),
78
96
  gapReport: gapReportHandlerSchema.optional(),
97
+ discover: discoverSourceSchema.optional(),
79
98
  experimental: z
80
99
  .object({
81
100
  xle: z
@@ -63,6 +63,14 @@ describe('parseConfig (load boundary)', () => {
63
63
  ).toEqual({audience: 'internal', handle});
64
64
  });
65
65
 
66
+ it('accepts a discover source function and refuses anything else', () => {
67
+ const discover = async () => ({});
68
+ expect(parseConfig({discover}).discover).toBe(discover);
69
+ expect(reason({discover: 'https://example.com/catalog.json'})).toContain(
70
+ 'discover',
71
+ );
72
+ });
73
+
66
74
  it('rejects obsolete or extended gap-report handler shapes', () => {
67
75
  expect(reason({gapReport: {command: './report.mjs'}})).toContain(
68
76
  'gapReport',
@@ -11,6 +11,7 @@
11
11
 
12
12
  import type {DebugEventHandler} from '../debug/type.js';
13
13
  import type {GapReportHandler} from '../gap-report/type.js';
14
+ import type {DiscoverSource} from '../discover/type.js';
14
15
 
15
16
  /**
16
17
  * A command to run as part of a post-codemod hook. Returned by a hook's
@@ -96,6 +97,16 @@ export interface AstryxConfig {
96
97
  debug?: DebugConfig;
97
98
  /** Route gap reports through a project-owned handler. See {@link GapReportHandler}. */
98
99
  gapReport?: GapReportHandler;
100
+ /**
101
+ * Tell `astryx discover` about integrations this project could add. See
102
+ * {@link DiscoverSource}.
103
+ *
104
+ * An integration can provide a source too, as a `discover` named export from
105
+ * its `astryx.integration.*` module. Discover calls every source: this one
106
+ * first, then each integration's in load order, and one that fails never
107
+ * hides the others.
108
+ */
109
+ discover?: DiscoverSource;
99
110
  /**
100
111
  * EXPERIMENTAL — shape may change and is not part of the stable config
101
112
  * contract. Provisional home for features still being proven out.
@@ -0,0 +1,13 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in authoring/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * @file SchemaDoc for DiscoverSource, the function `astryx discover` calls to
6
+ * learn which integrations a project could add.
7
+ * @input The DiscoverSource type and the catalog types beside it (`type.ts`),
8
+ * which `parse.mjs` validates.
9
+ * @output The `discover-source` section of `astryx docs authoring`.
10
+ * @position packages/cli/authoring/discover — schema documentation
11
+ */
12
+ /** @type {import('@astryxdesign/cli/authoring').SchemaDoc} */
13
+ export const doc: import("@astryxdesign/cli/authoring").SchemaDoc;
@@ -0,0 +1,138 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file SchemaDoc for DiscoverSource, the function `astryx discover` calls to
5
+ * learn which integrations a project could add.
6
+ * @input The DiscoverSource type and the catalog types beside it (`type.ts`),
7
+ * which `parse.mjs` validates.
8
+ * @output The `discover-source` section of `astryx docs authoring`.
9
+ * @position packages/cli/authoring/discover — schema documentation
10
+ */
11
+
12
+ /** @type {import('@astryxdesign/cli/authoring').SchemaDoc} */
13
+ export const doc = {
14
+ type: 'schema',
15
+ name: 'discover-source',
16
+ displayName: 'DiscoverSource',
17
+ namespace: 'authoring',
18
+ description:
19
+ 'A source for `astryx discover`: an async function that returns a catalog of packages a project could add, their versions, and what each version adds. Set it as `discover` in astryx.config, or export it as `discover` from an integration manifest. Discover calls every source, the project one first, and one that throws, runs past 30 seconds, or returns an invalid catalog never hides the others; discover then uses the last good answer it saved for that source. Discover only reads: it prints the command that adds a package and never runs it.',
20
+ appliesTo:
21
+ '`discover` in astryx.config.*, or the `discover` named export of astryx.integration.*',
22
+ fields: [
23
+ {
24
+ name: 'context',
25
+ type: 'DiscoverSourceContext',
26
+ description: 'The one argument the source is called with.',
27
+ required: true,
28
+ fields: [
29
+ {
30
+ name: 'context.signal',
31
+ type: 'AbortSignal',
32
+ description: 'Aborted when the source runs past 30 seconds.',
33
+ required: true,
34
+ },
35
+ {
36
+ name: 'context.package',
37
+ type: 'string',
38
+ description:
39
+ 'Set when discover shows one package: return that package with every version.',
40
+ },
41
+ {
42
+ name: 'context.version',
43
+ type: 'string',
44
+ description:
45
+ "With `package`: return that version's contributions. Without it, the latest release's.",
46
+ },
47
+ ],
48
+ },
49
+ {
50
+ name: 'returns',
51
+ type: 'Promise<DiscoverCatalog>',
52
+ description:
53
+ 'The catalog. Discover checks it, ignores fields and item kinds it does not know, and refuses any schemaVersion but 1.',
54
+ required: true,
55
+ fields: [
56
+ {
57
+ name: 'schemaVersion',
58
+ type: '1',
59
+ description: 'Version of the catalog shape.',
60
+ required: true,
61
+ },
62
+ {
63
+ name: 'source',
64
+ type: '{name: string, generatedAt: string, complete: boolean}',
65
+ description:
66
+ 'Who answered, when the data was produced (ISO 8601), and false when the source knows its list is partial.',
67
+ required: true,
68
+ },
69
+ {
70
+ name: 'packages',
71
+ type: 'DiscoverPackage[]',
72
+ description:
73
+ 'One entry per npm package. When two sources list the same package, the earlier source wins.',
74
+ required: true,
75
+ fields: [
76
+ {
77
+ name: 'packages[].package',
78
+ type: 'string',
79
+ description: 'The npm name.',
80
+ required: true,
81
+ },
82
+ {
83
+ name: 'packages[].integration',
84
+ type: 'string',
85
+ description:
86
+ 'Shared by every npm name that publishes the same integration. Discover lists an integration once.',
87
+ required: true,
88
+ },
89
+ {
90
+ name: 'packages[].aliases',
91
+ type: 'string[]',
92
+ description:
93
+ "The integration's other npm names. Discover never offers a package the project has under another name.",
94
+ required: true,
95
+ },
96
+ {
97
+ name: 'packages[].description',
98
+ type: 'string',
99
+ description: 'One line, for the list and search.',
100
+ },
101
+ {
102
+ name: 'packages[].latest',
103
+ type: 'string | null',
104
+ description: 'The latest release. Null when there are only prereleases.',
105
+ required: true,
106
+ },
107
+ {
108
+ name: 'packages[].versions',
109
+ type: 'DiscoverVersion[]',
110
+ description:
111
+ 'Every version, newest first: `{version, publishedAt, prerelease, status}`, where status is `ok` or why the version could not be read.',
112
+ required: true,
113
+ },
114
+ {
115
+ name: 'packages[].contributions',
116
+ type: 'DiscoverContribution[]',
117
+ description:
118
+ "What the requested (else latest) version adds: `{kind, name, title?, summary?, keywords?}`, where kind is `component`, `template`, `doc`, `theme`, `codemod`, or `agent-doc` (a DiscoverKind) and name is the name the CLI uses for it.",
119
+ required: true,
120
+ },
121
+ ],
122
+ },
123
+ ],
124
+ },
125
+ ],
126
+ examples: [
127
+ {
128
+ label: 'A project source in astryx.config',
129
+ code:
130
+ 'export default {\n' +
131
+ ' async discover({signal, package: name, version}) {\n' +
132
+ ' const res = await fetch(catalogUrl(name, version), {signal});\n' +
133
+ ' return res.json();\n' +
134
+ ' },\n' +
135
+ '};',
136
+ },
137
+ ],
138
+ };
@@ -0,0 +1,24 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in authoring/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * Check a catalog a discover source returned. Throws an Error naming the first
6
+ * problem. Items of a kind this CLI does not know are dropped, and versions are
7
+ * put newest first whatever order the source used.
8
+ *
9
+ * @param {unknown} value
10
+ * @param {string} [label]
11
+ * @returns {import('./type.js').DiscoverCatalog}
12
+ */
13
+ export function parseDiscoverCatalog(value: unknown, label?: string): import("./type.js").DiscoverCatalog;
14
+ /**
15
+ * Check a discover source itself: an async function, like `debug`, that takes
16
+ * `{signal, package?, version?}` and resolves to a catalog.
17
+ *
18
+ * @param {unknown} value
19
+ * @param {string} label
20
+ * @returns {import('./type.js').DiscoverSource}
21
+ */
22
+ export function parseDiscoverSource(value: unknown, label: string): import("./type.js").DiscoverSource;
23
+ /** Item kinds a catalog may list, in display order. */
24
+ export const DISCOVER_KINDS: readonly ["component", "template", "doc", "theme", "codemod", "agent-doc"];
@@ -0,0 +1,128 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Runtime checks for discover sources and the catalogs they return.
5
+ *
6
+ * The catalog schema is deliberately not strict: a source may add fields this
7
+ * CLI does not know, and they are dropped. An unknown `schemaVersion` is
8
+ * refused, and an item of a kind this CLI does not know is skipped, so a newer
9
+ * source never breaks an older CLI.
10
+ *
11
+ * @position packages/cli/authoring/discover — parse + validate, no I/O.
12
+ */
13
+
14
+ import {z} from 'zod';
15
+
16
+ /** Item kinds a catalog may list, in display order. */
17
+ export const DISCOVER_KINDS = /** @type {const} */ ([
18
+ 'component',
19
+ 'template',
20
+ 'doc',
21
+ 'theme',
22
+ 'codemod',
23
+ 'agent-doc',
24
+ ]);
25
+
26
+ const text = (/** @type {number} */ max) => z.string().min(1).max(max);
27
+
28
+ const contributionSchema = z.object({
29
+ kind: text(32),
30
+ name: text(512),
31
+ title: z.string().max(512).optional(),
32
+ summary: z.string().max(4096).optional(),
33
+ keywords: z.array(z.string().max(128)).max(64).optional(),
34
+ });
35
+
36
+ const versionSchema = z.object({
37
+ version: text(256),
38
+ publishedAt: z.string().max(64).nullable(),
39
+ prerelease: z.boolean(),
40
+ status: text(64),
41
+ });
42
+
43
+ const packageSchema = z.object({
44
+ package: text(214),
45
+ integration: text(214),
46
+ aliases: z.array(text(214)).max(64),
47
+ description: z.string().max(1024).optional(),
48
+ latest: text(256).nullable(),
49
+ versions: z.array(versionSchema).max(50_000),
50
+ contributions: z.array(contributionSchema).max(50_000),
51
+ });
52
+
53
+ const catalogSchema = z.object({
54
+ schemaVersion: z.literal(1),
55
+ source: z.object({
56
+ name: text(256),
57
+ generatedAt: text(64),
58
+ complete: z.boolean(),
59
+ }),
60
+ packages: z.array(packageSchema).max(20_000),
61
+ });
62
+
63
+ /**
64
+ * Newest first by publish time. A version with no known publish time goes
65
+ * last, and ties fall back to the version number.
66
+ * @param {{version: string, publishedAt: string | null}} a
67
+ * @param {{version: string, publishedAt: string | null}} b
68
+ */
69
+ function newestFirst(a, b) {
70
+ const at = Date.parse(a.publishedAt ?? '');
71
+ const bt = Date.parse(b.publishedAt ?? '');
72
+ if (Number.isNaN(at) !== Number.isNaN(bt)) return Number.isNaN(at) ? 1 : -1;
73
+ if (!Number.isNaN(at) && at !== bt) return bt - at;
74
+ return b.version.localeCompare(a.version, 'en', {numeric: true});
75
+ }
76
+
77
+ /**
78
+ * Check a catalog a discover source returned. Throws an Error naming the first
79
+ * problem. Items of a kind this CLI does not know are dropped, and versions are
80
+ * put newest first whatever order the source used.
81
+ *
82
+ * @param {unknown} value
83
+ * @param {string} [label]
84
+ * @returns {import('./type.js').DiscoverCatalog}
85
+ */
86
+ export function parseDiscoverCatalog(value, label = 'discover source') {
87
+ const version =
88
+ value != null && typeof value === 'object'
89
+ ? /** @type {{schemaVersion?: unknown}} */ (value).schemaVersion
90
+ : undefined;
91
+ if (version !== undefined && version !== 1) {
92
+ throw new Error(
93
+ `${label} returned schemaVersion ${String(version)}; this CLI reads schemaVersion 1`,
94
+ );
95
+ }
96
+ const parsed = catalogSchema.safeParse(value);
97
+ if (!parsed.success) {
98
+ const issue = parsed.error.issues[0];
99
+ const where = issue?.path.length ? ` at ${issue.path.join('.')}` : '';
100
+ throw new Error(
101
+ `${label} returned an invalid catalog${where}: ${issue?.message}`,
102
+ );
103
+ }
104
+ const known = /** @type {readonly string[]} */ (DISCOVER_KINDS);
105
+ return /** @type {import('./type.js').DiscoverCatalog} */ ({
106
+ ...parsed.data,
107
+ packages: parsed.data.packages.map(pkg => ({
108
+ ...pkg,
109
+ versions: [...pkg.versions].sort(newestFirst),
110
+ contributions: pkg.contributions.filter(c => known.includes(c.kind)),
111
+ })),
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Check a discover source itself: an async function, like `debug`, that takes
117
+ * `{signal, package?, version?}` and resolves to a catalog.
118
+ *
119
+ * @param {unknown} value
120
+ * @param {string} label
121
+ * @returns {import('./type.js').DiscoverSource}
122
+ */
123
+ export function parseDiscoverSource(value, label) {
124
+ if (typeof value !== 'function') {
125
+ throw new Error(`${label} must be a function`);
126
+ }
127
+ return /** @type {import('./type.js').DiscoverSource} */ (value);
128
+ }
@@ -0,0 +1,124 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Tests for the discover source and catalog checks.
5
+ */
6
+
7
+ import {describe, it, expect} from 'vitest';
8
+ import {
9
+ DISCOVER_KINDS,
10
+ parseDiscoverCatalog,
11
+ parseDiscoverSource,
12
+ } from './parse.mjs';
13
+
14
+ function catalog(overrides = {}) {
15
+ return {
16
+ schemaVersion: 1,
17
+ source: {
18
+ name: 'Acme catalog',
19
+ generatedAt: '2026-09-30T14:00:00.000Z',
20
+ complete: true,
21
+ },
22
+ packages: [
23
+ {
24
+ package: '@acme/ui',
25
+ integration: 'acme-ui',
26
+ aliases: [],
27
+ latest: '2.0.0',
28
+ versions: [
29
+ {
30
+ version: '2.0.0',
31
+ publishedAt: '2026-09-29T00:00:00.000Z',
32
+ prerelease: false,
33
+ status: 'ok',
34
+ },
35
+ ],
36
+ contributions: [{kind: 'component', name: 'Button'}],
37
+ },
38
+ ],
39
+ ...overrides,
40
+ };
41
+ }
42
+
43
+ describe('parseDiscoverCatalog', () => {
44
+ it('accepts a catalog', () => {
45
+ expect(parseDiscoverCatalog(catalog())).toEqual(catalog());
46
+ });
47
+
48
+ it('drops fields it does not know, so a newer source still works', () => {
49
+ const parsed = parseDiscoverCatalog({...catalog(), cursor: 'next'});
50
+ expect(parsed).not.toHaveProperty('cursor');
51
+ });
52
+
53
+ it('drops items of a kind it does not know', () => {
54
+ const value = catalog();
55
+ value.packages[0].contributions.push({kind: 'widget', name: 'Spinner'});
56
+ expect(parseDiscoverCatalog(value).packages[0].contributions).toEqual([
57
+ {kind: 'component', name: 'Button'},
58
+ ]);
59
+ });
60
+
61
+ it('puts versions newest first whatever order the source used', () => {
62
+ const value = catalog();
63
+ value.packages[0].versions = [
64
+ {
65
+ version: '1.0.0',
66
+ publishedAt: '2026-01-05T00:00:00.000Z',
67
+ prerelease: false,
68
+ status: 'ok',
69
+ },
70
+ {version: '1.5.0', publishedAt: null, prerelease: false, status: 'ok'},
71
+ {
72
+ version: '2.0.0',
73
+ publishedAt: '2026-09-29T00:00:00.000Z',
74
+ prerelease: false,
75
+ status: 'ok',
76
+ },
77
+ {
78
+ version: '2.0.0-rc.1',
79
+ publishedAt: '2026-09-01T00:00:00.000Z',
80
+ prerelease: true,
81
+ status: 'ok',
82
+ },
83
+ ];
84
+ expect(
85
+ parseDiscoverCatalog(value).packages[0].versions.map(v => v.version),
86
+ ).toEqual(['2.0.0', '2.0.0-rc.1', '1.0.0', '1.5.0']);
87
+ });
88
+
89
+ it('refuses a schemaVersion it does not read', () => {
90
+ expect(() => parseDiscoverCatalog(catalog({schemaVersion: 2}))).toThrow(
91
+ 'this CLI reads schemaVersion 1',
92
+ );
93
+ });
94
+
95
+ it('names the first problem and where it is', () => {
96
+ expect(() =>
97
+ parseDiscoverCatalog(catalog({packages: [{package: ''}]}), 'the source'),
98
+ ).toThrow(/^the source returned an invalid catalog at packages\.0\./);
99
+ });
100
+
101
+ it('lists the kinds in display order', () => {
102
+ expect(DISCOVER_KINDS).toEqual([
103
+ 'component',
104
+ 'template',
105
+ 'doc',
106
+ 'theme',
107
+ 'codemod',
108
+ 'agent-doc',
109
+ ]);
110
+ });
111
+ });
112
+
113
+ describe('parseDiscoverSource', () => {
114
+ it('accepts a function', () => {
115
+ const source = async () => catalog();
116
+ expect(parseDiscoverSource(source, 'discover')).toBe(source);
117
+ });
118
+
119
+ it('refuses anything else, such as a URL', () => {
120
+ expect(() =>
121
+ parseDiscoverSource('https://example.com/catalog.json', 'discover'),
122
+ ).toThrow('discover must be a function');
123
+ });
124
+ });
@@ -0,0 +1,87 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * Public type surface for discover sources.
5
+ *
6
+ * A discover source tells `astryx discover` which integrations exist beyond the
7
+ * ones a project already has. A project sets one as `discover` in
8
+ * `astryx.config`; an integration exports one as a `discover` NAMED export from
9
+ * its manifest. Discover calls every source, checks each answer, keeps a saved
10
+ * copy of the last good one, and never installs, enables, or runs anything a
11
+ * catalog names.
12
+ */
13
+
14
+ /** Kinds of item a package can add. */
15
+ export type DiscoverKind =
16
+ 'component' | 'template' | 'doc' | 'theme' | 'codemod' | 'agent-doc';
17
+
18
+ /** One item a package version adds. */
19
+ export interface DiscoverContribution {
20
+ kind: DiscoverKind;
21
+ /**
22
+ * The name the CLI uses for it: a component name, template id, doc topic,
23
+ * theme slug, or codemod id.
24
+ */
25
+ name: string;
26
+ title?: string;
27
+ summary?: string;
28
+ keywords?: string[];
29
+ }
30
+
31
+ /** One published version of a package. */
32
+ export interface DiscoverVersion {
33
+ version: string;
34
+ /** ISO 8601 publish time, or null when the source does not know it. */
35
+ publishedAt: string | null;
36
+ prerelease: boolean;
37
+ /** `ok`, or why the source could not read this version. */
38
+ status: string;
39
+ }
40
+
41
+ /** One npm package a source knows about. */
42
+ export interface DiscoverPackage {
43
+ package: string;
44
+ /** Shared by every npm name that publishes the same integration. */
45
+ integration: string;
46
+ /** The integration's other npm names. Discover never offers one the project has. */
47
+ aliases: string[];
48
+ description?: string;
49
+ /** The latest release, or null when the package has only prereleases. */
50
+ latest: string | null;
51
+ /** Every version, newest first. */
52
+ versions: DiscoverVersion[];
53
+ /** What the requested version adds, or the latest when none was requested. */
54
+ contributions: DiscoverContribution[];
55
+ }
56
+
57
+ /** What a discover source returns. */
58
+ export interface DiscoverCatalog {
59
+ schemaVersion: 1;
60
+ source: {
61
+ /** Shown to people, for example "Acme catalog". */
62
+ name: string;
63
+ /** ISO 8601 time the source's data was produced. */
64
+ generatedAt: string;
65
+ /** False when the source knows its list is partial. */
66
+ complete: boolean;
67
+ };
68
+ packages: DiscoverPackage[];
69
+ }
70
+
71
+ /** One call to a discover source. */
72
+ export interface DiscoverSourceContext {
73
+ /** Aborted when the source exceeds its 30-second budget. */
74
+ readonly signal: AbortSignal;
75
+ /** Asks for one package: every version, and `version`'s contributions. */
76
+ readonly package?: string;
77
+ /** With `package`: the version whose contributions to return. Defaults to the latest. */
78
+ readonly version?: string;
79
+ }
80
+
81
+ /**
82
+ * A discover source: an async function, like `debug`. Set it as `discover` in
83
+ * astryx.config, or export it as `discover` from an integration manifest.
84
+ */
85
+ export type DiscoverSource = (
86
+ context: DiscoverSourceContext,
87
+ ) => Promise<DiscoverCatalog>;
@@ -216,6 +216,7 @@ export const ComponentDocKindSchema: z.ZodObject<{
216
216
  theming: z.ZodOptional<z.ZodUnknown>;
217
217
  playground: z.ZodOptional<z.ZodUnknown>;
218
218
  examples: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
219
+ replaces: z.ZodOptional<z.ZodString>;
219
220
  name: z.ZodString;
220
221
  displayName: z.ZodOptional<z.ZodString>;
221
222
  description: z.ZodOptional<z.ZodString>;
@@ -316,6 +317,7 @@ export const FunctionDocKindSchema: z.ZodObject<{
316
317
  export const GenericDocKindSchema: z.ZodObject<{
317
318
  type: z.ZodLiteral<"generic">;
318
319
  title: z.ZodOptional<z.ZodString>;
320
+ keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
319
321
  sections: z.ZodOptional<z.ZodArray<z.ZodObject<{
320
322
  id: z.ZodOptional<z.ZodString>;
321
323
  title: z.ZodString;
@@ -384,7 +386,6 @@ export const GenericDocKindSchema: z.ZodObject<{
384
386
  import: z.ZodOptional<z.ZodString>;
385
387
  group: z.ZodOptional<z.ZodString>;
386
388
  category: z.ZodOptional<z.ZodString>;
387
- keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
388
389
  parent: z.ZodOptional<z.ZodString>;
389
390
  relatedDocs: z.ZodOptional<z.ZodArray<z.ZodString>>;
390
391
  hidden: z.ZodOptional<z.ZodBoolean>;
@@ -840,7 +841,6 @@ export const LegacyDocSchema: z.ZodUnion<readonly [z.ZodObject<{
840
841
  displayName: z.ZodOptional<z.ZodString>;
841
842
  group: z.ZodOptional<z.ZodString>;
842
843
  category: z.ZodOptional<z.ZodString>;
843
- keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
844
844
  isHiddenFromOverview: z.ZodOptional<z.ZodBoolean>;
845
845
  hidden: z.ZodOptional<z.ZodBoolean>;
846
846
  hiddenComponents: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -865,6 +865,7 @@ export const LegacyDocSchema: z.ZodUnion<readonly [z.ZodObject<{
865
865
  }>>;
866
866
  title: z.ZodString;
867
867
  description: z.ZodString;
868
+ keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
868
869
  sections: z.ZodArray<z.ZodObject<{
869
870
  id: z.ZodOptional<z.ZodString>;
870
871
  title: z.ZodString;