@astryxdesign/cli 0.7.2-canary.fdd384f → 0.7.2

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 (450) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +169 -149
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/kit/kit.mjs +3 -11
  7. package/api/component/_adapter.d.mts +31 -0
  8. package/api/component/_adapter.mjs +119 -11
  9. package/api/component/component.doc.mjs +6 -1
  10. package/api/component/component.mjs +60 -10
  11. package/api/component/doc-links.test.mjs +386 -0
  12. package/api/discover/_adapter.d.mts +132 -12
  13. package/api/discover/_adapter.mjs +488 -27
  14. package/api/discover/_adapter.test.mjs +599 -17
  15. package/api/discover/_catalog-view.d.mts +16 -5
  16. package/api/discover/_catalog-view.mjs +32 -8
  17. package/api/discover/detail/doc/doc.mjs +9 -1
  18. package/api/discover/discover.d.mts +11 -0
  19. package/api/discover/discover.doc.mjs +9 -7
  20. package/api/discover/discover.mjs +121 -19
  21. package/api/discover/discover.type.d.mts +20 -7
  22. package/api/discover/discover.type.mjs +17 -7
  23. package/api/discover/list/list.d.mts +4 -3
  24. package/api/discover/list/list.mjs +17 -10
  25. package/api/docs/_adapter.d.mts +63 -0
  26. package/api/docs/_adapter.mjs +312 -18
  27. package/api/docs/docs.doc.mjs +2 -1
  28. package/api/docs/docs.mjs +2 -1
  29. package/api/docs/docs.test.mjs +5 -2
  30. package/api/docs/integration-tree.test.mjs +22 -0
  31. package/api/docs/list/list.mjs +12 -2
  32. package/api/docs/reference-blocks.test.mjs +1 -3
  33. package/api/doctor/_adapter.d.mts +108 -0
  34. package/api/doctor/_adapter.mjs +223 -4
  35. package/api/doctor/doctor.d.mts +199 -0
  36. package/api/doctor/doctor.doc.mjs +3 -2
  37. package/api/doctor/doctor.mjs +530 -34
  38. package/api/doctor/doctor.test.mjs +180 -14
  39. package/api/doctor/release-checks.test.mjs +156 -0
  40. package/api/doctor/theme-checks.mjs +16 -3
  41. package/api/doctor/theme-checks.test.mjs +223 -7
  42. package/api/error.d.mts +10 -0
  43. package/api/error.mjs +25 -0
  44. package/api/gap-report/gap-report.d.mts +3 -0
  45. package/api/gap-report/gap-report.doc.mjs +11 -3
  46. package/api/gap-report/gap-report.mjs +152 -48
  47. package/api/gap-report/gap-report.test.mjs +233 -0
  48. package/api/gap-report/gap-report.type.d.mts +41 -0
  49. package/api/gap-report/gap-report.type.mjs +18 -0
  50. package/api/hook/_adapter.mjs +3 -11
  51. package/api/hook/hook.doc.mjs +4 -0
  52. package/api/hook/list/list.d.mts +1 -1
  53. package/api/init/_adapter.d.mts +22 -0
  54. package/api/init/_adapter.mjs +59 -0
  55. package/api/init/init.d.mts +7 -5
  56. package/api/init/init.doc.mjs +28 -7
  57. package/api/init/init.mjs +28 -4
  58. package/api/init/init.type.d.mts +48 -3
  59. package/api/init/init.type.mjs +37 -3
  60. package/api/init/run/run.d.mts +1 -1
  61. package/api/init/run/run.mjs +15 -4
  62. package/api/init/user/user.d.mts +14 -0
  63. package/api/init/user/user.mjs +87 -0
  64. package/api/init/user/user.test.mjs +232 -0
  65. package/api/integration/_adapter.d.mts +33 -0
  66. package/api/integration/_adapter.mjs +58 -0
  67. package/api/integration/authoring-checks.mjs +100 -5
  68. package/api/integration/authoring-checks.test.mjs +769 -0
  69. package/api/integration/authoring-checks.type.d.mts +134 -0
  70. package/api/integration/authoring-checks.type.mjs +60 -1
  71. package/api/integration/integrationCheck.doc.mjs +1 -1
  72. package/api/integration/integrationComponentConflicts.doc.mjs +11 -3
  73. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  74. package/api/integration/pack-check.mjs +303 -13
  75. package/api/integration/pack-check.test.mjs +371 -10
  76. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  77. package/api/integration/validate-integration.d.mts +8 -0
  78. package/api/integration/validate-integration.mjs +55 -9
  79. package/api/integration/validate-integration.test.mjs +77 -8
  80. package/api/integration/validate-integration.type.d.mts +8 -0
  81. package/api/integration/validate-integration.type.mjs +3 -1
  82. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  83. package/api/integration/validateIntegration.doc.mjs +4 -2
  84. package/api/search/_adapter.d.mts +11 -0
  85. package/api/search/_adapter.mjs +25 -0
  86. package/api/search/search.d.mts +73 -13
  87. package/api/search/search.doc.mjs +8 -3
  88. package/api/search/search.domain-priority.test.mjs +108 -18
  89. package/api/search/search.mjs +541 -52
  90. package/api/search/search.test.mjs +143 -1
  91. package/api/search/search.type.d.mts +14 -1
  92. package/api/search/search.type.mjs +6 -1
  93. package/api/swizzle/_adapter.mjs +2 -2
  94. package/api/swizzle/copy/copy.mjs +1 -1
  95. package/api/template/template-integration.test.mjs +1 -1
  96. package/api/theme/_adapter.d.mts +16 -0
  97. package/api/theme/_adapter.mjs +32 -5
  98. package/api/theme/build/build.d.mts +2 -1
  99. package/api/theme/build/build.mjs +70 -14
  100. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  101. package/api/theme/build/font-warning.mjs +5 -3
  102. package/api/theme/build/font-warning.test.mjs +2 -1
  103. package/api/theme/remove/remove.test.mjs +2 -2
  104. package/api/theme/targets/targets.mjs +3 -10
  105. package/api/theme/themeTargets.doc.mjs +4 -0
  106. package/api/theme/use/use.test.mjs +1 -1
  107. package/api/upgrade/_adapter.d.mts +40 -2
  108. package/api/upgrade/_adapter.mjs +118 -5
  109. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  110. package/api/upgrade/run/run.mjs +35 -2
  111. package/api/upgrade/status/status.d.mts +21 -5
  112. package/api/upgrade/status/status.mjs +45 -8
  113. package/api/upgrade/upgrade.doc.mjs +6 -3
  114. package/api/upgrade/upgrade.mjs +5 -1
  115. package/api/upgrade/upgrade.type.d.mts +23 -0
  116. package/api/upgrade/upgrade.type.mjs +16 -1
  117. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  118. package/assets/codemods/registry.mjs +1 -0
  119. package/assets/codemods/runner.mjs +7 -1
  120. package/assets/codemods/transforms/next/index.mjs +1 -11
  121. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  122. package/assets/discover/official-packages.json +367 -0
  123. package/assets/docs/author-a-theme.doc.mjs +2 -2
  124. package/assets/docs/browser-support.doc.mjs +1 -1
  125. package/assets/docs/getting-started.doc.mjs +23 -3
  126. package/assets/docs/styling-overview.doc.mjs +1 -1
  127. package/assets/docs/theme.doc.mjs +1 -1
  128. package/assets/docs/tree/add-a-component.doc.mjs +12 -2
  129. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  130. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  131. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  132. package/assets/docs/tree/block-template.doc.mjs +6 -18
  133. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  134. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  135. package/assets/docs/tree/check-the-props.doc.mjs +8 -3
  136. package/assets/docs/tree/check-your-docs.doc.mjs +30 -13
  137. package/assets/docs/tree/checks.doc.mjs +17 -17
  138. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  139. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  140. package/assets/docs/tree/cli.doc.mjs +6 -0
  141. package/assets/docs/tree/codemods.doc.mjs +17 -7
  142. package/assets/docs/tree/commands.doc.mjs +7 -1
  143. package/assets/docs/tree/component-family.doc.mjs +3 -5
  144. package/assets/docs/tree/component-imports.doc.mjs +13 -3
  145. package/assets/docs/tree/components.doc.mjs +7 -1
  146. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  147. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  148. package/assets/docs/tree/configuration.doc.mjs +7 -3
  149. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  150. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  151. package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
  152. package/assets/docs/tree/docs.doc.mjs +9 -3
  153. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  154. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  155. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  156. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  157. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  158. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  159. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  160. package/assets/docs/tree/global.doc.mjs +131 -0
  161. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  162. package/assets/docs/tree/install-once.doc.mjs +105 -0
  163. package/assets/docs/tree/integrations.doc.mjs +13 -1
  164. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  165. package/assets/docs/tree/layout.doc.mjs +6 -6
  166. package/assets/docs/tree/links.doc.mjs +6 -5
  167. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  168. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  169. package/assets/docs/tree/migration.doc.mjs +0 -1
  170. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  171. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  172. package/assets/docs/tree/page-template.doc.mjs +3 -7
  173. package/assets/docs/tree/problems.doc.mjs +205 -0
  174. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  175. package/assets/docs/tree/publishing.doc.mjs +6 -6
  176. package/assets/docs/tree/quick-start.doc.mjs +52 -26
  177. package/assets/docs/tree/reference.doc.mjs +192 -0
  178. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  179. package/assets/docs/tree/replace-a-core-template.doc.mjs +9 -11
  180. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  181. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  182. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  183. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  184. package/assets/docs/tree/single-component.doc.mjs +14 -6
  185. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  186. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  187. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  188. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  189. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  190. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  191. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  192. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  193. package/assets/docs/tree/templates.doc.mjs +7 -1
  194. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  195. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  196. package/assets/docs/tree/themes.doc.mjs +4 -0
  197. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  198. package/assets/docs/tree/troubleshooting.doc.mjs +22 -14
  199. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  200. package/assets/docs/tree/updates.doc.mjs +92 -0
  201. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  202. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  203. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  204. package/assets/docs/tree/versioning.doc.mjs +9 -9
  205. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  206. package/assets/docs/tree/write-the-template-file.doc.mjs +5 -5
  207. package/assets/docs/working-with-ai.doc.mjs +23 -9
  208. package/authoring/codemod/codemod.doc.mjs +7 -3
  209. package/authoring/config/config.doc.mjs +9 -6
  210. package/authoring/config/type.ts +4 -2
  211. package/authoring/debug/parse.d.mts +5 -5
  212. package/authoring/discover/discover.doc.mjs +7 -1
  213. package/authoring/doctypes/_schema.d.mts +8 -3
  214. package/authoring/doctypes/_schema.mjs +1 -0
  215. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  216. package/authoring/doctypes/command/command.doc.mjs +20 -12
  217. package/authoring/doctypes/command/type.ts +14 -0
  218. package/authoring/doctypes/component/component.doc.mjs +29 -26
  219. package/authoring/doctypes/component/type.ts +15 -5
  220. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  221. package/authoring/doctypes/function/function.doc.mjs +9 -8
  222. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  223. package/authoring/doctypes/hook/type.ts +4 -0
  224. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  225. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  226. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  227. package/authoring/doctypes/template/template.doc.mjs +2 -2
  228. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  229. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  230. package/authoring/identity/identity.doc.mjs +3 -3
  231. package/authoring/index.d.ts +1 -0
  232. package/authoring/integration/integration.doc.mjs +22 -5
  233. package/authoring/integration/parse.test.mjs +11 -0
  234. package/authoring/integration/schema.d.mts +14 -3
  235. package/authoring/integration/schema.mjs +33 -2
  236. package/authoring/integration/type.ts +8 -0
  237. package/clients/cli/bin/astryx.mjs +20 -3
  238. package/clients/cli/cli-command.test.mjs +166 -0
  239. package/clients/cli/commands/blog.doc.mjs +1 -0
  240. package/clients/cli/commands/build-theme.batch-report.test.mjs +14 -2
  241. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  242. package/clients/cli/commands/build-theme.mjs +25 -12
  243. package/clients/cli/commands/build.doc.mjs +1 -0
  244. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  245. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  246. package/clients/cli/commands/component.doc.mjs +1 -0
  247. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  248. package/clients/cli/commands/discover.doc.mjs +9 -1
  249. package/clients/cli/commands/discover.mjs +144 -93
  250. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  251. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  252. package/clients/cli/commands/docs.doc.mjs +1 -0
  253. package/clients/cli/commands/docs.mjs +49 -19
  254. package/clients/cli/commands/docs.test.mjs +2 -2
  255. package/clients/cli/commands/doctor-integration-components.doc.mjs +7 -3
  256. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  257. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  258. package/clients/cli/commands/doctor-integration-validate.doc.mjs +13 -2
  259. package/clients/cli/commands/doctor-integration.test.mjs +52 -4
  260. package/clients/cli/commands/doctor.doc.mjs +12 -2
  261. package/clients/cli/commands/doctor.mjs +102 -7
  262. package/clients/cli/commands/doctor.test.mjs +10 -4
  263. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  264. package/clients/cli/commands/gap-report.mjs +24 -2
  265. package/clients/cli/commands/gap-report.test.mjs +79 -0
  266. package/clients/cli/commands/hook.doc.mjs +1 -0
  267. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  268. package/clients/cli/commands/init.doc.mjs +29 -3
  269. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  270. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  271. package/clients/cli/commands/integration-check.doc.mjs +10 -2
  272. package/clients/cli/commands/integration-check.test.mjs +175 -1
  273. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  274. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  275. package/clients/cli/commands/integration.mjs +15 -9
  276. package/clients/cli/commands/json-contract.test.mjs +11 -2
  277. package/clients/cli/commands/manifest.doc.mjs +1 -0
  278. package/clients/cli/commands/outside-project.test.mjs +774 -0
  279. package/clients/cli/commands/search.doc.mjs +1 -0
  280. package/clients/cli/commands/search.mjs +16 -11
  281. package/clients/cli/commands/search.test.mjs +429 -296
  282. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  283. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  284. package/clients/cli/commands/swizzle.mjs +5 -3
  285. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  286. package/clients/cli/commands/template.doc.mjs +1 -0
  287. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  288. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  289. package/clients/cli/commands/theme-build.doc.mjs +1 -0
  290. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  291. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  292. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  293. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  294. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  295. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  296. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  297. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  298. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  299. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  300. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  301. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  302. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  303. package/clients/cli/index.mjs +111 -16
  304. package/clients/cli/lib/cli-error.mjs +4 -1
  305. package/clients/cli/lib/component-format.test.mjs +1 -1
  306. package/clients/cli/lib/define-command.mjs +2 -2
  307. package/clients/cli/lib/json-shim.mjs +3 -1
  308. package/clients/cli/lib/manifest.d.ts +9 -0
  309. package/clients/cli/lib/manifest.mjs +17 -1
  310. package/clients/cli/lib/manifest.test.mjs +25 -0
  311. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  312. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  313. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  314. package/foundation/agent-docs/agent-docs.mjs +11 -9
  315. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  316. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  317. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  318. package/foundation/config/project.d.mts +35 -3
  319. package/foundation/config/project.mjs +145 -8
  320. package/foundation/config/project.test.mjs +66 -0
  321. package/foundation/config/theme-state.mjs +5 -4
  322. package/foundation/discovery/authoring-self-docs.mjs +1 -1
  323. package/foundation/discovery/cli-self-docs.mjs +20 -3
  324. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  325. package/foundation/discovery/component-replacement.mjs +2 -1
  326. package/foundation/discovery/copied-passages.d.mts +216 -0
  327. package/foundation/discovery/copied-passages.mjs +720 -0
  328. package/foundation/discovery/copied-passages.test.mjs +124 -0
  329. package/foundation/discovery/doc-consistency.d.mts +34 -0
  330. package/foundation/discovery/doc-consistency.mjs +513 -0
  331. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  332. package/foundation/discovery/doc-fluff.d.mts +112 -0
  333. package/foundation/discovery/doc-fluff.mjs +328 -0
  334. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  335. package/foundation/discovery/doc-types.d.mts +1 -1
  336. package/foundation/discovery/doc-types.mjs +15 -8
  337. package/foundation/discovery/doc-types.test.mjs +94 -2
  338. package/foundation/discovery/docs-discovery.d.mts +7 -0
  339. package/foundation/discovery/docs-discovery.mjs +26 -2
  340. package/foundation/discovery/project-typescript.d.mts +11 -2
  341. package/foundation/discovery/project-typescript.mjs +32 -4
  342. package/foundation/discovery/prop-drift.d.mts +26 -7
  343. package/foundation/discovery/prop-drift.mjs +173 -8
  344. package/foundation/discovery/prop-drift.test.mjs +120 -2
  345. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  346. package/foundation/discovery/runner-allowlist.mjs +53 -0
  347. package/foundation/discovery/stray-pointers.d.mts +52 -0
  348. package/foundation/discovery/stray-pointers.mjs +293 -0
  349. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  350. package/foundation/discovery/template-needs.mjs +5 -2
  351. package/foundation/discovery/theme-imports.mjs +8 -4
  352. package/foundation/discovery/theme-imports.test.mjs +1 -1
  353. package/foundation/discovery/type-text.mjs +1 -1
  354. package/foundation/discovery/type-text.test.mjs +1 -1
  355. package/foundation/doc-compiler/doc-loads.test.mjs +42 -2
  356. package/foundation/doc-compiler/inputs.mjs +4 -1
  357. package/foundation/doc-compiler/links.d.mts +32 -0
  358. package/foundation/doc-compiler/links.mjs +163 -26
  359. package/foundation/doc-compiler/links.test.mjs +97 -4
  360. package/foundation/doc-compiler/read.d.mts +1 -1
  361. package/foundation/doc-compiler/tree.mjs +30 -1
  362. package/foundation/doc-compiler/tree.test.mjs +8 -1
  363. package/foundation/env/cli-command.d.mts +83 -0
  364. package/foundation/env/cli-command.mjs +152 -0
  365. package/foundation/env/cli-command.test.mjs +129 -0
  366. package/foundation/env/node-version.test.mjs +15 -3
  367. package/foundation/env/package-manager.d.mts +93 -9
  368. package/foundation/env/package-manager.global.test.mjs +66 -0
  369. package/foundation/env/package-manager.mjs +184 -13
  370. package/foundation/env/package-manager.test.mjs +341 -15
  371. package/foundation/env/project-scope.d.mts +9 -0
  372. package/foundation/env/project-scope.mjs +33 -0
  373. package/foundation/env/search-path.d.mts +42 -0
  374. package/foundation/env/search-path.mjs +205 -0
  375. package/foundation/env/search-path.test.mjs +122 -0
  376. package/foundation/env/user-dirs.d.mts +39 -0
  377. package/foundation/env/user-dirs.mjs +93 -0
  378. package/foundation/env/user-dirs.test.mjs +72 -0
  379. package/foundation/env/user-settings.d.mts +46 -0
  380. package/foundation/env/user-settings.mjs +106 -0
  381. package/foundation/env/user-settings.test.mjs +64 -0
  382. package/foundation/fs/file-protection.mjs +15 -1
  383. package/foundation/fs/module-loader.d.mts +2 -1
  384. package/foundation/fs/module-loader.mjs +60 -4
  385. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  386. package/foundation/fs/module-loader.test.mjs +194 -0
  387. package/foundation/fs/path-compare.d.mts +33 -0
  388. package/foundation/fs/path-compare.mjs +73 -0
  389. package/foundation/fs/paths.d.mts +57 -1
  390. package/foundation/fs/paths.mjs +131 -3
  391. package/foundation/fs/paths.test.mjs +10 -1
  392. package/foundation/integrations/computer-integrations.d.mts +78 -0
  393. package/foundation/integrations/computer-integrations.mjs +316 -0
  394. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  395. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  396. package/foundation/integrations/contribution-inventory.mjs +50 -2
  397. package/foundation/integrations/integration-warnings.mjs +3 -2
  398. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  399. package/foundation/integrations/integrations.d.mts +25 -1
  400. package/foundation/integrations/integrations.mjs +46 -3
  401. package/foundation/integrations/issue.ts +6 -0
  402. package/foundation/integrations/validate-contributions.d.mts +2 -0
  403. package/foundation/integrations/validate-contributions.mjs +41 -1
  404. package/foundation/release/agent-text-worker.d.mts +4 -0
  405. package/foundation/release/agent-text-worker.mjs +52 -0
  406. package/foundation/release/cache.d.mts +310 -0
  407. package/foundation/release/cache.mjs +1216 -0
  408. package/foundation/release/cache.test.mjs +920 -0
  409. package/foundation/release/choose.d.mts +207 -0
  410. package/foundation/release/choose.mjs +677 -0
  411. package/foundation/release/choose.test.mjs +427 -0
  412. package/foundation/release/core-worker.d.mts +4 -0
  413. package/foundation/release/core-worker.mjs +38 -0
  414. package/foundation/release/global-state.d.mts +259 -0
  415. package/foundation/release/global-state.mjs +472 -0
  416. package/foundation/release/global-state.test.mjs +381 -0
  417. package/foundation/release/handoff.d.mts +60 -0
  418. package/foundation/release/handoff.e2e.test.mjs +278 -0
  419. package/foundation/release/handoff.mjs +357 -0
  420. package/foundation/release/lock-lease.d.mts +23 -0
  421. package/foundation/release/lock-lease.mjs +80 -0
  422. package/foundation/release/notices.d.mts +253 -0
  423. package/foundation/release/notices.mjs +596 -0
  424. package/foundation/release/notices.test.mjs +565 -0
  425. package/foundation/release/npm-guard.d.mts +4 -0
  426. package/foundation/release/npm-guard.mjs +126 -0
  427. package/foundation/release/project.d.mts +141 -0
  428. package/foundation/release/project.mjs +466 -0
  429. package/foundation/release/project.test.mjs +288 -0
  430. package/foundation/release/refresh-worker.d.mts +4 -0
  431. package/foundation/release/refresh-worker.mjs +27 -0
  432. package/foundation/release/run-context.d.mts +47 -0
  433. package/foundation/release/run-context.mjs +149 -0
  434. package/foundation/release/update-notice-env.d.mts +28 -0
  435. package/foundation/release/update-notice-env.mjs +39 -0
  436. package/foundation/response/base.d.ts +26 -3
  437. package/foundation/response/error-codes.d.mts +3 -1
  438. package/foundation/response/error-codes.doc.mjs +12 -0
  439. package/foundation/response/error-codes.mjs +17 -0
  440. package/foundation/response/error-codes.test.mjs +2 -0
  441. package/foundation/response/json-contract.test.mjs +7 -2
  442. package/foundation/response/json.mjs +4 -1
  443. package/foundation/response/response-types.doc.mjs +17 -11
  444. package/foundation/response/response-types.doc.test.mjs +46 -0
  445. package/foundation/response/response.doc.mjs +3 -3
  446. package/foundation/xle/browser-imports.test.mjs +74 -0
  447. package/package.json +11 -11
  448. package/scripts/postinstall.mjs +24 -5
  449. /package/assets/codemods/transforms/{next → v0.7.2}/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +0 -0
  450. /package/assets/codemods/transforms/{next → v0.7.2}/migrate-list-edge-compensation-to-edge.mjs +0 -0
@@ -17,6 +17,7 @@ import {
17
17
  integrationAddComponent,
18
18
  integrationAddTemplate,
19
19
  } from './add-contribution.mjs';
20
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
20
21
 
21
22
  let tmpDir;
22
23
 
@@ -213,6 +214,7 @@ function writePackage({
213
214
  themeExports = false,
214
215
  npmignore,
215
216
  components = false,
217
+ templates = false,
216
218
  scripts,
217
219
  } = {}) {
218
220
  const pkg = {name, version};
@@ -272,6 +274,14 @@ export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description:
272
274
  'export default function Card() { return null; }\n',
273
275
  );
274
276
  }
277
+ if (templates) {
278
+ const root = path.join(tmpDir, 'templates');
279
+ fs.mkdirSync(root, {recursive: true});
280
+ fs.writeFileSync(
281
+ path.join(root, 'stray.tsx'),
282
+ 'export default function Stray() { return null; }\n',
283
+ );
284
+ }
275
285
  if (npmignore) {
276
286
  fs.writeFileSync(path.join(tmpDir, '.npmignore'), npmignore);
277
287
  }
@@ -303,6 +313,345 @@ function runCliVerify() {
303
313
  };
304
314
  }
305
315
 
316
+ /**
317
+ * Give the built ocean theme a font stylesheet and an entry module that loads
318
+ * the theme's own styles, and export them the way such a package does.
319
+ * @param {string} entry
320
+ * @param {string} [file] the entry's file name in `entries/`
321
+ */
322
+ function writeOwnStylesEntry(entry, file = 'ocean.mjs') {
323
+ fs.writeFileSync(
324
+ path.join(tmpDir, 'themes', 'ocean', 'ocean.fonts.css'),
325
+ "@font-face { font-family: 'Ocean Sans'; src: local('Ocean Sans'); }\n",
326
+ );
327
+ fs.mkdirSync(path.join(tmpDir, 'entries'), {recursive: true});
328
+ fs.writeFileSync(path.join(tmpDir, 'entries', file), entry);
329
+ const packageFile = path.join(tmpDir, 'package.json');
330
+ const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf-8'));
331
+ pkg.files = ['astryx.integration.mjs', 'themes', 'entries'];
332
+ pkg.exports = {
333
+ './themes/ocean': `./entries/${file}`,
334
+ './themes/ocean.css': './themes/ocean/ocean.css',
335
+ './themes/ocean.fonts.css': './themes/ocean/ocean.fonts.css',
336
+ };
337
+ fs.writeFileSync(packageFile, `${JSON.stringify(pkg, null, 2)}\n`);
338
+ }
339
+
340
+ /**
341
+ * Rename the ocean theme to deep-sea, keeping its `ocean` slug, and build it,
342
+ * so its outputs are named after the theme: `deep-sea.css` and `deep-sea.js`,
343
+ * which exports `deepSeaTheme`.
344
+ */
345
+ function writeRenamedOcean() {
346
+ writePackage({files: ['astryx.integration.mjs', 'themes', 'entries']});
347
+ fs.writeFileSync(
348
+ path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
349
+ "import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const oceanTheme = defineTheme({name: 'deep-sea'});\n",
350
+ );
351
+ const built = spawnSync(
352
+ process.execPath,
353
+ [
354
+ path.join(process.cwd(), 'packages/cli/clients/cli/bin/astryx.mjs'),
355
+ 'theme',
356
+ 'build',
357
+ 'themes/ocean/oceanTheme.ts',
358
+ ],
359
+ {cwd: tmpDir, encoding: 'utf-8', timeout: 30_000},
360
+ );
361
+ if (built.status !== 0) {
362
+ throw new Error(`Could not build the theme fixture: ${built.stderr}`);
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Give the ocean theme an icon registry and build it, so its built module
368
+ * also exports `oceanIcons`.
369
+ */
370
+ function writeOceanWithIcons() {
371
+ writePackage({files: ['astryx.integration.mjs', 'themes', 'entries']});
372
+ const themeDir = path.join(tmpDir, 'themes', 'ocean');
373
+ fs.writeFileSync(
374
+ path.join(themeDir, 'icons.js'),
375
+ 'export const oceanIcons = {};\n',
376
+ );
377
+ fs.writeFileSync(
378
+ path.join(themeDir, 'oceanTheme.ts'),
379
+ "import {defineTheme} from '@astryxdesign/core/theme';\nimport {oceanIcons} from './icons';\n\nexport const oceanTheme = defineTheme({name: 'ocean', icons: oceanIcons});\n",
380
+ );
381
+ const built = spawnSync(
382
+ process.execPath,
383
+ [
384
+ path.join(process.cwd(), 'packages/cli/clients/cli/bin/astryx.mjs'),
385
+ 'theme',
386
+ 'build',
387
+ 'themes/ocean/oceanTheme.ts',
388
+ ],
389
+ {cwd: tmpDir, encoding: 'utf-8', timeout: 30_000},
390
+ );
391
+ if (built.status !== 0) {
392
+ throw new Error(`Could not build the theme fixture: ${built.stderr}`);
393
+ }
394
+ }
395
+
396
+ // An entry like one whose import is the whole integration: it loads the
397
+ // theme's fonts and stylesheet, by relative path and through the package's
398
+ // own exports, and re-exports the built theme.
399
+ const OWN_STYLES_ENTRY = `// Copyright (c) Acme.
400
+
401
+ import '../themes/ocean/ocean.fonts.css';
402
+ import '@acme/widgets/themes/ocean.css';
403
+
404
+ export {oceanTheme} from '../themes/ocean/ocean.js';
405
+ `;
406
+
407
+ describe('a theme module that loads its own styles', () => {
408
+ it('passes an entry that imports the theme stylesheet and fonts and re-exports the built module', async () => {
409
+ writePackage({themeExports: true});
410
+ writeOwnStylesEntry(OWN_STYLES_ENTRY);
411
+
412
+ const result = await integrationPackCheck({cwd: tmpDir});
413
+
414
+ expect(result.data.issues).toEqual([]);
415
+ expect(result.data.packable).toBe(true);
416
+ const cli = runCliVerify();
417
+ expect(cli.status, cli.stderr).toBe(0);
418
+ expect(cli.receipt?.data.issues).toEqual([]);
419
+ });
420
+
421
+ it('passes an entry that imports its fonts through the package exports and re-exports everything', async () => {
422
+ writePackage({themeExports: true});
423
+ writeOwnStylesEntry(
424
+ "import '@acme/widgets/themes/ocean.fonts.css';\nimport '../themes/ocean/ocean.css';\nexport * from '../themes/ocean/ocean.js';\n",
425
+ );
426
+
427
+ const result = await integrationPackCheck({cwd: tmpDir});
428
+
429
+ expect(result.data.issues).toEqual([]);
430
+ expect(result.data.packable).toBe(true);
431
+ });
432
+
433
+ it.each([
434
+ [
435
+ 'also imports another stylesheet',
436
+ `${OWN_STYLES_ENTRY}import './other.css';\n`,
437
+ "./other.css is not the theme's own stylesheet or font stylesheet",
438
+ ],
439
+ [
440
+ 'also imports a script',
441
+ `import './setup.mjs';\n${OWN_STYLES_ENTRY}`,
442
+ "./setup.mjs is not the theme's own stylesheet or font stylesheet",
443
+ ],
444
+ [
445
+ 'runs code',
446
+ `${OWN_STYLES_ENTRY}console.log('ocean');\n`,
447
+ 'line 7 is neither a stylesheet import nor the re-export',
448
+ ],
449
+ [
450
+ 'exports another value',
451
+ `${OWN_STYLES_ENTRY}export const extra = 1;\n`,
452
+ 'line 7 is neither a stylesheet import nor the re-export',
453
+ ],
454
+ [
455
+ 'renames the theme it re-exports',
456
+ "import '../themes/ocean/ocean.css';\nexport {oceanTheme, oceanTheme as theme} from '../themes/ocean/ocean.js';\n",
457
+ 'it re-exports names other than oceanTheme',
458
+ ],
459
+ [
460
+ 'binds the stylesheet it imports',
461
+ "import styles from '../themes/ocean/ocean.css';\nexport {oceanTheme} from '../themes/ocean/ocean.js';\n",
462
+ 'its import of ../themes/ocean/ocean.css is not a side-effect import',
463
+ ],
464
+ [
465
+ 'imports the stylesheet as a CSS module script',
466
+ "import '../themes/ocean/ocean.css' with {type: 'css'};\nexport {oceanTheme} from '../themes/ocean/ocean.js';\n",
467
+ 'its import of ../themes/ocean/ocean.css is not a side-effect import',
468
+ ],
469
+ [
470
+ 're-exports another name',
471
+ "import '../themes/ocean/ocean.css';\nexport {oceanTheme, missing} from '../themes/ocean/ocean.js';\n",
472
+ 'it re-exports names other than oceanTheme',
473
+ ],
474
+ [
475
+ 're-exports a copy that is not a .js module',
476
+ "import '../themes/ocean/ocean.css';\nexport {oceanTheme} from './copy.cjs';\n",
477
+ 'its re-export from ./copy.cjs does not name a .js module',
478
+ ],
479
+ [
480
+ 'has a directive',
481
+ `'use client';\n${OWN_STYLES_ENTRY}`,
482
+ 'it has a directive',
483
+ ],
484
+ [
485
+ 're-exports twice',
486
+ `${OWN_STYLES_ENTRY}export * from '../themes/ocean/ocean.js';\n`,
487
+ 'it has more than one re-export',
488
+ ],
489
+ ])('fails an entry that %s', async (_label, entry, reason) => {
490
+ writePackage({themeExports: true});
491
+ writeOwnStylesEntry(entry);
492
+ fs.writeFileSync(path.join(tmpDir, 'entries', 'other.css'), '.x {}\n');
493
+ fs.writeFileSync(path.join(tmpDir, 'entries', 'setup.mjs'), 'export {};\n');
494
+ fs.copyFileSync(
495
+ path.join(tmpDir, 'themes', 'ocean', 'ocean.js'),
496
+ path.join(tmpDir, 'entries', 'copy.cjs'),
497
+ );
498
+
499
+ const result = await integrationPackCheck({cwd: tmpDir});
500
+
501
+ expect(result.data.packable).toBe(false);
502
+ expect(result.data.issues).toEqual([
503
+ {
504
+ code: 'theme_module_stale',
505
+ severity: 'error',
506
+ message: `Theme "ocean" module is not the module \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` writes and does not only wrap it: ${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 oceanTheme.`,
507
+ },
508
+ ]);
509
+ });
510
+
511
+ it('fails an entry whose re-exported module drifts from source', async () => {
512
+ writePackage({themeExports: true});
513
+ writeOwnStylesEntry(OWN_STYLES_ENTRY);
514
+ fs.appendFileSync(
515
+ path.join(tmpDir, 'themes', 'ocean', 'ocean.js'),
516
+ '// stale module\n',
517
+ );
518
+
519
+ const result = await integrationPackCheck({cwd: tmpDir});
520
+
521
+ expect(result.data.packable).toBe(false);
522
+ expect(result.data.issues).toEqual([
523
+ {
524
+ code: 'theme_module_stale',
525
+ severity: 'error',
526
+ message: `Theme "ocean" module re-exports ../themes/ocean/ocean.js, which does not match themes/ocean/oceanTheme.ts. Run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before packing.`,
527
+ },
528
+ ]);
529
+ });
530
+
531
+ it('does not accept a TypeScript entry', async () => {
532
+ writePackage({themeExports: true});
533
+ writeOwnStylesEntry(OWN_STYLES_ENTRY, 'ocean.ts');
534
+
535
+ const result = await integrationPackCheck({cwd: tmpDir});
536
+
537
+ expect(result.data.packable).toBe(false);
538
+ expect(result.data.issues).toEqual([
539
+ {
540
+ code: 'theme_module_stale',
541
+ severity: 'error',
542
+ message: `Theme "ocean" module does not match themes/ocean/oceanTheme.ts. Run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before packing.`,
543
+ },
544
+ ]);
545
+ });
546
+
547
+ it('does not accept an entry that re-exports itself', async () => {
548
+ writePackage({themeExports: true});
549
+ writeOwnStylesEntry(
550
+ "import '../themes/ocean/ocean.css';\nexport * from './ocean.js';\n",
551
+ 'ocean.js',
552
+ );
553
+
554
+ const result = await integrationPackCheck({cwd: tmpDir});
555
+
556
+ expect(result.data.packable).toBe(false);
557
+ expect(result.data.issues).toContainEqual(
558
+ expect.objectContaining({
559
+ code: 'theme_import_unresolvable',
560
+ message: expect.stringContaining('does not export "oceanTheme"'),
561
+ }),
562
+ );
563
+ });
564
+
565
+ it('passes an entry for a theme whose own name differs from its slug', async () => {
566
+ writeRenamedOcean();
567
+ writeOwnStylesEntry(
568
+ "import '../themes/ocean/deep-sea.css';\nexport {deepSeaTheme as oceanTheme} from '../themes/ocean/deep-sea.js';\n",
569
+ );
570
+ setThemeExports({
571
+ './themes/ocean': './entries/ocean.mjs',
572
+ './themes/ocean.css': './themes/ocean/deep-sea.css',
573
+ });
574
+
575
+ const result = await integrationPackCheck({cwd: tmpDir});
576
+
577
+ expect(result.data.issues).toEqual([]);
578
+ expect(result.data.packable).toBe(true);
579
+ const cli = runCliVerify();
580
+ expect(cli.status, cli.stderr).toBe(0);
581
+ });
582
+
583
+ it('compares a partial export set with the module named after the theme', async () => {
584
+ writeRenamedOcean();
585
+ setThemeExports({'./themes/ocean': './themes/ocean/deep-sea.js'});
586
+
587
+ const result = await integrationPackCheck({cwd: tmpDir});
588
+
589
+ expect(result.data.packable).toBe(true);
590
+ expect(result.data.issues.map(issue => issue.code)).toEqual([
591
+ 'theme_exports_incomplete',
592
+ ]);
593
+ });
594
+
595
+ it('passes an entry that re-exports only the theme from a built module that also exports its icons', async () => {
596
+ writeOceanWithIcons();
597
+ writeOwnStylesEntry(OWN_STYLES_ENTRY);
598
+
599
+ const result = await integrationPackCheck({cwd: tmpDir});
600
+
601
+ expect(result.data.issues).toEqual([]);
602
+ expect(result.data.packable).toBe(true);
603
+ });
604
+
605
+ it('fails an entry that gives the built icons the theme export name', async () => {
606
+ writeOceanWithIcons();
607
+ writeOwnStylesEntry(
608
+ "import '../themes/ocean/ocean.css';\nexport {oceanIcons as oceanTheme} from '../themes/ocean/ocean.js';\n",
609
+ );
610
+
611
+ const result = await integrationPackCheck({cwd: tmpDir});
612
+
613
+ expect(result.data.packable).toBe(false);
614
+ expect(result.data.issues).toEqual([
615
+ expect.objectContaining({
616
+ code: 'theme_module_stale',
617
+ message: expect.stringContaining(
618
+ 'it re-exports oceanIcons, which is not the built theme',
619
+ ),
620
+ }),
621
+ ]);
622
+ });
623
+
624
+ it('fails when packing changes the module an entry re-exports', async () => {
625
+ const prepack = [
626
+ "const fs=require('fs')",
627
+ "fs.copyFileSync('themes/ocean/ocean.js','.ocean.js.orig')",
628
+ "fs.appendFileSync('themes/ocean/ocean.js','// packed\\n')",
629
+ ].join(';');
630
+ const postpack =
631
+ "require('fs').renameSync('.ocean.js.orig','themes/ocean/ocean.js')";
632
+ writePackage({
633
+ themeExports: true,
634
+ scripts: {
635
+ prepack: `node -e "${prepack}"`,
636
+ postpack: `node -e "${postpack}"`,
637
+ },
638
+ });
639
+ writeOwnStylesEntry(OWN_STYLES_ENTRY);
640
+
641
+ const result = await integrationPackCheck({cwd: tmpDir});
642
+
643
+ expect(result.data.packable).toBe(false);
644
+ expect(result.data.issues).toEqual([
645
+ {
646
+ code: 'packed_theme_module_changed',
647
+ severity: 'error',
648
+ message:
649
+ 'Theme "ocean" module changed during packing. Keep the built output unchanged in the tarball.',
650
+ },
651
+ ]);
652
+ });
653
+ });
654
+
306
655
  describe('integrationPackCheck', () => {
307
656
  it('returns packable:true for a valid integration with themes', async () => {
308
657
  writePackage({files: ['astryx.integration.mjs', 'themes']});
@@ -337,8 +686,7 @@ describe('integrationPackCheck', () => {
337
686
  {
338
687
  code: 'theme_exports_missing',
339
688
  severity: 'warning',
340
- message:
341
- 'Theme "ocean" has no declared built exports. The package remains source-compatible. To make it importable, run `astryx theme build themes/ocean/oceanTheme.ts` and export "./themes/ocean" plus "./themes/ocean.css" from package.json; `astryx integration add theme ocean` creates those exports for a new theme.',
689
+ message: `Theme "ocean" has no declared built exports. The package remains source-compatible. To make it importable, run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` and export "./themes/ocean" plus "./themes/ocean.css" from package.json; \`${formatCliCommand('integration add theme ocean', tmpDir)}\` creates those exports for a new theme.`,
342
690
  },
343
691
  ]);
344
692
  const cli = runCliVerify();
@@ -509,8 +857,7 @@ describe('integrationPackCheck', () => {
509
857
  {
510
858
  code: 'theme_stylesheet_stale',
511
859
  severity: 'warning',
512
- message:
513
- 'Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. This incomplete export remains packable, but run `astryx theme build themes/ocean/oceanTheme.ts` before adding its matching export.',
860
+ message: `Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. This incomplete export remains packable, but run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before adding its matching export.`,
514
861
  },
515
862
  ]);
516
863
  const cli = runCliVerify();
@@ -543,8 +890,7 @@ describe('integrationPackCheck', () => {
543
890
  {
544
891
  code: 'theme_stylesheet_stale',
545
892
  severity: 'warning',
546
- message:
547
- 'Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. This incomplete export remains packable, but run `astryx theme build themes/ocean/oceanTheme.ts` before adding its matching export.',
893
+ message: `Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. This incomplete export remains packable, but run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before adding its matching export.`,
548
894
  },
549
895
  ]);
550
896
  const cli = runCliVerify();
@@ -617,14 +963,12 @@ describe('integrationPackCheck', () => {
617
963
  {
618
964
  code: 'theme_module_stale',
619
965
  severity: 'error',
620
- message:
621
- 'Theme "ocean" module does not match themes/ocean/oceanTheme.ts. Run `astryx theme build themes/ocean/oceanTheme.ts` before packing.',
966
+ message: `Theme "ocean" module does not match themes/ocean/oceanTheme.ts. Run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before packing.`,
622
967
  },
623
968
  {
624
969
  code: 'theme_stylesheet_stale',
625
970
  severity: 'error',
626
- message:
627
- 'Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. Run `astryx theme build themes/ocean/oceanTheme.ts` before packing.',
971
+ message: `Theme "ocean" stylesheet does not match themes/ocean/oceanTheme.ts. Run \`${formatCliCommand('theme build themes/ocean/oceanTheme.ts', tmpDir)}\` before packing.`,
628
972
  },
629
973
  ]);
630
974
  const cli = runCliVerify();
@@ -1558,6 +1902,23 @@ describe('integrationPackCheck', () => {
1558
1902
  expect(sourceWarnings[0].message).toContain('Card.tsx');
1559
1903
  });
1560
1904
 
1905
+ it('reports template sources without metadata as warnings', async () => {
1906
+ writePackage({
1907
+ manifest:
1908
+ "export default {themes: './themes', templates: './templates'};\n",
1909
+ files: ['astryx.integration.mjs', 'themes', 'templates'],
1910
+ templates: true,
1911
+ });
1912
+ const result = await integrationPackCheck({cwd: tmpDir});
1913
+
1914
+ const sourceWarnings = result.data.issues.filter(
1915
+ issue => issue.code === 'source_without_template_doc',
1916
+ );
1917
+ expect(sourceWarnings).toHaveLength(1);
1918
+ expect(sourceWarnings[0].severity).toBe('warning');
1919
+ expect(sourceWarnings[0].message).toContain('stray.tsx');
1920
+ });
1921
+
1561
1922
  it('cleans up its scratch consumer when npm pack fails', async () => {
1562
1923
  writePackage({
1563
1924
  files: ['astryx.integration.mjs', 'themes'],
@@ -37,6 +37,8 @@ const componentDoc = name =>
37
37
  `export default {type: 'component', name: '${name}', displayName: '${name}', usage: {description: '${name}.'}, props: []};\n`;
38
38
  /** @param {string} name */
39
39
  const componentSource = name => `export function ${name}() { return null; }\n`;
40
+ const templateSource = name =>
41
+ `export default function ${name}() { return null; }\n`;
40
42
  /** @param {string} name */
41
43
  const topic = name =>
42
44
  `export default ${JSON.stringify({
@@ -1131,6 +1133,71 @@ describe('source_without_component_doc fixes hold when followed', () => {
1131
1133
  });
1132
1134
  });
1133
1135
 
1136
+ describe('source_without_template_doc fixes hold when followed', () => {
1137
+ it('adds the named doc, which resolves the warning', async () => {
1138
+ const dir = writePackage({
1139
+ [MANIFEST]: manifest({templates: './templates'}),
1140
+ 'templates/hero.tsx': templateSource('Hero'),
1141
+ 'templates/hero.test.tsx': templateSource('HeroTest'),
1142
+ });
1143
+
1144
+ const message = only(await issuesOf(dir), 'source_without_template_doc');
1145
+ expect(message).toBe(
1146
+ "Template source \"hero.tsx\" has no same-stem metadata file hero.doc.mjs, so `astryx template` never lists it. Fix: add hero.doc.mjs beside it with type: 'page' or 'block'; `astryx docs authoring integration-template-doc` lists its fields. If it is not a template, move it out of the templates root.",
1147
+ );
1148
+
1149
+ const fixed = follow(dir, {
1150
+ write: {
1151
+ 'templates/hero.doc.mjs': `export default {type: 'page', name: 'hero', displayName: 'Hero'};\n`,
1152
+ },
1153
+ });
1154
+ expect(await issuesOf(fixed)).toEqual([]);
1155
+ });
1156
+
1157
+ it('checks a dotted template id, but no test, spec or story file', async () => {
1158
+ const dir = writePackage({
1159
+ [MANIFEST]: manifest({templates: './templates'}),
1160
+ 'templates/landing.page.tsx': templateSource('LandingPage'),
1161
+ 'templates/hero.test.tsx': templateSource('HeroTest'),
1162
+ 'templates/hero.spec.tsx': templateSource('HeroSpec'),
1163
+ 'templates/hero.stories.tsx': templateSource('HeroStories'),
1164
+ });
1165
+
1166
+ const message = only(await issuesOf(dir), 'source_without_template_doc');
1167
+ expect(message).toContain(
1168
+ 'Template source "landing.page.tsx" has no same-stem metadata file landing.page.doc.mjs',
1169
+ );
1170
+
1171
+ const fixed = follow(dir, {
1172
+ write: {
1173
+ 'templates/landing.page.doc.mjs': `export default {type: 'page', name: 'landing.page', displayName: 'Landing'};\n`,
1174
+ },
1175
+ });
1176
+ expect(await issuesOf(fixed)).toEqual([]);
1177
+ });
1178
+
1179
+ it('never flags a helper in a subfolder of the templates root', async () => {
1180
+ const dir = writePackage({
1181
+ [MANIFEST]: manifest({templates: './templates'}),
1182
+ 'templates/hero.doc.mjs': `export default {type: 'page', name: 'hero', displayName: 'Hero'};\n`,
1183
+ 'templates/hero.tsx': templateSource('Hero'),
1184
+ 'templates/hero/HeroCard.tsx': templateSource('HeroCard'),
1185
+ });
1186
+
1187
+ expect(await issuesOf(dir)).toEqual([]);
1188
+ });
1189
+
1190
+ it('accepts a released .template.mjs spec as the metadata', async () => {
1191
+ const dir = writePackage({
1192
+ [MANIFEST]: manifest({templates: './templates'}),
1193
+ 'templates/hero.tsx': templateSource('Hero'),
1194
+ 'templates/hero.template.mjs': `export default {type: 'page', name: 'hero', displayName: 'Hero'};\n`,
1195
+ });
1196
+
1197
+ expect(await issuesOf(dir)).toEqual([]);
1198
+ });
1199
+ });
1200
+
1134
1201
  describe('codemod fixes hold when followed', () => {
1135
1202
  it('moves a stray codemod into a version folder, and renames a mis-named one', async () => {
1136
1203
  const dir = writePackage({
@@ -67,6 +67,14 @@ export type ValidateResult = {
67
67
  */
68
68
  reason?: "no_package_json" | undefined;
69
69
  issues: Issue[];
70
+ /**
71
+ * Information that
72
+ * fails nothing, such as `invalid_cli_command` (a malformed `cliCommand`).
73
+ */
74
+ notes?: {
75
+ code: string;
76
+ message: string;
77
+ }[] | undefined;
70
78
  integration?: import("../../foundation/integrations/integrations.mjs").LoadedIntegration | undefined;
71
79
  };
72
80
  import { validateLoadedIntegration } from '../../foundation/integrations/validate-contributions.mjs';
@@ -35,6 +35,7 @@ import * as fs from 'node:fs';
35
35
  import * as path from 'node:path';
36
36
  import {assertWithin} from '../../foundation/fs/path-safety.mjs';
37
37
  import {integrationDocTypes} from '../docs/_adapter.mjs';
38
+ import {integrationDocConsistency} from '../../foundation/discovery/doc-consistency.mjs';
38
39
  import {
39
40
  THEME_SLUG_RE,
40
41
  unreadThemeFolders,
@@ -55,11 +56,13 @@ import {
55
56
  // The on-disk contribution validators live in foundation: Project and
56
57
  // integration-warnings need them too, and foundation must not depend on api.
57
58
  import {
59
+ INVALID_CLI_COMMAND,
58
60
  validateLoadedIntegration,
59
61
  issueError as error,
60
62
  issueWarning as warning,
61
63
  rootProblem,
62
64
  } from '../../foundation/integrations/validate-contributions.mjs';
65
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
63
66
 
64
67
  export {validateLoadedIntegration};
65
68
 
@@ -75,6 +78,8 @@ export {validateLoadedIntegration};
75
78
  * @property {string} [manifestFile] Absolute path to the loaded manifest.
76
79
  * @property {'no_package_json'} [reason] Why nothing was validated (internal).
77
80
  * @property {Issue[]} issues
81
+ * @property {Array<{code: string, message: string}>} [notes] Information that
82
+ * fails nothing, such as `invalid_cli_command` (a malformed `cliCommand`).
78
83
  * @property {import('../../foundation/integrations/integrations.mjs').LoadedIntegration} [integration]
79
84
  */
80
85
 
@@ -124,7 +129,7 @@ function unreadThemeFolderIssues(packageDir, loaded) {
124
129
  let fix;
125
130
  if (THEME_SLUG_RE.test(name)) {
126
131
  const stem = `${name.replace(/-([a-z0-9])/gu, (_, character) => character.toUpperCase())}Theme`;
127
- fix = `if it is a theme, add ${stem}.ts and ${stem}.doc.mjs to it (\`astryx integration add theme ${name}\` writes both) and move its code into ${stem}.ts; if not, ${hide}.`;
132
+ fix = `if it is a theme, add ${stem}.ts and ${stem}.doc.mjs to it (\`${formatCliCommand(`integration add theme ${name}`, packageDir)}\` writes both) and move its code into ${stem}.ts; if not, ${hide}.`;
128
133
  } else {
129
134
  fix = `${hide}; a theme folder needs a lower-kebab name.`;
130
135
  }
@@ -283,11 +288,14 @@ async function validateAtPackageDir(
283
288
  let unknownKeys;
284
289
  /** @type {string | undefined} */
285
290
  let agentDocsError;
291
+ /** @type {string | undefined} */
292
+ let cliCommandError;
286
293
  try {
287
- ({manifest, unknownKeys, agentDocsError} = await loadManifest(
288
- manifestFile,
289
- `Integration manifest (${path.basename(manifestFile)})`,
290
- ));
294
+ ({manifest, unknownKeys, agentDocsError, cliCommandError} =
295
+ await loadManifest(
296
+ manifestFile,
297
+ `Integration manifest (${path.basename(manifestFile)})`,
298
+ ));
291
299
  } catch (err) {
292
300
  issues.push(error('invalid_manifest', /** @type {any} */ (err).message));
293
301
  return result;
@@ -319,6 +327,8 @@ async function validateAtPackageDir(
319
327
  themes: resolveRoot(manifest.themes),
320
328
  issuesUrl: manifest.issuesUrl,
321
329
  agentDocs: manifest.agentDocs,
330
+ cliCommand: manifest.cliCommand,
331
+ __cliCommandError: cliCommandError,
322
332
  __agentDocsError: agentDocsError,
323
333
  __unknownKeys: unknownKeys,
324
334
  __spec: identity.name,
@@ -329,9 +339,35 @@ async function validateAtPackageDir(
329
339
 
330
340
  // Roots + contribution checks are shared with validateLoadedIntegration so
331
341
  // the everyday-command nudge runs the exact same validators.
332
- issues.push(...(await validateLoadedIntegration(loaded)));
342
+ // A malformed `cliCommand` is an info note beside the issues, not an issue:
343
+ // `integration check --strict` fails on any warning, and a new failure code
344
+ // joins only in a minor release (architecture:cli-surface INV35). Doctor's
345
+ // project check still warns about it.
346
+ for (const issue of await validateLoadedIntegration(loaded)) {
347
+ if (issue.code === INVALID_CLI_COMMAND) {
348
+ (result.notes ??= []).push({code: issue.code, message: issue.message});
349
+ } else {
350
+ issues.push(issue);
351
+ }
352
+ }
333
353
  if (loaded.themes && !rootProblem(loaded.themes))
334
354
  issues.push(...unreadThemeFolderIssues(packageDir, loaded));
355
+ // What the docs say that no reader serves: a prop listed twice, an
356
+ // overlay's text for a prop the doc lacks, an empty or unreachable section,
357
+ // and an overlay of no topic.
358
+ issues.push(
359
+ ...(await integrationDocConsistency(
360
+ {
361
+ components:
362
+ loaded.components && !rootProblem(loaded.components)
363
+ ? loaded.components
364
+ : undefined,
365
+ docs:
366
+ loaded.docs && !rootProblem(loaded.docs) ? loaded.docs : undefined,
367
+ },
368
+ packageDir,
369
+ )),
370
+ );
335
371
  if (scanUnreachable) {
336
372
  issues.push(
337
373
  ...(await findUnreachableContributionIssues(packageDir, loaded)),
@@ -468,6 +504,7 @@ export async function validateIntegration(pkg, options = {}) {
468
504
  const docTypes = integration
469
505
  ? await integrationDocTypes(integration, cwd)
470
506
  : undefined;
507
+ const notes = result.found ? (result.notes ?? []) : [];
471
508
  return {
472
509
  type: 'integration.validate',
473
510
  data: {
@@ -476,9 +513,18 @@ export async function validateIntegration(pkg, options = {}) {
476
513
  validated: result.found,
477
514
  name: result.found ? (result.name ?? null) : null,
478
515
  version: result.found ? (result.version ?? null) : null,
479
- issues: result.reason === 'no_package_json'
480
- ? [{code: 'no_package', severity: 'error', message: 'No package.json found. Run this command inside a package directory.'}]
481
- : result.issues,
516
+ issues:
517
+ result.reason === 'no_package_json'
518
+ ? [
519
+ {
520
+ code: 'no_package',
521
+ severity: 'error',
522
+ message:
523
+ 'No package.json found. Run this command inside a package directory.',
524
+ },
525
+ ]
526
+ : result.issues,
527
+ ...(notes.length > 0 ? {notes} : {}),
482
528
  ...(docTypes ? {docTypes} : {}),
483
529
  },
484
530
  };