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

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 (466) hide show
  1. package/README.md +106 -73
  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/component.doc.mjs +13 -3
  10. package/api/component/component.mjs +31 -2
  11. package/api/component/component.test.mjs +38 -0
  12. package/api/component/component.type.d.mts +22 -11
  13. package/api/component/component.type.mjs +32 -24
  14. package/api/component/detail/blocks/blocks.d.mts +2 -1
  15. package/api/component/detail/blocks/blocks.mjs +4 -3
  16. package/api/component/list/list.d.mts +0 -5
  17. package/api/component/list/list.mjs +37 -9
  18. package/api/discover/discover.doc.mjs +2 -1
  19. package/api/discover/discover.type.d.mts +4 -4
  20. package/api/discover/discover.type.mjs +10 -10
  21. package/api/docs/_adapter.d.mts +28 -30
  22. package/api/docs/_adapter.mjs +73 -135
  23. package/api/docs/compiled-topics.test.mjs +78 -0
  24. package/api/docs/detail/detail.d.mts +0 -15
  25. package/api/docs/detail/detail.mjs +14 -78
  26. package/api/docs/detail/section/section.mjs +22 -18
  27. package/api/docs/detail/section/section.test.mjs +4 -3
  28. package/api/docs/docs.doc.mjs +1 -0
  29. package/api/docs/docs.type.d.mts +4 -4
  30. package/api/docs/docs.type.mjs +10 -10
  31. package/api/docs/index/index.mjs +6 -5
  32. package/api/docs/list/list.mjs +3 -7
  33. package/api/doctor/doctor.d.mts +25 -3
  34. package/api/doctor/doctor.doc.mjs +1 -0
  35. package/api/doctor/doctor.mjs +186 -18
  36. package/api/doctor/doctor.test.mjs +326 -1
  37. package/api/gap-report/gap-report.doc.mjs +8 -4
  38. package/api/hook/_adapter.mjs +19 -5
  39. package/api/hook/hook.doc.mjs +1 -0
  40. package/api/hook/hook.type.d.mts +3 -3
  41. package/api/hook/hook.type.mjs +11 -11
  42. package/api/hook/list/list.d.mts +1 -1
  43. package/api/hook/list/list.mjs +69 -17
  44. package/api/init/init.doc.mjs +5 -0
  45. package/api/init/init.test.mjs +41 -1
  46. package/api/init/remove/remove.mjs +1 -1
  47. package/api/init/run/run.mjs +20 -10
  48. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  49. package/api/integration/add-contribution.mjs +23 -10
  50. package/api/integration/add-contribution.test.mjs +121 -7
  51. package/api/integration/add-theme.mjs +34 -64
  52. package/api/integration/add-theme.test.mjs +105 -21
  53. package/api/integration/authoring-checks.test.mjs +8 -4
  54. package/api/integration/integration-block-exports.test.mjs +10 -6
  55. package/api/integration/integrationAdd.doc.mjs +8 -4
  56. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  57. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  58. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  59. package/api/integration/integrationAddDoc.doc.mjs +1 -0
  60. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  61. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  62. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  63. package/api/integration/integrationDocConflicts.doc.mjs +1 -0
  64. package/api/integration/integrationPackCheck.doc.mjs +1 -0
  65. package/api/integration/integrationTemplateConflicts.doc.mjs +1 -0
  66. package/api/integration/pack-check.mjs +49 -7
  67. package/api/integration/pack-check.test.mjs +266 -47
  68. package/api/integration/summarizeIssues.doc.mjs +1 -0
  69. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  70. package/api/integration/validate-integration.mjs +52 -102
  71. package/api/integration/validate-integration.test.mjs +176 -23
  72. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  73. package/api/integration/validateIntegration.doc.mjs +2 -1
  74. package/api/json/assertResponse.doc.mjs +1 -0
  75. package/api/json/envelope-types.test.mjs +76 -0
  76. package/api/json/isError.doc.mjs +1 -0
  77. package/api/json/parseResponse.doc.mjs +3 -2
  78. package/api/layout/expand/expand.mjs +7 -5
  79. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  80. package/api/layout/grammar/grammar.mjs +2 -1
  81. package/api/layout/layoutCheck.doc.mjs +1 -0
  82. package/api/layout/layoutExpand.doc.mjs +2 -1
  83. package/api/layout/layoutGrammar.doc.mjs +1 -0
  84. package/api/search/search-return-type.test.mjs +54 -0
  85. package/api/search/search.d.mts +2 -9
  86. package/api/search/search.doc.mjs +6 -1
  87. package/api/search/search.mjs +31 -14
  88. package/api/search/search.test.mjs +34 -0
  89. package/api/search/search.type.d.mts +1 -1
  90. package/api/search/search.type.mjs +1 -1
  91. package/api/swizzle/copy/copy.mjs +28 -11
  92. package/api/swizzle/swizzle.doc.mjs +2 -1
  93. package/api/swizzle/swizzle.type.d.mts +2 -2
  94. package/api/swizzle/swizzle.type.mjs +2 -2
  95. package/api/template/copy/copy.mjs +17 -23
  96. package/api/template/copy/copy.test.mjs +17 -0
  97. package/api/template/template-suffix.test.mjs +41 -21
  98. package/api/template/template.doc.mjs +3 -1
  99. package/api/template/template.type.d.mts +5 -5
  100. package/api/template/template.type.mjs +12 -12
  101. package/api/theme/_adapter.d.mts +2 -3
  102. package/api/theme/_adapter.mjs +4 -5
  103. package/api/theme/add/add.binary.test.mjs +84 -0
  104. package/api/theme/add/add.mjs +20 -3
  105. package/api/theme/add/add.staging.test.mjs +66 -0
  106. package/api/theme/add/add.test.mjs +14 -1
  107. package/api/theme/build/build.mjs +133 -42
  108. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  109. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  110. package/api/theme/build/build.test.mjs +127 -0
  111. package/api/theme/build/font-warning.mjs +3 -3
  112. package/api/theme/build/font-warning.test.mjs +5 -2
  113. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  114. package/api/theme/integration-themes.test.mjs +39 -28
  115. package/api/theme/list/list.test.mjs +19 -20
  116. package/api/theme/listThemes.doc.mjs +6 -5
  117. package/api/theme/palette/generate/generate.mjs +8 -3
  118. package/api/theme/palette/generate/generate.test.mjs +96 -0
  119. package/api/theme/palette/generate/generator.d.mts +10 -13
  120. package/api/theme/palette/generate/generator.mjs +15 -4
  121. package/api/theme/palette/generate/generator.test.mjs +10 -0
  122. package/api/theme/template/template.mjs +11 -2
  123. package/api/theme/template/template.test.mjs +15 -0
  124. package/api/theme/theme.type.d.mts +170 -11
  125. package/api/theme/theme.type.mjs +94 -27
  126. package/api/theme/themeAdd.doc.mjs +4 -3
  127. package/api/theme/themeBuild.doc.mjs +8 -4
  128. package/api/theme/themeList.doc.mjs +6 -3
  129. package/api/theme/themeListAvailable.doc.mjs +5 -3
  130. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  131. package/api/theme/themeTargets.doc.mjs +1 -0
  132. package/api/theme/themeTemplate.doc.mjs +5 -1
  133. package/api/upgrade/_adapter.d.mts +12 -3
  134. package/api/upgrade/_adapter.mjs +108 -70
  135. package/api/upgrade/list/list.mjs +2 -1
  136. package/api/upgrade/list/list.test.mjs +73 -0
  137. package/api/upgrade/provider-agreement.test.mjs +152 -0
  138. package/api/upgrade/run/run.mjs +1 -0
  139. package/api/upgrade/status/status.mjs +2 -2
  140. package/api/upgrade/upgrade.doc.mjs +3 -1
  141. package/api/upgrade/upgrade.type.d.mts +8 -4
  142. package/api/upgrade/upgrade.type.mjs +11 -10
  143. package/assets/codemods/integration-discovery.mjs +48 -4
  144. package/assets/codemods/integration-discovery.test.mjs +73 -0
  145. package/assets/codemods/runner.mjs +115 -5
  146. package/assets/codemods/term-log.mjs +32 -8
  147. package/assets/codemods/term-log.test.mjs +19 -1
  148. package/assets/codemods/transform-prop.mjs +109 -0
  149. package/assets/codemods/transform-prop.test.mjs +95 -0
  150. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +216 -0
  151. package/assets/codemods/transforms/next/index.mjs +11 -1
  152. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  153. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  154. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  155. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  156. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  157. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  158. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  159. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  160. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  161. package/assets/docs/cli-integrations.doc.mjs +26 -30
  162. package/assets/docs/cli.doc.mjs +15 -0
  163. package/assets/docs/styling-libraries.doc.mjs +1 -1
  164. package/assets/docs/theme.doc.mjs +1 -1
  165. package/assets/docs/working-with-ai.doc.mjs +1 -1
  166. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  167. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  168. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  169. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  170. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  171. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  172. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  173. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  174. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  175. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  176. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  177. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  178. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  179. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  180. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  181. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  182. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  183. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  184. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  185. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  186. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  187. package/authoring/_shared/contract.ts +22 -0
  188. package/authoring/codemod/codemod.doc.mjs +7 -2
  189. package/authoring/codemod/parse.d.mts +8 -8
  190. package/authoring/codemod/parse.mjs +8 -6
  191. package/authoring/config/config.doc.mjs +2 -2
  192. package/authoring/config/debug-composition.test.mjs +92 -0
  193. package/authoring/config/parse.d.mts +13 -13
  194. package/authoring/config/parse.mjs +8 -8
  195. package/authoring/config/type.ts +18 -6
  196. package/authoring/debug/debug.doc.d.mts +11 -0
  197. package/authoring/debug/debug.doc.mjs +182 -0
  198. package/authoring/debug/parse.d.mts +4 -4
  199. package/authoring/debug/parse.mjs +3 -3
  200. package/authoring/doctypes/_schema.d.mts +121 -11
  201. package/authoring/doctypes/_schema.mjs +144 -13
  202. package/authoring/doctypes/base/graph-fields.doc.mjs +11 -4
  203. package/authoring/doctypes/base/type.ts +8 -4
  204. package/authoring/doctypes/command/command.doc.mjs +4 -3
  205. package/authoring/doctypes/command/parse.d.mts +2 -2
  206. package/authoring/doctypes/command/parse.mjs +1 -1
  207. package/authoring/doctypes/command/type.ts +3 -3
  208. package/authoring/doctypes/component/component.doc.mjs +5 -2
  209. package/authoring/doctypes/component/parse.d.mts +2 -2
  210. package/authoring/doctypes/component/parse.mjs +1 -1
  211. package/authoring/doctypes/component/type.ts +3 -3
  212. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  213. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  214. package/authoring/doctypes/enum/parse.d.mts +2 -2
  215. package/authoring/doctypes/enum/parse.mjs +1 -1
  216. package/authoring/doctypes/enum/type.ts +2 -2
  217. package/authoring/doctypes/function/function.doc.mjs +5 -1
  218. package/authoring/doctypes/function/parse.d.mts +2 -2
  219. package/authoring/doctypes/function/parse.mjs +1 -1
  220. package/authoring/doctypes/function/type.ts +2 -2
  221. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  222. package/authoring/doctypes/hook/parse.d.mts +2 -2
  223. package/authoring/doctypes/hook/parse.mjs +1 -1
  224. package/authoring/doctypes/hook/type.ts +3 -3
  225. package/authoring/doctypes/legacy.d.mts +6 -6
  226. package/authoring/doctypes/legacy.mjs +3 -3
  227. package/authoring/doctypes/load-contract.test.mjs +208 -0
  228. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -3
  229. package/authoring/doctypes/namespace/parse.d.mts +2 -2
  230. package/authoring/doctypes/namespace/parse.mjs +1 -1
  231. package/authoring/doctypes/namespace/type.ts +2 -2
  232. package/authoring/doctypes/parse.d.mts +22 -20
  233. package/authoring/doctypes/parse.mjs +16 -12
  234. package/authoring/doctypes/reference/parse.d.mts +2 -2
  235. package/authoring/doctypes/reference/parse.mjs +1 -1
  236. package/authoring/doctypes/reference/reference.doc.mjs +7 -3
  237. package/authoring/doctypes/reference/type.ts +3 -3
  238. package/authoring/doctypes/schema/parse.d.mts +2 -2
  239. package/authoring/doctypes/schema/parse.mjs +1 -1
  240. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  241. package/authoring/doctypes/schema/type.ts +3 -4
  242. package/authoring/doctypes/template/parse.d.mts +92 -1
  243. package/authoring/doctypes/template/parse.mjs +33 -1
  244. package/authoring/doctypes/template/template.doc.mjs +7 -3
  245. package/authoring/doctypes/template/type.ts +4 -1
  246. package/authoring/doctypes/theme/parse.d.mts +35 -0
  247. package/authoring/doctypes/theme/parse.mjs +76 -0
  248. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  249. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  250. package/authoring/doctypes/theme/type.ts +42 -0
  251. package/authoring/doctypes/types.ts +12 -11
  252. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  253. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  254. package/authoring/gap-report/parse.d.mts +9 -9
  255. package/authoring/gap-report/parse.mjs +6 -6
  256. package/authoring/gap-report/type.ts +1 -1
  257. package/authoring/identity/identity.doc.mjs +3 -2
  258. package/authoring/identity/type.ts +10 -10
  259. package/authoring/index.d.mts +1 -0
  260. package/authoring/index.d.ts +21 -19
  261. package/authoring/index.mjs +2 -1
  262. package/authoring/integration/integration.doc.mjs +2 -2
  263. package/authoring/integration/parse.d.mts +2 -2
  264. package/authoring/integration/parse.mjs +1 -1
  265. package/authoring/integration/schema.d.mts +4 -4
  266. package/authoring/integration/schema.mjs +3 -3
  267. package/authoring/integration/type.ts +4 -10
  268. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  269. package/clients/cli/command-load-failure.test.mjs +83 -0
  270. package/clients/cli/commands/blog.doc.mjs +1 -1
  271. package/clients/cli/commands/blog.mjs +23 -8
  272. package/clients/cli/commands/blog.test.mjs +42 -1
  273. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  274. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  275. package/clients/cli/commands/build-theme.mjs +5 -5
  276. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  277. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  278. package/clients/cli/commands/build.doc.mjs +5 -2
  279. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  280. package/clients/cli/commands/build.mjs +32 -47
  281. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  282. package/clients/cli/commands/build.text-fields.test.mjs +40 -0
  283. package/clients/cli/commands/component/index.mjs +2 -7
  284. package/clients/cli/commands/component-package.test.mjs +46 -0
  285. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  286. package/clients/cli/commands/component.doc.mjs +1 -1
  287. package/clients/cli/commands/component.test.mjs +19 -0
  288. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  289. package/clients/cli/commands/discover.broken-integration.test.mjs +48 -0
  290. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  291. package/clients/cli/commands/discover.doc.mjs +5 -3
  292. package/clients/cli/commands/discover.mjs +3 -3
  293. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  294. package/clients/cli/commands/docs.doc.mjs +1 -1
  295. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  296. package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
  297. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -1
  298. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  299. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  300. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  301. package/clients/cli/commands/doctor-integration.test.mjs +15 -7
  302. package/clients/cli/commands/doctor.doc.mjs +1 -1
  303. package/clients/cli/commands/doctor.mjs +6 -16
  304. package/clients/cli/commands/doctor.test.mjs +42 -0
  305. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  306. package/clients/cli/commands/gap-report.test.mjs +72 -0
  307. package/clients/cli/commands/hook/index.mjs +7 -17
  308. package/clients/cli/commands/hook.doc.mjs +1 -1
  309. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  310. package/clients/cli/commands/init.doc.mjs +20 -9
  311. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  312. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  313. package/clients/cli/commands/integration-add.doc.mjs +22 -6
  314. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  315. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  316. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  317. package/clients/cli/commands/integration.doc.mjs +1 -1
  318. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  319. package/clients/cli/commands/json-contract.test.mjs +33 -0
  320. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  321. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  322. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  323. package/clients/cli/commands/layout.doc.mjs +3 -3
  324. package/clients/cli/commands/layout.mjs +21 -9
  325. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  326. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  327. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  328. package/clients/cli/commands/manifest.doc.mjs +1 -1
  329. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  330. package/clients/cli/commands/search.doc.mjs +7 -4
  331. package/clients/cli/commands/search.mjs +17 -7
  332. package/clients/cli/commands/search.test.mjs +75 -0
  333. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  334. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  335. package/clients/cli/commands/template.doc.mjs +29 -7
  336. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  337. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  338. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  339. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  340. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  341. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  342. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  343. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  344. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  345. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  346. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  347. package/clients/cli/commands/theme.doc.mjs +1 -1
  348. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  349. package/clients/cli/commands/upgrade.doc.mjs +18 -7
  350. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  351. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  352. package/clients/cli/index.mjs +13 -30
  353. package/clients/cli/latest-version-env.test.mjs +50 -0
  354. package/clients/cli/lib/cli-error.test.mjs +7 -0
  355. package/clients/cli/lib/component-format.mjs +9 -9
  356. package/clients/cli/lib/component-format.test.mjs +1 -1
  357. package/clients/cli/lib/define-command.mjs +32 -6
  358. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  359. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  360. package/clients/cli/lib/hook-format.mjs +19 -10
  361. package/clients/cli/lib/json-shim.mjs +38 -2
  362. package/clients/cli/lib/json-shim.test.mjs +83 -0
  363. package/clients/cli/lib/manifest.d.ts +2 -0
  364. package/clients/cli/lib/manifest.mjs +22 -0
  365. package/clients/cli/lib/manifest.test.mjs +17 -0
  366. package/foundation/agent-docs/agent-docs.d.mts +4 -0
  367. package/foundation/agent-docs/agent-docs.mjs +69 -3
  368. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  369. package/foundation/config/integration-debug.test.mjs +28 -3
  370. package/foundation/config/project-themes.test.mjs +11 -19
  371. package/foundation/config/project.d.mts +8 -0
  372. package/foundation/config/project.mjs +173 -30
  373. package/foundation/config/project.test.mjs +129 -16
  374. package/foundation/discovery/authoring-self-docs.d.mts +6 -0
  375. package/foundation/discovery/authoring-self-docs.mjs +17 -7
  376. package/foundation/discovery/authoring-self-docs.test.mjs +71 -12
  377. package/foundation/discovery/authoring-surface.d.mts +74 -0
  378. package/foundation/discovery/authoring-surface.mjs +525 -0
  379. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  380. package/foundation/discovery/cli-self-docs.d.mts +113 -0
  381. package/foundation/discovery/cli-self-docs.mjs +514 -0
  382. package/foundation/discovery/cli-self-docs.test.mjs +437 -0
  383. package/foundation/discovery/component-loader.d.mts +35 -38
  384. package/foundation/discovery/component-loader.mjs +53 -222
  385. package/foundation/discovery/docs-discovery.d.mts +7 -2
  386. package/foundation/discovery/docs-discovery.mjs +24 -14
  387. package/foundation/discovery/docs-discovery.test.mjs +55 -16
  388. package/foundation/discovery/template-adapter.d.mts +21 -5
  389. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  390. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  391. package/foundation/discovery/template-adapter.mjs +319 -65
  392. package/foundation/discovery/template-adapter.test.mjs +15 -0
  393. package/foundation/discovery/theme-discovery.d.mts +67 -7
  394. package/foundation/discovery/theme-discovery.mjs +916 -186
  395. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  396. package/foundation/discovery/theming-targets.test.mjs +4 -0
  397. package/foundation/doc-compiler/bundle.d.mts +47 -0
  398. package/foundation/doc-compiler/bundle.mjs +218 -0
  399. package/foundation/doc-compiler/bundle.test.mjs +255 -0
  400. package/foundation/doc-compiler/compile.d.mts +362 -0
  401. package/foundation/doc-compiler/compile.mjs +511 -0
  402. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  403. package/foundation/doc-compiler/diagnostics.mjs +277 -0
  404. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  405. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  406. package/foundation/doc-compiler/import.d.mts +24 -0
  407. package/foundation/doc-compiler/import.mjs +59 -0
  408. package/foundation/doc-compiler/inputs.d.mts +102 -0
  409. package/foundation/doc-compiler/inputs.mjs +286 -0
  410. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  411. package/foundation/doc-compiler/ir.d.mts +22 -0
  412. package/foundation/doc-compiler/ir.mjs +464 -0
  413. package/foundation/doc-compiler/lenses.d.mts +33 -0
  414. package/foundation/doc-compiler/lenses.mjs +127 -0
  415. package/foundation/doc-compiler/lower-doc.test.mjs +492 -0
  416. package/foundation/doc-compiler/overlays.d.mts +37 -0
  417. package/foundation/doc-compiler/overlays.mjs +206 -0
  418. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  419. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  420. package/foundation/doc-compiler/read.d.mts +126 -0
  421. package/foundation/doc-compiler/read.mjs +320 -0
  422. package/foundation/doc-compiler/read.test.mjs +313 -0
  423. package/foundation/doc-compiler/source.d.mts +33 -0
  424. package/foundation/doc-compiler/source.mjs +128 -0
  425. package/foundation/fs/module-loader.d.mts +1 -0
  426. package/foundation/fs/module-loader.mjs +50 -1
  427. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  428. package/foundation/fs/path-safety.d.mts +3 -2
  429. package/foundation/fs/path-safety.mjs +49 -19
  430. package/foundation/fs/path-safety.test.mjs +50 -0
  431. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  432. package/foundation/integrations/autolink.d.mts +58 -1
  433. package/foundation/integrations/autolink.mjs +143 -52
  434. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  435. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  436. package/foundation/integrations/contribution-inventory.d.mts +1 -1
  437. package/foundation/integrations/contribution-inventory.mjs +17 -20
  438. package/foundation/integrations/contribution-inventory.test.mjs +67 -27
  439. package/foundation/integrations/integrations.d.mts +3 -0
  440. package/foundation/integrations/integrations.mjs +11 -97
  441. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  442. package/foundation/integrations/provider-resolution.d.mts +152 -0
  443. package/foundation/integrations/provider-resolution.mjs +576 -0
  444. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  445. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  446. package/foundation/integrations/theme-descriptor.mjs +44 -0
  447. package/foundation/integrations/validate-contributions.mjs +104 -10
  448. package/foundation/response/base.d.ts +8 -4
  449. package/foundation/response/error-codes.doc.mjs +3 -4
  450. package/foundation/response/error-codes.mjs +2 -2
  451. package/foundation/response/error-codes.test.mjs +83 -0
  452. package/foundation/response/json-contract.test.mjs +11 -0
  453. package/foundation/response/json.d.mts +4 -2
  454. package/foundation/response/json.mjs +8 -10
  455. package/foundation/response/response-types.doc.mjs +11 -11
  456. package/foundation/response/response-types.doc.test.mjs +158 -0
  457. package/foundation/response/response.doc.mjs +1 -1
  458. package/foundation/text/string-utils.mjs +22 -10
  459. package/foundation/xle/expand.d.mts +2 -0
  460. package/foundation/xle/expand.mjs +3 -2
  461. package/foundation/xle/expand.test.mjs +54 -0
  462. package/package.json +9 -11
  463. package/assets/templates/themes/manifest.json +0 -95
  464. package/clients/cli/lib/update-check.mjs +0 -83
  465. package/clients/cli/lib/update-check.test.mjs +0 -137
  466. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -5,10 +5,11 @@ export const doc = {
5
5
  type: 'function',
6
6
  kind: 'api',
7
7
  name: 'integrationAddComponent',
8
+ namespace: 'cli/api',
8
9
  displayName: 'integrationAddComponent()',
9
10
  summary: 'Add a complete component contribution.',
10
11
  description:
11
- 'Creates the same-stem component source and metadata pair, declares the components root on first use, preserves existing package allowlists, and publishes an exact source subpath when the package already has an exports map.',
12
+ 'Creates the same-stem component source and metadata pair, declares the components root on first use, preserves existing package allowlists, and publishes an exact source subpath when the package already has an exports map. Refuses with ERR_FILE_EXISTS when a component doc anywhere under the components root already uses the name.',
12
13
  importPath: '@astryxdesign/cli/api',
13
14
  signature:
14
15
  'integrationAddComponent(name: string, options?: IntegrationAddComponentOptions): Promise<IntegrationAddResponse>',
@@ -5,6 +5,7 @@ export const doc = {
5
5
  type: 'function',
6
6
  kind: 'api',
7
7
  name: 'integrationAddDoc',
8
+ namespace: 'cli/api',
8
9
  displayName: 'integrationAddDoc()',
9
10
  summary: 'Add a complete reference-doc contribution.',
10
11
  description:
@@ -5,6 +5,7 @@ export const doc = {
5
5
  type: 'function',
6
6
  kind: 'api',
7
7
  name: 'integrationAddTemplate',
8
+ namespace: 'cli/api',
8
9
  displayName: 'integrationAddTemplate()',
9
10
  summary: 'Add a complete page or block template contribution.',
10
11
  description:
@@ -5,10 +5,11 @@ export const doc = {
5
5
  type: 'function',
6
6
  kind: 'api',
7
7
  name: 'integrationAddTheme',
8
+ namespace: 'cli/api',
8
9
  displayName: 'integrationAddTheme()',
9
10
  summary: 'Add a source theme to an integration package.',
10
11
  description:
11
- 'Creates an integration manifest when the package has none, writes a minimal named-export defineTheme source file, adds its entry to the root theme catalog, declares the optional themes root on first use, and includes the manifest and root in package.json files when the package already uses an allowlist. Every path is confined to the package and existing theme files are never overwritten.',
12
+ 'Creates an integration manifest when the package has none, writes a minimal named-export defineTheme source file plus its strongly typed same-stem ThemeDoc, declares the optional themes root on first use, and includes the manifest and root in package.json files when the package already uses an allowlist. Every path is confined to the package and existing theme directories are never overwritten.',
12
13
  importPath: '@astryxdesign/cli/api',
13
14
  signature:
14
15
  'integrationAddTheme(name: string, options?: IntegrationAddThemeOptions): Promise<IntegrationAddResponse>',
@@ -17,7 +18,7 @@ export const doc = {
17
18
  {
18
19
  name: 'name',
19
20
  type: 'string',
20
- description: 'Lowercase kebab-case theme name and catalog slug.',
21
+ description: 'Lowercase kebab-case theme name and directory slug.',
21
22
  required: true,
22
23
  },
23
24
  {
@@ -51,7 +52,7 @@ export const doc = {
51
52
  },
52
53
  {
53
54
  code: 'ERR_FILE_EXISTS',
54
- when: 'the theme slug or source file already exists',
55
+ when: 'the theme slug directory already exists',
55
56
  },
56
57
  {
57
58
  code: 'ERR_PATH_TRAVERSAL',
@@ -63,7 +64,7 @@ export const doc = {
63
64
  },
64
65
  {
65
66
  code: 'ERR_THEME_INVALID',
66
- when: 'the package, integration manifest, or theme catalog is invalid',
67
+ when: 'the package, integration manifest, or theme descriptor is invalid',
67
68
  },
68
69
  {
69
70
  code: 'ERR_WRITE_FAILED',
@@ -80,6 +81,6 @@ export const doc = {
80
81
  code: "await integrationAddTheme('ocean', {dryRun: true});",
81
82
  },
82
83
  ],
83
- command: 'integration add',
84
+ command: 'integration add theme',
84
85
  related: ['themeList', 'themeAdd', 'validateIntegration'],
85
86
  };
@@ -7,6 +7,7 @@ export const doc = {
7
7
  type: 'function',
8
8
  kind: 'api',
9
9
  name: 'integrationComponentConflicts',
10
+ namespace: 'cli/api',
10
11
  displayName: 'integrationComponentConflicts()',
11
12
  summary: 'Find integration component names that also exist in Core.',
12
13
  description:
@@ -7,6 +7,7 @@ export const doc = {
7
7
  type: 'function',
8
8
  kind: 'api',
9
9
  name: 'integrationDocConflicts',
10
+ namespace: 'cli/api',
10
11
  displayName: 'integrationDocConflicts()',
11
12
  summary: 'Classify integration doc overlaps with Core topics.',
12
13
  description:
@@ -5,6 +5,7 @@ export const doc = {
5
5
  type: 'function',
6
6
  kind: 'api',
7
7
  name: 'integrationPackCheck',
8
+ namespace: 'cli/api',
8
9
  displayName: 'integrationPackCheck()',
9
10
  summary: 'Prove an integration package survives npm packing.',
10
11
  description:
@@ -9,6 +9,7 @@ export const doc = {
9
9
  type: 'function',
10
10
  kind: 'api',
11
11
  name: 'integrationTemplateConflicts',
12
+ namespace: 'cli/api',
12
13
  displayName: 'integrationTemplateConflicts()',
13
14
  summary: 'Find integration template ids that also exist in Core.',
14
15
  description:
@@ -388,6 +388,14 @@ async function validatePackedComponentExports(integration, scratchBase) {
388
388
  components.map(component => component.specifier),
389
389
  scratchBase,
390
390
  );
391
+ issues.push(
392
+ ...validateSpecifierExtensions(
393
+ components.map(({name, specifier}) => ({
394
+ label: `Component "${name}"`,
395
+ specifier,
396
+ })),
397
+ ),
398
+ );
391
399
  for (const {name, specifier} of components) {
392
400
  const result = resolved.get(specifier);
393
401
  if (!result?.url || result.error) {
@@ -427,19 +435,27 @@ async function validatePackedComponentExports(integration, scratchBase) {
427
435
  */
428
436
  async function validatePackedTemplateExports(integration, scratchBase) {
429
437
  const {templates} = await discoverIntegrationTemplatesForOne(integration);
430
- const entries = templates.map(template => ({
431
- id: template.dirName,
432
- specifier: `${integration.name}/${path
438
+ const entries = templates.map(template => {
439
+ const relPath = path
433
440
  .relative(integration.__packageDir, template.filePath)
434
441
  .split(path.sep)
435
- .join('/')}`,
436
- }));
442
+ .join('/');
443
+ const extensionless = relPath.replace(/\.tsx?$/u, '');
444
+ return {
445
+ id: template.dirName,
446
+ specifier: `${integration.name}/${extensionless}`,
447
+ };
448
+ });
437
449
  const resolved = resolveConsumerSpecifiers(
438
450
  entries.map(entry => entry.specifier),
439
451
  scratchBase,
440
452
  );
441
- /** @type {Issue[]} */
442
- const issues = [];
453
+ const issues = validateSpecifierExtensions(
454
+ entries.map(({id, specifier}) => ({
455
+ label: `Template "${id}"`,
456
+ specifier,
457
+ })),
458
+ );
443
459
  for (const {id, specifier} of entries) {
444
460
  const result = resolved.get(specifier);
445
461
  if (!result?.url || result.error) {
@@ -469,6 +485,32 @@ async function validatePackedTemplateExports(integration, scratchBase) {
469
485
  return issues;
470
486
  }
471
487
 
488
+ const TS_EXTENSION_RE = /\.tsx?$/u;
489
+
490
+ /**
491
+ * Reject specifiers that end in a TypeScript extension — they fail under
492
+ * default `moduleResolution` with TS5097/TS2307 unless the consumer enables
493
+ * `allowImportingTsExtensions`.
494
+ *
495
+ * @param {Array<{label: string, specifier: string}>} entries
496
+ * @returns {Issue[]}
497
+ */
498
+ function validateSpecifierExtensions(entries) {
499
+ /** @type {Issue[]} */
500
+ const issues = [];
501
+ for (const {label, specifier} of entries) {
502
+ if (TS_EXTENSION_RE.test(specifier)) {
503
+ issues.push(
504
+ error(
505
+ 'typescript_extension_in_specifier',
506
+ `${label} advertises import "${specifier}", which ends in a TypeScript extension. A consumer with default moduleResolution will reject it (TS5097). Use an extensionless specifier mapped through the package exports.`,
507
+ ),
508
+ );
509
+ }
510
+ }
511
+ return issues;
512
+ }
513
+
472
514
  /**
473
515
  * Verify an integration package is ready to publish.
474
516
  *
@@ -53,25 +53,10 @@ function writePackage({
53
53
  "import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const oceanTheme = defineTheme({name: 'ocean'});\n",
54
54
  );
55
55
  fs.writeFileSync(
56
- path.join(root, 'manifest.json'),
57
- JSON.stringify(
58
- {
59
- version: 1,
60
- themes: [
61
- {
62
- slug: 'ocean',
63
- displayName: 'Ocean',
64
- description: 'Ocean theme.',
65
- maintained: true,
66
- entry: 'oceanTheme.ts',
67
- exportName: 'oceanTheme',
68
- files: ['oceanTheme.ts'],
69
- },
70
- ],
71
- },
72
- null,
73
- 2,
74
- ) + '\n',
56
+ path.join(root, 'ocean', 'oceanTheme.doc.mjs'),
57
+ `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */
58
+ export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Ocean theme.', maintained: true};
59
+ `,
75
60
  );
76
61
  }
77
62
  if (components) {
@@ -109,7 +94,7 @@ describe('integrationPackCheck', () => {
109
94
  );
110
95
  });
111
96
 
112
- it('fails when a theme entry omits its catalog export', async () => {
97
+ it('fails when a theme entry omits its inferred runtime export', async () => {
113
98
  writePackage({files: ['astryx.integration.mjs', 'themes']});
114
99
  fs.writeFileSync(
115
100
  path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
@@ -129,19 +114,12 @@ describe('integrationPackCheck', () => {
129
114
  );
130
115
  });
131
116
 
132
- it('fails when a theme imports a file omitted from its catalog', async () => {
117
+ it('fails when a theme imports a missing local file', async () => {
133
118
  writePackage({files: ['astryx.integration.mjs', 'themes']});
134
- fs.mkdirSync(path.join(tmpDir, 'themes', 'ocean', 'tokens'), {
135
- recursive: true,
136
- });
137
119
  fs.writeFileSync(
138
120
  path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
139
121
  "import {oceanPalette} from './tokens/ocean.palette';\nexport const oceanTheme = {oceanPalette};\n",
140
122
  );
141
- fs.writeFileSync(
142
- path.join(tmpDir, 'themes', 'ocean', 'tokens', 'ocean.palette.ts'),
143
- 'export const oceanPalette = {};\n',
144
- );
145
123
 
146
124
  const result = await integrationPackCheck({cwd: tmpDir});
147
125
 
@@ -150,7 +128,7 @@ describe('integrationPackCheck', () => {
150
128
  expect.objectContaining({
151
129
  code: 'invalid_theme',
152
130
  message: expect.stringContaining(
153
- 'must resolve to a listed file inside the theme directory',
131
+ 'must resolve to a file inside the theme directory',
154
132
  ),
155
133
  }),
156
134
  );
@@ -231,7 +209,7 @@ describe('integrationPackCheck', () => {
231
209
  );
232
210
  fs.mkdirSync(path.join(tmpDir, 'templates'));
233
211
  fs.writeFileSync(
234
- path.join(tmpDir, 'templates', 'account-page.template.mjs'),
212
+ path.join(tmpDir, 'templates', 'account-page.doc.mjs'),
235
213
  "export default {type: 'page', name: 'Account page', description: 'Account page.'};\n",
236
214
  );
237
215
  fs.writeFileSync(
@@ -314,10 +292,10 @@ describe('integrationPackCheck', () => {
314
292
  const script = [
315
293
  "const fs=require('fs')",
316
294
  "fs.renameSync('themes/ocean','themes/storm')",
317
- "const p='themes/manifest.json'",
318
- 'const x=JSON.parse(fs.readFileSync(p))',
319
- "x.themes[0].slug='storm'",
320
- 'fs.writeFileSync(p,JSON.stringify(x))',
295
+ "const p='themes/storm/oceanTheme.doc.mjs'",
296
+ "let x=fs.readFileSync(p,'utf8')",
297
+ "x=x.replace(/name: 'ocean'/, 'name: '+String.fromCharCode(39)+'storm'+String.fromCharCode(39))",
298
+ 'fs.writeFileSync(p,x)',
321
299
  ].join(';');
322
300
  writePackage({
323
301
  files: ['astryx.integration.mjs', 'themes'],
@@ -513,23 +491,15 @@ describe('integrationPackCheck', () => {
513
491
  });
514
492
 
515
493
  describe('pack-check mutation tests', () => {
516
- it('detects when a theme file is deleted after initial add', async () => {
494
+ it('detects when a theme source is deleted after initial authoring', async () => {
517
495
  writePackage({files: ['astryx.integration.mjs', 'themes']});
518
-
519
- // Write a second theme file then delete it — catalog still references it
520
- const catalog = JSON.parse(
521
- fs.readFileSync(path.join(tmpDir, 'themes', 'manifest.json'), 'utf-8'),
522
- );
523
- catalog.themes[0].files.push('tokens.ts');
524
- fs.writeFileSync(
525
- path.join(tmpDir, 'themes', 'manifest.json'),
526
- JSON.stringify(catalog, null, 2) + '\n',
527
- );
528
- // tokens.ts doesn't exist on disk → will be in inventory but not on disk
529
- // (Phase 1 catches this; the file won't be in the pack list either)
496
+ fs.rmSync(path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'));
530
497
 
531
498
  const result = await integrationPackCheck({cwd: tmpDir});
532
499
  expect(result.data.packable).toBe(false);
500
+ expect(result.data.issues).toContainEqual(
501
+ expect.objectContaining({code: 'invalid_theme'}),
502
+ );
533
503
  });
534
504
 
535
505
  it('detects when files[] is narrowed after add removes themes', async () => {
@@ -567,3 +537,252 @@ describe('pack-check mutation tests', () => {
567
537
  }
568
538
  });
569
539
  });
540
+
541
+ describe('extensionless subpath resolution', () => {
542
+ it('rejects .tsx public specifiers before publishing', async () => {
543
+ // Manually construct a package with OLD-style .tsx exports keys
544
+ writePackage({
545
+ manifest: "export default {components: './components'};\n",
546
+ files: ['astryx.integration.mjs', 'components', 'index.mjs'],
547
+ themes: false,
548
+ });
549
+ const pkgFile = path.join(tmpDir, 'package.json');
550
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
551
+ pkg.exports = {
552
+ '.': './index.mjs',
553
+ './components/AcmeWidget.tsx': './components/AcmeWidget.tsx',
554
+ };
555
+ fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
556
+ fs.writeFileSync(
557
+ path.join(tmpDir, 'index.mjs'),
558
+ 'export const existing = 1;\n',
559
+ );
560
+ fs.mkdirSync(path.join(tmpDir, 'components'));
561
+ fs.writeFileSync(
562
+ path.join(tmpDir, 'components', 'AcmeWidget.doc.mjs'),
563
+ `export default {type: 'component', name: 'AcmeWidget', import: '@acme/widgets/components/AcmeWidget.tsx', description: 'Widget.', props: []};\n`,
564
+ );
565
+ fs.writeFileSync(
566
+ path.join(tmpDir, 'components', 'AcmeWidget.tsx'),
567
+ 'export function AcmeWidget() { return null; }\n',
568
+ );
569
+
570
+ const result = await integrationPackCheck({cwd: tmpDir});
571
+
572
+ // The .tsx extension in the specifier must be caught
573
+ expect(result.data.packable).toBe(false);
574
+ expect(result.data.issues).toContainEqual(
575
+ expect.objectContaining({
576
+ code: 'typescript_extension_in_specifier',
577
+ message: expect.stringContaining('.tsx'),
578
+ }),
579
+ );
580
+ });
581
+
582
+ it('generated extensionless component specifier resolves through exports map', async () => {
583
+ fs.writeFileSync(
584
+ path.join(tmpDir, 'package.json'),
585
+ `${JSON.stringify({
586
+ name: '@acme/widgets',
587
+ version: '1.0.0',
588
+ files: ['index.mjs'],
589
+ exports: {'.': './index.mjs'},
590
+ })}\n`,
591
+ );
592
+ fs.writeFileSync(
593
+ path.join(tmpDir, 'index.mjs'),
594
+ 'export const existing = 1;\n',
595
+ );
596
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
597
+
598
+ // Verify the exports map has extensionless key → .tsx target
599
+ const pkg = JSON.parse(
600
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
601
+ );
602
+ expect(pkg.exports['./components/AcmeWidget']).toBe(
603
+ './components/AcmeWidget.tsx',
604
+ );
605
+ expect(pkg.exports['./components/AcmeWidget.tsx']).toBeUndefined();
606
+
607
+ const result = await integrationPackCheck({cwd: tmpDir});
608
+
609
+ expect(result.data.packable).toBe(true);
610
+ expect(result.data.issues).not.toContainEqual(
611
+ expect.objectContaining({code: 'typescript_extension_in_specifier'}),
612
+ );
613
+ expect(result.data.issues).not.toContainEqual(
614
+ expect.objectContaining({code: 'component_import_unresolvable'}),
615
+ );
616
+ });
617
+
618
+ it('validates generated imports without project-local TypeScript', async () => {
619
+ fs.rmSync(tmpDir, {recursive: true, force: true});
620
+ tmpDir = fs.mkdtempSync(
621
+ path.join(os.tmpdir(), 'astryx-pack-check-no-typescript-'),
622
+ );
623
+ fs.writeFileSync(
624
+ path.join(tmpDir, 'package.json'),
625
+ `${JSON.stringify({
626
+ name: '@acme/widgets',
627
+ version: '1.0.0',
628
+ files: ['index.mjs'],
629
+ exports: {'.': './index.mjs'},
630
+ })}\n`,
631
+ );
632
+ fs.writeFileSync(
633
+ path.join(tmpDir, 'index.mjs'),
634
+ 'export const existing = 1;\n',
635
+ );
636
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
637
+
638
+ const result = await integrationPackCheck({cwd: tmpDir});
639
+
640
+ expect(result.data.packable).toBe(true);
641
+ expect(result.data.issues).not.toContainEqual(
642
+ expect.objectContaining({code: 'component_import_unresolvable'}),
643
+ );
644
+ });
645
+
646
+ it('generated extensionless template specifiers resolve for page and block types', async () => {
647
+ fs.writeFileSync(
648
+ path.join(tmpDir, 'package.json'),
649
+ `${JSON.stringify({
650
+ name: '@acme/widgets',
651
+ version: '1.0.0',
652
+ files: ['index.mjs'],
653
+ exports: {'.': './index.mjs'},
654
+ })}\n`,
655
+ );
656
+ fs.writeFileSync(
657
+ path.join(tmpDir, 'index.mjs'),
658
+ 'export const existing = 1;\n',
659
+ );
660
+ await integrationAddTemplate('account-page', {cwd: tmpDir, type: 'page'});
661
+ await integrationAddTemplate('info-card', {cwd: tmpDir, type: 'block'});
662
+
663
+ const pkg = JSON.parse(
664
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
665
+ );
666
+ expect(pkg.exports['./templates/account-page']).toBe(
667
+ './templates/account-page.tsx',
668
+ );
669
+ expect(pkg.exports['./templates/info-card']).toBe(
670
+ './templates/info-card.tsx',
671
+ );
672
+
673
+ const result = await integrationPackCheck({cwd: tmpDir});
674
+
675
+ expect(result.data.packable).toBe(true);
676
+ expect(result.data.issues).not.toContainEqual(
677
+ expect.objectContaining({code: 'template_import_unresolvable'}),
678
+ );
679
+ expect(result.data.issues).not.toContainEqual(
680
+ expect.objectContaining({code: 'typescript_extension_in_specifier'}),
681
+ );
682
+ });
683
+
684
+ it('preserves condition-style exports sugar without creating a map', async () => {
685
+ // Package with condition-only exports (sugar, no subpaths)
686
+ fs.writeFileSync(
687
+ path.join(tmpDir, 'package.json'),
688
+ `${JSON.stringify({
689
+ name: '@acme/widgets',
690
+ version: '1.0.0',
691
+ files: ['index.mjs'],
692
+ exports: {import: './index.mjs', require: './index.cjs'},
693
+ })}\n`,
694
+ );
695
+ fs.writeFileSync(
696
+ path.join(tmpDir, 'index.mjs'),
697
+ 'export const existing = 1;\n',
698
+ );
699
+ fs.writeFileSync(path.join(tmpDir, 'index.cjs'), 'exports.existing = 1;\n');
700
+ fs.writeFileSync(
701
+ path.join(tmpDir, 'astryx.integration.mjs'),
702
+ 'export default {};\n',
703
+ );
704
+
705
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
706
+
707
+ const pkg = JSON.parse(
708
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
709
+ );
710
+ // Condition sugar wrapped into subpath map with the component added
711
+ expect(pkg.exports['.']).toEqual({
712
+ import: './index.mjs',
713
+ require: './index.cjs',
714
+ });
715
+ expect(pkg.exports['./components/AcmeWidget']).toBe(
716
+ './components/AcmeWidget.tsx',
717
+ );
718
+ });
719
+
720
+ it('no-map: pack-check fails when generated component has no exports map', async () => {
721
+ fs.writeFileSync(
722
+ path.join(tmpDir, 'package.json'),
723
+ `${JSON.stringify({
724
+ name: '@acme/widgets',
725
+ version: '1.0.0',
726
+ files: ['dist'],
727
+ })}\n`,
728
+ );
729
+ fs.writeFileSync(
730
+ path.join(tmpDir, 'astryx.integration.mjs'),
731
+ 'export default {};\n',
732
+ );
733
+
734
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
735
+ await integrationAddTemplate('hero-page', {cwd: tmpDir, type: 'page'});
736
+
737
+ const pkg = JSON.parse(
738
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
739
+ );
740
+ // No exports map created
741
+ expect(pkg.exports).toBeUndefined();
742
+
743
+ const result = await integrationPackCheck({cwd: tmpDir});
744
+
745
+ // The extensionless import cannot resolve without an exports map —
746
+ // pack-check must fail closed, not false-green.
747
+ expect(result.data.packable).toBe(false);
748
+ expect(result.data.issues).toContainEqual(
749
+ expect.objectContaining({
750
+ severity: 'error',
751
+ message: expect.stringContaining('AcmeWidget'),
752
+ }),
753
+ );
754
+ });
755
+
756
+ it('idempotent when extensionless export already exists', async () => {
757
+ fs.writeFileSync(
758
+ path.join(tmpDir, 'package.json'),
759
+ `${JSON.stringify({
760
+ name: '@acme/widgets',
761
+ version: '1.0.0',
762
+ files: ['index.mjs'],
763
+ exports: {
764
+ '.': './index.mjs',
765
+ './components/AcmeWidget': './components/AcmeWidget.tsx',
766
+ },
767
+ })}\n`,
768
+ );
769
+ fs.writeFileSync(
770
+ path.join(tmpDir, 'index.mjs'),
771
+ 'export const existing = 1;\n',
772
+ );
773
+ fs.writeFileSync(
774
+ path.join(tmpDir, 'astryx.integration.mjs'),
775
+ 'export default {};\n',
776
+ );
777
+
778
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
779
+
780
+ const pkg = JSON.parse(
781
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
782
+ );
783
+ // Export preserved, no duplicate
784
+ expect(
785
+ Object.keys(pkg.exports).filter(k => k.includes('AcmeWidget')),
786
+ ).toEqual(['./components/AcmeWidget']);
787
+ });
788
+ });
@@ -12,6 +12,7 @@ export const doc = {
12
12
  type: 'function',
13
13
  kind: 'api',
14
14
  name: 'summarizeIssues',
15
+ namespace: 'cli/api',
15
16
  displayName: 'summarizeIssues()',
16
17
  summary:
17
18
  'Tally integration issues by severity into error and warning counts.',