@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
@@ -0,0 +1,152 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The command that runs the CLI for this project, when something other
5
+ * than the package-manager guess says what it is.
6
+ *
7
+ * `getCliInvocation` (package-manager.mjs) is the one picker every printed
8
+ * command goes through. It asks, in order:
9
+ *
10
+ * 1. **The integrations** — the `cliCommand` field of each loaded
11
+ * integration's manifest. `Project.load` records them per project with
12
+ * {@link recordDeclaredCliCommands}. One command, declared by one or more
13
+ * integrations, is used. Two different commands cancel each other out: the
14
+ * picker falls back to its guess, even when a host set a door, and
15
+ * `astryx doctor` warns.
16
+ * 2. **The door** — the command a host ran this call through. A host sets it
17
+ * for the duration of one call with {@link runWithCliDoor}; nothing in the
18
+ * public API sets it yet, so it is empty in every plain run.
19
+ * 3. **The guess** — the package-manager prefix, as before.
20
+ *
21
+ * @input A host's door name; the loaded integrations of a project.
22
+ * @output The declared command for a directory, or the conflict.
23
+ * @position foundation/env — read by the picker and by `astryx doctor`.
24
+ */
25
+
26
+ import {AsyncLocalStorage} from 'node:async_hooks';
27
+ import * as fs from 'node:fs';
28
+ import * as path from 'node:path';
29
+
30
+ /**
31
+ * One integration's declared command.
32
+ * @typedef {object} DeclaredCliCommand
33
+ * @property {string} package the integration package that declared it
34
+ * @property {string} command its `cliCommand` value
35
+ */
36
+
37
+ /** @type {AsyncLocalStorage<{command: string}>} */
38
+ const doorScope = new AsyncLocalStorage();
39
+
40
+ /**
41
+ * Run `fn` with `command` as the door printed commands start with. The slot a
42
+ * host fills for one call. An integration's `cliCommand` still comes first,
43
+ * and conflicting ones still fall back to the guess.
44
+ * @template T
45
+ * @param {string} command e.g. `astryx` for a global launcher
46
+ * @param {() => T} fn
47
+ * @returns {T}
48
+ */
49
+ export function runWithCliDoor(command, fn) {
50
+ return doorScope.run({command}, fn);
51
+ }
52
+
53
+ /**
54
+ * The door of the current call, if a host set one.
55
+ * @returns {string | undefined}
56
+ */
57
+ export function cliDoor() {
58
+ return doorScope.getStore()?.command;
59
+ }
60
+
61
+ /** @type {Map<string, DeclaredCliCommand[]>} */
62
+ const declaredByProject = new Map();
63
+
64
+ /**
65
+ * The directory a project is keyed by: the nearest one with a package.json,
66
+ * the same root `Project.load` resolves; otherwise the directory itself.
67
+ * @param {string} dir
68
+ * @returns {string}
69
+ */
70
+ function projectKey(dir) {
71
+ const start = path.resolve(dir);
72
+ let current = start;
73
+ for (;;) {
74
+ if (fs.existsSync(path.join(current, 'package.json'))) return current;
75
+ const parent = path.dirname(current);
76
+ if (parent === current) return start;
77
+ current = parent;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * The commands a set of loaded integrations declares, in load order. An
83
+ * integration that failed to load, or was set aside for a provider conflict,
84
+ * contributes nothing, so it declares nothing either.
85
+ * @param {ReadonlyArray<{name?: string, __spec?: string, cliCommand?: string, __loadError?: string, __providerConflict?: unknown}>} integrations
86
+ * @returns {DeclaredCliCommand[]}
87
+ */
88
+ export function declaredCliCommandsOf(integrations) {
89
+ /** @type {DeclaredCliCommand[]} */
90
+ const declared = [];
91
+ for (const integration of integrations) {
92
+ if (integration.__loadError != null) continue;
93
+ if (integration.__providerConflict != null) continue;
94
+ if (typeof integration.cliCommand !== 'string') continue;
95
+ declared.push({
96
+ package: integration.name ?? integration.__spec ?? '(unnamed)',
97
+ command: integration.cliCommand,
98
+ });
99
+ }
100
+ return declared;
101
+ }
102
+
103
+ /**
104
+ * Choose among declarations: one command, declared by one or more
105
+ * integrations, is used; different commands are a conflict.
106
+ * @param {DeclaredCliCommand[]} declared
107
+ * @returns {{command?: string, conflict: boolean, declared: DeclaredCliCommand[]}}
108
+ */
109
+ export function chooseDeclaredCliCommand(declared) {
110
+ const commands = new Set(declared.map(entry => entry.command));
111
+ if (commands.size === 1) {
112
+ return {command: declared[0].command, conflict: false, declared};
113
+ }
114
+ return {conflict: commands.size > 1, declared};
115
+ }
116
+
117
+ /**
118
+ * Record the commands a project's loaded integrations declare. Called by
119
+ * `Project.load` each time it resolves the integration set; the latest load
120
+ * wins.
121
+ * @param {string} projectDir
122
+ * @param {Parameters<typeof declaredCliCommandsOf>[0]} integrations
123
+ * @returns {void}
124
+ */
125
+ export function recordDeclaredCliCommands(projectDir, integrations) {
126
+ declaredByProject.set(
127
+ projectKey(projectDir),
128
+ declaredCliCommandsOf(integrations),
129
+ );
130
+ }
131
+
132
+ /**
133
+ * Whether this process has loaded the project at `targetDir`.
134
+ * @param {string} [targetDir=process.cwd()]
135
+ * @returns {boolean}
136
+ */
137
+ export function hasRecordedProject(targetDir = process.cwd()) {
138
+ return declaredByProject.has(projectKey(targetDir));
139
+ }
140
+
141
+ /**
142
+ * What the integrations of the project at `targetDir` declare, as recorded by
143
+ * its last `Project.load` in this process; see
144
+ * {@link chooseDeclaredCliCommand}.
145
+ * @param {string} [targetDir=process.cwd()]
146
+ * @returns {{command?: string, conflict: boolean, declared: DeclaredCliCommand[]}}
147
+ */
148
+ export function declaredCliCommand(targetDir = process.cwd()) {
149
+ return chooseDeclaredCliCommand(
150
+ declaredByProject.get(projectKey(targetDir)) ?? [],
151
+ );
152
+ }
@@ -0,0 +1,129 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect, afterEach} from 'vitest';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import * as os from 'node:os';
7
+ import {
8
+ chooseDeclaredCliCommand,
9
+ cliDoor,
10
+ declaredCliCommand,
11
+ declaredCliCommandsOf,
12
+ hasRecordedProject,
13
+ recordDeclaredCliCommands,
14
+ runWithCliDoor,
15
+ } from './cli-command.mjs';
16
+
17
+ /** @type {string[]} */
18
+ const dirs = [];
19
+
20
+ afterEach(() => {
21
+ for (const dir of dirs.splice(0)) {
22
+ fs.rmSync(dir, {recursive: true, force: true});
23
+ }
24
+ });
25
+
26
+ /** A project directory with a package.json, and a folder inside it. */
27
+ function makeProject() {
28
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-cli-command-'));
29
+ dirs.push(dir);
30
+ fs.writeFileSync(path.join(dir, 'package.json'), '{"name":"app"}');
31
+ fs.mkdirSync(path.join(dir, 'src'));
32
+ return dir;
33
+ }
34
+
35
+ describe('runWithCliDoor', () => {
36
+ it('sets the door for the call, and only for it', async () => {
37
+ expect(cliDoor()).toBeUndefined();
38
+ const inside = await runWithCliDoor('astryx', async () => {
39
+ await Promise.resolve();
40
+ return cliDoor();
41
+ });
42
+ expect(inside).toBe('astryx');
43
+ expect(cliDoor()).toBeUndefined();
44
+ });
45
+ });
46
+
47
+ describe('declaredCliCommandsOf', () => {
48
+ it('skips integrations that failed to load or were set aside', () => {
49
+ expect(
50
+ declaredCliCommandsOf([
51
+ {name: '@acme/a', cliCommand: 'acme astryx'},
52
+ {name: '@acme/b'},
53
+ {name: '@acme/c', cliCommand: 'c astryx', __loadError: 'boom'},
54
+ {name: '@acme/d', cliCommand: 'd astryx', __providerConflict: {}},
55
+ {__spec: '@acme/e', cliCommand: 'acme astryx'},
56
+ ]),
57
+ ).toEqual([
58
+ {package: '@acme/a', command: 'acme astryx'},
59
+ {package: '@acme/e', command: 'acme astryx'},
60
+ ]);
61
+ });
62
+ });
63
+
64
+ describe('chooseDeclaredCliCommand', () => {
65
+ it('uses one command, however many packages declare it', () => {
66
+ const declared = [
67
+ {package: '@acme/a', command: 'acme astryx'},
68
+ {package: '@acme/b', command: 'acme astryx'},
69
+ ];
70
+ expect(chooseDeclaredCliCommand(declared)).toEqual({
71
+ command: 'acme astryx',
72
+ conflict: false,
73
+ declared,
74
+ });
75
+ });
76
+
77
+ it('uses neither of two different commands, and calls it a conflict', () => {
78
+ const result = chooseDeclaredCliCommand([
79
+ {package: '@acme/a', command: 'acme astryx'},
80
+ {package: '@acme/b', command: 'other astryx'},
81
+ ]);
82
+ expect(result.command).toBeUndefined();
83
+ expect(result.conflict).toBe(true);
84
+ });
85
+
86
+ it('has nothing to choose with no declarations', () => {
87
+ expect(chooseDeclaredCliCommand([])).toEqual({
88
+ conflict: false,
89
+ declared: [],
90
+ });
91
+ });
92
+ });
93
+
94
+ describe('recordDeclaredCliCommands', () => {
95
+ it('answers for the project and any folder inside it', () => {
96
+ const dir = makeProject();
97
+ expect(hasRecordedProject(dir)).toBe(false);
98
+ recordDeclaredCliCommands(dir, [
99
+ {name: '@acme/a', cliCommand: 'acme astryx'},
100
+ ]);
101
+ expect(hasRecordedProject(dir)).toBe(true);
102
+ expect(declaredCliCommand(dir).command).toBe('acme astryx');
103
+ expect(declaredCliCommand(path.join(dir, 'src')).command).toBe(
104
+ 'acme astryx',
105
+ );
106
+ });
107
+
108
+ it('lets the latest load win', () => {
109
+ const dir = makeProject();
110
+ recordDeclaredCliCommands(dir, [
111
+ {name: '@acme/a', cliCommand: 'acme astryx'},
112
+ ]);
113
+ recordDeclaredCliCommands(dir, []);
114
+ expect(hasRecordedProject(dir)).toBe(true);
115
+ expect(declaredCliCommand(dir).command).toBeUndefined();
116
+ });
117
+
118
+ it('does not answer for a nested project of its own', () => {
119
+ const dir = makeProject();
120
+ const nested = path.join(dir, 'packages', 'web');
121
+ fs.mkdirSync(nested, {recursive: true});
122
+ fs.writeFileSync(path.join(nested, 'package.json'), '{"name":"web"}');
123
+ recordDeclaredCliCommands(dir, [
124
+ {name: '@acme/a', cliCommand: 'acme astryx'},
125
+ ]);
126
+ expect(hasRecordedProject(nested)).toBe(false);
127
+ expect(declaredCliCommand(nested).command).toBeUndefined();
128
+ });
129
+ });
@@ -20,15 +20,27 @@ import {
20
20
 
21
21
  describe('parseNodeVersion', () => {
22
22
  it('parses a plain semver string', () => {
23
- expect(parseNodeVersion('22.14.1')).toEqual({major: 22, minor: 14, patch: 1});
23
+ expect(parseNodeVersion('22.14.1')).toEqual({
24
+ major: 22,
25
+ minor: 14,
26
+ patch: 1,
27
+ });
24
28
  });
25
29
 
26
30
  it('strips a leading v', () => {
27
- expect(parseNodeVersion('v20.10.0')).toEqual({major: 20, minor: 10, patch: 0});
31
+ expect(parseNodeVersion('v20.10.0')).toEqual({
32
+ major: 20,
33
+ minor: 10,
34
+ patch: 0,
35
+ });
28
36
  });
29
37
 
30
38
  it('ignores a prerelease/build suffix on the patch segment', () => {
31
- expect(parseNodeVersion('16.20.2-nightly')).toEqual({major: 16, minor: 20, patch: 2});
39
+ expect(parseNodeVersion('16.20.2-nightly')).toEqual({
40
+ major: 16,
41
+ minor: 20,
42
+ patch: 2,
43
+ });
32
44
  });
33
45
 
34
46
  it('defaults missing segments to 0', () => {
@@ -130,21 +130,55 @@ export function isCliOneOff(): boolean;
130
130
  */
131
131
  export function cliBinResolves(targetDir?: string): boolean;
132
132
  /**
133
- * The safe, install-aware CLI invocation stem to suggest to users.
133
+ * The CLI invocation stem every printed command starts with. The one picker:
134
+ * every hint, error, Doctor fix and doc line that names a command goes through
135
+ * it (directly, or through {@link formatCliCommand} and
136
+ * {@link formatCliCommandsIn}). JSON fields that carry a command stay bare.
134
137
  *
135
- * - The `astryx` bin resolves from `targetDir`: `<run-prefix> astryx`
136
- * (e.g. `pnpm exec astryx`).
137
- * - Launched one-off (npx/dlx cache), or the bin does not resolve from
138
- * `targetDir` (a global install, a fresh package in a workspace):
139
- * `<dlx-prefix> @astryxdesign/cli`. The bare `astryx` name would make npm
140
- * fetch an unrelated registry package; the scoped package always resolves
141
- * to this CLI.
138
+ * In order:
139
+ *
140
+ * - The `cliCommand` an integration loaded in this project declares, e.g.
141
+ * `acme astryx`. When two integrations declare different commands,
142
+ * neither is used, the guess below is (even when a host set a door), and
143
+ * `astryx doctor` warns.
144
+ * - The door a host ran this call through (see cli-command.mjs). Empty in a
145
+ * plain run.
146
+ * - Otherwise the guess below.
147
+ *
148
+ * The guess names a command that, run from `targetDir`, reaches the release
149
+ * that answered (spec AST-081 FR5):
150
+ *
151
+ * - The project's own CLI answered and its `astryx` bin resolves from
152
+ * `targetDir`: `<run-prefix> astryx` (e.g. `pnpm exec astryx`).
153
+ * - Outside a project, the CLI installed for the computer (or the release it
154
+ * keeps) answered: `astryx`.
155
+ * - Otherwise: `<dlx-prefix> @astryxdesign/cli@<answering version>`, pinned so
156
+ * the package runner starts the same release. The bare `astryx` name would
157
+ * make npm fetch an unrelated registry package, and the unpinned scoped
158
+ * package the newest release.
159
+ *
160
+ * With `installed`, the line follows a step that installs the project's own
161
+ * CLI (an update notice, the hint that matches a project's CLI to its Core),
162
+ * so the guess is that CLI: `<run-prefix> astryx`. A declared `cliCommand`
163
+ * and a host's door still come first.
142
164
  *
143
165
  * @param {string} [targetDir] the project the printed command runs in;
144
166
  * defaults to the working directory
167
+ * @param {{installed?: boolean}} [options]
145
168
  * @returns {string}
146
169
  */
147
- export function getCliInvocation(targetDir?: string): string;
170
+ export function getCliInvocation(targetDir?: string, { installed }?: {
171
+ installed?: boolean;
172
+ }): string;
173
+ /**
174
+ * The package-manager guess alone, without any integration's `cliCommand` or
175
+ * a host's door. The picker falls back to it when declared commands conflict,
176
+ * and Doctor names it then.
177
+ *
178
+ * @param {string} [targetDir]
179
+ * @returns {string}
180
+ */
181
+ export function guessCliInvocation(targetDir?: string): string;
148
182
  /**
149
183
  * Format a full, runnable CLI command from a subcommand string.
150
184
  *
@@ -157,6 +191,56 @@ export function getCliInvocation(targetDir?: string): string;
157
191
  * @returns {string}
158
192
  */
159
193
  export function formatCliCommand(command: string, targetDir?: string): string;
194
+ /**
195
+ * Prefix every CLI command in doc text with `stem`, the invocation from
196
+ * {@link getCliInvocation}.
197
+ *
198
+ * Docs, including an integration's, are written with bare `astryx ...`
199
+ * commands; this rewrites them when they are shown. In prose, an inline code
200
+ * span that starts with `astryx`. In a shell code fence (no language, `bash`,
201
+ * `sh`, `shell`, `zsh`, `console`), each `astryx` that starts a command. In a
202
+ * `text` or `markdown` fence, both. Other fences, and plain words, are left
203
+ * alone. JSON output keeps the authored text.
204
+ *
205
+ * @param {string} text Markdown-style doc text, or the body of one code block.
206
+ * @param {string} stem e.g. `pnpm exec astryx`
207
+ * @param {string | null} [lang] the code block's language when `text` is one
208
+ * block's body; omit for Markdown, whose fences are followed
209
+ * @returns {string}
210
+ */
211
+ export function prefixCliCommands(text: string, stem: string, lang?: string | null): string;
212
+ /**
213
+ * Quote one argument of a printed command so the shell it is pasted into
214
+ * passes it on unchanged. Printed commands target a POSIX shell (sh, bash,
215
+ * zsh), and PowerShell on Windows; cmd.exe is not a target. A value made only
216
+ * of letters, digits and `@ / . _ -` (and, on Windows, a drive path's `:` and
217
+ * `\`) stays bare. Any other value gets single quotes, inside which both
218
+ * shells read `$`, backticks, `%`, `!`, spaces and double quotes literally. An
219
+ * embedded single quote is written `'\''` for a POSIX shell and doubled for
220
+ * PowerShell, which also ends a single-quoted string at the typographic
221
+ * quotes `‘ ’ ‚ ‛`, so those are doubled too (`Macy’s` → `'Macy’’s'`).
222
+ *
223
+ * @param {string} value
224
+ * @param {string} [platform] the `process.platform` the command is printed for
225
+ * @returns {string}
226
+ */
227
+ export function quoteCommandArgument(value: string, platform?: string): string;
228
+ /**
229
+ * A printed command that changes to `dir`, then runs `command` there, so it
230
+ * does the same work pasted from any folder. It runs `command` only when the
231
+ * change worked. For a POSIX shell: `cd <dir> && <command>`. For PowerShell
232
+ * on Windows: `cd -LiteralPath <dir> -ErrorAction Stop; <command>`, because
233
+ * `-LiteralPath` reads `[` and `]` in a folder name literally, and a failed
234
+ * change stops the line in Windows PowerShell 5.1, which has no `&&`, as in
235
+ * PowerShell 7.
236
+ *
237
+ * @param {string} dir an absolute folder
238
+ * @param {string} command the command to run there, its arguments already
239
+ * quoted with {@link quoteCommandArgument}
240
+ * @param {string} [platform] the `process.platform` the command is printed for
241
+ * @returns {string}
242
+ */
243
+ export function commandInFolder(dir: string, command: string, platform?: string): string;
160
244
  /** The published CLI package name — used for one-off (uninstalled) invocations. */
161
245
  export const CLI_PACKAGE: "@astryxdesign/cli";
162
246
  /** The CLI binary name — only resolves once the CLI is installed (or run via CLI_PACKAGE). */
@@ -0,0 +1,66 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The picker's guess when the CLI installed for the computer answers:
5
+ * `astryx` outside a project, and the pinned package inside one, where the
6
+ * global copy never answers for itself (spec AST-081 FR5).
7
+ */
8
+
9
+ import {describe, it, expect, vi, afterEach} from 'vitest';
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import {guessCliInvocation} from './package-manager.mjs';
13
+ import {
14
+ CLI_VERSION,
15
+ cleanupFixtures,
16
+ installCore,
17
+ project,
18
+ tempDir,
19
+ } from '../../test-utils/release-fixtures.mjs';
20
+
21
+ vi.mock('../release/choose.mjs', async importOriginal => ({
22
+ .../** @type {object} */ (await importOriginal()),
23
+ isGlobalCopy: () => true,
24
+ }));
25
+
26
+ afterEach(cleanupFixtures);
27
+
28
+ describe('guessCliInvocation for the copy installed for the computer', () => {
29
+ it('prints the bare `astryx` command outside a project', () => {
30
+ const empty = tempDir('empty');
31
+ fs.writeFileSync(path.join(empty, 'package-lock.json'), '{}');
32
+ const before = process.cwd();
33
+ process.chdir(empty);
34
+ try {
35
+ expect(guessCliInvocation(empty)).toBe('astryx');
36
+ } finally {
37
+ process.chdir(before);
38
+ }
39
+ });
40
+
41
+ it('prints the pinned package inside a project it answers as the matched release', () => {
42
+ const root = project(tempDir(), {'@astryxdesign/core': CLI_VERSION});
43
+ installCore(root, CLI_VERSION);
44
+ fs.writeFileSync(path.join(root, 'package-lock.json'), '{}');
45
+ expect(guessCliInvocation(root)).toBe(
46
+ `npx @astryxdesign/cli@${CLI_VERSION}`,
47
+ );
48
+ });
49
+ });
50
+
51
+ describe('one stem per run', () => {
52
+ it('names the release that answered the run, whichever folder a line names', () => {
53
+ // The run answers outside a project; a line about a project folder whose
54
+ // own CLI sits beyond the read reach still gets the same stem.
55
+ const empty = tempDir('empty');
56
+ const other = project(tempDir(), {'@astryxdesign/core': CLI_VERSION});
57
+ installCore(other, CLI_VERSION);
58
+ const before = process.cwd();
59
+ process.chdir(empty);
60
+ try {
61
+ expect(guessCliInvocation(other)).toBe(guessCliInvocation(empty));
62
+ } finally {
63
+ process.chdir(before);
64
+ }
65
+ });
66
+ });