@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
@@ -16,8 +16,14 @@ import {Command, Option} from 'commander';
16
16
  import {fileURLToPath} from 'node:url';
17
17
  import * as fs from 'node:fs';
18
18
  import * as path from 'node:path';
19
- import {getCliInvocation} from '../../foundation/env/package-manager.mjs';
19
+ import {formatCliCommand, getCliInvocation} from '../../foundation/env/package-manager.mjs';
20
+ import {hasRecordedProject} from '../../foundation/env/cli-command.mjs';
21
+ import {isOutsideProject} from '../../foundation/env/project-scope.mjs';
20
22
  import {API_VERSION, setJsonMode} from '../../foundation/response/json.mjs';
23
+ import {answeredBy, runChoice} from '../../foundation/release/run-context.mjs';
24
+ import {addCliCommand} from '../../foundation/release/notices.mjs';
25
+ import {projectRootOf} from '../../foundation/release/choose.mjs';
26
+ import {readReleaseFacts} from '../../foundation/release/project.mjs';
21
27
  import {buildManifest} from './lib/manifest.mjs';
22
28
  import {cliError} from './lib/cli-error.mjs';
23
29
  import {emit, section, text, records} from './formatters/index.mjs';
@@ -26,7 +32,9 @@ import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
26
32
  import {installJsonShim} from './lib/json-shim.mjs';
27
33
  import {addDocHelp, markReportsResult} from './lib/define-command.mjs';
28
34
  import {doc as manifestDoc} from './commands/manifest.doc.mjs';
29
- import {isAstryxInitialized} from '../../foundation/agent-docs/agent-docs.mjs';
35
+ import {isAstryxInitialized, isAstryxPromptInReach} from '../../foundation/agent-docs/agent-docs.mjs';
36
+ import {CLI_ROOT} from '../../foundation/fs/paths.mjs';
37
+ import {setupNudge} from '../../foundation/agent-docs/agent-doc-state.mjs';
30
38
  import * as debug from '../../foundation/debug/index.mjs';
31
39
 
32
40
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -63,7 +71,7 @@ export function handleVersionJsonPreflight(argv = process.argv.slice(2)) {
63
71
  // reports the same shape Commander's own `--version` path does.
64
72
  debug.recordCommandResult(debug.NO_RESULT_SET);
65
73
  debug.setOutcome('ok', {exitCode: 0});
66
- console.log(JSON.stringify({apiVersion: API_VERSION, type: 'version', data: {version: pkg.version}}, null, 2));
74
+ console.log(JSON.stringify({apiVersion: API_VERSION, type: 'version', data: {version: pkg.version}, meta: {answeredBy: answeredBy()}}, null, 2));
67
75
  process.exit(0);
68
76
  }
69
77
 
@@ -185,6 +193,31 @@ export async function loadProjectDebugHandler() {
185
193
  }
186
194
  }
187
195
 
196
+ /**
197
+ * Load the project's integrations before a help run, so help prints commands
198
+ * with the `cliCommand` they declare (spec:AST-081 FR5). Help is printed while
199
+ * Commander parses, before any hook, so the preAction load cannot reach it.
200
+ * `Project.load` reads astryx.config and each integration's manifest; it does
201
+ * no discovery. Skipped when the debug preload already loaded the project, and
202
+ * outside a package. Called from the bin before Commander parses.
203
+ *
204
+ * @param {string[]} [argv] arguments after the binary.
205
+ * @returns {Promise<void>}
206
+ */
207
+ export async function loadProjectForHelp(argv = process.argv.slice(2)) {
208
+ const help =
209
+ argv.includes('--help') || argv.includes('-h') || argv[0] === 'help';
210
+ if (!help) return;
211
+ try {
212
+ const cwd = process.cwd();
213
+ if (hasRecordedProject(cwd)) return;
214
+ const {Project} = await import('../../foundation/config/project.mjs');
215
+ await Project.load(cwd);
216
+ } catch {
217
+ // Help prints with the package-manager guess.
218
+ }
219
+ }
220
+
188
221
  /**
189
222
  * Hand the whole invocation to the debug recorder: which command ran, its
190
223
  * positional arguments by name, its options and where each value came from,
@@ -277,6 +310,26 @@ const commands = [
277
310
  ];
278
311
 
279
312
  const SETUP_NUDGE_EXEMPT = new Set(['init', 'agent-docs']);
313
+
314
+ /**
315
+ * Is `cwd` inside the CLI's own source checkout while the CLI runs from it?
316
+ * An installed CLI always lives under `node_modules`; a CLI running from source
317
+ * does not, and its checkout is the pnpm workspace that holds it. Developing
318
+ * Astryx is not an app to set up, so the setup nudge stays quiet there.
319
+ * @param {string} cwd
320
+ * @returns {boolean}
321
+ */
322
+ function inOwnSourceCheckout(cwd) {
323
+ if (CLI_ROOT.split(path.sep).includes('node_modules')) return false;
324
+ let checkout = CLI_ROOT;
325
+ while (!fs.existsSync(path.join(checkout, 'pnpm-workspace.yaml'))) {
326
+ const parent = path.dirname(checkout);
327
+ if (parent === checkout) return false;
328
+ checkout = parent;
329
+ }
330
+ const rel = path.relative(checkout, path.resolve(cwd));
331
+ return rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
332
+ }
280
333
  /** An integration package's manifest: the package is not an app to set up. */
281
334
  const INTEGRATION_MANIFEST_FILES = [
282
335
  'astryx.integration.ts',
@@ -308,7 +361,8 @@ export async function createProgram() {
308
361
  // kit in clients/cli/formatters.
309
362
  program.addHelpText(
310
363
  'after',
311
- '\n' +
364
+ // A function, so the example names the invocation when help is printed.
365
+ () => '\n' +
312
366
  [
313
367
  section(
314
368
  'Output format',
@@ -331,9 +385,13 @@ export async function createProgram() {
331
385
  {fields: ['block', 'shape']},
332
386
  ),
333
387
  text(
334
- 'Grep a field across records, e.g. astryx search button | grep "^command:". ' +
388
+ `Grep a field across records, e.g. ${formatCliCommand('search button')} | grep "^command:". ` +
335
389
  'Errors/warnings go to stderr; use --json for structured parsing.',
336
390
  ),
391
+ text(
392
+ "Global mode: in a project, the project's own CLI answers (this copy hands the run to it); a copy installed for the computer checks for updates once a day and keeps an agent skill in your home folder. " +
393
+ `See ${formatCliCommand('docs global')}.`,
394
+ ),
337
395
  ]
338
396
  .map(block => block.toString())
339
397
  .join('\n\n'),
@@ -430,6 +488,7 @@ export async function createProgram() {
430
488
  // Enriched, self-describing surface (the full manifest payload).
431
489
  manifest,
432
490
  },
491
+ meta: {answeredBy: answeredBy()},
433
492
  }, null, 2));
434
493
  debug.recordCommandResult(
435
494
  debug.resultSet({
@@ -526,10 +585,29 @@ export async function createProgram() {
526
585
  process.exit(1);
527
586
  });
528
587
 
588
+ /**
589
+ * Load the project's integrations before any command runs, so every command
590
+ * it prints starts with the `cliCommand` they declare (the picker reads them
591
+ * synchronously; see foundation/env/cli-command.mjs). Skipped when this
592
+ * process already loaded the project, such as the bin's debug preload. A
593
+ * project that cannot load is the command's to report, never this hook's.
594
+ */
595
+ program.hook('preAction', async () => {
596
+ try {
597
+ const cwd = process.cwd();
598
+ if (hasRecordedProject(cwd)) return;
599
+ const {Project} = await import('../../foundation/config/project.mjs');
600
+ await Project.load(cwd);
601
+ } catch {
602
+ // Best-effort: the picker falls back to its package-manager guess.
603
+ }
604
+ });
605
+
529
606
  /**
530
607
  * Enforcement layer 3 — setup nudge. If this project hasn't run `astryx init`
531
- * yet (no Astryx marker in any agent-doc file — see isAstryxInitialized), remind
532
- * the user/agent that setup is missing.
608
+ * yet (no Astryx marker in any agent-doc file between the project and its
609
+ * repository root — see isAstryxPromptInReach), remind the user/agent that
610
+ * setup is missing.
533
611
  *
534
612
  * Uses `preAction` (not postAction) so it fires for EVERY valid command — even
535
613
  * ones whose action errors or calls process.exit (postAction is skipped then).
@@ -539,7 +617,9 @@ export async function createProgram() {
539
617
  * consumers parse stdout, not stderr — a stderr nudge would not reach them anyway.
540
618
  * The core/cli postinstall layers already nudge at install time regardless of
541
619
  * --json; a machine-readable nudge could later be an envelope field. Also skipped
542
- * for the installer commands themselves and outside a project (no package.json).
620
+ * for the installer commands themselves, outside a project (no package.json,
621
+ * or one that neither installs nor declares Astryx), and inside the CLI's own
622
+ * source checkout when it runs from there.
543
623
  */
544
624
  program.hook('preAction', (thisCommand, actionCommand) => {
545
625
  try {
@@ -547,15 +627,30 @@ export async function createProgram() {
547
627
  if (SETUP_NUDGE_EXEMPT.has(actionCommand.name())) return;
548
628
  const cwd = process.cwd();
549
629
  if (!fs.existsSync(path.join(cwd, 'package.json'))) return; // not a project
630
+ // A package.json that neither installs nor declares Astryx is outside a
631
+ // project: `init` would set up a project the folder does not have
632
+ // (spec AST-081 FR3).
633
+ if (isOutsideProject(cwd)) return;
550
634
  // An integration package is not an app: `init` is not its next step.
551
635
  if (INTEGRATION_MANIFEST_FILES.some(file => fs.existsSync(path.join(cwd, file)))) return;
552
- if (isAstryxInitialized(cwd)) return; // already set up — stay quiet
553
- // Same wording as the core/cli postinstall nudges. #4151's getCliInvocation()
554
- // renders the correct form for THIS project — scoped `npx @astryxdesign/cli`
555
- // one-off, or `<pm> astryx` when installed — never the bare `npx astryx` footgun.
556
- console.error(
557
- `\nNext step: run \`${getCliInvocation(cwd)} init\` to finish setup and install the Astryx agent prompt.`,
558
- );
636
+ if (inOwnSourceCheckout(cwd)) return; // developing Astryx itself, not an app
637
+ if (isAstryxPromptInReach(cwd)) return; // already set up — stay quiet
638
+ // Same wording as the core/cli postinstall nudges. getCliInvocation()
639
+ // renders the correct form for THIS project — an integration's cliCommand,
640
+ // scoped `npx @astryxdesign/cli` one-off, or `<pm> astryx` when installed —
641
+ // never npx with the unscoped name, which fetches an unrelated package.
642
+ // A project with no CLI of its own, answered by another release than its
643
+ // Core's: add the CLI at Core's version first, as the daily hint says,
644
+ // then run that CLI's init (spec AST-081 FR2).
645
+ const choice = runChoice(cwd);
646
+ if (choice.copy === 'starting' && choice.coreVersion && choice.coreVersion !== choice.version) {
647
+ const root = projectRootOf(readReleaseFacts(cwd)) ?? cwd;
648
+ console.error(
649
+ setupNudge(getCliInvocation(root, {installed: true}), {before: addCliCommand(root, choice.coreVersion)}).trimEnd(),
650
+ );
651
+ return;
652
+ }
653
+ console.error(setupNudge(getCliInvocation(cwd)).trimEnd());
559
654
  } catch {
560
655
  // Never let the nudge break a command.
561
656
  }
@@ -608,7 +703,7 @@ export async function createProgram() {
608
703
  );
609
704
  if (program.opts().json) {
610
705
  process.__xdsJsonHandled = true;
611
- console.log(JSON.stringify({apiVersion: API_VERSION, type: 'manifest', data: manifest}, null, 2));
706
+ console.log(JSON.stringify({apiVersion: API_VERSION, type: 'manifest', data: manifest, meta: {answeredBy: answeredBy()}}, null, 2));
612
707
  return;
613
708
  }
614
709
  // Human-readable summary as greppable records (agents should use --json).
@@ -53,6 +53,7 @@
53
53
  import {isJsonMode, jsonError as _jsonError, humanWarn} from '../../../foundation/response/json.mjs';
54
54
  import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
55
55
  import {setOutcome} from '../../../foundation/debug/index.mjs';
56
+ import {formatCliCommand} from '../../../foundation/env/package-manager.mjs';
56
57
 
57
58
  /**
58
59
  * Suggestion object — matches the shape used by API errors and the JSON
@@ -122,7 +123,9 @@ export function cliError(message, options = {}) {
122
123
  if (suggestions?.length) {
123
124
  console.error('');
124
125
  for (const s of suggestions) {
125
- const tag = s.reason ? ` ${s.name} (${s.reason})` : ` ${s.name}`;
126
+ // A suggested command stays bare in JSON and is prefixed here.
127
+ const name = /^astryx(\s|$)/.test(s.name) ? formatCliCommand(s.name) : s.name;
128
+ const tag = s.reason ? ` ${name} (${s.reason})` : ` ${name}`;
126
129
  console.error(tag);
127
130
  }
128
131
  }
@@ -67,7 +67,7 @@ describe('formatFull sub-component rendering', () => {
67
67
  expect(out).not.toContain('undefined');
68
68
  // Points the reader at the sub-component's own docs instead of a blank.
69
69
  expect(out).toMatch(
70
- /(?:astryx|@astryxdesign\/cli) component XDSRadioListItem/,
70
+ /(?:astryx|@astryxdesign\/cli(?:@\S+)?) component XDSRadioListItem/,
71
71
  );
72
72
  });
73
73
 
@@ -180,8 +180,8 @@ export function defineCommand(parent, doc, {fn, action} = {}) {
180
180
  */
181
181
  export function addDocHelp(cmd, doc) {
182
182
  addExitCodesHelp(cmd, doc.exitCodes);
183
- // Rendered when help is shown, so the run prefix (npx astryx, pnpm astryx,
184
- // ...) is looked up then, not on every start.
183
+ // Rendered when help is shown, so the run prefix (pnpm exec astryx, yarn
184
+ // astryx, ...) is looked up then, not on every start.
185
185
  cmd.addHelpText('after', () => {
186
186
  const examples = (doc.examples ?? []).flatMap(({label, cli}) => [
187
187
  ...(label ? [` # ${label}`] : []),
@@ -42,6 +42,7 @@
42
42
  */
43
43
 
44
44
  import {API_VERSION, isJsonMode, toErrorEnvelope} from '../../../foundation/response/json.mjs';
45
+ import {answeredBy} from '../../../foundation/release/run-context.mjs';
45
46
  import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
46
47
  import {setCommand, setOutcome, recordHelp} from '../../../foundation/debug/index.mjs';
47
48
 
@@ -84,7 +85,7 @@ function jsonActive() {
84
85
  * subcommand (e.g. `astryx component --help --json`).
85
86
  *
86
87
  * @param {import('commander').Command} cmd
87
- * @returns {{apiVersion: number, type: 'help', data: object}}
88
+ * @returns {{apiVersion: number, type: 'help', data: object, meta: {answeredBy: {cli: string, core: string | null, copy: 'project' | 'starting' | 'matched' | 'carried' | 'fallback'}}}}
88
89
  */
89
90
  export function buildHelpEnvelope(cmd) {
90
91
  // Reconstruct the fully-qualified command name (e.g. "astryx theme build").
@@ -119,6 +120,7 @@ export function buildHelpEnvelope(cmd) {
119
120
  options,
120
121
  subcommands,
121
122
  },
123
+ meta: {answeredBy: answeredBy()},
122
124
  };
123
125
  }
124
126
 
@@ -50,6 +50,13 @@ export interface ManifestCommand {
50
50
  examples?: string[];
51
51
  /** Documented exit codes: the process exit status and when it occurs. */
52
52
  exitCodes?: {code: number; when: string}[];
53
+ /**
54
+ * What the command does in a folder outside any project: `same` gives the
55
+ * answer it gives in a new project; `refuse` writes nothing and fails, naming
56
+ * the app project or integration package it needs; `own` does something
57
+ * else, which its docs state. Absent on a group that only holds subcommands.
58
+ */
59
+ outsideProject?: 'same' | 'refuse' | 'own';
53
60
  /** Nested subcommands (e.g. `theme build` under `theme`). */
54
61
  subcommands?: ManifestCommand[];
55
62
  }
@@ -64,6 +71,8 @@ export interface CLIManifest {
64
71
  commands: ManifestCommand[];
65
72
  /** Sorted list of fully-qualified command names that support `--json`. */
66
73
  jsonSupported: string[];
74
+ /** What a run may do beyond its command (the hand-off, the daily update check, the agent skill), and the docs topic that explains it. */
75
+ globalMode: {docs: string; summary: string};
67
76
  /** Flat index of response `type` discriminators keyed by command name. */
68
77
  responseTypes: Record<string, string[]>;
69
78
  }
@@ -9,7 +9,8 @@
9
9
  *
10
10
  * Its per-command facts come from the command's own definitions: names,
11
11
  * arguments and options from Commander metadata (program.commands, cmd.options,
12
- * cmd.registeredArguments, cmd.description()); examples from its CommandDoc;
12
+ * cmd.registeredArguments, cmd.description()); examples, exit codes, and what
13
+ * it does outside a project from its CommandDoc;
13
14
  * response `type` discriminators from the returns of the FunctionDoc it wraps
14
15
  * (both attached by `defineCommand`); `--json` support from the JSON_SUPPORTED
15
16
  * allowlist in index.mjs. The hand-kept lists are CLI_LAYER_RESPONSE_TYPES,
@@ -39,6 +40,16 @@ import {API_VERSION} from '../../../foundation/response/json.mjs';
39
40
  import {commandDocsOf} from './define-command.mjs';
40
41
  import {doc as manifestDoc} from '../commands/manifest.doc.mjs';
41
42
 
43
+ /**
44
+ * What a run may do beyond the command it was asked for (spec AST-081;
45
+ * `spec:AST-017` FR14), and where it is explained.
46
+ */
47
+ export const GLOBAL_MODE = Object.freeze({
48
+ docs: 'astryx docs global',
49
+ summary:
50
+ "In a folder that belongs to a project, the project's own CLI answers: this copy hands the run to it. In a project with no CLI of its own, and outside any project, this copy answers. A copy installed for the computer checks the registry for a newer release once a day in the background, and keeps one agent skill file in the home folder.",
51
+ });
52
+
42
53
  /**
43
54
  * Envelopes the CLI layer builds itself, so the wrapped FunctionDoc cannot
44
55
  * declare them: `manifest` wraps no API function, `theme build` batches several
@@ -194,6 +205,10 @@ function describeCommand(cmd, root, jsonSupported) {
194
205
  }));
195
206
  if (exitCodes.length > 0) entry.exitCodes = exitCodes;
196
207
 
208
+ // What the command does outside a project (spec AST-081 FR4). Every command
209
+ // declares it in its CommandDoc; a group that only holds subcommands does not.
210
+ if (docs?.doc.outsideProject) entry.outsideProject = docs.doc.outsideProject;
211
+
197
212
  // Sort subcommands by name for a stable, agent-facing contract — the same
198
213
  // guarantee the top-level command list makes. Otherwise Commander
199
214
  // registration order leaks into the manifest and a pure reorder of
@@ -265,6 +280,7 @@ export function buildManifest(program, opts = {}) {
265
280
  globalOptions: describeGlobalOptions(program),
266
281
  commands,
267
282
  jsonSupported: [...jsonSupported].sort(),
283
+ globalMode: GLOBAL_MODE,
268
284
  // Flat index of every response `type` discriminator the CLI can emit,
269
285
  // keyed by command — lets an agent know what to expect back per call.
270
286
  responseTypes: Object.fromEntries(
@@ -307,3 +307,28 @@ describe('manifest: text projection', () => {
307
307
  for (const key of textKeys) expect(jsonKeys).toContain(key);
308
308
  });
309
309
  });
310
+
311
+ describe('global mode is discoverable (spec:AST-017 FR14)', () => {
312
+ it('the manifest names what a run may do beyond its command, and the docs topic that explains it', () => {
313
+ expect(manifest.globalMode.docs).toBe('astryx docs global');
314
+ for (const word of ['hands the run', 'once a day', 'agent skill']) {
315
+ expect(manifest.globalMode.summary).toContain(word);
316
+ }
317
+ });
318
+
319
+ it('--help carries one line pointing to the global mode docs', () => {
320
+ const help = program.helpInformation() + '';
321
+ let after = '';
322
+ program.emit('afterHelp', {
323
+ error: false,
324
+ write: (/** @type {string} */ s) => {
325
+ after += s;
326
+ },
327
+ });
328
+ const lines = `${help}${after}`
329
+ .split('\n')
330
+ .filter(line => line.startsWith('Global mode:'));
331
+ expect(lines).toHaveLength(1);
332
+ expect(lines[0]).toMatch(/docs global\.$/u);
333
+ });
334
+ });
@@ -20,6 +20,34 @@ export function discoverAgentDocs(targetDir: string): string[];
20
20
  * @returns {boolean}
21
21
  */
22
22
  export function isAstryxInitialized(targetDir?: string): boolean;
23
+ /**
24
+ * Does an agent working in `startDir` already have the Astryx prompt in reach?
25
+ *
26
+ * Coding agents read the agent docs between the repository root and the folder
27
+ * they work in. So inside a git repository, init's block in any folder from
28
+ * `startDir` up to the repository root counts: a workspace package of a
29
+ * monorepo initialized at its root is set up. Outside a repository only
30
+ * `startDir` itself is checked, as {@link isAstryxInitialized} does. Both the
31
+ * per-command nudge and the postinstall nudges ask this.
32
+ *
33
+ * @param {string} [startDir=process.cwd()]
34
+ * @returns {boolean}
35
+ */
36
+ export function isAstryxPromptInReach(startDir?: string): boolean;
37
+ /**
38
+ * The one-line next-step every setup layer prints. Kept here so layer 1
39
+ * (core), layer 2 (cli postinstall) and layer 3 (each command) can never word
40
+ * it differently. Each layer passes the stem from the CLI's picker when it can
41
+ * load it.
42
+ *
43
+ * @param {string} [invocation] the CLI invocation stem, e.g. `pnpm exec astryx`
44
+ * @param {{before?: string | null}} [options] `before`: a command to run
45
+ * first, such as the one that adds the CLI to a project that has none
46
+ * @returns {string}
47
+ */
48
+ export function setupNudge(invocation?: string, { before }?: {
49
+ before?: string | null;
50
+ }): string;
23
51
  /**
24
52
  * Pure decision: should a postinstall print the setup nudge? Shared by BOTH
25
53
  * postinstall layers, so the matrix cannot drift between them, and unit-testable
@@ -61,11 +89,12 @@ export const AGENT_DOC_PATHS: string[];
61
89
  */
62
90
  export const INIT_MARKERS: string[];
63
91
  /**
64
- * The one-line next-step both postinstall nudges print. Kept here so layer 1
65
- * (core) and layer 2 (cli) can never word it differently.
66
- *
67
- * Scoped package form (`@astryxdesign/cli`) — always resolves to us, even before
68
- * the CLI is installed. Bare `npx astryx` would fetch an unrelated look-alike
92
+ * The invocation the setup nudge falls back to when the CLI's picker
93
+ * (`getCliInvocation`) cannot be loaded. Scoped package form
94
+ * (`@astryxdesign/cli`) — always resolves to us, even before the CLI is
95
+ * installed. npx with the unscoped name would fetch an unrelated look-alike
69
96
  * package (see PR #4151).
70
97
  */
71
- export const SETUP_NUDGE: "\nNext step: run `npx @astryxdesign/cli init` to finish setup and install the Astryx agent prompt.\n\n";
98
+ export const SETUP_INVOCATION: "npx @astryxdesign/cli";
99
+ /** The nudge with the fallback invocation. */
100
+ export const SETUP_NUDGE: string;
@@ -97,15 +97,75 @@ export function isAstryxInitialized(targetDir = process.cwd()) {
97
97
  }
98
98
 
99
99
  /**
100
- * The one-line next-step both postinstall nudges print. Kept here so layer 1
101
- * (core) and layer 2 (cli) can never word it differently.
100
+ * Does an agent working in `startDir` already have the Astryx prompt in reach?
102
101
  *
103
- * Scoped package form (`@astryxdesign/cli`) — always resolves to us, even before
104
- * the CLI is installed. Bare `npx astryx` would fetch an unrelated look-alike
102
+ * Coding agents read the agent docs between the repository root and the folder
103
+ * they work in. So inside a git repository, init's block in any folder from
104
+ * `startDir` up to the repository root counts: a workspace package of a
105
+ * monorepo initialized at its root is set up. Outside a repository only
106
+ * `startDir` itself is checked, as {@link isAstryxInitialized} does. Both the
107
+ * per-command nudge and the postinstall nudges ask this.
108
+ *
109
+ * @param {string} [startDir=process.cwd()]
110
+ * @returns {boolean}
111
+ */
112
+ export function isAstryxPromptInReach(startDir = process.cwd()) {
113
+ const start = path.resolve(startDir);
114
+ const repositoryRoot = findRepositoryRoot(start);
115
+ if (!repositoryRoot) return isAstryxInitialized(start);
116
+ for (let dir = start; ; dir = path.dirname(dir)) {
117
+ if (isAstryxInitialized(dir)) return true;
118
+ if (dir === repositoryRoot) return false;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * The nearest folder at or above `start` that holds `.git` (a folder, or the
124
+ * file a worktree uses), or null outside a repository.
125
+ * @param {string} start
126
+ * @returns {string | null}
127
+ */
128
+ function findRepositoryRoot(start) {
129
+ for (let dir = start; ; ) {
130
+ if (fs.existsSync(path.join(dir, '.git'))) return dir;
131
+ const parent = path.dirname(dir);
132
+ if (parent === dir) return null;
133
+ dir = parent;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * The invocation the setup nudge falls back to when the CLI's picker
139
+ * (`getCliInvocation`) cannot be loaded. Scoped package form
140
+ * (`@astryxdesign/cli`) — always resolves to us, even before the CLI is
141
+ * installed. npx with the unscoped name would fetch an unrelated look-alike
105
142
  * package (see PR #4151).
106
143
  */
107
- export const SETUP_NUDGE =
108
- '\nNext step: run `npx @astryxdesign/cli init` to finish setup and install the Astryx agent prompt.\n\n';
144
+ export const SETUP_INVOCATION = 'npx @astryxdesign/cli';
145
+
146
+ /**
147
+ * The one-line next-step every setup layer prints. Kept here so layer 1
148
+ * (core), layer 2 (cli postinstall) and layer 3 (each command) can never word
149
+ * it differently. Each layer passes the stem from the CLI's picker when it can
150
+ * load it.
151
+ *
152
+ * @param {string} [invocation] the CLI invocation stem, e.g. `pnpm exec astryx`
153
+ * @param {{before?: string | null}} [options] `before`: a command to run
154
+ * first, such as the one that adds the CLI to a project that has none
155
+ * @returns {string}
156
+ */
157
+ export function setupNudge(
158
+ invocation = SETUP_INVOCATION,
159
+ {before = null} = {},
160
+ ) {
161
+ const run = before
162
+ ? `\`${before}\`, then \`${invocation} init\``
163
+ : `\`${invocation} init\``;
164
+ return `\nNext step: run ${run} to finish setup and install the Astryx agent prompt.\n\n`;
165
+ }
166
+
167
+ /** The nudge with the fallback invocation. */
168
+ export const SETUP_NUDGE = setupNudge();
109
169
 
110
170
  /**
111
171
  * Pure decision: should a postinstall print the setup nudge? Shared by BOTH
@@ -97,11 +97,11 @@ export function detectStylingSystem(targetDir: string): "stylex" | "tailwind" |
97
97
  * among them. An agent cannot ask for a topic it was never told about, and
98
98
  * `getting-started` is the one it should reach for first.
99
99
  *
100
- * @param {string} version
100
+ * @param {string | null} version the Core version
101
101
  * @param {{coreDir?: string|null, invocation?: string, stylingSystem?: 'stylex'|'tailwind'|'css', zh?: boolean, lang?: string, topics?: string[], agentDocs?: Array<{package: string, append: readonly string[]}>}} [options]
102
102
  * @returns {string}
103
103
  */
104
- export function generateCompressedIndex(version: string, { coreDir, invocation, stylingSystem, topics, agentDocs, }?: {
104
+ export function generateCompressedIndex(version: string | null, { coreDir, invocation, stylingSystem, topics, agentDocs, }?: {
105
105
  coreDir?: string | null;
106
106
  invocation?: string;
107
107
  stylingSystem?: "stylex" | "tailwind" | "css";
@@ -226,4 +226,5 @@ export function installAgentDocs(targetDir: string, { zh, lang, agent, paths, on
226
226
  }): string[];
227
227
  import { discoverAgentDocs } from './agent-doc-state.mjs';
228
228
  import { isAstryxInitialized } from './agent-doc-state.mjs';
229
- export { discoverAgentDocs, isAstryxInitialized };
229
+ import { isAstryxPromptInReach } from './agent-doc-state.mjs';
230
+ export { discoverAgentDocs, isAstryxInitialized, isAstryxPromptInReach };
@@ -42,15 +42,17 @@ import {
42
42
  LEGACY_MARKER_END,
43
43
  discoverAgentDocs,
44
44
  isAstryxInitialized,
45
+ isAstryxPromptInReach,
45
46
  } from './agent-doc-state.mjs';
46
47
 
47
48
  // The agent-doc locations, markers, and the setup-state predicates
48
- // (discoverAgentDocs, isAstryxInitialized) are the ONE canonical contract. They
49
- // live in the dependency-free leaf ./agent-doc-state.mjs so the postinstall
50
- // nudge (enforcement layer 2) can load them safely at install time. Re-exported
51
- // here so existing importers (init/upgrade commands, the layer-3 nudge in
52
- // clients/cli/index.mjs, tests) keep their `from './agent-docs.mjs'` paths.
53
- export {discoverAgentDocs, isAstryxInitialized};
49
+ // (discoverAgentDocs, isAstryxInitialized, isAstryxPromptInReach) are the ONE
50
+ // canonical contract. They live in the dependency-free leaf
51
+ // ./agent-doc-state.mjs so the postinstall nudge (enforcement layer 2) can load
52
+ // them safely at install time. Re-exported here so existing importers
53
+ // (init/upgrade commands, the layer-3 nudge in clients/cli/index.mjs, tests)
54
+ // keep their `from './agent-docs.mjs'` paths.
55
+ export {discoverAgentDocs, isAstryxInitialized, isAstryxPromptInReach};
54
56
 
55
57
  const MAX_PROJECT_AGENT_DOC_LINES = 32;
56
58
  const MANAGED_MARKER_TEXT = /(?:ASTRYX|XDS):(START|END)/u;
@@ -377,7 +379,7 @@ export function detectStylingSystem(targetDir) {
377
379
  * among them. An agent cannot ask for a topic it was never told about, and
378
380
  * `getting-started` is the one it should reach for first.
379
381
  *
380
- * @param {string} version
382
+ * @param {string | null} version the Core version
381
383
  * @param {{coreDir?: string|null, invocation?: string, stylingSystem?: 'stylex'|'tailwind'|'css', zh?: boolean, lang?: string, topics?: string[], agentDocs?: Array<{package: string, append: readonly string[]}>}} [options]
382
384
  * @returns {string}
383
385
  */
@@ -418,9 +420,9 @@ export function generateCompressedIndex(
418
420
  // Best-effort: component count is cosmetic; fall back to the default.
419
421
  }
420
422
  }
421
-
422
- // Header — state the CLI prefix once; commands below are shown as `astryx <cmd>`.
423
423
  lines.push(`Astryx v${version} · ${componentCount} components`);
424
+
425
+ // State the CLI prefix once; commands below are shown as `astryx <cmd>`.
424
426
  lines.push(
425
427
  `CLI: run every command as \`${run} <cmd>\` (shown below as \`astryx ...\`).`,
426
428
  );