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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (694) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +216 -162
  3. package/api/build/_adapter.d.mts +66 -0
  4. package/api/build/_adapter.mjs +139 -4
  5. package/api/build/blocks/blocks.d.mts +92 -0
  6. package/api/build/blocks/blocks.mjs +528 -0
  7. package/api/build/blocks/blocks.test.mjs +238 -0
  8. package/api/build/blocks/blocks.weights.json +1 -0
  9. package/api/build/build.doc.mjs +4 -0
  10. package/api/build/build.mjs +25 -6
  11. package/api/build/build.type.mjs +1 -1
  12. package/api/build/help/help.mjs +1 -1
  13. package/api/build/kit/answer.d.mts +18 -0
  14. package/api/build/kit/answer.mjs +195 -0
  15. package/api/build/kit/answer.test.mjs +108 -0
  16. package/api/build/kit/kind.d.mts +25 -0
  17. package/api/build/kit/kind.mjs +170 -0
  18. package/api/build/kit/kit.d.mts +2 -4
  19. package/api/build/kit/kit.mjs +8 -406
  20. package/api/build/kit/rank.d.mts +3 -32
  21. package/api/build/kit/rank.mjs +25 -342
  22. package/api/build/kit/rank.test.mjs +2 -1
  23. package/api/build/kit/signals.d.mts +79 -0
  24. package/api/build/kit/signals.mjs +295 -0
  25. package/api/build/kit/start.d.mts +32 -0
  26. package/api/build/kit/start.mjs +163 -0
  27. package/api/build/kit/words.d.mts +72 -0
  28. package/api/build/kit/words.mjs +202 -0
  29. package/api/build/tree.d.mts +20 -0
  30. package/api/build/tree.mjs +53 -0
  31. package/api/build/tree.test.mjs +185 -0
  32. package/api/build/tree.weights.json +1 -0
  33. package/api/component/_adapter.d.mts +72 -1
  34. package/api/component/_adapter.mjs +251 -23
  35. package/api/component/component-replacement.test.mjs +1 -0
  36. package/api/component/component.doc.mjs +6 -1
  37. package/api/component/component.mjs +97 -16
  38. package/api/component/component.test.mjs +95 -0
  39. package/api/component/doc-links.test.mjs +386 -0
  40. package/api/component/integration-export-name.test.mjs +644 -0
  41. package/api/component/list/list.mjs +42 -4
  42. package/api/discover/_adapter.d.mts +131 -12
  43. package/api/discover/_adapter.mjs +520 -34
  44. package/api/discover/_adapter.test.mjs +641 -17
  45. package/api/discover/_catalog-view.d.mts +16 -5
  46. package/api/discover/_catalog-view.mjs +32 -8
  47. package/api/discover/detail/doc/doc.mjs +9 -1
  48. package/api/discover/discover.d.mts +11 -0
  49. package/api/discover/discover.doc.mjs +9 -7
  50. package/api/discover/discover.mjs +120 -19
  51. package/api/discover/discover.type.d.mts +20 -7
  52. package/api/discover/discover.type.mjs +17 -7
  53. package/api/discover/list/list.d.mts +4 -3
  54. package/api/discover/list/list.mjs +17 -10
  55. package/api/docs/_adapter.d.mts +76 -2
  56. package/api/docs/_adapter.mjs +630 -34
  57. package/api/docs/docs-homes.test.mjs +127 -0
  58. package/api/docs/docs.doc.mjs +5 -4
  59. package/api/docs/docs.mjs +2 -1
  60. package/api/docs/docs.test.mjs +39 -20
  61. package/api/docs/integration-tree.test.mjs +42 -20
  62. package/api/docs/integrationDocs.test.mjs +125 -1
  63. package/api/docs/list/list.mjs +12 -2
  64. package/api/docs/namespace-section.test.mjs +6 -6
  65. package/api/docs/reference-blocks.test.mjs +3 -5
  66. package/api/doctor/_adapter.d.mts +128 -0
  67. package/api/doctor/_adapter.mjs +253 -4
  68. package/api/doctor/doctor.d.mts +217 -0
  69. package/api/doctor/doctor.doc.mjs +3 -2
  70. package/api/doctor/doctor.mjs +691 -52
  71. package/api/doctor/doctor.test.mjs +267 -18
  72. package/api/doctor/release-checks.test.mjs +156 -0
  73. package/api/doctor/theme-checks.mjs +17 -4
  74. package/api/doctor/theme-checks.test.mjs +223 -7
  75. package/api/error.d.mts +10 -0
  76. package/api/error.mjs +25 -0
  77. package/api/gap-report/gap-report.d.mts +3 -0
  78. package/api/gap-report/gap-report.doc.mjs +11 -3
  79. package/api/gap-report/gap-report.mjs +219 -52
  80. package/api/gap-report/gap-report.test.mjs +233 -0
  81. package/api/gap-report/gap-report.type.d.mts +41 -0
  82. package/api/gap-report/gap-report.type.mjs +18 -0
  83. package/api/hook/_adapter.mjs +3 -11
  84. package/api/hook/hook.doc.mjs +4 -0
  85. package/api/hook/hook.mjs +1 -1
  86. package/api/hook/list/list.d.mts +1 -1
  87. package/api/index.d.mts +2 -0
  88. package/api/index.mjs +2 -0
  89. package/api/init/_adapter.d.mts +22 -0
  90. package/api/init/_adapter.mjs +59 -0
  91. package/api/init/init.d.mts +7 -5
  92. package/api/init/init.doc.mjs +45 -10
  93. package/api/init/init.mjs +28 -4
  94. package/api/init/init.test.mjs +18 -2
  95. package/api/init/init.type.d.mts +50 -5
  96. package/api/init/init.type.mjs +39 -5
  97. package/api/init/remove/remove.mjs +17 -4
  98. package/api/init/remove/remove.test.mjs +114 -2
  99. package/api/init/run/run.d.mts +1 -1
  100. package/api/init/run/run.mjs +86 -12
  101. package/api/init/user/user.d.mts +14 -0
  102. package/api/init/user/user.mjs +87 -0
  103. package/api/init/user/user.test.mjs +232 -0
  104. package/api/integration/_adapter.d.mts +53 -0
  105. package/api/integration/_adapter.mjs +132 -0
  106. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  107. package/api/integration/add-contribution.mjs +8 -4
  108. package/api/integration/add-contribution.test.mjs +4 -2
  109. package/api/integration/authoring-checks.mjs +192 -14
  110. package/api/integration/authoring-checks.test.mjs +1028 -0
  111. package/api/integration/authoring-checks.type.d.mts +143 -0
  112. package/api/integration/authoring-checks.type.mjs +74 -2
  113. package/api/integration/check/check.d.mts +96 -0
  114. package/api/integration/check/check.mjs +357 -0
  115. package/api/integration/check/check.test.mjs +489 -0
  116. package/api/integration/integration-check.type.d.mts +118 -0
  117. package/api/integration/integration-check.type.mjs +84 -0
  118. package/api/integration/integrationCheck.doc.d.mts +10 -0
  119. package/api/integration/integrationCheck.doc.mjs +73 -0
  120. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  121. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  122. package/api/integration/pack-check.mjs +486 -123
  123. package/api/integration/pack-check.test.mjs +817 -10
  124. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +73 -5
  126. package/api/integration/validate-integration-gaps.test.mjs +1975 -0
  127. package/api/integration/validate-integration.d.mts +23 -2
  128. package/api/integration/validate-integration.mjs +358 -45
  129. package/api/integration/validate-integration.test.mjs +88 -8
  130. package/api/integration/validate-integration.type.d.mts +105 -0
  131. package/api/integration/validate-integration.type.mjs +79 -1
  132. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  133. package/api/integration/validateIntegration.doc.mjs +19 -3
  134. package/api/search/ORDERING.md +28 -0
  135. package/api/search/_adapter.d.mts +91 -0
  136. package/api/search/_adapter.mjs +172 -0
  137. package/api/search/_adapter.test.mjs +173 -0
  138. package/api/search/_candidate-score.d.mts +40 -0
  139. package/api/search/_candidate-score.mjs +238 -0
  140. package/api/search/_cards.json +6098 -0
  141. package/api/search/_compound.d.mts +50 -0
  142. package/api/search/_compound.mjs +170 -0
  143. package/api/search/_doc-searcher.d.mts +4 -0
  144. package/api/search/_doc-searcher.mjs +23 -0
  145. package/api/search/_doc-searcher.test.mjs +36 -0
  146. package/api/search/_doc-searcher.weights.json +1 -0
  147. package/api/search/_doc-text.d.mts +30 -0
  148. package/api/search/_doc-text.mjs +87 -0
  149. package/api/search/_entries.d.mts +63 -0
  150. package/api/search/_entries.mjs +232 -0
  151. package/api/search/_entries.test.mjs +48 -0
  152. package/api/search/_features.d.mts +35 -0
  153. package/api/search/_features.mjs +155 -0
  154. package/api/search/_gather-components.d.mts +26 -0
  155. package/api/search/_gather-components.mjs +284 -0
  156. package/api/search/_gather-docs.d.mts +20 -0
  157. package/api/search/_gather-docs.mjs +254 -0
  158. package/api/search/_gather-hooks.d.mts +12 -0
  159. package/api/search/_gather-hooks.mjs +52 -0
  160. package/api/search/_gather-templates.d.mts +25 -0
  161. package/api/search/_gather-templates.mjs +107 -0
  162. package/api/search/_lexical.d.mts +135 -0
  163. package/api/search/_lexical.mjs +351 -0
  164. package/api/search/_main-searcher.d.mts +19 -0
  165. package/api/search/_main-searcher.mjs +115 -0
  166. package/api/search/_main-searcher.test.mjs +106 -0
  167. package/api/search/_main-searcher.weights.json +1 -0
  168. package/api/search/_module-doc.d.mts +32 -0
  169. package/api/search/_module-doc.mjs +78 -0
  170. package/api/search/_order.d.mts +32 -0
  171. package/api/search/_order.mjs +162 -0
  172. package/api/search/_order.test.mjs +72 -0
  173. package/api/search/_priority.d.mts +50 -0
  174. package/api/search/_priority.mjs +139 -0
  175. package/api/search/_query-words.d.mts +25 -0
  176. package/api/search/_query-words.mjs +92 -0
  177. package/api/search/_query.d.mts +65 -0
  178. package/api/search/_query.mjs +176 -0
  179. package/api/search/_result.d.mts +97 -0
  180. package/api/search/_result.mjs +150 -0
  181. package/api/search/_score.d.mts +60 -0
  182. package/api/search/_score.mjs +283 -0
  183. package/api/search/_synonyms.d.mts +21 -0
  184. package/api/search/_synonyms.mjs +67 -0
  185. package/api/search/_template-searcher.d.mts +4 -0
  186. package/api/search/_template-searcher.mjs +23 -0
  187. package/api/search/_template-searcher.test.mjs +40 -0
  188. package/api/search/_template-searcher.weights.json +1 -0
  189. package/api/search/_titles.d.mts +33 -0
  190. package/api/search/_titles.mjs +65 -0
  191. package/api/search/_words.d.mts +64 -0
  192. package/api/search/_words.mjs +157 -0
  193. package/api/search/search.d.mts +22 -236
  194. package/api/search/search.doc.mjs +14 -7
  195. package/api/search/search.domain-priority.test.mjs +108 -18
  196. package/api/search/search.integration-check.test.mjs +24 -0
  197. package/api/search/search.mjs +59 -1904
  198. package/api/search/search.test.mjs +193 -15
  199. package/api/search/search.type.d.mts +20 -2
  200. package/api/search/search.type.mjs +12 -2
  201. package/api/search/tree.d.mts +15 -0
  202. package/api/search/tree.mjs +40 -0
  203. package/api/search/tree.test.mjs +66 -0
  204. package/api/search/tree.weights.json +1 -0
  205. package/api/swizzle/_adapter.mjs +2 -2
  206. package/api/swizzle/copy/copy.mjs +29 -15
  207. package/api/template/template-integration.test.mjs +1 -1
  208. package/api/template/template.mjs +5 -1
  209. package/api/template/template.test.mjs +120 -3
  210. package/api/theme/_adapter.d.mts +16 -0
  211. package/api/theme/_adapter.mjs +32 -5
  212. package/api/theme/build/build.d.mts +2 -1
  213. package/api/theme/build/build.family.test.mjs +64 -0
  214. package/api/theme/build/build.mjs +250 -38
  215. package/api/theme/build/build.packed-old-core.test.mjs +21 -3
  216. package/api/theme/build/font-warning.mjs +5 -3
  217. package/api/theme/build/font-warning.test.mjs +2 -1
  218. package/api/theme/remove/remove.test.mjs +2 -2
  219. package/api/theme/targets/targets.mjs +3 -10
  220. package/api/theme/themeBuild.doc.mjs +4 -4
  221. package/api/theme/themeTargets.doc.mjs +4 -0
  222. package/api/theme/use/use.test.mjs +1 -1
  223. package/api/upgrade/_adapter.d.mts +97 -11
  224. package/api/upgrade/_adapter.mjs +315 -32
  225. package/api/upgrade/registry/registry.d.mts +10 -4
  226. package/api/upgrade/registry/registry.mjs +33 -16
  227. package/api/upgrade/registry/registry.test.mjs +85 -0
  228. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  229. package/api/upgrade/run/run.d.mts +4 -2
  230. package/api/upgrade/run/run.mjs +48 -4
  231. package/api/upgrade/run/run.test.mjs +417 -3
  232. package/api/upgrade/status/status.d.mts +21 -5
  233. package/api/upgrade/status/status.mjs +45 -8
  234. package/api/upgrade/upgrade.doc.mjs +16 -8
  235. package/api/upgrade/upgrade.mjs +18 -3
  236. package/api/upgrade/upgrade.test.mjs +194 -0
  237. package/api/upgrade/upgrade.type.d.mts +28 -3
  238. package/api/upgrade/upgrade.type.mjs +24 -7
  239. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  240. package/assets/codemods/registry.mjs +1 -0
  241. package/assets/codemods/runner.mjs +7 -1
  242. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  243. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  244. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  245. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  246. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  247. package/assets/discover/official-packages.json +367 -0
  248. package/assets/docs/README.md +10 -0
  249. package/assets/docs/author-a-theme.doc.mjs +5 -5
  250. package/assets/docs/browser-support.doc.mjs +1 -1
  251. package/assets/docs/getting-started.doc.mjs +26 -6
  252. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  253. package/assets/docs/styling-overview.doc.mjs +1 -1
  254. package/assets/docs/theme.doc.dense.mjs +1 -1
  255. package/assets/docs/theme.doc.mjs +2 -2
  256. package/assets/docs/theme.doc.zh.mjs +1 -1
  257. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  258. package/assets/docs/tree/add-a-theme.doc.mjs +14 -4
  259. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  260. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  261. package/assets/docs/tree/api.doc.mjs +6 -0
  262. package/assets/docs/tree/authoring.doc.mjs +61 -0
  263. package/assets/docs/tree/block-template.doc.mjs +8 -20
  264. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  265. package/assets/docs/tree/building-blocks.doc.mjs +6 -2
  266. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  267. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  268. package/assets/docs/tree/checks.doc.mjs +32 -24
  269. package/assets/docs/tree/ci-and-containers.doc.mjs +101 -0
  270. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  271. package/assets/docs/tree/cli.doc.mjs +7 -1
  272. package/assets/docs/tree/codemods.doc.mjs +17 -7
  273. package/assets/docs/tree/commands.doc.mjs +7 -1
  274. package/assets/docs/tree/component-family.doc.mjs +8 -6
  275. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  276. package/assets/docs/tree/components.doc.mjs +7 -1
  277. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  278. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  279. package/assets/docs/tree/configuration.doc.mjs +8 -4
  280. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  281. package/assets/docs/tree/define-the-theme.doc.mjs +7 -6
  282. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  283. package/assets/docs/tree/docs.doc.mjs +9 -3
  284. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  285. package/assets/docs/tree/document-the-theme.doc.mjs +4 -4
  286. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  287. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  288. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  289. package/assets/docs/tree/fonts-and-assets.doc.mjs +3 -3
  290. package/assets/docs/tree/generate-a-palette.doc.mjs +8 -6
  291. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  292. package/assets/docs/tree/global.doc.mjs +131 -0
  293. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  294. package/assets/docs/tree/help.doc.mjs +2 -2
  295. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  296. package/assets/docs/tree/install-once.doc.mjs +105 -0
  297. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  298. package/assets/docs/tree/layout.doc.mjs +6 -6
  299. package/assets/docs/tree/links.doc.mjs +7 -6
  300. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  301. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  302. package/assets/docs/tree/migration.doc.mjs +0 -1
  303. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  304. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  305. package/assets/docs/tree/page-template.doc.mjs +4 -8
  306. package/assets/docs/tree/problems.doc.mjs +205 -0
  307. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  308. package/assets/docs/tree/publishing.doc.mjs +6 -6
  309. package/assets/docs/tree/quick-start.doc.mjs +54 -28
  310. package/assets/docs/tree/reference.doc.mjs +192 -0
  311. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  312. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  313. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  314. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  315. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  316. package/assets/docs/tree/ship.doc.mjs +2 -2
  317. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  318. package/assets/docs/tree/single-component.doc.mjs +15 -6
  319. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  320. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  321. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  322. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  323. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  324. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  325. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  326. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  327. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  328. package/assets/docs/tree/templates.doc.mjs +7 -1
  329. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  330. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  331. package/assets/docs/tree/themes.doc.mjs +5 -1
  332. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  333. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  334. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  335. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  336. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  337. package/assets/docs/tree/updates.doc.mjs +92 -0
  338. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  339. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +15 -3
  340. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  341. package/assets/docs/tree/versioning.doc.mjs +14 -9
  342. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  343. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  344. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  345. package/assets/docs/use-a-theme.doc.mjs +2 -2
  346. package/assets/docs/use-integrations.doc.mjs +120 -0
  347. package/assets/docs/working-with-ai.doc.mjs +70 -13
  348. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  349. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  350. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  351. package/assets/theme.template.ts +1 -1
  352. package/authoring/codemod/codemod.doc.mjs +7 -3
  353. package/authoring/config/config.doc.mjs +9 -6
  354. package/authoring/config/type.ts +4 -2
  355. package/authoring/debug/parse.d.mts +5 -5
  356. package/authoring/discover/discover.doc.mjs +7 -1
  357. package/authoring/doctypes/_schema.d.mts +8 -3
  358. package/authoring/doctypes/_schema.mjs +1 -0
  359. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  360. package/authoring/doctypes/command/command.doc.mjs +20 -12
  361. package/authoring/doctypes/command/type.ts +14 -0
  362. package/authoring/doctypes/component/component.doc.mjs +30 -27
  363. package/authoring/doctypes/component/type.ts +21 -8
  364. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  365. package/authoring/doctypes/function/function.doc.mjs +9 -8
  366. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  367. package/authoring/doctypes/hook/type.ts +4 -0
  368. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  369. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  370. package/authoring/doctypes/schema/schema.doc.mjs +10 -10
  371. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  372. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  373. package/authoring/doctypes/template/parse.d.mts +6 -2
  374. package/authoring/doctypes/template/parse.mjs +3 -1
  375. package/authoring/doctypes/template/template.doc.mjs +3 -3
  376. package/authoring/doctypes/template/type.ts +22 -0
  377. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  378. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  379. package/authoring/identity/identity.doc.mjs +3 -3
  380. package/authoring/index.d.ts +2 -0
  381. package/authoring/integration/integration.doc.mjs +30 -6
  382. package/authoring/integration/parse.test.mjs +21 -0
  383. package/authoring/integration/schema.d.mts +16 -3
  384. package/authoring/integration/schema.mjs +34 -2
  385. package/authoring/integration/type.ts +13 -1
  386. package/clients/cli/bin/astryx.mjs +11 -65
  387. package/clients/cli/cli-command.test.mjs +166 -0
  388. package/clients/cli/command-result-coverage.test.mjs +6 -5
  389. package/clients/cli/commands/blog.doc.mjs +1 -0
  390. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  391. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  392. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  393. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  394. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  395. package/clients/cli/commands/build.doc.mjs +1 -0
  396. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  397. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  398. package/clients/cli/commands/component.doc.mjs +1 -0
  399. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  400. package/clients/cli/commands/component.test.mjs +6 -6
  401. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  402. package/clients/cli/commands/discover.doc.mjs +9 -1
  403. package/clients/cli/commands/discover.mjs +144 -93
  404. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  405. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  406. package/clients/cli/commands/docs.doc.mjs +3 -2
  407. package/clients/cli/commands/docs.mjs +50 -20
  408. package/clients/cli/commands/docs.test.mjs +16 -16
  409. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  410. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  411. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  412. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  413. package/clients/cli/commands/doctor-integration.test.mjs +936 -3
  414. package/clients/cli/commands/doctor.doc.mjs +12 -2
  415. package/clients/cli/commands/doctor.mjs +332 -7
  416. package/clients/cli/commands/doctor.test.mjs +75 -4
  417. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  418. package/clients/cli/commands/gap-report.mjs +24 -2
  419. package/clients/cli/commands/gap-report.test.mjs +79 -0
  420. package/clients/cli/commands/hook.doc.mjs +1 -0
  421. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  422. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  423. package/clients/cli/commands/init.behavior.test.mjs +235 -1
  424. package/clients/cli/commands/init.doc.mjs +55 -10
  425. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  426. package/clients/cli/commands/init.mjs +2 -2
  427. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  428. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  429. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  430. package/clients/cli/commands/integration-check.test.mjs +489 -0
  431. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  432. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  433. package/clients/cli/commands/integration.doc.mjs +6 -2
  434. package/clients/cli/commands/integration.mjs +119 -7
  435. package/clients/cli/commands/json-contract.test.mjs +11 -2
  436. package/clients/cli/commands/manifest.doc.mjs +2 -1
  437. package/clients/cli/commands/manifest.mjs +67 -0
  438. package/clients/cli/commands/outside-project.test.mjs +874 -0
  439. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  440. package/clients/cli/commands/postinstall.mjs +31 -0
  441. package/clients/cli/commands/search.doc.mjs +1 -0
  442. package/clients/cli/commands/search.mjs +16 -11
  443. package/clients/cli/commands/search.test.mjs +429 -296
  444. package/clients/cli/commands/setup-nudge.test.mjs +180 -2
  445. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  446. package/clients/cli/commands/swizzle.mjs +5 -3
  447. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  448. package/clients/cli/commands/template.doc.mjs +1 -0
  449. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  450. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  451. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  452. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  453. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  454. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  455. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  456. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  457. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  458. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  459. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  460. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  461. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +27 -14
  462. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  463. package/clients/cli/commands/upgrade.doc.mjs +26 -3
  464. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  465. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  466. package/clients/cli/commands/upgrade.mjs +9 -2
  467. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  468. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  469. package/clients/cli/index.mjs +156 -100
  470. package/clients/cli/lib/cli-error.mjs +4 -1
  471. package/clients/cli/lib/component-format.mjs +1 -1
  472. package/clients/cli/lib/component-format.test.mjs +1 -1
  473. package/clients/cli/lib/define-command.mjs +14 -9
  474. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  475. package/clients/cli/lib/json-shim.mjs +3 -1
  476. package/clients/cli/lib/manifest.d.ts +9 -0
  477. package/clients/cli/lib/manifest.mjs +17 -1
  478. package/clients/cli/lib/manifest.test.mjs +37 -0
  479. package/clients/cli/lib/welcome-box.mjs +50 -0
  480. package/clients/cli/run.mjs +108 -0
  481. package/foundation/agent-docs/agent-doc-state.d.mts +67 -13
  482. package/foundation/agent-docs/agent-doc-state.mjs +123 -14
  483. package/foundation/agent-docs/agent-docs.d.mts +104 -15
  484. package/foundation/agent-docs/agent-docs.mjs +1028 -114
  485. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  486. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  487. package/foundation/agent-docs/computer-agent-text.d.mts +170 -0
  488. package/foundation/agent-docs/computer-agent-text.mjs +750 -0
  489. package/foundation/agent-docs/computer-agent-text.test.mjs +699 -0
  490. package/foundation/config/project.d.mts +35 -3
  491. package/foundation/config/project.mjs +243 -26
  492. package/foundation/config/project.test.mjs +122 -0
  493. package/foundation/config/theme-state.mjs +5 -4
  494. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  495. package/foundation/discovery/authoring-self-docs.mjs +17 -4
  496. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  497. package/foundation/discovery/authoring-surface.d.mts +1 -1
  498. package/foundation/discovery/authoring-surface.mjs +2 -2
  499. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  500. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  501. package/foundation/discovery/cli-self-docs.mjs +22 -4
  502. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  503. package/foundation/discovery/component-discovery.d.mts +227 -10
  504. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  505. package/foundation/discovery/component-discovery.mjs +940 -57
  506. package/foundation/discovery/component-discovery.test.mjs +96 -0
  507. package/foundation/discovery/component-loader.d.mts +1 -1
  508. package/foundation/discovery/component-replacement.mjs +20 -1
  509. package/foundation/discovery/component-replacement.test.mjs +40 -0
  510. package/foundation/discovery/copied-passages.d.mts +216 -0
  511. package/foundation/discovery/copied-passages.mjs +720 -0
  512. package/foundation/discovery/copied-passages.test.mjs +124 -0
  513. package/foundation/discovery/doc-consistency.d.mts +34 -0
  514. package/foundation/discovery/doc-consistency.mjs +513 -0
  515. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  516. package/foundation/discovery/doc-fluff.d.mts +112 -0
  517. package/foundation/discovery/doc-fluff.mjs +328 -0
  518. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  519. package/foundation/discovery/doc-types.d.mts +157 -0
  520. package/foundation/discovery/doc-types.mjs +1231 -0
  521. package/foundation/discovery/doc-types.test.mjs +744 -0
  522. package/foundation/discovery/docs-discovery.d.mts +88 -0
  523. package/foundation/discovery/docs-discovery.mjs +97 -3
  524. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  525. package/foundation/discovery/integration-doc-files.mjs +231 -0
  526. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  527. package/foundation/discovery/module-exports.d.mts +68 -0
  528. package/foundation/discovery/module-exports.mjs +609 -31
  529. package/foundation/discovery/module-exports.test.mjs +172 -0
  530. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  531. package/foundation/discovery/package-tsconfig.mjs +228 -0
  532. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  533. package/foundation/discovery/project-typescript.d.mts +32 -0
  534. package/foundation/discovery/project-typescript.mjs +89 -0
  535. package/foundation/discovery/prop-drift.d.mts +297 -0
  536. package/foundation/discovery/prop-drift.mjs +2428 -0
  537. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  538. package/foundation/discovery/runner-allowlist.d.mts +38 -0
  539. package/foundation/discovery/runner-allowlist.mjs +51 -0
  540. package/foundation/discovery/runner-commands.d.mts +77 -0
  541. package/foundation/discovery/runner-commands.mjs +294 -0
  542. package/foundation/discovery/runner-commands.test.mjs +128 -0
  543. package/foundation/discovery/stray-pointers.d.mts +52 -0
  544. package/foundation/discovery/stray-pointers.mjs +293 -0
  545. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  546. package/foundation/discovery/template-adapter.mjs +92 -6
  547. package/foundation/discovery/template-needs.mjs +6 -46
  548. package/foundation/discovery/theme-discovery.mjs +147 -3
  549. package/foundation/discovery/theme-imports.mjs +8 -4
  550. package/foundation/discovery/theme-imports.test.mjs +1 -1
  551. package/foundation/discovery/type-match.d.mts +53 -0
  552. package/foundation/discovery/type-match.mjs +660 -0
  553. package/foundation/discovery/type-match.test.mjs +169 -0
  554. package/foundation/discovery/type-text.d.mts +68 -0
  555. package/foundation/discovery/type-text.mjs +658 -0
  556. package/foundation/discovery/type-text.test.mjs +196 -0
  557. package/foundation/discovery/unresolved-references.d.mts +62 -0
  558. package/foundation/discovery/unresolved-references.mjs +790 -0
  559. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  560. package/foundation/doc-compiler/doc-loads.test.mjs +84 -10
  561. package/foundation/doc-compiler/inputs.mjs +27 -1
  562. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  563. package/foundation/doc-compiler/links.d.mts +41 -5
  564. package/foundation/doc-compiler/links.mjs +167 -28
  565. package/foundation/doc-compiler/links.test.mjs +97 -4
  566. package/foundation/doc-compiler/read.d.mts +1 -1
  567. package/foundation/doc-compiler/read.mjs +59 -1
  568. package/foundation/doc-compiler/read.test.mjs +11 -2
  569. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  570. package/foundation/doc-compiler/tree.d.mts +32 -6
  571. package/foundation/doc-compiler/tree.mjs +107 -44
  572. package/foundation/doc-compiler/tree.test.mjs +14 -7
  573. package/foundation/env/cli-command.d.mts +83 -0
  574. package/foundation/env/cli-command.mjs +152 -0
  575. package/foundation/env/cli-command.test.mjs +129 -0
  576. package/foundation/env/node-version.test.mjs +15 -3
  577. package/foundation/env/package-manager.d.mts +93 -9
  578. package/foundation/env/package-manager.global.test.mjs +66 -0
  579. package/foundation/env/package-manager.mjs +184 -13
  580. package/foundation/env/package-manager.test.mjs +341 -15
  581. package/foundation/env/project-scope.d.mts +9 -0
  582. package/foundation/env/project-scope.mjs +33 -0
  583. package/foundation/env/search-path.d.mts +42 -0
  584. package/foundation/env/search-path.mjs +205 -0
  585. package/foundation/env/search-path.test.mjs +122 -0
  586. package/foundation/env/user-dirs.d.mts +39 -0
  587. package/foundation/env/user-dirs.mjs +93 -0
  588. package/foundation/env/user-dirs.test.mjs +72 -0
  589. package/foundation/env/user-settings.d.mts +46 -0
  590. package/foundation/env/user-settings.mjs +106 -0
  591. package/foundation/env/user-settings.test.mjs +64 -0
  592. package/foundation/fs/file-protection.mjs +15 -1
  593. package/foundation/fs/module-loader.d.mts +2 -1
  594. package/foundation/fs/module-loader.mjs +60 -4
  595. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  596. package/foundation/fs/module-loader.test.mjs +194 -0
  597. package/foundation/fs/path-compare.d.mts +33 -0
  598. package/foundation/fs/path-compare.mjs +73 -0
  599. package/foundation/fs/paths.d.mts +122 -4
  600. package/foundation/fs/paths.mjs +675 -29
  601. package/foundation/fs/paths.test.mjs +439 -54
  602. package/foundation/fs/read-record.d.mts +18 -0
  603. package/foundation/fs/read-record.mjs +131 -0
  604. package/foundation/fs/read-record.test.mjs +77 -0
  605. package/foundation/integrations/autolink.d.mts +2 -1
  606. package/foundation/integrations/autolink.mjs +4 -13
  607. package/foundation/integrations/cli-peer-version.d.mts +36 -0
  608. package/foundation/integrations/cli-peer-version.mjs +132 -0
  609. package/foundation/integrations/cli-peer-version.test.mjs +354 -0
  610. package/foundation/integrations/computer-integrations.d.mts +81 -0
  611. package/foundation/integrations/computer-integrations.mjs +345 -0
  612. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  613. package/foundation/integrations/contribution-inventory.d.mts +26 -20
  614. package/foundation/integrations/contribution-inventory.mjs +97 -8
  615. package/foundation/integrations/exports-subpaths.d.mts +57 -0
  616. package/foundation/integrations/exports-subpaths.mjs +113 -0
  617. package/foundation/integrations/integration-warnings.mjs +3 -2
  618. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  619. package/foundation/integrations/integrations.d.mts +51 -1
  620. package/foundation/integrations/integrations.mjs +106 -4
  621. package/foundation/integrations/issue.ts +6 -0
  622. package/foundation/integrations/public-imports.d.mts +118 -0
  623. package/foundation/integrations/public-imports.mjs +1769 -0
  624. package/foundation/integrations/public-imports.test.mjs +1793 -0
  625. package/foundation/integrations/validate-contributions.d.mts +117 -0
  626. package/foundation/integrations/validate-contributions.mjs +1209 -14
  627. package/foundation/release/agent-text-worker.d.mts +4 -0
  628. package/foundation/release/agent-text-worker.mjs +52 -0
  629. package/foundation/release/cache.d.mts +310 -0
  630. package/foundation/release/cache.mjs +1216 -0
  631. package/foundation/release/cache.test.mjs +923 -0
  632. package/foundation/release/choose.d.mts +207 -0
  633. package/foundation/release/choose.mjs +677 -0
  634. package/foundation/release/choose.test.mjs +427 -0
  635. package/foundation/release/core-worker.d.mts +4 -0
  636. package/foundation/release/core-worker.mjs +38 -0
  637. package/foundation/release/global-state.d.mts +263 -0
  638. package/foundation/release/global-state.mjs +474 -0
  639. package/foundation/release/global-state.test.mjs +381 -0
  640. package/foundation/release/handoff.d.mts +79 -0
  641. package/foundation/release/handoff.e2e.test.mjs +278 -0
  642. package/foundation/release/handoff.mjs +524 -0
  643. package/foundation/release/lock-lease.d.mts +23 -0
  644. package/foundation/release/lock-lease.mjs +80 -0
  645. package/foundation/release/notices.d.mts +307 -0
  646. package/foundation/release/notices.mjs +707 -0
  647. package/foundation/release/notices.test.mjs +586 -0
  648. package/foundation/release/npm-guard.d.mts +4 -0
  649. package/foundation/release/npm-guard.mjs +126 -0
  650. package/foundation/release/project.d.mts +141 -0
  651. package/foundation/release/project.mjs +466 -0
  652. package/foundation/release/project.test.mjs +288 -0
  653. package/foundation/release/refresh-worker.d.mts +4 -0
  654. package/foundation/release/refresh-worker.mjs +27 -0
  655. package/foundation/release/run-context.d.mts +47 -0
  656. package/foundation/release/run-context.mjs +163 -0
  657. package/foundation/release/update-notice-env.d.mts +28 -0
  658. package/foundation/release/update-notice-env.mjs +39 -0
  659. package/foundation/response/base.d.ts +26 -3
  660. package/foundation/response/error-codes.d.mts +3 -1
  661. package/foundation/response/error-codes.doc.mjs +12 -0
  662. package/foundation/response/error-codes.mjs +17 -0
  663. package/foundation/response/error-codes.test.mjs +2 -0
  664. package/foundation/response/json-contract.test.mjs +7 -2
  665. package/foundation/response/json.mjs +4 -1
  666. package/foundation/response/response-types.doc.mjs +22 -11
  667. package/foundation/response/response-types.doc.test.mjs +46 -0
  668. package/foundation/response/response.doc.mjs +3 -3
  669. package/foundation/route/route.d.mts +285 -0
  670. package/foundation/route/route.mjs +324 -0
  671. package/foundation/route/route.test.mjs +153 -0
  672. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  673. package/foundation/runtime/locked-versions.d.mts +32 -0
  674. package/foundation/runtime/locked-versions.mjs +65 -0
  675. package/foundation/runtime/package-root.d.mts +91 -0
  676. package/foundation/runtime/package-root.mjs +174 -0
  677. package/foundation/runtime/package-set.d.mts +62 -0
  678. package/foundation/runtime/package-set.mjs +130 -0
  679. package/foundation/runtime/package-set.test.mjs +432 -0
  680. package/foundation/text/string-utils.d.mts +2 -1
  681. package/foundation/text/string-utils.mjs +16 -5
  682. package/foundation/text/suggest-order.d.mts +72 -0
  683. package/foundation/text/suggest-order.mjs +363 -0
  684. package/foundation/text/suggest-order.test.mjs +259 -0
  685. package/foundation/xle/browser-imports.test.mjs +74 -0
  686. package/foundation/xle/registry.mjs +4 -0
  687. package/foundation/xle/registry.test.mjs +28 -0
  688. package/host/door-conformance.test.mjs +274 -0
  689. package/host/index.d.ts +116 -0
  690. package/host/index.mjs +295 -0
  691. package/host/index.test.mjs +302 -0
  692. package/package.json +16 -11
  693. package/scripts/postinstall.mjs +24 -5
  694. package/assets/docs/tree/integrations.doc.mjs +0 -40
@@ -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,13 +28,14 @@ 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, ' +
35
35
  'and its related docs); `previous` and `next` ' +
36
36
  'to the section or node before and after it. ' +
37
- 'Overlay options select localized or dense variants.',
37
+ 'Overlay options select localized or dense variants.' +
38
+ " In global mode: with `cwd` outside a project, doc topics from integrations installed next to this CLI package globally are listed too; inside a project, only the project's own integrations count. See {@link namespace:global} and {@link generic:computer-integrations}.",
38
39
  importPath: '@astryxdesign/cli/api',
39
40
  signature:
40
41
  'docs(topic?: string, section?: string, options?: DocsOptions): Promise<DocsListResponse | DocsIndexResponse | DocsDetailResponse | DocsDetailSectionResponse | DocsNodeResponse>',
@@ -161,12 +162,12 @@ export const doc = {
161
162
  },
162
163
  {
163
164
  label: 'A namespace and everything below it, in full',
164
- code: "await docs('cli/integrations', undefined, {depth: 'all', detail: 'full'});",
165
+ code: "await docs('authoring', undefined, {depth: 'all', detail: 'full'});",
165
166
  },
166
167
  {label: 'One API function', code: "await docs('cli/api/functions/search');"},
167
168
  {
168
169
  label: 'A whole guide from the docs tree',
169
- code: "await docs('cli/integrations/quick-start');",
170
+ code: "await docs('authoring/quick-start');",
170
171
  },
171
172
  {label: 'One section by key', code: "await docs('spacing', 'scale');"},
172
173
  ],
package/api/docs/docs.mjs CHANGED
@@ -34,6 +34,7 @@ import {node as nodeLeaf, nodeView} from './node/node.mjs';
34
34
  import {resolveDocsArgument} from './_adapter.mjs';
35
35
  import {AstryxError} from '../error.mjs';
36
36
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
37
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
37
38
 
38
39
  export {list, index, detail, sectionLeaf as section, nodeLeaf as node};
39
40
 
@@ -108,7 +109,7 @@ export async function docs(topic, section, options = {}) {
108
109
  return namespaceSection(found.tree, found.node, section, options);
109
110
  }
110
111
  throw new AstryxError(
111
- `"${found.node.route}" has no sections. Read it whole: astryx docs ${found.node.route}.`,
112
+ `"${found.node.route}" has no sections. Read it whole: ${formatCliCommand(`docs ${found.node.route}`)}.`,
112
113
  [{name: found.node.route, reason: found.node.summary}],
113
114
  ERROR_CODES.ERR_UNKNOWN_SECTION,
114
115
  );
@@ -11,6 +11,7 @@
11
11
  import {describe, it, expect} from 'vitest';
12
12
  import {docs} from './docs.mjs';
13
13
  import {AstryxError} from '../error.mjs';
14
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
14
15
 
15
16
  const SLOW = 30_000;
16
17
 
@@ -92,7 +93,7 @@ describe('docs() dispatcher routing', () => {
92
93
 
93
94
  it("lists the docs tree's namespaces in meta, so every data entry reads as a topic", async () => {
94
95
  const res = await docs();
95
- expect(res.meta.namespaces.map(entry => entry.topic)).toEqual(['cli', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography', 'unorganized']);
96
+ expect(res.meta.namespaces.map(entry => entry.topic)).toEqual(['authoring', 'cli', 'foundations', 'global', 'guides', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography']);
96
97
  for (const entry of res.data) {
97
98
  expect((await docs(entry.topic)).type).toBe('docs.detail');
98
99
  }
@@ -107,7 +108,9 @@ describe('docs() dispatcher routing', () => {
107
108
  it('a section of a typed doc -> ERR_UNKNOWN_SECTION, suggesting the doc itself', async () => {
108
109
  const err = await docs('cli/api/functions/search', 'x').catch(e => e);
109
110
  expect(err.code).toBe('ERR_UNKNOWN_SECTION');
110
- expect(err.message).toContain('astryx docs cli/api/functions/search');
111
+ expect(err.message).toContain(
112
+ formatCliCommand('docs cli/api/functions/search'),
113
+ );
111
114
  expect(err.suggestions.map(s => s.name)).toEqual(['cli/api/functions/search']);
112
115
  }, SLOW);
113
116
 
@@ -120,7 +123,13 @@ describe('docs() dispatcher routing', () => {
120
123
  kind: 'namespace',
121
124
  package: '@astryxdesign/cli',
122
125
  breadcrumb: [{route: 'cli', title: 'Astryx CLI'}],
123
- content: [],
126
+ // Its one block points to the host entry's guide.
127
+ content: [
128
+ {
129
+ type: 'prose',
130
+ text: expect.stringContaining('`astryx docs cli/host-entry`'),
131
+ },
132
+ ],
124
133
  });
125
134
  expect(r.data.slots.flatMap(slot => slot.children.map(c => c.route))).toEqual([
126
135
  'cli/api/functions',
@@ -149,8 +158,8 @@ describe('docs() dispatcher routing', () => {
149
158
  }, SLOW);
150
159
 
151
160
  it('a guide the tree places reads like a topic: the whole doc, its index, a section', async () => {
152
- // cli/integrations is a namespace of short guides; each guide reads like a topic.
153
- const integrations = await docs('cli/integrations');
161
+ // authoring is a namespace of short guides; each guide reads like a topic.
162
+ const integrations = await docs('authoring');
154
163
  expect(integrations.type).toBe('docs.node');
155
164
  const guide = placedGuide(integrations.data);
156
165
  expect((await docs(guide)).type).toBe('docs.detail');
@@ -169,7 +178,7 @@ describe('docs() dispatcher routing', () => {
169
178
  expect(leaf.links.up).toBe('astryx docs cli/api/functions');
170
179
  expect(leaf.links.previous).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
171
180
  expect(leaf.links.next).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
172
- const integrations = (await docs('cli/integrations')).data;
181
+ const integrations = (await docs('authoring')).data;
173
182
  const guide = placedGuide(integrations);
174
183
  const siblings = integrations.slots
175
184
  .find(slot => slot.children.some(child => child.route === guide))
@@ -178,7 +187,7 @@ describe('docs() dispatcher routing', () => {
178
187
  const index = await docs(guide, undefined, {index: true});
179
188
  // A guide moves across its namespace's slot, as any tree node does.
180
189
  expect(index.data.links).toEqual({
181
- up: 'astryx docs cli/integrations',
190
+ up: 'astryx docs authoring',
182
191
  ...(at > 0 ? {previous: `astryx docs ${siblings[at - 1]}`} : {}),
183
192
  ...(at < siblings.length - 1
184
193
  ? {next: `astryx docs ${siblings[at + 1]}`}
@@ -195,16 +204,22 @@ describe('docs() dispatcher routing', () => {
195
204
  expect(end.links.previous).toBe(
196
205
  `astryx docs ${guide} ${index.data.sections.at(-2).id}`,
197
206
  );
198
- // A flat topic's home is the Unorganized level, and it moves across it.
207
+ // A flat topic's home is the level for its category, and it moves across it.
199
208
  const flat = (await docs('principles')).data.links;
200
- expect(flat.up).toBe('astryx docs unorganized');
209
+ expect(flat.up).toBe('astryx docs guides');
201
210
  expect(flat.previous).toMatch(/^astryx docs [a-z-]+$/);
202
211
  expect(flat.next).toMatch(/^astryx docs [a-z-]+$/);
203
- const home = (await docs('unorganized')).data;
204
- expect(home).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
205
- expect(home.slots[0].children.map(child => child.route)).toEqual(
206
- (await docs()).data.map(entry => entry.topic),
207
- );
212
+ const guides = (await docs('guides')).data;
213
+ expect(guides).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
214
+ const foundations = (await docs('foundations')).data;
215
+ expect(foundations).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
216
+ // Between them the two levels hold every flat topic, each in list order.
217
+ const topics = (await docs()).data.map(entry => entry.topic);
218
+ const held = [guides, foundations].map(level => level.slots[0].children.map(child => child.route));
219
+ for (const routes of held) {
220
+ expect(routes).toEqual(topics.filter(topic => routes.includes(topic)));
221
+ }
222
+ expect(held.flat().sort()).toEqual([...topics].sort());
208
223
  }, SLOW);
209
224
 
210
225
  it('names a node by its doc identity; a generated level has id null', async () => {
@@ -231,10 +246,9 @@ describe('docs() dispatcher routing', () => {
231
246
  }, SLOW);
232
247
 
233
248
  it("the guide's old flat name is gone, and its error names the new route", async () => {
234
- await expect(docs('cli-integrations')).rejects.toMatchObject({
235
- code: 'ERR_UNKNOWN_TOPIC',
236
- suggestions: [expect.objectContaining({name: 'cli/integrations'})],
237
- });
249
+ const error = await docs('cli-integrations').catch(e => e);
250
+ expect(error.code).toBe('ERR_UNKNOWN_TOPIC');
251
+ expect(error.suggestions[0]).toMatchObject({name: 'authoring'});
238
252
  expect((await docs()).data.map(entry => entry.topic)).not.toContain(
239
253
  'cli-integrations',
240
254
  );
@@ -244,11 +258,16 @@ describe('docs() dispatcher routing', () => {
244
258
  const err = await docs('cli', 'zzzz-nope').catch(e => e);
245
259
  expect(err).toBeInstanceOf(AstryxError);
246
260
  expect(err.code).toBe('ERR_UNKNOWN_SECTION');
247
- // It names every guide below the namespace, at any depth.
248
261
  const names = err.suggestions.map(s => s.name);
249
262
  expect(names).toContain('cli/component-lookups');
250
- expect(names).toContain('cli/integrations/quick-start');
251
263
  expect(names.every(name => name.startsWith('cli/'))).toBe(true);
264
+ // It names every guide below the namespace, at any depth.
265
+ const deep = await docs('authoring', 'zzzz-nope').catch(e => e);
266
+ expect(deep.code).toBe('ERR_UNKNOWN_SECTION');
267
+ const below = deep.suggestions.map(s => s.name);
268
+ expect(below).toContain('authoring/quick-start');
269
+ expect(below).toContain('authoring/building-blocks/components/add-a-component');
270
+ expect(below.every(name => name.startsWith('authoring/'))).toBe(true);
252
271
  }, SLOW);
253
272
 
254
273
  it('an unknown route suggests the children of the deepest namespace it reaches', async () => {
@@ -246,7 +246,7 @@ describe('integration docs in the docs tree', () => {
246
246
  });
247
247
  scaffold({
248
248
  ...kit(),
249
- 'unorganized.doc.mjs': {...NAMESPACE, name: 'unorganized', title: 'Mine', summary: 'Mine.'},
249
+ 'guides.doc.mjs': {...NAMESPACE, name: 'guides', title: 'Mine', summary: 'Mine.'},
250
250
  'use-a-theme.doc.mjs': {...NAMESPACE, name: 'use-a-theme', title: 'Acme use-a-theme', summary: 'Acme use-a-theme.'},
251
251
  'cli.doc.mjs': flat('cli'),
252
252
  });
@@ -254,26 +254,26 @@ describe('integration docs in the docs tree', () => {
254
254
  expect(listed.meta.namespaces).toEqual(
255
255
  expect.arrayContaining([
256
256
  expect.objectContaining({topic: 'cli', package: '@astryxdesign/cli'}),
257
- expect.objectContaining({topic: 'unorganized', package: '@astryxdesign/cli'}),
257
+ expect.objectContaining({topic: 'guides', package: '@astryxdesign/cli'}),
258
258
  ]),
259
259
  );
260
- expect(listed.meta.namespaces.filter(n => ['use-a-theme', 'unorganized'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
260
+ expect(listed.meta.namespaces.filter(n => ['use-a-theme', 'guides'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
261
261
  expect(listed.data.map(entry => entry.topic)).not.toContain('cli');
262
262
  // Each name opens the CLI's doc, and a CLI topic keeps its home.
263
263
  expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
264
- expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
264
+ expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
265
265
  const tokens = await docs('use-a-theme', undefined, {cwd: tmpDir});
266
266
  expect(tokens.type).toBe('docs.detail');
267
- expect(tokens.data.links.up).toBe('astryx docs unorganized');
267
+ expect(tokens.data.links.up).toBe('astryx docs guides');
268
268
  // The project doctor and the package doctor both name the claims.
269
269
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
270
270
  expect(check.status).toBe('warn');
271
- expect(check.message).toContain('takes the route "unorganized", which the CLI\'s own docs keep');
271
+ expect(check.message).toContain('takes the route "guides", which the CLI\'s own docs keep');
272
272
  expect(check.message).toContain('takes the route "use-a-theme"');
273
273
  expect(check.message).toContain('both have the route "cli"');
274
274
  const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
275
275
  const graph = result.data.issues.filter(issue => issue.code === 'invalid_doc_graph').map(issue => issue.message).join('\n');
276
- expect(graph).toContain('takes the route "unorganized"');
276
+ expect(graph).toContain('takes the route "guides"');
277
277
  expect(graph).toContain('takes the route "use-a-theme"');
278
278
  expect(graph).toContain('route "cli"');
279
279
  }, SLOW);
@@ -294,16 +294,16 @@ describe('integration docs in the docs tree', () => {
294
294
  const nested = path.join(tmpDir, 'node_modules', '@acme', 'kit', 'docs', 'nested');
295
295
  fs.mkdirSync(nested, {recursive: true});
296
296
  fs.writeFileSync(
297
- path.join(nested, 'caps-unorganized.doc.mjs'),
298
- `export const docs = ${JSON.stringify(flat('Unorganized'), null, 2)};\n`,
297
+ path.join(nested, 'caps-guides.doc.mjs'),
298
+ `export const docs = ${JSON.stringify(flat('Guides'), null, 2)};\n`,
299
299
  );
300
300
  fs.writeFileSync(
301
301
  path.join(nested, 'caps-use-a-theme.doc.mjs'),
302
302
  `export const docs = ${JSON.stringify(flat('USE-A-THEME'), null, 2)};\n`,
303
303
  );
304
304
  expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
305
- expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
306
- expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs unorganized');
305
+ expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
306
+ expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs guides');
307
307
  const listed = await docs(undefined, undefined, {cwd: tmpDir});
308
308
  expect(listed.data.map(entry => entry.topic.toLowerCase())).not.toContain('cli');
309
309
  // Search does not offer a topic whose route another doc owns.
@@ -314,10 +314,10 @@ describe('integration docs in the docs tree', () => {
314
314
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
315
315
  expect(check.status).toBe('warn');
316
316
  expect(check.message).toContain('route "CLI"');
317
- expect(check.message).toContain('takes the route "Unorganized"');
317
+ expect(check.message).toContain('takes the route "Guides"');
318
318
  // `USE-A-THEME` is the CLI's topic `use-a-theme` in another spelling: the CLI's wins.
319
319
  const tokens = await docs('USE-A-THEME', undefined, {cwd: tmpDir, index: true});
320
- expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs unorganized'}});
320
+ expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs guides'}});
321
321
  expect(tokens.data.title).not.toBe('Acme USE-A-THEME');
322
322
  const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
323
323
  const graph = result.data.issues
@@ -325,7 +325,7 @@ describe('integration docs in the docs tree', () => {
325
325
  .map(issue => issue.message)
326
326
  .join('\n');
327
327
  expect(graph).toContain('route "CLI"');
328
- expect(graph).toContain('takes the route "Unorganized"');
328
+ expect(graph).toContain('takes the route "Guides"');
329
329
  }, SLOW);
330
330
 
331
331
  it("keeps a replaced name for the topic that replaces it, over another integration's namespace", async () => {
@@ -420,9 +420,9 @@ describe('integration docs in the docs tree', () => {
420
420
  scaffold({
421
421
  ...kit(),
422
422
  'a-cli.doc.mjs': flat('cli'),
423
- 'a-unorganized.doc.mjs': flat('Unorganized'),
423
+ 'a-guides.doc.mjs': flat('Guides'),
424
424
  'z-b2.doc.mjs': flat('b2', {replaces: 'cli'}),
425
- 'z-u2.doc.mjs': flat('u2', {replaces: 'Unorganized'}),
425
+ 'z-u2.doc.mjs': flat('u2', {replaces: 'Guides'}),
426
426
  });
427
427
  // Another package carries the chain on: c3 replaces b2, which replaced cli.
428
428
  const three = path.join(tmpDir, 'node_modules', '@acme', 'three');
@@ -440,8 +440,8 @@ describe('integration docs in the docs tree', () => {
440
440
  for (const name of ['cli', 'CLI']) {
441
441
  expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
442
442
  }
443
- for (const name of ['unorganized', 'UNORGANIZED']) {
444
- expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
443
+ for (const name of ['guides', 'GUIDES']) {
444
+ expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
445
445
  }
446
446
  // The replacement still answers to its own names.
447
447
  for (const name of ['b2', 'c3']) {
@@ -456,7 +456,7 @@ describe('integration docs in the docs tree', () => {
456
456
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
457
457
  expect(check.status).toBe('warn');
458
458
  expect(check.message).toContain('The topic "c3" answers to "cli" through replaces');
459
- expect(check.message).toContain('The topic "u2" answers to "unorganized" through replaces');
459
+ expect(check.message).toContain('The topic "u2" answers to "guides" through replaces');
460
460
  const inPackage = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
461
461
  const graph = inPackage.data.issues
462
462
  .filter(issue => issue.code === 'invalid_doc_graph')
@@ -519,7 +519,7 @@ describe('integration docs in the docs tree', () => {
519
519
  });
520
520
  const {data} = await docs('theme', 'acme-theming-notes', {cwd: tmpDir});
521
521
  // `generic:integrations` is the extension's own guide, never the CLI's
522
- // `cli/integrations`; a provider-qualified link reaches the CLI's topic.
522
+ // `authoring`; a provider-qualified link reaches the CLI's topic.
523
523
  expect(data.content[0].text).toBe(
524
524
  'See `astryx docs acme/integrations`, and `astryx docs tokens` for the tokens.',
525
525
  );
@@ -569,4 +569,26 @@ describe('integration docs in the docs tree', () => {
569
569
  expect(check.status).toBe('warn');
570
570
  expect(check.message).toContain('both have the route "cli"');
571
571
  }, SLOW);
572
+
573
+ it('says what to write for a link that names a doc by its bare name, and when no doc has that name', async () => {
574
+ scaffold({
575
+ ...kit(),
576
+ 'bare.doc.mjs': guide('bare', {
577
+ sections: [
578
+ {
579
+ title: 'Overview',
580
+ content: [{type: 'prose', text: 'Read {@link deploy}, then {@link nosuchtopic}.'}],
581
+ },
582
+ ],
583
+ }),
584
+ });
585
+ const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
586
+ const graph = result.data.issues.filter(issue => issue.code === 'invalid_doc_graph').map(issue => issue.message);
587
+ expect(graph).toEqual(
588
+ expect.arrayContaining([
589
+ expect.stringContaining('"deploy" is a topic: write `{@link generic:deploy}`.'),
590
+ expect.stringContaining('no topic is named "nosuchtopic"'),
591
+ ]),
592
+ );
593
+ }, SLOW);
572
594
  });
@@ -22,6 +22,7 @@ import {docs} from './docs.mjs';
22
22
  import {search} from '../search/search.mjs';
23
23
  import {loadDocsCatalog} from './_adapter.mjs';
24
24
  import {AstryxError} from '../error.mjs';
25
+ import {discoverCoreTemplates} from '../../foundation/discovery/template-adapter.mjs';
25
26
 
26
27
  const SLOW = 30_000;
27
28
 
@@ -110,6 +111,129 @@ describe('integration-contributed topics', () => {
110
111
  expect(section.data.title).toBe('Overview');
111
112
  }, SLOW);
112
113
 
114
+ it('reads a link to a component or a template as the command that opens it', async () => {
115
+ scaffold({
116
+ 'using-widgets.doc.mjs': topic({
117
+ name: 'using-widgets',
118
+ title: 'Using widgets',
119
+ sections: [
120
+ {
121
+ title: 'Overview',
122
+ content: [
123
+ {
124
+ type: 'prose',
125
+ text: 'Start with {@link component:AcmeButton} or {@link block:acme-card}, built on {@link @astryxdesign/core:component:Button}.',
126
+ },
127
+ ],
128
+ },
129
+ ],
130
+ }),
131
+ });
132
+ const pkgDir = path.join(tmpDir, 'node_modules', '@acme', 'widgets');
133
+ fs.writeFileSync(
134
+ path.join(pkgDir, 'astryx.integration.mjs'),
135
+ "export default {components: './components', templates: './templates', docs: './docs'};\n",
136
+ );
137
+ fs.mkdirSync(path.join(pkgDir, 'components'));
138
+ fs.writeFileSync(
139
+ path.join(pkgDir, 'components', 'AcmeButton.doc.mjs'),
140
+ "export default {type: 'component', name: 'AcmeButton', displayName: 'Acme Button', description: 'A button.', props: []};\n",
141
+ );
142
+ fs.writeFileSync(
143
+ path.join(pkgDir, 'components', 'AcmeButton.tsx'),
144
+ 'export function AcmeButton() { return null; }\n',
145
+ );
146
+ fs.mkdirSync(path.join(pkgDir, 'templates'));
147
+ fs.writeFileSync(
148
+ path.join(pkgDir, 'templates', 'acme-card.doc.mjs'),
149
+ "export default {type: 'block', name: 'Acme card', description: 'A card.'};\n",
150
+ );
151
+ fs.writeFileSync(
152
+ path.join(pkgDir, 'templates', 'acme-card.tsx'),
153
+ 'export default function Fixture() { return null; }\n',
154
+ );
155
+
156
+ const detail = await docs('using-widgets', undefined, {cwd: tmpDir, full: true});
157
+
158
+ const prose = JSON.stringify(detail.data.sections);
159
+ expect(prose).toContain('`astryx component AcmeButton --package @acme/widgets`');
160
+ expect(prose).toContain(
161
+ '`astryx template acme-card --type block --package @acme/widgets`',
162
+ );
163
+ expect(prose).toContain('`astryx component Button`');
164
+ expect(prose).not.toContain('{@link');
165
+ }, SLOW);
166
+
167
+ it('selects Core in a link only where the bare name would open something else', async () => {
168
+ const core = await discoverCoreTemplates();
169
+ const page = core.find(template => template.type === 'page')?.dirName;
170
+ const block = core.find(template => template.type === 'block')?.dirName;
171
+ scaffold({
172
+ 'using-widgets.doc.mjs': topic({
173
+ name: 'using-widgets',
174
+ title: 'Using widgets',
175
+ sections: [
176
+ {
177
+ title: 'Overview',
178
+ content: [
179
+ {
180
+ type: 'prose',
181
+ text:
182
+ 'Core: {@link @astryxdesign/core:component:Button}, {@link @astryxdesign/core:component:Badge}, ' +
183
+ `{@link @astryxdesign/core:page:${page}}, {@link @astryxdesign/core:block:${block}}.`,
184
+ },
185
+ ],
186
+ },
187
+ ],
188
+ }),
189
+ });
190
+ const pkgDir = path.join(tmpDir, 'node_modules', '@acme', 'widgets');
191
+ // The CLI range that turns component replacement on.
192
+ fs.writeFileSync(
193
+ path.join(pkgDir, 'package.json'),
194
+ JSON.stringify({
195
+ name: '@acme/widgets',
196
+ version: '1.0.0',
197
+ peerDependencies: {'@astryxdesign/cli': '>=0.6.7'},
198
+ peerDependenciesMeta: {'@astryxdesign/cli': {optional: true}},
199
+ }),
200
+ );
201
+ fs.writeFileSync(
202
+ path.join(pkgDir, 'astryx.integration.mjs'),
203
+ "export default {components: './components', templates: './templates', docs: './docs'};\n",
204
+ );
205
+ fs.mkdirSync(path.join(pkgDir, 'components'));
206
+ // AcmeButton replaces Core's Button, so bare `Button` opens AcmeButton.
207
+ fs.writeFileSync(
208
+ path.join(pkgDir, 'components', 'AcmeButton.doc.mjs'),
209
+ "export default {type: 'component', name: 'AcmeButton', displayName: 'Acme Button', description: 'A button.', replaces: 'Button', props: []};\n",
210
+ );
211
+ fs.writeFileSync(
212
+ path.join(pkgDir, 'components', 'AcmeButton.tsx'),
213
+ 'export function AcmeButton() { return null; }\n',
214
+ );
215
+ // A page template with a Core page's id makes the bare id ambiguous.
216
+ fs.mkdirSync(path.join(pkgDir, 'templates'));
217
+ fs.writeFileSync(
218
+ path.join(pkgDir, 'templates', `${page}.doc.mjs`),
219
+ "export default {type: 'page', name: 'Acme page', displayName: 'Acme page', description: 'A page.'};\n",
220
+ );
221
+ fs.writeFileSync(
222
+ path.join(pkgDir, 'templates', `${page}.tsx`),
223
+ 'export default function Fixture() { return null; }\n',
224
+ );
225
+
226
+ const detail = await docs('using-widgets', undefined, {cwd: tmpDir, full: true});
227
+
228
+ const prose = JSON.stringify(detail.data.sections);
229
+ expect(prose).toContain('`astryx component Button --package @astryxdesign/core`');
230
+ expect(prose).toContain('`astryx component Badge`');
231
+ expect(prose).toContain(
232
+ `\`astryx template ${page} --type page --package @astryxdesign/core\``,
233
+ );
234
+ expect(prose).toContain(`\`astryx template ${block} --type block\``);
235
+ }, SLOW);
236
+
113
237
  it('is invisible to a project that does not configure the integration', async () => {
114
238
  scaffold({'deploying.doc.mjs': topic()}, {config: 'export default {};\n'});
115
239
  const listed = await docs(undefined, undefined, {cwd: tmpDir});
@@ -323,7 +447,7 @@ describe('integration-contributed topics', () => {
323
447
  // places it.
324
448
  expect(top).toContain('troubleshooting');
325
449
  expect(
326
- top.some(name => /^cli\/integrations\/(?:.+\/)?troubleshooting$/.test(name)),
450
+ top.some(name => /^authoring\/(?:.+\/)?troubleshooting$/.test(name)),
327
451
  top.join(', '),
328
452
  ).toBe(true);
329
453
  }, SLOW);
@@ -15,7 +15,12 @@
15
15
  */
16
16
 
17
17
  import {loadTopicFile} from '../../../foundation/doc-compiler/read.mjs';
18
- import {holdsOwnName, loadDocsCatalog, projectTree} from '../_adapter.mjs';
18
+ import {
19
+ holdsOwnName,
20
+ linkDocText,
21
+ loadDocsCatalog,
22
+ projectTree,
23
+ } from '../_adapter.mjs';
19
24
 
20
25
  /**
21
26
  * @param {object} [options]
@@ -39,7 +44,12 @@ export async function list({cwd} = {}) {
39
44
  /** @type {import('../docs.type.mjs').DocsListEntry} */
40
45
  const listed = {
41
46
  topic: entry.name,
42
- description,
47
+ // A link in the description reads as the command that opens its doc.
48
+ description: await linkDocText(
49
+ catalog,
50
+ entry.providerId ?? entry.package,
51
+ description,
52
+ ),
43
53
  package: entry.package,
44
54
  };
45
55
  if (entry.replaces != null) listed.replaces = entry.replaces;