@astryxdesign/cli 0.6.3-canary.98a2e4e → 0.6.3-canary.9c4d44d

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 (612) hide show
  1. package/README.md +117 -79
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/_adapter.d.mts +50 -0
  4. package/api/build/_adapter.mjs +60 -0
  5. package/api/build/build.doc.mjs +16 -9
  6. package/api/build/build.test.mjs +197 -8
  7. package/api/build/build.type.d.mts +91 -2
  8. package/api/build/build.type.mjs +52 -8
  9. package/api/build/help/help.d.mts +12 -5
  10. package/api/build/help/help.mjs +69 -6
  11. package/api/build/kit/kit.d.mts +4 -1
  12. package/api/build/kit/kit.mjs +165 -49
  13. package/api/build/kit/rank.d.mts +44 -0
  14. package/api/build/kit/rank.mjs +432 -0
  15. package/api/build/kit/rank.test.mjs +196 -0
  16. package/api/component/_adapter.d.mts +6 -12
  17. package/api/component/_adapter.mjs +20 -10
  18. package/api/component/component.doc.mjs +13 -3
  19. package/api/component/component.mjs +91 -14
  20. package/api/component/component.test.mjs +38 -0
  21. package/api/component/component.type.d.mts +22 -11
  22. package/api/component/component.type.mjs +32 -24
  23. package/api/component/detail/blocks/blocks.d.mts +2 -1
  24. package/api/component/detail/blocks/blocks.mjs +4 -3
  25. package/api/component/list/list.d.mts +0 -5
  26. package/api/component/list/list.mjs +40 -11
  27. package/api/discover/_adapter.d.mts +114 -6
  28. package/api/discover/_adapter.mjs +372 -17
  29. package/api/discover/_adapter.test.mjs +215 -0
  30. package/api/discover/_catalog-view.d.mts +115 -0
  31. package/api/discover/_catalog-view.mjs +203 -0
  32. package/api/discover/_catalog-view.test.mjs +128 -0
  33. package/api/discover/detail/detail.d.mts +18 -6
  34. package/api/discover/detail/detail.mjs +67 -13
  35. package/api/discover/detail/detail.test.mjs +85 -0
  36. package/api/discover/detail/item/item.d.mts +26 -0
  37. package/api/discover/detail/item/item.mjs +78 -0
  38. package/api/discover/detail/item/item.test.mjs +73 -0
  39. package/api/discover/discover.d.mts +3 -9
  40. package/api/discover/discover.doc.mjs +62 -18
  41. package/api/discover/discover.mjs +220 -36
  42. package/api/discover/discover.test.mjs +11 -2
  43. package/api/discover/discover.type.d.mts +150 -11
  44. package/api/discover/discover.type.mjs +107 -17
  45. package/api/discover/list/list.d.mts +20 -6
  46. package/api/discover/list/list.mjs +45 -12
  47. package/api/discover/list/list.test.mjs +46 -0
  48. package/api/discover/search/search.d.mts +18 -16
  49. package/api/discover/search/search.mjs +102 -56
  50. package/api/discover/search/search.test.mjs +144 -10
  51. package/api/docs/_adapter.d.mts +268 -47
  52. package/api/docs/_adapter.mjs +970 -149
  53. package/api/docs/compiled-topics.test.mjs +78 -0
  54. package/api/docs/detail/detail.d.mts +0 -15
  55. package/api/docs/detail/detail.mjs +22 -78
  56. package/api/docs/detail/section/section.mjs +39 -24
  57. package/api/docs/detail/section/section.test.mjs +19 -9
  58. package/api/docs/docs.d.mts +5 -3
  59. package/api/docs/docs.doc.mjs +39 -17
  60. package/api/docs/docs.mjs +44 -8
  61. package/api/docs/docs.test.mjs +158 -4
  62. package/api/docs/docs.type.d.mts +185 -6
  63. package/api/docs/docs.type.mjs +127 -13
  64. package/api/docs/index/index.mjs +15 -6
  65. package/api/docs/index/index.test.mjs +1 -1
  66. package/api/docs/integration-tree.test.mjs +555 -0
  67. package/api/docs/integrationDocs.test.mjs +14 -14
  68. package/api/docs/list/list.mjs +28 -12
  69. package/api/docs/node/node.d.mts +43 -0
  70. package/api/docs/node/node.mjs +192 -0
  71. package/api/docs/reference-blocks.test.mjs +406 -0
  72. package/api/doctor/doctor.d.mts +54 -4
  73. package/api/doctor/doctor.doc.mjs +1 -0
  74. package/api/doctor/doctor.mjs +332 -21
  75. package/api/doctor/doctor.test.mjs +420 -7
  76. package/api/gap-report/gap-report.doc.mjs +8 -4
  77. package/api/hook/_adapter.mjs +19 -5
  78. package/api/hook/hook.doc.mjs +1 -0
  79. package/api/hook/hook.type.d.mts +3 -3
  80. package/api/hook/hook.type.mjs +11 -11
  81. package/api/hook/list/list.d.mts +1 -1
  82. package/api/hook/list/list.mjs +69 -17
  83. package/api/index.d.mts +1 -1
  84. package/api/index.mjs +1 -0
  85. package/api/init/init.doc.mjs +6 -1
  86. package/api/init/init.test.mjs +41 -1
  87. package/api/init/remove/remove.mjs +1 -1
  88. package/api/init/run/run.mjs +20 -10
  89. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  90. package/api/integration/add-contribution.d.mts +2 -1
  91. package/api/integration/add-contribution.mjs +130 -15
  92. package/api/integration/add-contribution.test.mjs +258 -7
  93. package/api/integration/add-helpers.d.mts +5 -2
  94. package/api/integration/add-helpers.mjs +36 -9
  95. package/api/integration/add-theme.mjs +34 -64
  96. package/api/integration/add-theme.test.mjs +105 -21
  97. package/api/integration/authoring-checks.mjs +138 -28
  98. package/api/integration/authoring-checks.test.mjs +179 -7
  99. package/api/integration/authoring-checks.type.mjs +6 -1
  100. package/api/integration/integration-authoring.type.d.mts +2 -0
  101. package/api/integration/integration-authoring.type.mjs +2 -0
  102. package/api/integration/integration-block-exports.test.mjs +10 -6
  103. package/api/integration/integrationAdd.doc.mjs +14 -4
  104. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  105. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  106. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  107. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  108. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  109. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  110. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  111. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  112. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  113. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  114. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  115. package/api/integration/pack-check.mjs +83 -7
  116. package/api/integration/pack-check.test.mjs +387 -47
  117. package/api/integration/pack-check.type.d.mts +26 -2
  118. package/api/integration/pack-check.type.mjs +14 -1
  119. package/api/integration/summarizeIssues.doc.mjs +1 -0
  120. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  121. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  122. package/api/integration/validate-integration.mjs +52 -102
  123. package/api/integration/validate-integration.test.mjs +179 -26
  124. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  125. package/api/integration/validateIntegration.doc.mjs +3 -2
  126. package/api/json/assertResponse.doc.mjs +1 -0
  127. package/api/json/envelope-types.test.mjs +76 -0
  128. package/api/json/index.ts +2 -0
  129. package/api/json/isError.doc.mjs +1 -0
  130. package/api/json/parseResponse.doc.mjs +3 -2
  131. package/api/layout/_adapter.mjs +20 -5
  132. package/api/layout/expand/expand.mjs +7 -5
  133. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  134. package/api/layout/grammar/grammar.mjs +2 -1
  135. package/api/layout/layoutCheck.doc.mjs +1 -0
  136. package/api/layout/layoutExpand.doc.mjs +2 -1
  137. package/api/layout/layoutGrammar.doc.mjs +1 -0
  138. package/api/search/search-return-type.test.mjs +54 -0
  139. package/api/search/search.d.mts +61 -10
  140. package/api/search/search.doc.mjs +8 -2
  141. package/api/search/search.mjs +471 -83
  142. package/api/search/search.test.mjs +124 -1
  143. package/api/search/search.type.d.mts +14 -2
  144. package/api/search/search.type.mjs +5 -2
  145. package/api/swizzle/copy/copy.mjs +28 -11
  146. package/api/swizzle/swizzle.doc.mjs +2 -1
  147. package/api/swizzle/swizzle.type.d.mts +2 -2
  148. package/api/swizzle/swizzle.type.mjs +2 -2
  149. package/api/template/copy/copy.mjs +17 -23
  150. package/api/template/copy/copy.test.mjs +17 -0
  151. package/api/template/list/list.mjs +1 -0
  152. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  153. package/api/template/template-integration.test.mjs +1072 -3
  154. package/api/template/template-suffix.test.mjs +41 -21
  155. package/api/template/template.doc.mjs +30 -8
  156. package/api/template/template.mjs +45 -8
  157. package/api/template/template.type.d.mts +11 -13
  158. package/api/template/template.type.mjs +15 -14
  159. package/api/theme/_adapter.d.mts +2 -3
  160. package/api/theme/_adapter.mjs +4 -5
  161. package/api/theme/add/add.binary.test.mjs +84 -0
  162. package/api/theme/add/add.mjs +31 -22
  163. package/api/theme/add/add.rollback.test.mjs +158 -0
  164. package/api/theme/add/add.staging.test.mjs +83 -0
  165. package/api/theme/add/add.test.mjs +14 -1
  166. package/api/theme/build/build.family.test.mjs +7 -12
  167. package/api/theme/build/build.mjs +140 -59
  168. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  169. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  170. package/api/theme/build/build.rollback.test.mjs +148 -0
  171. package/api/theme/build/build.test.mjs +127 -0
  172. package/api/theme/build/font-warning.mjs +3 -3
  173. package/api/theme/build/font-warning.test.mjs +5 -2
  174. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  175. package/api/theme/integration-themes.test.mjs +39 -28
  176. package/api/theme/list/list.test.mjs +19 -20
  177. package/api/theme/listThemes.doc.mjs +6 -5
  178. package/api/theme/palette/generate/generate.mjs +8 -3
  179. package/api/theme/palette/generate/generate.test.mjs +96 -0
  180. package/api/theme/palette/generate/generator.d.mts +10 -13
  181. package/api/theme/palette/generate/generator.mjs +15 -4
  182. package/api/theme/palette/generate/generator.test.mjs +10 -0
  183. package/api/theme/template/template.mjs +11 -2
  184. package/api/theme/template/template.test.mjs +20 -0
  185. package/api/theme/theme.type.d.mts +170 -11
  186. package/api/theme/theme.type.mjs +94 -27
  187. package/api/theme/themeAdd.doc.mjs +4 -3
  188. package/api/theme/themeBuild.doc.mjs +8 -4
  189. package/api/theme/themeList.doc.mjs +6 -3
  190. package/api/theme/themeListAvailable.doc.mjs +5 -3
  191. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  192. package/api/theme/themeTargets.doc.mjs +1 -0
  193. package/api/theme/themeTemplate.doc.mjs +6 -2
  194. package/api/upgrade/_adapter.d.mts +32 -5
  195. package/api/upgrade/_adapter.mjs +124 -73
  196. package/api/upgrade/list/list.mjs +2 -1
  197. package/api/upgrade/list/list.test.mjs +73 -0
  198. package/api/upgrade/provider-agreement.test.mjs +152 -0
  199. package/api/upgrade/run/run.mjs +356 -59
  200. package/api/upgrade/status/status.mjs +2 -2
  201. package/api/upgrade/upgrade.doc.mjs +8 -2
  202. package/api/upgrade/upgrade.type.d.mts +42 -4
  203. package/api/upgrade/upgrade.type.mjs +26 -10
  204. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  205. package/assets/codemods/integration-discovery.mjs +48 -4
  206. package/assets/codemods/integration-discovery.test.mjs +73 -0
  207. package/assets/codemods/integration-runner.mjs +56 -4
  208. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  209. package/assets/codemods/run-codemod.mjs +177 -34
  210. package/assets/codemods/runner.mjs +350 -102
  211. package/assets/codemods/term-log.mjs +32 -8
  212. package/assets/codemods/term-log.test.mjs +19 -1
  213. package/assets/codemods/transform-prop.mjs +109 -0
  214. package/assets/codemods/transform-prop.test.mjs +95 -0
  215. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  216. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  217. package/assets/codemods/transforms/next/index.mjs +19 -1
  218. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  219. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  220. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  221. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  222. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  223. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  224. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  225. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  226. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  227. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  228. package/assets/docs/getting-started.doc.mjs +2 -2
  229. package/assets/docs/internationalization.doc.mjs +7 -5
  230. package/assets/docs/layout.doc.dense.mjs +2 -2
  231. package/assets/docs/layout.doc.mjs +1 -1
  232. package/assets/docs/principles.doc.mjs +6 -6
  233. package/assets/docs/styling-libraries.doc.mjs +4 -4
  234. package/assets/docs/styling.doc.mjs +4 -4
  235. package/assets/docs/theme.doc.mjs +5 -5
  236. package/assets/docs/tokens.doc.mjs +1 -1
  237. package/assets/docs/tree/api.doc.mjs +30 -0
  238. package/assets/docs/tree/cli.doc.mjs +23 -0
  239. package/assets/docs/tree/commands.doc.mjs +25 -0
  240. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +95 -39
  241. package/assets/docs/tree/integrations.test.mjs +62 -0
  242. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  243. package/assets/docs/working-with-ai.doc.mjs +4 -4
  244. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  245. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  246. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  247. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  248. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  249. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  250. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  251. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  252. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  253. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  254. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  255. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  256. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  257. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  258. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  259. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  260. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  261. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  262. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  263. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  264. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  265. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  266. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  267. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  268. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  269. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  270. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  271. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  272. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  273. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  274. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  275. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  276. package/authoring/_shared/contract.ts +22 -0
  277. package/authoring/codemod/codemod.doc.mjs +7 -2
  278. package/authoring/codemod/parse.d.mts +8 -8
  279. package/authoring/codemod/parse.mjs +8 -6
  280. package/authoring/codemod/type.ts +12 -0
  281. package/authoring/config/config.doc.mjs +10 -2
  282. package/authoring/config/debug-composition.test.mjs +92 -0
  283. package/authoring/config/parse.d.mts +15 -13
  284. package/authoring/config/parse.mjs +27 -8
  285. package/authoring/config/parse.test.mjs +8 -0
  286. package/authoring/config/type.ts +29 -6
  287. package/authoring/debug/debug.doc.d.mts +11 -0
  288. package/authoring/debug/debug.doc.mjs +182 -0
  289. package/authoring/debug/parse.d.mts +7 -7
  290. package/authoring/debug/parse.mjs +3 -3
  291. package/authoring/discover/discover.doc.d.mts +13 -0
  292. package/authoring/discover/discover.doc.mjs +138 -0
  293. package/authoring/discover/parse.d.mts +24 -0
  294. package/authoring/discover/parse.mjs +128 -0
  295. package/authoring/discover/parse.test.mjs +124 -0
  296. package/authoring/discover/type.ts +87 -0
  297. package/authoring/doctypes/_schema.d.mts +240 -128
  298. package/authoring/doctypes/_schema.mjs +198 -16
  299. package/authoring/doctypes/base/graph-fields.doc.mjs +15 -6
  300. package/authoring/doctypes/base/type.ts +9 -4
  301. package/authoring/doctypes/command/command.doc.mjs +4 -3
  302. package/authoring/doctypes/command/parse.d.mts +2 -2
  303. package/authoring/doctypes/command/parse.mjs +1 -1
  304. package/authoring/doctypes/command/type.ts +4 -4
  305. package/authoring/doctypes/component/component.doc.mjs +5 -2
  306. package/authoring/doctypes/component/parse.d.mts +2 -2
  307. package/authoring/doctypes/component/parse.mjs +1 -1
  308. package/authoring/doctypes/component/type.ts +3 -3
  309. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  310. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  311. package/authoring/doctypes/enum/parse.d.mts +2 -2
  312. package/authoring/doctypes/enum/parse.mjs +1 -1
  313. package/authoring/doctypes/enum/type.ts +2 -2
  314. package/authoring/doctypes/function/function.doc.mjs +7 -2
  315. package/authoring/doctypes/function/parse.d.mts +2 -2
  316. package/authoring/doctypes/function/parse.mjs +1 -1
  317. package/authoring/doctypes/function/type.ts +4 -3
  318. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  319. package/authoring/doctypes/hook/parse.d.mts +2 -2
  320. package/authoring/doctypes/hook/parse.mjs +1 -1
  321. package/authoring/doctypes/hook/type.ts +3 -3
  322. package/authoring/doctypes/legacy.d.mts +6 -6
  323. package/authoring/doctypes/legacy.mjs +3 -3
  324. package/authoring/doctypes/load-contract.test.mjs +233 -0
  325. package/authoring/doctypes/namespace/namespace.doc.mjs +9 -9
  326. package/authoring/doctypes/namespace/parse.d.mts +2 -2
  327. package/authoring/doctypes/namespace/parse.mjs +1 -1
  328. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  329. package/authoring/doctypes/namespace/type.ts +6 -3
  330. package/authoring/doctypes/parse.d.mts +22 -20
  331. package/authoring/doctypes/parse.mjs +19 -14
  332. package/authoring/doctypes/reference/parse.d.mts +2 -2
  333. package/authoring/doctypes/reference/parse.mjs +1 -1
  334. package/authoring/doctypes/reference/reference.doc.mjs +39 -6
  335. package/authoring/doctypes/reference/type.ts +31 -14
  336. package/authoring/doctypes/schema/parse.d.mts +2 -2
  337. package/authoring/doctypes/schema/parse.mjs +1 -1
  338. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  339. package/authoring/doctypes/schema/type.ts +3 -4
  340. package/authoring/doctypes/template/parse.d.mts +94 -1
  341. package/authoring/doctypes/template/parse.mjs +37 -1
  342. package/authoring/doctypes/template/parse.test.mjs +18 -0
  343. package/authoring/doctypes/template/template.doc.mjs +13 -3
  344. package/authoring/doctypes/template/type.ts +12 -1
  345. package/authoring/doctypes/theme/parse.d.mts +35 -0
  346. package/authoring/doctypes/theme/parse.mjs +76 -0
  347. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  348. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  349. package/authoring/doctypes/theme/type.ts +42 -0
  350. package/authoring/doctypes/types.ts +12 -11
  351. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  352. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  353. package/authoring/gap-report/parse.d.mts +9 -9
  354. package/authoring/gap-report/parse.mjs +6 -6
  355. package/authoring/gap-report/type.ts +1 -1
  356. package/authoring/identity/identity.doc.mjs +3 -2
  357. package/authoring/identity/type.ts +10 -10
  358. package/authoring/index.d.mts +2 -0
  359. package/authoring/index.d.ts +32 -19
  360. package/authoring/index.mjs +3 -1
  361. package/authoring/integration/integration.doc.mjs +2 -2
  362. package/authoring/integration/parse.d.mts +2 -2
  363. package/authoring/integration/parse.mjs +1 -1
  364. package/authoring/integration/schema.d.mts +4 -4
  365. package/authoring/integration/schema.mjs +3 -3
  366. package/authoring/integration/type.ts +5 -11
  367. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  368. package/clients/cli/command-load-failure.test.mjs +83 -0
  369. package/clients/cli/commands/blog.doc.mjs +1 -1
  370. package/clients/cli/commands/blog.mjs +23 -8
  371. package/clients/cli/commands/blog.test.mjs +42 -1
  372. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  373. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  374. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  375. package/clients/cli/commands/build-theme.mjs +16 -50
  376. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  377. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  378. package/clients/cli/commands/build.doc.mjs +16 -8
  379. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  380. package/clients/cli/commands/build.mjs +137 -114
  381. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  382. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  383. package/clients/cli/commands/component/index.mjs +3 -8
  384. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  385. package/clients/cli/commands/component-package.test.mjs +46 -0
  386. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  387. package/clients/cli/commands/component.doc.mjs +1 -1
  388. package/clients/cli/commands/component.test.mjs +19 -0
  389. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  390. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  391. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  392. package/clients/cli/commands/discover.doc.mjs +55 -9
  393. package/clients/cli/commands/discover.mjs +393 -118
  394. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  395. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  396. package/clients/cli/commands/docs.doc.mjs +21 -9
  397. package/clients/cli/commands/docs.mjs +184 -70
  398. package/clients/cli/commands/docs.test.mjs +120 -16
  399. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  400. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  401. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  402. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  403. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  404. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  405. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  406. package/clients/cli/commands/doctor.doc.mjs +1 -1
  407. package/clients/cli/commands/doctor.mjs +59 -32
  408. package/clients/cli/commands/doctor.test.mjs +42 -0
  409. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  410. package/clients/cli/commands/gap-report.test.mjs +72 -0
  411. package/clients/cli/commands/hook/index.mjs +7 -17
  412. package/clients/cli/commands/hook.doc.mjs +1 -1
  413. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  414. package/clients/cli/commands/init.doc.mjs +20 -9
  415. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  416. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  417. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  418. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  419. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  420. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  421. package/clients/cli/commands/integration.doc.mjs +1 -1
  422. package/clients/cli/commands/integration.mjs +1 -0
  423. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  424. package/clients/cli/commands/json-contract.test.mjs +33 -0
  425. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  426. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  427. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  428. package/clients/cli/commands/layout.doc.mjs +3 -3
  429. package/clients/cli/commands/layout.mjs +21 -9
  430. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  431. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  432. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  433. package/clients/cli/commands/manifest.doc.mjs +1 -1
  434. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  435. package/clients/cli/commands/search.doc.mjs +7 -4
  436. package/clients/cli/commands/search.mjs +28 -9
  437. package/clients/cli/commands/search.test.mjs +75 -0
  438. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  439. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  440. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  441. package/clients/cli/commands/template.doc.mjs +52 -13
  442. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  443. package/clients/cli/commands/template.mjs +4 -91
  444. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  445. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  446. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  447. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  448. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  449. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  450. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  451. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  452. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  453. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  454. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  455. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  456. package/clients/cli/commands/theme.doc.mjs +1 -1
  457. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  458. package/clients/cli/commands/upgrade.doc.mjs +20 -8
  459. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  460. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  461. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  462. package/clients/cli/commands/upgrade.mjs +29 -7
  463. package/clients/cli/formatters/index.mjs +2 -0
  464. package/clients/cli/formatters/index.test.mjs +6 -0
  465. package/clients/cli/index.mjs +21 -30
  466. package/clients/cli/latest-version-env.test.mjs +50 -0
  467. package/clients/cli/lib/cli-error.test.mjs +7 -0
  468. package/clients/cli/lib/component-format.mjs +9 -9
  469. package/clients/cli/lib/component-format.test.mjs +1 -1
  470. package/clients/cli/lib/define-command.mjs +32 -6
  471. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  472. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  473. package/clients/cli/lib/hook-format.mjs +19 -10
  474. package/clients/cli/lib/json-shim.mjs +38 -2
  475. package/clients/cli/lib/json-shim.test.mjs +83 -0
  476. package/clients/cli/lib/manifest.d.ts +2 -0
  477. package/clients/cli/lib/manifest.mjs +32 -2
  478. package/clients/cli/lib/manifest.test.mjs +17 -0
  479. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  480. package/foundation/agent-docs/agent-docs.mjs +82 -12
  481. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  482. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  483. package/foundation/config/integration-debug.test.mjs +28 -3
  484. package/foundation/config/project-themes.test.mjs +11 -19
  485. package/foundation/config/project.d.mts +20 -11
  486. package/foundation/config/project.mjs +246 -89
  487. package/foundation/config/project.test.mjs +270 -21
  488. package/foundation/discovery/authoring-self-docs.d.mts +18 -0
  489. package/foundation/discovery/authoring-self-docs.mjs +38 -15
  490. package/foundation/discovery/authoring-self-docs.test.mjs +87 -12
  491. package/foundation/discovery/authoring-surface.d.mts +74 -0
  492. package/foundation/discovery/authoring-surface.mjs +525 -0
  493. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  494. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  495. package/foundation/discovery/cli-self-docs.mjs +490 -0
  496. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  497. package/foundation/discovery/component-discovery.d.mts +38 -0
  498. package/foundation/discovery/component-discovery.mjs +48 -0
  499. package/foundation/discovery/component-loader.d.mts +35 -38
  500. package/foundation/discovery/component-loader.mjs +53 -222
  501. package/foundation/discovery/docs-discovery.d.mts +114 -9
  502. package/foundation/discovery/docs-discovery.mjs +239 -30
  503. package/foundation/discovery/docs-discovery.test.mjs +150 -35
  504. package/foundation/discovery/docs-output-budget.d.mts +2 -2
  505. package/foundation/discovery/docs-output-budget.mjs +1 -1
  506. package/foundation/discovery/docs-section-key.d.mts +28 -10
  507. package/foundation/discovery/docs-section-key.mjs +134 -33
  508. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  509. package/foundation/discovery/template-adapter.d.mts +113 -11
  510. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  511. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  512. package/foundation/discovery/template-adapter.mjs +772 -82
  513. package/foundation/discovery/template-adapter.test.mjs +57 -0
  514. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  515. package/foundation/discovery/template-conflict-release.mjs +40 -0
  516. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  517. package/foundation/discovery/theme-discovery.d.mts +67 -7
  518. package/foundation/discovery/theme-discovery.mjs +916 -186
  519. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  520. package/foundation/discovery/theming-targets.test.mjs +4 -0
  521. package/foundation/doc-compiler/bundle.d.mts +47 -0
  522. package/foundation/doc-compiler/bundle.mjs +278 -0
  523. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  524. package/foundation/doc-compiler/compile.d.mts +343 -0
  525. package/foundation/doc-compiler/compile.mjs +558 -0
  526. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  527. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  528. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  529. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  530. package/foundation/doc-compiler/import.d.mts +24 -0
  531. package/foundation/doc-compiler/import.mjs +59 -0
  532. package/foundation/doc-compiler/inputs.d.mts +102 -0
  533. package/foundation/doc-compiler/inputs.mjs +291 -0
  534. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  535. package/foundation/doc-compiler/ir.d.mts +22 -0
  536. package/foundation/doc-compiler/ir.mjs +471 -0
  537. package/foundation/doc-compiler/lenses.d.mts +36 -0
  538. package/foundation/doc-compiler/lenses.mjs +173 -0
  539. package/foundation/doc-compiler/links.d.mts +162 -0
  540. package/foundation/doc-compiler/links.mjs +294 -0
  541. package/foundation/doc-compiler/links.test.mjs +192 -0
  542. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  543. package/foundation/doc-compiler/overlays.d.mts +37 -0
  544. package/foundation/doc-compiler/overlays.mjs +206 -0
  545. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  546. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  547. package/foundation/doc-compiler/read.d.mts +127 -0
  548. package/foundation/doc-compiler/read.mjs +325 -0
  549. package/foundation/doc-compiler/read.test.mjs +313 -0
  550. package/foundation/doc-compiler/source.d.mts +33 -0
  551. package/foundation/doc-compiler/source.mjs +128 -0
  552. package/foundation/doc-compiler/tree.d.mts +288 -0
  553. package/foundation/doc-compiler/tree.mjs +876 -0
  554. package/foundation/doc-compiler/tree.test.mjs +598 -0
  555. package/foundation/fs/file-protection.d.mts +33 -0
  556. package/foundation/fs/file-protection.mjs +825 -0
  557. package/foundation/fs/file-protection.test.mjs +250 -0
  558. package/foundation/fs/module-loader.d.mts +1 -0
  559. package/foundation/fs/module-loader.mjs +50 -1
  560. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  561. package/foundation/fs/path-safety.d.mts +3 -2
  562. package/foundation/fs/path-safety.mjs +49 -19
  563. package/foundation/fs/path-safety.test.mjs +50 -0
  564. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  565. package/foundation/integrations/autolink.d.mts +58 -1
  566. package/foundation/integrations/autolink.mjs +143 -52
  567. package/foundation/integrations/autolink.test.mjs +1 -1
  568. package/foundation/integrations/cli-requirement.d.mts +45 -0
  569. package/foundation/integrations/cli-requirement.mjs +154 -0
  570. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  571. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  572. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  573. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  574. package/foundation/integrations/contribution-inventory.mjs +27 -24
  575. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  576. package/foundation/integrations/integration-warnings.d.mts +9 -2
  577. package/foundation/integrations/integration-warnings.mjs +51 -26
  578. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  579. package/foundation/integrations/integrations.d.mts +17 -1
  580. package/foundation/integrations/integrations.mjs +52 -98
  581. package/foundation/integrations/integrations.test.mjs +31 -0
  582. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  583. package/foundation/integrations/provider-resolution.d.mts +152 -0
  584. package/foundation/integrations/provider-resolution.mjs +576 -0
  585. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  586. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  587. package/foundation/integrations/theme-descriptor.mjs +44 -0
  588. package/foundation/integrations/validate-contributions.mjs +121 -29
  589. package/foundation/response/base.d.ts +8 -4
  590. package/foundation/response/error-codes.d.mts +3 -1
  591. package/foundation/response/error-codes.d.ts +2 -0
  592. package/foundation/response/error-codes.doc.mjs +13 -4
  593. package/foundation/response/error-codes.mjs +8 -2
  594. package/foundation/response/error-codes.test.mjs +137 -10
  595. package/foundation/response/json-contract.test.mjs +11 -0
  596. package/foundation/response/json.d.mts +4 -2
  597. package/foundation/response/json.mjs +8 -10
  598. package/foundation/response/response-types.doc.d.mts +5 -1
  599. package/foundation/response/response-types.doc.mjs +37 -22
  600. package/foundation/response/response-types.doc.test.mjs +158 -0
  601. package/foundation/response/response.doc.mjs +1 -1
  602. package/foundation/text/string-utils.d.mts +8 -0
  603. package/foundation/text/string-utils.mjs +40 -10
  604. package/foundation/xle/expand.d.mts +2 -0
  605. package/foundation/xle/expand.mjs +4 -3
  606. package/foundation/xle/expand.test.mjs +54 -0
  607. package/foundation/xle/xle.test.mjs +13 -0
  608. package/package.json +10 -11
  609. package/assets/templates/themes/manifest.json +0 -95
  610. package/clients/cli/lib/update-check.mjs +0 -83
  611. package/clients/cli/lib/update-check.test.mjs +0 -137
  612. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -0,0 +1,188 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file `astryx upgrade` documents how its flags interact and when it exits 1,
5
+ * and behaves as documented. Option text is read from the generated manifest
6
+ * (the same strings `--help` prints); exit codes from the CommandDoc.
7
+ */
8
+
9
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import {runCli} from '../../../test-utils/run-cli.mjs';
14
+ import {doc as upgradeDoc} from './upgrade.doc.mjs';
15
+
16
+ const SLOW = 30_000;
17
+
18
+ /** @type {string} */
19
+ let tmpDir;
20
+
21
+ beforeEach(() => {
22
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-upgrade-flags-'));
23
+ fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({name: 'consumer'}));
24
+ fs.mkdirSync(path.join(tmpDir, 'src'));
25
+ fs.writeFileSync(path.join(tmpDir, 'src', 'index.ts'), 'const foo = 1;\n');
26
+ });
27
+
28
+ afterEach(() => {
29
+ fs.rmSync(tmpDir, {recursive: true, force: true});
30
+ });
31
+
32
+ /** @param {string} name @param {string} version */
33
+ function installPackage(name, version) {
34
+ const dir = path.join(tmpDir, 'node_modules', ...name.split('/'));
35
+ fs.mkdirSync(dir, {recursive: true});
36
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({name, version}));
37
+ }
38
+
39
+ /** @param {string} rel @param {string} body */
40
+ function write(rel, body) {
41
+ fs.mkdirSync(path.dirname(path.join(tmpDir, rel)), {recursive: true});
42
+ fs.writeFileSync(path.join(tmpDir, rel), body);
43
+ }
44
+
45
+ /**
46
+ * upgrade's option descriptions from the manifest, keyed by long flag.
47
+ * @returns {Promise<Record<string, string>>}
48
+ */
49
+ async function upgradeOptions() {
50
+ const {stdout} = await runCli(['--json', 'manifest'], tmpDir);
51
+ const upgrade = JSON.parse(stdout).data.commands.find(
52
+ (/** @type {{name: string}} */ c) => c.name === 'upgrade',
53
+ );
54
+ return Object.fromEntries(
55
+ upgrade.options.map((/** @type {{flag: string, description: string}} */ o) => [
56
+ o.flag.match(/--[a-z-]+/)?.[0],
57
+ o.description,
58
+ ]),
59
+ );
60
+ }
61
+
62
+ /** @param {string[]} args */
63
+ async function upgradeJson(args) {
64
+ const result = await runCli(['--json', 'upgrade', ...args], tmpDir);
65
+ return {status: result.status, envelope: JSON.parse(result.stdout)};
66
+ }
67
+
68
+ const exit1 = () => upgradeDoc.exitCodes?.find(e => e.code === 1)?.when ?? '';
69
+
70
+ const MIGRATION_FLAGS = [
71
+ ['--from', '0.5.0'],
72
+ ['--force'],
73
+ ['--codemod', 'x'],
74
+ ['--skip-codemod', 'x'],
75
+ ['--integration', 'x'],
76
+ ['--install-deps'],
77
+ ];
78
+
79
+ describe('astryx upgrade flag interactions', () => {
80
+ it('--list: help says it ignores every other flag but --registry, and it does', async () => {
81
+ const options = await upgradeOptions();
82
+ expect(options['--list']).toMatch(/Every other flag is ignored, except --registry/);
83
+
84
+ installPackage('@astryxdesign/core', '0.6.0');
85
+ const listed = await upgradeJson([
86
+ '--list',
87
+ '--from',
88
+ 'bogus',
89
+ '--codemod',
90
+ 'bogus',
91
+ '--apply',
92
+ '--path',
93
+ '../outside',
94
+ ]);
95
+ expect(listed.status).toBe(0);
96
+ expect(listed.envelope.type).toBe('upgrade.list');
97
+
98
+ const refused = await upgradeJson(['--list', '--registry']);
99
+ expect(refused.status).toBe(1);
100
+ expect(refused.envelope.code).toBe('ERR_INVALID_ARGUMENT');
101
+ }, SLOW);
102
+
103
+ it('--registry: help names every flag it refuses, and each exits 1', async () => {
104
+ const options = await upgradeOptions();
105
+ for (const [flag] of MIGRATION_FLAGS) expect(options['--registry']).toContain(flag);
106
+ expect(options['--registry']).toContain('--list');
107
+ expect(options['--registry']).toContain('ERR_INVALID_ARGUMENT');
108
+
109
+ for (const flag of MIGRATION_FLAGS) {
110
+ const {status, envelope} = await upgradeJson(['--registry', ...flag]);
111
+ expect(status, flag[0]).toBe(1);
112
+ expect(envelope.code, flag[0]).toBe('ERR_INVALID_ARGUMENT');
113
+ }
114
+ }, SLOW);
115
+
116
+ it('--codemod: help says it runs optional codemods and skips the composition check, and it does', async () => {
117
+ const options = await upgradeOptions();
118
+ expect(options['--codemod']).toMatch(/Optional codemods run only when named here/);
119
+ expect(options['--codemod']).toMatch(/skips the check of ShadCN-copied compositions/);
120
+
121
+ installPackage('@astryxdesign/core', '0.0.15');
122
+ // An unreadable receipt leaves a registry item unresolved.
123
+ write('src/components/.astryx/broken.json', '{}');
124
+
125
+ const normal = await upgradeJson(['--from', '0.0.14']);
126
+ expect(normal.status).toBe(1);
127
+ expect(normal.envelope.data.registryCompositions.invalid).toBe(1);
128
+
129
+ // 0.0.15 ships one optional codemod, which only runs when named.
130
+ const named = await upgradeJson(['--from', '0.0.14', '--codemod', 'migrate-theme-selectors-to-data-attrs']);
131
+ expect(named.status).toBe(0);
132
+ expect(named.envelope.data.codemods).toBe(1);
133
+ expect(named.envelope.data.registryCompositions).toBeUndefined();
134
+ expect(normal.envelope.data.codemods).toBe(6);
135
+ }, SLOW);
136
+
137
+ it('--from: help names the legacy @xds/core target, which upgrade falls back to', async () => {
138
+ const options = await upgradeOptions();
139
+ expect(options['--from']).toMatch(/legacy @xds\/core/);
140
+
141
+ installPackage('@xds/core', '0.0.20');
142
+ const {status, envelope} = await upgradeJson(['--from', '0.0.19']);
143
+ expect(status).toBe(0);
144
+ expect(envelope.data.to).toBe('0.0.20');
145
+ }, SLOW);
146
+ });
147
+
148
+ describe('astryx upgrade exit codes', () => {
149
+ it('lists a missing core, which exits 1 in both modes', async () => {
150
+ expect(exit1()).toMatch(/no installed @astryxdesign\/core/);
151
+ const text = await runCli(['upgrade', '--from', '0.5.0'], tmpDir);
152
+ const json = await upgradeJson(['--from', '0.5.0']);
153
+ expect(text.status).toBe(1);
154
+ expect(json.status).toBe(1);
155
+ expect(json.envelope.code).toBe('ERR_VERSION_DETECT');
156
+ }, SLOW);
157
+
158
+ it('lists an astryx.config no codemod repairs, which exits 1', async () => {
159
+ expect(exit1()).toMatch(/astryx\.config that fails validation/);
160
+ installPackage('@astryxdesign/core', '0.6.0');
161
+ write('astryx.config.mjs', "export default {theme: 'neutral'};\n");
162
+ const {status, envelope} = await upgradeJson(['--from', '0.5.0']);
163
+ expect(status).toBe(1);
164
+ expect(envelope.code).toBe('ERR_INVALID_ARGUMENT');
165
+ }, SLOW);
166
+
167
+ it('lists a post-codemod hook failure, which exits 1', async () => {
168
+ expect(exit1()).toMatch(/post-codemod hook failure/);
169
+ installPackage('@astryxdesign/core', '0.6.0');
170
+ write(
171
+ 'src/panel.tsx',
172
+ "import {useResizable} from '@astryxdesign/core';\nexport const r = () => useResizable({minSizePx: 200});\n",
173
+ );
174
+ write(
175
+ 'astryx.config.mjs',
176
+ "export default {hooks: {postCodemod: [{buildCommand: () => { throw new Error('formatter crashed'); }}]}};\n",
177
+ );
178
+ const {status, envelope} = await upgradeJson(['--from', '0.5.0']);
179
+ expect(status).toBe(1);
180
+ expect(envelope.code).toBe('ERR_CODEMOD_FAILED');
181
+ expect(envelope.error).toMatch(/Post-codemod hook failed/);
182
+ }, SLOW);
183
+
184
+ it('lists a missing jscodeshift and the refused flag combinations', () => {
185
+ expect(exit1()).toMatch(/jscodeshift missing and not installed/);
186
+ expect(exit1()).toMatch(/--registry with --list or a migration flag/);
187
+ });
188
+ });
@@ -0,0 +1,88 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Subprocess test: a post-codemod hook that prints must not corrupt the
5
+ * `upgrade --json` envelope. Stdout carries exactly one envelope; the hook's
6
+ * output goes to stderr.
7
+ */
8
+
9
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
10
+ import {spawnSync} from 'node:child_process';
11
+ import * as fs from 'node:fs';
12
+ import * as path from 'node:path';
13
+ import * as os from 'node:os';
14
+ import {fileURLToPath} from 'node:url';
15
+
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ const CLI = path.resolve(__dirname, '..', 'bin', 'astryx.mjs');
18
+
19
+ let tmpDir;
20
+
21
+ /** @param {string} rel @param {string} body */
22
+ function write(rel, body) {
23
+ const file = path.join(tmpDir, rel);
24
+ fs.mkdirSync(path.dirname(file), {recursive: true});
25
+ fs.writeFileSync(file, body);
26
+ }
27
+
28
+ /** @param {string[]} args */
29
+ function runCli(args) {
30
+ return spawnSync(process.execPath, [CLI, ...args], {
31
+ cwd: tmpDir,
32
+ encoding: 'utf8',
33
+ timeout: 60_000,
34
+ stdio: ['ignore', 'pipe', 'pipe'],
35
+ env: {...process.env, FORCE_COLOR: '0', CI: ''},
36
+ });
37
+ }
38
+
39
+ beforeEach(() => {
40
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-upgrade-hook-output-'));
41
+ write('package.json', JSON.stringify({name: 'consumer', private: true}));
42
+ write(
43
+ 'node_modules/@astryxdesign/core/package.json',
44
+ JSON.stringify({name: '@astryxdesign/core', version: '0.6.0'}),
45
+ );
46
+ write(
47
+ 'src/panel.tsx',
48
+ "import {useResizable} from '@astryxdesign/core';\n" +
49
+ 'export const usePanel = () => useResizable({defaultSize: 250, minSizePx: 200});\n',
50
+ );
51
+ write(
52
+ 'astryx.config.mjs',
53
+ 'export default {hooks: {postCodemod: [{name: "noisy", buildCommand: ({files}) => {\n' +
54
+ ' console.log("hook saw " + files.join(","));\n' +
55
+ ' process.stdout.write("hook raw write\\n");\n' +
56
+ ' return null;\n' +
57
+ '}}]}};\n',
58
+ );
59
+ });
60
+
61
+ afterEach(() => {
62
+ fs.rmSync(tmpDir, {recursive: true, force: true});
63
+ });
64
+
65
+ describe('upgrade post-codemod hook output', () => {
66
+ it('keeps --json stdout to one envelope and sends hook output to stderr', () => {
67
+ const r = runCli([
68
+ '--json',
69
+ 'upgrade',
70
+ '--from',
71
+ '0.5.0',
72
+ '--codemod',
73
+ 'rename-resizable-pixel-bounds',
74
+ '--apply',
75
+ ]);
76
+
77
+ expect(r.signal).toBeNull();
78
+ expect(r.status).toBe(0);
79
+ const envelope = JSON.parse(r.stdout);
80
+ expect(envelope.type).toBe('upgrade.run');
81
+ expect(envelope.data.filesChanged).toBe(1);
82
+ expect(r.stderr).toContain('hook saw src/panel.tsx');
83
+ expect(r.stderr).toContain('hook raw write');
84
+ expect(fs.readFileSync(path.join(tmpDir, 'src/panel.tsx'), 'utf8')).toContain(
85
+ 'minSize: 200',
86
+ );
87
+ });
88
+ });
@@ -13,6 +13,7 @@
13
13
  */
14
14
 
15
15
  import {jsonOut, jsonError} from '../../../foundation/response/json.mjs';
16
+ import {emit, section, records} from '../formatters/index.mjs';
16
17
  import {logger} from '../../../api/logger.mjs';
17
18
  import {AstryxError} from '../../../api/error.mjs';
18
19
  import {defineCommand} from '../lib/define-command.mjs';
@@ -33,27 +34,45 @@ export function registerUpgrade(program) {
33
34
  */
34
35
  async options => {
35
36
  const json = program.opts().json || false;
36
- logger.setSilent(json);
37
+ const isList = Boolean(options.list);
38
+ // Silence the logger for --list so the handler renders from the
39
+ // result (parity with --json), and for --json as before.
40
+ // Re-enable on error so handled failures still print.
41
+ logger.setSilent(json || isList);
37
42
 
38
43
  /** @type {import('../../../api/upgrade/upgrade.type.mjs').UpgradeListResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeRegistryResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeStatusResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeRunResponse} */
39
44
  let result;
40
45
  try {
41
46
  result = await upgradeApi(options, {cwd: process.cwd()});
42
47
  } catch (e) {
43
- // Handled failures throw AstryxError: --json emits the structured
44
- // envelope (byte-identical to the old inline jsonError) + exits 1;
45
- // human mode already saw the error line + outro via the logger, so we
46
- // just set the exit code. Anything else is unexpected — let the
47
- // top-level boundary in bin/astryx.mjs format it as before.
48
+ // Re-enable the logger so the error is visible in text mode.
49
+ // For --list the logger was silent; for other modes the API
50
+ // already printed the error before throwing.
51
+ logger.setSilent(json);
48
52
  if (e instanceof AstryxError) {
49
53
  if (json) jsonError(e.message, undefined, e.code);
50
- else process.exitCode = 1;
54
+ else {
55
+ // The logger was silent only for --list; replay the error there.
56
+ // Non-list failures were already printed by the API.
57
+ if (isList) logger.error(e.message);
58
+ process.exitCode = 1;
59
+ }
51
60
  return NO_RESULT_SET;
52
61
  }
53
62
  throw e;
54
63
  }
55
64
 
56
65
  if (json) jsonOut(result);
66
+ else if (result.type === 'upgrade.list') {
67
+ // Render the list from the result, not the API logger, so the text
68
+ // carries the same fields the JSON does (name, title, version, optional).
69
+ emit(
70
+ section('Available codemods'),
71
+ records(result.data, {
72
+ fields: ['name', 'title', 'version', 'optional'],
73
+ }),
74
+ );
75
+ }
57
76
 
58
77
  const registrySummary =
59
78
  result.type === 'upgrade.registry'
@@ -65,6 +84,9 @@ export function registerUpgrade(program) {
65
84
  ? result.data.registryCompositions
66
85
  : undefined;
67
86
  if (registrySummary && !registrySummary.ok) process.exitCode = 1;
87
+ if (result.type === 'upgrade.run' && result.data.complete === false) {
88
+ process.exitCode = 1;
89
+ }
68
90
 
69
91
  // `--list` is the one lookup here: which migrations exist for the
70
92
  // range. Everything else migrates the project — an effect, reported by
@@ -152,6 +152,8 @@ function toAscii(s) {
152
152
  .replace(/[\u2018\u2019]/g, "'")
153
153
  .replace(/[\u201C\u201D]/g, '"')
154
154
  .replace(/\u2026/g, '...')
155
+ .replace(/\u2192/g, '->')
156
+ .replace(/\u2190/g, '<-')
155
157
  .replace(/\u00a0/g, ' ');
156
158
  }
157
159
 
@@ -117,6 +117,12 @@ describe('ASCII normalization', () => {
117
117
  expect(list(['Avatar \u2014 Group']).toString()).toBe('- Avatar - Group');
118
118
  });
119
119
 
120
+ it('converts Unicode arrows to ASCII arrows', () => {
121
+ expect(text('Rename items \u2192 options').toString()).toBe('Rename items -> options');
122
+ expect(text('options \u2190 items').toString()).toBe('options <- items');
123
+ expect(record({title: 'a \u2192 b'}).toString()).toBe('title: a -> b');
124
+ });
125
+
120
126
  it('leaves code verbatim (no normalization)', () => {
121
127
  expect(code('a \u2014 b').toString()).toBe('a \u2014 b');
122
128
  });
@@ -16,7 +16,6 @@ import {Command, Option} from 'commander';
16
16
  import {fileURLToPath} from 'node:url';
17
17
  import * as fs from 'node:fs';
18
18
  import * as path from 'node:path';
19
- import {checkForUpdate} from './lib/update-check.mjs';
20
19
  import {getCliInvocation} from '../../foundation/env/package-manager.mjs';
21
20
  import {API_VERSION, setJsonMode} from '../../foundation/response/json.mjs';
22
21
  import {buildManifest} from './lib/manifest.mjs';
@@ -25,7 +24,8 @@ import {emit, section, text, records} from './formatters/index.mjs';
25
24
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
26
25
  import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
27
26
  import {installJsonShim} from './lib/json-shim.mjs';
28
- import {markReportsResult} from './lib/define-command.mjs';
27
+ import {addExitCodesHelp, markReportsResult} from './lib/define-command.mjs';
28
+ import {doc as manifestDoc} from './commands/manifest.doc.mjs';
29
29
  import {isAstryxInitialized} from '../../foundation/agent-docs/agent-docs.mjs';
30
30
  import * as debug from '../../foundation/debug/index.mjs';
31
31
 
@@ -275,8 +275,13 @@ const commands = [
275
275
  {name: 'doctor', path: './commands/doctor.mjs', register: 'registerDoctor'},
276
276
  ];
277
277
 
278
- const UPDATE_HINT_COMMANDS = new Set(['component', 'docs']);
279
278
  const SETUP_NUDGE_EXEMPT = new Set(['init', 'agent-docs']);
279
+ /** An integration package's manifest: the package is not an app to set up. */
280
+ const INTEGRATION_MANIFEST_FILES = [
281
+ 'astryx.integration.ts',
282
+ 'astryx.integration.mjs',
283
+ 'astryx.integration.js',
284
+ ];
280
285
 
281
286
  /**
282
287
  * Build a fresh, fully-wired Astryx CLI program (root options, hooks, all
@@ -352,7 +357,7 @@ export async function createProgram() {
352
357
  )
353
358
  .option(
354
359
  '--json',
355
- 'Output as typed JSON. Success envelope: { type, data }. Error envelope: { error, suggestions? }.',
360
+ 'Output as typed JSON. Success envelope: { apiVersion, type, data, meta? }. Error envelope: { apiVersion, error, code, suggestions? }.',
356
361
  )
357
362
  .addHelpCommand('help', 'Show all commands')
358
363
  .action((options, cmd) => {
@@ -499,25 +504,6 @@ export async function createProgram() {
499
504
  process.exit(1);
500
505
  });
501
506
 
502
- /**
503
- * Post-action hook: print update hint after any command output.
504
- * Only fires for commands that produce output agents read (component, docs, etc.).
505
- * Suppressed when --json is active to avoid contaminating stdout.
506
- */
507
- program.hook('postAction', (thisCommand, actionCommand) => {
508
- if (program.opts().json) return;
509
- try {
510
- if (UPDATE_HINT_COMMANDS.has(actionCommand.name())) {
511
- const hint = checkForUpdate();
512
- if (hint) {
513
- console.error(`\n${hint}`);
514
- }
515
- }
516
- } catch {
517
- // Never let update check break the CLI
518
- }
519
- });
520
-
521
507
  /**
522
508
  * Enforcement layer 3 — setup nudge. If this project hasn't run `astryx init`
523
509
  * yet (no Astryx marker in any agent-doc file — see isAstryxInitialized), remind
@@ -539,6 +525,8 @@ export async function createProgram() {
539
525
  if (SETUP_NUDGE_EXEMPT.has(actionCommand.name())) return;
540
526
  const cwd = process.cwd();
541
527
  if (!fs.existsSync(path.join(cwd, 'package.json'))) return; // not a project
528
+ // An integration package is not an app: `init` is not its next step.
529
+ if (INTEGRATION_MANIFEST_FILES.some(file => fs.existsSync(path.join(cwd, file)))) return;
542
530
  if (isAstryxInitialized(cwd)) return; // already set up — stay quiet
543
531
  // Same wording as the core/cli postinstall nudges. #4151's getCliInvocation()
544
532
  // renders the correct form for THIS project — scoped `npx @astryxdesign/cli`
@@ -557,16 +545,18 @@ export async function createProgram() {
557
545
  mod[cmd.register](program);
558
546
  } catch (e) {
559
547
  // Command fails to load but CLI still works
548
+ const reason = /** @type {any} */ (e).message;
560
549
  const stub = program
561
550
  .command(cmd.name)
562
- .description(`(failed to load: ${/** @type {any} */ (e).message})`)
551
+ .description(`(failed to load: ${reason})`)
563
552
  .action(() => {
564
553
  // Nothing loaded, so nothing was answered — say that rather than
565
554
  // leaving the run's result unreported.
566
555
  debug.recordCommandResult(debug.NO_RESULT_SET);
567
- console.error(`Command "${cmd.name}" failed to load:`);
568
- console.error(/** @type {any} */ (e).message);
569
- process.exit(1);
556
+ // cliError, so --json still gets its one envelope.
557
+ cliError(`Command "${cmd.name}" failed to load: ${reason}`, {
558
+ code: ERROR_CODES.ERR_UNKNOWN,
559
+ });
570
560
  });
571
561
  markReportsResult(stub);
572
562
  }
@@ -601,20 +591,21 @@ export async function createProgram() {
601
591
  }
602
592
  // Human-readable summary as greppable records (agents should use --json).
603
593
  // One record per command: name, whether it supports --json, and the
604
- // description.
594
+ // description. Field names are the manifest entry's own keys.
605
595
  emit(
606
596
  section(`${manifest.name} v${manifest.version} (${manifest.commands.length} commands)`),
607
597
  records(
608
598
  manifest.commands.map(c => ({
609
- command: c.name,
599
+ name: c.name,
610
600
  json: c.json ? 'yes' : '',
611
601
  description: c.description || '',
612
602
  })),
613
- {fields: ['command', 'json', 'description']},
603
+ {fields: ['name', 'json', 'description']},
614
604
  ),
615
605
  text(`Run \`${getCliInvocation()} manifest --json\` for the full structured manifest.`),
616
606
  );
617
607
  });
608
+ addExitCodesHelp(manifestCommand, manifestDoc.exitCodes);
618
609
  markReportsResult(manifestCommand);
619
610
 
620
611
  // Hidden command used by package.json postinstall scripts
@@ -0,0 +1,50 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file ASTRYX_LATEST_VERSION is not a CLI control: setting it changes nothing
5
+ * a command prints. It used to append an update hint to `component` and
6
+ * `docs`.
7
+ */
8
+
9
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import {runCli} from '../../test-utils/run-cli.mjs';
14
+
15
+ const VARIABLE = 'ASTRYX_LATEST_VERSION';
16
+
17
+ /** @type {string} */
18
+ let dir;
19
+ /** @type {string | undefined} */
20
+ let saved;
21
+
22
+ beforeEach(() => {
23
+ saved = process.env[VARIABLE];
24
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-latest-version-'));
25
+ // A project on an old core, so a "newer version" hint would have a reason to fire.
26
+ fs.writeFileSync(
27
+ path.join(dir, 'package.json'),
28
+ JSON.stringify({name: 'app', private: true, dependencies: {'@astryxdesign/core': '^0.0.1'}}),
29
+ );
30
+ });
31
+
32
+ afterEach(() => {
33
+ if (saved === undefined) delete process.env[VARIABLE];
34
+ else process.env[VARIABLE] = saved;
35
+ fs.rmSync(dir, {recursive: true, force: true});
36
+ });
37
+
38
+ describe('ASTRYX_LATEST_VERSION', () => {
39
+ it('does not change what astryx docs prints', async () => {
40
+ delete process.env[VARIABLE];
41
+ const without = await runCli(['docs'], {cwd: dir});
42
+ process.env[VARIABLE] = '999.0.0';
43
+ const withVariable = await runCli(['docs'], {cwd: dir});
44
+
45
+ expect(withVariable.status).toBe(without.status);
46
+ expect(withVariable.stdout).toBe(without.stdout);
47
+ expect(withVariable.stderr).toBe(without.stderr);
48
+ expect(withVariable.stderr).not.toMatch(/newer version/i);
49
+ });
50
+ });
@@ -133,6 +133,13 @@ describe('cliError — JSON mode', () => {
133
133
  expect(env.suggestions).toEqual([{name: 'Button', reason: 'closest match'}]);
134
134
  });
135
135
 
136
+ it('replaces an unregistered code with ERR_UNKNOWN', () => {
137
+ expect(() =>
138
+ cliError('EACCES: permission denied', {code: 'EACCES'}),
139
+ ).toThrow('__exit_1__');
140
+ expect(JSON.parse(stdout[0]).code).toBe('ERR_UNKNOWN');
141
+ });
142
+
136
143
  it('always exits 1 in JSON mode (custom exitCode is ignored — contract)', () => {
137
144
  expect(() => cliError('msg', {exitCode: 2})).toThrow('__exit_1__');
138
145
  expect(exitCode).toBe(1);
@@ -71,7 +71,7 @@ function formatPropsTable(props) {
71
71
  lines.push('| Prop | Type | Default | Description |');
72
72
  lines.push('|------|------|---------|-------------|');
73
73
  for (const p of props) {
74
- const def = p.default ? `\`${mdCell(p.default)}\`` : '—';
74
+ const def = p.default ? `\`${mdCell(p.default)}\`` : '-';
75
75
  const req = p.required ? ' **(required)**' : '';
76
76
  lines.push(
77
77
  `| \`${mdCell(p.name)}\` | \`${mdCell(p.type)}\` | ${def} | ${mdCell(p.description)}${req} |`,
@@ -190,11 +190,11 @@ function formatTargetsTable(docs, themeData) {
190
190
  ...themeVariants.map((/** @type {string} */ v) => `${v}*`),
191
191
  ];
192
192
 
193
- const variantsStr = variantParts.length > 0 ? variantParts.join(', ') : '—';
194
- const statesStr = states.length > 0 ? states.join(', ') : '—';
193
+ const variantsStr = variantParts.length > 0 ? variantParts.join(', ') : '-';
194
+ const statesStr = states.length > 0 ? states.join(', ') : '-';
195
195
  const dataAttrs = getTargetDataAttributes(target);
196
196
  const dataAttrsStr =
197
- dataAttrs.length > 0 ? dataAttrs.map(attr => `\`${attr}\``).join(', ') : '—';
197
+ dataAttrs.length > 0 ? dataAttrs.map(attr => `\`${attr}\``).join(', ') : '-';
198
198
 
199
199
  const className = target.deprecatedFor
200
200
  ? `\`${target.className}\` _(deprecated; use \`${target.deprecatedFor}\`)_`
@@ -342,7 +342,7 @@ export function formatFull(docs, options = {}) {
342
342
  const publicVars = docs.theming.vars.filter((/** @type {any} */ v) => !v.private && !v.derived);
343
343
 
344
344
  if (publicVars.length > 0) {
345
- sections.push('**Themeable CSS variables** — additional properties that can be overridden in `defineTheme` component overrides.\n');
345
+ sections.push('**Themeable CSS variables** - additional properties that can be overridden in `defineTheme` component overrides.\n');
346
346
  const varLines = [];
347
347
  varLines.push('| CSS Variable | Default | Description |');
348
348
  varLines.push('|-------------|---------|-------------|');
@@ -544,7 +544,7 @@ export function formatBrief(docs, componentName, importHint, options = {}) {
544
544
  signatureProps.length > 0
545
545
  ? `${displayName}(${signatureProps.join(', ')})`
546
546
  : displayName;
547
- output.push(importHint ? `${sigStr} ← from '${importHint}'` : sigStr);
547
+ output.push(importHint ? `${sigStr} <- from '${importHint}'` : sigStr);
548
548
 
549
549
  // Description (shortened)
550
550
  if (description) {
@@ -569,7 +569,7 @@ export function formatBrief(docs, componentName, importHint, options = {}) {
569
569
  // Derived properties (if any)
570
570
  if (docs.theming?.derived?.length) {
571
571
  const derivedNames = docs.theming.derived
572
- .map((/** @type {any} */ d) => d.expand === 'container' ? `${d.property} → container tokens` : `${d.property} → ${(d.vars || []).join(', ')}`)
572
+ .map((/** @type {any} */ d) => d.expand === 'container' ? `${d.property} -> container tokens` : `${d.property} -> ${(d.vars || []).join(', ')}`)
573
573
  .join('; ');
574
574
  output.push(` Derived: ${derivedNames}`);
575
575
  }
@@ -579,7 +579,7 @@ export function formatBrief(docs, componentName, importHint, options = {}) {
579
579
  const { themeData = null } = options;
580
580
  const targetParts = docs.theming.targets.map((/** @type {any} */ t) => {
581
581
  const parts = [t.className];
582
- if (t.deprecatedFor) parts.push(`deprecated→${t.deprecatedFor}`);
582
+ if (t.deprecatedFor) parts.push(`deprecated->${t.deprecatedFor}`);
583
583
  const dataAttrs = getTargetDataAttributes(t);
584
584
  if (dataAttrs.length) parts.push(`preferred attrs: ${dataAttrs.join(', ')}`);
585
585
  if (t.visualProps?.length) parts.push(`variants: ${t.visualProps.join(', ')}`);
@@ -595,7 +595,7 @@ export function formatBrief(docs, componentName, importHint, options = {}) {
595
595
 
596
596
  // Other props
597
597
  if (otherProps.length > 0) {
598
- output.push(` ${otherProps.join(' · ')}`);
598
+ output.push(` ${otherProps.join(', ')}`);
599
599
  }
600
600
 
601
601
  // First code example
@@ -157,7 +157,7 @@ describe('deprecated theming target guidance', () => {
157
157
 
158
158
  it('keeps the replacement in brief agent guidance', () => {
159
159
  expect(formatBrief(docs, 'Example')).toContain(
160
- 'astryx-old-target deprecated→new-target',
160
+ 'astryx-old-target deprecated->new-target',
161
161
  );
162
162
  });
163
163
  });