@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
@@ -42,7 +42,7 @@ export type InitRunData = {
42
42
  */
43
43
  templatePath: string | null;
44
44
  /**
45
- * Whether the getting-started "Next steps" were emitted (default mode).
45
+ * Whether the getting-started "Next steps" were emitted (default mode inside a project; false outside one).
46
46
  */
47
47
  nextSteps: boolean;
48
48
  };
@@ -59,6 +59,47 @@ export type InitRemoveResponse = {
59
59
  removed: boolean;
60
60
  };
61
61
  };
62
+ /**
63
+ * What `init --user` did with one file of the computer-level agent text.
64
+ * `written`: created or refreshed. `unchanged`: already this release's text.
65
+ * `removed`: deleted (with `--remove-agents`). `absent`: nothing to remove.
66
+ * `kept`: a file left as it is, because a person edited it or Astryx did not
67
+ * write it (see `reason`).
68
+ */
69
+ export type InitUserAction = "written" | "linked" | "unchanged" | "removed" | "absent" | "kept";
70
+ export type InitUserFile = {
71
+ /**
72
+ * Absolute path in the home folder: the skill file,
73
+ * or a link to its folder.
74
+ */
75
+ path: string;
76
+ action: InitUserAction;
77
+ /**
78
+ * Only on `kept`: `edited`, the
79
+ * text no longer matches the hash Astryx recorded in it; `not-astryx`, it
80
+ * has no Astryx markers or is a symlink, or a link target holds something
81
+ * Astryx did not create.
82
+ */
83
+ reason?: "edited" | "not-astryx" | undefined;
84
+ };
85
+ export type InitUserData = {
86
+ /**
87
+ * One row per path acted on: `~/.agents/skills/astryx/SKILL.md` first, then each link to its folder: `~/.claude/skills/astryx` always, and another agent's skills folder when that agent's folder exists (`linked`, or `unchanged` when the link is already there). Removal removes the file and the links Astryx made.
88
+ */
89
+ files: InitUserFile[];
90
+ /**
91
+ * The command the text tells agents to run: `astryx`, or the host's command when a host started the run.
92
+ */
93
+ command: string;
94
+ /**
95
+ * Non-fatal notes, such as no `astryx` on the computer that runs the Astryx CLI.
96
+ */
97
+ warnings: string[];
98
+ };
99
+ export type InitUserResponse = {
100
+ type: "init.user";
101
+ data: InitUserData;
102
+ };
62
103
  /**
63
104
  * Options for `init()`.
64
105
  */
@@ -72,11 +113,15 @@ export type InitOptions = {
72
113
  */
73
114
  all?: boolean | undefined;
74
115
  /**
75
- * Remove the managed agent-docs block instead of installing.
116
+ * Remove the managed agent-docs block instead of installing; with `user`, remove the computer-level agent text.
76
117
  */
77
118
  removeAgents?: boolean | undefined;
78
119
  /**
79
- * Agent preset: claude, cursor, codex, hermes, muse, all.
120
+ * Write the computer-level agent text (`~/.agents/skills/astryx/SKILL.md`, linked into `~/.claude/skills` and the skill folders of other installed tools, with a copy for Continue) instead of setting up the folder.
121
+ */
122
+ user?: boolean | undefined;
123
+ /**
124
+ * Agent preset: claude, cursor, codex, hermes, muse, all. Refused with `user`.
80
125
  */
81
126
  agent?: string | undefined;
82
127
  /**
@@ -17,7 +17,7 @@
17
17
  * @property {string | null} themeTemplatePath Relative output path when `themeTemplate === 'created'`.
18
18
  * @property {'workflow' | 'created' | 'skipped' | null} template Template outcome (`workflow` is the CLI default; `created`/`skipped` are programmatic).
19
19
  * @property {string | null} templatePath Relative output path when `template === 'created'`.
20
- * @property {boolean} nextSteps Whether the getting-started "Next steps" were emitted (default mode).
20
+ * @property {boolean} nextSteps Whether the getting-started "Next steps" were emitted (default mode inside a project; false outside one).
21
21
  */
22
22
 
23
23
  /**
@@ -32,13 +32,47 @@
32
32
  * @property {{removed: boolean}} data False when no managed agent-docs block was found, so nothing was removed.
33
33
  */
34
34
 
35
+ /**
36
+ * What `init --user` did with one file of the computer-level agent text.
37
+ * `written`: created or refreshed. `unchanged`: already this release's text.
38
+ * `removed`: deleted (with `--remove-agents`). `absent`: nothing to remove.
39
+ * `kept`: a file left as it is, because a person edited it or Astryx did not
40
+ * write it (see `reason`).
41
+ * @typedef {'written' | 'linked' | 'unchanged' | 'removed' | 'absent' | 'kept'} InitUserAction
42
+ */
43
+
44
+ /**
45
+ * @typedef {object} InitUserFile
46
+ * @property {string} path Absolute path in the home folder: the skill file,
47
+ * or a link to its folder.
48
+ * @property {InitUserAction} action
49
+ * @property {'edited' | 'not-astryx'} [reason] Only on `kept`: `edited`, the
50
+ * text no longer matches the hash Astryx recorded in it; `not-astryx`, it
51
+ * has no Astryx markers or is a symlink, or a link target holds something
52
+ * Astryx did not create.
53
+ */
54
+
55
+ /**
56
+ * @typedef {object} InitUserData
57
+ * @property {InitUserFile[]} files One row per path acted on: `~/.agents/skills/astryx/SKILL.md` first, then each link to its folder: `~/.claude/skills/astryx` always, and another agent's skills folder when that agent's folder exists (`linked`, or `unchanged` when the link is already there). Removal removes the file and the links Astryx made.
58
+ * @property {string} command The command the text tells agents to run: `astryx`, or the host's command when a host started the run.
59
+ * @property {string[]} warnings Non-fatal notes, such as no `astryx` on the computer that runs the Astryx CLI.
60
+ */
61
+
62
+ /**
63
+ * @typedef {object} InitUserResponse
64
+ * @property {'init.user'} type
65
+ * @property {InitUserData} data
66
+ */
67
+
35
68
  /**
36
69
  * Options for `init()`.
37
70
  * @typedef {object} InitOptions
38
71
  * @property {string} [features] Comma-separated features to install (agents, theme, template).
39
72
  * @property {boolean} [all] Install all features.
40
- * @property {boolean} [removeAgents] Remove the managed agent-docs block instead of installing.
41
- * @property {string} [agent] Agent preset: claude, cursor, codex, hermes, muse, all.
73
+ * @property {boolean} [removeAgents] Remove the managed agent-docs block instead of installing; with `user`, remove the computer-level agent text.
74
+ * @property {boolean} [user] Write the computer-level agent text (`~/.agents/skills/astryx/SKILL.md`, linked into `~/.claude/skills` and the skill folders of other installed tools, with a copy for Continue) instead of setting up the folder.
75
+ * @property {string} [agent] Agent preset: claude, cursor, codex, hermes, muse, all. Refused with `user`.
42
76
  * @property {string | string[]} [agentDocsPath] Explicit agent-docs file path(s).
43
77
  * @property {string} [templateName] Scaffold a named page template (programmatic only; the CLI never sets it).
44
78
  */
@@ -8,7 +8,7 @@
8
8
  * installed built themes and imports their production and font stylesheets. The
9
9
  * app imports that module once and passes its default to <Theme>.
10
10
  *
11
- * @param {string} invocation install-aware CLI invocation stem (e.g. `npx astryx`, `pnpm exec astryx`, or `npx @astryxdesign/cli` for one-off runs)
11
+ * @param {string} invocation install-aware CLI invocation stem (e.g. `pnpm exec astryx`, `yarn astryx`, or `npx @astryxdesign/cli` for one-off runs)
12
12
  * @returns {string[]} ordered list of human-facing lines
13
13
  */
14
14
  export function getNextSteps(invocation: string): string[];
@@ -19,6 +19,7 @@ import * as fs from 'node:fs';
19
19
  import {CLI_ROOT} from '../../../foundation/fs/paths.mjs';
20
20
  import {PathSafetyError, assertWithin} from '../../../foundation/fs/path-safety.mjs';
21
21
  import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
22
+ import {isOutsideProject} from '../../../foundation/env/project-scope.mjs';
22
23
  import {
23
24
  installAgentDocs,
24
25
  renderAgentDocsBlock,
@@ -39,7 +40,7 @@ const VALID_AGENTS = ['claude', 'cursor', 'codex', 'hermes', 'muse', 'all'];
39
40
  * installed built themes and imports their production and font stylesheets. The
40
41
  * app imports that module once and passes its default to <Theme>.
41
42
  *
42
- * @param {string} invocation install-aware CLI invocation stem (e.g. `npx astryx`, `pnpm exec astryx`, or `npx @astryxdesign/cli` for one-off runs)
43
+ * @param {string} invocation install-aware CLI invocation stem (e.g. `pnpm exec astryx`, `yarn astryx`, or `npx @astryxdesign/cli` for one-off runs)
43
44
  * @returns {string[]} ordered list of human-facing lines
44
45
  */
45
46
  export function getNextSteps(invocation) {
@@ -140,8 +141,11 @@ function applyTheme(cwd, invocation, data) {
140
141
  data.themeTemplate = 'failed';
141
142
  logger.error('Could not write the theme template.');
142
143
  }
144
+ // Outside a project there is no app to add a theme to (spec AST-081 FR3).
143
145
  logger.log(
144
- ` Edit the blank template for a new theme, or run \`${invocation} theme add <slug>\` to import an installed built theme (\`${invocation} theme list\` to browse). Extend an imported theme for ordinary customization; use \`${invocation} theme eject <slug>\` only to fork source.`,
146
+ isOutsideProject(cwd)
147
+ ? ` Edit the blank template for a new theme, or run \`${invocation} theme eject <slug>\` to start from the source of a built theme (\`${invocation} theme list\` to browse).`
148
+ : ` Edit the blank template for a new theme, or run \`${invocation} theme add <slug>\` to import an installed built theme (\`${invocation} theme list\` to browse). Extend an imported theme for ordinary customization; use \`${invocation} theme eject <slug>\` only to fork source.`,
145
149
  );
146
150
  }
147
151
 
@@ -276,7 +280,10 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
276
280
  }
277
281
 
278
282
  // No flags: TTY-free default — install the AI agent cheat sheet with NO
279
- // prompts, then print the getting-started guidance.
283
+ // prompts, then print the getting-started guidance. Outside a project the
284
+ // steps would set up a project the folder does not have, so they are left
285
+ // out (spec AST-081 FR3).
286
+ const outside = isOutsideProject(cwd);
280
287
  /** @type {import('../init.type.mjs').InitRunData} */
281
288
  const data = {
282
289
  mode: 'default',
@@ -288,13 +295,17 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
288
295
  themeTemplatePath: null,
289
296
  template: null,
290
297
  templatePath: null,
291
- nextSteps: true,
298
+ nextSteps: !outside,
292
299
  };
293
300
  await applyAgents(cwd, options, invocation, data);
294
301
  logger.log('');
295
302
  logger.log(
296
303
  ` Tip: \`${invocation} init --all\` also points you to the theme and page-building workflows.`,
297
304
  );
305
+ if (outside) {
306
+ logger.log('');
307
+ return {type: 'init.run', data};
308
+ }
298
309
  for (const line of getNextSteps(invocation)) logger.log(line);
299
310
  return {type: 'init.run', data};
300
311
  }
@@ -0,0 +1,14 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * Write or remove the computer-level agent text and return an `init.user`
6
+ * receipt. Progress is emitted through the shared `logger` (silent by
7
+ * default); warnings go to its warn channel.
8
+ *
9
+ * @param {{remove?: boolean}} [options]
10
+ * @returns {Promise<import('../init.type.mjs').InitUserResponse>}
11
+ */
12
+ export function user({ remove }?: {
13
+ remove?: boolean;
14
+ }): Promise<import("../init.type.mjs").InitUserResponse>;
@@ -0,0 +1,87 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file init.user leaf — the `--user` path behind `astryx init`.
5
+ *
6
+ * `user(options)` writes, refreshes, or (with `remove`) removes the
7
+ * computer-level agent text: one skill file in the home folder, linked into
8
+ * the skill folders agents read (spec AST-081 FR7, FR8). It records the
9
+ * setting and the links it made in the settings file, so the global copy,
10
+ * which keeps the text current in the background, does the same, or, after
11
+ * `remove`, writes nothing. The adapter does every file access. It works in any
12
+ * folder and never touches a project's agent docs. A file without the Astryx
13
+ * markers, one a person edited, or a symlinked one is kept as it is. When no
14
+ * `astryx` on the computer's search path runs the Astryx CLI, the text is
15
+ * still written and the receipt warns that the CLI should be installed for
16
+ * the computer.
17
+ *
18
+ * @input `remove`; the home folder, search path, and settings of
19
+ * the computer
20
+ * @output an `init.user` receipt
21
+ * @position packages/cli/api/init — dispatched by init.mjs
22
+ */
23
+
24
+ import {
25
+ COMPUTER_COMMAND,
26
+ COMPUTER_INSTALL_STEP,
27
+ applyComputerAgentText,
28
+ displayHomePath,
29
+ } from '../_adapter.mjs';
30
+ import {logger} from '../../logger.mjs';
31
+
32
+ /**
33
+ * @param {string} file
34
+ * @param {string} home
35
+ * @returns {string}
36
+ */
37
+ const display = (file, home) => displayHomePath(file, home);
38
+
39
+ /** @type {Record<import('../init.type.mjs').InitUserAction, string>} */
40
+ const ACTION_LINES = {
41
+ written: '[ok] Wrote',
42
+ linked: '[ok] Linked',
43
+ unchanged: '[ok] Already current:',
44
+ removed: '[ok] Removed',
45
+ absent: '[ok] Nothing to remove:',
46
+ kept: '[skip] Kept',
47
+ };
48
+
49
+ /** @type {Record<'edited' | 'not-astryx', string>} */
50
+ const KEPT_REASONS = {
51
+ edited: '(edited since Astryx wrote it; delete it to get the current text):',
52
+ 'not-astryx': '(not created by Astryx):',
53
+ };
54
+
55
+ /**
56
+ * Write or remove the computer-level agent text and return an `init.user`
57
+ * receipt. Progress is emitted through the shared `logger` (silent by
58
+ * default); warnings go to its warn channel.
59
+ *
60
+ * @param {{remove?: boolean}} [options]
61
+ * @returns {Promise<import('../init.type.mjs').InitUserResponse>}
62
+ */
63
+ export async function user({remove = false} = {}) {
64
+ const {home, command, files, cliOnSearchPath} = applyComputerAgentText({
65
+ remove,
66
+ });
67
+ /** @type {string[]} */
68
+ const warnings = [];
69
+ // A host's door is its own command; only the plain `astryx` needs a copy of
70
+ // the CLI installed for the computer.
71
+ if (!remove && command === COMPUTER_COMMAND && !cliOnSearchPath) {
72
+ warnings.push(
73
+ `No \`${COMPUTER_COMMAND}\` command on this computer runs the Astryx CLI, so agents cannot run the commands this text names. Install the CLI for the computer: ${COMPUTER_INSTALL_STEP}`,
74
+ );
75
+ }
76
+ for (const file of files) {
77
+ const reason = file.reason ? ` ${KEPT_REASONS[file.reason]}` : '';
78
+ logger.log(
79
+ `${ACTION_LINES[file.action]}${reason || (file.action === 'kept' ? ':' : '')} ${display(file.path, home)}`,
80
+ );
81
+ }
82
+ for (const warning of warnings) logger.warn(`[warn] ${warning}`);
83
+ return {
84
+ type: 'init.user',
85
+ data: {files, command, warnings},
86
+ };
87
+ }
@@ -0,0 +1,232 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file `init({user})` and `astryx init --user`: the `init.user` receipt, the
5
+ * install warning, the refused combinations, and that it touches nothing in
6
+ * the folder it runs in. Every test uses a temporary home folder and search
7
+ * path.
8
+ */
9
+
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
14
+ import {init} from '../init.mjs';
15
+ import {user} from './user.mjs';
16
+ import {runWithCliDoor} from '../../../foundation/env/cli-command.mjs';
17
+ import {renderComputerAgentText} from '../../../foundation/agent-docs/computer-agent-text.mjs';
18
+ import {runCli} from '../../../test-utils/run-cli.mjs';
19
+ import {settingsFile} from '../../../foundation/env/user-settings.mjs';
20
+ import {readGlobalState} from '../../../foundation/release/global-state.mjs';
21
+ import {cliVersion} from '../../../foundation/release/run-context.mjs';
22
+
23
+ /** @type {string[]} */
24
+ const dirs = [];
25
+ /** @param {string} label */
26
+ function tmp(label) {
27
+ const dir = fs.mkdtempSync(
28
+ path.join(os.tmpdir(), `astryx-init-user-${label}-`),
29
+ );
30
+ dirs.push(dir);
31
+ return dir;
32
+ }
33
+
34
+ let home = '';
35
+ let emptyPath = '';
36
+ beforeEach(() => {
37
+ home = tmp('home');
38
+ emptyPath = tmp('path');
39
+ vi.stubEnv('HOME', home);
40
+ vi.stubEnv('USERPROFILE', home);
41
+ vi.stubEnv('PATH', emptyPath);
42
+ // The settings file and the cache live under this home folder too.
43
+ vi.stubEnv('XDG_CONFIG_HOME', path.join(home, '.config'));
44
+ vi.stubEnv('XDG_CACHE_HOME', path.join(home, '.cache'));
45
+ vi.stubEnv('APPDATA', path.join(home, 'AppData', 'Roaming'));
46
+ vi.stubEnv('LOCALAPPDATA', path.join(home, 'AppData', 'Local'));
47
+ });
48
+
49
+ /** The settings file under the temporary home folder. */
50
+ const settings = () => {
51
+ try {
52
+ return JSON.parse(fs.readFileSync(settingsFile(), 'utf8'));
53
+ } catch {
54
+ return null;
55
+ }
56
+ };
57
+ afterEach(() => {
58
+ vi.unstubAllEnvs();
59
+ while (dirs.length) {
60
+ fs.rmSync(/** @type {string} */ (dirs.pop()), {
61
+ recursive: true,
62
+ force: true,
63
+ });
64
+ }
65
+ });
66
+
67
+ const FILE = path.join('.agents', 'skills', 'astryx', 'SKILL.md');
68
+ const CLAUDE = path.join('.claude', 'skills', 'astryx');
69
+
70
+ /** Put a linked Astryx CLI first on the search path. */
71
+ function installCliOnPath() {
72
+ const prefix = tmp('prefix');
73
+ const pkg = path.join(prefix, 'lib', 'node_modules', '@astryxdesign', 'cli');
74
+ fs.mkdirSync(pkg, {recursive: true});
75
+ fs.writeFileSync(
76
+ path.join(pkg, 'package.json'),
77
+ '{"name":"@astryxdesign/cli"}',
78
+ );
79
+ fs.writeFileSync(path.join(pkg, 'bin.mjs'), '#!/usr/bin/env node\n');
80
+ fs.chmodSync(path.join(pkg, 'bin.mjs'), 0o755);
81
+ fs.mkdirSync(path.join(prefix, 'bin'));
82
+ fs.symlinkSync(path.join(pkg, 'bin.mjs'), path.join(prefix, 'bin', 'astryx'));
83
+ vi.stubEnv('PATH', path.join(prefix, 'bin'));
84
+ }
85
+
86
+ describe('init({user: true})', () => {
87
+ it('writes the file, links Claude Code to it, and returns the init.user receipt, warning when no astryx runs the CLI', async () => {
88
+ const r = await init({user: true}, {cwd: tmp('cwd')});
89
+ expect(r.type).toBe('init.user');
90
+ if (r.type !== 'init.user') return;
91
+ expect(r.data.files).toEqual([
92
+ {path: path.join(home, FILE), action: 'written'},
93
+ {path: path.join(home, CLAUDE), action: 'linked'},
94
+ ]);
95
+ expect(r.data.command).toBe('astryx');
96
+ expect(r.data.warnings).toHaveLength(1);
97
+ expect(r.data.warnings[0]).toContain('npm i -g @astryxdesign/cli');
98
+ expect(fs.readFileSync(path.join(home, FILE), 'utf8')).toBe(
99
+ renderComputerAgentText({command: 'astryx'}),
100
+ );
101
+ expect(fs.readFileSync(path.join(home, CLAUDE, 'SKILL.md'), 'utf8')).toBe(
102
+ renderComputerAgentText({command: 'astryx'}),
103
+ );
104
+ });
105
+
106
+ it.skipIf(process.platform === 'win32')(
107
+ 'does not warn when the astryx on the search path is the Astryx CLI',
108
+ async () => {
109
+ installCliOnPath();
110
+ const r = await user();
111
+ expect(r.data.warnings).toEqual([]);
112
+ },
113
+ );
114
+
115
+ it("names the host's door and does not ask for a global install", async () => {
116
+ const r = await runWithCliDoor('acme astryx', () => user());
117
+ expect(r.data.command).toBe('acme astryx');
118
+ expect(r.data.warnings).toEqual([]);
119
+ expect(fs.readFileSync(path.join(home, FILE), 'utf8')).toContain(
120
+ "`acme astryx search '<what you need>'`",
121
+ );
122
+ });
123
+
124
+ it('works inside a project and writes nothing in it', async () => {
125
+ const dir = tmp('project');
126
+ fs.writeFileSync(
127
+ path.join(dir, 'package.json'),
128
+ '{"name":"app","dependencies":{"@astryxdesign/core":"*"}}',
129
+ );
130
+ const before = fs.readdirSync(dir).sort();
131
+ const r = await init({user: true}, {cwd: dir});
132
+ expect(r.type).toBe('init.user');
133
+ expect(fs.readdirSync(dir).sort()).toEqual(before);
134
+ });
135
+
136
+ it('records the links it made, and the release that wrote the text', async () => {
137
+ await init({user: true});
138
+ expect(settings()).toEqual({
139
+ computerAgentText: {install: true, links: [path.join(home, CLAUDE)]},
140
+ });
141
+ expect(readGlobalState().agentText).toEqual({writtenBy: cliVersion()});
142
+ });
143
+
144
+ it('keeps every other setting when it records the choice', async () => {
145
+ fs.mkdirSync(path.dirname(settingsFile()), {recursive: true});
146
+ fs.writeFileSync(settingsFile(), '{"other": 1}');
147
+ await init({user: true, removeAgents: true});
148
+ expect(settings()).toEqual({
149
+ other: 1,
150
+ computerAgentText: {install: false, links: []},
151
+ });
152
+ });
153
+
154
+ it('with removeAgents removes the file and the links it made, and records that the text is not wanted', async () => {
155
+ await init({user: true});
156
+ const r = await init({user: true, removeAgents: true});
157
+ expect(r.type).toBe('init.user');
158
+ if (r.type !== 'init.user') return;
159
+ expect(r.data.files).toEqual([
160
+ {path: path.join(home, FILE), action: 'removed'},
161
+ {path: path.join(home, CLAUDE), action: 'removed'},
162
+ ]);
163
+ expect(r.data.warnings).toEqual([]);
164
+ expect(fs.existsSync(path.join(home, FILE))).toBe(false);
165
+ expect(fs.existsSync(path.join(home, CLAUDE))).toBe(false);
166
+ expect(settings()).toEqual({
167
+ computerAgentText: {install: false, links: []},
168
+ });
169
+ });
170
+
171
+ it.each([
172
+ [{features: 'agents'}, '--features'],
173
+ [{all: true}, '--all'],
174
+ [{agentDocsPath: 'X.md'}, '--agent-docs-path'],
175
+ [{agent: 'claude'}, '--agent'],
176
+ [{removeAgents: true, agent: 'claude'}, '--agent'],
177
+ ])(
178
+ 'refuses %o with ERR_INVALID_ARGUMENT and writes nothing',
179
+ async (extra, flag) => {
180
+ await expect(init({user: true, ...extra})).rejects.toMatchObject({
181
+ code: 'ERR_INVALID_ARGUMENT',
182
+ message: expect.stringContaining(flag),
183
+ });
184
+ expect(fs.existsSync(path.join(home, '.agents'))).toBe(false);
185
+ expect(fs.existsSync(path.join(home, '.claude'))).toBe(false);
186
+ },
187
+ );
188
+ });
189
+
190
+ describe('astryx init --user', () => {
191
+ it('prints the file, the link, and the install warning in text mode', async () => {
192
+ const r = await runCli(['init', '--user'], tmp('cwd'));
193
+ expect(r.status).toBe(0);
194
+ expect(r.stdout).toContain(`Wrote ~${path.sep}${FILE}`);
195
+ expect(r.stdout).toContain(`Linked ~${path.sep}${CLAUDE}`);
196
+ expect(r.stderr).toContain('npm i -g @astryxdesign/cli');
197
+ });
198
+
199
+ it('emits the init.user envelope under --json', async () => {
200
+ const r = await runCli(['--json', 'init', '--user'], tmp('cwd'));
201
+ expect(r.status).toBe(0);
202
+ const env = JSON.parse(r.stdout);
203
+ expect(env.type).toBe('init.user');
204
+ expect(
205
+ env.data.files.map((/** @type {{action: string}} */ f) => f.action),
206
+ ).toEqual(['written', 'linked']);
207
+ expect(env.data.command).toBe('astryx');
208
+ });
209
+
210
+ it('names a file a person edited as kept, and why', async () => {
211
+ await runCli(['init', '--user'], tmp('cwd'));
212
+ const file = path.join(home, FILE);
213
+ fs.appendFileSync(file, 'my note\n');
214
+ const r = await runCli(['init', '--user'], tmp('cwd'));
215
+ expect(r.status).toBe(0);
216
+ expect(r.stdout).toContain(
217
+ `Kept (edited since Astryx wrote it; delete it to get the current text): ~${path.sep}${FILE}`,
218
+ );
219
+ expect(fs.readFileSync(file, 'utf8')).toMatch(/my note\n$/u);
220
+ });
221
+
222
+ it('exits 1 with ERR_INVALID_ARGUMENT when combined with --all or --agent', async () => {
223
+ for (const extra of [['--all'], ['--agent', 'claude']]) {
224
+ const r = await runCli(
225
+ ['--json', 'init', '--user', ...extra],
226
+ tmp('cwd'),
227
+ );
228
+ expect(r.status).toBe(1);
229
+ expect(JSON.parse(r.stdout).code).toBe('ERR_INVALID_ARGUMENT');
230
+ }
231
+ });
232
+ });
@@ -10,3 +10,36 @@
10
10
  * @returns {Promise<import('../../foundation/discovery/prop-drift.mjs').PropDriftReport>}
11
11
  */
12
12
  export function integrationPropDrift(integration: any, cwd: string): Promise<import("../../foundation/discovery/prop-drift.mjs").PropDriftReport>;
13
+ /**
14
+ * The passages two of a package's topics, or one of them and a Core topic,
15
+ * repeat word for word (architecture:cli-surface DEC-8). Reads the package's
16
+ * topics and Core's guides.
17
+ *
18
+ * @param {Parameters<typeof findCopiedPassages>[0]} discovered the package's
19
+ * docs, as discoverIntegrationDocs returns them
20
+ */
21
+ export function integrationCopiedPassages(discovered: Parameters<typeof findCopiedPassages>[0]): Promise<import("./authoring-checks.type.mjs").CopiedPassage[]>;
22
+ /**
23
+ * Padding phrases and low-density topics in a package's prose
24
+ * (architecture:cli-surface DEC-8). Reads the package's topics, and Core's
25
+ * guides for the density median a finding names.
26
+ *
27
+ * @param {Parameters<typeof findFluff>[0]} discovered the package's docs, as
28
+ * discoverIntegrationDocs returns them
29
+ */
30
+ export function integrationFluff(discovered: Parameters<typeof findFluff>[0]): Promise<import("./authoring-checks.type.mjs").DocFluff[]>;
31
+ /**
32
+ * Code spans in a package's prose that write `astryx docs <name>` for a doc
33
+ * that exists, where `{@link generic:<name>}` would be checked
34
+ * (architecture:cli-surface DEC-8). Reads the package's topics, its own
35
+ * component docs, and the names of Core's docs.
36
+ *
37
+ * @param {Parameters<typeof findStrayPointers>[0]} discovered the package's
38
+ * docs, as discoverIntegrationDocs returns them
39
+ * @param {any} [integration] the loaded integration, whose component docs are
40
+ * read too
41
+ */
42
+ export function integrationStrayPointers(discovered: Parameters<typeof findStrayPointers>[0], integration?: any): Promise<import("./authoring-checks.type.mjs").StrayPointer[]>;
43
+ import { findCopiedPassages } from '../../foundation/discovery/copied-passages.mjs';
44
+ import { findFluff } from '../../foundation/discovery/doc-fluff.mjs';
45
+ import { findStrayPointers } from '../../foundation/discovery/stray-pointers.mjs';
@@ -15,6 +15,9 @@ import {
15
15
  integrationSourceForDoc,
16
16
  } from '../../foundation/discovery/component-discovery.mjs';
17
17
  import {comparePropDocs} from '../../foundation/discovery/prop-drift.mjs';
18
+ import {findCopiedPassages} from '../../foundation/discovery/copied-passages.mjs';
19
+ import {findFluff} from '../../foundation/discovery/doc-fluff.mjs';
20
+ import {findStrayPointers} from '../../foundation/discovery/stray-pointers.mjs';
18
21
 
19
22
  /**
20
23
  * Each component doc's props compared with the component's TypeScript props,
@@ -52,3 +55,58 @@ export async function integrationPropDrift(integration, cwd) {
52
55
  resolveFrom: [cwd, packageDir],
53
56
  });
54
57
  }
58
+
59
+ /**
60
+ * The passages two of a package's topics, or one of them and a Core topic,
61
+ * repeat word for word (architecture:cli-surface DEC-8). Reads the package's
62
+ * topics and Core's guides.
63
+ *
64
+ * @param {Parameters<typeof findCopiedPassages>[0]} discovered the package's
65
+ * docs, as discoverIntegrationDocs returns them
66
+ */
67
+ export function integrationCopiedPassages(discovered) {
68
+ return findCopiedPassages(discovered);
69
+ }
70
+
71
+ /**
72
+ * Padding phrases and low-density topics in a package's prose
73
+ * (architecture:cli-surface DEC-8). Reads the package's topics, and Core's
74
+ * guides for the density median a finding names.
75
+ *
76
+ * @param {Parameters<typeof findFluff>[0]} discovered the package's docs, as
77
+ * discoverIntegrationDocs returns them
78
+ */
79
+ export function integrationFluff(discovered) {
80
+ return findFluff(discovered);
81
+ }
82
+
83
+ /**
84
+ * Code spans in a package's prose that write `astryx docs <name>` for a doc
85
+ * that exists, where `{@link generic:<name>}` would be checked
86
+ * (architecture:cli-surface DEC-8). Reads the package's topics, its own
87
+ * component docs, and the names of Core's docs.
88
+ *
89
+ * @param {Parameters<typeof findStrayPointers>[0]} discovered the package's
90
+ * docs, as discoverIntegrationDocs returns them
91
+ * @param {any} [integration] the loaded integration, whose component docs are
92
+ * read too
93
+ */
94
+ export async function integrationStrayPointers(discovered, integration) {
95
+ /** @type {{name: string, file: string}[]} */
96
+ const components = [];
97
+ if (integration?.components) {
98
+ const seen = new Set();
99
+ try {
100
+ const {components: records} =
101
+ await discoverValidIntegrationComponents(integration);
102
+ for (const record of records) {
103
+ if (!record.docPath || seen.has(record.docPath)) continue;
104
+ seen.add(record.docPath);
105
+ components.push({name: record.name, file: record.docPath});
106
+ }
107
+ } catch {
108
+ // `validate` reports component docs that do not load.
109
+ }
110
+ }
111
+ return findStrayPointers({...discovered, components});
112
+ }