@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.3-canary.02f5fe4

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 (694) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +216 -162
  3. package/api/build/_adapter.d.mts +66 -0
  4. package/api/build/_adapter.mjs +139 -4
  5. package/api/build/blocks/blocks.d.mts +92 -0
  6. package/api/build/blocks/blocks.mjs +528 -0
  7. package/api/build/blocks/blocks.test.mjs +238 -0
  8. package/api/build/blocks/blocks.weights.json +1 -0
  9. package/api/build/build.doc.mjs +4 -0
  10. package/api/build/build.mjs +25 -6
  11. package/api/build/build.type.mjs +1 -1
  12. package/api/build/help/help.mjs +1 -1
  13. package/api/build/kit/answer.d.mts +18 -0
  14. package/api/build/kit/answer.mjs +195 -0
  15. package/api/build/kit/answer.test.mjs +108 -0
  16. package/api/build/kit/kind.d.mts +25 -0
  17. package/api/build/kit/kind.mjs +170 -0
  18. package/api/build/kit/kit.d.mts +2 -4
  19. package/api/build/kit/kit.mjs +8 -406
  20. package/api/build/kit/rank.d.mts +3 -32
  21. package/api/build/kit/rank.mjs +25 -342
  22. package/api/build/kit/rank.test.mjs +2 -1
  23. package/api/build/kit/signals.d.mts +79 -0
  24. package/api/build/kit/signals.mjs +295 -0
  25. package/api/build/kit/start.d.mts +32 -0
  26. package/api/build/kit/start.mjs +163 -0
  27. package/api/build/kit/words.d.mts +72 -0
  28. package/api/build/kit/words.mjs +202 -0
  29. package/api/build/tree.d.mts +20 -0
  30. package/api/build/tree.mjs +53 -0
  31. package/api/build/tree.test.mjs +185 -0
  32. package/api/build/tree.weights.json +1 -0
  33. package/api/component/_adapter.d.mts +72 -1
  34. package/api/component/_adapter.mjs +251 -23
  35. package/api/component/component-replacement.test.mjs +1 -0
  36. package/api/component/component.doc.mjs +6 -1
  37. package/api/component/component.mjs +97 -16
  38. package/api/component/component.test.mjs +95 -0
  39. package/api/component/doc-links.test.mjs +386 -0
  40. package/api/component/integration-export-name.test.mjs +644 -0
  41. package/api/component/list/list.mjs +42 -4
  42. package/api/discover/_adapter.d.mts +131 -12
  43. package/api/discover/_adapter.mjs +520 -34
  44. package/api/discover/_adapter.test.mjs +641 -17
  45. package/api/discover/_catalog-view.d.mts +16 -5
  46. package/api/discover/_catalog-view.mjs +32 -8
  47. package/api/discover/detail/doc/doc.mjs +9 -1
  48. package/api/discover/discover.d.mts +11 -0
  49. package/api/discover/discover.doc.mjs +9 -7
  50. package/api/discover/discover.mjs +120 -19
  51. package/api/discover/discover.type.d.mts +20 -7
  52. package/api/discover/discover.type.mjs +17 -7
  53. package/api/discover/list/list.d.mts +4 -3
  54. package/api/discover/list/list.mjs +17 -10
  55. package/api/docs/_adapter.d.mts +76 -2
  56. package/api/docs/_adapter.mjs +630 -34
  57. package/api/docs/docs-homes.test.mjs +127 -0
  58. package/api/docs/docs.doc.mjs +5 -4
  59. package/api/docs/docs.mjs +2 -1
  60. package/api/docs/docs.test.mjs +39 -20
  61. package/api/docs/integration-tree.test.mjs +42 -20
  62. package/api/docs/integrationDocs.test.mjs +125 -1
  63. package/api/docs/list/list.mjs +12 -2
  64. package/api/docs/namespace-section.test.mjs +6 -6
  65. package/api/docs/reference-blocks.test.mjs +3 -5
  66. package/api/doctor/_adapter.d.mts +128 -0
  67. package/api/doctor/_adapter.mjs +253 -4
  68. package/api/doctor/doctor.d.mts +217 -0
  69. package/api/doctor/doctor.doc.mjs +3 -2
  70. package/api/doctor/doctor.mjs +691 -52
  71. package/api/doctor/doctor.test.mjs +267 -18
  72. package/api/doctor/release-checks.test.mjs +156 -0
  73. package/api/doctor/theme-checks.mjs +17 -4
  74. package/api/doctor/theme-checks.test.mjs +223 -7
  75. package/api/error.d.mts +10 -0
  76. package/api/error.mjs +25 -0
  77. package/api/gap-report/gap-report.d.mts +3 -0
  78. package/api/gap-report/gap-report.doc.mjs +11 -3
  79. package/api/gap-report/gap-report.mjs +219 -52
  80. package/api/gap-report/gap-report.test.mjs +233 -0
  81. package/api/gap-report/gap-report.type.d.mts +41 -0
  82. package/api/gap-report/gap-report.type.mjs +18 -0
  83. package/api/hook/_adapter.mjs +3 -11
  84. package/api/hook/hook.doc.mjs +4 -0
  85. package/api/hook/hook.mjs +1 -1
  86. package/api/hook/list/list.d.mts +1 -1
  87. package/api/index.d.mts +2 -0
  88. package/api/index.mjs +2 -0
  89. package/api/init/_adapter.d.mts +22 -0
  90. package/api/init/_adapter.mjs +59 -0
  91. package/api/init/init.d.mts +7 -5
  92. package/api/init/init.doc.mjs +45 -10
  93. package/api/init/init.mjs +28 -4
  94. package/api/init/init.test.mjs +18 -2
  95. package/api/init/init.type.d.mts +50 -5
  96. package/api/init/init.type.mjs +39 -5
  97. package/api/init/remove/remove.mjs +17 -4
  98. package/api/init/remove/remove.test.mjs +114 -2
  99. package/api/init/run/run.d.mts +1 -1
  100. package/api/init/run/run.mjs +86 -12
  101. package/api/init/user/user.d.mts +14 -0
  102. package/api/init/user/user.mjs +87 -0
  103. package/api/init/user/user.test.mjs +232 -0
  104. package/api/integration/_adapter.d.mts +53 -0
  105. package/api/integration/_adapter.mjs +132 -0
  106. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  107. package/api/integration/add-contribution.mjs +8 -4
  108. package/api/integration/add-contribution.test.mjs +4 -2
  109. package/api/integration/authoring-checks.mjs +192 -14
  110. package/api/integration/authoring-checks.test.mjs +1028 -0
  111. package/api/integration/authoring-checks.type.d.mts +143 -0
  112. package/api/integration/authoring-checks.type.mjs +74 -2
  113. package/api/integration/check/check.d.mts +96 -0
  114. package/api/integration/check/check.mjs +357 -0
  115. package/api/integration/check/check.test.mjs +489 -0
  116. package/api/integration/integration-check.type.d.mts +118 -0
  117. package/api/integration/integration-check.type.mjs +84 -0
  118. package/api/integration/integrationCheck.doc.d.mts +10 -0
  119. package/api/integration/integrationCheck.doc.mjs +73 -0
  120. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  121. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  122. package/api/integration/pack-check.mjs +486 -123
  123. package/api/integration/pack-check.test.mjs +817 -10
  124. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +73 -5
  126. package/api/integration/validate-integration-gaps.test.mjs +1975 -0
  127. package/api/integration/validate-integration.d.mts +23 -2
  128. package/api/integration/validate-integration.mjs +358 -45
  129. package/api/integration/validate-integration.test.mjs +88 -8
  130. package/api/integration/validate-integration.type.d.mts +105 -0
  131. package/api/integration/validate-integration.type.mjs +79 -1
  132. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  133. package/api/integration/validateIntegration.doc.mjs +19 -3
  134. package/api/search/ORDERING.md +28 -0
  135. package/api/search/_adapter.d.mts +91 -0
  136. package/api/search/_adapter.mjs +172 -0
  137. package/api/search/_adapter.test.mjs +173 -0
  138. package/api/search/_candidate-score.d.mts +40 -0
  139. package/api/search/_candidate-score.mjs +238 -0
  140. package/api/search/_cards.json +6098 -0
  141. package/api/search/_compound.d.mts +50 -0
  142. package/api/search/_compound.mjs +170 -0
  143. package/api/search/_doc-searcher.d.mts +4 -0
  144. package/api/search/_doc-searcher.mjs +23 -0
  145. package/api/search/_doc-searcher.test.mjs +36 -0
  146. package/api/search/_doc-searcher.weights.json +1 -0
  147. package/api/search/_doc-text.d.mts +30 -0
  148. package/api/search/_doc-text.mjs +87 -0
  149. package/api/search/_entries.d.mts +63 -0
  150. package/api/search/_entries.mjs +232 -0
  151. package/api/search/_entries.test.mjs +48 -0
  152. package/api/search/_features.d.mts +35 -0
  153. package/api/search/_features.mjs +155 -0
  154. package/api/search/_gather-components.d.mts +26 -0
  155. package/api/search/_gather-components.mjs +284 -0
  156. package/api/search/_gather-docs.d.mts +20 -0
  157. package/api/search/_gather-docs.mjs +254 -0
  158. package/api/search/_gather-hooks.d.mts +12 -0
  159. package/api/search/_gather-hooks.mjs +52 -0
  160. package/api/search/_gather-templates.d.mts +25 -0
  161. package/api/search/_gather-templates.mjs +107 -0
  162. package/api/search/_lexical.d.mts +135 -0
  163. package/api/search/_lexical.mjs +351 -0
  164. package/api/search/_main-searcher.d.mts +19 -0
  165. package/api/search/_main-searcher.mjs +115 -0
  166. package/api/search/_main-searcher.test.mjs +106 -0
  167. package/api/search/_main-searcher.weights.json +1 -0
  168. package/api/search/_module-doc.d.mts +32 -0
  169. package/api/search/_module-doc.mjs +78 -0
  170. package/api/search/_order.d.mts +32 -0
  171. package/api/search/_order.mjs +162 -0
  172. package/api/search/_order.test.mjs +72 -0
  173. package/api/search/_priority.d.mts +50 -0
  174. package/api/search/_priority.mjs +139 -0
  175. package/api/search/_query-words.d.mts +25 -0
  176. package/api/search/_query-words.mjs +92 -0
  177. package/api/search/_query.d.mts +65 -0
  178. package/api/search/_query.mjs +176 -0
  179. package/api/search/_result.d.mts +97 -0
  180. package/api/search/_result.mjs +150 -0
  181. package/api/search/_score.d.mts +60 -0
  182. package/api/search/_score.mjs +283 -0
  183. package/api/search/_synonyms.d.mts +21 -0
  184. package/api/search/_synonyms.mjs +67 -0
  185. package/api/search/_template-searcher.d.mts +4 -0
  186. package/api/search/_template-searcher.mjs +23 -0
  187. package/api/search/_template-searcher.test.mjs +40 -0
  188. package/api/search/_template-searcher.weights.json +1 -0
  189. package/api/search/_titles.d.mts +33 -0
  190. package/api/search/_titles.mjs +65 -0
  191. package/api/search/_words.d.mts +64 -0
  192. package/api/search/_words.mjs +157 -0
  193. package/api/search/search.d.mts +22 -236
  194. package/api/search/search.doc.mjs +14 -7
  195. package/api/search/search.domain-priority.test.mjs +108 -18
  196. package/api/search/search.integration-check.test.mjs +24 -0
  197. package/api/search/search.mjs +59 -1904
  198. package/api/search/search.test.mjs +193 -15
  199. package/api/search/search.type.d.mts +20 -2
  200. package/api/search/search.type.mjs +12 -2
  201. package/api/search/tree.d.mts +15 -0
  202. package/api/search/tree.mjs +40 -0
  203. package/api/search/tree.test.mjs +66 -0
  204. package/api/search/tree.weights.json +1 -0
  205. package/api/swizzle/_adapter.mjs +2 -2
  206. package/api/swizzle/copy/copy.mjs +29 -15
  207. package/api/template/template-integration.test.mjs +1 -1
  208. package/api/template/template.mjs +5 -1
  209. package/api/template/template.test.mjs +120 -3
  210. package/api/theme/_adapter.d.mts +16 -0
  211. package/api/theme/_adapter.mjs +32 -5
  212. package/api/theme/build/build.d.mts +2 -1
  213. package/api/theme/build/build.family.test.mjs +64 -0
  214. package/api/theme/build/build.mjs +250 -38
  215. package/api/theme/build/build.packed-old-core.test.mjs +21 -3
  216. package/api/theme/build/font-warning.mjs +5 -3
  217. package/api/theme/build/font-warning.test.mjs +2 -1
  218. package/api/theme/remove/remove.test.mjs +2 -2
  219. package/api/theme/targets/targets.mjs +3 -10
  220. package/api/theme/themeBuild.doc.mjs +4 -4
  221. package/api/theme/themeTargets.doc.mjs +4 -0
  222. package/api/theme/use/use.test.mjs +1 -1
  223. package/api/upgrade/_adapter.d.mts +97 -11
  224. package/api/upgrade/_adapter.mjs +315 -32
  225. package/api/upgrade/registry/registry.d.mts +10 -4
  226. package/api/upgrade/registry/registry.mjs +33 -16
  227. package/api/upgrade/registry/registry.test.mjs +85 -0
  228. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  229. package/api/upgrade/run/run.d.mts +4 -2
  230. package/api/upgrade/run/run.mjs +48 -4
  231. package/api/upgrade/run/run.test.mjs +417 -3
  232. package/api/upgrade/status/status.d.mts +21 -5
  233. package/api/upgrade/status/status.mjs +45 -8
  234. package/api/upgrade/upgrade.doc.mjs +16 -8
  235. package/api/upgrade/upgrade.mjs +18 -3
  236. package/api/upgrade/upgrade.test.mjs +194 -0
  237. package/api/upgrade/upgrade.type.d.mts +28 -3
  238. package/api/upgrade/upgrade.type.mjs +24 -7
  239. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  240. package/assets/codemods/registry.mjs +1 -0
  241. package/assets/codemods/runner.mjs +7 -1
  242. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  243. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  244. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  245. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  246. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  247. package/assets/discover/official-packages.json +367 -0
  248. package/assets/docs/README.md +10 -0
  249. package/assets/docs/author-a-theme.doc.mjs +5 -5
  250. package/assets/docs/browser-support.doc.mjs +1 -1
  251. package/assets/docs/getting-started.doc.mjs +26 -6
  252. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  253. package/assets/docs/styling-overview.doc.mjs +1 -1
  254. package/assets/docs/theme.doc.dense.mjs +1 -1
  255. package/assets/docs/theme.doc.mjs +2 -2
  256. package/assets/docs/theme.doc.zh.mjs +1 -1
  257. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  258. package/assets/docs/tree/add-a-theme.doc.mjs +14 -4
  259. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  260. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  261. package/assets/docs/tree/api.doc.mjs +6 -0
  262. package/assets/docs/tree/authoring.doc.mjs +61 -0
  263. package/assets/docs/tree/block-template.doc.mjs +8 -20
  264. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  265. package/assets/docs/tree/building-blocks.doc.mjs +6 -2
  266. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  267. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  268. package/assets/docs/tree/checks.doc.mjs +32 -24
  269. package/assets/docs/tree/ci-and-containers.doc.mjs +101 -0
  270. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  271. package/assets/docs/tree/cli.doc.mjs +7 -1
  272. package/assets/docs/tree/codemods.doc.mjs +17 -7
  273. package/assets/docs/tree/commands.doc.mjs +7 -1
  274. package/assets/docs/tree/component-family.doc.mjs +8 -6
  275. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  276. package/assets/docs/tree/components.doc.mjs +7 -1
  277. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  278. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  279. package/assets/docs/tree/configuration.doc.mjs +8 -4
  280. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  281. package/assets/docs/tree/define-the-theme.doc.mjs +7 -6
  282. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  283. package/assets/docs/tree/docs.doc.mjs +9 -3
  284. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  285. package/assets/docs/tree/document-the-theme.doc.mjs +4 -4
  286. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  287. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  288. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  289. package/assets/docs/tree/fonts-and-assets.doc.mjs +3 -3
  290. package/assets/docs/tree/generate-a-palette.doc.mjs +8 -6
  291. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  292. package/assets/docs/tree/global.doc.mjs +131 -0
  293. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  294. package/assets/docs/tree/help.doc.mjs +2 -2
  295. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  296. package/assets/docs/tree/install-once.doc.mjs +105 -0
  297. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  298. package/assets/docs/tree/layout.doc.mjs +6 -6
  299. package/assets/docs/tree/links.doc.mjs +7 -6
  300. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  301. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  302. package/assets/docs/tree/migration.doc.mjs +0 -1
  303. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  304. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  305. package/assets/docs/tree/page-template.doc.mjs +4 -8
  306. package/assets/docs/tree/problems.doc.mjs +205 -0
  307. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  308. package/assets/docs/tree/publishing.doc.mjs +6 -6
  309. package/assets/docs/tree/quick-start.doc.mjs +54 -28
  310. package/assets/docs/tree/reference.doc.mjs +192 -0
  311. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  312. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  313. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  314. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  315. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  316. package/assets/docs/tree/ship.doc.mjs +2 -2
  317. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  318. package/assets/docs/tree/single-component.doc.mjs +15 -6
  319. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  320. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  321. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  322. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  323. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  324. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  325. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  326. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  327. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  328. package/assets/docs/tree/templates.doc.mjs +7 -1
  329. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  330. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  331. package/assets/docs/tree/themes.doc.mjs +5 -1
  332. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  333. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  334. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  335. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  336. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  337. package/assets/docs/tree/updates.doc.mjs +92 -0
  338. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  339. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +15 -3
  340. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  341. package/assets/docs/tree/versioning.doc.mjs +14 -9
  342. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  343. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  344. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  345. package/assets/docs/use-a-theme.doc.mjs +2 -2
  346. package/assets/docs/use-integrations.doc.mjs +120 -0
  347. package/assets/docs/working-with-ai.doc.mjs +70 -13
  348. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  349. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  350. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  351. package/assets/theme.template.ts +1 -1
  352. package/authoring/codemod/codemod.doc.mjs +7 -3
  353. package/authoring/config/config.doc.mjs +9 -6
  354. package/authoring/config/type.ts +4 -2
  355. package/authoring/debug/parse.d.mts +5 -5
  356. package/authoring/discover/discover.doc.mjs +7 -1
  357. package/authoring/doctypes/_schema.d.mts +8 -3
  358. package/authoring/doctypes/_schema.mjs +1 -0
  359. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  360. package/authoring/doctypes/command/command.doc.mjs +20 -12
  361. package/authoring/doctypes/command/type.ts +14 -0
  362. package/authoring/doctypes/component/component.doc.mjs +30 -27
  363. package/authoring/doctypes/component/type.ts +21 -8
  364. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  365. package/authoring/doctypes/function/function.doc.mjs +9 -8
  366. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  367. package/authoring/doctypes/hook/type.ts +4 -0
  368. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  369. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  370. package/authoring/doctypes/schema/schema.doc.mjs +10 -10
  371. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  372. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  373. package/authoring/doctypes/template/parse.d.mts +6 -2
  374. package/authoring/doctypes/template/parse.mjs +3 -1
  375. package/authoring/doctypes/template/template.doc.mjs +3 -3
  376. package/authoring/doctypes/template/type.ts +22 -0
  377. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  378. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  379. package/authoring/identity/identity.doc.mjs +3 -3
  380. package/authoring/index.d.ts +2 -0
  381. package/authoring/integration/integration.doc.mjs +30 -6
  382. package/authoring/integration/parse.test.mjs +21 -0
  383. package/authoring/integration/schema.d.mts +16 -3
  384. package/authoring/integration/schema.mjs +34 -2
  385. package/authoring/integration/type.ts +13 -1
  386. package/clients/cli/bin/astryx.mjs +11 -65
  387. package/clients/cli/cli-command.test.mjs +166 -0
  388. package/clients/cli/command-result-coverage.test.mjs +6 -5
  389. package/clients/cli/commands/blog.doc.mjs +1 -0
  390. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  391. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  392. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  393. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  394. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  395. package/clients/cli/commands/build.doc.mjs +1 -0
  396. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  397. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  398. package/clients/cli/commands/component.doc.mjs +1 -0
  399. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  400. package/clients/cli/commands/component.test.mjs +6 -6
  401. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  402. package/clients/cli/commands/discover.doc.mjs +9 -1
  403. package/clients/cli/commands/discover.mjs +144 -93
  404. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  405. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  406. package/clients/cli/commands/docs.doc.mjs +3 -2
  407. package/clients/cli/commands/docs.mjs +50 -20
  408. package/clients/cli/commands/docs.test.mjs +16 -16
  409. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  410. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  411. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  412. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  413. package/clients/cli/commands/doctor-integration.test.mjs +936 -3
  414. package/clients/cli/commands/doctor.doc.mjs +12 -2
  415. package/clients/cli/commands/doctor.mjs +332 -7
  416. package/clients/cli/commands/doctor.test.mjs +75 -4
  417. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  418. package/clients/cli/commands/gap-report.mjs +24 -2
  419. package/clients/cli/commands/gap-report.test.mjs +79 -0
  420. package/clients/cli/commands/hook.doc.mjs +1 -0
  421. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  422. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  423. package/clients/cli/commands/init.behavior.test.mjs +235 -1
  424. package/clients/cli/commands/init.doc.mjs +55 -10
  425. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  426. package/clients/cli/commands/init.mjs +2 -2
  427. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  428. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  429. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  430. package/clients/cli/commands/integration-check.test.mjs +489 -0
  431. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  432. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  433. package/clients/cli/commands/integration.doc.mjs +6 -2
  434. package/clients/cli/commands/integration.mjs +119 -7
  435. package/clients/cli/commands/json-contract.test.mjs +11 -2
  436. package/clients/cli/commands/manifest.doc.mjs +2 -1
  437. package/clients/cli/commands/manifest.mjs +67 -0
  438. package/clients/cli/commands/outside-project.test.mjs +874 -0
  439. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  440. package/clients/cli/commands/postinstall.mjs +31 -0
  441. package/clients/cli/commands/search.doc.mjs +1 -0
  442. package/clients/cli/commands/search.mjs +16 -11
  443. package/clients/cli/commands/search.test.mjs +429 -296
  444. package/clients/cli/commands/setup-nudge.test.mjs +180 -2
  445. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  446. package/clients/cli/commands/swizzle.mjs +5 -3
  447. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  448. package/clients/cli/commands/template.doc.mjs +1 -0
  449. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  450. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  451. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  452. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  453. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  454. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  455. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  456. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  457. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  458. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  459. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  460. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  461. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +27 -14
  462. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  463. package/clients/cli/commands/upgrade.doc.mjs +26 -3
  464. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  465. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  466. package/clients/cli/commands/upgrade.mjs +9 -2
  467. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  468. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  469. package/clients/cli/index.mjs +156 -100
  470. package/clients/cli/lib/cli-error.mjs +4 -1
  471. package/clients/cli/lib/component-format.mjs +1 -1
  472. package/clients/cli/lib/component-format.test.mjs +1 -1
  473. package/clients/cli/lib/define-command.mjs +14 -9
  474. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  475. package/clients/cli/lib/json-shim.mjs +3 -1
  476. package/clients/cli/lib/manifest.d.ts +9 -0
  477. package/clients/cli/lib/manifest.mjs +17 -1
  478. package/clients/cli/lib/manifest.test.mjs +37 -0
  479. package/clients/cli/lib/welcome-box.mjs +50 -0
  480. package/clients/cli/run.mjs +108 -0
  481. package/foundation/agent-docs/agent-doc-state.d.mts +67 -13
  482. package/foundation/agent-docs/agent-doc-state.mjs +123 -14
  483. package/foundation/agent-docs/agent-docs.d.mts +104 -15
  484. package/foundation/agent-docs/agent-docs.mjs +1028 -114
  485. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  486. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  487. package/foundation/agent-docs/computer-agent-text.d.mts +170 -0
  488. package/foundation/agent-docs/computer-agent-text.mjs +750 -0
  489. package/foundation/agent-docs/computer-agent-text.test.mjs +699 -0
  490. package/foundation/config/project.d.mts +35 -3
  491. package/foundation/config/project.mjs +243 -26
  492. package/foundation/config/project.test.mjs +122 -0
  493. package/foundation/config/theme-state.mjs +5 -4
  494. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  495. package/foundation/discovery/authoring-self-docs.mjs +17 -4
  496. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  497. package/foundation/discovery/authoring-surface.d.mts +1 -1
  498. package/foundation/discovery/authoring-surface.mjs +2 -2
  499. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  500. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  501. package/foundation/discovery/cli-self-docs.mjs +22 -4
  502. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  503. package/foundation/discovery/component-discovery.d.mts +227 -10
  504. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  505. package/foundation/discovery/component-discovery.mjs +940 -57
  506. package/foundation/discovery/component-discovery.test.mjs +96 -0
  507. package/foundation/discovery/component-loader.d.mts +1 -1
  508. package/foundation/discovery/component-replacement.mjs +20 -1
  509. package/foundation/discovery/component-replacement.test.mjs +40 -0
  510. package/foundation/discovery/copied-passages.d.mts +216 -0
  511. package/foundation/discovery/copied-passages.mjs +720 -0
  512. package/foundation/discovery/copied-passages.test.mjs +124 -0
  513. package/foundation/discovery/doc-consistency.d.mts +34 -0
  514. package/foundation/discovery/doc-consistency.mjs +513 -0
  515. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  516. package/foundation/discovery/doc-fluff.d.mts +112 -0
  517. package/foundation/discovery/doc-fluff.mjs +328 -0
  518. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  519. package/foundation/discovery/doc-types.d.mts +157 -0
  520. package/foundation/discovery/doc-types.mjs +1231 -0
  521. package/foundation/discovery/doc-types.test.mjs +744 -0
  522. package/foundation/discovery/docs-discovery.d.mts +88 -0
  523. package/foundation/discovery/docs-discovery.mjs +97 -3
  524. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  525. package/foundation/discovery/integration-doc-files.mjs +231 -0
  526. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  527. package/foundation/discovery/module-exports.d.mts +68 -0
  528. package/foundation/discovery/module-exports.mjs +609 -31
  529. package/foundation/discovery/module-exports.test.mjs +172 -0
  530. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  531. package/foundation/discovery/package-tsconfig.mjs +228 -0
  532. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  533. package/foundation/discovery/project-typescript.d.mts +32 -0
  534. package/foundation/discovery/project-typescript.mjs +89 -0
  535. package/foundation/discovery/prop-drift.d.mts +297 -0
  536. package/foundation/discovery/prop-drift.mjs +2428 -0
  537. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  538. package/foundation/discovery/runner-allowlist.d.mts +38 -0
  539. package/foundation/discovery/runner-allowlist.mjs +51 -0
  540. package/foundation/discovery/runner-commands.d.mts +77 -0
  541. package/foundation/discovery/runner-commands.mjs +294 -0
  542. package/foundation/discovery/runner-commands.test.mjs +128 -0
  543. package/foundation/discovery/stray-pointers.d.mts +52 -0
  544. package/foundation/discovery/stray-pointers.mjs +293 -0
  545. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  546. package/foundation/discovery/template-adapter.mjs +92 -6
  547. package/foundation/discovery/template-needs.mjs +6 -46
  548. package/foundation/discovery/theme-discovery.mjs +147 -3
  549. package/foundation/discovery/theme-imports.mjs +8 -4
  550. package/foundation/discovery/theme-imports.test.mjs +1 -1
  551. package/foundation/discovery/type-match.d.mts +53 -0
  552. package/foundation/discovery/type-match.mjs +660 -0
  553. package/foundation/discovery/type-match.test.mjs +169 -0
  554. package/foundation/discovery/type-text.d.mts +68 -0
  555. package/foundation/discovery/type-text.mjs +658 -0
  556. package/foundation/discovery/type-text.test.mjs +196 -0
  557. package/foundation/discovery/unresolved-references.d.mts +62 -0
  558. package/foundation/discovery/unresolved-references.mjs +790 -0
  559. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  560. package/foundation/doc-compiler/doc-loads.test.mjs +84 -10
  561. package/foundation/doc-compiler/inputs.mjs +27 -1
  562. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  563. package/foundation/doc-compiler/links.d.mts +41 -5
  564. package/foundation/doc-compiler/links.mjs +167 -28
  565. package/foundation/doc-compiler/links.test.mjs +97 -4
  566. package/foundation/doc-compiler/read.d.mts +1 -1
  567. package/foundation/doc-compiler/read.mjs +59 -1
  568. package/foundation/doc-compiler/read.test.mjs +11 -2
  569. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  570. package/foundation/doc-compiler/tree.d.mts +32 -6
  571. package/foundation/doc-compiler/tree.mjs +107 -44
  572. package/foundation/doc-compiler/tree.test.mjs +14 -7
  573. package/foundation/env/cli-command.d.mts +83 -0
  574. package/foundation/env/cli-command.mjs +152 -0
  575. package/foundation/env/cli-command.test.mjs +129 -0
  576. package/foundation/env/node-version.test.mjs +15 -3
  577. package/foundation/env/package-manager.d.mts +93 -9
  578. package/foundation/env/package-manager.global.test.mjs +66 -0
  579. package/foundation/env/package-manager.mjs +184 -13
  580. package/foundation/env/package-manager.test.mjs +341 -15
  581. package/foundation/env/project-scope.d.mts +9 -0
  582. package/foundation/env/project-scope.mjs +33 -0
  583. package/foundation/env/search-path.d.mts +42 -0
  584. package/foundation/env/search-path.mjs +205 -0
  585. package/foundation/env/search-path.test.mjs +122 -0
  586. package/foundation/env/user-dirs.d.mts +39 -0
  587. package/foundation/env/user-dirs.mjs +93 -0
  588. package/foundation/env/user-dirs.test.mjs +72 -0
  589. package/foundation/env/user-settings.d.mts +46 -0
  590. package/foundation/env/user-settings.mjs +106 -0
  591. package/foundation/env/user-settings.test.mjs +64 -0
  592. package/foundation/fs/file-protection.mjs +15 -1
  593. package/foundation/fs/module-loader.d.mts +2 -1
  594. package/foundation/fs/module-loader.mjs +60 -4
  595. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  596. package/foundation/fs/module-loader.test.mjs +194 -0
  597. package/foundation/fs/path-compare.d.mts +33 -0
  598. package/foundation/fs/path-compare.mjs +73 -0
  599. package/foundation/fs/paths.d.mts +122 -4
  600. package/foundation/fs/paths.mjs +675 -29
  601. package/foundation/fs/paths.test.mjs +439 -54
  602. package/foundation/fs/read-record.d.mts +18 -0
  603. package/foundation/fs/read-record.mjs +131 -0
  604. package/foundation/fs/read-record.test.mjs +77 -0
  605. package/foundation/integrations/autolink.d.mts +2 -1
  606. package/foundation/integrations/autolink.mjs +4 -13
  607. package/foundation/integrations/cli-peer-version.d.mts +36 -0
  608. package/foundation/integrations/cli-peer-version.mjs +132 -0
  609. package/foundation/integrations/cli-peer-version.test.mjs +354 -0
  610. package/foundation/integrations/computer-integrations.d.mts +81 -0
  611. package/foundation/integrations/computer-integrations.mjs +345 -0
  612. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  613. package/foundation/integrations/contribution-inventory.d.mts +26 -20
  614. package/foundation/integrations/contribution-inventory.mjs +97 -8
  615. package/foundation/integrations/exports-subpaths.d.mts +57 -0
  616. package/foundation/integrations/exports-subpaths.mjs +113 -0
  617. package/foundation/integrations/integration-warnings.mjs +3 -2
  618. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  619. package/foundation/integrations/integrations.d.mts +51 -1
  620. package/foundation/integrations/integrations.mjs +106 -4
  621. package/foundation/integrations/issue.ts +6 -0
  622. package/foundation/integrations/public-imports.d.mts +118 -0
  623. package/foundation/integrations/public-imports.mjs +1769 -0
  624. package/foundation/integrations/public-imports.test.mjs +1793 -0
  625. package/foundation/integrations/validate-contributions.d.mts +117 -0
  626. package/foundation/integrations/validate-contributions.mjs +1209 -14
  627. package/foundation/release/agent-text-worker.d.mts +4 -0
  628. package/foundation/release/agent-text-worker.mjs +52 -0
  629. package/foundation/release/cache.d.mts +310 -0
  630. package/foundation/release/cache.mjs +1216 -0
  631. package/foundation/release/cache.test.mjs +923 -0
  632. package/foundation/release/choose.d.mts +207 -0
  633. package/foundation/release/choose.mjs +677 -0
  634. package/foundation/release/choose.test.mjs +427 -0
  635. package/foundation/release/core-worker.d.mts +4 -0
  636. package/foundation/release/core-worker.mjs +38 -0
  637. package/foundation/release/global-state.d.mts +263 -0
  638. package/foundation/release/global-state.mjs +474 -0
  639. package/foundation/release/global-state.test.mjs +381 -0
  640. package/foundation/release/handoff.d.mts +79 -0
  641. package/foundation/release/handoff.e2e.test.mjs +278 -0
  642. package/foundation/release/handoff.mjs +524 -0
  643. package/foundation/release/lock-lease.d.mts +23 -0
  644. package/foundation/release/lock-lease.mjs +80 -0
  645. package/foundation/release/notices.d.mts +307 -0
  646. package/foundation/release/notices.mjs +707 -0
  647. package/foundation/release/notices.test.mjs +586 -0
  648. package/foundation/release/npm-guard.d.mts +4 -0
  649. package/foundation/release/npm-guard.mjs +126 -0
  650. package/foundation/release/project.d.mts +141 -0
  651. package/foundation/release/project.mjs +466 -0
  652. package/foundation/release/project.test.mjs +288 -0
  653. package/foundation/release/refresh-worker.d.mts +4 -0
  654. package/foundation/release/refresh-worker.mjs +27 -0
  655. package/foundation/release/run-context.d.mts +47 -0
  656. package/foundation/release/run-context.mjs +163 -0
  657. package/foundation/release/update-notice-env.d.mts +28 -0
  658. package/foundation/release/update-notice-env.mjs +39 -0
  659. package/foundation/response/base.d.ts +26 -3
  660. package/foundation/response/error-codes.d.mts +3 -1
  661. package/foundation/response/error-codes.doc.mjs +12 -0
  662. package/foundation/response/error-codes.mjs +17 -0
  663. package/foundation/response/error-codes.test.mjs +2 -0
  664. package/foundation/response/json-contract.test.mjs +7 -2
  665. package/foundation/response/json.mjs +4 -1
  666. package/foundation/response/response-types.doc.mjs +22 -11
  667. package/foundation/response/response-types.doc.test.mjs +46 -0
  668. package/foundation/response/response.doc.mjs +3 -3
  669. package/foundation/route/route.d.mts +285 -0
  670. package/foundation/route/route.mjs +324 -0
  671. package/foundation/route/route.test.mjs +153 -0
  672. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  673. package/foundation/runtime/locked-versions.d.mts +32 -0
  674. package/foundation/runtime/locked-versions.mjs +65 -0
  675. package/foundation/runtime/package-root.d.mts +91 -0
  676. package/foundation/runtime/package-root.mjs +174 -0
  677. package/foundation/runtime/package-set.d.mts +62 -0
  678. package/foundation/runtime/package-set.mjs +130 -0
  679. package/foundation/runtime/package-set.test.mjs +432 -0
  680. package/foundation/text/string-utils.d.mts +2 -1
  681. package/foundation/text/string-utils.mjs +16 -5
  682. package/foundation/text/suggest-order.d.mts +72 -0
  683. package/foundation/text/suggest-order.mjs +363 -0
  684. package/foundation/text/suggest-order.test.mjs +259 -0
  685. package/foundation/xle/browser-imports.test.mjs +74 -0
  686. package/foundation/xle/registry.mjs +4 -0
  687. package/foundation/xle/registry.test.mjs +28 -0
  688. package/host/door-conformance.test.mjs +274 -0
  689. package/host/index.d.ts +116 -0
  690. package/host/index.mjs +295 -0
  691. package/host/index.test.mjs +302 -0
  692. package/package.json +16 -11
  693. package/scripts/postinstall.mjs +24 -5
  694. package/assets/docs/tree/integrations.doc.mjs +0 -40
@@ -414,8 +414,9 @@ async function fetchLatestReceipt(
414
414
  /**
415
415
  * @param {string} receiptPath
416
416
  * @param {string} root
417
+ * @param {string} [display] the folder reported paths are relative to
417
418
  */
418
- function loadInstalledReceipt(receiptPath, root) {
419
+ function loadInstalledReceipt(receiptPath, root, display = root) {
419
420
  let receipt;
420
421
  let receiptText;
421
422
  try {
@@ -436,7 +437,7 @@ function loadInstalledReceipt(receiptPath, root) {
436
437
  }
437
438
  } catch (error) {
438
439
  throw new Error(
439
- `Invalid receipt ${relativePath(receiptPath, root)}: ${error instanceof Error ? error.message : String(error)}`,
440
+ `Invalid receipt ${relativePath(receiptPath, display)}: ${error instanceof Error ? error.message : String(error)}`,
440
441
  {cause: error},
441
442
  );
442
443
  }
@@ -445,7 +446,7 @@ function loadInstalledReceipt(receiptPath, root) {
445
446
  const candidates = receiptFileCandidates(receipt, file).map(candidate => {
446
447
  if (registryContentHash(candidate.content) !== candidate.sha256) {
447
448
  throw new Error(
448
- `Invalid receipt ${relativePath(receiptPath, root)}: stored hash does not match ${file.registryPath} (${candidate.format})`,
449
+ `Invalid receipt ${relativePath(receiptPath, display)}: stored hash does not match ${file.registryPath} (${candidate.format})`,
449
450
  );
450
451
  }
451
452
  let sourcePath;
@@ -458,7 +459,7 @@ function loadInstalledReceipt(receiptPath, root) {
458
459
  } catch (error) {
459
460
  if (error instanceof PathSafetyError) {
460
461
  throw new Error(
461
- `Invalid receipt ${relativePath(receiptPath, root)}: ${error.message}`,
462
+ `Invalid receipt ${relativePath(receiptPath, display)}: ${error.message}`,
462
463
  {cause: error},
463
464
  );
464
465
  }
@@ -471,7 +472,7 @@ function loadInstalledReceipt(receiptPath, root) {
471
472
  );
472
473
  if (existing.length > 1) {
473
474
  throw new Error(
474
- `Invalid receipt ${relativePath(receiptPath, root)}: multiple install variants exist for ${file.registryPath}`,
475
+ `Invalid receipt ${relativePath(receiptPath, display)}: multiple install variants exist for ${file.registryPath}`,
475
476
  );
476
477
  }
477
478
  return existing[0] ?? candidates[0];
@@ -483,12 +484,14 @@ function loadInstalledReceipt(receiptPath, root) {
483
484
  /**
484
485
  * @param {string} receiptPath
485
486
  * @param {string} root
486
- * @param {{fetchImpl: typeof fetch, registryOrigin: string, expectedVersion?: string}} options
487
+ * @param {{fetchImpl: typeof fetch, registryOrigin: string, expectedVersion?: string, display?: string}} options
488
+ * `display` is the folder reported paths are relative to, `root` by default
487
489
  */
488
490
  async function planReceipt(receiptPath, root, options) {
491
+ const display = options.display ?? root;
489
492
  let installed;
490
493
  try {
491
- installed = loadInstalledReceipt(receiptPath, root);
494
+ installed = loadInstalledReceipt(receiptPath, root, display);
492
495
  } catch (error) {
493
496
  return {
494
497
  receiptPath,
@@ -584,7 +587,7 @@ async function planReceipt(receiptPath, root, options) {
584
587
  oldReceiptText,
585
588
  };
586
589
  }
587
- const displayPath = relativePath(sourcePath, root);
590
+ const displayPath = relativePath(sourcePath, display);
588
591
  try {
589
592
  if (!fs.existsSync(sourcePath)) {
590
593
  plannedFiles.push({
@@ -636,7 +639,7 @@ async function planReceipt(receiptPath, root, options) {
636
639
  const newFile = newReceiptFile
637
640
  ? receiptFileForFormat(newReceipt, newReceiptFile, oldFile.format)
638
641
  : null;
639
- const displayPath = relativePath(oldFile.sourcePath, root);
642
+ const displayPath = relativePath(oldFile.sourcePath, display);
640
643
  if (!newReceiptFile) {
641
644
  plannedFiles.push({
642
645
  id: oldFile.id,
@@ -856,8 +859,12 @@ function publicAction(action, apply) {
856
859
  return action;
857
860
  }
858
861
 
859
- /** @param {any} item @param {string} root @param {boolean} apply */
860
- function publicItem(item, root, apply) {
862
+ /**
863
+ * @param {any} item
864
+ * @param {string} display the folder reported paths are relative to
865
+ * @param {boolean} apply
866
+ */
867
+ function publicItem(item, display, apply) {
861
868
  return {
862
869
  item: item.item,
863
870
  path: item.itemPath,
@@ -870,7 +877,7 @@ function publicItem(item, root, apply) {
870
877
  action: publicAction(file.action, apply),
871
878
  ...(file.message ? {message: file.message} : {}),
872
879
  ...(file.action === 'conflict' && file.conflictPath
873
- ? {conflictFile: relativePath(file.conflictPath, root)}
880
+ ? {conflictFile: relativePath(file.conflictPath, display)}
874
881
  : {}),
875
882
  }),
876
883
  ),
@@ -968,13 +975,17 @@ function applyPlan(plan) {
968
975
  }
969
976
 
970
977
  /**
978
+ * Reported paths are relative to the scanned source folder, or, when `origin`
979
+ * names the folder the command ran in below the project root `cwd`, to that
980
+ * folder, so they resolve from where the command ran.
971
981
  * @param {{apply?: boolean, path?: string}} options
972
- * @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
982
+ * @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
973
983
  */
974
984
  export async function reconcileRegistryCompositions(
975
985
  options = {},
976
986
  {
977
987
  cwd = process.cwd(),
988
+ origin,
978
989
  fetchImpl = globalThis.fetch,
979
990
  registryOrigin = PUBLIC_SHADCN_REGISTRY_ORIGIN,
980
991
  expectedVersion,
@@ -998,6 +1009,7 @@ export async function reconcileRegistryCompositions(
998
1009
  throw error;
999
1010
  }
1000
1011
 
1012
+ const display = origin ?? root;
1001
1013
  const apply = options.apply ?? false;
1002
1014
  const receipts = discoverRegistryReceipts(root);
1003
1015
  const summary = emptySummary(apply);
@@ -1019,6 +1031,7 @@ export async function reconcileRegistryCompositions(
1019
1031
  fetchImpl,
1020
1032
  registryOrigin,
1021
1033
  expectedVersion,
1034
+ display,
1022
1035
  }),
1023
1036
  );
1024
1037
 
@@ -1031,7 +1044,7 @@ export async function reconcileRegistryCompositions(
1031
1044
  summary.invalid++;
1032
1045
  }
1033
1046
  }
1034
- recordItem(summary, publicItem(plan, root, apply), plan.action, apply);
1047
+ recordItem(summary, publicItem(plan, display, apply), plan.action, apply);
1035
1048
  if (!apply) continue;
1036
1049
 
1037
1050
  try {
@@ -1119,13 +1132,17 @@ export function logRegistryCompositionSummary(summary) {
1119
1132
  }
1120
1133
 
1121
1134
  /**
1122
- * Standalone `astryx upgrade --registry` leaf.
1135
+ * Standalone `astryx upgrade --registry` leaf. `ctx.origin` is the folder the
1136
+ * command ran in, when `ctx.cwd` is the project root above it.
1123
1137
  * @param {{apply?: boolean, path?: string}} options
1124
- * @param {{cwd?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
1138
+ * @param {{cwd?: string, origin?: string, fetchImpl?: typeof fetch, registryOrigin?: string, expectedVersion?: string, requireExpectedVersion?: boolean}} [ctx]
1125
1139
  * @returns {Promise<import('../upgrade.type.mjs').UpgradeRegistryResponse>}
1126
1140
  */
1127
1141
  export async function registryUpgrade(options = {}, ctx = {}) {
1128
1142
  const cwd = ctx.cwd ?? process.cwd();
1143
+ if (ctx.origin != null) {
1144
+ logger.log(`Project root: ${path.relative(ctx.origin, cwd) || '.'}`);
1145
+ }
1129
1146
  const installed = detectInstalledTargetVersion(cwd);
1130
1147
  const expectedVersion =
1131
1148
  ctx.expectedVersion ??
@@ -19,6 +19,8 @@ import {
19
19
  discoverRegistryReceipts,
20
20
  reconcileRegistryCompositions,
21
21
  } from './registry.mjs';
22
+ import {upgrade} from '../upgrade.mjs';
23
+ import {logger} from '../../logger.mjs';
22
24
 
23
25
  const ITEM = {
24
26
  name: 'example-button-basic',
@@ -824,3 +826,86 @@ describe('registry composition upgrades', () => {
824
826
  expect(fs.readFileSync(sourcePath, 'utf8')).toBe('old\n');
825
827
  });
826
828
  });
829
+
830
+ describe('copied-composition paths name files from the folder the command ran in', () => {
831
+ it('below the project root, and from the scanned source folder at the root', async () => {
832
+ const {sourcePath} = seed({
833
+ base: 'value = 1\n',
834
+ current: 'value = local\n',
835
+ });
836
+ const fetchImpl = remote('value = upstream\n');
837
+ const origin = path.join(project, 'apps', 'web');
838
+
839
+ const [atRoot] = (await reconcile({}, {fetchImpl})).summary.items[0].files;
840
+ const [below] = (await reconcile({}, {fetchImpl, origin})).summary.items[0]
841
+ .files;
842
+
843
+ expect(atRoot).toMatchObject({
844
+ path: SOURCE_TARGET,
845
+ conflictFile: `${SOURCE_TARGET}.astryx-conflict`,
846
+ });
847
+ expect(below).toMatchObject({
848
+ path: `../../src/${SOURCE_TARGET}`,
849
+ conflictFile: `../../src/${SOURCE_TARGET}.astryx-conflict`,
850
+ });
851
+ expect(path.resolve(origin, below.path)).toBe(sourcePath);
852
+ });
853
+
854
+ it('for an invalid receipt too', async () => {
855
+ const value = receipt('base\n');
856
+ value.files[0].sha256 = '0'.repeat(64);
857
+ seed({base: 'base\n', receiptValue: value});
858
+ const fetchImpl = remote('new\n');
859
+ const origin = path.join(project, 'docs');
860
+
861
+ const [atRoot] = (await reconcile({}, {fetchImpl})).summary.items;
862
+ const [below] = (await reconcile({}, {fetchImpl, origin})).summary.items;
863
+
864
+ expect(atRoot.message).toContain(`Invalid receipt ${RECEIPT_TARGET}:`);
865
+ expect(below.message).toContain(
866
+ `Invalid receipt ../src/${RECEIPT_TARGET}:`,
867
+ );
868
+ });
869
+
870
+ it('through upgrade(), with --registry and in a run, which name the project root', async () => {
871
+ fs.writeFileSync(
872
+ path.join(project, 'package.json'),
873
+ JSON.stringify({
874
+ name: 'app',
875
+ dependencies: {'@astryxdesign/core': '0.6.0'},
876
+ }),
877
+ );
878
+ const core = path.join(project, 'node_modules', '@astryxdesign', 'core');
879
+ fs.mkdirSync(core, {recursive: true});
880
+ fs.writeFileSync(
881
+ path.join(core, 'package.json'),
882
+ JSON.stringify({name: '@astryxdesign/core', version: '0.6.0'}),
883
+ );
884
+ const frontend = path.join(project, 'frontend');
885
+ fs.mkdirSync(frontend);
886
+ seed({base: 'old\n'});
887
+ vi.stubGlobal('fetch', remote('new\n'));
888
+ const log = vi.spyOn(logger, 'log');
889
+ try {
890
+ const registry = await upgrade({registry: true}, {cwd: frontend});
891
+ const run = await upgrade({from: '0.6.0'}, {cwd: frontend});
892
+ const atRoot = await upgrade({registry: true}, {cwd: project});
893
+
894
+ expect(registry.data.items[0].files[0].path).toBe(
895
+ `../src/${SOURCE_TARGET}`,
896
+ );
897
+ expect(run.data.registryCompositions.items[0].files[0].path).toBe(
898
+ `../src/${SOURCE_TARGET}`,
899
+ );
900
+ expect(atRoot.data.items[0].files[0].path).toBe(SOURCE_TARGET);
901
+ expect(
902
+ log.mock.calls.filter(([line]) =>
903
+ String(line).startsWith('Project root:'),
904
+ ),
905
+ ).toEqual([['Project root: ..'], ['Project root: ..']]);
906
+ } finally {
907
+ vi.unstubAllGlobals();
908
+ log.mockRestore();
909
+ }
910
+ });
911
+ });
@@ -0,0 +1,438 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Core codemods ship inside the CLI, so a CLI older than the installed
5
+ * Core has none for the releases after its own version. Every result past the
6
+ * up-to-date exit says so in `cliBehindCore`, with the same upgrade pinned to
7
+ * the CLI release that matches the Core; a CLI that covers the range returns
8
+ * what it always did. The pinned command changes to the folder the run used
9
+ * and names the directory it scanned as an absolute path, both with symbolic
10
+ * links resolved, so a POSIX shell runs it there, with every argument
11
+ * unchanged, wherever it is pasted, even when upgrade() reached the project
12
+ * through a link.
13
+ */
14
+
15
+ import {describe, it, expect, beforeEach, afterEach, vi} from 'vitest';
16
+ import {execFileSync, spawnSync} from 'node:child_process';
17
+ import * as fs from 'node:fs';
18
+ import * as os from 'node:os';
19
+ import * as path from 'node:path';
20
+ import {upgrade} from '../upgrade.mjs';
21
+ import {logCliBehindCore} from '../status/status.mjs';
22
+ import {logger} from '../../logger.mjs';
23
+ import {CLI_ROOT} from '../../../foundation/fs/paths.mjs';
24
+ import {
25
+ commandInFolder,
26
+ getDlxPrefix,
27
+ quoteCommandArgument,
28
+ } from '../../../foundation/env/package-manager.mjs';
29
+
30
+ const SLOW = 30_000;
31
+
32
+ const CLI_VERSION = JSON.parse(
33
+ fs.readFileSync(path.join(CLI_ROOT, 'package.json'), 'utf8'),
34
+ ).version;
35
+ const [MAJOR, MINOR] = CLI_VERSION.split('.').map(Number);
36
+ /** A Core release after this CLI: it has no codemods for it. */
37
+ const NEWER_CORE = `${MAJOR}.${MINOR + 1}.0`;
38
+
39
+ /** A source file a 0.7.0 codemod rewrites (`emptySearchResultsText`). */
40
+ const TYPEAHEAD_SOURCE =
41
+ "import {Typeahead} from '@astryxdesign/core';\n" +
42
+ 'export const x = <Typeahead emptySearchResultsText="None" />;\n';
43
+
44
+ let dir;
45
+
46
+ /** @param {string} version @param {string} [packageName] */
47
+ function installCore(version, packageName = '@astryxdesign/core') {
48
+ const core = path.join(dir, 'node_modules', ...packageName.split('/'));
49
+ fs.mkdirSync(core, {recursive: true});
50
+ fs.writeFileSync(
51
+ path.join(core, 'package.json'),
52
+ JSON.stringify({name: packageName, version}),
53
+ );
54
+ }
55
+
56
+ /** @param {string} rel @param {string} body */
57
+ function write(rel, body) {
58
+ const file = path.join(dir, rel);
59
+ fs.mkdirSync(path.dirname(file), {recursive: true});
60
+ fs.writeFileSync(file, body);
61
+ }
62
+
63
+ /**
64
+ * A path in the project as a process running there sees it: every symbolic
65
+ * link resolved.
66
+ * @param {string} rel
67
+ */
68
+ function inProject(rel) {
69
+ return path.join(fs.realpathSync(dir), rel);
70
+ }
71
+
72
+ /**
73
+ * The pinned command for this project, as the CLI prints it.
74
+ * @param {...string} args the arguments after `upgrade`
75
+ */
76
+ function pinned(...args) {
77
+ return commandInFolder(
78
+ fs.realpathSync(dir),
79
+ [
80
+ getDlxPrefix(dir),
81
+ `@astryxdesign/cli@${NEWER_CORE}`,
82
+ 'upgrade',
83
+ ...args.map(arg => quoteCommandArgument(arg)),
84
+ ].join(' '),
85
+ );
86
+ }
87
+
88
+ /**
89
+ * Stand-ins for the package runners: each prints the folder it runs in and the
90
+ * arguments the shell passed.
91
+ */
92
+ const RUNNERS = ['npx', 'pnpm', 'yarn', 'bunx']
93
+ .map(
94
+ name =>
95
+ `${name}() { "$0" -e 'process.stdout.write(JSON.stringify({cwd: process.cwd(), argv: process.argv.slice(1)}))' -- "$@"; }`,
96
+ )
97
+ .join('; ');
98
+
99
+ /**
100
+ * What a POSIX shell runs for `command` pasted in `cwd`: the folder the
101
+ * package runner ran in, and its arguments from the pinned CLI package on.
102
+ * @param {string} command
103
+ * @param {string} cwd the folder the command is pasted in
104
+ * @returns {{cwd: string, args: string[]}}
105
+ */
106
+ function runInShell(command, cwd) {
107
+ const ran = JSON.parse(
108
+ execFileSync(
109
+ '/bin/sh',
110
+ ['-c', `${RUNNERS}; ${command}`, process.execPath],
111
+ {
112
+ cwd,
113
+ encoding: 'utf8',
114
+ },
115
+ ),
116
+ );
117
+ return {
118
+ cwd: ran.cwd,
119
+ args: ran.argv.slice(ran.argv.indexOf(`@astryxdesign/cli@${NEWER_CORE}`)),
120
+ };
121
+ }
122
+
123
+ beforeEach(() => {
124
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'upg-cli-behind-'));
125
+ write('package.json', JSON.stringify({name: 'consumer', version: '1.0.0'}));
126
+ write('src/index.tsx', TYPEAHEAD_SOURCE);
127
+ });
128
+
129
+ afterEach(() => fs.rmSync(dir, {recursive: true, force: true}));
130
+
131
+ describe('a CLI older than the installed Core', {timeout: SLOW}, () => {
132
+ // The defect: the range past this CLI has no codemods here, so the run
133
+ // reported `no_codemods` (and "already up to date") and exited 0, while the
134
+ // project still needed the newer releases' migrations.
135
+ it('marks a range this CLI has no codemods for, and names the CLI that does', async () => {
136
+ installCore(NEWER_CORE);
137
+
138
+ const res = await upgrade({from: CLI_VERSION, apply: true}, {cwd: dir});
139
+
140
+ expect(res.type).toBe('upgrade.status');
141
+ expect(res.data.status).toBe('no_codemods');
142
+ expect(res.data.cliBehindCore).toEqual({
143
+ cliVersion: CLI_VERSION,
144
+ command: pinned(
145
+ '--from',
146
+ CLI_VERSION,
147
+ '--path',
148
+ inProject('src'),
149
+ '--apply',
150
+ ),
151
+ });
152
+ });
153
+
154
+ it('runs the codemods it has for a range it covers only in part, and marks the rest', async () => {
155
+ installCore(NEWER_CORE);
156
+
157
+ const res = await upgrade({from: '0.6.8', apply: true}, {cwd: dir});
158
+
159
+ expect(res.type).toBe('upgrade.run');
160
+ expect(res.data.codemods).toBeGreaterThan(0);
161
+ expect(fs.readFileSync(path.join(dir, 'src/index.tsx'), 'utf8')).toContain(
162
+ 'emptySearchText="None"',
163
+ );
164
+ expect(res.data.cliBehindCore).toEqual({
165
+ cliVersion: CLI_VERSION,
166
+ command: pinned('--from', '0.6.8', '--path', inProject('src'), '--apply'),
167
+ });
168
+ });
169
+
170
+ it('repeats the invocation in the pinned command', async () => {
171
+ installCore(NEWER_CORE);
172
+ write('my src/index.tsx', TYPEAHEAD_SOURCE);
173
+ // An installed integration the run names, so --integration is repeated.
174
+ write(
175
+ 'node_modules/@acme/widgets/package.json',
176
+ JSON.stringify({name: '@acme/widgets', version: '1.0.0'}),
177
+ );
178
+ write(
179
+ 'node_modules/@acme/widgets/astryx.integration.mjs',
180
+ 'export default {};\n',
181
+ );
182
+
183
+ const res = await upgrade(
184
+ {
185
+ from: CLI_VERSION,
186
+ path: 'my src',
187
+ codemod: 'only-this',
188
+ skipCodemod: ['first', 'second'],
189
+ integration: ['@acme/widgets'],
190
+ force: true,
191
+ installDeps: true,
192
+ },
193
+ {cwd: dir},
194
+ );
195
+
196
+ expect(res.data.cliBehindCore?.command).toBe(
197
+ pinned(
198
+ '--from',
199
+ CLI_VERSION,
200
+ '--path',
201
+ inProject('my src'),
202
+ '--codemod',
203
+ 'only-this',
204
+ '--skip-codemod',
205
+ 'first',
206
+ '--skip-codemod',
207
+ 'second',
208
+ '--integration',
209
+ '@acme/widgets',
210
+ '--force',
211
+ '--install-deps',
212
+ ),
213
+ );
214
+ });
215
+
216
+ // Where an upgrade runs decides what it finds: the installed Core is read
217
+ // from that folder, and --path must stay inside it. The command printed
218
+ // without a folder failed when pasted anywhere else: ERR_PATH_TRAVERSAL from
219
+ // a subfolder, ERR_VERSION_DETECT from a parent. A package runner can also
220
+ // move the run: Yarn 1 runs `yarn astryx` at the project root.
221
+ it('changes to the folder the run used and names the directory it scanned as an absolute path', async () => {
222
+ installCore(NEWER_CORE);
223
+ write('app/index.tsx', TYPEAHEAD_SOURCE);
224
+ const project = fs.realpathSync(dir);
225
+
226
+ for (const [given, scanned] of [
227
+ [undefined, inProject('src')],
228
+ ['.', project],
229
+ ['app', inProject('app')],
230
+ ['./app/', inProject('app')],
231
+ ]) {
232
+ const res = await upgrade(
233
+ {from: CLI_VERSION, ...(given ? {path: given} : {})},
234
+ {cwd: dir},
235
+ );
236
+ const command = /** @type {string} */ (res.data.cliBehindCore?.command);
237
+
238
+ expect(command).toBe(pinned('--from', CLI_VERSION, '--path', scanned));
239
+ if (process.platform !== 'win32') {
240
+ for (const pastedIn of [
241
+ path.join(dir, 'app'),
242
+ path.dirname(dir),
243
+ path.parse(dir).root,
244
+ ]) {
245
+ const ran = runInShell(command, pastedIn);
246
+ expect(ran.cwd).toBe(project);
247
+ expect(ran.args[ran.args.indexOf('--path') + 1]).toBe(scanned);
248
+ }
249
+ }
250
+ }
251
+ });
252
+
253
+ it.skipIf(process.platform === 'win32')(
254
+ 'quotes the command so a POSIX shell enters the folder and passes every argument unchanged',
255
+ async () => {
256
+ fs.rmSync(dir, {recursive: true, force: true});
257
+ dir = fs.mkdtempSync(
258
+ path.join(os.tmpdir(), 'upg cost $5 `date` \'one\' "two" !x -'),
259
+ );
260
+ write(
261
+ 'package.json',
262
+ JSON.stringify({name: 'consumer', version: '1.0.0'}),
263
+ );
264
+ write('src/index.tsx', TYPEAHEAD_SOURCE);
265
+ installCore(NEWER_CORE);
266
+
267
+ const res = await upgrade(
268
+ {
269
+ from: CLI_VERSION,
270
+ skipCodemod: ["it's", 'a$b c'],
271
+ apply: true,
272
+ },
273
+ {cwd: dir},
274
+ );
275
+
276
+ const ran = runInShell(
277
+ /** @type {string} */ (res.data.cliBehindCore?.command),
278
+ path.dirname(dir),
279
+ );
280
+
281
+ expect(ran.cwd).toBe(fs.realpathSync(dir));
282
+ expect(ran.args).toEqual([
283
+ `@astryxdesign/cli@${NEWER_CORE}`,
284
+ 'upgrade',
285
+ '--from',
286
+ CLI_VERSION,
287
+ '--path',
288
+ inProject('src'),
289
+ '--skip-codemod',
290
+ "it's",
291
+ '--skip-codemod',
292
+ 'a$b c',
293
+ '--apply',
294
+ ]);
295
+ },
296
+ );
297
+ });
298
+
299
+ /** The CLI's own bin, which the stand-in runners below run. */
300
+ const BIN = path.join(CLI_ROOT, 'clients', 'cli', 'bin', 'astryx.mjs');
301
+
302
+ /**
303
+ * Stand-ins for the package runners: each drops its own words and the pinned
304
+ * package, then runs this CLI with the rest of the command.
305
+ */
306
+ const RUNS_THIS_CLI = /** @type {Array<[string, number]>} */ ([
307
+ ['npx', 1],
308
+ ['bunx', 1],
309
+ ['pnpm', 2],
310
+ ['yarn', 2],
311
+ ])
312
+ .map(
313
+ ([name, words]) =>
314
+ `${name}() { shift ${words}; "$0" ${quoteCommandArgument(BIN)} "$@"; }`,
315
+ )
316
+ .join('; ');
317
+
318
+ // A shell's `cd` follows a symbolic link, but the CLI it starts reads its
319
+ // folder with every link resolved and checks --path against that. A command
320
+ // that kept the link upgrade() was given exited 1 with ERR_PATH_TRAVERSAL.
321
+ describe.skipIf(process.platform === 'win32')(
322
+ 'a project upgrade() reaches through a symbolic link',
323
+ {timeout: SLOW},
324
+ () => {
325
+ /** @type {string} */
326
+ let base;
327
+
328
+ beforeEach(() => {
329
+ fs.rmSync(dir, {recursive: true, force: true});
330
+ base = fs.mkdtempSync(path.join(os.tmpdir(), 'upg-link-'));
331
+ dir = path.join(base, 'real', 'my app');
332
+ write(
333
+ 'package.json',
334
+ JSON.stringify({name: 'consumer', version: '1.0.0'}),
335
+ );
336
+ write('src/index.tsx', TYPEAHEAD_SOURCE);
337
+ installCore(NEWER_CORE);
338
+ });
339
+
340
+ afterEach(() => fs.rmSync(base, {recursive: true, force: true}));
341
+
342
+ /**
343
+ * Run upgrade() from `cwd`, then the command it prints, in /bin/sh, from
344
+ * `cwd` and from the folder above the project.
345
+ * @param {string} cwd
346
+ */
347
+ async function expectPrintedCommandToRun(cwd) {
348
+ const res = await upgrade({from: CLI_VERSION}, {cwd});
349
+ const command = /** @type {string} */ (res.data.cliBehindCore?.command);
350
+
351
+ for (const pastedIn of [cwd, base]) {
352
+ const ran = spawnSync(
353
+ '/bin/sh',
354
+ ['-c', `${RUNS_THIS_CLI}; ${command}`, process.execPath],
355
+ {cwd: pastedIn, encoding: 'utf8'},
356
+ );
357
+
358
+ expect(ran.status, ran.stderr).toBe(0);
359
+ expect(ran.stdout).toContain(`Installed target: ${NEWER_CORE}`);
360
+ expect(ran.stdout).toContain(`Scanning ${inProject('src')} `);
361
+ }
362
+ expect(command).toBe(
363
+ pinned('--from', CLI_VERSION, '--path', inProject('src')),
364
+ );
365
+ }
366
+
367
+ it('prints a command that runs, from a folder reached through a link above the project', async () => {
368
+ fs.symlinkSync(path.join(base, 'real'), path.join(base, 'link'), 'dir');
369
+
370
+ await expectPrintedCommandToRun(path.join(base, 'link', 'my app'));
371
+ });
372
+
373
+ it('prints a command that runs, through a project root that is a link', async () => {
374
+ fs.symlinkSync(dir, path.join(base, 'app'), 'dir');
375
+
376
+ await expectPrintedCommandToRun(path.join(base, 'app'));
377
+ });
378
+ },
379
+ );
380
+
381
+ describe('a CLI that covers the range', {timeout: SLOW}, () => {
382
+ it('adds nothing when the installed Core is this CLI release', async () => {
383
+ installCore(CLI_VERSION);
384
+
385
+ const res = await upgrade({from: '0.6.8'}, {cwd: dir});
386
+
387
+ expect(res.type).toBe('upgrade.run');
388
+ expect('cliBehindCore' in res.data).toBe(false);
389
+ });
390
+
391
+ it('adds nothing when --from is already the installed Core', async () => {
392
+ installCore(NEWER_CORE);
393
+
394
+ const res = await upgrade({from: NEWER_CORE}, {cwd: dir});
395
+
396
+ expect(res.data.status).toBe('up_to_date');
397
+ expect('cliBehindCore' in res.data).toBe(false);
398
+
399
+ const forced = await upgrade({from: NEWER_CORE, force: true}, {cwd: dir});
400
+
401
+ expect(forced.data.status).toBe('no_codemods');
402
+ expect('cliBehindCore' in forced.data).toBe(false);
403
+ });
404
+
405
+ it('adds nothing for legacy @xds/core, which shares no version with a CLI release', async () => {
406
+ installCore(NEWER_CORE, '@xds/core');
407
+
408
+ const res = await upgrade({from: CLI_VERSION}, {cwd: dir});
409
+
410
+ expect(res.data.status).toBe('no_codemods');
411
+ expect('cliBehindCore' in res.data).toBe(false);
412
+ });
413
+ });
414
+
415
+ describe('logCliBehindCore: the warning names the shell its command is written for', () => {
416
+ it.each([
417
+ ['win32', 'Run it in PowerShell with the CLI that matches your Core:'],
418
+ ['linux', 'Run it with the CLI that matches your Core:'],
419
+ ['darwin', 'Run it with the CLI that matches your Core:'],
420
+ ])('on %s', (platform, ending) => {
421
+ const warn = vi.spyOn(logger, 'warn').mockImplementation(() => {});
422
+ try {
423
+ logCliBehindCore(
424
+ {cliVersion: '0.7.0', command: 'cd x; npx y'},
425
+ '0.8.0',
426
+ platform,
427
+ );
428
+ expect(warn.mock.calls.map(([line]) => String(line))).toEqual([
429
+ expect.stringMatching(
430
+ new RegExp(`${ending.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}$`, 'u'),
431
+ ),
432
+ ' cd x; npx y',
433
+ ]);
434
+ } finally {
435
+ warn.mockRestore();
436
+ }
437
+ });
438
+ });