@astryxdesign/cli 0.6.3-canary.ea2f048 → 0.6.3-canary.ee13359

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 (571) hide show
  1. package/README.md +114 -76
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/build.doc.mjs +4 -3
  4. package/api/build/build.test.mjs +14 -3
  5. package/api/build/build.type.d.mts +36 -2
  6. package/api/build/build.type.mjs +25 -4
  7. package/api/build/help/help.d.mts +8 -5
  8. package/api/build/help/help.mjs +56 -6
  9. package/api/component/_adapter.d.mts +6 -12
  10. package/api/component/_adapter.mjs +20 -10
  11. package/api/component/component.doc.mjs +13 -3
  12. package/api/component/component.mjs +91 -14
  13. package/api/component/component.test.mjs +38 -0
  14. package/api/component/component.type.d.mts +22 -11
  15. package/api/component/component.type.mjs +32 -24
  16. package/api/component/detail/blocks/blocks.d.mts +2 -1
  17. package/api/component/detail/blocks/blocks.mjs +4 -3
  18. package/api/component/list/list.d.mts +0 -5
  19. package/api/component/list/list.mjs +40 -11
  20. package/api/discover/discover.doc.mjs +2 -1
  21. package/api/discover/discover.type.d.mts +4 -4
  22. package/api/discover/discover.type.mjs +10 -10
  23. package/api/docs/_adapter.d.mts +230 -41
  24. package/api/docs/_adapter.mjs +734 -108
  25. package/api/docs/compiled-topics.test.mjs +78 -0
  26. package/api/docs/detail/detail.mjs +22 -63
  27. package/api/docs/detail/section/section.d.mts +1 -1
  28. package/api/docs/detail/section/section.mjs +54 -19
  29. package/api/docs/detail/section/section.test.mjs +50 -0
  30. package/api/docs/docs.d.mts +10 -3
  31. package/api/docs/docs.doc.mjs +54 -16
  32. package/api/docs/docs.mjs +53 -10
  33. package/api/docs/docs.test.mjs +164 -4
  34. package/api/docs/docs.type.d.mts +205 -5
  35. package/api/docs/docs.type.mjs +137 -11
  36. package/api/docs/index/index.d.mts +18 -0
  37. package/api/docs/index/index.mjs +40 -0
  38. package/api/docs/index/index.test.mjs +62 -0
  39. package/api/docs/integration-tree.test.mjs +547 -0
  40. package/api/docs/integrationDocs.test.mjs +114 -8
  41. package/api/docs/list/list.mjs +28 -12
  42. package/api/docs/node/node.d.mts +43 -0
  43. package/api/docs/node/node.mjs +192 -0
  44. package/api/doctor/doctor.d.mts +99 -1
  45. package/api/doctor/doctor.doc.mjs +1 -0
  46. package/api/doctor/doctor.mjs +544 -1
  47. package/api/doctor/doctor.test.mjs +610 -1
  48. package/api/gap-report/gap-report.doc.mjs +8 -4
  49. package/api/hook/_adapter.mjs +19 -5
  50. package/api/hook/hook.doc.mjs +1 -0
  51. package/api/hook/hook.type.d.mts +3 -3
  52. package/api/hook/hook.type.mjs +11 -11
  53. package/api/hook/list/list.d.mts +2 -2
  54. package/api/hook/list/list.mjs +69 -17
  55. package/api/index.d.mts +1 -1
  56. package/api/index.mjs +1 -0
  57. package/api/init/init.doc.mjs +6 -1
  58. package/api/init/init.test.mjs +41 -1
  59. package/api/init/remove/remove.mjs +1 -1
  60. package/api/init/run/run.mjs +20 -10
  61. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  62. package/api/integration/add-contribution.d.mts +2 -1
  63. package/api/integration/add-contribution.mjs +130 -15
  64. package/api/integration/add-contribution.test.mjs +258 -7
  65. package/api/integration/add-theme.mjs +34 -64
  66. package/api/integration/add-theme.test.mjs +105 -21
  67. package/api/integration/authoring-checks.mjs +108 -31
  68. package/api/integration/authoring-checks.test.mjs +171 -6
  69. package/api/integration/authoring-checks.type.d.mts +3 -1
  70. package/api/integration/authoring-checks.type.mjs +3 -1
  71. package/api/integration/integration-authoring.type.d.mts +3 -1
  72. package/api/integration/integration-authoring.type.mjs +2 -0
  73. package/api/integration/integration-block-exports.test.mjs +10 -6
  74. package/api/integration/integrationAdd.doc.mjs +14 -4
  75. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  76. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  77. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  78. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  79. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  80. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  81. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  82. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  83. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  84. package/api/integration/integrationTemplateConflicts.doc.mjs +7 -5
  85. package/api/integration/pack-check.mjs +83 -7
  86. package/api/integration/pack-check.test.mjs +387 -47
  87. package/api/integration/pack-check.type.d.mts +26 -2
  88. package/api/integration/pack-check.type.mjs +14 -1
  89. package/api/integration/summarizeIssues.doc.mjs +1 -0
  90. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  91. package/api/integration/validate-integration.mjs +52 -102
  92. package/api/integration/validate-integration.test.mjs +179 -26
  93. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  94. package/api/integration/validateIntegration.doc.mjs +3 -2
  95. package/api/json/assertResponse.doc.mjs +1 -0
  96. package/api/json/envelope-types.test.mjs +76 -0
  97. package/api/json/index.ts +2 -0
  98. package/api/json/isError.doc.mjs +1 -0
  99. package/api/json/parseResponse.doc.mjs +3 -2
  100. package/api/layout/_adapter.mjs +20 -5
  101. package/api/layout/expand/expand.mjs +7 -5
  102. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  103. package/api/layout/grammar/grammar.mjs +2 -1
  104. package/api/layout/layoutCheck.doc.mjs +1 -0
  105. package/api/layout/layoutExpand.doc.mjs +2 -1
  106. package/api/layout/layoutGrammar.doc.mjs +1 -0
  107. package/api/search/search-return-type.test.mjs +54 -0
  108. package/api/search/search.d.mts +29 -11
  109. package/api/search/search.doc.mjs +8 -2
  110. package/api/search/search.mjs +337 -41
  111. package/api/search/search.test.mjs +124 -1
  112. package/api/search/search.type.d.mts +15 -3
  113. package/api/search/search.type.mjs +5 -2
  114. package/api/swizzle/copy/copy.mjs +28 -11
  115. package/api/swizzle/swizzle.doc.mjs +2 -1
  116. package/api/swizzle/swizzle.type.d.mts +2 -2
  117. package/api/swizzle/swizzle.type.mjs +2 -2
  118. package/api/template/copy/copy.mjs +17 -23
  119. package/api/template/copy/copy.test.mjs +17 -0
  120. package/api/template/list/list.mjs +1 -0
  121. package/api/template/template-integration.test.mjs +1022 -3
  122. package/api/template/template-suffix.test.mjs +41 -21
  123. package/api/template/template.d.mts +1 -1
  124. package/api/template/template.doc.mjs +30 -8
  125. package/api/template/template.mjs +45 -8
  126. package/api/template/template.type.d.mts +12 -14
  127. package/api/template/template.type.mjs +15 -14
  128. package/api/theme/_adapter.d.mts +2 -3
  129. package/api/theme/_adapter.mjs +4 -5
  130. package/api/theme/add/add.binary.test.mjs +84 -0
  131. package/api/theme/add/add.mjs +20 -3
  132. package/api/theme/add/add.staging.test.mjs +66 -0
  133. package/api/theme/add/add.test.mjs +14 -1
  134. package/api/theme/build/build.mjs +133 -42
  135. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  136. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  137. package/api/theme/build/build.test.mjs +127 -0
  138. package/api/theme/build/font-warning.mjs +3 -3
  139. package/api/theme/build/font-warning.test.mjs +5 -2
  140. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  141. package/api/theme/integration-themes.test.mjs +39 -28
  142. package/api/theme/list/list.test.mjs +19 -20
  143. package/api/theme/listThemes.doc.mjs +6 -5
  144. package/api/theme/palette/generate/generate.mjs +8 -3
  145. package/api/theme/palette/generate/generate.test.mjs +96 -0
  146. package/api/theme/palette/generate/generator.d.mts +10 -13
  147. package/api/theme/palette/generate/generator.mjs +15 -4
  148. package/api/theme/palette/generate/generator.test.mjs +10 -0
  149. package/api/theme/template/template.mjs +11 -2
  150. package/api/theme/template/template.test.mjs +20 -0
  151. package/api/theme/theme.type.d.mts +170 -11
  152. package/api/theme/theme.type.mjs +94 -27
  153. package/api/theme/themeAdd.doc.mjs +4 -3
  154. package/api/theme/themeBuild.doc.mjs +8 -4
  155. package/api/theme/themeList.doc.mjs +6 -3
  156. package/api/theme/themeListAvailable.doc.mjs +5 -3
  157. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  158. package/api/theme/themeTargets.doc.mjs +1 -0
  159. package/api/theme/themeTemplate.doc.mjs +6 -2
  160. package/api/upgrade/_adapter.d.mts +32 -5
  161. package/api/upgrade/_adapter.mjs +139 -22
  162. package/api/upgrade/list/list.mjs +2 -1
  163. package/api/upgrade/list/list.test.mjs +73 -0
  164. package/api/upgrade/project-context.test.mjs +272 -0
  165. package/api/upgrade/provider-agreement.test.mjs +152 -0
  166. package/api/upgrade/run/run.mjs +356 -59
  167. package/api/upgrade/status/status.mjs +2 -2
  168. package/api/upgrade/upgrade.doc.mjs +12 -5
  169. package/api/upgrade/upgrade.type.d.mts +43 -5
  170. package/api/upgrade/upgrade.type.mjs +27 -11
  171. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  172. package/assets/codemods/integration-discovery.mjs +48 -4
  173. package/assets/codemods/integration-discovery.test.mjs +73 -0
  174. package/assets/codemods/integration-runner.mjs +56 -4
  175. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  176. package/assets/codemods/run-codemod.mjs +177 -34
  177. package/assets/codemods/runner.mjs +350 -102
  178. package/assets/codemods/term-log.mjs +32 -8
  179. package/assets/codemods/term-log.test.mjs +19 -1
  180. package/assets/codemods/transform-prop.mjs +109 -0
  181. package/assets/codemods/transform-prop.test.mjs +95 -0
  182. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  183. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  184. package/assets/codemods/transforms/next/index.mjs +19 -1
  185. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  186. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  187. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  188. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  189. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  190. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  191. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  192. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  193. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  194. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  195. package/assets/docs/README.md +9 -0
  196. package/assets/docs/authoring.doc.mjs +14 -0
  197. package/assets/docs/getting-started.doc.mjs +2 -2
  198. package/assets/docs/principles.doc.mjs +6 -6
  199. package/assets/docs/styling-libraries.doc.mjs +3 -3
  200. package/assets/docs/styling.doc.mjs +4 -4
  201. package/assets/docs/theme.doc.mjs +4 -4
  202. package/assets/docs/tokens.doc.mjs +1 -1
  203. package/assets/docs/tree/api.doc.mjs +30 -0
  204. package/assets/docs/tree/cli.doc.mjs +23 -0
  205. package/assets/docs/tree/commands.doc.mjs +25 -0
  206. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +124 -25
  207. package/assets/docs/tree/integrations.test.mjs +62 -0
  208. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  209. package/assets/docs/working-with-ai.doc.mjs +1 -1
  210. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  211. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  212. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  213. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  214. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  215. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  216. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  217. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  218. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  219. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  220. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  221. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  222. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  223. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  224. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  225. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  226. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  227. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  228. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  229. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  230. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  231. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  232. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  233. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  234. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  235. package/authoring/_shared/contract.ts +22 -0
  236. package/authoring/codemod/codemod.doc.mjs +7 -2
  237. package/authoring/codemod/parse.d.mts +8 -8
  238. package/authoring/codemod/parse.mjs +8 -6
  239. package/authoring/codemod/type.ts +12 -0
  240. package/authoring/config/config.doc.mjs +2 -2
  241. package/authoring/config/debug-composition.test.mjs +92 -0
  242. package/authoring/config/parse.d.mts +13 -13
  243. package/authoring/config/parse.mjs +8 -8
  244. package/authoring/config/type.ts +18 -6
  245. package/authoring/debug/debug.doc.d.mts +11 -0
  246. package/authoring/debug/debug.doc.mjs +182 -0
  247. package/authoring/debug/parse.d.mts +8 -8
  248. package/authoring/debug/parse.mjs +3 -3
  249. package/authoring/doctypes/_schema.d.mts +718 -23
  250. package/authoring/doctypes/_schema.mjs +519 -39
  251. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  252. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  253. package/authoring/doctypes/base/type.ts +41 -0
  254. package/authoring/doctypes/command/command.doc.mjs +4 -3
  255. package/authoring/doctypes/command/parse.d.mts +2 -2
  256. package/authoring/doctypes/command/parse.mjs +1 -1
  257. package/authoring/doctypes/command/type.ts +5 -4
  258. package/authoring/doctypes/component/component.doc.mjs +6 -3
  259. package/authoring/doctypes/component/parse.d.mts +2 -2
  260. package/authoring/doctypes/component/parse.mjs +1 -1
  261. package/authoring/doctypes/component/type.ts +6 -5
  262. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  263. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  264. package/authoring/doctypes/enum/parse.d.mts +2 -2
  265. package/authoring/doctypes/enum/parse.mjs +1 -1
  266. package/authoring/doctypes/enum/type.ts +4 -2
  267. package/authoring/doctypes/function/function.doc.mjs +7 -2
  268. package/authoring/doctypes/function/parse.d.mts +2 -2
  269. package/authoring/doctypes/function/parse.mjs +1 -1
  270. package/authoring/doctypes/function/type.ts +9 -4
  271. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  272. package/authoring/doctypes/hook/parse.d.mts +2 -2
  273. package/authoring/doctypes/hook/parse.mjs +1 -1
  274. package/authoring/doctypes/hook/type.ts +5 -4
  275. package/authoring/doctypes/legacy.d.mts +8 -6
  276. package/authoring/doctypes/legacy.mjs +5 -4
  277. package/authoring/doctypes/load-contract.test.mjs +208 -0
  278. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  279. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  280. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  281. package/authoring/doctypes/namespace/parse.mjs +25 -0
  282. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  283. package/authoring/doctypes/namespace/type.ts +74 -0
  284. package/authoring/doctypes/parse.d.mts +22 -18
  285. package/authoring/doctypes/parse.mjs +22 -11
  286. package/authoring/doctypes/parse.test.mjs +77 -3
  287. package/authoring/doctypes/reference/parse.d.mts +2 -2
  288. package/authoring/doctypes/reference/parse.mjs +8 -5
  289. package/authoring/doctypes/reference/reference.doc.mjs +20 -5
  290. package/authoring/doctypes/reference/type.ts +53 -5
  291. package/authoring/doctypes/schema/parse.d.mts +2 -2
  292. package/authoring/doctypes/schema/parse.mjs +1 -1
  293. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  294. package/authoring/doctypes/schema/type.ts +4 -4
  295. package/authoring/doctypes/template/parse.d.mts +94 -1
  296. package/authoring/doctypes/template/parse.mjs +40 -2
  297. package/authoring/doctypes/template/parse.test.mjs +26 -2
  298. package/authoring/doctypes/template/template.doc.mjs +13 -3
  299. package/authoring/doctypes/template/type.ts +13 -2
  300. package/authoring/doctypes/theme/parse.d.mts +35 -0
  301. package/authoring/doctypes/theme/parse.mjs +76 -0
  302. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  303. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  304. package/authoring/doctypes/theme/type.ts +42 -0
  305. package/authoring/doctypes/types.ts +12 -10
  306. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  307. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  308. package/authoring/gap-report/parse.d.mts +10 -10
  309. package/authoring/gap-report/parse.mjs +6 -6
  310. package/authoring/gap-report/type.ts +1 -1
  311. package/authoring/identity/identity.doc.d.mts +9 -0
  312. package/authoring/identity/identity.doc.mjs +61 -0
  313. package/authoring/identity/type.ts +132 -0
  314. package/authoring/index.d.mts +2 -0
  315. package/authoring/index.d.ts +52 -17
  316. package/authoring/index.mjs +3 -1
  317. package/authoring/integration/integration.doc.mjs +15 -8
  318. package/authoring/integration/parse.d.mts +2 -2
  319. package/authoring/integration/parse.mjs +1 -1
  320. package/authoring/integration/parse.test.mjs +10 -1
  321. package/authoring/integration/schema.d.mts +6 -4
  322. package/authoring/integration/schema.mjs +9 -3
  323. package/authoring/integration/type.ts +19 -8
  324. package/authoring/shadcn/receipt.d.mts +6 -6
  325. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  326. package/clients/cli/command-load-failure.test.mjs +83 -0
  327. package/clients/cli/commands/blog.doc.mjs +1 -1
  328. package/clients/cli/commands/blog.mjs +23 -8
  329. package/clients/cli/commands/blog.test.mjs +42 -1
  330. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  331. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  332. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  333. package/clients/cli/commands/build-theme.mjs +16 -50
  334. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  335. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  336. package/clients/cli/commands/build.doc.mjs +5 -2
  337. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  338. package/clients/cli/commands/build.mjs +37 -49
  339. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  340. package/clients/cli/commands/build.text-fields.test.mjs +40 -0
  341. package/clients/cli/commands/component/index.mjs +3 -8
  342. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  343. package/clients/cli/commands/component-package.test.mjs +46 -0
  344. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  345. package/clients/cli/commands/component.doc.mjs +1 -1
  346. package/clients/cli/commands/component.test.mjs +19 -0
  347. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  348. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  349. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  350. package/clients/cli/commands/discover.doc.mjs +5 -3
  351. package/clients/cli/commands/discover.mjs +4 -4
  352. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  353. package/clients/cli/commands/docs.doc.mjs +28 -6
  354. package/clients/cli/commands/docs.mjs +238 -24
  355. package/clients/cli/commands/docs.test.mjs +193 -1
  356. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  357. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  358. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  359. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  360. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  361. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  362. package/clients/cli/commands/doctor-integration.test.mjs +83 -8
  363. package/clients/cli/commands/doctor.doc.mjs +1 -1
  364. package/clients/cli/commands/doctor.mjs +30 -25
  365. package/clients/cli/commands/doctor.test.mjs +42 -0
  366. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  367. package/clients/cli/commands/gap-report.test.mjs +72 -0
  368. package/clients/cli/commands/hook/index.mjs +7 -17
  369. package/clients/cli/commands/hook.doc.mjs +1 -1
  370. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  371. package/clients/cli/commands/init.doc.mjs +20 -9
  372. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  373. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  374. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  375. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  376. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  377. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  378. package/clients/cli/commands/integration.doc.mjs +1 -1
  379. package/clients/cli/commands/integration.mjs +1 -0
  380. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  381. package/clients/cli/commands/json-contract.test.mjs +33 -0
  382. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  383. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  384. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  385. package/clients/cli/commands/layout.doc.mjs +3 -3
  386. package/clients/cli/commands/layout.mjs +21 -9
  387. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  388. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  389. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  390. package/clients/cli/commands/manifest.doc.mjs +1 -1
  391. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  392. package/clients/cli/commands/search.doc.mjs +7 -4
  393. package/clients/cli/commands/search.mjs +28 -9
  394. package/clients/cli/commands/search.test.mjs +75 -0
  395. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  396. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  397. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  398. package/clients/cli/commands/template.doc.mjs +52 -13
  399. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  400. package/clients/cli/commands/template.mjs +4 -91
  401. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  402. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  403. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  404. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  405. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  406. package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
  407. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  408. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  409. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  410. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  411. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  412. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  413. package/clients/cli/commands/theme.doc.mjs +1 -1
  414. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  415. package/clients/cli/commands/upgrade.doc.mjs +22 -10
  416. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  417. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  418. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  419. package/clients/cli/commands/upgrade.mjs +29 -7
  420. package/clients/cli/formatters/index.mjs +164 -1
  421. package/clients/cli/formatters/index.test.mjs +97 -0
  422. package/clients/cli/index.mjs +21 -30
  423. package/clients/cli/latest-version-env.test.mjs +50 -0
  424. package/clients/cli/lib/cli-error.test.mjs +7 -0
  425. package/clients/cli/lib/component-format.mjs +9 -9
  426. package/clients/cli/lib/component-format.test.mjs +1 -1
  427. package/clients/cli/lib/define-command.mjs +32 -6
  428. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  429. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  430. package/clients/cli/lib/hook-format.mjs +19 -10
  431. package/clients/cli/lib/json-shim.mjs +38 -2
  432. package/clients/cli/lib/json-shim.test.mjs +83 -0
  433. package/clients/cli/lib/manifest.d.ts +2 -0
  434. package/clients/cli/lib/manifest.mjs +36 -2
  435. package/clients/cli/lib/manifest.test.mjs +17 -0
  436. package/foundation/agent-docs/agent-docs.d.mts +4 -0
  437. package/foundation/agent-docs/agent-docs.mjs +70 -3
  438. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  439. package/foundation/agent-docs/agent-docs.test.mjs +10 -1
  440. package/foundation/config/integration-debug.test.mjs +28 -3
  441. package/foundation/config/project-themes.test.mjs +11 -19
  442. package/foundation/config/project.d.mts +20 -11
  443. package/foundation/config/project.mjs +263 -91
  444. package/foundation/config/project.test.mjs +270 -21
  445. package/foundation/discovery/authoring-self-docs.d.mts +75 -0
  446. package/foundation/discovery/authoring-self-docs.mjs +224 -0
  447. package/foundation/discovery/authoring-self-docs.test.mjs +165 -0
  448. package/foundation/discovery/authoring-surface.d.mts +74 -0
  449. package/foundation/discovery/authoring-surface.mjs +525 -0
  450. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  451. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  452. package/foundation/discovery/cli-self-docs.mjs +490 -0
  453. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  454. package/foundation/discovery/component-discovery.d.mts +39 -1
  455. package/foundation/discovery/component-discovery.mjs +50 -1
  456. package/foundation/discovery/component-loader.d.mts +35 -38
  457. package/foundation/discovery/component-loader.mjs +53 -222
  458. package/foundation/discovery/docs-discovery.d.mts +116 -11
  459. package/foundation/discovery/docs-discovery.mjs +389 -108
  460. package/foundation/discovery/docs-discovery.test.mjs +325 -20
  461. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  462. package/foundation/discovery/docs-output-budget.mjs +50 -0
  463. package/foundation/discovery/docs-section-key.d.mts +116 -0
  464. package/foundation/discovery/docs-section-key.mjs +322 -0
  465. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  466. package/foundation/discovery/template-adapter.d.mts +113 -11
  467. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  468. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  469. package/foundation/discovery/template-adapter.mjs +774 -83
  470. package/foundation/discovery/template-adapter.test.mjs +57 -0
  471. package/foundation/discovery/theme-discovery.d.mts +67 -7
  472. package/foundation/discovery/theme-discovery.mjs +916 -186
  473. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  474. package/foundation/discovery/theming-targets.test.mjs +4 -0
  475. package/foundation/doc-compiler/bundle.d.mts +47 -0
  476. package/foundation/doc-compiler/bundle.mjs +278 -0
  477. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  478. package/foundation/doc-compiler/compile.d.mts +343 -0
  479. package/foundation/doc-compiler/compile.mjs +558 -0
  480. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  481. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  482. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  483. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  484. package/foundation/doc-compiler/import.d.mts +24 -0
  485. package/foundation/doc-compiler/import.mjs +59 -0
  486. package/foundation/doc-compiler/inputs.d.mts +102 -0
  487. package/foundation/doc-compiler/inputs.mjs +291 -0
  488. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  489. package/foundation/doc-compiler/ir.d.mts +22 -0
  490. package/foundation/doc-compiler/ir.mjs +471 -0
  491. package/foundation/doc-compiler/lenses.d.mts +34 -0
  492. package/foundation/doc-compiler/lenses.mjs +128 -0
  493. package/foundation/doc-compiler/links.d.mts +135 -0
  494. package/foundation/doc-compiler/links.mjs +253 -0
  495. package/foundation/doc-compiler/links.test.mjs +139 -0
  496. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  497. package/foundation/doc-compiler/overlays.d.mts +37 -0
  498. package/foundation/doc-compiler/overlays.mjs +206 -0
  499. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  500. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  501. package/foundation/doc-compiler/read.d.mts +127 -0
  502. package/foundation/doc-compiler/read.mjs +325 -0
  503. package/foundation/doc-compiler/read.test.mjs +313 -0
  504. package/foundation/doc-compiler/source.d.mts +33 -0
  505. package/foundation/doc-compiler/source.mjs +128 -0
  506. package/foundation/doc-compiler/tree.d.mts +288 -0
  507. package/foundation/doc-compiler/tree.mjs +876 -0
  508. package/foundation/doc-compiler/tree.test.mjs +598 -0
  509. package/foundation/fs/file-protection.d.mts +33 -0
  510. package/foundation/fs/file-protection.mjs +825 -0
  511. package/foundation/fs/file-protection.test.mjs +250 -0
  512. package/foundation/fs/module-loader.d.mts +1 -0
  513. package/foundation/fs/module-loader.mjs +50 -1
  514. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  515. package/foundation/fs/path-safety.d.mts +3 -2
  516. package/foundation/fs/path-safety.mjs +49 -19
  517. package/foundation/fs/path-safety.test.mjs +50 -0
  518. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  519. package/foundation/identity/provider-identity.d.mts +90 -0
  520. package/foundation/identity/provider-identity.mjs +320 -0
  521. package/foundation/identity/provider-identity.test.mjs +254 -0
  522. package/foundation/identity/providers.d.mts +7 -0
  523. package/foundation/identity/providers.mjs +16 -0
  524. package/foundation/integrations/autolink.d.mts +58 -1
  525. package/foundation/integrations/autolink.mjs +143 -45
  526. package/foundation/integrations/autolink.test.mjs +1 -1
  527. package/foundation/integrations/cli-requirement.d.mts +45 -0
  528. package/foundation/integrations/cli-requirement.mjs +154 -0
  529. package/foundation/integrations/cli-requirement.test.mjs +109 -0
  530. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  531. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  532. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  533. package/foundation/integrations/contribution-inventory.mjs +27 -24
  534. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  535. package/foundation/integrations/integration-warnings.d.mts +9 -2
  536. package/foundation/integrations/integration-warnings.mjs +52 -21
  537. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  538. package/foundation/integrations/integrations.d.mts +49 -2
  539. package/foundation/integrations/integrations.mjs +81 -8
  540. package/foundation/integrations/integrations.test.mjs +384 -1
  541. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  542. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  543. package/foundation/integrations/provider-resolution.d.mts +152 -0
  544. package/foundation/integrations/provider-resolution.mjs +576 -0
  545. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  546. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  547. package/foundation/integrations/theme-descriptor.mjs +44 -0
  548. package/foundation/integrations/validate-contributions.d.mts +2 -0
  549. package/foundation/integrations/validate-contributions.mjs +131 -29
  550. package/foundation/response/base.d.ts +8 -4
  551. package/foundation/response/error-codes.d.mts +3 -1
  552. package/foundation/response/error-codes.d.ts +2 -0
  553. package/foundation/response/error-codes.doc.mjs +13 -4
  554. package/foundation/response/error-codes.mjs +8 -2
  555. package/foundation/response/error-codes.test.mjs +137 -10
  556. package/foundation/response/json-contract.test.mjs +57 -17
  557. package/foundation/response/json.d.mts +4 -2
  558. package/foundation/response/json.mjs +8 -10
  559. package/foundation/response/response-types.doc.mjs +26 -16
  560. package/foundation/response/response-types.doc.test.mjs +158 -0
  561. package/foundation/response/response.doc.mjs +1 -1
  562. package/foundation/text/string-utils.mjs +22 -10
  563. package/foundation/xle/expand.d.mts +2 -0
  564. package/foundation/xle/expand.mjs +4 -3
  565. package/foundation/xle/expand.test.mjs +54 -0
  566. package/foundation/xle/xle.test.mjs +13 -0
  567. package/package.json +10 -11
  568. package/assets/templates/themes/manifest.json +0 -95
  569. package/clients/cli/lib/update-check.mjs +0 -83
  570. package/clients/cli/lib/update-check.test.mjs +0 -137
  571. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -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,
@@ -32,7 +32,7 @@ afterEach(() => {
32
32
  });
33
33
 
34
34
  describe('integrationAddTheme', () => {
35
- it('writes a valid source theme, catalog, root, package files entry, and receipt', async () => {
35
+ it('writes a typed same-stem descriptor and source with no central catalog', async () => {
36
36
  setup();
37
37
  const result = await integrationAddTheme('ocean', {cwd: tmpDir});
38
38
 
@@ -45,7 +45,7 @@ describe('integrationAddTheme', () => {
45
45
  manifest: 'astryx.integration.mjs',
46
46
  files: [
47
47
  'themes/ocean/oceanTheme.ts',
48
- 'themes/manifest.json',
48
+ 'themes/ocean/oceanTheme.doc.mjs',
49
49
  'package.json',
50
50
  'astryx.integration.mjs',
51
51
  ],
@@ -56,21 +56,17 @@ describe('integrationAddTheme', () => {
56
56
  expect(
57
57
  fs.readFileSync(path.join(tmpDir, 'themes/ocean/oceanTheme.ts'), 'utf-8'),
58
58
  ).toContain('export const oceanTheme = defineTheme');
59
- expect(
60
- JSON.parse(
61
- fs.readFileSync(path.join(tmpDir, 'themes/manifest.json'), 'utf-8'),
62
- ),
63
- ).toMatchObject({
64
- version: 1,
65
- themes: [
66
- {
67
- slug: 'ocean',
68
- entry: 'oceanTheme.ts',
69
- exportName: 'oceanTheme',
70
- files: ['oceanTheme.ts'],
71
- },
72
- ],
73
- });
59
+
60
+ const descriptor = fs.readFileSync(
61
+ path.join(tmpDir, 'themes/ocean/oceanTheme.doc.mjs'),
62
+ 'utf-8',
63
+ );
64
+ expect(descriptor).toContain("@astryxdesign/cli/authoring').ThemeDoc");
65
+ expect(descriptor).toContain("type: 'theme'");
66
+ expect(descriptor).toContain("name: 'ocean'");
67
+ expect(fs.existsSync(path.join(tmpDir, 'themes/manifest.json'))).toBe(
68
+ false,
69
+ );
74
70
  expect(
75
71
  fs.readFileSync(path.join(tmpDir, 'astryx.integration.mjs'), 'utf-8'),
76
72
  ).toContain("themes: './themes'");
@@ -96,6 +92,7 @@ describe('integrationAddTheme', () => {
96
92
  expect(result.data.dryRun).toBe(true);
97
93
  expect(result.data.root).toEqual({path: './themes', created: true});
98
94
  expect(result.data.files).toContain('themes/ocean/oceanTheme.ts');
95
+ expect(result.data.files).toContain('themes/ocean/oceanTheme.doc.mjs');
99
96
  expect(fs.existsSync(path.join(tmpDir, 'themes'))).toBe(false);
100
97
  expect(
101
98
  fs.readFileSync(path.join(tmpDir, 'astryx.integration.mjs'), 'utf-8'),
@@ -125,22 +122,69 @@ describe('integrationAddTheme', () => {
125
122
  expect(
126
123
  fs.existsSync(path.join(tmpDir, 'src/themes/ocean/oceanTheme.ts')),
127
124
  ).toBe(true);
125
+ expect(
126
+ fs.existsSync(path.join(tmpDir, 'src/themes/ocean/oceanTheme.doc.mjs')),
127
+ ).toBe(true);
128
128
  });
129
129
 
130
- it('refuses an invalid existing catalog without changing its bytes', async () => {
130
+ it('keeps each theme to its own folder: a second theme touches no shared file', async () => {
131
+ setup({manifest: "export default {themes: './themes'};\n"});
132
+ await integrationAddTheme('ocean', {cwd: tmpDir});
133
+ const shared = ['package.json', 'astryx.integration.mjs'].map(file =>
134
+ fs.readFileSync(path.join(tmpDir, file), 'utf-8'),
135
+ );
136
+
137
+ const result = await integrationAddTheme('reef', {cwd: tmpDir});
138
+
139
+ expect(result.data.files).toEqual([
140
+ 'themes/reef/reefTheme.ts',
141
+ 'themes/reef/reefTheme.doc.mjs',
142
+ ]);
143
+ expect(fs.readdirSync(path.join(tmpDir, 'themes')).sort()).toEqual([
144
+ 'ocean',
145
+ 'reef',
146
+ ]);
147
+ expect(
148
+ ['package.json', 'astryx.integration.mjs'].map(file =>
149
+ fs.readFileSync(path.join(tmpDir, file), 'utf-8'),
150
+ ),
151
+ ).toEqual(shared);
152
+ });
153
+
154
+ it('refuses an obsolete central catalog without changing its bytes', async () => {
131
155
  setup();
132
156
  fs.mkdirSync(path.join(tmpDir, 'themes'));
133
157
  const catalog = path.join(tmpDir, 'themes', 'manifest.json');
134
- fs.writeFileSync(catalog, '{not-json\n');
158
+ fs.writeFileSync(catalog, '{"version":1}\n');
135
159
 
136
160
  await expect(
137
161
  integrationAddTheme('ocean', {cwd: tmpDir}),
138
162
  ).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
139
- expect(fs.readFileSync(catalog, 'utf-8')).toBe('{not-json\n');
163
+ expect(fs.readFileSync(catalog, 'utf-8')).toBe('{"version":1}\n');
140
164
  expect(fs.existsSync(path.join(tmpDir, 'themes', 'ocean'))).toBe(false);
141
165
  });
142
166
 
143
- it('refuses duplicate themes and existing source files', async () => {
167
+ it('refuses an invalid existing descriptor without changing it', async () => {
168
+ setup();
169
+ const existing = path.join(tmpDir, 'themes', 'forest');
170
+ fs.mkdirSync(existing, {recursive: true});
171
+ const descriptor = path.join(existing, 'forestTheme.doc.mjs');
172
+ fs.writeFileSync(descriptor, 'export default {type: "theme"};\n');
173
+ fs.writeFileSync(
174
+ path.join(existing, 'forestTheme.ts'),
175
+ 'export const forestTheme = {};\n',
176
+ );
177
+
178
+ await expect(
179
+ integrationAddTheme('ocean', {cwd: tmpDir}),
180
+ ).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
181
+ expect(fs.readFileSync(descriptor, 'utf-8')).toBe(
182
+ 'export default {type: "theme"};\n',
183
+ );
184
+ expect(fs.existsSync(path.join(tmpDir, 'themes', 'ocean'))).toBe(false);
185
+ });
186
+
187
+ it('refuses a duplicate valid theme directory', async () => {
144
188
  setup();
145
189
  await integrationAddTheme('ocean', {cwd: tmpDir});
146
190
  await expect(
@@ -148,6 +192,46 @@ describe('integrationAddTheme', () => {
148
192
  ).rejects.toMatchObject({code: 'ERR_FILE_EXISTS'});
149
193
  });
150
194
 
195
+ it('refuses an existing invalid theme directory', async () => {
196
+ setup();
197
+ fs.mkdirSync(path.join(tmpDir, 'themes', 'ocean'), {recursive: true});
198
+ fs.writeFileSync(
199
+ path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
200
+ 'export const oceanTheme = {};\n',
201
+ );
202
+ await expect(
203
+ integrationAddTheme('ocean', {cwd: tmpDir}),
204
+ ).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
205
+ });
206
+
207
+ it.each([
208
+ ['an empty folder', []],
209
+ ['a folder holding .gitkeep', ['.gitkeep']],
210
+ ['a folder holding NOTES.md', ['NOTES.md']],
211
+ ])('fills %s', async (_, files) => {
212
+ setup();
213
+ const dir = path.join(tmpDir, 'themes', 'ocean');
214
+ fs.mkdirSync(dir, {recursive: true});
215
+ for (const file of files) fs.writeFileSync(path.join(dir, file), 'x\n');
216
+ const result = await integrationAddTheme('ocean', {cwd: tmpDir});
217
+ expect(result.data.written).toBe(true);
218
+ expect(fs.readdirSync(dir).sort()).toEqual(
219
+ [...files, 'oceanTheme.doc.mjs', 'oceanTheme.ts'].sort(),
220
+ );
221
+ });
222
+
223
+ it('refuses to overwrite a file it would write', async () => {
224
+ setup();
225
+ await integrationAddTheme('ocean', {cwd: tmpDir});
226
+ await expect(
227
+ integrationAddTheme('ocean', {cwd: tmpDir}),
228
+ ).rejects.toMatchObject({
229
+ code: 'ERR_FILE_EXISTS',
230
+ message:
231
+ 'Refusing to overwrite existing file themes/ocean/oceanTheme.ts.',
232
+ });
233
+ });
234
+
151
235
  it.each(['../ocean', 'Ocean', 'ocean theme', '.ocean'])(
152
236
  'refuses unsafe or noncanonical name %s',
153
237
  async name => {
@@ -3,13 +3,13 @@
3
3
  /**
4
4
  * @file Integration authoring diagnostics against the built-in Core catalog.
5
5
  *
6
- * Components and templates may intentionally share a Core identity, but
7
- * unqualified lookup then fails closed and callers must select the package.
8
- * Docs have explicit `replaces` / `extends` relationships, so the check can
9
- * distinguish intentional ownership from an accidental same-name shadow.
6
+ * Templates may intentionally replace Core identities; undeclared same-id
7
+ * overlaps stay fail-closed and require package selection. Docs have explicit
8
+ * `replaces` / `extends` relationships with parallel validation semantics.
10
9
  */
11
10
 
12
11
  import {getCliInvocation} from '../../foundation/env/package-manager.mjs';
12
+ import {packageDocsProblems} from '../docs/_adapter.mjs';
13
13
  import {findCoreDir} from '../../foundation/fs/paths.mjs';
14
14
  import {
15
15
  discoverIntegrationComponents,
@@ -20,6 +20,7 @@ import {
20
20
  discoverIntegrationDocs,
21
21
  } from '../../foundation/discovery/docs-discovery.mjs';
22
22
  import {
23
+ applyTemplateReplacements,
23
24
  discoverCoreTemplates,
24
25
  discoverIntegrationTemplatesForOne,
25
26
  } from '../../foundation/discovery/template-adapter.mjs';
@@ -48,16 +49,27 @@ async function resolveIntegration(pkg, cwd) {
48
49
  /**
49
50
  * Add discovery errors once to an issue list.
50
51
  * @param {Array<{code: string, severity: 'warning' | 'error', message: string}>} issues
51
- * @param {Array<{message: string} | Error>} errors
52
+ * @param {Array<{message: string, code?: string, severity?: 'warning' | 'error'} | Error>} errors
52
53
  * @param {string} code
53
54
  */
54
55
  function addErrors(issues, errors, code) {
55
56
  for (const error of errors) {
56
57
  const message = error.message;
57
- if (issues.some(issue => issue.code === code && issue.message === message)) {
58
+ const issueCode =
59
+ 'code' in error && typeof error.code === 'string' ? error.code : code;
60
+ const severity =
61
+ 'severity' in error &&
62
+ (error.severity === 'warning' || error.severity === 'error')
63
+ ? error.severity
64
+ : 'error';
65
+ if (
66
+ issues.some(
67
+ issue => issue.code === issueCode && issue.message === message,
68
+ )
69
+ ) {
58
70
  continue;
59
71
  }
60
- issues.push({code, severity: 'error', message});
72
+ issues.push({code: issueCode, severity, message});
61
73
  }
62
74
  }
63
75
 
@@ -74,7 +86,7 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
74
86
  const version = resolved.found ? (resolved.version ?? null) : null;
75
87
  const issues = [...resolved.issues];
76
88
 
77
- if (!resolved.integration?.templates || name == null) {
89
+ if (!resolved.integration || name == null) {
78
90
  return {
79
91
  type: 'integration.template-conflicts',
80
92
  data: {name, version, conflicts: [], issues},
@@ -87,6 +99,31 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
87
99
  ]);
88
100
  addErrors(issues, errors, 'invalid_template');
89
101
 
102
+ const replacementResolution = applyTemplateReplacements(
103
+ [...coreTemplates, ...templates],
104
+ errors.filter(error => error.replacementTarget != null),
105
+ );
106
+ for (const error of replacementResolution.errors) {
107
+ if (
108
+ !issues.some(
109
+ issue => issue.code === error.code && issue.message === error.message,
110
+ )
111
+ ) {
112
+ issues.push({
113
+ code: error.code,
114
+ severity: error.severity,
115
+ message: error.message,
116
+ });
117
+ }
118
+ }
119
+ const activeReplacementIds = new Set(
120
+ replacementResolution.templates
121
+ .filter(
122
+ template => template.package === name && template.replaces != null,
123
+ )
124
+ .map(template => template.dirName),
125
+ );
126
+
90
127
  /** @type {Map<string, Array<{type: 'page' | 'block', name: string}>>} */
91
128
  const coreById = new Map();
92
129
  for (const template of coreTemplates) {
@@ -101,30 +138,57 @@ export async function integrationTemplateConflicts(pkg, options = {}) {
101
138
  }
102
139
 
103
140
  const run = getCliInvocation(cwd);
104
- const conflicts = templates
105
- .flatMap(template => {
106
- const coreMatches = coreById.get(template.dirName);
107
- if (!coreMatches) return [];
108
- const command = `${run} template ${shellArg(template.dirName)} --package ${shellArg(name)}`;
109
- const coreKinds = coreMatches
141
+ /** @type {import('./authoring-checks.type.mjs').IntegrationTemplateConflict[]} */
142
+ const conflicts = [];
143
+ for (const template of templates) {
144
+ const sameIdCore = coreById.get(template.dirName);
145
+ const replacementIsActive = activeReplacementIds.has(template.dirName);
146
+
147
+ if (replacementIsActive && template.replaces != null) {
148
+ conflicts.push({
149
+ id: template.dirName,
150
+ severity: 'info',
151
+ relationship: 'replaces',
152
+ replaces: template.replaces,
153
+ integrationPackage: name,
154
+ integrationType: template.type,
155
+ integrationName: template.name,
156
+ coreMatches: coreById.get(template.replaces) ?? [],
157
+ message:
158
+ `Intentional replacement: "${template.dirName}" replaces the Core template ` +
159
+ `"${template.replaces}" for unqualified lookup.`,
160
+ command: `${run} template ${shellArg(template.replaces)} --package ${shellArg('@astryxdesign/core')}`,
161
+ });
162
+ }
163
+
164
+ if (
165
+ sameIdCore &&
166
+ !(replacementIsActive && template.replaces === template.dirName)
167
+ ) {
168
+ const coreKinds = sameIdCore
110
169
  .map(match => `${match.type} "${match.name}"`)
111
170
  .join(', ');
112
- return [
113
- {
114
- id: template.dirName,
115
- severity: /** @type {const} */ ('warning'),
116
- integrationPackage: name,
117
- integrationType: template.type,
118
- integrationName: template.name,
119
- coreMatches,
120
- message:
121
- `Template id "${template.dirName}" conflicts with Core (${coreKinds}). ` +
122
- 'Consider renaming the integration template. If you keep it, always select it with --package.',
123
- command,
124
- },
125
- ];
126
- })
127
- .sort((a, b) => a.id.localeCompare(b.id));
171
+ const compatibleKind = sameIdCore.some(
172
+ match => match.type === template.type,
173
+ );
174
+ conflicts.push({
175
+ id: template.dirName,
176
+ severity: 'warning',
177
+ relationship: 'accidental',
178
+ integrationPackage: name,
179
+ integrationType: template.type,
180
+ integrationName: template.name,
181
+ coreMatches: sameIdCore,
182
+ message: compatibleKind
183
+ ? `Template id "${template.dirName}" conflicts with Core (${coreKinds}). Consider renaming it, or set replaces: ${JSON.stringify(template.dirName)} in its metadata to replace the Core template.`
184
+ : `Template id "${template.dirName}" conflicts with Core (${coreKinds}), but a ${template.type} template cannot replace a different template kind. Rename the integration template.`,
185
+ command: `${run} template ${shellArg(template.dirName)} --package ${shellArg(name)}`,
186
+ });
187
+ }
188
+ }
189
+ conflicts.sort((a, b) =>
190
+ `${a.id}:${a.relationship}`.localeCompare(`${b.id}:${b.relationship}`),
191
+ );
128
192
 
129
193
  return {
130
194
  type: 'integration.template-conflicts',
@@ -211,10 +275,11 @@ export async function integrationDocConflicts(pkg, options = {}) {
211
275
  };
212
276
  }
213
277
 
214
- const [{records, errors}, builtinTopics] = await Promise.all([
278
+ const [discovered, builtinTopics] = await Promise.all([
215
279
  discoverIntegrationDocs(resolved.integration),
216
280
  Promise.resolve(discoverBuiltinTopics()),
217
281
  ]);
282
+ const {records, errors} = discovered;
218
283
  addErrors(issues, errors, 'invalid_doc');
219
284
  const coreTopicsByKey = new Map(
220
285
  Object.keys(builtinTopics).map(topic => [topic.toLowerCase(), topic]),
@@ -276,6 +341,18 @@ export async function integrationDocConflicts(pkg, options = {}) {
276
341
  ),
277
342
  );
278
343
 
344
+ // The same graph checks `astryx doctor` runs in a project: the namespaces
345
+ // and placed guides this package adds to the docs tree, and every link in
346
+ // its docs (spec:AST-046, spec:AST-047).
347
+ if (errors.length === 0) {
348
+ for (const message of await packageDocsProblems(
349
+ /** @type {{name: string}} */ (resolved.integration),
350
+ discovered,
351
+ )) {
352
+ issues.push({code: 'invalid_doc_graph', severity: 'warning', message});
353
+ }
354
+ }
355
+
279
356
  return {
280
357
  type: 'integration.doc-conflicts',
281
358
  data: {name, version, findings, issues},