@astryxdesign/cli 0.6.3 → 0.6.4-canary.06c8fa3

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 (670) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +121 -85
  3. package/api/blog/blog.doc.mjs +1 -0
  4. package/api/build/_adapter.d.mts +50 -0
  5. package/api/build/_adapter.mjs +60 -0
  6. package/api/build/build.doc.mjs +16 -9
  7. package/api/build/build.test.mjs +197 -8
  8. package/api/build/build.type.d.mts +91 -2
  9. package/api/build/build.type.mjs +52 -8
  10. package/api/build/help/help.d.mts +12 -5
  11. package/api/build/help/help.mjs +69 -6
  12. package/api/build/kit/kit.d.mts +4 -1
  13. package/api/build/kit/kit.mjs +165 -49
  14. package/api/build/kit/rank.d.mts +44 -0
  15. package/api/build/kit/rank.mjs +432 -0
  16. package/api/build/kit/rank.test.mjs +196 -0
  17. package/api/component/_adapter.d.mts +31 -12
  18. package/api/component/_adapter.mjs +79 -15
  19. package/api/component/component.d.mts +6 -3
  20. package/api/component/component.doc.mjs +36 -13
  21. package/api/component/component.mjs +339 -22
  22. package/api/component/component.test.mjs +38 -0
  23. package/api/component/component.type.d.mts +47 -11
  24. package/api/component/component.type.mjs +76 -24
  25. package/api/component/detail/blocks/blocks.d.mts +2 -1
  26. package/api/component/detail/blocks/blocks.mjs +4 -3
  27. package/api/component/list/list.d.mts +0 -5
  28. package/api/component/list/list.mjs +40 -11
  29. package/api/discover/_adapter.d.mts +114 -6
  30. package/api/discover/_adapter.mjs +372 -17
  31. package/api/discover/_adapter.test.mjs +215 -0
  32. package/api/discover/_catalog-view.d.mts +115 -0
  33. package/api/discover/_catalog-view.mjs +203 -0
  34. package/api/discover/_catalog-view.test.mjs +128 -0
  35. package/api/discover/detail/detail.d.mts +18 -6
  36. package/api/discover/detail/detail.mjs +67 -13
  37. package/api/discover/detail/detail.test.mjs +85 -0
  38. package/api/discover/detail/item/item.d.mts +26 -0
  39. package/api/discover/detail/item/item.mjs +78 -0
  40. package/api/discover/detail/item/item.test.mjs +73 -0
  41. package/api/discover/discover.d.mts +3 -9
  42. package/api/discover/discover.doc.mjs +62 -18
  43. package/api/discover/discover.mjs +220 -36
  44. package/api/discover/discover.test.mjs +11 -2
  45. package/api/discover/discover.type.d.mts +150 -11
  46. package/api/discover/discover.type.mjs +107 -17
  47. package/api/discover/list/list.d.mts +20 -6
  48. package/api/discover/list/list.mjs +45 -12
  49. package/api/discover/list/list.test.mjs +46 -0
  50. package/api/discover/search/search.d.mts +18 -16
  51. package/api/discover/search/search.mjs +102 -56
  52. package/api/discover/search/search.test.mjs +144 -10
  53. package/api/docs/_adapter.d.mts +272 -41
  54. package/api/docs/_adapter.mjs +985 -108
  55. package/api/docs/compiled-topics.test.mjs +78 -0
  56. package/api/docs/detail/detail.mjs +22 -63
  57. package/api/docs/detail/section/section.d.mts +1 -1
  58. package/api/docs/detail/section/section.mjs +54 -19
  59. package/api/docs/detail/section/section.test.mjs +50 -0
  60. package/api/docs/docs.d.mts +10 -3
  61. package/api/docs/docs.doc.mjs +55 -16
  62. package/api/docs/docs.mjs +53 -10
  63. package/api/docs/docs.test.mjs +166 -4
  64. package/api/docs/docs.type.d.mts +221 -5
  65. package/api/docs/docs.type.mjs +153 -11
  66. package/api/docs/index/index.d.mts +18 -0
  67. package/api/docs/index/index.mjs +40 -0
  68. package/api/docs/index/index.test.mjs +62 -0
  69. package/api/docs/integration-tree.test.mjs +555 -0
  70. package/api/docs/integrationDocs.test.mjs +114 -8
  71. package/api/docs/list/list.mjs +28 -12
  72. package/api/docs/node/node.d.mts +43 -0
  73. package/api/docs/node/node.mjs +192 -0
  74. package/api/docs/reference-blocks.test.mjs +406 -0
  75. package/api/doctor/doctor.d.mts +104 -1
  76. package/api/doctor/doctor.doc.mjs +1 -0
  77. package/api/doctor/doctor.mjs +635 -7
  78. package/api/doctor/doctor.test.mjs +732 -11
  79. package/api/gap-report/gap-report.doc.mjs +8 -4
  80. package/api/hook/_adapter.mjs +19 -5
  81. package/api/hook/hook.doc.mjs +1 -0
  82. package/api/hook/hook.type.d.mts +3 -3
  83. package/api/hook/hook.type.mjs +11 -11
  84. package/api/hook/list/list.d.mts +2 -2
  85. package/api/hook/list/list.mjs +69 -17
  86. package/api/index.d.mts +2 -3
  87. package/api/index.mjs +5 -4
  88. package/api/init/init.doc.mjs +6 -1
  89. package/api/init/init.test.mjs +41 -1
  90. package/api/init/remove/remove.mjs +1 -1
  91. package/api/init/run/run.mjs +20 -10
  92. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  93. package/api/integration/add-contribution.d.mts +2 -1
  94. package/api/integration/add-contribution.mjs +130 -15
  95. package/api/integration/add-contribution.test.mjs +258 -7
  96. package/api/integration/add-helpers.d.mts +5 -2
  97. package/api/integration/add-helpers.mjs +36 -9
  98. package/api/integration/add-theme.mjs +34 -64
  99. package/api/integration/add-theme.test.mjs +105 -21
  100. package/api/integration/authoring-checks.mjs +138 -28
  101. package/api/integration/authoring-checks.test.mjs +179 -7
  102. package/api/integration/authoring-checks.type.mjs +6 -1
  103. package/api/integration/integration-authoring.type.d.mts +3 -1
  104. package/api/integration/integration-authoring.type.mjs +2 -0
  105. package/api/integration/integration-block-exports.test.mjs +10 -6
  106. package/api/integration/integrationAdd.doc.mjs +14 -4
  107. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  108. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  109. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  110. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  111. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  112. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  113. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  114. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  115. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  116. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  117. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  118. package/api/integration/pack-check.lifecycle-output.test.mjs +105 -0
  119. package/api/integration/pack-check.mjs +111 -10
  120. package/api/integration/pack-check.test.mjs +387 -47
  121. package/api/integration/pack-check.type.d.mts +26 -2
  122. package/api/integration/pack-check.type.mjs +14 -1
  123. package/api/integration/summarizeIssues.doc.mjs +1 -0
  124. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  126. package/api/integration/validate-integration.mjs +52 -102
  127. package/api/integration/validate-integration.test.mjs +179 -26
  128. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  129. package/api/integration/validateIntegration.doc.mjs +3 -2
  130. package/api/json/assertResponse.doc.mjs +1 -0
  131. package/api/json/envelope-types.test.mjs +76 -0
  132. package/api/json/index.ts +2 -1
  133. package/api/json/isError.doc.mjs +1 -0
  134. package/api/json/parseResponse.doc.mjs +3 -2
  135. package/api/search/search-return-type.test.mjs +54 -0
  136. package/api/search/search.d.mts +62 -11
  137. package/api/search/search.doc.mjs +8 -2
  138. package/api/search/search.mjs +471 -83
  139. package/api/search/search.test.mjs +142 -1
  140. package/api/search/search.type.d.mts +15 -3
  141. package/api/search/search.type.mjs +5 -2
  142. package/api/swizzle/copy/copy.mjs +28 -11
  143. package/api/swizzle/swizzle.doc.mjs +2 -1
  144. package/api/swizzle/swizzle.type.d.mts +2 -2
  145. package/api/swizzle/swizzle.type.mjs +2 -2
  146. package/api/template/copy/copy.mjs +17 -23
  147. package/api/template/copy/copy.test.mjs +17 -0
  148. package/api/template/list/list.mjs +1 -0
  149. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  150. package/api/template/template-integration.test.mjs +1008 -3
  151. package/api/template/template-suffix.test.mjs +41 -21
  152. package/api/template/template.d.mts +1 -1
  153. package/api/template/template.doc.mjs +30 -8
  154. package/api/template/template.mjs +46 -9
  155. package/api/template/template.type.d.mts +12 -14
  156. package/api/template/template.type.mjs +15 -14
  157. package/api/theme/_adapter.d.mts +2 -3
  158. package/api/theme/_adapter.mjs +4 -5
  159. package/api/theme/add/add.binary.test.mjs +84 -0
  160. package/api/theme/add/add.mjs +31 -22
  161. package/api/theme/add/add.rollback.test.mjs +158 -0
  162. package/api/theme/add/add.staging.test.mjs +83 -0
  163. package/api/theme/add/add.test.mjs +14 -1
  164. package/api/theme/build/build.family.test.mjs +7 -12
  165. package/api/theme/build/build.mjs +140 -59
  166. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  167. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  168. package/api/theme/build/build.rollback.test.mjs +148 -0
  169. package/api/theme/build/build.test.mjs +127 -0
  170. package/api/theme/build/font-warning.mjs +3 -3
  171. package/api/theme/build/font-warning.test.mjs +5 -2
  172. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  173. package/api/theme/integration-themes.test.mjs +39 -28
  174. package/api/theme/list/list.test.mjs +19 -20
  175. package/api/theme/listThemes.doc.mjs +6 -5
  176. package/api/theme/palette/generate/generate.mjs +8 -3
  177. package/api/theme/palette/generate/generate.test.mjs +96 -0
  178. package/api/theme/palette/generate/generator.d.mts +10 -13
  179. package/api/theme/palette/generate/generator.mjs +15 -4
  180. package/api/theme/palette/generate/generator.test.mjs +10 -0
  181. package/api/theme/template/template.mjs +11 -2
  182. package/api/theme/template/template.test.mjs +20 -0
  183. package/api/theme/theme.type.d.mts +170 -11
  184. package/api/theme/theme.type.mjs +94 -27
  185. package/api/theme/themeAdd.doc.mjs +4 -3
  186. package/api/theme/themeBuild.doc.mjs +8 -4
  187. package/api/theme/themeList.doc.mjs +6 -3
  188. package/api/theme/themeListAvailable.doc.mjs +5 -3
  189. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  190. package/api/theme/themeTargets.doc.mjs +1 -0
  191. package/api/theme/themeTemplate.doc.mjs +6 -2
  192. package/api/upgrade/_adapter.d.mts +32 -5
  193. package/api/upgrade/_adapter.mjs +139 -22
  194. package/api/upgrade/list/list.mjs +2 -1
  195. package/api/upgrade/list/list.test.mjs +73 -0
  196. package/api/upgrade/project-context.test.mjs +272 -0
  197. package/api/upgrade/provider-agreement.test.mjs +152 -0
  198. package/api/upgrade/run/files-changed.test.mjs +111 -0
  199. package/api/upgrade/run/run.mjs +359 -60
  200. package/api/upgrade/status/status.mjs +2 -2
  201. package/api/upgrade/upgrade.doc.mjs +12 -5
  202. package/api/upgrade/upgrade.type.d.mts +43 -5
  203. package/api/upgrade/upgrade.type.mjs +29 -13
  204. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  205. package/assets/codemods/__tests__/runner.test.mjs +332 -8
  206. package/assets/codemods/file-count.test.mjs +163 -0
  207. package/assets/codemods/integration-discovery.mjs +48 -4
  208. package/assets/codemods/integration-discovery.test.mjs +73 -0
  209. package/assets/codemods/integration-runner.mjs +59 -7
  210. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  211. package/assets/codemods/registry.mjs +1 -0
  212. package/assets/codemods/run-codemod.mjs +177 -34
  213. package/assets/codemods/runner.mjs +353 -104
  214. package/assets/codemods/term-log.mjs +32 -8
  215. package/assets/codemods/term-log.test.mjs +19 -1
  216. package/assets/codemods/transform-prop.mjs +109 -0
  217. package/assets/codemods/transform-prop.test.mjs +95 -0
  218. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  219. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  220. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  221. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  222. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  223. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  224. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  225. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  226. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  227. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  228. package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
  229. package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
  230. package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
  231. package/assets/docs/README.md +9 -0
  232. package/assets/docs/authoring.doc.mjs +14 -0
  233. package/assets/docs/getting-started.doc.mjs +2 -2
  234. package/assets/docs/internationalization.doc.mjs +7 -5
  235. package/assets/docs/layout.doc.dense.mjs +2 -2
  236. package/assets/docs/layout.doc.mjs +1 -1
  237. package/assets/docs/principles.doc.mjs +6 -6
  238. package/assets/docs/styling-libraries.doc.mjs +4 -4
  239. package/assets/docs/styling.doc.mjs +4 -4
  240. package/assets/docs/theme.doc.mjs +5 -5
  241. package/assets/docs/tokens.doc.mjs +1 -1
  242. package/assets/docs/tree/api.doc.mjs +30 -0
  243. package/assets/docs/tree/cli.doc.mjs +23 -0
  244. package/assets/docs/tree/commands.doc.mjs +25 -0
  245. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  246. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
  247. package/assets/docs/tree/integrations.test.mjs +62 -0
  248. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  249. package/assets/docs/working-with-ai.doc.mjs +4 -4
  250. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  251. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  252. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  253. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  254. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  255. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  256. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  257. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  258. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  259. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  260. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  261. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  262. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  263. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  264. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  265. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  266. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  267. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  268. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  269. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  270. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  271. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  272. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  273. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
  274. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
  275. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
  276. package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
  277. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
  278. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
  279. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
  280. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
  281. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
  282. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
  283. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  284. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  285. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  286. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  287. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  288. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  289. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  290. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  291. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  292. package/authoring/_shared/contract.ts +22 -0
  293. package/authoring/codemod/codemod.doc.mjs +7 -2
  294. package/authoring/codemod/parse.d.mts +8 -8
  295. package/authoring/codemod/parse.mjs +8 -6
  296. package/authoring/codemod/type.ts +12 -0
  297. package/authoring/config/config.doc.mjs +11 -3
  298. package/authoring/config/debug-composition.test.mjs +92 -0
  299. package/authoring/config/parse.d.mts +15 -13
  300. package/authoring/config/parse.mjs +27 -8
  301. package/authoring/config/parse.test.mjs +8 -0
  302. package/authoring/config/type.ts +31 -8
  303. package/authoring/debug/debug.doc.d.mts +11 -0
  304. package/authoring/debug/debug.doc.mjs +182 -0
  305. package/authoring/debug/parse.d.mts +8 -8
  306. package/authoring/debug/parse.mjs +3 -3
  307. package/authoring/discover/discover.doc.d.mts +13 -0
  308. package/authoring/discover/discover.doc.mjs +138 -0
  309. package/authoring/discover/parse.d.mts +24 -0
  310. package/authoring/discover/parse.mjs +128 -0
  311. package/authoring/discover/parse.test.mjs +124 -0
  312. package/authoring/discover/type.ts +87 -0
  313. package/authoring/doctypes/_schema.d.mts +790 -23
  314. package/authoring/doctypes/_schema.mjs +543 -39
  315. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  316. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  317. package/authoring/doctypes/base/type.ts +41 -0
  318. package/authoring/doctypes/command/command.doc.mjs +5 -4
  319. package/authoring/doctypes/command/parse.d.mts +2 -2
  320. package/authoring/doctypes/command/parse.mjs +1 -1
  321. package/authoring/doctypes/command/type.ts +6 -5
  322. package/authoring/doctypes/component/component.doc.mjs +6 -3
  323. package/authoring/doctypes/component/parse.d.mts +2 -2
  324. package/authoring/doctypes/component/parse.mjs +1 -1
  325. package/authoring/doctypes/component/type.ts +6 -5
  326. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  327. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  328. package/authoring/doctypes/enum/parse.d.mts +2 -2
  329. package/authoring/doctypes/enum/parse.mjs +1 -1
  330. package/authoring/doctypes/enum/type.ts +4 -2
  331. package/authoring/doctypes/function/function.doc.mjs +7 -2
  332. package/authoring/doctypes/function/parse.d.mts +2 -2
  333. package/authoring/doctypes/function/parse.mjs +1 -1
  334. package/authoring/doctypes/function/type.ts +9 -4
  335. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  336. package/authoring/doctypes/hook/parse.d.mts +2 -2
  337. package/authoring/doctypes/hook/parse.mjs +1 -1
  338. package/authoring/doctypes/hook/type.ts +5 -4
  339. package/authoring/doctypes/legacy.d.mts +8 -6
  340. package/authoring/doctypes/legacy.mjs +5 -4
  341. package/authoring/doctypes/load-contract.test.mjs +233 -0
  342. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  343. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  344. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  345. package/authoring/doctypes/namespace/parse.mjs +25 -0
  346. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  347. package/authoring/doctypes/namespace/type.ts +74 -0
  348. package/authoring/doctypes/parse.d.mts +22 -18
  349. package/authoring/doctypes/parse.mjs +22 -11
  350. package/authoring/doctypes/parse.test.mjs +77 -3
  351. package/authoring/doctypes/reference/parse.d.mts +2 -2
  352. package/authoring/doctypes/reference/parse.mjs +8 -5
  353. package/authoring/doctypes/reference/reference.doc.mjs +48 -6
  354. package/authoring/doctypes/reference/type.ts +70 -7
  355. package/authoring/doctypes/schema/parse.d.mts +2 -2
  356. package/authoring/doctypes/schema/parse.mjs +1 -1
  357. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  358. package/authoring/doctypes/schema/type.ts +4 -4
  359. package/authoring/doctypes/template/parse.d.mts +94 -1
  360. package/authoring/doctypes/template/parse.mjs +40 -2
  361. package/authoring/doctypes/template/parse.test.mjs +26 -2
  362. package/authoring/doctypes/template/template.doc.mjs +13 -3
  363. package/authoring/doctypes/template/type.ts +13 -2
  364. package/authoring/doctypes/theme/parse.d.mts +35 -0
  365. package/authoring/doctypes/theme/parse.mjs +76 -0
  366. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  367. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  368. package/authoring/doctypes/theme/type.ts +42 -0
  369. package/authoring/doctypes/types.ts +12 -10
  370. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  371. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  372. package/authoring/gap-report/parse.d.mts +10 -10
  373. package/authoring/gap-report/parse.mjs +6 -6
  374. package/authoring/gap-report/type.ts +1 -1
  375. package/authoring/identity/identity.doc.d.mts +9 -0
  376. package/authoring/identity/identity.doc.mjs +61 -0
  377. package/authoring/identity/type.ts +132 -0
  378. package/authoring/index.d.mts +3 -0
  379. package/authoring/index.d.ts +62 -17
  380. package/authoring/index.mjs +4 -1
  381. package/authoring/integration/integration.doc.mjs +15 -8
  382. package/authoring/integration/parse.d.mts +2 -2
  383. package/authoring/integration/parse.mjs +1 -1
  384. package/authoring/integration/parse.test.mjs +10 -1
  385. package/authoring/integration/schema.d.mts +6 -4
  386. package/authoring/integration/schema.mjs +9 -3
  387. package/authoring/integration/type.ts +19 -8
  388. package/authoring/shadcn/receipt.d.mts +6 -6
  389. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  390. package/clients/cli/command-load-failure.test.mjs +83 -0
  391. package/clients/cli/command-result-coverage.test.mjs +7 -7
  392. package/clients/cli/commands/blog.doc.mjs +1 -1
  393. package/clients/cli/commands/blog.mjs +23 -8
  394. package/clients/cli/commands/blog.test.mjs +42 -1
  395. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  396. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  397. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  398. package/clients/cli/commands/build-theme.mjs +16 -50
  399. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  400. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  401. package/clients/cli/commands/build.doc.mjs +16 -8
  402. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  403. package/clients/cli/commands/build.mjs +137 -114
  404. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  405. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  406. package/clients/cli/commands/component/index.mjs +153 -61
  407. package/clients/cli/commands/component-batch.test.mjs +341 -0
  408. package/clients/cli/commands/component-ownership.test.mjs +92 -3
  409. package/clients/cli/commands/component-package.test.mjs +46 -0
  410. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  411. package/clients/cli/commands/component.doc.mjs +24 -7
  412. package/clients/cli/commands/component.test.mjs +19 -0
  413. package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
  414. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  415. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  416. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  417. package/clients/cli/commands/discover.doc.mjs +55 -9
  418. package/clients/cli/commands/discover.mjs +393 -118
  419. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  420. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  421. package/clients/cli/commands/docs.doc.mjs +28 -6
  422. package/clients/cli/commands/docs.mjs +240 -26
  423. package/clients/cli/commands/docs.test.mjs +222 -1
  424. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  425. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  426. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  427. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  428. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  429. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  430. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  431. package/clients/cli/commands/doctor.doc.mjs +1 -1
  432. package/clients/cli/commands/doctor.mjs +59 -32
  433. package/clients/cli/commands/doctor.test.mjs +42 -0
  434. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  435. package/clients/cli/commands/gap-report.test.mjs +72 -0
  436. package/clients/cli/commands/hook/index.mjs +7 -17
  437. package/clients/cli/commands/hook.doc.mjs +1 -1
  438. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  439. package/clients/cli/commands/init.doc.mjs +20 -9
  440. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  441. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  442. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  443. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  444. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  445. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  446. package/clients/cli/commands/integration.doc.mjs +1 -1
  447. package/clients/cli/commands/integration.mjs +1 -0
  448. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  449. package/clients/cli/commands/json-contract.test.mjs +33 -0
  450. package/clients/cli/commands/manifest.doc.mjs +1 -1
  451. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  452. package/clients/cli/commands/search.doc.mjs +7 -4
  453. package/clients/cli/commands/search.mjs +28 -9
  454. package/clients/cli/commands/search.test.mjs +75 -0
  455. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  456. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  457. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  458. package/clients/cli/commands/template.doc.mjs +52 -13
  459. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  460. package/clients/cli/commands/template.mjs +4 -91
  461. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  462. package/clients/cli/commands/text-json-parity.test.mjs +702 -0
  463. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  464. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  465. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  466. package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
  467. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  468. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  469. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  470. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  471. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  472. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  473. package/clients/cli/commands/theme.doc.mjs +1 -1
  474. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  475. package/clients/cli/commands/upgrade.doc.mjs +22 -10
  476. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  477. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  478. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  479. package/clients/cli/commands/upgrade.mjs +29 -7
  480. package/clients/cli/formatters/index.mjs +164 -1
  481. package/clients/cli/formatters/index.test.mjs +97 -0
  482. package/clients/cli/index.mjs +21 -34
  483. package/clients/cli/latest-version-env.test.mjs +50 -0
  484. package/clients/cli/lib/cli-error.test.mjs +7 -0
  485. package/clients/cli/lib/component-format.mjs +9 -9
  486. package/clients/cli/lib/component-format.test.mjs +1 -1
  487. package/clients/cli/lib/define-command.mjs +32 -6
  488. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  489. package/clients/cli/lib/exit-codes.test.mjs +90 -0
  490. package/clients/cli/lib/hook-format.mjs +19 -10
  491. package/clients/cli/lib/json-shim.mjs +62 -16
  492. package/clients/cli/lib/json-shim.test.mjs +69 -0
  493. package/clients/cli/lib/manifest.d.ts +2 -0
  494. package/clients/cli/lib/manifest.mjs +39 -10
  495. package/clients/cli/lib/manifest.test.mjs +22 -2
  496. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  497. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  498. package/foundation/agent-docs/agent-docs.mjs +82 -12
  499. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  500. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  501. package/foundation/config/integration-debug.test.mjs +28 -3
  502. package/foundation/config/project-themes.test.mjs +11 -19
  503. package/foundation/config/project.d.mts +20 -11
  504. package/foundation/config/project.mjs +263 -91
  505. package/foundation/config/project.test.mjs +270 -21
  506. package/foundation/discovery/authoring-self-docs.d.mts +87 -0
  507. package/foundation/discovery/authoring-self-docs.mjs +237 -0
  508. package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
  509. package/foundation/discovery/authoring-surface.d.mts +74 -0
  510. package/foundation/discovery/authoring-surface.mjs +525 -0
  511. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  512. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  513. package/foundation/discovery/cli-self-docs.mjs +490 -0
  514. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  515. package/foundation/discovery/component-discovery.d.mts +39 -1
  516. package/foundation/discovery/component-discovery.mjs +50 -1
  517. package/foundation/discovery/component-loader.d.mts +35 -38
  518. package/foundation/discovery/component-loader.mjs +53 -222
  519. package/foundation/discovery/docs-discovery.d.mts +119 -11
  520. package/foundation/discovery/docs-discovery.mjs +423 -108
  521. package/foundation/discovery/docs-discovery.test.mjs +365 -20
  522. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  523. package/foundation/discovery/docs-output-budget.mjs +50 -0
  524. package/foundation/discovery/docs-section-key.d.mts +116 -0
  525. package/foundation/discovery/docs-section-key.mjs +322 -0
  526. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  527. package/foundation/discovery/template-adapter.d.mts +113 -11
  528. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  529. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  530. package/foundation/discovery/template-adapter.mjs +775 -84
  531. package/foundation/discovery/template-adapter.test.mjs +57 -0
  532. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  533. package/foundation/discovery/template-conflict-release.mjs +40 -0
  534. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  535. package/foundation/discovery/theme-discovery.d.mts +67 -7
  536. package/foundation/discovery/theme-discovery.mjs +916 -186
  537. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  538. package/foundation/discovery/theming-targets.test.mjs +4 -0
  539. package/foundation/doc-compiler/bundle.d.mts +47 -0
  540. package/foundation/doc-compiler/bundle.mjs +278 -0
  541. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  542. package/foundation/doc-compiler/compile.d.mts +343 -0
  543. package/foundation/doc-compiler/compile.mjs +558 -0
  544. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  545. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  546. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  547. package/foundation/doc-compiler/doc-loads.test.mjs +1630 -0
  548. package/foundation/doc-compiler/import.d.mts +24 -0
  549. package/foundation/doc-compiler/import.mjs +59 -0
  550. package/foundation/doc-compiler/inputs.d.mts +102 -0
  551. package/foundation/doc-compiler/inputs.mjs +291 -0
  552. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  553. package/foundation/doc-compiler/ir.d.mts +22 -0
  554. package/foundation/doc-compiler/ir.mjs +471 -0
  555. package/foundation/doc-compiler/lenses.d.mts +36 -0
  556. package/foundation/doc-compiler/lenses.mjs +173 -0
  557. package/foundation/doc-compiler/links.d.mts +162 -0
  558. package/foundation/doc-compiler/links.mjs +294 -0
  559. package/foundation/doc-compiler/links.test.mjs +192 -0
  560. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  561. package/foundation/doc-compiler/overlays.d.mts +37 -0
  562. package/foundation/doc-compiler/overlays.mjs +206 -0
  563. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  564. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  565. package/foundation/doc-compiler/read.d.mts +127 -0
  566. package/foundation/doc-compiler/read.mjs +325 -0
  567. package/foundation/doc-compiler/read.test.mjs +313 -0
  568. package/foundation/doc-compiler/source.d.mts +33 -0
  569. package/foundation/doc-compiler/source.mjs +128 -0
  570. package/foundation/doc-compiler/tree.d.mts +288 -0
  571. package/foundation/doc-compiler/tree.mjs +876 -0
  572. package/foundation/doc-compiler/tree.test.mjs +606 -0
  573. package/foundation/fs/file-protection.d.mts +33 -0
  574. package/foundation/fs/file-protection.mjs +825 -0
  575. package/foundation/fs/file-protection.test.mjs +250 -0
  576. package/foundation/fs/module-loader.d.mts +1 -0
  577. package/foundation/fs/module-loader.mjs +50 -1
  578. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  579. package/foundation/fs/path-safety.d.mts +3 -2
  580. package/foundation/fs/path-safety.mjs +49 -19
  581. package/foundation/fs/path-safety.test.mjs +50 -0
  582. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  583. package/foundation/identity/provider-identity.d.mts +90 -0
  584. package/foundation/identity/provider-identity.mjs +320 -0
  585. package/foundation/identity/provider-identity.test.mjs +254 -0
  586. package/foundation/identity/providers.d.mts +7 -0
  587. package/foundation/identity/providers.mjs +16 -0
  588. package/foundation/integrations/autolink.d.mts +58 -1
  589. package/foundation/integrations/autolink.mjs +143 -45
  590. package/foundation/integrations/autolink.test.mjs +1 -1
  591. package/foundation/integrations/cli-requirement.d.mts +45 -0
  592. package/foundation/integrations/cli-requirement.mjs +154 -0
  593. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  594. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  595. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  596. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  597. package/foundation/integrations/contribution-inventory.mjs +27 -24
  598. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  599. package/foundation/integrations/integration-warnings.d.mts +9 -2
  600. package/foundation/integrations/integration-warnings.mjs +52 -21
  601. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  602. package/foundation/integrations/integrations.d.mts +63 -3
  603. package/foundation/integrations/integrations.mjs +122 -9
  604. package/foundation/integrations/integrations.test.mjs +415 -1
  605. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  606. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  607. package/foundation/integrations/provider-resolution.d.mts +152 -0
  608. package/foundation/integrations/provider-resolution.mjs +576 -0
  609. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  610. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  611. package/foundation/integrations/theme-descriptor.mjs +44 -0
  612. package/foundation/integrations/validate-contributions.d.mts +2 -0
  613. package/foundation/integrations/validate-contributions.mjs +131 -29
  614. package/foundation/response/base.d.ts +8 -4
  615. package/foundation/response/batch.type.d.mts +33 -0
  616. package/foundation/response/batch.type.mjs +34 -0
  617. package/foundation/response/error-codes.d.mts +3 -1
  618. package/foundation/response/error-codes.d.ts +2 -0
  619. package/foundation/response/error-codes.doc.mjs +13 -4
  620. package/foundation/response/error-codes.mjs +8 -2
  621. package/foundation/response/error-codes.test.mjs +137 -10
  622. package/foundation/response/json-contract.test.mjs +57 -17
  623. package/foundation/response/json.d.mts +4 -2
  624. package/foundation/response/json.mjs +8 -10
  625. package/foundation/response/response-types.doc.d.mts +5 -1
  626. package/foundation/response/response-types.doc.mjs +46 -38
  627. package/foundation/response/response-types.doc.test.mjs +181 -0
  628. package/foundation/response/response.doc.mjs +1 -1
  629. package/foundation/text/string-utils.d.mts +8 -0
  630. package/foundation/text/string-utils.mjs +40 -10
  631. package/foundation/xle/browser.d.mts +3 -3
  632. package/foundation/xle/browser.mjs +3 -3
  633. package/foundation/xle/expand.d.mts +2 -0
  634. package/foundation/xle/expand.mjs +6 -5
  635. package/foundation/xle/expand.test.mjs +54 -0
  636. package/foundation/xle/parse.mjs +1 -1
  637. package/foundation/xle/print.mjs +2 -2
  638. package/foundation/xle/splice.mjs +1 -1
  639. package/foundation/xle/xle.test.mjs +13 -0
  640. package/package.json +10 -11
  641. package/api/layout/_adapter.d.mts +0 -34
  642. package/api/layout/_adapter.mjs +0 -133
  643. package/api/layout/check/check.d.mts +0 -16
  644. package/api/layout/check/check.mjs +0 -40
  645. package/api/layout/expand/expand.d.mts +0 -22
  646. package/api/layout/expand/expand.mjs +0 -153
  647. package/api/layout/grammar/grammar.d.mts +0 -13
  648. package/api/layout/grammar/grammar.mjs +0 -86
  649. package/api/layout/layout.d.mts +0 -6
  650. package/api/layout/layout.mjs +0 -17
  651. package/api/layout/layout.test.mjs +0 -297
  652. package/api/layout/layout.type.d.mts +0 -89
  653. package/api/layout/layout.type.mjs +0 -103
  654. package/api/layout/layoutCheck.doc.d.mts +0 -11
  655. package/api/layout/layoutCheck.doc.mjs +0 -84
  656. package/api/layout/layoutExpand.doc.d.mts +0 -11
  657. package/api/layout/layoutExpand.doc.mjs +0 -106
  658. package/api/layout/layoutGrammar.doc.d.mts +0 -11
  659. package/api/layout/layoutGrammar.doc.mjs +0 -56
  660. package/assets/templates/themes/manifest.json +0 -95
  661. package/clients/cli/commands/layout-check.doc.mjs +0 -54
  662. package/clients/cli/commands/layout-expand.doc.mjs +0 -66
  663. package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
  664. package/clients/cli/commands/layout.doc.mjs +0 -34
  665. package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
  666. package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
  667. package/clients/cli/commands/layout.mjs +0 -263
  668. package/clients/cli/lib/update-check.mjs +0 -83
  669. package/clients/cli/lib/update-check.test.mjs +0 -137
  670. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -12,6 +12,7 @@ import {
12
12
  integrationAddTemplate,
13
13
  } from './add-contribution.mjs';
14
14
  import {validateLocalIntegration} from './validate-integration.mjs';
15
+ import {DOCS_TREE_CLI} from '../../foundation/integrations/cli-requirement.mjs';
15
16
 
16
17
  let tmpDir;
17
18
 
@@ -77,6 +78,7 @@ describe('integrationAdd component', () => {
77
78
  path.join(tmpDir, 'components/MyWidget.doc.mjs'),
78
79
  'utf-8',
79
80
  );
81
+ expect(doc).toContain("@astryxdesign/cli/authoring').ComponentDoc");
80
82
  expect(doc).toContain("type: 'component'");
81
83
  expect(doc).toContain("name: 'MyWidget'");
82
84
  expect(doc).toContain('props: []');
@@ -118,14 +120,14 @@ describe('integrationAdd component', () => {
118
120
  );
119
121
  expect(pkg.exports).toEqual({
120
122
  '.': './index.mjs',
121
- './components/MyWidget.tsx': './components/MyWidget.tsx',
123
+ './components/MyWidget': './components/MyWidget.tsx',
122
124
  });
123
125
  expect(
124
126
  fs.readFileSync(
125
127
  path.join(tmpDir, 'components/MyWidget.doc.mjs'),
126
128
  'utf-8',
127
129
  ),
128
- ).toContain('import: "@acme/integration/components/MyWidget.tsx"');
130
+ ).toContain('import: "@acme/integration/components/MyWidget"');
129
131
  });
130
132
 
131
133
  it('does not create exports when the package has no exports map', async () => {
@@ -143,7 +145,7 @@ describe('integrationAdd component', () => {
143
145
  setup({
144
146
  exports: {
145
147
  '.': './index.mjs',
146
- './components/MyWidget.tsx': './different.tsx',
148
+ './components/MyWidget': './different.tsx',
147
149
  },
148
150
  });
149
151
 
@@ -304,6 +306,7 @@ describe('integrationAdd doc', () => {
304
306
  path.join(tmpDir, 'docs/my-guide.doc.mjs'),
305
307
  'utf-8',
306
308
  );
309
+ expect(doc).toContain("@astryxdesign/cli/authoring').ReferenceDoc");
307
310
  expect(doc).toContain("type: 'generic'");
308
311
  expect(doc).toContain("name: 'my-guide'");
309
312
 
@@ -312,6 +315,142 @@ describe('integrationAdd doc', () => {
312
315
  expect(docErrors).toEqual([]);
313
316
  });
314
317
 
318
+ it('refuses to write from a folder with no package.json into the package above it', async () => {
319
+ setupBare();
320
+ const inside = path.join(tmpDir, 'kit');
321
+ fs.mkdirSync(inside);
322
+ await expect(
323
+ integrationAdd('doc', 'my-guide', {cwd: inside, parent: 'acme'}),
324
+ ).rejects.toMatchObject({
325
+ code: 'ERR_INVALID_ARGUMENT',
326
+ message: expect.stringContaining('has no package.json'),
327
+ });
328
+ expect(fs.existsSync(path.join(tmpDir, 'docs'))).toBe(false);
329
+ expect(fs.existsSync(path.join(tmpDir, 'astryx.integration.mjs'))).toBe(false);
330
+ });
331
+
332
+ it('finds an integration from a folder inside it', async () => {
333
+ setup();
334
+ const inside = path.join(tmpDir, 'src');
335
+ fs.mkdirSync(inside);
336
+ const result = await integrationAdd('doc', 'my-guide', {cwd: inside});
337
+ expect(result.data.files).toContain('docs/my-guide.doc.mjs');
338
+ expect(fs.existsSync(path.join(tmpDir, 'docs/my-guide.doc.mjs'))).toBe(true);
339
+ });
340
+
341
+ it('places a guide in a namespace of the package, writing the namespace once', async () => {
342
+ setup();
343
+ const first = await integrationAdd('doc', 'deploying', {
344
+ cwd: tmpDir,
345
+ parent: 'acme',
346
+ });
347
+ expect(first.data.files).toEqual(
348
+ expect.arrayContaining(['docs/deploying.doc.mjs', 'docs/acme.doc.mjs']),
349
+ );
350
+ const guide = fs.readFileSync(path.join(tmpDir, 'docs/deploying.doc.mjs'), 'utf-8');
351
+ expect(guide).toContain("placement: {parent: 'namespace:acme', slot: 'guides'}");
352
+ const namespace = fs.readFileSync(path.join(tmpDir, 'docs/acme.doc.mjs'), 'utf-8');
353
+ expect(namespace).toContain("type: 'namespace'");
354
+ expect(namespace).toContain("guides: {title: 'Guides', accepts: {kinds: ['generic']}}");
355
+
356
+ // The namespace doc needs a CLI that reads it, declared as an optional peer.
357
+ const pkg = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'));
358
+ expect(pkg.peerDependencies).toEqual({'@astryxdesign/cli': `>=${DOCS_TREE_CLI}`});
359
+ expect(pkg.peerDependenciesMeta).toEqual({'@astryxdesign/cli': {optional: true}});
360
+
361
+ const second = await integrationAdd('doc', 'upgrading', {
362
+ cwd: tmpDir,
363
+ parent: 'acme',
364
+ });
365
+ expect(second.data.files).not.toContain('docs/acme.doc.mjs');
366
+
367
+ const validation = await validateLocalIntegration(tmpDir);
368
+ expect(validation.issues.filter(i => i.code === 'invalid_doc')).toEqual([]);
369
+ });
370
+
371
+ it('finds the --parent namespace by its name, wherever its file is, and uses its slot', async () => {
372
+ setup({manifest: "export default {docs: './docs'};\n"});
373
+ fs.mkdirSync(path.join(tmpDir, 'docs', 'ns'), {recursive: true});
374
+ fs.writeFileSync(
375
+ path.join(tmpDir, 'docs', 'ns', 'acme.doc.mjs'),
376
+ "export default {type: 'namespace', name: 'acme', title: 'Acme', summary: 'Acme.', slots: {items: {title: 'Items', accepts: {kinds: ['generic']}}}};\n",
377
+ );
378
+ const result = await integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'});
379
+ expect(result.data.files).not.toContain('docs/acme.doc.mjs');
380
+ expect(fs.existsSync(path.join(tmpDir, 'docs', 'acme.doc.mjs'))).toBe(false);
381
+ expect(fs.readFileSync(path.join(tmpDir, 'docs', 'deploying.doc.mjs'), 'utf-8')).toContain(
382
+ "placement: {parent: 'namespace:acme', slot: 'items'}",
383
+ );
384
+ });
385
+
386
+ it('refuses --parent when its file is not that namespace, or the namespace has no slot for a guide', async () => {
387
+ setup({manifest: "export default {docs: './docs'};\n"});
388
+ fs.mkdirSync(path.join(tmpDir, 'docs'), {recursive: true});
389
+ const nsFile = path.join(tmpDir, 'docs', 'acme.doc.mjs');
390
+ fs.writeFileSync(
391
+ nsFile,
392
+ "export default {type: 'generic', name: 'acme', title: 'Acme', description: 'A topic.', sections: [{title: 'Only', content: [{type: 'prose', text: 'x'}]}]};\n",
393
+ );
394
+ await expect(
395
+ integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'}),
396
+ ).rejects.toMatchObject({code: 'ERR_FILE_EXISTS'});
397
+ // A fresh file: the module loader keeps the first import of a path.
398
+ fs.writeFileSync(
399
+ path.join(tmpDir, 'docs', 'beta.doc.mjs'),
400
+ "export default {type: 'namespace', name: 'beta', title: 'Beta', summary: 'Beta.', slots: {items: {title: 'Items', accepts: {kinds: ['function']}}}};\n",
401
+ );
402
+ await expect(
403
+ integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'beta'}),
404
+ ).rejects.toMatchObject({
405
+ code: 'ERR_INVALID_ARGUMENT',
406
+ message: expect.stringContaining('no slot that takes a guide'),
407
+ });
408
+ fs.writeFileSync(
409
+ path.join(tmpDir, 'docs', 'gamma.doc.mjs'),
410
+ "export default {type: 'namespace', name: 'gamma', title: 'Gamma', summary: 'Gamma.', slots: {guides: {title: 'Guides', accepts: {kinds: ['function']}}, more: {title: 'More', accepts: {kinds: ['generic']}}, extra: {title: 'Extra', accepts: {kinds: ['generic']}}}};\n",
411
+ );
412
+ await expect(
413
+ integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'gamma'}),
414
+ ).rejects.toMatchObject({
415
+ code: 'ERR_INVALID_ARGUMENT',
416
+ message: expect.stringContaining('more than one slot that takes a guide (more, extra)'),
417
+ });
418
+ expect(fs.existsSync(path.join(tmpDir, 'docs', 'deploying.doc.mjs'))).toBe(false);
419
+ });
420
+
421
+ it('raises a CLI peer that admits a CLI too old for namespace docs, and keeps one that does not', async () => {
422
+ setup();
423
+ const file = path.join(tmpDir, 'package.json');
424
+ const write = (/** @type {string} */ range) => {
425
+ const pkg = JSON.parse(fs.readFileSync(file, 'utf-8'));
426
+ pkg.peerDependencies = {'@astryxdesign/cli': range};
427
+ fs.writeFileSync(file, `${JSON.stringify(pkg, null, 2)}\n`);
428
+ };
429
+ write('^0.6.0');
430
+ await integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'});
431
+ expect(JSON.parse(fs.readFileSync(file, 'utf-8')).peerDependencies).toEqual({
432
+ '@astryxdesign/cli': `>=${DOCS_TREE_CLI}`,
433
+ });
434
+ write('^9.1.0');
435
+ await integrationAdd('doc', 'upgrading', {cwd: tmpDir, parent: 'acme'});
436
+ expect(JSON.parse(fs.readFileSync(file, 'utf-8')).peerDependencies).toEqual({
437
+ '@astryxdesign/cli': '^9.1.0',
438
+ });
439
+ });
440
+
441
+ it('refuses --parent with a relationship, or a namespace name that is not a route segment', async () => {
442
+ setup();
443
+ await expect(
444
+ integrationAdd('doc', 'x', {cwd: tmpDir, parent: 'acme', replaces: 'getting-started'}),
445
+ ).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
446
+ await expect(
447
+ integrationAdd('doc', 'x', {cwd: tmpDir, parent: 'Acme Kit'}),
448
+ ).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
449
+ await expect(
450
+ integrationAdd('template', 'x', {cwd: tmpDir, parent: 'acme'}),
451
+ ).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
452
+ });
453
+
315
454
  it('includes replaces in the generated doc', async () => {
316
455
  setup();
317
456
  const result = await integrationAdd('doc', 'my-tokens', {
@@ -390,13 +529,14 @@ describe('integrationAdd template', () => {
390
529
  expect(result.data.kind).toBe('template');
391
530
  expect(result.data.name).toBe('my-widget');
392
531
  expect(result.data.root).toEqual({path: './templates', created: true});
393
- expect(result.data.files).toContain('templates/my-widget.template.mjs');
532
+ expect(result.data.files).toContain('templates/my-widget.doc.mjs');
394
533
  expect(result.data.files).toContain('templates/my-widget.tsx');
395
534
 
396
535
  const spec = fs.readFileSync(
397
- path.join(tmpDir, 'templates/my-widget.template.mjs'),
536
+ path.join(tmpDir, 'templates/my-widget.doc.mjs'),
398
537
  'utf-8',
399
538
  );
539
+ expect(spec).toContain("@astryxdesign/cli/authoring').TemplateDoc");
400
540
  expect(spec).toContain("type: 'page'");
401
541
  expect(spec).toContain("name: 'my-widget'");
402
542
 
@@ -421,7 +561,7 @@ describe('integrationAdd template', () => {
421
561
  );
422
562
  expect(pkg.exports).toEqual({
423
563
  '.': './index.mjs',
424
- './templates/my-widget.tsx': './templates/my-widget.tsx',
564
+ './templates/my-widget': './templates/my-widget.tsx',
425
565
  });
426
566
  });
427
567
 
@@ -432,10 +572,11 @@ describe('integrationAdd template', () => {
432
572
  templateType: 'block',
433
573
  });
434
574
  const spec = fs.readFileSync(
435
- path.join(tmpDir, 'templates/my-card.template.mjs'),
575
+ path.join(tmpDir, 'templates/my-card.doc.mjs'),
436
576
  'utf-8',
437
577
  );
438
578
  expect(spec).toContain("type: 'block'");
579
+ expect(spec).toContain('aspectRatio: 1');
439
580
  });
440
581
 
441
582
  it('rejects an invalid template type', async () => {
@@ -676,6 +817,35 @@ describe('custom root preservation', () => {
676
817
  });
677
818
  });
678
819
 
820
+ describe('typed descriptor conformance', () => {
821
+ it('emits a strongly typed .doc.mjs for every canonical item writer', async () => {
822
+ setup();
823
+ await integrationAdd('component', 'MyWidget', {cwd: tmpDir});
824
+ await integrationAdd('doc', 'my-guide', {cwd: tmpDir});
825
+ await integrationAdd('template', 'my-page', {cwd: tmpDir});
826
+ await integrationAdd('theme', 'ocean', {cwd: tmpDir});
827
+
828
+ // Codemod and agent-doc keep their released formats for compatibility;
829
+ // no new kind may copy those exceptions.
830
+ for (const [relativePath, type] of [
831
+ ['components/MyWidget.doc.mjs', 'ComponentDoc'],
832
+ ['docs/my-guide.doc.mjs', 'ReferenceDoc'],
833
+ ['templates/my-page.doc.mjs', 'TemplateDoc'],
834
+ ['themes/ocean/oceanTheme.doc.mjs', 'ThemeDoc'],
835
+ ]) {
836
+ const source = fs.readFileSync(path.join(tmpDir, relativePath), 'utf-8');
837
+ expect(source).toContain(`@astryxdesign/cli/authoring').${type}`);
838
+ expect(source).toContain('export default {');
839
+ }
840
+ expect(
841
+ fs.existsSync(path.join(tmpDir, 'templates/my-page.template.mjs')),
842
+ ).toBe(false);
843
+ expect(fs.existsSync(path.join(tmpDir, 'themes/manifest.json'))).toBe(
844
+ false,
845
+ );
846
+ });
847
+ });
848
+
679
849
  describe('public per-kind APIs', () => {
680
850
  it('exposes narrow functions for every non-theme contribution kind', async () => {
681
851
  setup();
@@ -711,6 +881,7 @@ describe('public dispatcher', () => {
711
881
  const result = await integrationAdd('theme', 'ocean', {cwd: tmpDir});
712
882
  expect(result.data).toMatchObject({kind: 'theme', name: 'ocean'});
713
883
  expect(result.data.files).toContain('themes/ocean/oceanTheme.ts');
884
+ expect(result.data.files).toContain('themes/ocean/oceanTheme.doc.mjs');
714
885
  });
715
886
 
716
887
  it('refuses a kind-specific option on the wrong kind', async () => {
@@ -731,3 +902,83 @@ describe('public dispatcher', () => {
731
902
  ).rejects.toThrow(/component, doc, template, codemod, agent-doc, or theme/);
732
903
  });
733
904
  });
905
+
906
+ describe('dry-run receipts match the real write', () => {
907
+ /** Package states each writer has to plan for. */
908
+ const STATES = {
909
+ 'no manifest': {pkg: {files: ['dist']}},
910
+ 'an empty manifest': {pkg: {}, manifest: 'export default {};\n'},
911
+ 'declared roots and an exports map': {
912
+ pkg: {files: ['dist'], exports: {'.': './dist/index.js'}},
913
+ manifest:
914
+ "export default {\n components: './components',\n docs: './docs',\n templates: './templates',\n codemods: './codemods',\n themes: './themes',\n};\n",
915
+ },
916
+ };
917
+ /** @type {Array<[any, string, Record<string, unknown>]>} */
918
+ const KINDS = [
919
+ ['component', 'AcmeWidget', {}],
920
+ ['doc', 'deploying', {}],
921
+ ['template', 'account-page', {}],
922
+ ['template', 'account-card', {templateType: 'block'}],
923
+ ['codemod', 'rename-widget', {to: '1.2.0'}],
924
+ ['agent-doc', 'Run acme verify before finishing.', {}],
925
+ ['theme', 'ocean', {}],
926
+ ];
927
+
928
+ /** Every file under the package, keyed by project path, with its bytes. */
929
+ function snapshot() {
930
+ /** @type {Record<string, string>} */
931
+ const files = {};
932
+ /** @param {string} dir */
933
+ const walk = dir => {
934
+ for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
935
+ const full = path.join(dir, entry.name);
936
+ if (entry.isDirectory()) walk(full);
937
+ else {
938
+ files[path.relative(tmpDir, full).split(path.sep).join('/')] =
939
+ fs.readFileSync(full, 'base64');
940
+ }
941
+ }
942
+ };
943
+ walk(tmpDir);
944
+ return files;
945
+ }
946
+
947
+ for (const [stateName, state] of Object.entries(STATES)) {
948
+ for (const [kind, name, options] of KINDS) {
949
+ it(`${kind} ${name} in a package with ${stateName}`, async () => {
950
+ fs.writeFileSync(
951
+ path.join(tmpDir, 'package.json'),
952
+ `${JSON.stringify({name: '@acme/integration', version: '1.0.0', ...state.pkg}, null, 2)}\n`,
953
+ );
954
+ if (state.manifest != null) {
955
+ fs.writeFileSync(
956
+ path.join(tmpDir, 'astryx.integration.mjs'),
957
+ state.manifest,
958
+ );
959
+ }
960
+ const before = snapshot();
961
+
962
+ const plan = await integrationAdd(kind, name, {
963
+ cwd: tmpDir,
964
+ dryRun: true,
965
+ ...options,
966
+ });
967
+ expect(snapshot()).toEqual(before);
968
+
969
+ const written = await integrationAdd(kind, name, {
970
+ cwd: tmpDir,
971
+ ...options,
972
+ });
973
+ const after = snapshot();
974
+ const changed = Object.keys(after)
975
+ .filter(file => after[file] !== before[file])
976
+ .sort();
977
+
978
+ expect(written.data.root).toEqual(plan.data.root);
979
+ expect(written.data.files).toEqual(plan.data.files);
980
+ expect([...written.data.files].sort()).toEqual(changed);
981
+ });
982
+ }
983
+ }
984
+ });
@@ -8,7 +8,7 @@ export function findPackageDir(startDir: string): string;
8
8
  /**
9
9
  * @typedef {object} WritePlan
10
10
  * @property {string} path
11
- * @property {string} contents
11
+ * @property {string | Buffer} contents a Buffer is written byte for byte
12
12
  * @property {boolean} createOnly
13
13
  * @property {Buffer} [expectedOriginal] bytes captured before validation;
14
14
  * a different current file is a concurrent edit and must never be overwritten
@@ -56,7 +56,10 @@ export function packageJsonUpdate(packageFile: string, rootPath: string, manifes
56
56
  export function applyWrites(plans: WritePlan[]): () => void;
57
57
  export type WritePlan = {
58
58
  path: string;
59
- contents: string;
59
+ /**
60
+ * a Buffer is written byte for byte
61
+ */
62
+ contents: string | Buffer;
60
63
  createOnly: boolean;
61
64
  /**
62
65
  * bytes captured before validation;
@@ -5,7 +5,8 @@
5
5
  *
6
6
  * Hosts the atomic staged-write transaction, package.json files-array
7
7
  * maintenance, package-dir resolution, and project-path normalization that
8
- * every `integration add <kind>` command needs. Stateless and side-effect-free
8
+ * every `integration add <kind>` command needs. `theme add` and `theme build`
9
+ * write through the same transaction. Stateless and side-effect-free
9
10
  * outside of {@link applyWrites}.
10
11
  */
11
12
 
@@ -40,7 +41,7 @@ export function findPackageDir(startDir) {
40
41
  /**
41
42
  * @typedef {object} WritePlan
42
43
  * @property {string} path
43
- * @property {string} contents
44
+ * @property {string | Buffer} contents a Buffer is written byte for byte
44
45
  * @property {boolean} createOnly
45
46
  * @property {Buffer} [expectedOriginal] bytes captured before validation;
46
47
  * a different current file is a concurrent edit and must never be overwritten
@@ -192,21 +193,29 @@ export function packageJsonUpdate(
192
193
 
193
194
  // ── Atomic staged-write transaction ─────────────────────────────────
194
195
 
195
- /** @param {string} file */
196
+ /**
197
+ * @param {string} file
198
+ * @returns {boolean} false when the file is still there
199
+ */
196
200
  function removeTemporary(file) {
197
201
  try {
198
202
  fs.rmSync(file, {force: true});
203
+ return true;
199
204
  } catch {
200
205
  // Best effort. The transaction error remains the actionable failure.
206
+ return false;
201
207
  }
202
208
  }
203
209
 
204
210
  /**
205
211
  * Restore writes that already published. Best-effort so callers preserve
206
- * the original actionable error.
212
+ * the original actionable error; returns every path it could not put back.
207
213
  * @param {Array<WritePlan & {temporary: string, original: Buffer|null, mode: number}>} published
214
+ * @returns {string[]}
208
215
  */
209
216
  function rollbackWrites(published) {
217
+ /** @type {string[]} */
218
+ const unrestored = [];
210
219
  for (const plan of [...published].reverse()) {
211
220
  let restore = null;
212
221
  try {
@@ -225,12 +234,18 @@ function rollbackWrites(published) {
225
234
  fs.renameSync(restore, plan.path);
226
235
  restore = null;
227
236
  }
228
- } catch {
229
- // Best effort. A concurrent edit belongs to its writer, not this rollback.
237
+ } catch (error) {
238
+ // A created file that is already gone needs nothing. Any other failure
239
+ // leaves this call's bytes, or no bytes, where the original was.
240
+ const gone =
241
+ error instanceof Error &&
242
+ /** @type {NodeJS.ErrnoException} */ (error).code === 'ENOENT';
243
+ if (!(gone && plan.original == null)) unrestored.push(plan.path);
230
244
  } finally {
231
245
  if (restore != null) removeTemporary(restore);
232
246
  }
233
247
  }
248
+ return unrestored;
234
249
  }
235
250
 
236
251
  /** @param {string} file */
@@ -325,10 +340,22 @@ export function applyWrites(plans) {
325
340
  }
326
341
  published.push(plan);
327
342
  }
328
- return () => rollbackWrites(published);
343
+ return () => {
344
+ rollbackWrites(published);
345
+ };
329
346
  } catch (error) {
330
- for (const plan of staged) removeTemporary(plan.temporary);
331
- rollbackWrites(published);
347
+ const leftovers = staged
348
+ .filter(plan => !removeTemporary(plan.temporary))
349
+ .map(plan => plan.temporary);
350
+ const unrestored = rollbackWrites(published);
351
+ if (error instanceof Error) {
352
+ if (unrestored.length > 0) {
353
+ error.message += ` Could not restore: ${unrestored.join(', ')}.`;
354
+ }
355
+ if (leftovers.length > 0) {
356
+ error.message += ` Could not remove temporary files: ${leftovers.join(', ')}.`;
357
+ }
358
+ }
332
359
  throw error;
333
360
  }
334
361
  }
@@ -1,9 +1,9 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file `astryx integration add theme` — scaffold one valid source theme into
5
- * an integration package, update its theme catalog, and declare the root on
6
- * first use.
4
+ * @file `astryx integration add theme` — scaffold one strongly typed,
5
+ * same-stem source/descriptor pair into an integration package and declare the
6
+ * themes root on first use.
7
7
  */
8
8
 
9
9
  import * as fs from 'node:fs';
@@ -15,16 +15,14 @@ import {
15
15
  PathSafetyError,
16
16
  sanitizeName,
17
17
  } from '../../foundation/fs/path-safety.mjs';
18
- import {
19
- discoverThemeCatalog,
20
- THEME_MANIFEST_BASENAME,
21
- } from '../../foundation/discovery/theme-discovery.mjs';
18
+ import {discoverThemeDirectory} from '../../foundation/discovery/theme-discovery.mjs';
22
19
  import {
23
20
  findLocalIntegrationManifestOrNull,
24
21
  IntegrationRootConflictError,
25
22
  patchIntegrationRoot,
26
23
  } from '../../foundation/integrations/manifest-writer.mjs';
27
24
  import {loadManifestObject} from '../../foundation/integrations/integrations.mjs';
25
+ import {themeDescriptorSource} from '../../foundation/integrations/theme-descriptor.mjs';
28
26
  import {assertContributionVisible} from '../../foundation/integrations/contribution-inventory.mjs';
29
27
  import {
30
28
  applyWrites,
@@ -70,6 +68,7 @@ function themeIdentity(slug) {
70
68
  displayName,
71
69
  exportName: `${identifier}Theme`,
72
70
  entry: `${identifier}Theme.ts`,
71
+ descriptor: `${identifier}Theme.doc.mjs`,
73
72
  };
74
73
  }
75
74
 
@@ -78,9 +77,20 @@ function themeSource(identity) {
78
77
  return `import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const ${identity.exportName} = defineTheme({\n name: '${identity.slug}',\n});\n`;
79
78
  }
80
79
 
80
+ /** @param {{slug: string, displayName: string}} identity */
81
+ function themeDescriptor(identity) {
82
+ return themeDescriptorSource({
83
+ type: 'theme',
84
+ name: identity.slug,
85
+ displayName: identity.displayName,
86
+ description: `${identity.displayName} theme.`,
87
+ maintained: true,
88
+ });
89
+ }
90
+
81
91
  /**
82
- * Read the bytes back through the same integration-theme discovery seam Project
83
- * uses. A write is not successful until the requested slug resolves.
92
+ * Read bytes back through the same discovery seam Project uses. A write is not
93
+ * successful until the requested slug resolves.
84
94
  * @param {string} packageDir
85
95
  * @param {string} manifestFile
86
96
  * @param {string} owner
@@ -176,6 +186,9 @@ export async function integrationAddTheme(name, options = {}) {
176
186
  dryRun: true,
177
187
  createIfMissing: true,
178
188
  });
189
+ if (fs.existsSync(root)) {
190
+ discoverThemeDirectory(root, owner);
191
+ }
179
192
  } catch (error) {
180
193
  if (error instanceof IntegrationRootConflictError) {
181
194
  throw new AstryxError(
@@ -197,72 +210,29 @@ export async function integrationAddTheme(name, options = {}) {
197
210
  const sourceFile = assertWithin(identity.entry, themeDir, {
198
211
  label: 'theme source file',
199
212
  });
200
- if (fs.existsSync(sourceFile)) {
201
- throw new AstryxError(
202
- `Refusing to overwrite existing file ${projectPath(path.relative(packageDir, sourceFile))}.`,
203
- undefined,
204
- ERROR_CODES.ERR_FILE_EXISTS,
205
- );
206
- }
207
-
208
- const catalogFile = assertWithin(THEME_MANIFEST_BASENAME, root, {
209
- label: 'theme catalog manifest',
213
+ const descriptorFile = assertWithin(identity.descriptor, themeDir, {
214
+ label: 'theme descriptor file',
210
215
  });
211
- /** @type {{version: 1, themes: Array<Record<string, unknown>>, [key: string]: unknown}} */
212
- let catalog = {version: 1, themes: []};
213
- /** @type {Buffer|null} */
214
- let catalogOriginal = null;
215
- if (fs.existsSync(catalogFile)) {
216
- try {
217
- catalogOriginal = fs.readFileSync(catalogFile);
218
- catalog = JSON.parse(catalogOriginal.toString('utf-8'));
219
- // The discovery seam is the schema/source-of-truth validator. The write
220
- // plan carries catalogOriginal, so any concurrent change between this read
221
- // and publish is refused rather than overwritten with this snapshot.
222
- discoverThemeCatalog(root, owner);
223
- } catch (error) {
216
+ // An existing folder is filled; only a file this would write is refused.
217
+ for (const file of [sourceFile, descriptorFile]) {
218
+ if (fs.existsSync(file)) {
224
219
  throw new AstryxError(
225
- error instanceof Error ? error.message : String(error),
220
+ `Refusing to overwrite existing file ${projectPath(path.relative(packageDir, file))}.`,
226
221
  undefined,
227
- ERROR_CODES.ERR_THEME_INVALID,
222
+ ERROR_CODES.ERR_FILE_EXISTS,
228
223
  );
229
224
  }
230
225
  }
231
- if (
232
- catalog.themes.some(
233
- theme =>
234
- typeof theme.slug === 'string' &&
235
- theme.slug.toLowerCase() === identity.slug.toLowerCase(),
236
- )
237
- ) {
238
- throw new AstryxError(
239
- `Theme "${identity.slug}" already exists in ${projectPath(path.relative(packageDir, catalogFile))}.`,
240
- undefined,
241
- ERROR_CODES.ERR_FILE_EXISTS,
242
- );
243
- }
244
-
245
- catalog.themes.push({
246
- slug: identity.slug,
247
- displayName: identity.displayName,
248
- description: `${identity.displayName} theme.`,
249
- maintained: true,
250
- entry: identity.entry,
251
- exportName: identity.exportName,
252
- files: [identity.entry],
253
- });
254
226
 
255
227
  /** @type {import('./add-helpers.mjs').WritePlan[]} */
256
- const plans = [];
257
- plans.push(
228
+ const plans = [
258
229
  {path: sourceFile, contents: themeSource(identity), createOnly: true},
259
230
  {
260
- path: catalogFile,
261
- contents: `${JSON.stringify(catalog, null, 2)}\n`,
262
- createOnly: catalogOriginal == null,
263
- expectedOriginal: catalogOriginal ?? undefined,
231
+ path: descriptorFile,
232
+ contents: themeDescriptor(identity),
233
+ createOnly: true,
264
234
  },
265
- );
235
+ ];
266
236
  const packageUpdate = packageJsonUpdate(
267
237
  packageFile,
268
238
  rootPath,