@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
@@ -43,6 +43,16 @@ import {
43
43
  resolvePackageDir,
44
44
  } from '../integrations/integrations.mjs';
45
45
  import {loadAutolinkCandidates} from '../integrations/autolink.mjs';
46
+ import {
47
+ computerInstallRoots,
48
+ loadComputerIntegrations,
49
+ scanComputerIntegrations,
50
+ } from '../integrations/computer-integrations.mjs';
51
+ import {relativeWithin, samePath} from '../fs/path-compare.mjs';
52
+ import {isOutsideProject} from '../env/project-scope.mjs';
53
+ import {cliVersion} from '../release/run-context.mjs';
54
+ import {isGlobalCopy} from '../release/choose.mjs';
55
+ import {astryxCommandsOnSearchPath} from '../env/search-path.mjs';
46
56
  import {resolveProviders} from '../integrations/provider-resolution.mjs';
47
57
  import {
48
58
  setProject as setDebugProject,
@@ -55,7 +65,7 @@ import {
55
65
  discoverValidIntegrationComponents,
56
66
  } from '../discovery/component-discovery.mjs';
57
67
  import {resolveComponentReplacements} from '../discovery/component-replacement.mjs';
58
- import {findCoreDir} from '../fs/paths.mjs';
68
+ import {CLI_ROOT, findCoreDir, findProjectCoreDir} from '../fs/paths.mjs';
59
69
  import {
60
70
  applyTemplateReplacements,
61
71
  effectiveTemplateDiscovery,
@@ -78,6 +88,7 @@ import {
78
88
  selectIntegrationCodemods,
79
89
  } from '../../assets/codemods/integration-discovery.mjs';
80
90
  import {validateLoadedIntegration} from '../integrations/validate-contributions.mjs';
91
+ import {recordDeclaredCliCommands} from '../env/cli-command.mjs';
81
92
  import {
82
93
  InMemoryConfigCache,
83
94
  cacheKey,
@@ -100,6 +111,80 @@ function errorMessage(err) {
100
111
  return message == null ? String(err) : String(message);
101
112
  }
102
113
 
114
+ /**
115
+ * The computer-level integrations (spec AST-081 FR12), read from package.json
116
+ * files only. Outside a project, those installed beside the running CLI;
117
+ * inside one, where the project's own CLI may be the copy that answers, those
118
+ * installed beside the CLI installed for the computer (see globalCliRoot).
119
+ * @param {string} [cwd]
120
+ * @returns {import('../integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]}
121
+ */
122
+ export function computerIntegrationCandidates(cwd = process.cwd()) {
123
+ try {
124
+ const cliRoot = isOutsideProject(cwd) ? CLI_ROOT : globalCliRoot(cwd);
125
+ return cliRoot
126
+ ? scanComputerIntegrations({cliRoot, release: cliVersion()})
127
+ : [];
128
+ } catch {
129
+ return [];
130
+ }
131
+ }
132
+
133
+ /**
134
+ * The CLI package whose install root holds the computer-level integrations
135
+ * for a folder inside a project: this copy when it was installed outside the
136
+ * project (installed for the computer, or in a tool's package set), else the
137
+ * first `astryx` on the search path that is installed for the computer. A
138
+ * project's own CLI and a release from the per-user cache are neither.
139
+ * @param {string} cwd
140
+ * @returns {string | null}
141
+ */
142
+ function globalCliRoot(cwd) {
143
+ let folder = path.resolve(cwd);
144
+ try {
145
+ folder = fs.realpathSync(folder);
146
+ } catch {
147
+ // A folder that cannot be resolved is compared as written.
148
+ }
149
+ const own = computerInstallRoots(CLI_ROOT);
150
+ if (
151
+ own.length > 0 &&
152
+ !own.some(
153
+ root => samePath(root, folder) || relativeWithin(root, folder) != null,
154
+ )
155
+ ) {
156
+ return CLI_ROOT;
157
+ }
158
+ for (const command of astryxCommandsOnSearchPath()) {
159
+ if (command.cliRoot && isGlobalCopy(command.cliRoot)) {
160
+ return command.cliRoot;
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+
166
+ /**
167
+ * The computer-level integrations a project could add (spec AST-081 FR12):
168
+ * those it does not install, whose peer ranges admit the release that
169
+ * answers, and whose manifest loads.
170
+ * @param {string} cwd
171
+ * @param {Set<string>} installed package names the project loads or declares
172
+ * @returns {Promise<import('../integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]>}
173
+ */
174
+ export async function availableComputerIntegrations(cwd, installed) {
175
+ const candidates = computerIntegrationCandidates(cwd).filter(
176
+ c => !c.incompatible && !installed.has(c.name),
177
+ );
178
+ if (candidates.length === 0) return [];
179
+ const loaded = await loadComputerIntegrations(candidates);
180
+ const usable = new Set(
181
+ loaded.flatMap(entry =>
182
+ entry.integration && !entry.integration.__loadError ? [entry.spec] : [],
183
+ ),
184
+ );
185
+ return candidates.filter(c => usable.has(c.name));
186
+ }
187
+
103
188
  /**
104
189
  * Load the configured integrations one at a time, so a package that cannot
105
190
  * load at all (not installed, no manifest, more than one manifest, not a bare
@@ -338,6 +423,12 @@ export class Project {
338
423
  #cache;
339
424
  /** @type {string} */
340
425
  #hash;
426
+ /**
427
+ * Which Core the project reads: `any`, its installed Core else the Core the
428
+ * answering release carries, or `project`, its installed Core only.
429
+ * @type {'any' | 'project'}
430
+ */
431
+ #core = 'any';
341
432
  /** @type {ProjectIntegrationIssue[]} */
342
433
  #issues = [];
343
434
  /**
@@ -360,6 +451,7 @@ export class Project {
360
451
  * @param {import('../integrations/integrations.mjs').LoadedIntegration[]} init.loadedIntegrations
361
452
  * @param {import('./config-cache.mjs').ConfigCache} init.cache
362
453
  * @param {string} init.hash config content hash
454
+ * @param {'any' | 'project'} [init.core] which Core it reads
363
455
  */
364
456
  constructor({
365
457
  cwd,
@@ -369,7 +461,9 @@ export class Project {
369
461
  loadedIntegrations,
370
462
  cache,
371
463
  hash,
464
+ core = 'any',
372
465
  }) {
466
+ this.#core = core;
373
467
  this.#cwd = cwd;
374
468
  this.#configPath = configPath;
375
469
  this.#config = config;
@@ -384,11 +478,15 @@ export class Project {
384
478
  * and loads the configured integrations. Discovery is NOT run here — it is
385
479
  * lazy and memoized on the returned instance.
386
480
  *
481
+ * `core: 'project'` reads only the project's installed Core, never the Core
482
+ * the answering release carries: the commands that judge or change a
483
+ * project (`doctor`, `swizzle`, `upgrade`) load it so (spec AST-081 FR3).
484
+ *
387
485
  * @param {string} [cwd]
388
- * @param {{cache?: import('./config-cache.mjs').ConfigCache, fresh?: boolean}} [options]
486
+ * @param {{cache?: import('./config-cache.mjs').ConfigCache, fresh?: boolean, core?: 'any' | 'project'}} [options]
389
487
  * @returns {Promise<Project>}
390
488
  */
391
- static async load(cwd = process.cwd(), {cache, fresh = false} = {}) {
489
+ static async load(cwd = process.cwd(), {cache, fresh = false, core = 'any'} = {}) {
392
490
  const resolvedCache = fresh
393
491
  ? new InMemoryConfigCache()
394
492
  : (cache ?? new InMemoryConfigCache());
@@ -440,7 +538,26 @@ export class Project {
440
538
  // existing consumer command doubles as the author's preview. A local copy
441
539
  // replaces the same installed package in place, preserving configured
442
540
  // precedence while making the source being edited authoritative.
443
- const localIntegration = await loadLocalIntegrationSafely(projectDir, fresh);
541
+ const localIntegration = await loadLocalIntegrationSafely(
542
+ projectDir,
543
+ fresh,
544
+ );
545
+
546
+ // Outside a project, the integrations installed beside the running CLI
547
+ // load too (spec AST-081 FR12); a package the folder already loads keeps
548
+ // its own copy. Inside a project they never load.
549
+ const computer = isOutsideProject(cwd)
550
+ ? await loadComputerIntegrations(computerIntegrationCandidates(cwd), {
551
+ fresh,
552
+ exclude: [
553
+ ...loadedIntegrations.map(integration => integration.name),
554
+ ...autolinked.flatMap(candidate =>
555
+ candidate.integration ? [candidate.integration.name] : [],
556
+ ),
557
+ ...(localIntegration ? [localIntegration.name] : []),
558
+ ],
559
+ })
560
+ : [];
444
561
 
445
562
  // Autolinked and local packages can claim a provider ID that a configured
446
563
  // package already holds, so identity is resolved once over the final set.
@@ -451,6 +568,7 @@ export class Project {
451
568
  spec: integration.__spec,
452
569
  })),
453
570
  ...autolinked,
571
+ ...computer,
454
572
  ...(localIntegration
455
573
  ? [
456
574
  {
@@ -462,6 +580,9 @@ export class Project {
462
580
  : []),
463
581
  ]);
464
582
  loadedIntegrations = resolution.integrations;
583
+ // The picker (getCliInvocation) is synchronous, so the commands these
584
+ // integrations declare are recorded here, where they become known.
585
+ recordDeclaredCliCommands(projectDir, loadedIntegrations);
465
586
 
466
587
  // The debug recorder resolves its settings synchronously, long before any
467
588
  // command gets here, so this is where a project's `debug` block gets a
@@ -500,6 +621,7 @@ export class Project {
500
621
  loadedIntegrations,
501
622
  cache: resolvedCache,
502
623
  hash,
624
+ core,
503
625
  });
504
626
  PROVIDER_LEDGERS.set(project, resolution.ledger);
505
627
  return project;
@@ -634,6 +756,18 @@ export class Project {
634
756
  }
635
757
  }
636
758
 
759
+ /**
760
+ * The Core this project reads: its installed Core, else, unless it was
761
+ * loaded with `core: 'project'`, the Core the answering release carries
762
+ * (spec AST-081 FR3). Null when there is none.
763
+ * @returns {string | null}
764
+ */
765
+ coreDir() {
766
+ return this.#core === 'project'
767
+ ? findProjectCoreDir(this.#cwd)
768
+ : findCoreDir(this.#cwd);
769
+ }
770
+
637
771
  /**
638
772
  * Core + integration component ownership records. Wraps
639
773
  * discoverOwnedComponents for core and discoverIntegrationComponents (via
@@ -645,7 +779,7 @@ export class Project {
645
779
  */
646
780
  async components() {
647
781
  return this.#memo('components', async () => {
648
- const coreDir = findCoreDir(this.#cwd);
782
+ const coreDir = this.coreDir();
649
783
  /** @type {Array<{name: string, package: string, group: string|null, docPath: string|null, sourcePath: string|null, issuesUrl: string|undefined}>} */
650
784
  const records = [];
651
785
 
@@ -696,7 +830,7 @@ export class Project {
696
830
  async componentReplacements() {
697
831
  return this.#memo('componentReplacements', async () => {
698
832
  const replacements = await resolveComponentReplacements(
699
- findCoreDir(this.#cwd),
833
+ this.coreDir(),
700
834
  this.#loadedIntegrations,
701
835
  );
702
836
  for (const finding of replacements.findings) {
@@ -846,7 +980,7 @@ export class Project {
846
980
  const replacing = new Map();
847
981
  if (this.#loadedIntegrations.length > 0) {
848
982
  const {active} = await resolveComponentReplacements(
849
- findCoreDir(this.#cwd),
983
+ this.coreDir(),
850
984
  this.#loadedIntegrations,
851
985
  );
852
986
  for (const each of active) {
@@ -943,7 +1077,10 @@ export class Project {
943
1077
  // nothing and a reader gets the topic it was meant to replace.
944
1078
  if (errors.length > 0) {
945
1079
  for (const e of errors) {
946
- catalog.addIssue({package: integration.name ?? pkg, message: e.message});
1080
+ catalog.addIssue({
1081
+ package: integration.name ?? pkg,
1082
+ message: e.message,
1083
+ });
947
1084
  }
948
1085
  continue;
949
1086
  }
@@ -2,9 +2,11 @@
2
2
 
3
3
  import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
4
4
  import * as fs from 'node:fs';
5
+ import * as os from 'node:os';
5
6
  import * as path from 'node:path';
6
7
  import {Project, DEFAULT_ISSUES_URL, findConfigPath} from './project.mjs';
7
8
  import {InMemoryConfigCache} from './config-cache.mjs';
9
+ import {getCliInvocation} from '../env/package-manager.mjs';
8
10
  import * as componentDiscovery from '../discovery/component-discovery.mjs';
9
11
  import {discoverCoreTemplates} from '../discovery/template-adapter.mjs';
10
12
 
@@ -31,6 +33,7 @@ function scaffold({
31
33
  docs = null,
32
34
  unknownKeys = null,
33
35
  agentDocs = null,
36
+ cliCommand = null,
34
37
  integrationIssuesUrl = 'https://example.com/widgets/issues',
35
38
  } = {}) {
36
39
  fs.writeFileSync(
@@ -57,6 +60,7 @@ function scaffold({
57
60
  if (withCodemods) manifest.codemods = './codemods';
58
61
  if (docs) manifest.docs = './docs';
59
62
  if (agentDocs != null) manifest.agentDocs = agentDocs;
63
+ if (cliCommand != null) manifest.cliCommand = cliCommand;
60
64
  if (unknownKeys) Object.assign(manifest, unknownKeys);
61
65
  if (integrationIssuesUrl) manifest.issuesUrl = integrationIssuesUrl;
62
66
  fs.writeFileSync(
@@ -287,6 +291,68 @@ describe('Project.load', () => {
287
291
  });
288
292
  });
289
293
 
294
+ describe('Project.load and the cliCommand an integration declares', () => {
295
+ it('records it, so the picker prints commands with it', async () => {
296
+ scaffold({cliCommand: 'acme astryx'});
297
+ const project = await Project.load(tmpDir);
298
+ expect(project.loadedIntegrations[0].cliCommand).toBe('acme astryx');
299
+ expect(getCliInvocation(tmpDir)).toBe('acme astryx');
300
+ });
301
+
302
+ it('ignores an invalid one with a warning and keeps the rest of the package', async () => {
303
+ scaffold({cliCommand: ' acme astryx\n'});
304
+ const project = await Project.load(tmpDir);
305
+ const [widgets] = project.loadedIntegrations;
306
+ expect(widgets.__loadError).toBeUndefined();
307
+ expect(widgets.cliCommand).toBeUndefined();
308
+ expect(widgets.components).toBeDefined();
309
+ expect(getCliInvocation(tmpDir)).not.toContain('acme astryx');
310
+ const issues = await project.issues();
311
+ expect(issues).toContainEqual(
312
+ expect.objectContaining({
313
+ code: 'invalid_cli_command',
314
+ severity: 'warning',
315
+ }),
316
+ );
317
+ });
318
+
319
+ it('drops a previous load once the declaration is gone', async () => {
320
+ scaffold({cliCommand: 'acme astryx'});
321
+ await Project.load(tmpDir);
322
+ scaffold();
323
+ await Project.load(tmpDir, {fresh: true});
324
+ expect(getCliInvocation(tmpDir)).not.toBe('acme astryx');
325
+ });
326
+ });
327
+
328
+ describe("Project.load({core: 'project'})", () => {
329
+ it('reads only the installed Core, never the Core the answering release carries', async () => {
330
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-project-core-'));
331
+ try {
332
+ fs.writeFileSync(
333
+ path.join(dir, 'package.json'),
334
+ JSON.stringify({name: 'a', dependencies: {'@astryxdesign/core': '^0.7.0'}}),
335
+ );
336
+ const any = await Project.load(dir);
337
+ const own = await Project.load(dir, {core: 'project'});
338
+ // The CLI in this repository carries the Core beside it.
339
+ expect(any.coreDir()).not.toBeNull();
340
+ expect(own.coreDir()).toBeNull();
341
+ expect((await own.components()).filter(c => c.package === '@astryxdesign/core')).toEqual([]);
342
+
343
+ const core = path.join(dir, 'node_modules', '@astryxdesign', 'core');
344
+ fs.mkdirSync(core, {recursive: true});
345
+ fs.writeFileSync(
346
+ path.join(core, 'package.json'),
347
+ JSON.stringify({name: '@astryxdesign/core', version: '0.7.0'}),
348
+ );
349
+ expect((await Project.load(dir, {core: 'project'})).coreDir()).toBe(fs.realpathSync(core));
350
+ } finally {
351
+ fs.rmSync(dir, {recursive: true, force: true});
352
+ }
353
+ });
354
+ });
355
+
290
356
  describe('findConfigPath', () => {
291
357
  it('rejects multiple config files at the same root', () => {
292
358
  fs.writeFileSync(
@@ -16,6 +16,7 @@
16
16
  import * as fs from 'node:fs';
17
17
  import * as path from 'node:path';
18
18
  import {assertWithin, PathSafetyError} from '../fs/path-safety.mjs';
19
+ import {formatCliCommand} from '../env/package-manager.mjs';
19
20
 
20
21
  export const LOCAL_THEME_ROOT = './src/themes';
21
22
  export const THEME_MODULE_BASENAME = 'astryx-themes';
@@ -106,7 +107,7 @@ export function themeModuleCandidates(projectDir) {
106
107
  function validThemeRecord(value, label) {
107
108
  if (!isRecord(value) || !isRecord(value.themes)) {
108
109
  throw new ThemeStateError(
109
- `${label} must carry a static ${THEME_RECORD_MARKER} header. Regenerate it with \`astryx theme add <slug>\`.`,
110
+ `${label} must carry a static ${THEME_RECORD_MARKER} header. Regenerate it with \`${formatCliCommand('theme add <slug>')}\`.`,
110
111
  );
111
112
  }
112
113
  const keys = Object.keys(value);
@@ -139,7 +140,7 @@ function validThemeRecord(value, label) {
139
140
  !THEME_SLUG_RE.test(value.defaultThemeSlug)
140
141
  ) {
141
142
  throw new ThemeStateError(
142
- `${label} defaultThemeSlug must be a lowercase kebab-case slug. Regenerate it with \`astryx theme use <slug>\`.`,
143
+ `${label} defaultThemeSlug must be a lowercase kebab-case slug. Regenerate it with \`${formatCliCommand('theme use <slug>')}\`.`,
143
144
  );
144
145
  }
145
146
  return {themes, defaultSlug: value.defaultThemeSlug};
@@ -159,7 +160,7 @@ export function parseThemeModuleRecord(source, label = 'theme module') {
159
160
  .filter(line => /^\s*\*\s*@astryx-theme-record\s+/u.test(line));
160
161
  if (recordLines.length !== 1) {
161
162
  throw new ThemeStateError(
162
- `${label} must carry exactly one static ${THEME_RECORD_MARKER} header. Regenerate it with \`astryx theme add <slug>\`.`,
163
+ `${label} must carry exactly one static ${THEME_RECORD_MARKER} header. Regenerate it with \`${formatCliCommand('theme add <slug>')}\`.`,
163
164
  );
164
165
  }
165
166
  const payload = recordLines[0].replace(
@@ -318,7 +319,7 @@ export function readThemeState(cwd = process.cwd()) {
318
319
  export function renderThemeModule(themes, defaultSlug, typescript) {
319
320
  if (!themes.some(theme => theme.slug === defaultSlug)) {
320
321
  throw new ThemeStateError(
321
- `Default theme "${defaultSlug}" is not added. Run \`astryx theme add ${defaultSlug}\` first.`,
322
+ `Default theme "${defaultSlug}" is not added. Run \`${formatCliCommand(`theme add ${defaultSlug}`)}\` first.`,
322
323
  );
323
324
  }
324
325
  /** @type {string[]} */
@@ -193,7 +193,7 @@ export function buildAuthoringReferenceDoc(docs) {
193
193
  title: 'Authoring Reference',
194
194
  category: 'guide',
195
195
  description:
196
- 'Every file an integration author writes, field by field: the integration manifest, astryx.config, codemods, identity, and each doc type.',
196
+ 'Every file an integration author writes, field by field: the integration manifest, astryx.config, codemods, identity, and each doc type. The step-by-step guides are under `astryx docs cli/integrations`.',
197
197
  sections: docs.map(selfDocSection),
198
198
  });
199
199
  }
@@ -25,6 +25,7 @@ import {
25
25
  oversizedDocSections,
26
26
  } from './docs-output-budget.mjs';
27
27
  import {routeSegment} from './docs-section-key.mjs';
28
+ import {formatCliCommand} from '../env/package-manager.mjs';
28
29
 
29
30
  /** The directories, relative to the CLI root, that hold the CLI's own docs. */
30
31
  export const CLI_SELF_DOC_DIRS = [
@@ -187,6 +188,19 @@ function sentence(text, more) {
187
188
  return more && text !== '' && !/[.!?:]$/.test(text) ? `${text}.` : text;
188
189
  }
189
190
 
191
+ /**
192
+ * The line a command doc prints for what it does outside a project (spec
193
+ * AST-081 FR4). A group that only holds subcommands declares nothing and
194
+ * prints nothing.
195
+ * @type {Record<string, string>}
196
+ */
197
+ const OUTSIDE_PROJECT_TEXT = {
198
+ same: "Outside a project (`same`): it answers as it would in a new project on this release, reading this release's Core, as it does in a project with nothing installed: the one installed beside the CLI, else one in the per-user cache, which a global install downloads in the background after a command run online (in CI, the first command that needs it downloads it).",
199
+ refuse:
200
+ 'Outside a project (`refuse`): it writes nothing and fails, naming the app project or integration package it needs.',
201
+ own: 'Outside a project (`own`): it does what the description above says it does outside a project.',
202
+ };
203
+
190
204
  /** @param {any[]} notes */
191
205
  function noteBlocks(notes) {
192
206
  return (notes ?? []).filter(note => TOPIC_BLOCKS.has(note?.type));
@@ -251,6 +265,8 @@ function commandSection(cmd, index) {
251
265
  rows: exitCodes.map((/** @type {any} */ e) => [String(e.code), e.when]),
252
266
  });
253
267
  }
268
+ const outside = OUTSIDE_PROJECT_TEXT[cmd.outsideProject];
269
+ if (outside) content.push({type: 'prose', text: outside});
254
270
  // Links name docs by identity; the route in each command is derived when
255
271
  // the doc is read (spec:AST-047 FR9).
256
272
  const subcommands = (cmd.subcommands ?? []).filter(
@@ -318,7 +334,8 @@ function functionSection(fn, index) {
318
334
  // A Default column only when some parameter declares a default, so a
319
335
  // function with none keeps a three-column table.
320
336
  const defaults = params.some(
321
- (/** @type {any} */ p) => typeof p.default === 'string' && p.default !== '',
337
+ (/** @type {any} */ p) =>
338
+ typeof p.default === 'string' && p.default !== '',
322
339
  );
323
340
  content.push({
324
341
  type: 'table',
@@ -475,13 +492,13 @@ export async function auditCliSelfDocs({
475
492
  else {
476
493
  misfiled.push({
477
494
  source,
478
- message: `${source} has namespace "authoring", but \`astryx docs authoring\` does not list it`,
495
+ message: `${source} has namespace "authoring", but \`${formatCliCommand('docs authoring')}\` does not list it`,
479
496
  });
480
497
  }
481
498
  } else if (inAuthoring) {
482
499
  misfiled.push({
483
500
  source,
484
- message: `${source} is read in \`astryx docs authoring\`, but its namespace is "${namespace}"`,
501
+ message: `${source} is read in \`${formatCliCommand('docs authoring')}\`, but its namespace is "${namespace}"`,
485
502
  });
486
503
  } else {
487
504
  treeDocs.push(doc);
@@ -25,6 +25,7 @@ import {
25
25
  discoverCliSelfDocSources,
26
26
  } from './cli-self-docs.mjs';
27
27
  import {routeSegment} from './docs-section-key.mjs';
28
+ import {formatCliCommand} from '../env/package-manager.mjs';
28
29
 
29
30
  const SLOW = 60_000;
30
31
 
@@ -145,8 +146,8 @@ describe('auditCliSelfDocs', () => {
145
146
  });
146
147
  const result = await audit(root, ['y/y.doc.mjs', 'z/z.doc.mjs']);
147
148
  expect(result.misfiled.map(entry => entry.message)).toEqual([
148
- 'authoring/x/x.doc.mjs has namespace "authoring", but `astryx docs authoring` does not list it',
149
- 'authoring/y/y.doc.mjs is read in `astryx docs authoring`, but its namespace is "cli/api"',
149
+ `authoring/x/x.doc.mjs has namespace "authoring", but \`${formatCliCommand('docs authoring')}\` does not list it`,
150
+ `authoring/y/y.doc.mjs is read in \`${formatCliCommand('docs authoring')}\`, but its namespace is "cli/api"`,
150
151
  ]);
151
152
  expect(result.authoring).toBe(1);
152
153
  expect(result.tree).toBe(0);
@@ -30,6 +30,7 @@ import {
30
30
  COMPONENT_REPLACES_CLI,
31
31
  componentReplacesCliProblem,
32
32
  } from '../integrations/cli-requirement.mjs';
33
+ import {formatCliCommand} from '../env/package-manager.mjs';
33
34
 
34
35
  /**
35
36
  * @typedef {import('../integrations/integrations.mjs').LoadedIntegration} LoadedIntegration
@@ -292,7 +293,7 @@ export async function resolveComponentReplacements(
292
293
  'missing_component_replacement_target',
293
294
  differentCase
294
295
  ? `Component "${name}" replaces "${replaces}", which is not a Core component name. Core names it "${differentCase}".`
295
- : `Component "${name}" replaces "${replaces}", which is not a Core component. Run \`astryx component --list\` for Core component names.`,
296
+ : `Component "${name}" replaces "${replaces}", which is not a Core component. Run \`${formatCliCommand('component --list')}\` for Core component names.`,
296
297
  );
297
298
  if (declaration.optedIn) {
298
299
  const key = differentCase ?? replaces;