@astryxdesign/cli 0.7.2 → 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 (373) hide show
  1. package/README.md +104 -71
  2. package/api/build/_adapter.d.mts +58 -0
  3. package/api/build/_adapter.mjs +127 -3
  4. package/api/build/blocks/blocks.d.mts +92 -0
  5. package/api/build/blocks/blocks.mjs +528 -0
  6. package/api/build/blocks/blocks.test.mjs +238 -0
  7. package/api/build/blocks/blocks.weights.json +1 -0
  8. package/api/build/build.mjs +25 -6
  9. package/api/build/build.type.mjs +1 -1
  10. package/api/build/kit/answer.d.mts +18 -0
  11. package/api/build/kit/answer.mjs +195 -0
  12. package/api/build/kit/answer.test.mjs +108 -0
  13. package/api/build/kit/kind.d.mts +25 -0
  14. package/api/build/kit/kind.mjs +170 -0
  15. package/api/build/kit/kit.d.mts +2 -4
  16. package/api/build/kit/kit.mjs +8 -398
  17. package/api/build/kit/rank.d.mts +3 -32
  18. package/api/build/kit/rank.mjs +25 -342
  19. package/api/build/kit/rank.test.mjs +2 -1
  20. package/api/build/kit/signals.d.mts +79 -0
  21. package/api/build/kit/signals.mjs +295 -0
  22. package/api/build/kit/start.d.mts +32 -0
  23. package/api/build/kit/start.mjs +163 -0
  24. package/api/build/kit/words.d.mts +72 -0
  25. package/api/build/kit/words.mjs +202 -0
  26. package/api/build/tree.d.mts +20 -0
  27. package/api/build/tree.mjs +53 -0
  28. package/api/build/tree.test.mjs +185 -0
  29. package/api/build/tree.weights.json +1 -0
  30. package/api/component/_adapter.mjs +39 -5
  31. package/api/component/component-replacement.test.mjs +1 -0
  32. package/api/component/component.mjs +17 -3
  33. package/api/component/component.test.mjs +15 -0
  34. package/api/component/doc-links.test.mjs +2 -2
  35. package/api/discover/_adapter.d.mts +1 -2
  36. package/api/discover/_adapter.mjs +42 -17
  37. package/api/discover/_adapter.test.mjs +42 -0
  38. package/api/discover/discover.mjs +0 -1
  39. package/api/docs/_adapter.d.mts +2 -2
  40. package/api/docs/_adapter.mjs +82 -23
  41. package/api/docs/docs-homes.test.mjs +127 -0
  42. package/api/docs/docs.doc.mjs +3 -3
  43. package/api/docs/docs.test.mjs +35 -19
  44. package/api/docs/integration-tree.test.mjs +20 -20
  45. package/api/docs/integrationDocs.test.mjs +1 -1
  46. package/api/docs/namespace-section.test.mjs +6 -6
  47. package/api/docs/reference-blocks.test.mjs +2 -2
  48. package/api/doctor/_adapter.d.mts +33 -13
  49. package/api/doctor/_adapter.mjs +55 -25
  50. package/api/doctor/doctor.d.mts +23 -5
  51. package/api/doctor/doctor.mjs +183 -40
  52. package/api/doctor/doctor.test.mjs +95 -12
  53. package/api/hook/hook.mjs +1 -1
  54. package/api/init/init.doc.mjs +20 -6
  55. package/api/init/init.test.mjs +18 -2
  56. package/api/init/init.type.d.mts +3 -3
  57. package/api/init/init.type.mjs +3 -3
  58. package/api/init/remove/remove.mjs +17 -4
  59. package/api/init/remove/remove.test.mjs +114 -2
  60. package/api/init/run/run.mjs +69 -6
  61. package/api/integration/_adapter.d.mts +8 -0
  62. package/api/integration/_adapter.mjs +21 -1
  63. package/api/integration/authoring-checks.mjs +83 -9
  64. package/api/integration/authoring-checks.test.mjs +220 -0
  65. package/api/integration/pack-check.mjs +123 -4
  66. package/api/integration/pack-check.test.mjs +87 -0
  67. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  68. package/api/integration/validate-integration-fixes.test.mjs +6 -5
  69. package/api/integration/validate-integration-gaps.test.mjs +1975 -0
  70. package/api/integration/validate-integration.d.mts +15 -2
  71. package/api/integration/validate-integration.mjs +298 -39
  72. package/api/integration/validate-integration.type.d.mts +90 -1
  73. package/api/integration/validate-integration.type.mjs +67 -2
  74. package/api/integration/validateIntegration.doc.mjs +1 -1
  75. package/api/search/ORDERING.md +28 -0
  76. package/api/search/_adapter.d.mts +82 -2
  77. package/api/search/_adapter.mjs +157 -10
  78. package/api/search/_adapter.test.mjs +173 -0
  79. package/api/search/_candidate-score.d.mts +40 -0
  80. package/api/search/_candidate-score.mjs +238 -0
  81. package/api/search/_cards.json +6098 -0
  82. package/api/search/_compound.d.mts +50 -0
  83. package/api/search/_compound.mjs +170 -0
  84. package/api/search/_doc-searcher.d.mts +4 -0
  85. package/api/search/_doc-searcher.mjs +23 -0
  86. package/api/search/_doc-searcher.test.mjs +36 -0
  87. package/api/search/_doc-searcher.weights.json +1 -0
  88. package/api/search/_doc-text.d.mts +30 -0
  89. package/api/search/_doc-text.mjs +87 -0
  90. package/api/search/_entries.d.mts +63 -0
  91. package/api/search/_entries.mjs +232 -0
  92. package/api/search/_entries.test.mjs +48 -0
  93. package/api/search/_features.d.mts +35 -0
  94. package/api/search/_features.mjs +155 -0
  95. package/api/search/_gather-components.d.mts +26 -0
  96. package/api/search/_gather-components.mjs +284 -0
  97. package/api/search/_gather-docs.d.mts +20 -0
  98. package/api/search/_gather-docs.mjs +254 -0
  99. package/api/search/_gather-hooks.d.mts +12 -0
  100. package/api/search/_gather-hooks.mjs +52 -0
  101. package/api/search/_gather-templates.d.mts +25 -0
  102. package/api/search/_gather-templates.mjs +107 -0
  103. package/api/search/_lexical.d.mts +135 -0
  104. package/api/search/_lexical.mjs +351 -0
  105. package/api/search/_main-searcher.d.mts +19 -0
  106. package/api/search/_main-searcher.mjs +115 -0
  107. package/api/search/_main-searcher.test.mjs +106 -0
  108. package/api/search/_main-searcher.weights.json +1 -0
  109. package/api/search/_module-doc.d.mts +32 -0
  110. package/api/search/_module-doc.mjs +78 -0
  111. package/api/search/_order.d.mts +32 -0
  112. package/api/search/_order.mjs +162 -0
  113. package/api/search/_order.test.mjs +72 -0
  114. package/api/search/_priority.d.mts +50 -0
  115. package/api/search/_priority.mjs +139 -0
  116. package/api/search/_query-words.d.mts +25 -0
  117. package/api/search/_query-words.mjs +92 -0
  118. package/api/search/_query.d.mts +65 -0
  119. package/api/search/_query.mjs +176 -0
  120. package/api/search/_result.d.mts +97 -0
  121. package/api/search/_result.mjs +150 -0
  122. package/api/search/_score.d.mts +60 -0
  123. package/api/search/_score.mjs +283 -0
  124. package/api/search/_synonyms.d.mts +21 -0
  125. package/api/search/_synonyms.mjs +67 -0
  126. package/api/search/_template-searcher.d.mts +4 -0
  127. package/api/search/_template-searcher.mjs +23 -0
  128. package/api/search/_template-searcher.test.mjs +40 -0
  129. package/api/search/_template-searcher.weights.json +1 -0
  130. package/api/search/_titles.d.mts +33 -0
  131. package/api/search/_titles.mjs +65 -0
  132. package/api/search/_words.d.mts +64 -0
  133. package/api/search/_words.mjs +157 -0
  134. package/api/search/search.d.mts +22 -305
  135. package/api/search/search.doc.mjs +8 -6
  136. package/api/search/search.mjs +56 -2482
  137. package/api/search/search.test.mjs +14 -14
  138. package/api/search/search.type.d.mts +6 -1
  139. package/api/search/search.type.mjs +6 -1
  140. package/api/search/tree.d.mts +15 -0
  141. package/api/search/tree.mjs +40 -0
  142. package/api/search/tree.test.mjs +66 -0
  143. package/api/search/tree.weights.json +1 -0
  144. package/api/template/template.mjs +5 -1
  145. package/api/theme/build/build.packed-old-core.test.mjs +1 -0
  146. package/api/upgrade/_adapter.d.mts +57 -9
  147. package/api/upgrade/_adapter.mjs +198 -28
  148. package/api/upgrade/registry/registry.d.mts +10 -4
  149. package/api/upgrade/registry/registry.mjs +33 -16
  150. package/api/upgrade/registry/registry.test.mjs +85 -0
  151. package/api/upgrade/run/run.d.mts +4 -2
  152. package/api/upgrade/run/run.mjs +13 -2
  153. package/api/upgrade/run/run.test.mjs +417 -3
  154. package/api/upgrade/upgrade.doc.mjs +10 -5
  155. package/api/upgrade/upgrade.mjs +13 -2
  156. package/api/upgrade/upgrade.test.mjs +194 -0
  157. package/api/upgrade/upgrade.type.d.mts +5 -3
  158. package/api/upgrade/upgrade.type.mjs +8 -6
  159. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  160. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  161. package/assets/docs/author-a-theme.doc.mjs +2 -2
  162. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  163. package/assets/docs/tree/add-a-component.doc.mjs +1 -1
  164. package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
  165. package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
  166. package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
  167. package/assets/docs/tree/api.doc.mjs +6 -0
  168. package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
  169. package/assets/docs/tree/block-template.doc.mjs +1 -1
  170. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  171. package/assets/docs/tree/building-blocks.doc.mjs +2 -2
  172. package/assets/docs/tree/check-the-props.doc.mjs +1 -1
  173. package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
  174. package/assets/docs/tree/checks.doc.mjs +3 -3
  175. package/assets/docs/tree/ci-and-containers.doc.mjs +13 -0
  176. package/assets/docs/tree/cli-command.doc.mjs +1 -1
  177. package/assets/docs/tree/cli.doc.mjs +1 -1
  178. package/assets/docs/tree/codemods.doc.mjs +1 -1
  179. package/assets/docs/tree/component-family.doc.mjs +1 -1
  180. package/assets/docs/tree/component-imports.doc.mjs +1 -1
  181. package/assets/docs/tree/components.doc.mjs +1 -1
  182. package/assets/docs/tree/configuration.doc.mjs +1 -1
  183. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
  184. package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
  185. package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
  186. package/assets/docs/tree/docs.doc.mjs +1 -1
  187. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  188. package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
  189. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  190. package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
  191. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  192. package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
  193. package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
  194. package/assets/docs/tree/global-integrations.doc.mjs +2 -2
  195. package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
  196. package/assets/docs/tree/help.doc.mjs +2 -2
  197. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  198. package/assets/docs/tree/links.doc.mjs +1 -1
  199. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  200. package/assets/docs/tree/page-template.doc.mjs +1 -1
  201. package/assets/docs/tree/publishing.doc.mjs +1 -1
  202. package/assets/docs/tree/quick-start.doc.mjs +1 -1
  203. package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
  204. package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
  207. package/assets/docs/tree/ship.doc.mjs +2 -2
  208. package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
  209. package/assets/docs/tree/single-component.doc.mjs +1 -1
  210. package/assets/docs/tree/start-a-template.doc.mjs +1 -1
  211. package/assets/docs/tree/subcomponent.doc.mjs +1 -1
  212. package/assets/docs/tree/template-assets.doc.mjs +1 -1
  213. package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
  214. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  215. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  216. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  217. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  218. package/assets/docs/tree/template-styles.doc.mjs +1 -1
  219. package/assets/docs/tree/templates.doc.mjs +1 -1
  220. package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
  221. package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
  222. package/assets/docs/tree/themes.doc.mjs +1 -1
  223. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  224. package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
  225. package/assets/docs/tree/upgrading.doc.mjs +1 -1
  226. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
  227. package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
  228. package/assets/docs/tree/versioning.doc.mjs +5 -1
  229. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  230. package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
  231. package/assets/docs/use-integrations.doc.mjs +120 -0
  232. package/assets/docs/working-with-ai.doc.mjs +6 -2
  233. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  234. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  235. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  236. package/authoring/debug/parse.d.mts +1 -1
  237. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  238. package/authoring/integration/integration.doc.mjs +1 -1
  239. package/authoring/integration/type.ts +1 -1
  240. package/clients/cli/bin/astryx.mjs +7 -78
  241. package/clients/cli/command-result-coverage.test.mjs +6 -5
  242. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  243. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  244. package/clients/cli/commands/component.test.mjs +6 -6
  245. package/clients/cli/commands/docs.doc.mjs +2 -2
  246. package/clients/cli/commands/docs.mjs +1 -1
  247. package/clients/cli/commands/docs.test.mjs +14 -14
  248. package/clients/cli/commands/doctor-integration.test.mjs +49 -1
  249. package/clients/cli/commands/doctor.doc.mjs +1 -1
  250. package/clients/cli/commands/doctor.mjs +40 -0
  251. package/clients/cli/commands/doctor.test.mjs +65 -0
  252. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  253. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  254. package/clients/cli/commands/init.behavior.test.mjs +230 -1
  255. package/clients/cli/commands/init.doc.mjs +28 -9
  256. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  257. package/clients/cli/commands/init.mjs +2 -2
  258. package/clients/cli/commands/integration-check.test.mjs +48 -0
  259. package/clients/cli/commands/integration.doc.mjs +1 -1
  260. package/clients/cli/commands/manifest.doc.mjs +1 -1
  261. package/clients/cli/commands/manifest.mjs +67 -0
  262. package/clients/cli/commands/outside-project.test.mjs +101 -1
  263. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  264. package/clients/cli/commands/postinstall.mjs +31 -0
  265. package/clients/cli/commands/setup-nudge.test.mjs +78 -0
  266. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
  267. package/clients/cli/commands/upgrade.doc.mjs +4 -2
  268. package/clients/cli/commands/upgrade.mjs +9 -2
  269. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  270. package/clients/cli/index.mjs +54 -94
  271. package/clients/cli/lib/component-format.mjs +1 -1
  272. package/clients/cli/lib/define-command.mjs +12 -7
  273. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  274. package/clients/cli/lib/manifest.test.mjs +12 -0
  275. package/clients/cli/lib/welcome-box.mjs +50 -0
  276. package/clients/cli/run.mjs +108 -0
  277. package/foundation/agent-docs/agent-doc-state.d.mts +32 -7
  278. package/foundation/agent-docs/agent-doc-state.mjs +58 -9
  279. package/foundation/agent-docs/agent-docs.d.mts +100 -12
  280. package/foundation/agent-docs/agent-docs.mjs +1017 -105
  281. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  282. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  283. package/foundation/agent-docs/computer-agent-text.d.mts +39 -2
  284. package/foundation/agent-docs/computer-agent-text.mjs +135 -8
  285. package/foundation/agent-docs/computer-agent-text.test.mjs +99 -2
  286. package/foundation/config/project.mjs +20 -22
  287. package/foundation/config/project.test.mjs +56 -0
  288. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  289. package/foundation/discovery/authoring-self-docs.mjs +16 -4
  290. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  291. package/foundation/discovery/authoring-surface.d.mts +1 -1
  292. package/foundation/discovery/authoring-surface.mjs +2 -2
  293. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  294. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  295. package/foundation/discovery/cli-self-docs.mjs +4 -3
  296. package/foundation/discovery/cli-self-docs.test.mjs +2 -2
  297. package/foundation/discovery/component-discovery.d.mts +37 -0
  298. package/foundation/discovery/component-discovery.mjs +80 -5
  299. package/foundation/discovery/component-loader.d.mts +1 -1
  300. package/foundation/discovery/docs-discovery.mjs +14 -1
  301. package/foundation/discovery/module-exports.d.mts +41 -0
  302. package/foundation/discovery/module-exports.mjs +253 -0
  303. package/foundation/discovery/runner-allowlist.d.mts +2 -4
  304. package/foundation/discovery/runner-allowlist.mjs +2 -4
  305. package/foundation/discovery/runner-commands.d.mts +77 -0
  306. package/foundation/discovery/runner-commands.mjs +294 -0
  307. package/foundation/discovery/runner-commands.test.mjs +128 -0
  308. package/foundation/discovery/stray-pointers.test.mjs +1 -1
  309. package/foundation/discovery/template-adapter.mjs +18 -1
  310. package/foundation/discovery/template-needs.mjs +1 -44
  311. package/foundation/discovery/theme-discovery.mjs +147 -3
  312. package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
  313. package/foundation/doc-compiler/read.mjs +59 -1
  314. package/foundation/doc-compiler/read.test.mjs +11 -2
  315. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  316. package/foundation/doc-compiler/tree.d.mts +32 -6
  317. package/foundation/doc-compiler/tree.mjs +77 -43
  318. package/foundation/doc-compiler/tree.test.mjs +7 -7
  319. package/foundation/fs/paths.d.mts +70 -8
  320. package/foundation/fs/paths.mjs +556 -38
  321. package/foundation/fs/paths.test.mjs +430 -54
  322. package/foundation/fs/read-record.d.mts +18 -0
  323. package/foundation/fs/read-record.mjs +131 -0
  324. package/foundation/fs/read-record.test.mjs +77 -0
  325. package/foundation/integrations/autolink.d.mts +2 -1
  326. package/foundation/integrations/autolink.mjs +4 -13
  327. package/foundation/integrations/cli-peer-version.d.mts +36 -0
  328. package/foundation/integrations/cli-peer-version.mjs +132 -0
  329. package/foundation/integrations/cli-peer-version.test.mjs +354 -0
  330. package/foundation/integrations/computer-integrations.d.mts +6 -3
  331. package/foundation/integrations/computer-integrations.mjs +38 -9
  332. package/foundation/integrations/contribution-inventory.d.mts +15 -20
  333. package/foundation/integrations/contribution-inventory.mjs +41 -5
  334. package/foundation/integrations/exports-subpaths.d.mts +57 -0
  335. package/foundation/integrations/exports-subpaths.mjs +113 -0
  336. package/foundation/integrations/integrations.d.mts +27 -1
  337. package/foundation/integrations/integrations.mjs +61 -2
  338. package/foundation/integrations/public-imports.d.mts +118 -0
  339. package/foundation/integrations/public-imports.mjs +1769 -0
  340. package/foundation/integrations/public-imports.test.mjs +1793 -0
  341. package/foundation/integrations/validate-contributions.d.mts +115 -0
  342. package/foundation/integrations/validate-contributions.mjs +1168 -13
  343. package/foundation/release/cache.test.mjs +24 -21
  344. package/foundation/release/global-state.d.mts +8 -4
  345. package/foundation/release/global-state.mjs +4 -2
  346. package/foundation/release/handoff.d.mts +23 -4
  347. package/foundation/release/handoff.mjs +175 -8
  348. package/foundation/release/notices.d.mts +62 -8
  349. package/foundation/release/notices.mjs +136 -25
  350. package/foundation/release/notices.test.mjs +21 -0
  351. package/foundation/release/run-context.mjs +14 -0
  352. package/foundation/response/response-types.doc.mjs +1 -1
  353. package/foundation/route/route.d.mts +285 -0
  354. package/foundation/route/route.mjs +324 -0
  355. package/foundation/route/route.test.mjs +153 -0
  356. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  357. package/foundation/runtime/locked-versions.d.mts +32 -0
  358. package/foundation/runtime/locked-versions.mjs +65 -0
  359. package/foundation/runtime/package-root.d.mts +91 -0
  360. package/foundation/runtime/package-root.mjs +174 -0
  361. package/foundation/runtime/package-set.d.mts +62 -0
  362. package/foundation/runtime/package-set.mjs +130 -0
  363. package/foundation/runtime/package-set.test.mjs +432 -0
  364. package/foundation/text/string-utils.d.mts +2 -1
  365. package/foundation/text/string-utils.mjs +16 -5
  366. package/foundation/text/suggest-order.d.mts +72 -0
  367. package/foundation/text/suggest-order.mjs +363 -0
  368. package/foundation/text/suggest-order.test.mjs +259 -0
  369. package/host/door-conformance.test.mjs +274 -0
  370. package/host/index.d.ts +116 -0
  371. package/host/index.mjs +295 -0
  372. package/host/index.test.mjs +302 -0
  373. package/package.json +14 -9
@@ -25,6 +25,8 @@ import {
25
25
  availableComputerIntegrations,
26
26
  } from '../../foundation/config/project.mjs';
27
27
  import {isOutsideProject} from '../../foundation/env/project-scope.mjs';
28
+ import {projectAddCommand} from '../../foundation/release/notices.mjs';
29
+ import {hostedRun} from '../../foundation/runtime/package-root.mjs';
28
30
  import {
29
31
  scanAllPackages,
30
32
  findComponentInPackages,
@@ -242,6 +244,7 @@ export async function describeInstalled(project, scanned) {
242
244
  * @returns {boolean}
243
245
  */
244
246
  export function hasSources(project) {
247
+ if (doorSources().length > 0) return true;
245
248
  if (project == null) return false;
246
249
  if (typeof project.config?.discover === 'function') return true;
247
250
  return project.loadedIntegrations.some(
@@ -249,6 +252,19 @@ export function hasSources(project) {
249
252
  );
250
253
  }
251
254
 
255
+ /** Where a discover source a host passed comes from (spec AST-081 FR1). */
256
+ const DOOR_SOURCE = 'the host';
257
+
258
+ /**
259
+ * The discover sources the host that started this run passed, if any.
260
+ * @returns {readonly DiscoverSource[]}
261
+ */
262
+ function doorSources() {
263
+ return /** @type {readonly DiscoverSource[]} */ (
264
+ hostedRun()?.discoverSources ?? []
265
+ );
266
+ }
267
+
252
268
  /** The source name of a package installed for the computer. */
253
269
  const COMPUTER_SOURCE = 'installed for this computer';
254
270
 
@@ -259,17 +275,14 @@ const COMPUTER_SOURCE = 'installed for this computer';
259
275
  * @param {Project | undefined} project
260
276
  * @param {Array<{name: string}>} installed
261
277
  * @param {Set<string>} declared
262
- * @param {(name: string, version?: string) => string} add
263
278
  * @returns {Promise<import('./discover.type.mjs').DiscoverAvailableEntry[]>}
264
279
  */
265
- export async function computerAvailableEntries(
266
- project,
267
- installed,
268
- declared,
269
- add,
270
- ) {
280
+ export async function computerAvailableEntries(project, installed, declared) {
271
281
  const cwd = project?.cwd ?? process.cwd();
272
282
  if (isOutsideProject(cwd)) return [];
283
+ // The same command doctor names: in the project spec:AST-040 FR9 defines,
284
+ // and none where FR9 finds no project.
285
+ const add = projectAddCommand(cwd);
273
286
  const have = new Set([...installed.map(pkg => pkg.name), ...declared]);
274
287
  return (await availableComputerIntegrations(cwd, have)).map(c => ({
275
288
  name: c.name,
@@ -277,7 +290,7 @@ export async function computerAvailableEntries(
277
290
  ...(c.version ? {version: c.version} : {}),
278
291
  ...(c.description ? {description: c.description} : {}),
279
292
  source: COMPUTER_SOURCE,
280
- install: add(c.name),
293
+ ...(add ? {install: add(c.name)} : {}),
281
294
  }));
282
295
  }
283
296
 
@@ -479,7 +492,8 @@ export function defaultCacheDir() {
479
492
 
480
493
  /**
481
494
  * @param {string} cacheDir
482
- * @param {string} from
495
+ * @param {string} from the source's key: its `from` label, with the host for
496
+ * a host's source
483
497
  * @param {{package?: string, version?: string}} request
484
498
  */
485
499
  function savedCopyPath(cacheDir, from, request) {
@@ -557,8 +571,9 @@ async function callSource(source, request, label, timeoutMs) {
557
571
  }
558
572
 
559
573
  /**
560
- * Call the project's own discover sources — the project's `discover` first,
561
- * then each integration's in load order — once per distinct function. A source that
574
+ * Call the discover sources — the project's `discover` first, then each
575
+ * integration's in load order, then each a host passed, named as the host's
576
+ * (spec AST-081 FR1, AST-051 FR6) — once per distinct function. A source that
562
577
  * throws, times out, or returns an invalid catalog falls back to its saved copy;
563
578
  * with none, it is reported and adds nothing. The others always count.
564
579
  *
@@ -572,20 +587,30 @@ async function callOwnSources(project, request = {}, options = {}) {
572
587
  const {cacheDir = defaultCacheDir(), timeoutMs = SOURCE_TIMEOUT_MS} = options;
573
588
  /** @type {CatalogResult} */
574
589
  const result = {sources: [], packages: []};
575
- if (project == null) return result;
590
+ const fromDoor = doorSources();
591
+ if (project == null && fromDoor.length === 0) return result;
576
592
 
577
- /** @type {Array<{from: string, source?: DiscoverSource, error?: string}>} */
593
+ /** @type {Array<{from: string, key?: string, source?: DiscoverSource, error?: string}>} */
578
594
  const origins = [];
579
- if (typeof project.config?.discover === 'function') {
595
+ if (typeof project?.config?.discover === 'function') {
580
596
  origins.push({from: 'astryx.config', source: project.config.discover});
581
597
  }
582
- for (const integration of project.loadedIntegrations) {
598
+ for (const integration of project?.loadedIntegrations ?? []) {
583
599
  if (integration.__discoverError) {
584
600
  origins.push({from: integration.name, error: integration.__discoverError});
585
601
  } else if (integration.__discover) {
586
602
  origins.push({from: integration.name, source: integration.__discover});
587
603
  }
588
604
  }
605
+ // Every tool that carries the CLI reports its sources as the host's, so
606
+ // their saved copies are kept per host, by the root that holds its CLI
607
+ // (spec:AST-051 FR8).
608
+ const host = hostedRun()?.startingRoot ?? '';
609
+ fromDoor.forEach((source, index) => {
610
+ const from =
611
+ fromDoor.length === 1 ? DOOR_SOURCE : `${DOOR_SOURCE} (${index + 1})`;
612
+ origins.push({from, key: `${from}\n${host}`, source});
613
+ });
589
614
 
590
615
  /** @type {Set<unknown>} */
591
616
  const called = new Set();
@@ -594,7 +619,7 @@ async function callOwnSources(project, request = {}, options = {}) {
594
619
  const ask = request.package
595
620
  ? {package: request.package, ...(request.version ? {version: request.version} : {})}
596
621
  : {};
597
- for (const {from, source, error} of origins) {
622
+ for (const {from, key = from, source, error} of origins) {
598
623
  if (source == null) {
599
624
  result.sources.push({name: from, from, status: 'failed', error});
600
625
  continue;
@@ -603,7 +628,7 @@ async function callOwnSources(project, request = {}, options = {}) {
603
628
  called.add(source);
604
629
 
605
630
  const label = `the discover source from ${from}`;
606
- const file = savedCopyPath(cacheDir, from, ask);
631
+ const file = savedCopyPath(cacheDir, key, ask);
607
632
  /** @type {import('../../authoring/discover/type').DiscoverCatalog} */
608
633
  let catalog;
609
634
  try {
@@ -21,6 +21,10 @@ import {
21
21
  withDeclaredOfficial,
22
22
  } from './_adapter.mjs';
23
23
  import {parseDiscoverCatalog} from '../../authoring/discover/parse.mjs';
24
+ import {
25
+ _resetHostedRun,
26
+ activateHostedRun,
27
+ } from '../../foundation/runtime/package-root.mjs';
24
28
 
25
29
  /** No official packages, so a test sees only its own sources after it. */
26
30
  const NO_OFFICIAL = {packages: []};
@@ -230,6 +234,44 @@ describe('callSources', () => {
230
234
  expect(otherRequest.sources[0].status).toBe('failed');
231
235
  });
232
236
 
237
+ it("keeps a host's saved copies per host, so one tool never answers with another's", async () => {
238
+ let online = true;
239
+ const source = async () => {
240
+ if (!online) throw new Error('offline');
241
+ return catalog('Acme catalog', [pkg('@acme/one')]);
242
+ };
243
+ const options = {cacheDir, official: NO_OFFICIAL};
244
+ try {
245
+ activateHostedRun({
246
+ discoverSources: [source],
247
+ startingRoot: '/tools/acme',
248
+ });
249
+ await callSources(undefined, {}, options);
250
+ online = false;
251
+ const sameHost = await callSources(undefined, {}, options);
252
+ expect(sameHost.sources[0]).toMatchObject({
253
+ name: 'Acme catalog',
254
+ from: 'the host',
255
+ status: 'saved',
256
+ });
257
+
258
+ _resetHostedRun();
259
+ activateHostedRun({
260
+ discoverSources: [source],
261
+ startingRoot: '/tools/other',
262
+ });
263
+ const otherHost = await callSources(undefined, {}, options);
264
+ expect(otherHost.sources[0]).toMatchObject({
265
+ from: 'the host',
266
+ status: 'failed',
267
+ error: 'offline',
268
+ });
269
+ expect(otherHost.packages).toEqual([]);
270
+ } finally {
271
+ _resetHostedRun();
272
+ }
273
+ });
274
+
233
275
  it('keeps the saved copy in the cache directory, not in the project', async () => {
234
276
  await callSources(
235
277
  project({
@@ -223,7 +223,6 @@ export async function discover(query, options = {}) {
223
223
  project,
224
224
  packages,
225
225
  declared,
226
- add,
227
226
  );
228
227
  const fromSources = officialFirst(
229
228
  availableEntries(catalog, packages, declared, {
@@ -226,7 +226,7 @@ export function topicUp(entry: import("../../foundation/discovery/docs-discovery
226
226
  export function placeLinks(tree: DocsTree, node: TreeNode): import("./docs.type.mjs").DocsLinks;
227
227
  /**
228
228
  * The moves a topic read offers: from its place in the tree, where a guide
229
- * sits in its namespace and a flat topic in the Unorganized level.
229
+ * sits in its namespace and a flat topic in its topic level.
230
230
  * @param {DocsCatalog} catalog
231
231
  * @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
232
232
  * @returns {Promise<import('./docs.type.mjs').DocsLinks>}
@@ -290,7 +290,7 @@ export function holdsOwnName(tree: DocsTree, catalog: DocsCatalog, entry: import
290
290
  /**
291
291
  * The doc that took a flat topic's route in the docs tree, when it is not
292
292
  * that topic (spec:AST-046 FR11): the CLI keeps its routes, such as `cli`
293
- * and `unorganized`, and a namespace keeps its route over a topic of the same
293
+ * and `guides`, and a namespace keeps its route over a topic of the same
294
294
  * name. Null when the topic owns its route, or the tree has no node there.
295
295
  * @param {DocsTree} tree
296
296
  * @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
@@ -52,6 +52,7 @@ import {
52
52
  cliDocSection,
53
53
  } from '../../foundation/discovery/cli-self-docs.mjs';
54
54
  import {
55
+ AUTHORING_REFERENCE_ROUTE,
55
56
  loadAuthoringSelfDocs,
56
57
  schemaFieldTable,
57
58
  selfDocSection,
@@ -70,6 +71,7 @@ import {
70
71
  import {findCoreDir} from '../../foundation/fs/paths.mjs';
71
72
  import {AstryxError} from '../error.mjs';
72
73
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
74
+ import {orderRouteSuggestions} from '../../foundation/text/suggest-order.mjs';
73
75
  import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
74
76
 
75
77
  export {OVERLAY_LANGUAGES, overlayLanguages};
@@ -385,7 +387,7 @@ export function projectTree(catalog, {fresh = false} = {}) {
385
387
  let cliTreeInputs;
386
388
 
387
389
  /**
388
- * Every flat topic in the catalog, as the tree's Unorganized level reads it.
390
+ * Every flat topic in the catalog, as the tree's topic levels read it.
389
391
  * @param {DocsCatalog} catalog
390
392
  * @returns {Promise<import('../../foundation/doc-compiler/tree.mjs').TreeTopicInput[]>}
391
393
  */
@@ -394,12 +396,13 @@ async function flatTopicInputs(catalog) {
394
396
  const topics = [];
395
397
  for (const entry of catalog.entries()) {
396
398
  const aliases = catalog.aliasesOf(entry);
397
- let {title, description} = entry;
398
- if (title == null || description == null) {
399
+ let {title, description, category} = entry;
400
+ if (title == null || description == null || category === undefined) {
399
401
  try {
400
402
  const file = await loadTopicFile(entry.path, null);
401
403
  title ??= file.doc?.title;
402
404
  description ??= file.doc?.description;
405
+ category ??= file.doc?.category;
403
406
  } catch {
404
407
  // A topic that does not load is reported where it is read.
405
408
  }
@@ -410,6 +413,7 @@ async function flatTopicInputs(catalog) {
410
413
  name: entry.name,
411
414
  title: title ?? entry.name,
412
415
  summary: description ?? '',
416
+ category: category ?? null,
413
417
  source: `${entry.package}:${entry.name}`,
414
418
  ...(aliases.length > 0 ? {aliases} : {}),
415
419
  });
@@ -419,7 +423,7 @@ async function flatTopicInputs(catalog) {
419
423
 
420
424
  /**
421
425
  * The CLI's tree, each configured integration's namespaces and guides, and
422
- * every flat topic in the generated Unorganized level.
426
+ * every flat topic in the generated level for its category.
423
427
  * @param {DocsCatalog} catalog
424
428
  * @param {boolean} fresh
425
429
  * @returns {Promise<DocsTree>}
@@ -509,23 +513,22 @@ function identitiesOf(tree) {
509
513
  }
510
514
 
511
515
  /**
512
- * The CLI's authoring docs, by kind and name. `astryx docs authoring` reads
513
- * each as one section keyed by its name, so a link to one opens that section.
514
- * Loaded once per process, like the CLI's tree files.
516
+ * The CLI's authoring docs, by kind and name. The field reference under
517
+ * `astryx docs authoring` reads each as one section keyed by its name, so a
518
+ * link to one opens that section. Loaded once per process, like the CLI's
519
+ * tree files.
515
520
  * @type {Promise<Map<string, any>> | undefined}
516
521
  */
517
522
  let authoringDocs;
518
523
 
519
524
  /**
520
- * The CLI authoring doc a link names, while `astryx docs authoring` is the
521
- * CLI's own topic.
522
- * @param {DocsCatalog} catalog
525
+ * The CLI authoring doc a link names. The `authoring` namespace is the CLI's
526
+ * own, so no integration can take its route.
523
527
  * @param {string} kind
524
528
  * @param {string} name
525
529
  * @returns {Promise<any | null>}
526
530
  */
527
- async function authoringDoc(catalog, kind, name) {
528
- if (catalog.resolve('authoring')?.package !== CLI_PROVIDER_ID) return null;
531
+ async function authoringDoc(kind, name) {
529
532
  authoringDocs ??= loadAuthoringSelfDocs().then(
530
533
  ({loaded}) =>
531
534
  new Map(loaded.map(({doc}) => [`${doc.type}\u0000${doc.name}`, doc])),
@@ -611,14 +614,14 @@ function docFinderOver(catalog, tree, fromProvider, summaries = true) {
611
614
  }
612
615
  const authored =
613
616
  provider === CLI_PROVIDER_ID
614
- ? await authoringDoc(catalog, parsed.kind, parsed.name)
617
+ ? await authoringDoc(parsed.kind, parsed.name)
615
618
  : null;
616
619
  if (authored) {
617
620
  return {
618
621
  link: {
619
622
  target,
620
623
  id: createDocId(provider, authored.type, authored.name),
621
- route: 'authoring',
624
+ route: AUTHORING_REFERENCE_ROUTE,
622
625
  title: authored.displayName ?? authored.name,
623
626
  summary: authored.description ?? '',
624
627
  command: `astryx docs authoring ${authored.name}`,
@@ -1146,6 +1149,14 @@ function packageCatalog(integration, discovered) {
1146
1149
  * @returns {Promise<Array<{severity: 'warning', message: string}>>}
1147
1150
  */
1148
1151
  export async function packageComponentLinkProblems(integration, discovered) {
1152
+ // A package with no provider id (its manifest's, else its name) links
1153
+ // nothing, as on the read path: its text reads as written, so there is
1154
+ // nothing to report.
1155
+ try {
1156
+ normalizeProviderId(integration.providerId ?? integration.name);
1157
+ } catch {
1158
+ return [];
1159
+ }
1149
1160
  const catalog = packageCatalog(integration, discovered);
1150
1161
  return (await componentLinkProblems(catalog, integration.name)).map(
1151
1162
  message => ({severity: /** @type {const} */ ('warning'), message}),
@@ -1176,11 +1187,15 @@ async function componentLinkProblems(catalog, owner) {
1176
1187
  // The components check reports a doc that does not load.
1177
1188
  continue;
1178
1189
  }
1179
- const linked = await linkComponentDoc(
1180
- catalog,
1181
- componentLinkProvider(record.package, record.providerId),
1182
- doc,
1183
- );
1190
+ let provider;
1191
+ try {
1192
+ provider = componentLinkProvider(record.package, record.providerId);
1193
+ } catch {
1194
+ // An owner that is not a provider id links nothing (as on the read
1195
+ // path); its text reads as written.
1196
+ continue;
1197
+ }
1198
+ const linked = await linkComponentDoc(catalog, provider, doc);
1184
1199
  const name = typeof doc?.name === 'string' ? doc.name : record.name;
1185
1200
  for (const problem of linked.problems) {
1186
1201
  problems.push(
@@ -1416,7 +1431,7 @@ export function placeLinks(tree, node) {
1416
1431
 
1417
1432
  /**
1418
1433
  * The moves a topic read offers: from its place in the tree, where a guide
1419
- * sits in its namespace and a flat topic in the Unorganized level.
1434
+ * sits in its namespace and a flat topic in its topic level.
1420
1435
  * @param {DocsCatalog} catalog
1421
1436
  * @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
1422
1437
  * @returns {Promise<import('./docs.type.mjs').DocsLinks>}
@@ -1514,7 +1529,7 @@ function treeArgument(catalog, tree, node) {
1514
1529
  /**
1515
1530
  * The doc that took a flat topic's route in the docs tree, when it is not
1516
1531
  * that topic (spec:AST-046 FR11): the CLI keeps its routes, such as `cli`
1517
- * and `unorganized`, and a namespace keeps its route over a topic of the same
1532
+ * and `guides`, and a namespace keeps its route over a topic of the same
1518
1533
  * name. Null when the topic owns its route, or the tree has no node there.
1519
1534
  * @param {DocsTree} tree
1520
1535
  * @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
@@ -1528,6 +1543,35 @@ export function routeOwner(tree, entry) {
1528
1543
  : node;
1529
1544
  }
1530
1545
 
1546
+ /**
1547
+ * Routes that moved, old prefix first: the integration guides moved from
1548
+ * `cli/integrations` (and, before that, the `cli-integrations` topic) into
1549
+ * `authoring`, the one home for integration authors.
1550
+ * Only the not-found error reads this, to name where a doc went; an old route
1551
+ * opens nothing.
1552
+ */
1553
+ const MOVED_ROUTES = [
1554
+ ['cli/integrations', 'authoring'],
1555
+ ['cli-integrations', 'authoring'],
1556
+ ];
1557
+
1558
+ /**
1559
+ * The node an old route moved to, or null.
1560
+ * @param {unknown} topic
1561
+ * @param {DocsTree} tree
1562
+ * @returns {TreeNode | null}
1563
+ */
1564
+ function movedRoute(topic, tree) {
1565
+ if (typeof topic !== 'string') return null;
1566
+ const wanted = topic.toLowerCase();
1567
+ for (const [from, to] of MOVED_ROUTES) {
1568
+ if (wanted !== from && !wanted.startsWith(`${from}/`)) continue;
1569
+ const node = tree.getFolded(`${to}${wanted.slice(from.length)}`);
1570
+ if (node) return node;
1571
+ }
1572
+ return null;
1573
+ }
1574
+
1531
1575
  /**
1532
1576
  * The error for a docs argument that names nothing. For a route, it suggests
1533
1577
  * the children of the deepest namespace the route reaches; otherwise, every
@@ -1560,8 +1604,7 @@ export async function unknownTopicError(topic, catalog) {
1560
1604
  }
1561
1605
  if (suggestions.length === 0 && typeof topic === 'string') {
1562
1606
  // The docs whose own name it is (`doctor` is cli/commands/doctor), or whose
1563
- // route it spells with hyphens (`cli-integrations`, the guide's name before
1564
- // it moved to cli/integrations).
1607
+ // route it spells with hyphens (`cli-host-entry` is cli/host-entry).
1565
1608
  const wanted = topic.toLowerCase();
1566
1609
  suggestions = [...tree.nodes.values()]
1567
1610
  .filter(
@@ -1580,6 +1623,22 @@ export async function unknownTopicError(topic, catalog) {
1580
1623
  ...catalog.names().map(name => ({name, reason: 'available topic'})),
1581
1624
  ];
1582
1625
  }
1626
+ if (typeof topic === 'string') {
1627
+ suggestions = orderRouteSuggestions(topic, suggestions);
1628
+ }
1629
+ // A route that moved names where it went, ahead of the usual suggestions
1630
+ // (spec:AST-046 FR9, FR6).
1631
+ const moved = movedRoute(topic, tree);
1632
+ if (moved) {
1633
+ return new AstryxError(
1634
+ `Unknown topic "${String(topic)}". It moved to "${moved.route}"${notLoaded(catalog)}`,
1635
+ [
1636
+ {name: moved.route, reason: moved.summary},
1637
+ ...suggestions.filter(entry => entry.name !== moved.route),
1638
+ ],
1639
+ ERROR_CODES.ERR_UNKNOWN_TOPIC,
1640
+ );
1641
+ }
1583
1642
  return new AstryxError(
1584
1643
  `Unknown topic "${String(topic)}"${notLoaded(catalog)}`,
1585
1644
  suggestions,
@@ -0,0 +1,127 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Every Core doc has a named home in the docs tree (spec:AST-046 FR12).
5
+ *
6
+ * A reader sees a doc's home in its path (`Guides › Getting started`) and in
7
+ * its Up move. A flat Core topic sits in Guides or Foundations by the
8
+ * category it declares, so a new topic with no category, or one the levels
9
+ * do not know, fails here instead of landing in a catch-all. The integration
10
+ * guides and their field reference live under `authoring`, and the routes
11
+ * they left name where they went.
12
+ */
13
+
14
+ import {describe, expect, it} from 'vitest';
15
+ import {docs} from './docs.mjs';
16
+ import {TOPIC_LEVELS} from '../../foundation/doc-compiler/tree.mjs';
17
+
18
+ const CLI = '@astryxdesign/cli';
19
+ const SLOW = 60_000;
20
+
21
+ describe('every Core doc has a named home', () => {
22
+ it(
23
+ 'puts each flat Core topic in Guides or Foundations by its category',
24
+ async () => {
25
+ const list = await docs();
26
+ const core = list.data.filter(topic => topic.package === CLI);
27
+ expect(core.length).toBeGreaterThan(10);
28
+ /** @type {string[]} */
29
+ const unfiled = [];
30
+ for (const topic of core) {
31
+ const read = await docs(topic.topic);
32
+ const {category} = read.data;
33
+ if (category !== 'guide' && category !== 'foundations') {
34
+ unfiled.push(`${topic.topic} (category ${String(category)})`);
35
+ continue;
36
+ }
37
+ const level =
38
+ category === 'foundations'
39
+ ? TOPIC_LEVELS.foundations
40
+ : TOPIC_LEVELS.guides;
41
+ expect(read.data.links.up, topic.topic).toBe(
42
+ `astryx docs ${level.route}`,
43
+ );
44
+ }
45
+ expect(unfiled, 'Core topics with no home: give each a category').toEqual(
46
+ [],
47
+ );
48
+ },
49
+ SLOW,
50
+ );
51
+
52
+ it(
53
+ 'lists each level under a plain name, and no catch-all',
54
+ async () => {
55
+ const list = await docs();
56
+ const roots = (list.meta.namespaces ?? []).map(entry => entry.topic);
57
+ expect(roots).toEqual(expect.arrayContaining(['guides', 'foundations']));
58
+ expect(roots).not.toContain('unorganized');
59
+ const guides = await docs('guides');
60
+ expect(guides.data).toMatchObject({route: 'guides', title: 'Guides'});
61
+ expect(guides.data.slots[0].children.map(child => child.route)).toEqual(
62
+ expect.arrayContaining(['getting-started', 'principles', 'theme']),
63
+ );
64
+ const foundations = await docs('foundations');
65
+ expect(foundations.data.title).toBe('Foundations');
66
+ expect(
67
+ foundations.data.slots[0].children.map(child => child.route),
68
+ ).toEqual(expect.arrayContaining(['color', 'icons', 'spacing']));
69
+ await expect(docs('unorganized')).rejects.toMatchObject({
70
+ code: 'ERR_UNKNOWN_TOPIC',
71
+ });
72
+ },
73
+ SLOW,
74
+ );
75
+
76
+ it(
77
+ 'keeps everything for integration authors under authoring, and names where an old route went',
78
+ async () => {
79
+ const authoring = await docs('authoring');
80
+ expect(authoring.data).toMatchObject({
81
+ route: 'authoring',
82
+ kind: 'namespace',
83
+ breadcrumb: [],
84
+ links: {up: 'astryx docs'},
85
+ });
86
+ const children = authoring.data.slots.flatMap(slot =>
87
+ slot.children.map(child => child.route),
88
+ );
89
+ expect(children).toEqual(
90
+ expect.arrayContaining([
91
+ 'authoring/quick-start',
92
+ 'authoring/building-blocks',
93
+ 'authoring/ship',
94
+ 'authoring/help',
95
+ 'authoring/field-reference',
96
+ ]),
97
+ );
98
+ // Every field reference section still opens from the namespace by its
99
+ // key, as `astryx docs authoring <name>` did on the topic (FR13).
100
+ const reference = await docs('authoring/field-reference', undefined, {
101
+ index: true,
102
+ });
103
+ const keys = reference.data.sections.map(section => section.id);
104
+ expect(keys.length).toBeGreaterThan(15);
105
+ for (const key of keys) {
106
+ const section = await docs('authoring', key);
107
+ expect(section.type, key).toBe('docs.detail.section');
108
+ expect(section.data.id, key).toBe(key);
109
+ }
110
+ for (const [old, now] of [
111
+ ['cli/integrations', 'authoring'],
112
+ ['cli/integrations/quick-start', 'authoring/quick-start'],
113
+ ['cli/integrations/ship/publishing', 'authoring/ship/publishing'],
114
+ ]) {
115
+ const error = await docs(old).catch(e => e);
116
+ expect(error).toMatchObject({
117
+ code: 'ERR_UNKNOWN_TOPIC',
118
+ message: expect.stringContaining(`It moved to "${now}"`),
119
+ });
120
+ // The new route comes first, ahead of the suggestions any unknown
121
+ // route gets (FR6).
122
+ expect(error.suggestions[0]).toMatchObject({name: now});
123
+ }
124
+ },
125
+ SLOW,
126
+ );
127
+ });
@@ -28,7 +28,7 @@ export const doc = {
28
28
  '`cli/api` returns its children one level down (`depth` reads as many ' +
29
29
  'levels as asked, and `detail` how much of each doc below), a typed doc such as ' +
30
30
  "`cli/api/functions/search` returns its content, and a guide the tree " +
31
- 'places (`cli/integrations/quick-start`) reads like any topic. ' +
31
+ 'places (`authoring/quick-start`) reads like any topic. ' +
32
32
  'Every read but the list carries `links`, the commands that move from it: ' +
33
33
  '`up` to the level it sits in, `previous` and `next` to its neighbors, and, ' +
34
34
  'for a typed doc, `related` to the docs it names (its command or function, ' +
@@ -162,12 +162,12 @@ export const doc = {
162
162
  },
163
163
  {
164
164
  label: 'A namespace and everything below it, in full',
165
- code: "await docs('cli/integrations', undefined, {depth: 'all', detail: 'full'});",
165
+ code: "await docs('authoring', undefined, {depth: 'all', detail: 'full'});",
166
166
  },
167
167
  {label: 'One API function', code: "await docs('cli/api/functions/search');"},
168
168
  {
169
169
  label: 'A whole guide from the docs tree',
170
- code: "await docs('cli/integrations/quick-start');",
170
+ code: "await docs('authoring/quick-start');",
171
171
  },
172
172
  {label: 'One section by key', code: "await docs('spacing', 'scale');"},
173
173
  ],