@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
@@ -1,75 +1,490 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file `astryx discover` when no discover source is configured and no
5
- * integration provides one.
4
+ * @file `astryx discover` and the official list the CLI carries
5
+ * (spec:AST-051 FR11), in projects with no discover source of their own.
6
6
  *
7
- * In a fresh public app with no integrations, `discover --available` used to
8
- * print "No integrations configured. Add integration package names..." — a
9
- * message that told users to add names they had no way to find. These tests
10
- * pin the honest replacement.
7
+ * A fresh app sees the official Astryx packages it could add, and a declared
8
+ * official theme counts as installed. In a project that loads no integration
9
+ * and has no source of its own, every query still answers with the list (FR1);
10
+ * a project that loads an integration gets package pages and search, where an
11
+ * official theme is added at a pinned version and then with `theme add`.
11
12
  */
12
13
 
13
14
  import {describe, it, expect, beforeEach, afterEach} from 'vitest';
14
15
  import * as fs from 'node:fs';
15
16
  import * as path from 'node:path';
16
17
  import * as os from 'node:os';
18
+ import {fileURLToPath} from 'node:url';
17
19
  import {runCli} from '../../../test-utils/run-cli.mjs';
18
20
 
21
+ const CLI_VERSION = JSON.parse(
22
+ fs.readFileSync(
23
+ path.resolve(
24
+ path.dirname(fileURLToPath(import.meta.url)),
25
+ '../../../package.json',
26
+ ),
27
+ 'utf8',
28
+ ),
29
+ ).version;
30
+
19
31
  let tmpDir;
20
32
  let project;
21
33
 
34
+ /** @param {object} [fields] */
35
+ function writeProject(fields = {}) {
36
+ fs.writeFileSync(
37
+ path.join(project, 'package.json'),
38
+ JSON.stringify({name: 'my-app', version: '1.0.0', ...fields}),
39
+ );
40
+ }
41
+
42
+ /** @param {string} name @param {string} version */
43
+ function install(name, version) {
44
+ const dir = path.join(project, 'node_modules', ...name.split('/'));
45
+ fs.mkdirSync(dir, {recursive: true});
46
+ fs.writeFileSync(
47
+ path.join(dir, 'package.json'),
48
+ JSON.stringify({name, version}),
49
+ );
50
+ }
51
+
52
+ /** A configured integration, so discover answers queries. */
53
+ function addIntegration() {
54
+ const pkg = path.join(project, 'node_modules', '@acme', 'ui');
55
+ fs.mkdirSync(path.join(pkg, 'components'), {recursive: true});
56
+ fs.writeFileSync(
57
+ path.join(pkg, 'package.json'),
58
+ '{"name":"@acme/ui","version":"1.0.0","type":"module"}',
59
+ );
60
+ fs.writeFileSync(
61
+ path.join(pkg, 'astryx.integration.mjs'),
62
+ "export default {components: './components'};\n",
63
+ );
64
+ fs.writeFileSync(
65
+ path.join(pkg, 'components', 'Widget.doc.mjs'),
66
+ 'export const doc = {type: "component", name: "Widget", description: "A widget"};\n',
67
+ );
68
+ fs.writeFileSync(
69
+ path.join(pkg, 'components', 'Widget.tsx'),
70
+ 'export function Widget() { return null; }\n',
71
+ );
72
+ writeProject({type: 'module'});
73
+ fs.writeFileSync(
74
+ path.join(project, 'astryx.config.mjs'),
75
+ "export default {integrations: ['@acme/ui']};\n",
76
+ );
77
+ }
78
+
22
79
  beforeEach(() => {
23
80
  tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-discover-nosource-'));
24
81
  project = path.join(tmpDir, 'project');
25
82
  fs.mkdirSync(project, {recursive: true});
26
- fs.writeFileSync(
27
- path.join(project, 'package.json'),
28
- JSON.stringify({name: 'my-app', version: '1.0.0'}),
29
- );
83
+ writeProject();
30
84
  });
31
85
 
32
86
  afterEach(() => {
33
87
  fs.rmSync(tmpDir, {recursive: true, force: true});
34
88
  });
35
89
 
36
- describe('astryx discover --available with no source', () => {
37
- it('explains what discover sources are and where to find packages', async () => {
38
- const {status, stdout} = await runCli(['discover', '--available'], {
90
+ describe('astryx discover in a project with nothing of its own', () => {
91
+ it('lists the official packages it could add, each with its add command, and no query hints', async () => {
92
+ const {status, stdout} = await runCli(['discover'], {cwd: project});
93
+
94
+ expect(status).toBe(0);
95
+ expect(stdout).toMatch(/^Available$/m);
96
+ expect(stdout).toMatch(/^from Astryx$/m);
97
+ expect(stdout).toMatch(/^name:\s+@astryxdesign\/theme-neutral$/m);
98
+ expect(stdout).toMatch(/^source:\s+Astryx$/m);
99
+ expect(stdout).toMatch(
100
+ new RegExp(
101
+ `^install:\\s+.* @astryxdesign/theme-neutral@${CLI_VERSION}$`,
102
+ 'm',
103
+ ),
104
+ );
105
+ expect(stdout).toContain('To add a package, run its install command.');
106
+ expect(stdout).toMatch(/theme add <theme>, for example .*theme add \w+/);
107
+ // Every query here returns this list, so the list must not suggest one.
108
+ expect(stdout).not.toContain('Usage:');
109
+ expect(stdout).not.toMatch(/discover <(package|search)>/);
110
+ });
111
+
112
+ it('keeps the list with meta.configured=false, and reports the official list in meta.sources', async () => {
113
+ const {status, stdout} = await runCli(['discover', '--json'], {
114
+ cwd: project,
115
+ });
116
+
117
+ expect(status).toBe(0);
118
+ const result = JSON.parse(stdout);
119
+ expect(result.type).toBe('discover.list');
120
+ expect(result.data).toEqual([]);
121
+ expect(result.meta.configured).toBe(false);
122
+ expect(result.meta.sources).toEqual([
123
+ {
124
+ name: 'Astryx',
125
+ from: '@astryxdesign/cli',
126
+ status: 'fresh',
127
+ complete: true,
128
+ },
129
+ ]);
130
+ expect(result.meta.available.length).toBeGreaterThan(0);
131
+ for (const entry of result.meta.available) {
132
+ expect(entry.source).toBe('Astryx');
133
+ expect(entry.name.startsWith('@astryxdesign/')).toBe(true);
134
+ }
135
+ expect(result.meta.available).toContainEqual(
136
+ expect.objectContaining({
137
+ name: '@astryxdesign/theme-neutral',
138
+ version: CLI_VERSION,
139
+ themes: ['neutral'],
140
+ }),
141
+ );
142
+ expect(result.meta.answeredBy).toEqual(expect.any(Object));
143
+ });
144
+
145
+ it('answers every query with the list, and says why in text', async () => {
146
+ for (const query of ['gothic', '@astryxdesign/theme-gothic', ' ']) {
147
+ const asJson = await runCli(['discover', query, '--json'], {
148
+ cwd: project,
149
+ });
150
+ expect(asJson.status, query).toBe(0);
151
+ expect(JSON.parse(asJson.stdout).type, query).toBe('discover.list');
152
+ }
153
+
154
+ const {stdout} = await runCli(['discover', 'gothic'], {cwd: project});
155
+ expect(stdout).toContain(
156
+ 'This project loads no integration and has no discover source of its own, so discover lists everything instead of answering "gothic".',
157
+ );
158
+ expect(stdout).not.toContain('Usage:');
159
+ });
160
+
161
+ it('counts a declared official theme as installed, keeps meta.configured, and does not offer it again', async () => {
162
+ writeProject({dependencies: {'@astryxdesign/theme-butter': CLI_VERSION}});
163
+ install('@astryxdesign/theme-butter', '0.7.0');
164
+
165
+ const {status, stdout} = await runCli(['discover', '--json'], {
166
+ cwd: project,
167
+ });
168
+
169
+ expect(status).toBe(0);
170
+ const {data, meta} = JSON.parse(stdout);
171
+ expect(data).toEqual([
172
+ expect.objectContaining({
173
+ name: '@astryxdesign/theme-butter',
174
+ version: '0.7.0',
175
+ themes: ['butter'],
176
+ latest: CLI_VERSION,
177
+ }),
178
+ ]);
179
+ expect(meta.configured).toBe(false);
180
+ expect(meta.available.map(entry => entry.name)).not.toContain(
181
+ '@astryxdesign/theme-butter',
182
+ );
183
+ });
184
+ });
185
+
186
+ describe('astryx discover and the project’s own package.json', () => {
187
+ it('counts a declared official theme as installed from a subfolder', async () => {
188
+ writeProject({dependencies: {'@astryxdesign/theme-butter': CLI_VERSION}});
189
+ install('@astryxdesign/theme-butter', '0.7.0');
190
+ const src = path.join(project, 'src', 'components');
191
+ fs.mkdirSync(src, {recursive: true});
192
+
193
+ const {status, stdout} = await runCli(['discover', '--json'], {cwd: src});
194
+
195
+ expect(status).toBe(0);
196
+ const {data, meta} = JSON.parse(stdout);
197
+ expect(data.map(entry => entry.name)).toEqual([
198
+ '@astryxdesign/theme-butter',
199
+ ]);
200
+ expect(meta.available.map(entry => entry.name)).not.toContain(
201
+ '@astryxdesign/theme-butter',
202
+ );
203
+ });
204
+
205
+ it('pins the exact Core version a fresh clone declares, before install', async () => {
206
+ writeProject({dependencies: {'@astryxdesign/core': '0.6.8'}});
207
+
208
+ const {status, stdout} = await runCli(['discover', '--json'], {
209
+ cwd: project,
210
+ });
211
+
212
+ expect(status).toBe(0);
213
+ const neutral = JSON.parse(stdout).meta.available.find(
214
+ entry => entry.name === '@astryxdesign/theme-neutral',
215
+ );
216
+ // The entry shows the latest release and installs the declared Core's.
217
+ expect(neutral.version).toBe(CLI_VERSION);
218
+ expect(neutral.install).toMatch(/ @astryxdesign\/theme-neutral@0\.6\.8$/);
219
+ });
220
+
221
+ it('pins the Core range a fresh clone declares, quoted for the shell', async () => {
222
+ writeProject({dependencies: {'@astryxdesign/core': '^0.6.8'}});
223
+
224
+ const {status, stdout} = await runCli(['discover', '--json'], {
225
+ cwd: project,
226
+ });
227
+
228
+ expect(status).toBe(0);
229
+ const neutral = JSON.parse(stdout).meta.available.find(
230
+ entry => entry.name === '@astryxdesign/theme-neutral',
231
+ );
232
+ expect(neutral.version).toBe(CLI_VERSION);
233
+ expect(neutral.install).toMatch(
234
+ / "@astryxdesign\/theme-neutral@\^0\.6\.8"$/,
235
+ );
236
+ });
237
+
238
+ it('neither installs nor offers an official theme the project only peer-depends on', async () => {
239
+ writeProject({
240
+ peerDependencies: {'@astryxdesign/theme-butter': '>=0.7.0'},
241
+ });
242
+
243
+ const {stdout} = await runCli(['discover', '--json'], {cwd: project});
244
+ const {data, meta} = JSON.parse(stdout);
245
+ expect(data).toEqual([]);
246
+ expect(meta.available.map(entry => entry.name)).not.toContain(
247
+ '@astryxdesign/theme-butter',
248
+ );
249
+ });
250
+
251
+ it('recognizes an official theme installed under an npm alias', async () => {
252
+ writeProject({
253
+ dependencies: {'my-butter': 'npm:@astryxdesign/theme-butter@0.7.0'},
254
+ });
255
+ install('my-butter', '0.7.0');
256
+
257
+ const {stdout} = await runCli(['discover', '--json'], {cwd: project});
258
+ expect(JSON.parse(stdout).data).toEqual([
259
+ expect.objectContaining({
260
+ name: '@astryxdesign/theme-butter',
261
+ version: '0.7.0',
262
+ }),
263
+ ]);
264
+ });
265
+ });
266
+
267
+ describe('astryx discover with a source that publishes an official integration under another name', () => {
268
+ beforeEach(() => {
269
+ writeProject({type: 'module'});
270
+ fs.writeFileSync(
271
+ path.join(project, 'astryx.config.mjs'),
272
+ `export default {
273
+ discover: async () => ({
274
+ schemaVersion: 1,
275
+ source: {name: 'Fork catalog', generatedAt: '2026-10-01T00:00:00Z', complete: true},
276
+ packages: [{
277
+ package: '@acme/gothic-fork',
278
+ integration: '@astryxdesign/theme-gothic',
279
+ aliases: [],
280
+ latest: '1.0.0',
281
+ versions: [{version: '1.0.0', publishedAt: null, prerelease: false, status: 'ok'}],
282
+ contributions: [{kind: 'theme', name: 'gothic-fork'}],
283
+ }],
284
+ }),
285
+ };
286
+ `,
287
+ );
288
+ });
289
+
290
+ it('keeps the source’s package in the list and in search', async () => {
291
+ const list = await runCli(['discover', '--available', '--json'], {
39
292
  cwd: project,
40
293
  });
294
+ const names = JSON.parse(list.stdout).meta.available.map(e => e.name);
295
+ expect(names).toContain('@acme/gothic-fork');
296
+ expect(names).not.toContain('@astryxdesign/theme-gothic');
41
297
 
298
+ const search = await runCli(['discover', 'fork', '--json'], {
299
+ cwd: project,
300
+ });
301
+ expect(search.status).toBe(0);
302
+ expect(JSON.parse(search.stdout).data.matches).toEqual(
303
+ expect.arrayContaining([
304
+ expect.objectContaining({package: '@acme/gothic-fork'}),
305
+ ]),
306
+ );
307
+ });
308
+ });
309
+
310
+ describe('astryx discover in a project that loads an integration', () => {
311
+ beforeEach(addIntegration);
312
+
313
+ it('lists official packages first among what it could add', async () => {
314
+ const {status, stdout} = await runCli(['discover', '--json'], {
315
+ cwd: project,
316
+ });
42
317
  expect(status).toBe(0);
43
- expect(stdout).toContain('No discover source is configured.');
44
- expect(stdout).toContain('discover sources');
45
- expect(stdout).toContain('npm search @astryxdesign');
46
- expect(stdout).toContain('docs cli/integrations');
47
- // Must not show the old misleading message
48
- expect(stdout).not.toContain('Add integration package names');
318
+ const {data, meta} = JSON.parse(stdout);
319
+ expect(data.map(entry => entry.name)).toEqual(['@acme/ui']);
320
+ expect(meta.available[0].source).toBe('Astryx');
49
321
  });
50
322
 
51
- it('returns an empty list with configured=false in --json', async () => {
323
+ it('adds a theme package at the version shown, then points to theme add', async () => {
52
324
  const {status, stdout} = await runCli(
53
- ['discover', '--available', '--json'],
325
+ ['discover', '@astryxdesign/theme-gothic'],
54
326
  {cwd: project},
55
327
  );
56
328
 
57
329
  expect(status).toBe(0);
58
- const result = JSON.parse(stdout);
59
- expect(result.type).toBe('discover.list');
60
- expect(result.data).toEqual([]);
61
- expect(result.meta).toEqual({configured: false});
330
+ expect(stdout).toMatch(/^installed:\s+false$/m);
331
+ expect(stdout).toContain(`@astryxdesign/theme-gothic@${CLI_VERSION}`);
332
+ expect(stdout).toContain('Then use its theme:');
333
+ expect(stdout).toMatch(/theme add gothic$/m);
334
+ expect(stdout).not.toContain('Astryx loads an integration');
62
335
  });
63
- });
64
336
 
65
- describe('astryx discover with nothing configured', () => {
66
- it('shows the config snippet and a pointer to npm and docs', async () => {
67
- const {status, stdout} = await runCli(['discover'], {cwd: project});
337
+ it("lists the latest release and the project's Core version, pins the Core version, and finds both", async () => {
338
+ for (const [core, latest] of [
339
+ ['0.6.8', CLI_VERSION],
340
+ ['99.0.0', '99.0.0'],
341
+ ]) {
342
+ install('@astryxdesign/core', core);
343
+
344
+ const page = await runCli(
345
+ ['discover', '@astryxdesign/theme-gothic', '--json'],
346
+ {cwd: project},
347
+ );
348
+ expect(page.status, core).toBe(0);
349
+ const {data} = JSON.parse(page.stdout);
350
+ expect(data.latest, core).toBe(latest);
351
+ expect(data.version, core).toBe(latest);
352
+ expect(data.versions.map(v => v.version).sort(), core).toEqual(
353
+ [...new Set([CLI_VERSION, core])].sort(),
354
+ );
355
+ expect(data.install, core).toMatch(
356
+ new RegExp(
357
+ ` @astryxdesign/theme-gothic@${core.replaceAll('.', '\\.')}$`,
358
+ ),
359
+ );
360
+
361
+ for (const wanted of new Set([core, CLI_VERSION])) {
362
+ const lookup = await runCli(
363
+ ['discover', `@astryxdesign/theme-gothic@${wanted}`, '--json'],
364
+ {cwd: project},
365
+ );
366
+ expect(lookup.status, `${core} ${wanted}`).toBe(0);
367
+ expect(JSON.parse(lookup.stdout).data.version, wanted).toBe(wanted);
368
+ }
369
+
370
+ const list = await runCli(['discover', '--json'], {cwd: project});
371
+ expect(
372
+ JSON.parse(list.stdout).meta.available.find(
373
+ entry => entry.name === '@astryxdesign/theme-gothic',
374
+ ).version,
375
+ core,
376
+ ).toBe(latest);
377
+ }
378
+ });
379
+
380
+ it('says which version its add command installs when the page shows the latest release', async () => {
381
+ install('@astryxdesign/core', '0.6.8');
382
+
383
+ const {status, stdout} = await runCli(
384
+ ['discover', '@astryxdesign/theme-gothic'],
385
+ {cwd: project},
386
+ );
68
387
 
69
388
  expect(status).toBe(0);
70
- expect(stdout).toContain('No integrations configured.');
71
- expect(stdout).toContain("integrations: ['@scope/your-integration']");
72
- expect(stdout).toContain('npm search @astryxdesign');
73
- expect(stdout).toContain('docs cli/integrations');
389
+ expect(stdout).toMatch(
390
+ new RegExp(`^latest:\\s+${CLI_VERSION.replaceAll('.', '\\.')}$`, 'm'),
391
+ );
392
+ expect(stdout).toMatch(/^- 0\.6\.8 {2}date unknown$/m);
393
+ // The verb follows the detected package manager.
394
+ expect(stdout).toMatch(/^\S+ \S+ @astryxdesign\/theme-gothic@0\.6\.8$/m);
395
+ expect(stdout).toContain(
396
+ "This installs 0.6.8, the version that matches this project's Core.",
397
+ );
398
+ });
399
+
400
+ it('pins the declared Core range on the page and says so', async () => {
401
+ writeProject({
402
+ type: 'module',
403
+ dependencies: {'@astryxdesign/core': '>=0.6.8 <0.8.0'},
404
+ });
405
+
406
+ const {status, stdout} = await runCli(
407
+ ['discover', '@astryxdesign/theme-gothic'],
408
+ {cwd: project},
409
+ );
410
+
411
+ expect(status).toBe(0);
412
+ expect(stdout).toMatch(
413
+ /^\S+ \S+ "@astryxdesign\/theme-gothic@>=0\.6\.8 <0\.8\.0"$/m,
414
+ );
415
+ expect(stdout).toContain(
416
+ 'This installs the newest release in >=0.6.8 <0.8.0, the Core range this project declares.',
417
+ );
418
+ });
419
+
420
+ it('keeps latest at the newest release for an installed official theme', async () => {
421
+ install('@astryxdesign/core', '0.6.8');
422
+ writeProject({
423
+ type: 'module',
424
+ dependencies: {'@astryxdesign/theme-butter': '0.6.8'},
425
+ });
426
+ install('@astryxdesign/theme-butter', '0.6.8');
427
+
428
+ const list = await runCli(['discover', '--json'], {cwd: project});
429
+ expect(
430
+ JSON.parse(list.stdout).data.find(
431
+ entry => entry.name === '@astryxdesign/theme-butter',
432
+ ),
433
+ ).toMatchObject({version: '0.6.8', latest: CLI_VERSION});
434
+
435
+ const page = await runCli(['discover', '@astryxdesign/theme-butter'], {
436
+ cwd: project,
437
+ });
438
+ expect(page.stdout).toMatch(
439
+ new RegExp(
440
+ `^- ${CLI_VERSION.replaceAll('.', '\\.')} {2}date unknown {2}latest$`,
441
+ 'm',
442
+ ),
443
+ );
444
+ expect(page.stdout).toMatch(/^- 0\.6\.8 {2}date unknown {2}installed$/m);
445
+ });
446
+
447
+ it('keeps the error code for a version or item of an official package it does not show', async () => {
448
+ for (const query of [
449
+ '@astryxdesign/theme-gothic@0.6.8',
450
+ '@astryxdesign/theme-gothic@latest',
451
+ '@astryxdesign/theme-gothic/nope',
452
+ ]) {
453
+ const {status, stdout} = await runCli(['discover', query, '--json'], {
454
+ cwd: project,
455
+ });
456
+ expect(status, query).toBe(1);
457
+ expect(JSON.parse(stdout).code, query).toBe('ERR_UNKNOWN_PACKAGE');
458
+ }
459
+ });
460
+
461
+ it('points an installed theme’s page at its items, not at components', async () => {
462
+ writeProject({
463
+ type: 'module',
464
+ dependencies: {'@astryxdesign/theme-butter': CLI_VERSION},
465
+ });
466
+ install('@astryxdesign/theme-butter', CLI_VERSION);
467
+
468
+ const {stdout} = await runCli(['discover', '@astryxdesign/theme-butter'], {
469
+ cwd: project,
470
+ });
471
+ expect(stdout).toContain('discover @astryxdesign/theme-butter/<item>');
472
+ expect(stdout).not.toContain('<ComponentName>');
473
+ });
474
+
475
+ it('finds an official theme by name', async () => {
476
+ const {status, stdout} = await runCli(['discover', 'gothic', '--json'], {
477
+ cwd: project,
478
+ });
479
+
480
+ expect(status).toBe(0);
481
+ expect(JSON.parse(stdout).data.matches).toContainEqual(
482
+ expect.objectContaining({
483
+ package: '@astryxdesign/theme-gothic',
484
+ component: 'gothic',
485
+ kind: 'theme',
486
+ installed: false,
487
+ }),
488
+ );
74
489
  });
75
490
  });
@@ -145,13 +145,20 @@ describe('astryx discover with a discover source', () => {
145
145
  latest: '3.2.0',
146
146
  }),
147
147
  ]);
148
- expect(meta.available).toEqual([
148
+ // The official packages come first, then what the project's source adds.
149
+ const official = meta.available.filter(entry => entry.source === 'Astryx');
150
+ expect(official.length).toBeGreaterThan(0);
151
+ expect(meta.available.slice(0, official.length)).toEqual(official);
152
+ // Each entry carries the command that adds it; a source's entry is not
153
+ // pinned, as on its package page.
154
+ expect(meta.available.slice(official.length)).toEqual([
149
155
  {
150
156
  name: '@test/charts',
151
157
  components: ['Chart'],
152
158
  version: '2.0.0',
153
159
  templates: ['pages/Report'],
154
160
  source: 'Test catalog',
161
+ install: expect.stringMatching(/ @test\/charts$/),
155
162
  },
156
163
  {
157
164
  name: '@test/boards',
@@ -159,14 +166,26 @@ describe('astryx discover with a discover source', () => {
159
166
  version: '1.0.0',
160
167
  templates: ['pages/DialBoard'],
161
168
  source: 'Test catalog',
169
+ install: expect.stringMatching(/ @test\/boards$/),
162
170
  },
163
171
  ]);
172
+ for (const entry of official) {
173
+ expect(entry.install).toMatch(
174
+ new RegExp(` ${entry.name}@${entry.version.replaceAll('.', '\\.')}$`),
175
+ );
176
+ }
164
177
  expect(meta.sources).toEqual([
165
178
  expect.objectContaining({
166
179
  name: 'Test catalog',
167
180
  from: 'astryx.config',
168
181
  status: 'fresh',
169
182
  }),
183
+ {
184
+ name: 'Astryx',
185
+ from: '@astryxdesign/cli',
186
+ status: 'fresh',
187
+ complete: true,
188
+ },
170
189
  ]);
171
190
  });
172
191
 
@@ -63,6 +63,7 @@ export const doc = {
63
63
  {label: 'One API function', cli: 'astryx docs cli/api/functions/search'},
64
64
  {label: 'A whole guide', cli: 'astryx docs cli/integrations/quick-start --full'},
65
65
  ],
66
+ outsideProject: 'same',
66
67
  exitCodes: [
67
68
  {code: 0, when: 'success'},
68
69
  {