@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
@@ -44,6 +44,7 @@ export const doc = {
44
44
  type: 'string',
45
45
  description:
46
46
  'Project directory used for integration discovery and target paths.',
47
+ default: 'process.cwd()',
47
48
  },
48
49
  {
49
50
  name: 'options.package',
@@ -57,11 +58,6 @@ export const doc = {
57
58
  description:
58
59
  'Copy receipt with slug, displayName, maintained flag, owner package, outputDir, entry, exportName, and files.',
59
60
  },
60
- {
61
- type: 'theme.list',
62
- description:
63
- 'The CLI list affordance routes a bare `astryx theme add` or `--list` to themeListAvailable() and returns every available theme with its owner.',
64
- },
65
61
  ],
66
62
  throws: [
67
63
  {
@@ -74,7 +70,10 @@ export const doc = {
74
70
  when: 'the selected installed package has a blocking integration or theme-descriptor error',
75
71
  },
76
72
  {code: 'ERR_PATH_TRAVERSAL', when: 'the target path escapes cwd'},
77
- {code: 'ERR_NO_SOURCE', when: 'a theme file to copy is missing'},
73
+ {
74
+ code: 'ERR_NO_SOURCE',
75
+ when: 'the bundled theme descriptors cannot be read, or a theme file to copy is missing',
76
+ },
78
77
  {
79
78
  code: 'ERR_FILE_EXISTS',
80
79
  when: 'a destination exists and overwrite is not set',
@@ -82,12 +81,12 @@ export const doc = {
82
81
  {code: 'ERR_WRITE_FAILED', when: 'writing files fails'},
83
82
  ],
84
83
  examples: [
85
- {label: 'Copy a bundled theme', code: "await themeAdd('ocean');"},
84
+ {label: 'Copy a bundled theme', code: "await themeAdd('butter');"},
86
85
  {
87
- label: 'Copy an integration theme',
88
- code: "await themeAdd('ocean', {package: '@acme/themes'});",
86
+ label: 'Name the owner package and the destination',
87
+ code: "await themeAdd('butter', {package: '@astryxdesign/cli', targetPath: 'src/brand-theme'});",
89
88
  },
90
89
  ],
91
90
  command: 'theme add',
92
- related: ['themeList', 'listThemes'],
91
+ related: ['themeListAvailable', 'themeTemplate', 'listThemes'],
93
92
  };
@@ -14,14 +14,13 @@ export const doc = {
14
14
  name: 'themeBuild',
15
15
  namespace: 'cli/api',
16
16
  displayName: 'themeBuild()',
17
- summary: 'Compile a defineTheme file to CSS + JS + type declarations.',
17
+ summary:
18
+ 'Compile a defineTheme() file to scoped CSS, a JS module, and type declarations, or check committed outputs for drift in CI.',
18
19
  description:
19
- 'The compiler behind `astryx theme build`. Reads a file that calls defineTheme() and, ' +
20
- "via @astryxdesign/core's shared generator (the single source of truth, so the build " +
21
- 'emits the exact CSS the <Theme> runtime does), writes a scoped CSS file, a JS module ' +
22
- 'that re-exports the built theme, and a .d.ts (plus an optional .variants.d.ts when the ' +
23
- 'theme adds custom prop values). When another build step emits the icon registry, ' +
24
- '{iconsSpecifier} declares the fully specified module path for the generated JS import. ' +
20
+ 'The compiler behind `astryx theme build`. Reads a file that calls defineTheme() and ' +
21
+ 'writes a scoped CSS file, a JS module that re-exports the built theme, and a .d.ts ' +
22
+ '(plus an optional .variants.d.ts when the theme adds custom prop values). It uses ' +
23
+ "@astryxdesign/core's own generator, so the CSS matches what the <Theme> runtime emits. " +
25
24
  'With {check: true} it writes nothing and instead compares ' +
26
25
  'each output against disk, returning the drift: the CI guard for committed, generated theme CSS.',
27
26
  importPath: '@astryxdesign/cli/api',
@@ -48,7 +47,7 @@ export const doc = {
48
47
  name: 'options.out',
49
48
  type: 'string',
50
49
  description:
51
- 'Override the output CSS path; the sibling .js and .d.ts derive from it. A relative path must stay within cwd.',
50
+ 'Override the output CSS path. The .js, .d.ts and any .variants.d.ts are written in the same directory, named after the theme (<name>.js), not after the CSS file. A relative path must stay within cwd.',
52
51
  },
53
52
  {
54
53
  name: 'options.check',
@@ -61,13 +60,14 @@ export const doc = {
61
60
  name: 'options.iconsSpecifier',
62
61
  type: 'string',
63
62
  description:
64
- 'Override the icon-registry import specifier in the generated JS module, for example ./icons.mjs. When omitted, the source specifier is preserved.',
63
+ 'Override the import specifier of the icon registry in the generated JS module, for example ./icons.mjs. Takes effect only when the theme sets icons: to a named import; when omitted, the source specifier is kept.',
65
64
  },
66
65
  {
67
66
  name: 'ctx.cwd',
68
67
  type: 'string',
69
68
  description:
70
- 'Directory the theme file and @astryxdesign/core resolve against.',
69
+ 'Directory the theme file, a relative out path, and the returned output paths resolve against.',
70
+ default: 'process.cwd()',
71
71
  },
72
72
  ],
73
73
  returns: [
@@ -79,7 +79,7 @@ export const doc = {
79
79
  {
80
80
  type: 'theme.build.check',
81
81
  description:
82
- 'The {check: true} receipt: theme name, an upToDate flag, the stale outputs (each {path, reason: "missing" | "outdated"}), and the full list of checked paths. Writes nothing.',
82
+ 'The {check: true} receipt: theme name, an upToDate flag, the stale outputs (each {path, reason: "missing" | "outdated"}), and the full list of checked paths. Writes nothing. Resolves to null, like a normal build, when the theme produces no CSS.',
83
83
  },
84
84
  ],
85
85
  throws: [
@@ -102,7 +102,7 @@ export const doc = {
102
102
  },
103
103
  {
104
104
  code: 'ERR_CORE_INCOMPATIBLE',
105
- when: 'the selected theme carries ordered-adaptation intent but the installed @astryxdesign/core does not export generateAdaptationCSS (upgrade core)',
105
+ when: 'the installed @astryxdesign/core does not export generateAdaptationCSS and the theme either declares ordered adaptations or has lineage whose adaptation use could not be observed (upgrade core)',
106
106
  },
107
107
  {
108
108
  code: 'ERR_WRITE_FAILED',
@@ -124,5 +124,5 @@ export const doc = {
124
124
  },
125
125
  ],
126
126
  command: 'theme build',
127
- related: ['themeAdd', 'themeList', 'listThemes'],
127
+ related: ['themeTemplate', 'themeAdd', 'themeListAvailable', 'listThemes'],
128
128
  };
@@ -13,7 +13,7 @@ export const doc = {
13
13
  displayName: 'themeList()',
14
14
  summary: 'List themes bundled with this CLI build.',
15
15
  description:
16
- 'Projects the bundled typed theme descriptors into a synchronous theme.list envelope. This preserves the original programmatic API contract. The CLI command uses themeListAvailable() so installed integrations also appear.',
16
+ 'Synchronous list of the themes bundled with the CLI. It does not include themes from installed integrations; use themeListAvailable() for the list `astryx theme list` shows.',
17
17
  importPath: '@astryxdesign/cli/api',
18
18
  signature: 'themeList(): ThemeListResponse',
19
19
  keywords: ['theme', 'list', 'themes', 'bundled', 'available'],
@@ -13,7 +13,7 @@ export const doc = {
13
13
  displayName: 'themeListAvailable()',
14
14
  summary: 'List bundled and installed integration themes.',
15
15
  description:
16
- 'Loads Project for the requested directory, combines the CLI bundle with source themes from installed integrations, and projects each entry with its owner package. An unreadable project configuration degrades to the bundled descriptors.',
16
+ 'Lists the bundled themes plus source themes from integrations installed in cwd, each with its owner package. If the project configuration cannot be read, it falls back to the bundled themes.',
17
17
  importPath: '@astryxdesign/cli/api',
18
18
  signature:
19
19
  'themeListAvailable(options?: {cwd?: string, package?: string}): Promise<ThemeListResponse>',
@@ -24,6 +24,7 @@ export const doc = {
24
24
  type: 'string',
25
25
  description:
26
26
  'Project directory whose installed integrations contribute themes.',
27
+ default: 'process.cwd()',
27
28
  },
28
29
  {
29
30
  name: 'options.package',
@@ -27,30 +27,34 @@ export const doc = {
27
27
  {
28
28
  name: 'configPath',
29
29
  type: 'string',
30
- description: 'JSON generation request, resolved within cwd.',
30
+ description:
31
+ 'Path to a JSON file holding a TonalPaletteGenerationInput (the object generateTonalPalette() takes), resolved within cwd.',
31
32
  required: true,
32
33
  },
33
34
  {
34
35
  name: 'options.out',
35
36
  type: 'string',
36
37
  description:
37
- 'Optional candidate JSON destination. A sibling .receipt.json path is derived from it.',
38
+ 'Where to write the candidate: a path ending in .ts (a TypeScript module) or .json. A sibling <name>.receipt.json is written next to it.',
38
39
  },
39
40
  {
40
41
  name: 'options.preview',
41
42
  type: 'string',
42
- description: 'Optional path for a self-contained HTML review artifact.',
43
+ description:
44
+ 'Optional path, ending in .html, for a self-contained HTML review page.',
43
45
  },
44
46
  {
45
47
  name: 'options.overwrite',
46
48
  type: 'boolean',
47
- description: 'Replace existing candidate and receipt files.',
49
+ description:
50
+ "Replace existing candidate, receipt and preview files. Without it, if any target exists, nothing is written and the result has written: false, reason: 'exists'.",
48
51
  default: 'false',
49
52
  },
50
53
  {
51
54
  name: 'ctx.cwd',
52
55
  type: 'string',
53
56
  description: 'Directory used to resolve the input and output paths.',
57
+ default: 'process.cwd()',
54
58
  },
55
59
  ],
56
60
  returns: [
@@ -64,17 +68,20 @@ export const doc = {
64
68
  {code: 'ERR_FILE_NOT_FOUND', when: 'the config file does not exist'},
65
69
  {
66
70
  code: 'ERR_PALETTE_GENERATION',
67
- when: 'the request, seed, stop layout, mode, or anchor constraint is invalid',
71
+ when: 'the config is not valid JSON; the request, seed, stop layout, mode or anchor is invalid; out does not end in .ts or .json; or preview does not end in .html',
68
72
  },
69
73
  {
70
74
  code: 'ERR_PATH_TRAVERSAL',
71
75
  when: 'an input or output path escapes cwd, or output would replace input',
72
76
  },
73
- {code: 'ERR_WRITE_FAILED', when: 'the candidate pair cannot be written'},
77
+ {
78
+ code: 'ERR_WRITE_FAILED',
79
+ when: 'the candidate, receipt or preview file cannot be written',
80
+ },
74
81
  ],
75
82
  examples: [
76
83
  {
77
- label: 'Preview a candidate',
84
+ label: 'Generate a candidate without writing files',
78
85
  code: "themePaletteGenerate('palette.config.json');",
79
86
  },
80
87
  {
@@ -83,5 +90,5 @@ export const doc = {
83
90
  },
84
91
  ],
85
92
  command: 'theme palette generate',
86
- related: ['themeBuild', 'themeTemplate'],
93
+ related: ['generateTonalPalette', 'themeBuild', 'themeTemplate'],
87
94
  };
@@ -22,7 +22,7 @@ export const doc = {
22
22
  'Same source as the Theming table `astryx component <Name>` prints ' +
23
23
  '(the component docs), so the list cannot drift from the components, and `theme build` ' +
24
24
  'validates overrides against this exact set. A filter naming a component gives that ' +
25
- "component's set; anything else is a substring search over the keys.",
25
+ "component's set; anything else is a case-insensitive substring search over each target's key, class and component.",
26
26
  importPath: '@astryxdesign/cli/api',
27
27
  signature:
28
28
  'themeTargets(filter?: string, ctx?: {cwd?: string}): Promise<ThemeTargetsResponse>',
@@ -41,13 +41,14 @@ export const doc = {
41
41
  name: 'filter',
42
42
  type: 'string',
43
43
  description:
44
- 'A component name (exact, case-insensitive) or a substring of a target key. Omit for the whole surface.',
44
+ 'A component name (exact, case-insensitive), or a substring of a target key, class or component. Omit for the whole surface.',
45
45
  },
46
46
  {
47
47
  name: 'ctx.cwd',
48
48
  type: 'string',
49
49
  description:
50
50
  "Directory the project's @astryxdesign/core is resolved from.",
51
+ default: 'process.cwd()',
51
52
  },
52
53
  ],
53
54
  returns: [
@@ -43,6 +43,7 @@ export const doc = {
43
43
  name: 'options.cwd',
44
44
  type: 'string',
45
45
  description: 'Directory the target path resolves against.',
46
+ default: 'process.cwd()',
46
47
  },
47
48
  ],
48
49
  returns: [
@@ -64,5 +65,5 @@ export const doc = {
64
65
  },
65
66
  ],
66
67
  command: 'theme template',
67
- related: ['themeAdd', 'themeBuild', 'themeList'],
68
+ related: ['themeAdd', 'themeBuild', 'themeListAvailable', 'themeTargets'],
68
69
  };
@@ -0,0 +1,111 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The upgrade receipt counts a file once when a core codemod AND an
5
+ * integration codemod both change it: `filesChanged` is the union of the two
6
+ * runners' files, while `transformsApplied` adds their changes.
7
+ *
8
+ * Uses a real consumer under a repo-local temp dir (Vite blocks dynamic import
9
+ * of config and integration modules from /tmp), the real core registry, and an
10
+ * installed integration whose code codemod stamps the same file.
11
+ */
12
+
13
+ import {describe, it, expect, afterEach} from 'vitest';
14
+ import * as fs from 'node:fs';
15
+ import * as path from 'node:path';
16
+ import {upgrade} from '../upgrade.mjs';
17
+ import {
18
+ latestVersion,
19
+ versions,
20
+ getTransformsBetween,
21
+ } from '../../../assets/codemods/registry.mjs';
22
+
23
+ const SLOW = 60_000;
24
+
25
+ /** The registry version whose manifest ships the authoring migration. */
26
+ async function authoringTier() {
27
+ const all = await getTransformsBetween('0.0.0', latestVersion);
28
+ const tier = all.find(({transforms}) =>
29
+ transforms.some(t => t.name === 'migrate-authoring-imports'),
30
+ );
31
+ if (!tier) throw new Error('no registry version ships the authoring migration');
32
+ return tier.version;
33
+ }
34
+
35
+ /**
36
+ * A consumer with installed core at the registry's latest version and one
37
+ * old-surface file that the core authoring codemods rewrite.
38
+ * @param {string} dir
39
+ * @param {{integrationCodemod: boolean}} options
40
+ */
41
+ function seed(dir, {integrationCodemod}) {
42
+ fs.writeFileSync(
43
+ path.join(dir, 'package.json'),
44
+ JSON.stringify({name: 'consumer', version: '1.0.0'}),
45
+ );
46
+ const core = path.join(dir, 'node_modules', '@astryxdesign', 'core');
47
+ fs.mkdirSync(core, {recursive: true});
48
+ fs.writeFileSync(
49
+ path.join(core, 'package.json'),
50
+ JSON.stringify({name: '@astryxdesign/core', version: latestVersion}),
51
+ );
52
+ fs.mkdirSync(path.join(dir, 'src'), {recursive: true});
53
+ fs.writeFileSync(
54
+ path.join(dir, 'src', 'Button.doc.mjs'),
55
+ [
56
+ "import {createComponentDoc} from '@astryxdesign/core/authoring';",
57
+ "export default createComponentDoc({name: 'Button', props: []});",
58
+ '',
59
+ ].join('\n'),
60
+ );
61
+ if (!integrationCodemod) return;
62
+ fs.writeFileSync(
63
+ path.join(dir, 'astryx.config.mjs'),
64
+ "export default {integrations: ['@acme/widgets']};\n",
65
+ );
66
+ const pkg = path.join(dir, 'node_modules', '@acme', 'widgets');
67
+ fs.mkdirSync(path.join(pkg, 'codemods', latestVersion), {recursive: true});
68
+ fs.writeFileSync(
69
+ path.join(pkg, 'package.json'),
70
+ JSON.stringify({name: '@acme/widgets', version: '1.0.0'}),
71
+ );
72
+ fs.writeFileSync(
73
+ path.join(pkg, 'astryx.integration.mjs'),
74
+ "export default {codemods: './codemods'};\n",
75
+ );
76
+ fs.writeFileSync(
77
+ path.join(pkg, 'codemods', latestVersion, 'acme-stamp.mjs'),
78
+ "export default {type: 'code', title: 'Stamp', transform: file => (file.source.includes('// acme') ? null : `${file.source}// acme\\n`)};\n",
79
+ );
80
+ }
81
+
82
+ describe('upgrade receipt — filesChanged across core and integration codemods', () => {
83
+ /** @type {string[]} */
84
+ const dirs = [];
85
+ afterEach(() => {
86
+ for (const dir of dirs.splice(0)) fs.rmSync(dir, {recursive: true, force: true});
87
+ });
88
+
89
+ /** @param {{integrationCodemod: boolean}} options */
90
+ async function run(options) {
91
+ const dir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-files-changed-'));
92
+ dirs.push(dir);
93
+ seed(dir, options);
94
+ const tier = await authoringTier();
95
+ const from = versions[versions.indexOf(tier) - 1];
96
+ const res = await upgrade({from, path: 'src'}, {cwd: dir});
97
+ expect(res.type).toBe('upgrade.run');
98
+ return res.data;
99
+ }
100
+
101
+ it('counts a file changed by both a core and an integration codemod once', async () => {
102
+ const coreOnly = await run({integrationCodemod: false});
103
+ expect(coreOnly.filesChanged).toBe(1);
104
+ expect(coreOnly.transformsApplied).toBeGreaterThan(0);
105
+
106
+ const both = await run({integrationCodemod: true});
107
+ expect(both.integrations).toEqual(['@acme/widgets']);
108
+ expect(both.filesChanged).toBe(1);
109
+ expect(both.transformsApplied).toBe(coreOnly.transformsApplied + 1);
110
+ }, SLOW);
111
+ });
@@ -137,6 +137,12 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
137
137
  }
138
138
  const apply = options.apply ?? false;
139
139
 
140
+ // One fact about the resolved source directory, captured before anything
141
+ // runs. `--path` defaults to `./src`, so a project laid out as `app/` (or a
142
+ // typo) skips every code codemod; without this the receipt is byte-identical
143
+ // to a clean, fully migrated project.
144
+ const sourcePathFound = fs.existsSync(path_);
145
+
140
146
  const currentVersion = /** @type {string} */ (options.from);
141
147
  const installed = detectInstalledTargetVersion(cwd);
142
148
  if (!installed) {
@@ -282,6 +288,7 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
282
288
  refreshed: false,
283
289
  action: 'none',
284
290
  },
291
+ sourcePathFound,
285
292
  filesChanged: coreResult?.totalFilesChanged ?? 0,
286
293
  transformsApplied: coreResult?.totalTransformsApplied ?? 0,
287
294
  modifiedFiles: uniqueFiles(coreResult?.changedFiles).map(file =>
@@ -407,6 +414,12 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
407
414
  refreshed: false,
408
415
  action: 'none',
409
416
  }),
417
+ // A missing source directory is the one way this command can migrate
418
+ // nothing and still look complete: every codemod is skipped, filesChanged
419
+ // stays 0, and errors stays empty. The receipt carries the fact so a
420
+ // machine consumer can tell "nothing needed changing" from "nothing was
421
+ // ever read" — the human text says so via the runner's own error line.
422
+ sourcePathFound,
410
423
  };
411
424
 
412
425
  let integrationResult = null;
@@ -437,9 +450,11 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
437
450
 
438
451
  const registryResult = await reconcileCompositions();
439
452
 
440
- const mergedFilesChanged =
441
- (coreResult?.totalFilesChanged ?? 0) +
442
- (integrationResult?.totalFilesChanged ?? 0);
453
+ // A file a core codemod AND an integration codemod both changed is one file.
454
+ const mergedFilesChanged = new Set([
455
+ ...(coreResult?.changedFiles ?? []),
456
+ ...(integrationResult?.changedFiles ?? []),
457
+ ]).size;
443
458
  const mergedTransformsApplied =
444
459
  (coreResult?.totalTransformsApplied ?? 0) +
445
460
  (integrationResult?.totalTransformsApplied ?? 0);
@@ -640,12 +655,16 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
640
655
  }
641
656
 
642
657
  const registryOk = receipt.registryCompositions?.ok ?? true;
658
+ const done = apply ? 'Upgrade complete' : 'Dry run complete';
643
659
  logger.log(
644
660
  protectedFiles.length > 0
645
661
  ? 'Upgrade incomplete: protected changes remain\n'
646
- : registryOk
647
- ? (apply ? 'Upgrade complete' : 'Dry run complete') + '\n'
648
- : 'Upgrade finished with unresolved registry items\n',
662
+ : !registryOk
663
+ ? 'Upgrade finished with unresolved registry items\n'
664
+ : sourcePathFound
665
+ ? done + '\n'
666
+ : `${done}, but ${path.relative(cwd, path_) || '.'} does not exist, so no source files were scanned. ` +
667
+ `Pass --path <your source directory> if your code does not live in ./src.\n`,
649
668
  );
650
669
  return {
651
670
  type: 'upgrade.run',
@@ -3,7 +3,8 @@
3
3
  /**
4
4
  * @file Colocated tests for the upgrade.run leaf — the --path scan dir must be
5
5
  * confined to cwd (upgrade rewrites source in place with --apply, so an escaping
6
- * or out-of-tree path must be rejected).
6
+ * or out-of-tree path must be rejected), and the receipt must say whether that
7
+ * dir existed at all.
7
8
  */
8
9
 
9
10
  import {describe, it, expect, beforeEach, afterEach} from 'vitest';
@@ -51,3 +52,46 @@ describe('upgrade.run — --path confinement', () => {
51
52
  ).rejects.toMatchObject({code: 'ERR_PATH_TRAVERSAL'});
52
53
  }, SLOW);
53
54
  });
55
+
56
+ describe('upgrade.run — sourcePathFound', () => {
57
+ let dir;
58
+ beforeEach(() => {
59
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'upg-srcpath-'));
60
+ seedProject(dir);
61
+ });
62
+ afterEach(() => fs.rmSync(dir, {recursive: true, force: true}));
63
+
64
+ // The receipt for a project whose source lives somewhere other than ./src was
65
+ // byte-identical to a fully migrated one: exit 0, filesChanged 0, errors [].
66
+ // The only signal was a human log line --json suppresses by design.
67
+ it('reports false when the resolved source directory is missing, and still counts nothing', async () => {
68
+ fs.rmSync(path.join(dir, 'src'), {recursive: true, force: true});
69
+ fs.mkdirSync(path.join(dir, 'app'), {recursive: true});
70
+ fs.writeFileSync(path.join(dir, 'app', 'index.ts'), 'const x = 1;\n');
71
+
72
+ const res = await upgrade({from: '0.0.1', apply: true}, {cwd: dir});
73
+
74
+ expect(res.type).toBe('upgrade.run');
75
+ expect(res.data.sourcePathFound).toBe(false);
76
+ expect(res.data.filesChanged).toBe(0);
77
+ expect(res.data.errors).toEqual([]);
78
+ }, SLOW);
79
+
80
+ it('reports true for a source directory that exists', async () => {
81
+ const res = await upgrade({from: '0.0.1', apply: true}, {cwd: dir});
82
+
83
+ expect(res.type).toBe('upgrade.run');
84
+ expect(res.data.sourcePathFound).toBe(true);
85
+ }, SLOW);
86
+
87
+ it('follows --path, so the right directory under another name reports true', async () => {
88
+ fs.rmSync(path.join(dir, 'src'), {recursive: true, force: true});
89
+ fs.mkdirSync(path.join(dir, 'app'), {recursive: true});
90
+ fs.writeFileSync(path.join(dir, 'app', 'index.ts'), 'const x = 1;\n');
91
+
92
+ const res = await upgrade({from: '0.0.1', path: 'app'}, {cwd: dir});
93
+
94
+ expect(res.type).toBe('upgrade.run');
95
+ expect(res.data.sourcePathFound).toBe(true);
96
+ }, SLOW);
97
+ });
@@ -13,19 +13,16 @@ export const doc = {
13
13
  name: 'upgrade',
14
14
  namespace: 'cli/api',
15
15
  displayName: 'upgrade()',
16
- summary: 'Run version migrations and reconcile copied compositions.',
16
+ summary:
17
+ 'After bumping @astryxdesign/core, migrate project source with codemods and update copied compositions.',
17
18
  description:
18
- 'Migrates project source from a previous Astryx version to the currently ' +
19
- 'installed one by running the registered codemods, and compares the fully ' +
20
- 'rendered managed agent-docs block on every migration path, including ' +
21
- 'same-Core integration guidance changes; list and registry-only modes do not ' +
22
- 'run migration reconciliation. Dry-run previews without writing; `apply` ' +
23
- 'writes the prepared block only after selected codemods and hooks succeed. ' +
24
- 'Core codemods run before ' +
25
- 'the config is loaded so a config codemod can repair an otherwise-invalid ' +
26
- 'astryx.config. Copied compositions carry adjacent receipts with exact canonical and format-specific install bases; upgrade ' +
27
- 'compares those installed bases with the matching registry release, updates pristine ' +
28
- 'files, merges non-overlapping edits, and leaves conflicting originals untouched.',
19
+ 'Runs the codemods between `from` and the installed Core version, then refreshes the ' +
20
+ 'managed agent-docs block. Dry-run by default; `apply` writes changes only after the ' +
21
+ 'selected codemods and hooks succeed. Config codemods run before astryx.config is ' +
22
+ 'loaded, so they can repair an invalid config. Also updates copied compositions from ' +
23
+ 'their install receipts: unchanged files are updated, non-overlapping edits are merged, ' +
24
+ 'and conflicts are left untouched. `list` only lists codemods; `registry` only updates ' +
25
+ 'copied compositions.',
29
26
  importPath: '@astryxdesign/cli/api',
30
27
  signature:
31
28
  'upgrade(options?: UpgradeOptions, ctx?: {cwd?: string}): Promise<UpgradeListResponse | UpgradeRegistryResponse | UpgradeStatusResponse | UpgradeRunResponse>',
@@ -42,7 +39,7 @@ export const doc = {
42
39
  name: 'options.from',
43
40
  type: 'string',
44
41
  description:
45
- 'Version before the dependency bump. Required unless `list` or `registry` is set.',
42
+ 'Version before the dependency bump; the target is the installed @astryxdesign/core (or legacy @xds/core). Required unless `list` or `registry` is set.',
46
43
  },
47
44
  {
48
45
  name: 'options.apply',
@@ -55,11 +52,13 @@ export const doc = {
55
52
  type: 'boolean',
56
53
  description:
57
54
  'Run codemods even when `from` is at/after the installed version.',
55
+ default: 'false',
58
56
  },
59
57
  {
60
58
  name: 'options.codemod',
61
59
  type: 'string',
62
- description: 'Run a single named transform instead of the full set.',
60
+ description:
61
+ 'Run only this codemod. Optional codemods run only when named here. Setting it also skips copied-composition reconciliation.',
63
62
  },
64
63
  {
65
64
  name: 'options.skipCodemod',
@@ -83,23 +82,26 @@ export const doc = {
83
82
  type: 'boolean',
84
83
  description:
85
84
  'Install jscodeshift when it is missing; otherwise a missing jscodeshift throws ERR_DEP_MISSING.',
85
+ default: 'false',
86
86
  },
87
87
  {
88
88
  name: 'options.registry',
89
89
  type: 'boolean',
90
90
  description:
91
- 'Reconcile copied compositions from their install receipts without requiring `from`.',
91
+ 'Only reconcile copied compositions from their install receipts; `from` is not required. Cannot be combined with `list`, `from`, `force`, `codemod`, `skipCodemod`, `integration` or `installDeps`.',
92
92
  default: 'false',
93
93
  },
94
94
  {
95
95
  name: 'options.list',
96
96
  type: 'boolean',
97
97
  description: 'Return the available codemods instead of running any.',
98
+ default: 'false',
98
99
  },
99
100
  {
100
101
  name: 'ctx.cwd',
101
102
  type: 'string',
102
103
  description: 'Directory to run the upgrade in.',
104
+ default: 'process.cwd()',
103
105
  },
104
106
  ],
105
107
  returns: [
@@ -116,36 +118,36 @@ export const doc = {
116
118
  {
117
119
  type: 'upgrade.status',
118
120
  description:
119
- 'A short-circuit outcome (no codemods executed): `up_to_date` (`from` is at/after the installed target and no `force`), `no_codemods` (none apply to the range), or `config_fixable` (dry-run preview that a pending config codemod would repair an invalid astryx.config). Each carries the agent-docs summary and, when found, the copied-composition registry summary.',
121
+ 'A short-circuit outcome (no codemods executed): `up_to_date` (`from` is at/after the installed target and no `force`), `no_codemods` (none apply to the range), or `config_fixable` (dry-run preview that a pending config codemod would repair an invalid astryx.config). up_to_date and no_codemods carry the agent-docs summary and, when receipts are found, the copied-composition summary; config_fixable carries configError, configCodemods, suggestedCommand, message, note, and the agent-docs summary.',
120
122
  },
121
123
  {
122
124
  type: 'upgrade.run',
123
125
  description:
124
- 'The terminal run receipt: from/to versions, codemod count, integrations processed, agent-docs and registry summaries, modifiedFiles, protectedFiles, declinedCandidates, and completion state. A protected required change returns complete: false with ERR_CODEMOD_PROTECTED; the CLI exits nonzero while preserving the structured receipt.',
126
+ 'The terminal run receipt: from, to, codemods (count), integrations, agentDocs, agentDocsRefreshed, registryCompositions (when receipts are found), sourcePathFound (false when the resolved `path` does not exist, so nothing was scanned), filesChanged, transformsApplied, modifiedFiles, protectedFiles, declinedCandidates, errors, and complete. When a protected file still requires a change, complete is false and errorCode is ERR_CODEMOD_PROTECTED; the CLI exits nonzero while preserving the structured receipt.',
125
127
  },
126
128
  ],
127
129
  throws: [
128
130
  {
129
131
  code: 'ERR_INVALID_ARGUMENT',
130
- when: '`from` is missing (and neither `list` nor `registry` is set), or the project config fails strict validation and no pending config codemod can repair it',
132
+ when: '`from` is missing (and neither `list` nor `registry` is set); `list` and `registry` are both set; `registry` is combined with `from`, `force`, `codemod`, `skipCodemod`, `integration` or `installDeps`; an `integration` specifier is invalid or not installed; or astryx.config fails to load or validate and no pending config codemod repairs it',
131
133
  },
132
134
  {code: 'ERR_INVALID_VERSION', when: '`from` is not a valid semver string'},
133
135
  {code: 'ERR_PATH_TRAVERSAL', when: '`path` resolves outside cwd'},
134
136
  {
135
137
  code: 'ERR_VERSION_DETECT',
136
- when: 'the installed @astryxdesign/core version cannot be detected',
138
+ when: 'neither @astryxdesign/core nor legacy @xds/core is installed in cwd; with `registry`, only when copied-composition receipts exist and @astryxdesign/core is not installed',
137
139
  },
138
140
  {
139
141
  code: 'ERR_DEP_MISSING',
140
- when: 'jscodeshift is required but could not be installed',
142
+ when: 'jscodeshift is missing and `installDeps` is not set, or installing it failed',
141
143
  },
142
144
  {
143
145
  code: 'ERR_UNKNOWN_CODEMOD',
144
- when: 'a `codemod` name matches no registered codemod',
146
+ when: 'the version range has codemods but none remain selected: `codemod` names no codemod in the range, or `skipCodemod` excludes all of them',
145
147
  },
146
148
  {
147
149
  code: 'ERR_CODEMOD_FAILED',
148
- when: 'one or more codemods failed, or a post-codemod hook failed',
150
+ when: 'one or more codemods failed, or a post-codemod hook failed, and no protected file still needs a change (otherwise an upgrade.run receipt with complete: false is returned)',
149
151
  },
150
152
  {
151
153
  code: 'ERR_CODEMOD_PROTECTION_SOURCE',
@@ -168,6 +168,7 @@ export type UpgradeRunResponse = {
168
168
  integrations: string[];
169
169
  agentDocsRefreshed: boolean;
170
170
  agentDocs: AgentDocsSummary;
171
+ sourcePathFound: boolean;
171
172
  registryCompositions?: RegistryCompositionSummary | undefined;
172
173
  complete?: boolean | undefined;
173
174
  errorCode?: "ERR_CODEMOD_PROTECTED" | undefined;