@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.3-canary.02f5fe4

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 (694) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +216 -162
  3. package/api/build/_adapter.d.mts +66 -0
  4. package/api/build/_adapter.mjs +139 -4
  5. package/api/build/blocks/blocks.d.mts +92 -0
  6. package/api/build/blocks/blocks.mjs +528 -0
  7. package/api/build/blocks/blocks.test.mjs +238 -0
  8. package/api/build/blocks/blocks.weights.json +1 -0
  9. package/api/build/build.doc.mjs +4 -0
  10. package/api/build/build.mjs +25 -6
  11. package/api/build/build.type.mjs +1 -1
  12. package/api/build/help/help.mjs +1 -1
  13. package/api/build/kit/answer.d.mts +18 -0
  14. package/api/build/kit/answer.mjs +195 -0
  15. package/api/build/kit/answer.test.mjs +108 -0
  16. package/api/build/kit/kind.d.mts +25 -0
  17. package/api/build/kit/kind.mjs +170 -0
  18. package/api/build/kit/kit.d.mts +2 -4
  19. package/api/build/kit/kit.mjs +8 -406
  20. package/api/build/kit/rank.d.mts +3 -32
  21. package/api/build/kit/rank.mjs +25 -342
  22. package/api/build/kit/rank.test.mjs +2 -1
  23. package/api/build/kit/signals.d.mts +79 -0
  24. package/api/build/kit/signals.mjs +295 -0
  25. package/api/build/kit/start.d.mts +32 -0
  26. package/api/build/kit/start.mjs +163 -0
  27. package/api/build/kit/words.d.mts +72 -0
  28. package/api/build/kit/words.mjs +202 -0
  29. package/api/build/tree.d.mts +20 -0
  30. package/api/build/tree.mjs +53 -0
  31. package/api/build/tree.test.mjs +185 -0
  32. package/api/build/tree.weights.json +1 -0
  33. package/api/component/_adapter.d.mts +72 -1
  34. package/api/component/_adapter.mjs +251 -23
  35. package/api/component/component-replacement.test.mjs +1 -0
  36. package/api/component/component.doc.mjs +6 -1
  37. package/api/component/component.mjs +97 -16
  38. package/api/component/component.test.mjs +95 -0
  39. package/api/component/doc-links.test.mjs +386 -0
  40. package/api/component/integration-export-name.test.mjs +644 -0
  41. package/api/component/list/list.mjs +42 -4
  42. package/api/discover/_adapter.d.mts +131 -12
  43. package/api/discover/_adapter.mjs +520 -34
  44. package/api/discover/_adapter.test.mjs +641 -17
  45. package/api/discover/_catalog-view.d.mts +16 -5
  46. package/api/discover/_catalog-view.mjs +32 -8
  47. package/api/discover/detail/doc/doc.mjs +9 -1
  48. package/api/discover/discover.d.mts +11 -0
  49. package/api/discover/discover.doc.mjs +9 -7
  50. package/api/discover/discover.mjs +120 -19
  51. package/api/discover/discover.type.d.mts +20 -7
  52. package/api/discover/discover.type.mjs +17 -7
  53. package/api/discover/list/list.d.mts +4 -3
  54. package/api/discover/list/list.mjs +17 -10
  55. package/api/docs/_adapter.d.mts +76 -2
  56. package/api/docs/_adapter.mjs +630 -34
  57. package/api/docs/docs-homes.test.mjs +127 -0
  58. package/api/docs/docs.doc.mjs +5 -4
  59. package/api/docs/docs.mjs +2 -1
  60. package/api/docs/docs.test.mjs +39 -20
  61. package/api/docs/integration-tree.test.mjs +42 -20
  62. package/api/docs/integrationDocs.test.mjs +125 -1
  63. package/api/docs/list/list.mjs +12 -2
  64. package/api/docs/namespace-section.test.mjs +6 -6
  65. package/api/docs/reference-blocks.test.mjs +3 -5
  66. package/api/doctor/_adapter.d.mts +128 -0
  67. package/api/doctor/_adapter.mjs +253 -4
  68. package/api/doctor/doctor.d.mts +217 -0
  69. package/api/doctor/doctor.doc.mjs +3 -2
  70. package/api/doctor/doctor.mjs +691 -52
  71. package/api/doctor/doctor.test.mjs +267 -18
  72. package/api/doctor/release-checks.test.mjs +156 -0
  73. package/api/doctor/theme-checks.mjs +17 -4
  74. package/api/doctor/theme-checks.test.mjs +223 -7
  75. package/api/error.d.mts +10 -0
  76. package/api/error.mjs +25 -0
  77. package/api/gap-report/gap-report.d.mts +3 -0
  78. package/api/gap-report/gap-report.doc.mjs +11 -3
  79. package/api/gap-report/gap-report.mjs +219 -52
  80. package/api/gap-report/gap-report.test.mjs +233 -0
  81. package/api/gap-report/gap-report.type.d.mts +41 -0
  82. package/api/gap-report/gap-report.type.mjs +18 -0
  83. package/api/hook/_adapter.mjs +3 -11
  84. package/api/hook/hook.doc.mjs +4 -0
  85. package/api/hook/hook.mjs +1 -1
  86. package/api/hook/list/list.d.mts +1 -1
  87. package/api/index.d.mts +2 -0
  88. package/api/index.mjs +2 -0
  89. package/api/init/_adapter.d.mts +22 -0
  90. package/api/init/_adapter.mjs +59 -0
  91. package/api/init/init.d.mts +7 -5
  92. package/api/init/init.doc.mjs +45 -10
  93. package/api/init/init.mjs +28 -4
  94. package/api/init/init.test.mjs +18 -2
  95. package/api/init/init.type.d.mts +50 -5
  96. package/api/init/init.type.mjs +39 -5
  97. package/api/init/remove/remove.mjs +17 -4
  98. package/api/init/remove/remove.test.mjs +114 -2
  99. package/api/init/run/run.d.mts +1 -1
  100. package/api/init/run/run.mjs +86 -12
  101. package/api/init/user/user.d.mts +14 -0
  102. package/api/init/user/user.mjs +87 -0
  103. package/api/init/user/user.test.mjs +232 -0
  104. package/api/integration/_adapter.d.mts +53 -0
  105. package/api/integration/_adapter.mjs +132 -0
  106. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  107. package/api/integration/add-contribution.mjs +8 -4
  108. package/api/integration/add-contribution.test.mjs +4 -2
  109. package/api/integration/authoring-checks.mjs +192 -14
  110. package/api/integration/authoring-checks.test.mjs +1028 -0
  111. package/api/integration/authoring-checks.type.d.mts +143 -0
  112. package/api/integration/authoring-checks.type.mjs +74 -2
  113. package/api/integration/check/check.d.mts +96 -0
  114. package/api/integration/check/check.mjs +357 -0
  115. package/api/integration/check/check.test.mjs +489 -0
  116. package/api/integration/integration-check.type.d.mts +118 -0
  117. package/api/integration/integration-check.type.mjs +84 -0
  118. package/api/integration/integrationCheck.doc.d.mts +10 -0
  119. package/api/integration/integrationCheck.doc.mjs +73 -0
  120. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  121. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  122. package/api/integration/pack-check.mjs +486 -123
  123. package/api/integration/pack-check.test.mjs +817 -10
  124. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +73 -5
  126. package/api/integration/validate-integration-gaps.test.mjs +1975 -0
  127. package/api/integration/validate-integration.d.mts +23 -2
  128. package/api/integration/validate-integration.mjs +358 -45
  129. package/api/integration/validate-integration.test.mjs +88 -8
  130. package/api/integration/validate-integration.type.d.mts +105 -0
  131. package/api/integration/validate-integration.type.mjs +79 -1
  132. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  133. package/api/integration/validateIntegration.doc.mjs +19 -3
  134. package/api/search/ORDERING.md +28 -0
  135. package/api/search/_adapter.d.mts +91 -0
  136. package/api/search/_adapter.mjs +172 -0
  137. package/api/search/_adapter.test.mjs +173 -0
  138. package/api/search/_candidate-score.d.mts +40 -0
  139. package/api/search/_candidate-score.mjs +238 -0
  140. package/api/search/_cards.json +6098 -0
  141. package/api/search/_compound.d.mts +50 -0
  142. package/api/search/_compound.mjs +170 -0
  143. package/api/search/_doc-searcher.d.mts +4 -0
  144. package/api/search/_doc-searcher.mjs +23 -0
  145. package/api/search/_doc-searcher.test.mjs +36 -0
  146. package/api/search/_doc-searcher.weights.json +1 -0
  147. package/api/search/_doc-text.d.mts +30 -0
  148. package/api/search/_doc-text.mjs +87 -0
  149. package/api/search/_entries.d.mts +63 -0
  150. package/api/search/_entries.mjs +232 -0
  151. package/api/search/_entries.test.mjs +48 -0
  152. package/api/search/_features.d.mts +35 -0
  153. package/api/search/_features.mjs +155 -0
  154. package/api/search/_gather-components.d.mts +26 -0
  155. package/api/search/_gather-components.mjs +284 -0
  156. package/api/search/_gather-docs.d.mts +20 -0
  157. package/api/search/_gather-docs.mjs +254 -0
  158. package/api/search/_gather-hooks.d.mts +12 -0
  159. package/api/search/_gather-hooks.mjs +52 -0
  160. package/api/search/_gather-templates.d.mts +25 -0
  161. package/api/search/_gather-templates.mjs +107 -0
  162. package/api/search/_lexical.d.mts +135 -0
  163. package/api/search/_lexical.mjs +351 -0
  164. package/api/search/_main-searcher.d.mts +19 -0
  165. package/api/search/_main-searcher.mjs +115 -0
  166. package/api/search/_main-searcher.test.mjs +106 -0
  167. package/api/search/_main-searcher.weights.json +1 -0
  168. package/api/search/_module-doc.d.mts +32 -0
  169. package/api/search/_module-doc.mjs +78 -0
  170. package/api/search/_order.d.mts +32 -0
  171. package/api/search/_order.mjs +162 -0
  172. package/api/search/_order.test.mjs +72 -0
  173. package/api/search/_priority.d.mts +50 -0
  174. package/api/search/_priority.mjs +139 -0
  175. package/api/search/_query-words.d.mts +25 -0
  176. package/api/search/_query-words.mjs +92 -0
  177. package/api/search/_query.d.mts +65 -0
  178. package/api/search/_query.mjs +176 -0
  179. package/api/search/_result.d.mts +97 -0
  180. package/api/search/_result.mjs +150 -0
  181. package/api/search/_score.d.mts +60 -0
  182. package/api/search/_score.mjs +283 -0
  183. package/api/search/_synonyms.d.mts +21 -0
  184. package/api/search/_synonyms.mjs +67 -0
  185. package/api/search/_template-searcher.d.mts +4 -0
  186. package/api/search/_template-searcher.mjs +23 -0
  187. package/api/search/_template-searcher.test.mjs +40 -0
  188. package/api/search/_template-searcher.weights.json +1 -0
  189. package/api/search/_titles.d.mts +33 -0
  190. package/api/search/_titles.mjs +65 -0
  191. package/api/search/_words.d.mts +64 -0
  192. package/api/search/_words.mjs +157 -0
  193. package/api/search/search.d.mts +22 -236
  194. package/api/search/search.doc.mjs +14 -7
  195. package/api/search/search.domain-priority.test.mjs +108 -18
  196. package/api/search/search.integration-check.test.mjs +24 -0
  197. package/api/search/search.mjs +59 -1904
  198. package/api/search/search.test.mjs +193 -15
  199. package/api/search/search.type.d.mts +20 -2
  200. package/api/search/search.type.mjs +12 -2
  201. package/api/search/tree.d.mts +15 -0
  202. package/api/search/tree.mjs +40 -0
  203. package/api/search/tree.test.mjs +66 -0
  204. package/api/search/tree.weights.json +1 -0
  205. package/api/swizzle/_adapter.mjs +2 -2
  206. package/api/swizzle/copy/copy.mjs +29 -15
  207. package/api/template/template-integration.test.mjs +1 -1
  208. package/api/template/template.mjs +5 -1
  209. package/api/template/template.test.mjs +120 -3
  210. package/api/theme/_adapter.d.mts +16 -0
  211. package/api/theme/_adapter.mjs +32 -5
  212. package/api/theme/build/build.d.mts +2 -1
  213. package/api/theme/build/build.family.test.mjs +64 -0
  214. package/api/theme/build/build.mjs +250 -38
  215. package/api/theme/build/build.packed-old-core.test.mjs +21 -3
  216. package/api/theme/build/font-warning.mjs +5 -3
  217. package/api/theme/build/font-warning.test.mjs +2 -1
  218. package/api/theme/remove/remove.test.mjs +2 -2
  219. package/api/theme/targets/targets.mjs +3 -10
  220. package/api/theme/themeBuild.doc.mjs +4 -4
  221. package/api/theme/themeTargets.doc.mjs +4 -0
  222. package/api/theme/use/use.test.mjs +1 -1
  223. package/api/upgrade/_adapter.d.mts +97 -11
  224. package/api/upgrade/_adapter.mjs +315 -32
  225. package/api/upgrade/registry/registry.d.mts +10 -4
  226. package/api/upgrade/registry/registry.mjs +33 -16
  227. package/api/upgrade/registry/registry.test.mjs +85 -0
  228. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  229. package/api/upgrade/run/run.d.mts +4 -2
  230. package/api/upgrade/run/run.mjs +48 -4
  231. package/api/upgrade/run/run.test.mjs +417 -3
  232. package/api/upgrade/status/status.d.mts +21 -5
  233. package/api/upgrade/status/status.mjs +45 -8
  234. package/api/upgrade/upgrade.doc.mjs +16 -8
  235. package/api/upgrade/upgrade.mjs +18 -3
  236. package/api/upgrade/upgrade.test.mjs +194 -0
  237. package/api/upgrade/upgrade.type.d.mts +28 -3
  238. package/api/upgrade/upgrade.type.mjs +24 -7
  239. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  240. package/assets/codemods/registry.mjs +1 -0
  241. package/assets/codemods/runner.mjs +7 -1
  242. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  243. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  244. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  245. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  246. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  247. package/assets/discover/official-packages.json +367 -0
  248. package/assets/docs/README.md +10 -0
  249. package/assets/docs/author-a-theme.doc.mjs +5 -5
  250. package/assets/docs/browser-support.doc.mjs +1 -1
  251. package/assets/docs/getting-started.doc.mjs +26 -6
  252. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  253. package/assets/docs/styling-overview.doc.mjs +1 -1
  254. package/assets/docs/theme.doc.dense.mjs +1 -1
  255. package/assets/docs/theme.doc.mjs +2 -2
  256. package/assets/docs/theme.doc.zh.mjs +1 -1
  257. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  258. package/assets/docs/tree/add-a-theme.doc.mjs +14 -4
  259. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  260. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  261. package/assets/docs/tree/api.doc.mjs +6 -0
  262. package/assets/docs/tree/authoring.doc.mjs +61 -0
  263. package/assets/docs/tree/block-template.doc.mjs +8 -20
  264. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  265. package/assets/docs/tree/building-blocks.doc.mjs +6 -2
  266. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  267. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  268. package/assets/docs/tree/checks.doc.mjs +32 -24
  269. package/assets/docs/tree/ci-and-containers.doc.mjs +101 -0
  270. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  271. package/assets/docs/tree/cli.doc.mjs +7 -1
  272. package/assets/docs/tree/codemods.doc.mjs +17 -7
  273. package/assets/docs/tree/commands.doc.mjs +7 -1
  274. package/assets/docs/tree/component-family.doc.mjs +8 -6
  275. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  276. package/assets/docs/tree/components.doc.mjs +7 -1
  277. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  278. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  279. package/assets/docs/tree/configuration.doc.mjs +8 -4
  280. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  281. package/assets/docs/tree/define-the-theme.doc.mjs +7 -6
  282. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  283. package/assets/docs/tree/docs.doc.mjs +9 -3
  284. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  285. package/assets/docs/tree/document-the-theme.doc.mjs +4 -4
  286. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  287. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  288. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  289. package/assets/docs/tree/fonts-and-assets.doc.mjs +3 -3
  290. package/assets/docs/tree/generate-a-palette.doc.mjs +8 -6
  291. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  292. package/assets/docs/tree/global.doc.mjs +131 -0
  293. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  294. package/assets/docs/tree/help.doc.mjs +2 -2
  295. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  296. package/assets/docs/tree/install-once.doc.mjs +105 -0
  297. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  298. package/assets/docs/tree/layout.doc.mjs +6 -6
  299. package/assets/docs/tree/links.doc.mjs +7 -6
  300. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  301. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  302. package/assets/docs/tree/migration.doc.mjs +0 -1
  303. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  304. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  305. package/assets/docs/tree/page-template.doc.mjs +4 -8
  306. package/assets/docs/tree/problems.doc.mjs +205 -0
  307. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  308. package/assets/docs/tree/publishing.doc.mjs +6 -6
  309. package/assets/docs/tree/quick-start.doc.mjs +54 -28
  310. package/assets/docs/tree/reference.doc.mjs +192 -0
  311. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  312. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  313. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  314. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  315. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  316. package/assets/docs/tree/ship.doc.mjs +2 -2
  317. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  318. package/assets/docs/tree/single-component.doc.mjs +15 -6
  319. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  320. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  321. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  322. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  323. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  324. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  325. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  326. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  327. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  328. package/assets/docs/tree/templates.doc.mjs +7 -1
  329. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  330. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  331. package/assets/docs/tree/themes.doc.mjs +5 -1
  332. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  333. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  334. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  335. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  336. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  337. package/assets/docs/tree/updates.doc.mjs +92 -0
  338. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  339. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +15 -3
  340. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  341. package/assets/docs/tree/versioning.doc.mjs +14 -9
  342. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  343. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  344. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  345. package/assets/docs/use-a-theme.doc.mjs +2 -2
  346. package/assets/docs/use-integrations.doc.mjs +120 -0
  347. package/assets/docs/working-with-ai.doc.mjs +70 -13
  348. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  349. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  350. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  351. package/assets/theme.template.ts +1 -1
  352. package/authoring/codemod/codemod.doc.mjs +7 -3
  353. package/authoring/config/config.doc.mjs +9 -6
  354. package/authoring/config/type.ts +4 -2
  355. package/authoring/debug/parse.d.mts +5 -5
  356. package/authoring/discover/discover.doc.mjs +7 -1
  357. package/authoring/doctypes/_schema.d.mts +8 -3
  358. package/authoring/doctypes/_schema.mjs +1 -0
  359. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  360. package/authoring/doctypes/command/command.doc.mjs +20 -12
  361. package/authoring/doctypes/command/type.ts +14 -0
  362. package/authoring/doctypes/component/component.doc.mjs +30 -27
  363. package/authoring/doctypes/component/type.ts +21 -8
  364. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  365. package/authoring/doctypes/function/function.doc.mjs +9 -8
  366. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  367. package/authoring/doctypes/hook/type.ts +4 -0
  368. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  369. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  370. package/authoring/doctypes/schema/schema.doc.mjs +10 -10
  371. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  372. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  373. package/authoring/doctypes/template/parse.d.mts +6 -2
  374. package/authoring/doctypes/template/parse.mjs +3 -1
  375. package/authoring/doctypes/template/template.doc.mjs +3 -3
  376. package/authoring/doctypes/template/type.ts +22 -0
  377. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  378. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  379. package/authoring/identity/identity.doc.mjs +3 -3
  380. package/authoring/index.d.ts +2 -0
  381. package/authoring/integration/integration.doc.mjs +30 -6
  382. package/authoring/integration/parse.test.mjs +21 -0
  383. package/authoring/integration/schema.d.mts +16 -3
  384. package/authoring/integration/schema.mjs +34 -2
  385. package/authoring/integration/type.ts +13 -1
  386. package/clients/cli/bin/astryx.mjs +11 -65
  387. package/clients/cli/cli-command.test.mjs +166 -0
  388. package/clients/cli/command-result-coverage.test.mjs +6 -5
  389. package/clients/cli/commands/blog.doc.mjs +1 -0
  390. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  391. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  392. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  393. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  394. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  395. package/clients/cli/commands/build.doc.mjs +1 -0
  396. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  397. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  398. package/clients/cli/commands/component.doc.mjs +1 -0
  399. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  400. package/clients/cli/commands/component.test.mjs +6 -6
  401. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  402. package/clients/cli/commands/discover.doc.mjs +9 -1
  403. package/clients/cli/commands/discover.mjs +144 -93
  404. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  405. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  406. package/clients/cli/commands/docs.doc.mjs +3 -2
  407. package/clients/cli/commands/docs.mjs +50 -20
  408. package/clients/cli/commands/docs.test.mjs +16 -16
  409. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  410. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  411. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  412. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  413. package/clients/cli/commands/doctor-integration.test.mjs +936 -3
  414. package/clients/cli/commands/doctor.doc.mjs +12 -2
  415. package/clients/cli/commands/doctor.mjs +332 -7
  416. package/clients/cli/commands/doctor.test.mjs +75 -4
  417. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  418. package/clients/cli/commands/gap-report.mjs +24 -2
  419. package/clients/cli/commands/gap-report.test.mjs +79 -0
  420. package/clients/cli/commands/hook.doc.mjs +1 -0
  421. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  422. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  423. package/clients/cli/commands/init.behavior.test.mjs +235 -1
  424. package/clients/cli/commands/init.doc.mjs +55 -10
  425. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  426. package/clients/cli/commands/init.mjs +2 -2
  427. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  428. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  429. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  430. package/clients/cli/commands/integration-check.test.mjs +489 -0
  431. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  432. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  433. package/clients/cli/commands/integration.doc.mjs +6 -2
  434. package/clients/cli/commands/integration.mjs +119 -7
  435. package/clients/cli/commands/json-contract.test.mjs +11 -2
  436. package/clients/cli/commands/manifest.doc.mjs +2 -1
  437. package/clients/cli/commands/manifest.mjs +67 -0
  438. package/clients/cli/commands/outside-project.test.mjs +874 -0
  439. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  440. package/clients/cli/commands/postinstall.mjs +31 -0
  441. package/clients/cli/commands/search.doc.mjs +1 -0
  442. package/clients/cli/commands/search.mjs +16 -11
  443. package/clients/cli/commands/search.test.mjs +429 -296
  444. package/clients/cli/commands/setup-nudge.test.mjs +180 -2
  445. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  446. package/clients/cli/commands/swizzle.mjs +5 -3
  447. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  448. package/clients/cli/commands/template.doc.mjs +1 -0
  449. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  450. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  451. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  452. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  453. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  454. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  455. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  456. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  457. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  458. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  459. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  460. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  461. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +27 -14
  462. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  463. package/clients/cli/commands/upgrade.doc.mjs +26 -3
  464. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  465. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  466. package/clients/cli/commands/upgrade.mjs +9 -2
  467. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  468. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  469. package/clients/cli/index.mjs +156 -100
  470. package/clients/cli/lib/cli-error.mjs +4 -1
  471. package/clients/cli/lib/component-format.mjs +1 -1
  472. package/clients/cli/lib/component-format.test.mjs +1 -1
  473. package/clients/cli/lib/define-command.mjs +14 -9
  474. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  475. package/clients/cli/lib/json-shim.mjs +3 -1
  476. package/clients/cli/lib/manifest.d.ts +9 -0
  477. package/clients/cli/lib/manifest.mjs +17 -1
  478. package/clients/cli/lib/manifest.test.mjs +37 -0
  479. package/clients/cli/lib/welcome-box.mjs +50 -0
  480. package/clients/cli/run.mjs +108 -0
  481. package/foundation/agent-docs/agent-doc-state.d.mts +67 -13
  482. package/foundation/agent-docs/agent-doc-state.mjs +123 -14
  483. package/foundation/agent-docs/agent-docs.d.mts +104 -15
  484. package/foundation/agent-docs/agent-docs.mjs +1028 -114
  485. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  486. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  487. package/foundation/agent-docs/computer-agent-text.d.mts +170 -0
  488. package/foundation/agent-docs/computer-agent-text.mjs +750 -0
  489. package/foundation/agent-docs/computer-agent-text.test.mjs +699 -0
  490. package/foundation/config/project.d.mts +35 -3
  491. package/foundation/config/project.mjs +243 -26
  492. package/foundation/config/project.test.mjs +122 -0
  493. package/foundation/config/theme-state.mjs +5 -4
  494. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  495. package/foundation/discovery/authoring-self-docs.mjs +17 -4
  496. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  497. package/foundation/discovery/authoring-surface.d.mts +1 -1
  498. package/foundation/discovery/authoring-surface.mjs +2 -2
  499. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  500. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  501. package/foundation/discovery/cli-self-docs.mjs +22 -4
  502. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  503. package/foundation/discovery/component-discovery.d.mts +227 -10
  504. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  505. package/foundation/discovery/component-discovery.mjs +940 -57
  506. package/foundation/discovery/component-discovery.test.mjs +96 -0
  507. package/foundation/discovery/component-loader.d.mts +1 -1
  508. package/foundation/discovery/component-replacement.mjs +20 -1
  509. package/foundation/discovery/component-replacement.test.mjs +40 -0
  510. package/foundation/discovery/copied-passages.d.mts +216 -0
  511. package/foundation/discovery/copied-passages.mjs +720 -0
  512. package/foundation/discovery/copied-passages.test.mjs +124 -0
  513. package/foundation/discovery/doc-consistency.d.mts +34 -0
  514. package/foundation/discovery/doc-consistency.mjs +513 -0
  515. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  516. package/foundation/discovery/doc-fluff.d.mts +112 -0
  517. package/foundation/discovery/doc-fluff.mjs +328 -0
  518. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  519. package/foundation/discovery/doc-types.d.mts +157 -0
  520. package/foundation/discovery/doc-types.mjs +1231 -0
  521. package/foundation/discovery/doc-types.test.mjs +744 -0
  522. package/foundation/discovery/docs-discovery.d.mts +88 -0
  523. package/foundation/discovery/docs-discovery.mjs +97 -3
  524. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  525. package/foundation/discovery/integration-doc-files.mjs +231 -0
  526. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  527. package/foundation/discovery/module-exports.d.mts +68 -0
  528. package/foundation/discovery/module-exports.mjs +609 -31
  529. package/foundation/discovery/module-exports.test.mjs +172 -0
  530. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  531. package/foundation/discovery/package-tsconfig.mjs +228 -0
  532. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  533. package/foundation/discovery/project-typescript.d.mts +32 -0
  534. package/foundation/discovery/project-typescript.mjs +89 -0
  535. package/foundation/discovery/prop-drift.d.mts +297 -0
  536. package/foundation/discovery/prop-drift.mjs +2428 -0
  537. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  538. package/foundation/discovery/runner-allowlist.d.mts +38 -0
  539. package/foundation/discovery/runner-allowlist.mjs +51 -0
  540. package/foundation/discovery/runner-commands.d.mts +77 -0
  541. package/foundation/discovery/runner-commands.mjs +294 -0
  542. package/foundation/discovery/runner-commands.test.mjs +128 -0
  543. package/foundation/discovery/stray-pointers.d.mts +52 -0
  544. package/foundation/discovery/stray-pointers.mjs +293 -0
  545. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  546. package/foundation/discovery/template-adapter.mjs +92 -6
  547. package/foundation/discovery/template-needs.mjs +6 -46
  548. package/foundation/discovery/theme-discovery.mjs +147 -3
  549. package/foundation/discovery/theme-imports.mjs +8 -4
  550. package/foundation/discovery/theme-imports.test.mjs +1 -1
  551. package/foundation/discovery/type-match.d.mts +53 -0
  552. package/foundation/discovery/type-match.mjs +660 -0
  553. package/foundation/discovery/type-match.test.mjs +169 -0
  554. package/foundation/discovery/type-text.d.mts +68 -0
  555. package/foundation/discovery/type-text.mjs +658 -0
  556. package/foundation/discovery/type-text.test.mjs +196 -0
  557. package/foundation/discovery/unresolved-references.d.mts +62 -0
  558. package/foundation/discovery/unresolved-references.mjs +790 -0
  559. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  560. package/foundation/doc-compiler/doc-loads.test.mjs +84 -10
  561. package/foundation/doc-compiler/inputs.mjs +27 -1
  562. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  563. package/foundation/doc-compiler/links.d.mts +41 -5
  564. package/foundation/doc-compiler/links.mjs +167 -28
  565. package/foundation/doc-compiler/links.test.mjs +97 -4
  566. package/foundation/doc-compiler/read.d.mts +1 -1
  567. package/foundation/doc-compiler/read.mjs +59 -1
  568. package/foundation/doc-compiler/read.test.mjs +11 -2
  569. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  570. package/foundation/doc-compiler/tree.d.mts +32 -6
  571. package/foundation/doc-compiler/tree.mjs +107 -44
  572. package/foundation/doc-compiler/tree.test.mjs +14 -7
  573. package/foundation/env/cli-command.d.mts +83 -0
  574. package/foundation/env/cli-command.mjs +152 -0
  575. package/foundation/env/cli-command.test.mjs +129 -0
  576. package/foundation/env/node-version.test.mjs +15 -3
  577. package/foundation/env/package-manager.d.mts +93 -9
  578. package/foundation/env/package-manager.global.test.mjs +66 -0
  579. package/foundation/env/package-manager.mjs +184 -13
  580. package/foundation/env/package-manager.test.mjs +341 -15
  581. package/foundation/env/project-scope.d.mts +9 -0
  582. package/foundation/env/project-scope.mjs +33 -0
  583. package/foundation/env/search-path.d.mts +42 -0
  584. package/foundation/env/search-path.mjs +205 -0
  585. package/foundation/env/search-path.test.mjs +122 -0
  586. package/foundation/env/user-dirs.d.mts +39 -0
  587. package/foundation/env/user-dirs.mjs +93 -0
  588. package/foundation/env/user-dirs.test.mjs +72 -0
  589. package/foundation/env/user-settings.d.mts +46 -0
  590. package/foundation/env/user-settings.mjs +106 -0
  591. package/foundation/env/user-settings.test.mjs +64 -0
  592. package/foundation/fs/file-protection.mjs +15 -1
  593. package/foundation/fs/module-loader.d.mts +2 -1
  594. package/foundation/fs/module-loader.mjs +60 -4
  595. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  596. package/foundation/fs/module-loader.test.mjs +194 -0
  597. package/foundation/fs/path-compare.d.mts +33 -0
  598. package/foundation/fs/path-compare.mjs +73 -0
  599. package/foundation/fs/paths.d.mts +122 -4
  600. package/foundation/fs/paths.mjs +675 -29
  601. package/foundation/fs/paths.test.mjs +439 -54
  602. package/foundation/fs/read-record.d.mts +18 -0
  603. package/foundation/fs/read-record.mjs +131 -0
  604. package/foundation/fs/read-record.test.mjs +77 -0
  605. package/foundation/integrations/autolink.d.mts +2 -1
  606. package/foundation/integrations/autolink.mjs +4 -13
  607. package/foundation/integrations/cli-peer-version.d.mts +36 -0
  608. package/foundation/integrations/cli-peer-version.mjs +132 -0
  609. package/foundation/integrations/cli-peer-version.test.mjs +354 -0
  610. package/foundation/integrations/computer-integrations.d.mts +81 -0
  611. package/foundation/integrations/computer-integrations.mjs +345 -0
  612. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  613. package/foundation/integrations/contribution-inventory.d.mts +26 -20
  614. package/foundation/integrations/contribution-inventory.mjs +97 -8
  615. package/foundation/integrations/exports-subpaths.d.mts +57 -0
  616. package/foundation/integrations/exports-subpaths.mjs +113 -0
  617. package/foundation/integrations/integration-warnings.mjs +3 -2
  618. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  619. package/foundation/integrations/integrations.d.mts +51 -1
  620. package/foundation/integrations/integrations.mjs +106 -4
  621. package/foundation/integrations/issue.ts +6 -0
  622. package/foundation/integrations/public-imports.d.mts +118 -0
  623. package/foundation/integrations/public-imports.mjs +1769 -0
  624. package/foundation/integrations/public-imports.test.mjs +1793 -0
  625. package/foundation/integrations/validate-contributions.d.mts +117 -0
  626. package/foundation/integrations/validate-contributions.mjs +1209 -14
  627. package/foundation/release/agent-text-worker.d.mts +4 -0
  628. package/foundation/release/agent-text-worker.mjs +52 -0
  629. package/foundation/release/cache.d.mts +310 -0
  630. package/foundation/release/cache.mjs +1216 -0
  631. package/foundation/release/cache.test.mjs +923 -0
  632. package/foundation/release/choose.d.mts +207 -0
  633. package/foundation/release/choose.mjs +677 -0
  634. package/foundation/release/choose.test.mjs +427 -0
  635. package/foundation/release/core-worker.d.mts +4 -0
  636. package/foundation/release/core-worker.mjs +38 -0
  637. package/foundation/release/global-state.d.mts +263 -0
  638. package/foundation/release/global-state.mjs +474 -0
  639. package/foundation/release/global-state.test.mjs +381 -0
  640. package/foundation/release/handoff.d.mts +79 -0
  641. package/foundation/release/handoff.e2e.test.mjs +278 -0
  642. package/foundation/release/handoff.mjs +524 -0
  643. package/foundation/release/lock-lease.d.mts +23 -0
  644. package/foundation/release/lock-lease.mjs +80 -0
  645. package/foundation/release/notices.d.mts +307 -0
  646. package/foundation/release/notices.mjs +707 -0
  647. package/foundation/release/notices.test.mjs +586 -0
  648. package/foundation/release/npm-guard.d.mts +4 -0
  649. package/foundation/release/npm-guard.mjs +126 -0
  650. package/foundation/release/project.d.mts +141 -0
  651. package/foundation/release/project.mjs +466 -0
  652. package/foundation/release/project.test.mjs +288 -0
  653. package/foundation/release/refresh-worker.d.mts +4 -0
  654. package/foundation/release/refresh-worker.mjs +27 -0
  655. package/foundation/release/run-context.d.mts +47 -0
  656. package/foundation/release/run-context.mjs +163 -0
  657. package/foundation/release/update-notice-env.d.mts +28 -0
  658. package/foundation/release/update-notice-env.mjs +39 -0
  659. package/foundation/response/base.d.ts +26 -3
  660. package/foundation/response/error-codes.d.mts +3 -1
  661. package/foundation/response/error-codes.doc.mjs +12 -0
  662. package/foundation/response/error-codes.mjs +17 -0
  663. package/foundation/response/error-codes.test.mjs +2 -0
  664. package/foundation/response/json-contract.test.mjs +7 -2
  665. package/foundation/response/json.mjs +4 -1
  666. package/foundation/response/response-types.doc.mjs +22 -11
  667. package/foundation/response/response-types.doc.test.mjs +46 -0
  668. package/foundation/response/response.doc.mjs +3 -3
  669. package/foundation/route/route.d.mts +285 -0
  670. package/foundation/route/route.mjs +324 -0
  671. package/foundation/route/route.test.mjs +153 -0
  672. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  673. package/foundation/runtime/locked-versions.d.mts +32 -0
  674. package/foundation/runtime/locked-versions.mjs +65 -0
  675. package/foundation/runtime/package-root.d.mts +91 -0
  676. package/foundation/runtime/package-root.mjs +174 -0
  677. package/foundation/runtime/package-set.d.mts +62 -0
  678. package/foundation/runtime/package-set.mjs +130 -0
  679. package/foundation/runtime/package-set.test.mjs +432 -0
  680. package/foundation/text/string-utils.d.mts +2 -1
  681. package/foundation/text/string-utils.mjs +16 -5
  682. package/foundation/text/suggest-order.d.mts +72 -0
  683. package/foundation/text/suggest-order.mjs +363 -0
  684. package/foundation/text/suggest-order.test.mjs +259 -0
  685. package/foundation/xle/browser-imports.test.mjs +74 -0
  686. package/foundation/xle/registry.mjs +4 -0
  687. package/foundation/xle/registry.test.mjs +28 -0
  688. package/host/door-conformance.test.mjs +274 -0
  689. package/host/index.d.ts +116 -0
  690. package/host/index.mjs +295 -0
  691. package/host/index.test.mjs +302 -0
  692. package/package.json +16 -11
  693. package/scripts/postinstall.mjs +24 -5
  694. package/assets/docs/tree/integrations.doc.mjs +0 -40
@@ -24,9 +24,13 @@ import * as path from 'node:path';
24
24
  import * as os from 'node:os';
25
25
  import {fileURLToPath} from 'node:url';
26
26
  import {spawnSync} from 'node:child_process';
27
- import jscodeshift from 'jscodeshift';
28
27
  import {assertWithin} from '../../foundation/fs/path-safety.mjs';
29
28
  import {resolvePackageDir} from '../../foundation/integrations/integrations.mjs';
29
+ import {
30
+ literalThemeName,
31
+ rootProblem,
32
+ symlinkedFolder,
33
+ } from '../../foundation/integrations/validate-contributions.mjs';
30
34
  import {
31
35
  componentReplacesCliProblem,
32
36
  docsTreeCliProblem,
@@ -41,6 +45,8 @@ import {
41
45
  } from '../../foundation/discovery/docs-discovery.mjs';
42
46
  import {discoverIntegrationThemes} from '../../foundation/discovery/theme-discovery.mjs';
43
47
  import {inspectPackageExport} from '../../foundation/discovery/package-exports.mjs';
48
+ import {parse as parseModule} from '@babel/parser';
49
+ import {moduleExportsName} from '../../foundation/discovery/module-exports.mjs';
44
50
  import {
45
51
  ThemeImportError,
46
52
  resolveThemeImports,
@@ -51,6 +57,9 @@ import {
51
57
  } from '../theme/build/build.mjs';
52
58
  import {
53
59
  discoverIntegrationComponents,
60
+ docStem,
61
+ familyImports,
62
+ isIntegrationMember,
54
63
  resolveIntegrationImportPath,
55
64
  } from '../../foundation/discovery/component-discovery.mjs';
56
65
  import {loadComponentReplacements} from '../component/_adapter.mjs';
@@ -65,6 +74,7 @@ import {
65
74
  collectIdentities,
66
75
  compareIdentities,
67
76
  } from '../../foundation/integrations/contribution-inventory.mjs';
77
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
68
78
 
69
79
  /**
70
80
  * @typedef {import('../../foundation/integrations/issue').AstryxIntegrationIssue} Issue
@@ -307,98 +317,6 @@ function extractTarball(tgzPath, extractDir) {
307
317
  }
308
318
  }
309
319
 
310
- const MODULE_EXTENSIONS = ['.mjs', '.js', '.mts', '.ts', '.tsx', '.jsx'];
311
- const moduleParser = jscodeshift.withParser('tsx');
312
-
313
- /** @param {unknown} specifier @param {string} fromFile */
314
- function resolveLocalModule(specifier, fromFile) {
315
- if (typeof specifier !== 'string' || !specifier.startsWith('.')) return null;
316
- const base = path.resolve(path.dirname(fromFile), specifier);
317
- const candidates = [
318
- base,
319
- ...MODULE_EXTENSIONS.map(extension => `${base}${extension}`),
320
- ...MODULE_EXTENSIONS.map(extension => path.join(base, `index${extension}`)),
321
- ];
322
- return candidates.find(candidate => fs.existsSync(candidate)) ?? null;
323
- }
324
-
325
- /** @param {any} declaration @param {string} exportName */
326
- function declarationExports(declaration, exportName) {
327
- if (!declaration) return false;
328
- if (['FunctionDeclaration', 'ClassDeclaration'].includes(declaration.type)) {
329
- return declaration.id?.name === exportName;
330
- }
331
- if (declaration.type !== 'VariableDeclaration') return false;
332
- return declaration.declarations.some(
333
- (/** @type {any} */ item) =>
334
- item.id?.type === 'Identifier' && item.id.name === exportName,
335
- );
336
- }
337
-
338
- /**
339
- * Check one resolved module's static export surface without executing package
340
- * code. Local ESM re-exports are followed recursively.
341
- *
342
- * @param {string} file
343
- * @param {string} exportName
344
- * @param {Set<string>} [seen]
345
- */
346
- function moduleExportsName(file, exportName, seen = new Set()) {
347
- const identity = `${file}\0${exportName}`;
348
- if (seen.has(identity) || !fs.existsSync(file)) return false;
349
- seen.add(identity);
350
-
351
- let root;
352
- try {
353
- root = moduleParser(fs.readFileSync(file, 'utf-8'));
354
- } catch {
355
- return false;
356
- }
357
-
358
- let found = false;
359
- root
360
- .find(moduleParser.ExportNamedDeclaration)
361
- .forEach((/** @type {any} */ exportPath) => {
362
- if (found) return;
363
- const node = exportPath.node;
364
- if (declarationExports(node.declaration, exportName)) {
365
- found = true;
366
- return;
367
- }
368
- for (const specifier of node.specifiers ?? []) {
369
- const exported = specifier.exported?.name ?? specifier.exported?.value;
370
- if (exported !== exportName) continue;
371
- if (!node.source) {
372
- found = true;
373
- return;
374
- }
375
- const target = resolveLocalModule(node.source.value, file);
376
- const imported =
377
- specifier.local?.name ?? specifier.local?.value ?? exportName;
378
- if (target && moduleExportsName(target, imported, seen)) {
379
- found = true;
380
- return;
381
- }
382
- }
383
- });
384
- if (found) return true;
385
- if (
386
- exportName === 'default' &&
387
- root.find(moduleParser.ExportDefaultDeclaration).size() > 0
388
- ) {
389
- return true;
390
- }
391
-
392
- root
393
- .find(moduleParser.ExportAllDeclaration)
394
- .forEach((/** @type {any} */ exportPath) => {
395
- if (found) return;
396
- const target = resolveLocalModule(exportPath.node.source?.value, file);
397
- if (target && moduleExportsName(target, exportName, seen)) found = true;
398
- });
399
- return found;
400
- }
401
-
402
320
  /**
403
321
  * Whether any of these doc files has a section that sets `id`.
404
322
  * @param {string[]} files
@@ -472,15 +390,20 @@ async function validatePackedComponentExports(integration, scratchBase) {
472
390
  const issues = [];
473
391
  /** @type {Array<{name: string, specifier: string}>} */
474
392
  const components = [];
393
+ // A family doc backs several records: load it, and report it, once.
394
+ const loads = new Map();
475
395
  for (const record of records) {
396
+ const first = !loads.has(record.docPath);
397
+ if (first) loads.set(record.docPath, loadComponentDoc(record.docPath));
476
398
  let docs;
477
399
  try {
478
- docs = await loadComponentDoc(record.docPath);
400
+ docs = await loads.get(record.docPath);
479
401
  } catch (err) {
402
+ if (!first) continue;
480
403
  issues.push(
481
404
  error(
482
405
  'component_doc_unloadable',
483
- `Component "${record.name}" doc at "${record.docPath}" could not be loaded: ${err instanceof Error ? err.message : String(err)}`,
406
+ `Component "${docStem(record.docPath)}" doc at "${record.docPath}" could not be loaded: ${err instanceof Error ? err.message : String(err)}`,
484
407
  ),
485
408
  );
486
409
  continue;
@@ -658,16 +581,22 @@ async function validateIncompleteThemeExports(
658
581
  path.join(os.tmpdir(), `astryx-theme-${localTheme.slug}-`),
659
582
  );
660
583
  const expectedCss = path.join(expectedDir, `${localTheme.slug}.css`);
584
+ let expectedModule = path.join(expectedDir, `${localTheme.slug}.js`);
661
585
  try {
662
586
  if (outputs.some(output => output.kind !== 'font stylesheet')) {
663
- const receipt = await themeBuild(
664
- source,
665
- {out: expectedCss},
666
- {cwd: packageDir},
667
- );
587
+ // The scratch directory is the write root; the package stays the cwd,
588
+ // so the build selects the package's Core and its paths as before.
589
+ const scratchBuild = {out: expectedCss, __writeRoot: expectedDir};
590
+ const receipt = await themeBuild(source, scratchBuild, {cwd: packageDir});
668
591
  if (receipt == null || receipt.type !== 'theme.build') {
669
592
  throw new Error('the theme build produced no complete receipt');
670
593
  }
594
+ expectedModule = builtModuleFile(
595
+ receipt,
596
+ packageDir,
597
+ expectedDir,
598
+ localTheme.slug,
599
+ );
671
600
  }
672
601
  for (const output of outputs) {
673
602
  const localFile = /** @type {string} */ (output.inspected.target);
@@ -684,9 +613,7 @@ async function validateIncompleteThemeExports(
684
613
  continue;
685
614
  }
686
615
  const expectedFile =
687
- output.kind === 'module'
688
- ? path.join(expectedDir, `${localTheme.slug}.js`)
689
- : expectedCss;
616
+ output.kind === 'module' ? expectedModule : expectedCss;
690
617
  const expected = normalizeThemeVerifyForCompare(
691
618
  fs.readFileSync(expectedFile, 'utf-8'),
692
619
  );
@@ -702,7 +629,7 @@ async function validateIncompleteThemeExports(
702
629
  output.kind === 'module'
703
630
  ? 'theme_module_stale'
704
631
  : 'theme_stylesheet_stale',
705
- `Theme "${localTheme.slug}" ${output.kind} does not match ${sourceRelative}. This incomplete export remains packable, but run \`astryx theme build ${sourceRelative}\` before adding its matching export.`,
632
+ `Theme "${localTheme.slug}" ${output.kind} does not match ${sourceRelative}. This incomplete export remains packable, but run \`${formatCliCommand(`theme build ${sourceRelative}`, packageDir)}\` before adding its matching export.`,
706
633
  ),
707
634
  );
708
635
  }
@@ -721,7 +648,7 @@ async function validateIncompleteThemeExports(
721
648
  issues.push(
722
649
  error(
723
650
  'theme_build_failed',
724
- `Theme "${localTheme.slug}" could not be rebuilt from ${sourceRelative}: ${err instanceof Error ? err.message : String(err)} Run \`astryx theme build ${sourceRelative}\` before packing.`,
651
+ `Theme "${localTheme.slug}" could not be rebuilt from ${sourceRelative}: ${err instanceof Error ? err.message : String(err)} Run \`${formatCliCommand(`theme build ${sourceRelative}`, packageDir)}\` before packing.`,
725
652
  ),
726
653
  );
727
654
  } finally {
@@ -730,6 +657,250 @@ async function validateIncompleteThemeExports(
730
657
  return issues;
731
658
  }
732
659
 
660
+ /**
661
+ * The module a scratch `theme build` wrote. Its file is named by the theme's
662
+ * own name, which can differ from the slug the package exports it under. A
663
+ * receipt that names no file inside the scratch directory falls back to the
664
+ * slug.
665
+ * @param {any} receipt
666
+ * @param {string} cwd the directory the build ran in
667
+ * @param {string} expectedDir
668
+ * @param {string} slug
669
+ * @returns {string}
670
+ */
671
+ function builtModuleFile(receipt, cwd, expectedDir, slug) {
672
+ const written = receipt?.data?.outputs?.js;
673
+ if (typeof written === 'string') {
674
+ const file = path.resolve(cwd, written);
675
+ const relative = path.relative(expectedDir, file);
676
+ if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
677
+ return file;
678
+ }
679
+ }
680
+ return path.join(expectedDir, `${slug}.js`);
681
+ }
682
+
683
+ /**
684
+ * The `.js` file a relative module specifier names from `fromFile`, the
685
+ * extension `theme build` gives the built module: the exact path, the path
686
+ * with `.js`, or its `index.js`.
687
+ * @param {string} specifier
688
+ * @param {string} fromFile
689
+ * @returns {string | null}
690
+ */
691
+ function resolveRelativeJsModule(specifier, fromFile) {
692
+ if (!specifier.startsWith('./') && !specifier.startsWith('../')) return null;
693
+ const base = path.resolve(path.dirname(fromFile), specifier);
694
+ const candidates = [base, `${base}.js`, path.join(base, 'index.js')];
695
+ return (
696
+ candidates.find(candidate => {
697
+ try {
698
+ return candidate.endsWith('.js') && fs.statSync(candidate).isFile();
699
+ } catch {
700
+ return false;
701
+ }
702
+ }) ?? null
703
+ );
704
+ }
705
+
706
+ /** @param {string} file */
707
+ function realFile(file) {
708
+ try {
709
+ return fs.realpathSync(file);
710
+ } catch {
711
+ return null;
712
+ }
713
+ }
714
+
715
+ /**
716
+ * The file a stylesheet import names: a relative path from the module, or a
717
+ * subpath of the package itself, resolved through its own exports.
718
+ * @param {string} specifier
719
+ * @param {string} moduleFile
720
+ * @param {{name?: string}} pkg
721
+ * @param {string} packageDir
722
+ * @returns {string | null}
723
+ */
724
+ function resolveStylesheetImport(specifier, moduleFile, pkg, packageDir) {
725
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
726
+ const file = path.resolve(path.dirname(moduleFile), specifier);
727
+ try {
728
+ return fs.statSync(file).isFile() ? realFile(file) : null;
729
+ } catch {
730
+ return null;
731
+ }
732
+ }
733
+ if (typeof pkg.name !== 'string' || !specifier.startsWith(`${pkg.name}/`)) {
734
+ return null;
735
+ }
736
+ const exported = inspectPackageExport(
737
+ pkg,
738
+ packageDir,
739
+ `.${specifier.slice(pkg.name.length)}`,
740
+ );
741
+ return exported.exported && exported.target
742
+ ? realFile(exported.target)
743
+ : null;
744
+ }
745
+
746
+ /**
747
+ * The theme binding of a built module: the name of its `export const`.
748
+ * @param {string} file
749
+ * @returns {string | null}
750
+ */
751
+ function builtThemeBinding(file) {
752
+ try {
753
+ const ast = parseModule(fs.readFileSync(file, 'utf-8'), {
754
+ sourceType: 'module',
755
+ plugins: ['importAttributes'],
756
+ });
757
+ for (const node of ast.program.body) {
758
+ if (
759
+ node.type === 'ExportNamedDeclaration' &&
760
+ node.declaration?.type === 'VariableDeclaration'
761
+ ) {
762
+ const id = node.declaration.declarations[0]?.id;
763
+ return id?.type === 'Identifier' ? id.name : null;
764
+ }
765
+ }
766
+ } catch {
767
+ // An unreadable module has no binding to match.
768
+ }
769
+ return null;
770
+ }
771
+
772
+ /** @param {any} node */
773
+ function exportedName(node) {
774
+ return node?.name ?? node?.value;
775
+ }
776
+
777
+ /**
778
+ * Check a `.js` or `.mjs` theme module that is not the built module itself.
779
+ * It is accepted when it only loads the theme's own styles and re-exports the
780
+ * built module: each statement imports the theme's exported stylesheet or font
781
+ * stylesheet for its side effects, except one, which re-exports from a `.js`
782
+ * file that matches the built module either everything or only its theme,
783
+ * under the theme's export name. Returns null for any other file and for a module that
784
+ * re-exports nothing, and otherwise whether it is accepted. A
785
+ * rejection gives the reason, or, when only the re-exported module is stale,
786
+ * that module's specifier with `rebuild` set.
787
+ *
788
+ * @param {string} moduleFile
789
+ * @param {string} expected the built module, normalized for comparison
790
+ * @param {{exportName: string, stylesheetFile: string, fontStylesheetFile?: string, pkg: {name?: string}, packageDir: string}} theme
791
+ * @returns {{ok: true} | {ok: false, reason: string, rebuild: boolean} | null}
792
+ */
793
+ function ownStylesEntry(moduleFile, expected, theme) {
794
+ if (!/\.m?js$/u.test(moduleFile)) return null;
795
+ let ast;
796
+ try {
797
+ ast = parseModule(fs.readFileSync(moduleFile, 'utf-8'), {
798
+ sourceType: 'module',
799
+ plugins: ['importAttributes'],
800
+ });
801
+ } catch {
802
+ return null;
803
+ }
804
+ const body = ast.program.body;
805
+ const reexports = body.filter(
806
+ (/** @type {any} */ node) =>
807
+ node.type === 'ExportAllDeclaration' ||
808
+ (node.type === 'ExportNamedDeclaration' && node.source != null),
809
+ );
810
+ if (reexports.length === 0) return null;
811
+ /** @param {string} reason @param {boolean} [rebuild] */
812
+ const reject = (reason, rebuild = false) => ({
813
+ ok: /** @type {const} */ (false),
814
+ reason,
815
+ rebuild,
816
+ });
817
+ if (reexports.length > 1) return reject('it has more than one re-export');
818
+ if ((ast.program.directives ?? []).length > 0) {
819
+ return reject('it has a directive');
820
+ }
821
+ const ownStylesheets = new Set(
822
+ [theme.stylesheetFile, theme.fontStylesheetFile]
823
+ .filter(file => file != null)
824
+ .map(file => realFile(/** @type {string} */ (file))),
825
+ );
826
+ const imported = new Set();
827
+ for (const node of body) {
828
+ if (node === reexports[0]) continue;
829
+ const line = node.loc?.start.line;
830
+ if (node.type !== 'ImportDeclaration') {
831
+ return reject(
832
+ `line ${line} is neither a stylesheet import nor the re-export`,
833
+ );
834
+ }
835
+ const specifier = node.source.value;
836
+ if (
837
+ node.importKind === 'type' ||
838
+ node.specifiers.length > 0 ||
839
+ (node.attributes ?? []).length > 0 ||
840
+ node.phase != null
841
+ ) {
842
+ return reject(`its import of ${specifier} is not a side-effect import`);
843
+ }
844
+ const file = resolveStylesheetImport(
845
+ specifier,
846
+ moduleFile,
847
+ theme.pkg,
848
+ theme.packageDir,
849
+ );
850
+ if (!file || !ownStylesheets.has(file)) {
851
+ return reject(
852
+ `${specifier} is not the theme's own stylesheet or font stylesheet`,
853
+ );
854
+ }
855
+ if (imported.has(file)) return reject(`it imports ${specifier} twice`);
856
+ imported.add(file);
857
+ }
858
+ const reexport = /** @type {any} */ (reexports[0]);
859
+ const from = reexport.source.value;
860
+ /** @type {string | null} */
861
+ let reexported = null;
862
+ if (
863
+ reexport.exportKind === 'type' ||
864
+ (reexport.attributes ?? []).length > 0
865
+ ) {
866
+ return reject(`its re-export from ${from} is not a plain re-export`);
867
+ }
868
+ if (reexport.type === 'ExportAllDeclaration') {
869
+ if (reexport.exported != null) {
870
+ return reject(`it re-exports ${from} as a namespace`);
871
+ }
872
+ } else {
873
+ const specifiers = reexport.specifiers ?? [];
874
+ if (
875
+ specifiers.length !== 1 ||
876
+ specifiers[0].type !== 'ExportSpecifier' ||
877
+ specifiers[0].exportKind === 'type' ||
878
+ exportedName(specifiers[0].exported) !== theme.exportName
879
+ ) {
880
+ return reject(`it re-exports names other than ${theme.exportName}`);
881
+ }
882
+ reexported = exportedName(specifiers[0].local);
883
+ }
884
+ const target = resolveRelativeJsModule(from, moduleFile);
885
+ if (!target) {
886
+ return reject(`its re-export from ${from} does not name a .js module`);
887
+ }
888
+ if (
889
+ normalizeThemeVerifyForCompare(fs.readFileSync(target, 'utf-8')) !==
890
+ expected
891
+ ) {
892
+ return reject(from, true);
893
+ }
894
+ // `theme build` names the theme's export after the theme's own name, which
895
+ // can differ from its slug, so a named re-export may give that export the
896
+ // slug's export name. It must be the theme, not another export of the built
897
+ // module, such as its icon registry.
898
+ if (reexported != null && reexported !== builtThemeBinding(target)) {
899
+ return reject(`it re-exports ${reexported}, which is not the built theme`);
900
+ }
901
+ return {ok: /** @type {const} */ (true)};
902
+ }
903
+
733
904
  /**
734
905
  * Prove local theme exports are fresh, prove the same exports resolve from the
735
906
  * tarball, and reject lifecycle changes to source or built output bytes.
@@ -787,6 +958,10 @@ async function validatePackedThemeExports(
787
958
  );
788
959
  }
789
960
 
961
+ // The name the source gives defineTheme, when the file says it: the
962
+ // build names its files after it.
963
+ const builtName = literalThemeName(source, localTheme.exportName);
964
+
790
965
  const declaredOutputs = declaredThemeBuildOutputs(
791
966
  localIntegration,
792
967
  localTheme,
@@ -796,7 +971,7 @@ async function validatePackedThemeExports(
796
971
  issues.push(
797
972
  warning(
798
973
  'theme_exports_missing',
799
- `Theme "${localTheme.slug}" has no declared built exports. The package remains source-compatible. To make it importable, run \`astryx theme build ${sourceRelative}\` and export "./themes/${localTheme.slug}" plus "./themes/${localTheme.slug}.css" from package.json; \`astryx integration add theme ${localTheme.slug}\` creates those exports for a new theme.`,
974
+ `Theme "${localTheme.slug}" has no declared built exports. The package remains source-compatible. To make it importable, run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` and export "./themes/${localTheme.slug}" plus "./themes/${localTheme.slug}.css" from package.json; \`${formatCliCommand(`integration add theme ${localTheme.slug}`, localIntegration.__packageDir)}\` creates those exports for a new theme.`,
800
975
  ),
801
976
  );
802
977
  continue;
@@ -836,7 +1011,7 @@ async function validatePackedThemeExports(
836
1011
  err instanceof ThemeImportError
837
1012
  ? 'theme_import_unresolvable'
838
1013
  : 'theme_import_invalid',
839
- `${message} Run \`astryx theme build ${sourceRelative}\` before packing.`,
1014
+ `${message} Run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` before packing.`,
840
1015
  ),
841
1016
  );
842
1017
  continue;
@@ -847,21 +1022,27 @@ async function validatePackedThemeExports(
847
1022
  );
848
1023
  const expectedCss = path.join(expectedDir, `${localTheme.slug}.css`);
849
1024
  try {
850
- const receipt = await themeBuild(
851
- source,
852
- {out: expectedCss},
853
- {cwd: localIntegration.__packageDir},
854
- );
1025
+ // The scratch directory is the write root; the package stays the cwd,
1026
+ // so the build selects the package's Core and its paths as before.
1027
+ const scratchBuild = {out: expectedCss, __writeRoot: expectedDir};
1028
+ const receipt = await themeBuild(source, scratchBuild, {
1029
+ cwd: localIntegration.__packageDir,
1030
+ });
855
1031
  if (receipt == null || receipt.type !== 'theme.build') {
856
1032
  issues.push(
857
1033
  error(
858
1034
  'theme_build_failed',
859
- `Theme "${localTheme.slug}" did not produce a complete build. Run \`astryx theme build ${sourceRelative}\` before packing.`,
1035
+ `Theme "${localTheme.slug}" did not produce a complete build. Run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` before packing.`,
860
1036
  ),
861
1037
  );
862
1038
  continue;
863
1039
  }
864
- const expectedModule = path.join(expectedDir, `${localTheme.slug}.js`);
1040
+ const expectedModule = builtModuleFile(
1041
+ receipt,
1042
+ localIntegration.__packageDir,
1043
+ expectedDir,
1044
+ localTheme.slug,
1045
+ );
865
1046
  /** @type {Array<{kind: string, expected: string, local: string, packed: string, staleCode: string, packedCode: string}>} */
866
1047
  const buildOutputs = [
867
1048
  {
@@ -881,6 +1062,20 @@ async function validatePackedThemeExports(
881
1062
  packedCode: 'packed_theme_stylesheet_changed',
882
1063
  },
883
1064
  ];
1065
+ const localEntry = {
1066
+ exportName: localTheme.exportName,
1067
+ stylesheetFile: localImports.stylesheetFile,
1068
+ fontStylesheetFile: localImports.fontStylesheetFile,
1069
+ pkg: integrationPackageMetadata(localIntegration),
1070
+ packageDir: localIntegration.__packageDir,
1071
+ };
1072
+ const packedEntry = {
1073
+ exportName: packedTheme.exportName,
1074
+ stylesheetFile: packedImports.stylesheetFile,
1075
+ fontStylesheetFile: packedImports.fontStylesheetFile,
1076
+ pkg: integrationPackageMetadata(packedIntegration),
1077
+ packageDir: packedIntegration.__packageDir,
1078
+ };
884
1079
  for (const output of buildOutputs) {
885
1080
  const expected = normalizeThemeVerifyForCompare(
886
1081
  fs.readFileSync(output.expected, 'utf-8'),
@@ -891,15 +1086,39 @@ async function validatePackedThemeExports(
891
1086
  const packed = normalizeThemeVerifyForCompare(
892
1087
  fs.readFileSync(output.packed, 'utf-8'),
893
1088
  );
894
- if (expected !== local) {
1089
+ // A module that is not the built module may still be an entry that
1090
+ // loads the theme's own styles and re-exports the built module.
1091
+ const localWrapper =
1092
+ output.kind === 'module' && expected !== local
1093
+ ? ownStylesEntry(output.local, expected, localEntry)
1094
+ : null;
1095
+ const packedWrapper =
1096
+ output.kind === 'module' && expected !== packed
1097
+ ? ownStylesEntry(output.packed, expected, packedEntry)
1098
+ : null;
1099
+ const localMatches = expected === local || localWrapper?.ok === true;
1100
+ const packedMatches = expected === packed || packedWrapper?.ok === true;
1101
+ if (!localMatches) {
895
1102
  issues.push(
896
1103
  error(
897
1104
  output.staleCode,
898
- `Theme "${localTheme.slug}" ${output.kind} does not match ${sourceRelative}. Run \`astryx theme build ${sourceRelative}\` before packing.`,
1105
+ localWrapper && !localWrapper.ok && !localWrapper.rebuild
1106
+ ? `Theme "${localTheme.slug}" module is not the module \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` writes and does not only wrap it: ${localWrapper.reason}. A module that wraps the built module may only import the theme's own stylesheet and font stylesheet for their side effects and re-export from the built module either everything or only its theme, as ${localTheme.exportName}.`
1107
+ : localWrapper && !localWrapper.ok
1108
+ ? `Theme "${localTheme.slug}" module re-exports ${localWrapper.reason}, which does not match ${sourceRelative}. Run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` before packing.`
1109
+ : (renamedOutputMessage(
1110
+ localTheme,
1111
+ output.kind,
1112
+ output.local,
1113
+ source,
1114
+ builtName,
1115
+ localIntegration.__packageDir,
1116
+ ) ??
1117
+ `Theme "${localTheme.slug}" ${output.kind} does not match ${sourceRelative}. Run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` before packing.`),
899
1118
  ),
900
1119
  );
901
1120
  }
902
- if (local !== packed) {
1121
+ if (local !== packed || (localMatches && !packedMatches)) {
903
1122
  issues.push(
904
1123
  error(
905
1124
  output.packedCode,
@@ -927,7 +1146,7 @@ async function validatePackedThemeExports(
927
1146
  issues.push(
928
1147
  error(
929
1148
  'theme_build_failed',
930
- `Theme "${localTheme.slug}" could not be rebuilt from ${sourceRelative}: ${err instanceof Error ? err.message : String(err)} Run \`astryx theme build ${sourceRelative}\` before packing.`,
1149
+ `Theme "${localTheme.slug}" could not be rebuilt from ${sourceRelative}: ${err instanceof Error ? err.message : String(err)} Run \`${formatCliCommand(`theme build ${sourceRelative}`, localIntegration.__packageDir)}\` before packing.`,
931
1150
  ),
932
1151
  );
933
1152
  } finally {
@@ -1063,7 +1282,17 @@ export async function integrationPackCheck(options = {}) {
1063
1282
  // ── Phase 1: structure validation ──
1064
1283
  const localResult = await validateLocalIntegration(cwd);
1065
1284
  /** @type {Issue[]} */
1066
- const issues = [...localResult.issues];
1285
+ const issues = [
1286
+ ...localResult.issues,
1287
+ // Validate lists these layout findings without counting them. A
1288
+ // package.json npm cannot pack is what fails the pack here, as it did
1289
+ // before they were named; the rest stay warnings, which fail nothing.
1290
+ ...(localResult.found ? (localResult.listed ?? []) : []).map(issue =>
1291
+ issue.code === 'invalid_package_json'
1292
+ ? {...issue, severity: /** @type {const} */ ('error')}
1293
+ : issue,
1294
+ ),
1295
+ ];
1067
1296
 
1068
1297
  if (!localResult.found || !localResult.integration) {
1069
1298
  return emptyReceipt(pkgName, [
@@ -1085,6 +1314,24 @@ export async function integrationPackCheck(options = {}) {
1085
1314
  const fileInv = computeRequiredFiles(loaded);
1086
1315
  const {identities: localIdentities, errors: localDiscoveryErrors} =
1087
1316
  await collectIdentities(loaded);
1317
+ // A family lists its members from the module its import names, which the
1318
+ // pack lifecycle may build or rebuild, so they are compared as local
1319
+ // discovery lists them after the pack.
1320
+ const familiesBefore = familyImports(loaded).map(family => family.docPath);
1321
+ /**
1322
+ * @param {Array<{name: string, docPath: string|null}>} records
1323
+ * @param {Set<string>} families
1324
+ */
1325
+ const membersOf = (records, families) =>
1326
+ records
1327
+ .filter(
1328
+ r =>
1329
+ r.docPath != null &&
1330
+ families.has(r.docPath) &&
1331
+ isIntegrationMember(r),
1332
+ )
1333
+ .map(r => r.name);
1334
+ const recordsBefore = discoverIntegrationComponents(loaded);
1088
1335
  for (const discoveryError of localDiscoveryErrors) {
1089
1336
  issues.push(
1090
1337
  error(
@@ -1094,6 +1341,8 @@ export async function integrationPackCheck(options = {}) {
1094
1341
  );
1095
1342
  }
1096
1343
  for (const root of fileInv.roots) {
1344
+ // A root that is not a readable folder has its own issue.
1345
+ if (rootProblem(/** @type {string} */ (loaded[root.kind]))) continue;
1097
1346
  if (root.files.length === 0) {
1098
1347
  issues.push(
1099
1348
  error(
@@ -1183,6 +1432,9 @@ export async function integrationPackCheck(options = {}) {
1183
1432
  );
1184
1433
  /** @type {string|null} */
1185
1434
  let scratchBase = null;
1435
+ /** @type {string|undefined} the packed copy of the package */
1436
+ let extractDir;
1437
+ const issuesBeforePack = issues.length;
1186
1438
 
1187
1439
  try {
1188
1440
  // npm pack
@@ -1231,11 +1483,16 @@ export async function integrationPackCheck(options = {}) {
1231
1483
  for (const root of fileInv.roots) {
1232
1484
  const missing = root.files.filter(f => !packResult.packedPaths.has(f));
1233
1485
  if (missing.length === root.files.length && root.files.length > 0) {
1486
+ const absolute = /** @type {string} */ (loaded[root.kind]);
1487
+ const link = symlinkedFolder(absolute, packageDir);
1234
1488
  issues.push(
1235
1489
  error(
1236
1490
  'root_not_packed',
1237
1491
  `Declared ${root.kind} root "${root.path}" has 0 of ${root.files.length} expected ` +
1238
- `files in the pack list. Add "${root.path.replace(/^\.\//, '')}" to "files" in package.json.`,
1492
+ `files in the pack list. ` +
1493
+ (link
1494
+ ? `It is reached through the symlink "${path.relative(packageDir, link.path).split(path.sep).join('/')}", and npm pack does not follow a symlinked folder. Fix: replace the link with the folder itself, or point "${root.kind}" at the folder it links to.`
1495
+ : `Add "${root.path.replace(/^\.\//, '')}" to "files" in package.json.`),
1239
1496
  ),
1240
1497
  );
1241
1498
  } else {
@@ -1274,7 +1531,6 @@ export async function integrationPackCheck(options = {}) {
1274
1531
  }
1275
1532
 
1276
1533
  // ── Phase 3: extract + identity comparison ──
1277
- let extractDir;
1278
1534
  try {
1279
1535
  extractDir = resolvePackageDir(pkgName, scratchBase);
1280
1536
  } catch (err) {
@@ -1320,6 +1576,10 @@ export async function integrationPackCheck(options = {}) {
1320
1576
  code: `packed_${issue.code}`,
1321
1577
  severity: issue.severity,
1322
1578
  message: `Packed: ${issue.message}`,
1579
+ // The packed tree keeps the package's own paths.
1580
+ ...(issue.fix != null ? {fix: issue.fix} : {}),
1581
+ ...(issue.file != null ? {file: issue.file} : {}),
1582
+ ...(issue.line != null ? {line: issue.line} : {}),
1323
1583
  });
1324
1584
  }
1325
1585
 
@@ -1345,7 +1605,27 @@ export async function integrationPackCheck(options = {}) {
1345
1605
  );
1346
1606
  }
1347
1607
 
1348
- issues.push(...compareIdentities(localIdentities, packedIdentities));
1608
+ const families = new Set([
1609
+ ...familiesBefore,
1610
+ ...familyImports(loaded).map(family => family.docPath),
1611
+ ]);
1612
+ let localComponents = localIdentities.components;
1613
+ if (families.size > 0) {
1614
+ const stale = new Set(membersOf(recordsBefore, families));
1615
+ const built = new Set(
1616
+ membersOf(discoverIntegrationComponents(loaded), families),
1617
+ );
1618
+ const {identities: afterPack} = await collectIdentities(loaded);
1619
+ localComponents = [
1620
+ ...new Set([
1621
+ ...localComponents.filter(name => !stale.has(name)),
1622
+ ...afterPack.components.filter(name => built.has(name)),
1623
+ ]),
1624
+ ].sort();
1625
+ }
1626
+ // The receipt reports the local inventory that was compared.
1627
+ const comparedLocal = {...localIdentities, components: localComponents};
1628
+ issues.push(...compareIdentities(comparedLocal, packedIdentities));
1349
1629
  issues.push(
1350
1630
  ...(await validatePackedThemeExports(
1351
1631
  loaded,
@@ -1367,16 +1647,99 @@ export async function integrationPackCheck(options = {}) {
1367
1647
  pkgVersion,
1368
1648
  fileInv,
1369
1649
  packResult,
1370
- localIdentities,
1650
+ comparedLocal,
1371
1651
  packedIdentities,
1372
1652
  issues,
1373
1653
  );
1374
1654
  } finally {
1655
+ // The packed copy lives in a scratch folder that is gone once this
1656
+ // returns: name its files the way the package does.
1657
+ if (extractDir && scratchBase) {
1658
+ packageRelative(issues.slice(issuesBeforePack), extractDir, scratchBase);
1659
+ }
1375
1660
  removeTreeBestEffort(tgzTmpDir, 'temporary tarball directory', issues);
1376
1661
  removeTreeBestEffort(scratchBase, 'scratch consumer', issues);
1377
1662
  }
1378
1663
  }
1379
1664
 
1665
+ /**
1666
+ * When a theme's source names it something other than the file the package
1667
+ * exports for it, a rebuild writes new files under that name and leaves the
1668
+ * exported one stale forever: say so, with both ways out. Null otherwise.
1669
+ * @param {{slug: string}} theme
1670
+ * @param {string} kind 'module' or 'stylesheet'
1671
+ * @param {string} exported the file the package exports for it
1672
+ * @param {string} source the theme's source
1673
+ * @param {string | null} builtName the literal defineTheme name, if any
1674
+ * @param {string} packageDir
1675
+ * @returns {string | null}
1676
+ */
1677
+ function renamedOutputMessage(
1678
+ theme,
1679
+ kind,
1680
+ exported,
1681
+ source,
1682
+ builtName,
1683
+ packageDir,
1684
+ ) {
1685
+ if (builtName == null || builtName === theme.slug) return null;
1686
+ const extension = kind === 'module' ? '.js' : '.css';
1687
+ if (path.basename(exported) === `${builtName}${extension}`) return null;
1688
+ const rel = (/** @type {string} */ file) =>
1689
+ path.relative(packageDir, file).split(path.sep).join('/');
1690
+ const built = rel(
1691
+ path.join(path.dirname(source), `${builtName}${extension}`),
1692
+ );
1693
+ return `Theme "${theme.slug}" ${kind} is ${rel(exported)}, but ${path.basename(source)} calls defineTheme with name: '${builtName}', so \`${formatCliCommand(`theme build ${rel(source)}`, packageDir)}\` writes ${built} instead and rebuilding never updates ${path.basename(exported)}. Fix: point the package export that serves it at ${built} after building, or set name: '${theme.slug}' in ${path.basename(source)} and rebuild.`;
1694
+ }
1695
+
1696
+ /**
1697
+ * Rewrite the scratch copy's absolute paths in each issue's message: a file
1698
+ * of the packed package as its path in the package, and any other path in the
1699
+ * scratch consumer (such as the module that resolved an import) as that
1700
+ * consumer. Both folders are gone once verify returns.
1701
+ * @param {Issue[]} issues
1702
+ * @param {string} packedDir the packed package inside the scratch consumer
1703
+ * @param {string} consumerDir the scratch consumer
1704
+ */
1705
+ function packageRelative(issues, packedDir, consumerDir) {
1706
+ /** @param {string} dir */
1707
+ const spellings = dir => {
1708
+ const out = [dir];
1709
+ try {
1710
+ const real = fs.realpathSync(dir);
1711
+ if (real !== dir) out.push(real);
1712
+ } catch {
1713
+ // Already removed: the plain path is all there is.
1714
+ }
1715
+ return out;
1716
+ };
1717
+ /** @param {string} text */
1718
+ const escape = text => text.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
1719
+ const packed = spellings(packedDir);
1720
+ const consumer = spellings(consumerDir);
1721
+ for (const issue of issues) {
1722
+ if (typeof issue.message !== 'string') continue;
1723
+ let message = issue.message;
1724
+ for (const prefix of packed) {
1725
+ message = message
1726
+ .split(`${prefix}${path.sep}`)
1727
+ .join('')
1728
+ .replace(
1729
+ new RegExp(`${escape(prefix)}(?![\\w-]|\\.\\w)`, 'gu'),
1730
+ 'the package root',
1731
+ );
1732
+ }
1733
+ for (const prefix of consumer) {
1734
+ message = message.replace(
1735
+ new RegExp(`${escape(prefix)}[^\\s"'\`]*`, 'gu'),
1736
+ 'a consumer project',
1737
+ );
1738
+ }
1739
+ issue.message = message;
1740
+ }
1741
+ }
1742
+
1380
1743
  /**
1381
1744
  * Assemble the receipt.
1382
1745
  * @param {string} name