@astryxdesign/cli 0.6.4 → 0.6.5-canary.00f1ed9

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
@@ -92,6 +92,7 @@ function addErrors(issues, errors, code) {
92
92
  export async function integrationTemplateConflicts(pkg, options = {}) {
93
93
  const {cwd = process.cwd()} = options;
94
94
  const resolved = await resolveIntegration(pkg, cwd);
95
+ const validated = resolved.found;
95
96
  const name = resolved.found ? (resolved.name ?? null) : null;
96
97
  const version = resolved.found ? (resolved.version ?? null) : null;
97
98
  const issues = [...resolved.issues];
@@ -99,7 +100,7 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
99
100
  if (!resolved.integration || name == null) {
100
101
  return {
101
102
  type: 'integration.template-conflicts',
102
- data: {name, version, conflicts: [], issues},
103
+ data: {validated, name, version, conflicts: [], issues},
103
104
  };
104
105
  }
105
106
 
@@ -215,7 +216,7 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
215
216
 
216
217
  return {
217
218
  type: 'integration.template-conflicts',
218
- data: {name, version, conflicts, issues},
219
+ data: {validated, name, version, conflicts, issues},
219
220
  };
220
221
  }
221
222
 
@@ -228,6 +229,7 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
228
229
  export async function integrationComponentConflicts(pkg, options = {}) {
229
230
  const {cwd = process.cwd()} = options;
230
231
  const resolved = await resolveIntegration(pkg, cwd);
232
+ const validated = resolved.found;
231
233
  const name = resolved.found ? (resolved.name ?? null) : null;
232
234
  const version = resolved.found ? (resolved.version ?? null) : null;
233
235
  const issues = [...resolved.issues];
@@ -235,7 +237,7 @@ export async function integrationComponentConflicts(pkg, options = {}) {
235
237
  if (!resolved.integration?.components || name == null) {
236
238
  return {
237
239
  type: 'integration.component-conflicts',
238
- data: {name, version, conflicts: [], issues},
240
+ data: {validated, name, version, conflicts: [], issues},
239
241
  };
240
242
  }
241
243
 
@@ -249,7 +251,7 @@ export async function integrationComponentConflicts(pkg, options = {}) {
249
251
  });
250
252
  return {
251
253
  type: 'integration.component-conflicts',
252
- data: {name, version, conflicts: [], issues},
254
+ data: {validated, name, version, conflicts: [], issues},
253
255
  };
254
256
  }
255
257
 
@@ -274,7 +276,7 @@ export async function integrationComponentConflicts(pkg, options = {}) {
274
276
 
275
277
  return {
276
278
  type: 'integration.component-conflicts',
277
- data: {name, version, conflicts, issues},
279
+ data: {validated, name, version, conflicts, issues},
278
280
  };
279
281
  }
280
282
 
@@ -287,6 +289,7 @@ export async function integrationComponentConflicts(pkg, options = {}) {
287
289
  export async function integrationDocConflicts(pkg, options = {}) {
288
290
  const {cwd = process.cwd()} = options;
289
291
  const resolved = await resolveIntegration(pkg, cwd);
292
+ const validated = resolved.found;
290
293
  const name = resolved.found ? (resolved.name ?? null) : null;
291
294
  const version = resolved.found ? (resolved.version ?? null) : null;
292
295
  const issues = [...resolved.issues];
@@ -294,7 +297,7 @@ export async function integrationDocConflicts(pkg, options = {}) {
294
297
  if (!resolved.integration?.docs || name == null) {
295
298
  return {
296
299
  type: 'integration.doc-conflicts',
297
- data: {name, version, findings: [], issues},
300
+ data: {validated, name, version, findings: [], issues},
298
301
  };
299
302
  }
300
303
 
@@ -368,11 +371,11 @@ export async function integrationDocConflicts(pkg, options = {}) {
368
371
  // and placed guides this package adds to the docs tree, and every link in
369
372
  // its docs (spec:AST-046, spec:AST-047).
370
373
  if (errors.length === 0) {
371
- for (const message of await packageDocsProblems(
374
+ for (const {severity, message} of await packageDocsProblems(
372
375
  /** @type {{name: string}} */ (resolved.integration),
373
376
  discovered,
374
377
  )) {
375
- issues.push({code: 'invalid_doc_graph', severity: 'warning', message});
378
+ issues.push({code: 'invalid_doc_graph', severity, message});
376
379
  }
377
380
 
378
381
  // A reference block includes content rather than linking to it, so one
@@ -388,6 +391,6 @@ export async function integrationDocConflicts(pkg, options = {}) {
388
391
 
389
392
  return {
390
393
  type: 'integration.doc-conflicts',
391
- data: {name, version, findings, issues},
394
+ data: {validated, name, version, findings, issues},
392
395
  };
393
396
  }
@@ -32,9 +32,15 @@ export type IntegrationDocFinding = {
32
32
  coreTopic: string;
33
33
  message: string;
34
34
  };
35
+ /**
36
+ * Each of the three authoring checks reports `validated`: false means no
37
+ * integration manifest was found, so nothing was inspected and the empty
38
+ * conflicts/findings list carries no information about the package.
39
+ */
35
40
  export type IntegrationTemplateConflictResponse = {
36
41
  type: "integration.template-conflicts";
37
42
  data: {
43
+ validated: boolean;
38
44
  name: string | null;
39
45
  version: string | null;
40
46
  conflicts: IntegrationTemplateConflict[];
@@ -44,6 +50,7 @@ export type IntegrationTemplateConflictResponse = {
44
50
  export type IntegrationComponentConflictResponse = {
45
51
  type: "integration.component-conflicts";
46
52
  data: {
53
+ validated: boolean;
47
54
  name: string | null;
48
55
  version: string | null;
49
56
  conflicts: IntegrationComponentConflict[];
@@ -53,6 +60,7 @@ export type IntegrationComponentConflictResponse = {
53
60
  export type IntegrationDocConflictResponse = {
54
61
  type: "integration.doc-conflicts";
55
62
  data: {
63
+ validated: boolean;
56
64
  name: string | null;
57
65
  version: string | null;
58
66
  findings: IntegrationDocFinding[];
@@ -49,21 +49,25 @@
49
49
  */
50
50
 
51
51
  /**
52
+ * Each of the three authoring checks reports `validated`: false means no
53
+ * integration manifest was found, so nothing was inspected and the empty
54
+ * conflicts/findings list carries no information about the package.
55
+ *
52
56
  * @typedef {object} IntegrationTemplateConflictResponse
53
57
  * @property {'integration.template-conflicts'} type
54
- * @property {{name: string | null, version: string | null, conflicts: IntegrationTemplateConflict[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
58
+ * @property {{validated: boolean, name: string | null, version: string | null, conflicts: IntegrationTemplateConflict[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
55
59
  */
56
60
 
57
61
  /**
58
62
  * @typedef {object} IntegrationComponentConflictResponse
59
63
  * @property {'integration.component-conflicts'} type
60
- * @property {{name: string | null, version: string | null, conflicts: IntegrationComponentConflict[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
64
+ * @property {{validated: boolean, name: string | null, version: string | null, conflicts: IntegrationComponentConflict[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
61
65
  */
62
66
 
63
67
  /**
64
68
  * @typedef {object} IntegrationDocConflictResponse
65
69
  * @property {'integration.doc-conflicts'} type
66
- * @property {{name: string | null, version: string | null, findings: IntegrationDocFinding[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
70
+ * @property {{validated: boolean, name: string | null, version: string | null, findings: IntegrationDocFinding[], issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[]}} data
67
71
  */
68
72
 
69
73
  export {};
@@ -19,7 +19,9 @@ export type IntegrationAddCodemodOptions = IntegrationAddBaseOptions & {
19
19
  to: string;
20
20
  };
21
21
  export type IntegrationAddAgentDocOptions = IntegrationAddBaseOptions;
22
- export type IntegrationAddThemeOptions = IntegrationAddBaseOptions;
22
+ export type IntegrationAddThemeOptions = IntegrationAddBaseOptions & {
23
+ from?: string;
24
+ };
23
25
  /**
24
26
  * Options for the generic `integrationAdd` dispatcher. Prefer a per-kind API
25
27
  * when the contribution kind is known so the accepted options stay narrow.
@@ -54,4 +56,5 @@ export type IntegrationAddData = {
54
56
  files: string[];
55
57
  written: boolean;
56
58
  dryRun: boolean;
59
+ from?: string | undefined;
57
60
  };
@@ -37,7 +37,11 @@
37
37
  */
38
38
 
39
39
  /** @typedef {IntegrationAddBaseOptions} IntegrationAddAgentDocOptions */
40
- /** @typedef {IntegrationAddBaseOptions} IntegrationAddThemeOptions */
40
+ /**
41
+ * @typedef {IntegrationAddBaseOptions & {
42
+ * from?: string,
43
+ * }} IntegrationAddThemeOptions
44
+ */
41
45
 
42
46
  /**
43
47
  * Options for the generic `integrationAdd` dispatcher. Prefer a per-kind API
@@ -73,6 +77,7 @@
73
77
  * @property {string[]} files
74
78
  * @property {boolean} written
75
79
  * @property {boolean} dryRun
80
+ * @property {string} [from]
76
81
  */
77
82
 
78
83
  export {};
@@ -78,6 +78,12 @@ export const doc = {
78
78
  type: 'string',
79
79
  description: 'Exact target semver (e.g. 1.2.0). Required for codemod and only valid there.',
80
80
  },
81
+ {
82
+ name: 'options.from',
83
+ type: 'string',
84
+ description:
85
+ 'Slug of an existing theme to fork as the starting point. Only valid for theme.',
86
+ },
81
87
  ],
82
88
  returns: [
83
89
  {
@@ -33,6 +33,12 @@ export const doc = {
33
33
  'Validate and return the same receipt without writing; data.written is false and data.dryRun is true.',
34
34
  default: 'false',
35
35
  },
36
+ {
37
+ name: 'options.from',
38
+ type: 'string',
39
+ description:
40
+ 'Slug of an existing theme to fork as the starting point. The new theme copies the base and has no link back.',
41
+ },
36
42
  ],
37
43
  returns: [
38
44
  {
@@ -76,6 +82,10 @@ export const doc = {
76
82
  label: 'Add a theme',
77
83
  code: "await integrationAddTheme('ocean');",
78
84
  },
85
+ {
86
+ label: 'Fork an existing theme',
87
+ code: "await integrationAddTheme('ocean', {from: 'neutral'});",
88
+ },
79
89
  {
80
90
  label: 'Preview writes',
81
91
  code: "await integrationAddTheme('ocean', {dryRun: true});",
@@ -26,7 +26,7 @@ export const doc = {
26
26
  {
27
27
  type: 'integration.component-conflicts',
28
28
  description:
29
- 'Integration identity, structural issues, and Core component-name conflicts with package-qualified commands.',
29
+ '`validated` (false when no integration manifest was found, so nothing was inspected), integration identity, structural issues, and Core component-name conflicts with package-qualified commands.',
30
30
  },
31
31
  ],
32
32
  examples: [
@@ -26,7 +26,7 @@ export const doc = {
26
26
  {
27
27
  type: 'integration.doc-conflicts',
28
28
  description:
29
- 'Integration identity, structural issues, and classified Core doc relationships.',
29
+ '`validated` (false when no integration manifest was found, so nothing was inspected), integration identity, structural issues, and classified Core doc relationships.',
30
30
  },
31
31
  ],
32
32
  examples: [
@@ -7,13 +7,13 @@ export const doc = {
7
7
  name: 'integrationPackCheck',
8
8
  namespace: 'cli/api',
9
9
  displayName: 'integrationPackCheck()',
10
- summary: 'Prove an integration package survives npm packing.',
10
+ summary: 'Check an integration package the way npm will publish it.',
11
11
  description:
12
12
  "Validates the local integration, runs the package lifecycle, packs with npm, checks required files against npm's authoritative tarball list, extracts the real tarball into a scratch consumer, compares local and packed contribution inventories, and resolves every packed component through its documented public import to verify that module exports the component. A package that ships a namespace doc or a placed guide, or has a template that sets `replaces`, fails unless its `@astryxdesign/cli` peer range admits only CLIs that read them.",
13
13
  importPath: '@astryxdesign/cli/api',
14
14
  signature:
15
15
  'integrationPackCheck(options?: IntegrationPackCheckOptions): Promise<IntegrationPackCheckResponse>',
16
- keywords: ['integration', 'pack', 'check', 'publish', 'tarball', 'consumer'],
16
+ keywords: ['verify', 'pack', 'publish', 'tarball', 'consumer'],
17
17
  params: [
18
18
  {
19
19
  name: 'options.cwd',
@@ -31,6 +31,6 @@ export const doc = {
31
31
  examples: [
32
32
  {label: 'Check the local package', code: 'await integrationPackCheck();'},
33
33
  ],
34
- command: 'integration pack',
34
+ command: 'integration verify',
35
35
  related: ['integrationAdd', 'validateIntegration'],
36
36
  };
@@ -41,7 +41,7 @@ export const doc = {
41
41
  {
42
42
  type: 'integration.template-conflicts',
43
43
  description:
44
- 'The integration identity, structural issues, and every Core template-id conflict with a package-qualified command.',
44
+ '`validated` (false when no integration manifest was found, so nothing was inspected and the empty conflict list carries no information), the integration identity, structural issues, and every Core template-id conflict with a package-qualified command.',
45
45
  },
46
46
  ],
47
47
  examples: [
@@ -0,0 +1,107 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import {integrationPackCheck} from './pack-check.mjs';
7
+
8
+ let tmpDir;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-pack-check-'));
12
+ });
13
+
14
+ afterEach(() => {
15
+ fs.rmSync(tmpDir, {recursive: true, force: true});
16
+ });
17
+
18
+ /** @param {Record<string, string>} scripts */
19
+ function writeThemePackage(scripts) {
20
+ fs.writeFileSync(
21
+ path.join(tmpDir, 'package.json'),
22
+ `${JSON.stringify(
23
+ {
24
+ name: '@acme/widgets',
25
+ version: '1.0.0',
26
+ files: ['astryx.integration.mjs', 'themes'],
27
+ peerDependencies: {'@astryxdesign/cli': '>=0.7.0'},
28
+ peerDependenciesMeta: {'@astryxdesign/cli': {optional: true}},
29
+ scripts,
30
+ },
31
+ null,
32
+ 2,
33
+ )}\n`,
34
+ );
35
+ fs.writeFileSync(
36
+ path.join(tmpDir, 'astryx.integration.mjs'),
37
+ "export default {themes: './themes'};\n",
38
+ );
39
+ const root = path.join(tmpDir, 'themes');
40
+ fs.mkdirSync(path.join(root, 'ocean'), {recursive: true});
41
+ fs.writeFileSync(
42
+ path.join(root, 'ocean', 'oceanTheme.ts'),
43
+ "import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const oceanTheme = defineTheme({name: 'ocean'});\n",
44
+ );
45
+ fs.writeFileSync(
46
+ path.join(root, 'ocean', 'oceanTheme.doc.mjs'),
47
+ `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */
48
+ export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Ocean theme.', maintained: true};
49
+ `,
50
+ );
51
+ }
52
+
53
+ describe('integrationPackCheck with lifecycle script output', () => {
54
+ it('checks the tarball when lifecycle scripts print to stdout', async () => {
55
+ writeThemePackage({
56
+ prepack: 'node -e "console.log(\'building the package\')"',
57
+ prepare: 'node -e "console.log(\'preparing\')"',
58
+ postpack: 'node -e "console.log(\'packed\')"',
59
+ });
60
+
61
+ const result = await integrationPackCheck({cwd: tmpDir});
62
+
63
+ expect(result.data.issues).toEqual([]);
64
+ expect(result.data.packable).toBe(true);
65
+ expect(result.data.tarball?.filename).toBe('acme-widgets-1.0.0.tgz');
66
+ expect(result.data.contributions.packed).toEqual(
67
+ result.data.contributions.local,
68
+ );
69
+ });
70
+
71
+ it('still runs a chatty lifecycle script and compares what it packed', async () => {
72
+ const renameTheme = [
73
+ "console.log('renaming ocean to storm')",
74
+ "const fs=require('fs')",
75
+ "fs.renameSync('themes/ocean','themes/storm')",
76
+ "const p='themes/storm/oceanTheme.doc.mjs'",
77
+ "let x=fs.readFileSync(p,'utf8')",
78
+ "x=x.replace(/name: 'ocean'/, 'name: '+String.fromCharCode(39)+'storm'+String.fromCharCode(39))",
79
+ 'fs.writeFileSync(p,x)',
80
+ ].join(';');
81
+ writeThemePackage({prepack: `node -e "${renameTheme}"`});
82
+
83
+ const result = await integrationPackCheck({cwd: tmpDir});
84
+ const codes = result.data.issues.map(issue => issue.code);
85
+
86
+ expect(codes).not.toContain('pack_failed');
87
+ expect(codes).toContain('identity_not_packed');
88
+ expect(codes).toContain('packed_identity_unexpected');
89
+ expect(result.data.packable).toBe(false);
90
+ });
91
+
92
+ it('keeps a failing lifecycle script output in the pack_failed issue', async () => {
93
+ writeThemePackage({
94
+ prepack:
95
+ 'node -e "console.error(\'prepack exploded\'); process.exit(3)"',
96
+ });
97
+
98
+ const result = await integrationPackCheck({cwd: tmpDir});
99
+ const failure = result.data.issues.find(
100
+ issue => issue.code === 'pack_failed',
101
+ );
102
+
103
+ expect(result.data.packable).toBe(false);
104
+ expect(failure?.message).toContain('npm pack failed (exit 3)');
105
+ expect(failure?.message).toContain('prepack exploded');
106
+ });
107
+ });
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file `astryx integration pack --check` — verify an integration package is
4
+ * @file `astryx integration verify` — verify an integration package is
5
5
  * ready to publish by cross-referencing its declared contributions against the
6
6
  * real npm tarball.
7
7
  *
@@ -29,9 +29,15 @@ import {assertWithin} from '../../foundation/fs/path-safety.mjs';
29
29
  import {resolvePackageDir} from '../../foundation/integrations/integrations.mjs';
30
30
  import {
31
31
  docsTreeCliProblem,
32
+ keywordsCliProblem,
32
33
  replacesCliProblem,
34
+ sectionIdsCliProblem,
35
+ themesCliProblem,
33
36
  } from '../../foundation/integrations/cli-requirement.mjs';
34
- import {discoverIntegrationDocs} from '../../foundation/discovery/docs-discovery.mjs';
37
+ import {
38
+ discoverIntegrationDocs,
39
+ loadTopicModule,
40
+ } from '../../foundation/discovery/docs-discovery.mjs';
35
41
  import {
36
42
  discoverIntegrationComponents,
37
43
  resolveIntegrationImportPath,
@@ -162,6 +168,22 @@ export function parseNpmPackOutput(output) {
162
168
  };
163
169
  }
164
170
 
171
+ /**
172
+ * Summarize the JSON error npm prints on stdout when `--json` pack fails.
173
+ * @param {string} output
174
+ * @returns {string}
175
+ */
176
+ function npmPackErrorDetail(output) {
177
+ try {
178
+ const error = JSON.parse(output)?.error;
179
+ return [error?.summary, error?.detail]
180
+ .filter(part => typeof part === 'string' && part.trim() !== '')
181
+ .join(': ');
182
+ } catch {
183
+ return (output || '').trim();
184
+ }
185
+ }
186
+
165
187
  /**
166
188
  * Run `npm pack --json` with output directed to `destDir` so no preexisting
167
189
  * tgz is overwritten. This intentionally runs the package lifecycle, matching
@@ -175,16 +197,25 @@ export function parseNpmPackOutput(output) {
175
197
  function runNpmPack(packageDir, destDir) {
176
198
  const result = spawnSync(
177
199
  'npm',
178
- ['pack', '--json', '--silent', `--pack-destination=${destDir}`],
200
+ [
201
+ 'pack',
202
+ '--json',
203
+ '--silent',
204
+ // Lifecycle scripts still run; background mode keeps their output off
205
+ // the stdout that carries the JSON result.
206
+ '--foreground-scripts=false',
207
+ `--pack-destination=${destDir}`,
208
+ ],
179
209
  {cwd: packageDir, encoding: 'utf-8', timeout: 60_000},
180
210
  );
181
211
  if (result.error) {
182
212
  throw new Error(`Could not start npm pack: ${result.error.message}`);
183
213
  }
184
214
  if (result.status !== 0) {
185
- const stderr = (result.stderr || '').trim();
215
+ const detail =
216
+ (result.stderr || '').trim() || npmPackErrorDetail(result.stdout);
186
217
  throw new Error(
187
- `npm pack failed (exit ${result.status})${stderr ? `: ${stderr}` : ''}.`,
218
+ `npm pack failed (exit ${result.status})${detail ? `: ${detail}` : ''}.`,
188
219
  );
189
220
  }
190
221
  return parseNpmPackOutput(result.stdout);
@@ -308,6 +339,23 @@ function moduleExportsName(file, exportName, seen = new Set()) {
308
339
  return found;
309
340
  }
310
341
 
342
+ /**
343
+ * Whether any of these doc files has a section that sets `id`.
344
+ * @param {string[]} files
345
+ * @returns {Promise<boolean>}
346
+ */
347
+ async function setsSectionIds(files) {
348
+ for (const file of files) {
349
+ if (typeof file !== 'string') continue;
350
+ const doc = /** @type {any} */ (await loadTopicModule(file).catch(() => null));
351
+ const sections = Array.isArray(doc?.sections) ? doc.sections : [];
352
+ if (sections.some((/** @type {any} */ section) => section?.id != null)) {
353
+ return true;
354
+ }
355
+ }
356
+ return false;
357
+ }
358
+
311
359
  /**
312
360
  * Resolve package specifiers through Node's real ESM resolver from the scratch
313
361
  * consumer. Resolution does not execute the target module, so source `.tsx`
@@ -600,19 +648,32 @@ export async function integrationPackCheck(options = {}) {
600
648
  // (spec:AST-046 FR11): an older CLI can hide every doc topic the package
601
649
  // ships, so the declared CLI range must admit only CLIs that read it.
602
650
  if (loaded.docs) {
603
- const {namespaces, guides} = await discoverIntegrationDocs(loaded).catch(
604
- () => ({namespaces: [], guides: []}),
605
- );
651
+ const {records, namespaces, guides} = await discoverIntegrationDocs(
652
+ loaded,
653
+ ).catch(() => ({records: [], namespaces: [], guides: []}));
606
654
  const problem =
607
655
  namespaces.length > 0 || guides.length > 0
608
656
  ? docsTreeCliProblem(pkg)
609
657
  : null;
610
658
  if (problem != null) {
611
659
  issues.push(error('docs_tree_needs_cli', problem));
660
+ } else if (
661
+ await setsSectionIds([
662
+ ...records.map(record => record.path),
663
+ ...guides.map(guide => /** @type {any} */ (guide.ref).topicFile),
664
+ ])
665
+ ) {
666
+ // A section `id` is also a field an older CLI rejects, hiding the
667
+ // package's doc topics. It needs an older CLI than the docs tree does.
668
+ const idProblem = sectionIdsCliProblem(pkg);
669
+ if (idProblem != null) {
670
+ issues.push(error('section_ids_need_cli', idProblem));
671
+ }
612
672
  }
613
673
  }
614
- // A template that sets `replaces` needs a CLI that reads the field
615
- // (spec:AST-035): an older CLI withholds the package's templates and docs.
674
+ // A template that sets `replaces` (spec:AST-035) or `keywords` needs a CLI
675
+ // that reads the field: an older CLI drops that template and hides the
676
+ // package's docs.
616
677
  if (loaded.templates) {
617
678
  const found = await discoverIntegrationTemplatesForOne(loaded).catch(
618
679
  () => ({templates: [], errors: []}),
@@ -624,6 +685,19 @@ export async function integrationPackCheck(options = {}) {
624
685
  );
625
686
  const problem = setsReplaces ? replacesCliProblem(pkg) : null;
626
687
  if (problem != null) issues.push(error('replaces_needs_cli', problem));
688
+ const setsKeywords = found.templates.some(
689
+ template => template.keywords != null && template.keywords.length > 0,
690
+ );
691
+ const keywordsProblem = setsKeywords ? keywordsCliProblem(pkg) : null;
692
+ if (keywordsProblem != null) {
693
+ issues.push(error('keywords_needs_cli', keywordsProblem));
694
+ }
695
+ }
696
+ // A theme needs a CLI that reads typed theme descriptors: an older CLI
697
+ // rejects the themes root and withholds the package's themes and docs.
698
+ if (localIdentities.themes.length > 0) {
699
+ const problem = themesCliProblem(pkg);
700
+ if (problem != null) issues.push(error('themes_need_cli', problem));
627
701
  }
628
702
 
629
703
  // Temp resources — always cleaned up
@@ -657,6 +731,14 @@ export async function integrationPackCheck(options = {}) {
657
731
  // package's already-installed dependencies. The unique suffix makes
658
732
  // concurrent checks independent.
659
733
  scratchBase = fs.mkdtempSync(path.join(packageDir, '.astryx-pack-check-'));
734
+ // The consumer's own package.json makes it the package scope for its
735
+ // imports. Without one, Node resolves the package's name through the
736
+ // SOURCE package.json (self-reference), so an export target left out of
737
+ // the tarball would still resolve.
738
+ fs.writeFileSync(
739
+ path.join(scratchBase, 'package.json'),
740
+ `${JSON.stringify({name: 'astryx-verify-consumer', private: true})}\n`,
741
+ );
660
742
 
661
743
  // Cross-reference file inventory vs pack list
662
744
  if (!packResult.packedPaths.has(fileInv.manifest)) {