@astryxdesign/cli 0.7.2-canary.fdd384f → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +169 -149
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/kit/kit.mjs +3 -11
  7. package/api/component/_adapter.d.mts +31 -0
  8. package/api/component/_adapter.mjs +119 -11
  9. package/api/component/component.doc.mjs +6 -1
  10. package/api/component/component.mjs +60 -10
  11. package/api/component/doc-links.test.mjs +386 -0
  12. package/api/discover/_adapter.d.mts +132 -12
  13. package/api/discover/_adapter.mjs +488 -27
  14. package/api/discover/_adapter.test.mjs +599 -17
  15. package/api/discover/_catalog-view.d.mts +16 -5
  16. package/api/discover/_catalog-view.mjs +32 -8
  17. package/api/discover/detail/doc/doc.mjs +9 -1
  18. package/api/discover/discover.d.mts +11 -0
  19. package/api/discover/discover.doc.mjs +9 -7
  20. package/api/discover/discover.mjs +121 -19
  21. package/api/discover/discover.type.d.mts +20 -7
  22. package/api/discover/discover.type.mjs +17 -7
  23. package/api/discover/list/list.d.mts +4 -3
  24. package/api/discover/list/list.mjs +17 -10
  25. package/api/docs/_adapter.d.mts +63 -0
  26. package/api/docs/_adapter.mjs +312 -18
  27. package/api/docs/docs.doc.mjs +2 -1
  28. package/api/docs/docs.mjs +2 -1
  29. package/api/docs/docs.test.mjs +5 -2
  30. package/api/docs/integration-tree.test.mjs +22 -0
  31. package/api/docs/list/list.mjs +12 -2
  32. package/api/docs/reference-blocks.test.mjs +1 -3
  33. package/api/doctor/_adapter.d.mts +108 -0
  34. package/api/doctor/_adapter.mjs +223 -4
  35. package/api/doctor/doctor.d.mts +199 -0
  36. package/api/doctor/doctor.doc.mjs +3 -2
  37. package/api/doctor/doctor.mjs +530 -34
  38. package/api/doctor/doctor.test.mjs +180 -14
  39. package/api/doctor/release-checks.test.mjs +156 -0
  40. package/api/doctor/theme-checks.mjs +16 -3
  41. package/api/doctor/theme-checks.test.mjs +223 -7
  42. package/api/error.d.mts +10 -0
  43. package/api/error.mjs +25 -0
  44. package/api/gap-report/gap-report.d.mts +3 -0
  45. package/api/gap-report/gap-report.doc.mjs +11 -3
  46. package/api/gap-report/gap-report.mjs +152 -48
  47. package/api/gap-report/gap-report.test.mjs +233 -0
  48. package/api/gap-report/gap-report.type.d.mts +41 -0
  49. package/api/gap-report/gap-report.type.mjs +18 -0
  50. package/api/hook/_adapter.mjs +3 -11
  51. package/api/hook/hook.doc.mjs +4 -0
  52. package/api/hook/list/list.d.mts +1 -1
  53. package/api/init/_adapter.d.mts +22 -0
  54. package/api/init/_adapter.mjs +59 -0
  55. package/api/init/init.d.mts +7 -5
  56. package/api/init/init.doc.mjs +28 -7
  57. package/api/init/init.mjs +28 -4
  58. package/api/init/init.type.d.mts +48 -3
  59. package/api/init/init.type.mjs +37 -3
  60. package/api/init/run/run.d.mts +1 -1
  61. package/api/init/run/run.mjs +15 -4
  62. package/api/init/user/user.d.mts +14 -0
  63. package/api/init/user/user.mjs +87 -0
  64. package/api/init/user/user.test.mjs +232 -0
  65. package/api/integration/_adapter.d.mts +33 -0
  66. package/api/integration/_adapter.mjs +58 -0
  67. package/api/integration/authoring-checks.mjs +100 -5
  68. package/api/integration/authoring-checks.test.mjs +769 -0
  69. package/api/integration/authoring-checks.type.d.mts +134 -0
  70. package/api/integration/authoring-checks.type.mjs +60 -1
  71. package/api/integration/integrationCheck.doc.mjs +1 -1
  72. package/api/integration/integrationComponentConflicts.doc.mjs +11 -3
  73. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  74. package/api/integration/pack-check.mjs +303 -13
  75. package/api/integration/pack-check.test.mjs +371 -10
  76. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  77. package/api/integration/validate-integration.d.mts +8 -0
  78. package/api/integration/validate-integration.mjs +55 -9
  79. package/api/integration/validate-integration.test.mjs +77 -8
  80. package/api/integration/validate-integration.type.d.mts +8 -0
  81. package/api/integration/validate-integration.type.mjs +3 -1
  82. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  83. package/api/integration/validateIntegration.doc.mjs +4 -2
  84. package/api/search/_adapter.d.mts +11 -0
  85. package/api/search/_adapter.mjs +25 -0
  86. package/api/search/search.d.mts +73 -13
  87. package/api/search/search.doc.mjs +8 -3
  88. package/api/search/search.domain-priority.test.mjs +108 -18
  89. package/api/search/search.mjs +541 -52
  90. package/api/search/search.test.mjs +143 -1
  91. package/api/search/search.type.d.mts +14 -1
  92. package/api/search/search.type.mjs +6 -1
  93. package/api/swizzle/_adapter.mjs +2 -2
  94. package/api/swizzle/copy/copy.mjs +1 -1
  95. package/api/template/template-integration.test.mjs +1 -1
  96. package/api/theme/_adapter.d.mts +16 -0
  97. package/api/theme/_adapter.mjs +32 -5
  98. package/api/theme/build/build.d.mts +2 -1
  99. package/api/theme/build/build.mjs +70 -14
  100. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  101. package/api/theme/build/font-warning.mjs +5 -3
  102. package/api/theme/build/font-warning.test.mjs +2 -1
  103. package/api/theme/remove/remove.test.mjs +2 -2
  104. package/api/theme/targets/targets.mjs +3 -10
  105. package/api/theme/themeTargets.doc.mjs +4 -0
  106. package/api/theme/use/use.test.mjs +1 -1
  107. package/api/upgrade/_adapter.d.mts +40 -2
  108. package/api/upgrade/_adapter.mjs +118 -5
  109. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  110. package/api/upgrade/run/run.mjs +35 -2
  111. package/api/upgrade/status/status.d.mts +21 -5
  112. package/api/upgrade/status/status.mjs +45 -8
  113. package/api/upgrade/upgrade.doc.mjs +6 -3
  114. package/api/upgrade/upgrade.mjs +5 -1
  115. package/api/upgrade/upgrade.type.d.mts +23 -0
  116. package/api/upgrade/upgrade.type.mjs +16 -1
  117. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  118. package/assets/codemods/registry.mjs +1 -0
  119. package/assets/codemods/runner.mjs +7 -1
  120. package/assets/codemods/transforms/next/index.mjs +1 -11
  121. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  122. package/assets/discover/official-packages.json +367 -0
  123. package/assets/docs/author-a-theme.doc.mjs +2 -2
  124. package/assets/docs/browser-support.doc.mjs +1 -1
  125. package/assets/docs/getting-started.doc.mjs +23 -3
  126. package/assets/docs/styling-overview.doc.mjs +1 -1
  127. package/assets/docs/theme.doc.mjs +1 -1
  128. package/assets/docs/tree/add-a-component.doc.mjs +12 -2
  129. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  130. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  131. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  132. package/assets/docs/tree/block-template.doc.mjs +6 -18
  133. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  134. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  135. package/assets/docs/tree/check-the-props.doc.mjs +8 -3
  136. package/assets/docs/tree/check-your-docs.doc.mjs +30 -13
  137. package/assets/docs/tree/checks.doc.mjs +17 -17
  138. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  139. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  140. package/assets/docs/tree/cli.doc.mjs +6 -0
  141. package/assets/docs/tree/codemods.doc.mjs +17 -7
  142. package/assets/docs/tree/commands.doc.mjs +7 -1
  143. package/assets/docs/tree/component-family.doc.mjs +3 -5
  144. package/assets/docs/tree/component-imports.doc.mjs +13 -3
  145. package/assets/docs/tree/components.doc.mjs +7 -1
  146. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  147. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  148. package/assets/docs/tree/configuration.doc.mjs +7 -3
  149. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  150. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  151. package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
  152. package/assets/docs/tree/docs.doc.mjs +9 -3
  153. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  154. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  155. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  156. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  157. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  158. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  159. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  160. package/assets/docs/tree/global.doc.mjs +131 -0
  161. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  162. package/assets/docs/tree/install-once.doc.mjs +105 -0
  163. package/assets/docs/tree/integrations.doc.mjs +13 -1
  164. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  165. package/assets/docs/tree/layout.doc.mjs +6 -6
  166. package/assets/docs/tree/links.doc.mjs +6 -5
  167. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  168. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  169. package/assets/docs/tree/migration.doc.mjs +0 -1
  170. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  171. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  172. package/assets/docs/tree/page-template.doc.mjs +3 -7
  173. package/assets/docs/tree/problems.doc.mjs +205 -0
  174. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  175. package/assets/docs/tree/publishing.doc.mjs +6 -6
  176. package/assets/docs/tree/quick-start.doc.mjs +52 -26
  177. package/assets/docs/tree/reference.doc.mjs +192 -0
  178. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  179. package/assets/docs/tree/replace-a-core-template.doc.mjs +9 -11
  180. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  181. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  182. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  183. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  184. package/assets/docs/tree/single-component.doc.mjs +14 -6
  185. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  186. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  187. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  188. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  189. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  190. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  191. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  192. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  193. package/assets/docs/tree/templates.doc.mjs +7 -1
  194. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  195. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  196. package/assets/docs/tree/themes.doc.mjs +4 -0
  197. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  198. package/assets/docs/tree/troubleshooting.doc.mjs +22 -14
  199. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  200. package/assets/docs/tree/updates.doc.mjs +92 -0
  201. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  202. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  203. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  204. package/assets/docs/tree/versioning.doc.mjs +9 -9
  205. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  206. package/assets/docs/tree/write-the-template-file.doc.mjs +5 -5
  207. package/assets/docs/working-with-ai.doc.mjs +23 -9
  208. package/authoring/codemod/codemod.doc.mjs +7 -3
  209. package/authoring/config/config.doc.mjs +9 -6
  210. package/authoring/config/type.ts +4 -2
  211. package/authoring/debug/parse.d.mts +5 -5
  212. package/authoring/discover/discover.doc.mjs +7 -1
  213. package/authoring/doctypes/_schema.d.mts +8 -3
  214. package/authoring/doctypes/_schema.mjs +1 -0
  215. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  216. package/authoring/doctypes/command/command.doc.mjs +20 -12
  217. package/authoring/doctypes/command/type.ts +14 -0
  218. package/authoring/doctypes/component/component.doc.mjs +29 -26
  219. package/authoring/doctypes/component/type.ts +15 -5
  220. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  221. package/authoring/doctypes/function/function.doc.mjs +9 -8
  222. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  223. package/authoring/doctypes/hook/type.ts +4 -0
  224. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  225. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  226. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  227. package/authoring/doctypes/template/template.doc.mjs +2 -2
  228. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  229. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  230. package/authoring/identity/identity.doc.mjs +3 -3
  231. package/authoring/index.d.ts +1 -0
  232. package/authoring/integration/integration.doc.mjs +22 -5
  233. package/authoring/integration/parse.test.mjs +11 -0
  234. package/authoring/integration/schema.d.mts +14 -3
  235. package/authoring/integration/schema.mjs +33 -2
  236. package/authoring/integration/type.ts +8 -0
  237. package/clients/cli/bin/astryx.mjs +20 -3
  238. package/clients/cli/cli-command.test.mjs +166 -0
  239. package/clients/cli/commands/blog.doc.mjs +1 -0
  240. package/clients/cli/commands/build-theme.batch-report.test.mjs +14 -2
  241. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  242. package/clients/cli/commands/build-theme.mjs +25 -12
  243. package/clients/cli/commands/build.doc.mjs +1 -0
  244. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  245. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  246. package/clients/cli/commands/component.doc.mjs +1 -0
  247. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  248. package/clients/cli/commands/discover.doc.mjs +9 -1
  249. package/clients/cli/commands/discover.mjs +144 -93
  250. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  251. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  252. package/clients/cli/commands/docs.doc.mjs +1 -0
  253. package/clients/cli/commands/docs.mjs +49 -19
  254. package/clients/cli/commands/docs.test.mjs +2 -2
  255. package/clients/cli/commands/doctor-integration-components.doc.mjs +7 -3
  256. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  257. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  258. package/clients/cli/commands/doctor-integration-validate.doc.mjs +13 -2
  259. package/clients/cli/commands/doctor-integration.test.mjs +52 -4
  260. package/clients/cli/commands/doctor.doc.mjs +12 -2
  261. package/clients/cli/commands/doctor.mjs +102 -7
  262. package/clients/cli/commands/doctor.test.mjs +10 -4
  263. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  264. package/clients/cli/commands/gap-report.mjs +24 -2
  265. package/clients/cli/commands/gap-report.test.mjs +79 -0
  266. package/clients/cli/commands/hook.doc.mjs +1 -0
  267. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  268. package/clients/cli/commands/init.doc.mjs +29 -3
  269. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  270. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  271. package/clients/cli/commands/integration-check.doc.mjs +10 -2
  272. package/clients/cli/commands/integration-check.test.mjs +175 -1
  273. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  274. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  275. package/clients/cli/commands/integration.mjs +15 -9
  276. package/clients/cli/commands/json-contract.test.mjs +11 -2
  277. package/clients/cli/commands/manifest.doc.mjs +1 -0
  278. package/clients/cli/commands/outside-project.test.mjs +774 -0
  279. package/clients/cli/commands/search.doc.mjs +1 -0
  280. package/clients/cli/commands/search.mjs +16 -11
  281. package/clients/cli/commands/search.test.mjs +429 -296
  282. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  283. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  284. package/clients/cli/commands/swizzle.mjs +5 -3
  285. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  286. package/clients/cli/commands/template.doc.mjs +1 -0
  287. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  288. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  289. package/clients/cli/commands/theme-build.doc.mjs +1 -0
  290. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  291. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  292. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  293. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  294. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  295. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  296. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  297. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  298. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  299. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  300. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  301. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  302. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  303. package/clients/cli/index.mjs +111 -16
  304. package/clients/cli/lib/cli-error.mjs +4 -1
  305. package/clients/cli/lib/component-format.test.mjs +1 -1
  306. package/clients/cli/lib/define-command.mjs +2 -2
  307. package/clients/cli/lib/json-shim.mjs +3 -1
  308. package/clients/cli/lib/manifest.d.ts +9 -0
  309. package/clients/cli/lib/manifest.mjs +17 -1
  310. package/clients/cli/lib/manifest.test.mjs +25 -0
  311. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  312. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  313. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  314. package/foundation/agent-docs/agent-docs.mjs +11 -9
  315. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  316. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  317. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  318. package/foundation/config/project.d.mts +35 -3
  319. package/foundation/config/project.mjs +145 -8
  320. package/foundation/config/project.test.mjs +66 -0
  321. package/foundation/config/theme-state.mjs +5 -4
  322. package/foundation/discovery/authoring-self-docs.mjs +1 -1
  323. package/foundation/discovery/cli-self-docs.mjs +20 -3
  324. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  325. package/foundation/discovery/component-replacement.mjs +2 -1
  326. package/foundation/discovery/copied-passages.d.mts +216 -0
  327. package/foundation/discovery/copied-passages.mjs +720 -0
  328. package/foundation/discovery/copied-passages.test.mjs +124 -0
  329. package/foundation/discovery/doc-consistency.d.mts +34 -0
  330. package/foundation/discovery/doc-consistency.mjs +513 -0
  331. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  332. package/foundation/discovery/doc-fluff.d.mts +112 -0
  333. package/foundation/discovery/doc-fluff.mjs +328 -0
  334. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  335. package/foundation/discovery/doc-types.d.mts +1 -1
  336. package/foundation/discovery/doc-types.mjs +15 -8
  337. package/foundation/discovery/doc-types.test.mjs +94 -2
  338. package/foundation/discovery/docs-discovery.d.mts +7 -0
  339. package/foundation/discovery/docs-discovery.mjs +26 -2
  340. package/foundation/discovery/project-typescript.d.mts +11 -2
  341. package/foundation/discovery/project-typescript.mjs +32 -4
  342. package/foundation/discovery/prop-drift.d.mts +26 -7
  343. package/foundation/discovery/prop-drift.mjs +173 -8
  344. package/foundation/discovery/prop-drift.test.mjs +120 -2
  345. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  346. package/foundation/discovery/runner-allowlist.mjs +53 -0
  347. package/foundation/discovery/stray-pointers.d.mts +52 -0
  348. package/foundation/discovery/stray-pointers.mjs +293 -0
  349. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  350. package/foundation/discovery/template-needs.mjs +5 -2
  351. package/foundation/discovery/theme-imports.mjs +8 -4
  352. package/foundation/discovery/theme-imports.test.mjs +1 -1
  353. package/foundation/discovery/type-text.mjs +1 -1
  354. package/foundation/discovery/type-text.test.mjs +1 -1
  355. package/foundation/doc-compiler/doc-loads.test.mjs +42 -2
  356. package/foundation/doc-compiler/inputs.mjs +4 -1
  357. package/foundation/doc-compiler/links.d.mts +32 -0
  358. package/foundation/doc-compiler/links.mjs +163 -26
  359. package/foundation/doc-compiler/links.test.mjs +97 -4
  360. package/foundation/doc-compiler/read.d.mts +1 -1
  361. package/foundation/doc-compiler/tree.mjs +30 -1
  362. package/foundation/doc-compiler/tree.test.mjs +8 -1
  363. package/foundation/env/cli-command.d.mts +83 -0
  364. package/foundation/env/cli-command.mjs +152 -0
  365. package/foundation/env/cli-command.test.mjs +129 -0
  366. package/foundation/env/node-version.test.mjs +15 -3
  367. package/foundation/env/package-manager.d.mts +93 -9
  368. package/foundation/env/package-manager.global.test.mjs +66 -0
  369. package/foundation/env/package-manager.mjs +184 -13
  370. package/foundation/env/package-manager.test.mjs +341 -15
  371. package/foundation/env/project-scope.d.mts +9 -0
  372. package/foundation/env/project-scope.mjs +33 -0
  373. package/foundation/env/search-path.d.mts +42 -0
  374. package/foundation/env/search-path.mjs +205 -0
  375. package/foundation/env/search-path.test.mjs +122 -0
  376. package/foundation/env/user-dirs.d.mts +39 -0
  377. package/foundation/env/user-dirs.mjs +93 -0
  378. package/foundation/env/user-dirs.test.mjs +72 -0
  379. package/foundation/env/user-settings.d.mts +46 -0
  380. package/foundation/env/user-settings.mjs +106 -0
  381. package/foundation/env/user-settings.test.mjs +64 -0
  382. package/foundation/fs/file-protection.mjs +15 -1
  383. package/foundation/fs/module-loader.d.mts +2 -1
  384. package/foundation/fs/module-loader.mjs +60 -4
  385. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  386. package/foundation/fs/module-loader.test.mjs +194 -0
  387. package/foundation/fs/path-compare.d.mts +33 -0
  388. package/foundation/fs/path-compare.mjs +73 -0
  389. package/foundation/fs/paths.d.mts +57 -1
  390. package/foundation/fs/paths.mjs +131 -3
  391. package/foundation/fs/paths.test.mjs +10 -1
  392. package/foundation/integrations/computer-integrations.d.mts +78 -0
  393. package/foundation/integrations/computer-integrations.mjs +316 -0
  394. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  395. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  396. package/foundation/integrations/contribution-inventory.mjs +50 -2
  397. package/foundation/integrations/integration-warnings.mjs +3 -2
  398. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  399. package/foundation/integrations/integrations.d.mts +25 -1
  400. package/foundation/integrations/integrations.mjs +46 -3
  401. package/foundation/integrations/issue.ts +6 -0
  402. package/foundation/integrations/validate-contributions.d.mts +2 -0
  403. package/foundation/integrations/validate-contributions.mjs +41 -1
  404. package/foundation/release/agent-text-worker.d.mts +4 -0
  405. package/foundation/release/agent-text-worker.mjs +52 -0
  406. package/foundation/release/cache.d.mts +310 -0
  407. package/foundation/release/cache.mjs +1216 -0
  408. package/foundation/release/cache.test.mjs +920 -0
  409. package/foundation/release/choose.d.mts +207 -0
  410. package/foundation/release/choose.mjs +677 -0
  411. package/foundation/release/choose.test.mjs +427 -0
  412. package/foundation/release/core-worker.d.mts +4 -0
  413. package/foundation/release/core-worker.mjs +38 -0
  414. package/foundation/release/global-state.d.mts +259 -0
  415. package/foundation/release/global-state.mjs +472 -0
  416. package/foundation/release/global-state.test.mjs +381 -0
  417. package/foundation/release/handoff.d.mts +60 -0
  418. package/foundation/release/handoff.e2e.test.mjs +278 -0
  419. package/foundation/release/handoff.mjs +357 -0
  420. package/foundation/release/lock-lease.d.mts +23 -0
  421. package/foundation/release/lock-lease.mjs +80 -0
  422. package/foundation/release/notices.d.mts +253 -0
  423. package/foundation/release/notices.mjs +596 -0
  424. package/foundation/release/notices.test.mjs +565 -0
  425. package/foundation/release/npm-guard.d.mts +4 -0
  426. package/foundation/release/npm-guard.mjs +126 -0
  427. package/foundation/release/project.d.mts +141 -0
  428. package/foundation/release/project.mjs +466 -0
  429. package/foundation/release/project.test.mjs +288 -0
  430. package/foundation/release/refresh-worker.d.mts +4 -0
  431. package/foundation/release/refresh-worker.mjs +27 -0
  432. package/foundation/release/run-context.d.mts +47 -0
  433. package/foundation/release/run-context.mjs +149 -0
  434. package/foundation/release/update-notice-env.d.mts +28 -0
  435. package/foundation/release/update-notice-env.mjs +39 -0
  436. package/foundation/response/base.d.ts +26 -3
  437. package/foundation/response/error-codes.d.mts +3 -1
  438. package/foundation/response/error-codes.doc.mjs +12 -0
  439. package/foundation/response/error-codes.mjs +17 -0
  440. package/foundation/response/error-codes.test.mjs +2 -0
  441. package/foundation/response/json-contract.test.mjs +7 -2
  442. package/foundation/response/json.mjs +4 -1
  443. package/foundation/response/response-types.doc.mjs +17 -11
  444. package/foundation/response/response-types.doc.test.mjs +46 -0
  445. package/foundation/response/response.doc.mjs +3 -3
  446. package/foundation/xle/browser-imports.test.mjs +74 -0
  447. package/package.json +11 -11
  448. package/scripts/postinstall.mjs +24 -5
  449. /package/assets/codemods/transforms/{next → v0.7.2}/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +0 -0
  450. /package/assets/codemods/transforms/{next → v0.7.2}/migrate-list-edge-compensation-to-edge.mjs +0 -0
@@ -50,6 +50,42 @@ export function lowerTopic(catalog: DocsCatalog, entry: DocsTopicEntry, lang?: s
50
50
  * @returns {Promise<LinkProblem[]>}
51
51
  */
52
52
  export function topicLinkProblems(catalog: DocsCatalog, entry: DocsTopicEntry): Promise<LinkProblem[]>;
53
+ /**
54
+ * One line of a doc's text, such as a topic's or a tree node's summary, with
55
+ * every inline link resolved against the provider that wrote it (spec:AST-047
56
+ * FR9). A link that names no doc prints as written; doctor names it.
57
+ * @param {DocsCatalog} catalog
58
+ * @param {string} providerId the provider id of the doc the text sits in
59
+ * @param {string} text
60
+ * @returns {Promise<string>}
61
+ */
62
+ export function linkDocText(catalog: DocsCatalog, providerId: string, text: string): Promise<string>;
63
+ /**
64
+ * A component doc with every inline link in its text fields resolved
65
+ * (spec:AST-047 FR9): its description, usage, best practices, and each prop's
66
+ * and example's description. Code fields are shown as written. A Core
67
+ * component's links resolve against the CLI's own docs provider; an
68
+ * integration's against that integration's.
69
+ * @template T
70
+ * @param {DocsCatalog} catalog
71
+ * @param {string} providerId the provider id the component's links resolve
72
+ * against
73
+ * @param {T} doc
74
+ * @returns {Promise<{doc: T, problems: LinkProblem[]}>}
75
+ */
76
+ export function linkComponentDoc<T>(catalog: DocsCatalog, providerId: string, doc: T): Promise<{
77
+ doc: T;
78
+ problems: LinkProblem[];
79
+ }>;
80
+ /**
81
+ * The provider id a component's doc links resolve against: the CLI's own for
82
+ * a Core component, else its owner package's (or the provider id its manifest
83
+ * declares).
84
+ * @param {string} ownerPackage
85
+ * @param {string} [providerId]
86
+ * @returns {string}
87
+ */
88
+ export function componentLinkProvider(ownerPackage: string, providerId?: string): string;
53
89
  /**
54
90
  * The project's docs tree: the CLI's own docs plus the namespace docs and
55
91
  * placed guides the configured integrations ship (spec:AST-046), built once
@@ -85,6 +121,20 @@ export function docsLinkProblems(catalog: DocsCatalog, tree: DocsTree, { owner,
85
121
  owner?: string;
86
122
  references?: boolean;
87
123
  }): Promise<string[]>;
124
+ /**
125
+ * What \`astryx doctor integration components\` checks of the links in one
126
+ * integration's own component docs (spec:AST-047 FR9): each link in a
127
+ * description, usage, best practice, or prop's or example's description that
128
+ * names no doc. It prints as written, so each is a warning.
129
+ * @param {any} integration a loaded integration
130
+ * @param {Parameters<typeof packageCatalog>[1]} discovered the package's own
131
+ * docs, which its components' links may name; null when it ships none
132
+ * @returns {Promise<Array<{severity: 'warning', message: string}>>}
133
+ */
134
+ export function packageComponentLinkProblems(integration: any, discovered: Parameters<typeof packageCatalog>[1]): Promise<Array<{
135
+ severity: "warning";
136
+ message: string;
137
+ }>>;
88
138
  /**
89
139
  * What \`astryx doctor integration docs\` checks in one integration's docs: the
90
140
  * docs tree they build beside the CLI's (namespaces, placements, routes) and
@@ -320,6 +370,19 @@ export type LinkResolver = import("../../foundation/doc-compiler/links.mjs").Lin
320
370
  export type DocIncluder = import("../../foundation/doc-compiler/links.mjs").DocIncluder;
321
371
  export type DocsTopicEntry = import("../../foundation/discovery/docs-discovery.mjs").DocsTopicEntry;
322
372
  import { DocsCatalog } from '../../foundation/discovery/docs-discovery.mjs';
373
+ /**
374
+ * The catalog one integration package's docs and links read, as doctor checks
375
+ * it before any app configures it: the CLI's topics, Core's and the package's
376
+ * components and templates, and the package's own docs.
377
+ * @param {any} integration
378
+ * @param {{records: import('../../foundation/discovery/docs-discovery.mjs').DocsTopicRecord[], namespaces: import('../../foundation/doc-compiler/tree.mjs').TreeNamespaceInput[], guides: import('../../foundation/doc-compiler/tree.mjs').TreeDocInput[]} | null} discovered
379
+ * @returns {DocsCatalog}
380
+ */
381
+ declare function packageCatalog(integration: any, discovered: {
382
+ records: import("../../foundation/discovery/docs-discovery.mjs").DocsTopicRecord[];
383
+ namespaces: import("../../foundation/doc-compiler/tree.mjs").TreeNamespaceInput[];
384
+ guides: import("../../foundation/doc-compiler/tree.mjs").TreeDocInput[];
385
+ } | null): DocsCatalog;
323
386
  import { AstryxError } from '../error.mjs';
324
387
  import { OVERLAY_LANGUAGES } from '../../foundation/doc-compiler/read.mjs';
325
388
  import { overlayLanguages } from '../../foundation/doc-compiler/read.mjs';
@@ -40,6 +40,7 @@ import {
40
40
  import {sortDiagnostics} from '../../foundation/doc-compiler/diagnostics.mjs';
41
41
  import {
42
42
  linkBlocks,
43
+ linkFields,
43
44
  parseLinkTarget,
44
45
  } from '../../foundation/doc-compiler/links.mjs';
45
46
  import {
@@ -69,6 +70,7 @@ import {
69
70
  import {findCoreDir} from '../../foundation/fs/paths.mjs';
70
71
  import {AstryxError} from '../error.mjs';
71
72
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
73
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
72
74
 
73
75
  export {OVERLAY_LANGUAGES, overlayLanguages};
74
76
 
@@ -264,8 +266,16 @@ function linkTopic(catalog, entry, lang) {
264
266
  problems.push(...linked.problems);
265
267
  sections.push({...section, content: linked.content});
266
268
  }
269
+ // The topic's own text outside its sections, its description and
270
+ // summary, resolves against the topic's own provider.
271
+ const {resolve} = await linkerFor(providerOf(entry));
272
+ const fields = await linkFields(topicTextFields(raw.doc), resolve);
273
+ problems.push(...fields.problems);
267
274
  return {
268
- node: deepFreeze({...raw, doc: {...raw.doc, sections}}),
275
+ node: deepFreeze({
276
+ ...raw,
277
+ doc: {...raw.doc, ...fields.doc, sections},
278
+ }),
269
279
  problems,
270
280
  };
271
281
  })();
@@ -274,6 +284,82 @@ function linkTopic(catalog, entry, lang) {
274
284
  return linked;
275
285
  }
276
286
 
287
+ /**
288
+ * The text fields of a topic outside its sections: its description and
289
+ * summary, those it has.
290
+ * @param {any} doc
291
+ * @returns {{description?: string, summary?: string}}
292
+ */
293
+ function topicTextFields(doc) {
294
+ /** @type {{description?: string, summary?: string}} */
295
+ const fields = {};
296
+ if (typeof doc?.description === 'string')
297
+ fields.description = doc.description;
298
+ if (typeof doc?.summary === 'string') fields.summary = doc.summary;
299
+ return fields;
300
+ }
301
+
302
+ /**
303
+ * One line of a doc's text, such as a topic's or a tree node's summary, with
304
+ * every inline link resolved against the provider that wrote it (spec:AST-047
305
+ * FR9). A link that names no doc prints as written; doctor names it.
306
+ * @param {DocsCatalog} catalog
307
+ * @param {string} providerId the provider id of the doc the text sits in
308
+ * @param {string} text
309
+ * @returns {Promise<string>}
310
+ */
311
+ export async function linkDocText(catalog, providerId, text) {
312
+ if (typeof text !== 'string' || !text.includes('{@link')) return text;
313
+ let provider;
314
+ try {
315
+ provider = normalizeProviderId(providerId);
316
+ } catch {
317
+ return text;
318
+ }
319
+ const linked = await linkFields(
320
+ {description: text},
321
+ await linkResolver(catalog, provider),
322
+ );
323
+ return linked.doc.description ?? text;
324
+ }
325
+
326
+ /**
327
+ * A component doc with every inline link in its text fields resolved
328
+ * (spec:AST-047 FR9): its description, usage, best practices, and each prop's
329
+ * and example's description. Code fields are shown as written. A Core
330
+ * component's links resolve against the CLI's own docs provider; an
331
+ * integration's against that integration's.
332
+ * @template T
333
+ * @param {DocsCatalog} catalog
334
+ * @param {string} providerId the provider id the component's links resolve
335
+ * against
336
+ * @param {T} doc
337
+ * @returns {Promise<{doc: T, problems: LinkProblem[]}>}
338
+ */
339
+ export async function linkComponentDoc(catalog, providerId, doc) {
340
+ if (!JSON.stringify(doc ?? null).includes('{@link')) {
341
+ return {doc, problems: []};
342
+ }
343
+ return linkFields(
344
+ doc,
345
+ await linkResolver(catalog, normalizeProviderId(providerId)),
346
+ );
347
+ }
348
+
349
+ /**
350
+ * The provider id a component's doc links resolve against: the CLI's own for
351
+ * a Core component, else its owner package's (or the provider id its manifest
352
+ * declares).
353
+ * @param {string} ownerPackage
354
+ * @param {string} [providerId]
355
+ * @returns {string}
356
+ */
357
+ export function componentLinkProvider(ownerPackage, providerId) {
358
+ return ownerPackage === CORE_PACKAGE
359
+ ? CLI_PROVIDER_ID
360
+ : normalizeProviderId(providerId ?? ownerPackage);
361
+ }
362
+
277
363
  /** @type {WeakMap<DocsCatalog, Promise<DocsTree>>} */
278
364
  const treesByCatalog = new WeakMap();
279
365
 
@@ -347,12 +433,50 @@ async function buildProjectTree(catalog, fresh) {
347
433
  docs: [...cli.docs, ...added.flatMap(each => each.guides)],
348
434
  topics: await flatTopicInputs(catalog),
349
435
  });
436
+ // A summary is a doc's text too: each link in it reads as the command that
437
+ // opens its doc, wherever the tree's summaries print (spec:AST-047 FR9).
438
+ for (const node of result.nodes.values()) {
439
+ if (typeof node.summary === 'string' && node.summary.includes('{@link')) {
440
+ node.summary = await linkSummary(
441
+ catalog,
442
+ result,
443
+ node.providerId,
444
+ node.summary,
445
+ );
446
+ }
447
+ }
350
448
  return {
351
449
  ...result,
352
450
  diagnostics: sortDiagnostics([...cli.diagnostics, ...result.diagnostics]),
353
451
  };
354
452
  }
355
453
 
454
+ /**
455
+ * One summary with each inline link resolved to the command that opens its
456
+ * doc, against the provider that wrote it. A link that names no doc prints as
457
+ * written; doctor names it where it checks the doc's own fields.
458
+ * @param {DocsCatalog} catalog
459
+ * @param {DocsTree} tree
460
+ * @param {string} providerId
461
+ * @param {string} summary
462
+ * @returns {Promise<string>}
463
+ */
464
+ async function linkSummary(catalog, tree, providerId, summary) {
465
+ if (!summary.includes('{@link')) return summary;
466
+ let provider;
467
+ try {
468
+ provider = normalizeProviderId(providerId);
469
+ } catch {
470
+ return summary;
471
+ }
472
+ const find = docFinderOver(catalog, tree, provider, false);
473
+ const linked = await linkFields({summary}, async target => {
474
+ const found = await find(target);
475
+ return 'problem' in found ? found : found.link;
476
+ });
477
+ return linked.doc.summary;
478
+ }
479
+
356
480
  /** @type {WeakMap<DocsTree, Map<string, TreeNode>>} */
357
481
  const identitiesByTree = new WeakMap();
358
482
 
@@ -430,10 +554,34 @@ async function authoringDoc(catalog, kind, name) {
430
554
  * @returns {Promise<(target: string) => Promise<FoundDoc | {problem: string}>>}
431
555
  */
432
556
  async function docFinder(catalog, fromProvider) {
433
- const identities = identitiesOf(await projectTree(catalog));
557
+ return docFinderOver(catalog, await projectTree(catalog), fromProvider);
558
+ }
559
+
560
+ /**
561
+ * {@link docFinder} over a tree already built, so building the tree can
562
+ * resolve the links in its own summaries.
563
+ * @param {DocsCatalog} catalog
564
+ * @param {DocsTree} tree
565
+ * @param {string} fromProvider
566
+ * @param {boolean} [summaries] resolve the links in a found flat topic's
567
+ * summary; off while a summary is itself being resolved, so two summaries
568
+ * that link each other cannot loop
569
+ * @returns {(target: string) => Promise<FoundDoc | {problem: string}>}
570
+ */
571
+ function docFinderOver(catalog, tree, fromProvider, summaries = true) {
572
+ const identities = identitiesOf(tree);
434
573
  return async target => {
435
574
  const parsed = parseLinkTarget(target);
436
- if ('error' in parsed) return {problem: parsed.error};
575
+ if ('error' in parsed)
576
+ return {
577
+ problem: bareLinkHint(
578
+ parsed.error,
579
+ target,
580
+ catalog,
581
+ identities,
582
+ fromProvider,
583
+ ),
584
+ };
437
585
  let provider;
438
586
  try {
439
587
  provider = normalizeProviderId(parsed.provider ?? fromProvider);
@@ -442,7 +590,9 @@ async function docFinder(catalog, fromProvider) {
442
590
  problem: `"${target}" names "${parsed.provider}", which is not a provider id: an npm package name, or the \`providerId\` its manifest declares`,
443
591
  };
444
592
  }
445
- const node = identities.get(identityKey(provider, parsed.kind, parsed.name));
593
+ const node = identities.get(
594
+ identityKey(provider, parsed.kind, parsed.name),
595
+ );
446
596
  if (node) {
447
597
  return {
448
598
  link: {
@@ -491,6 +641,14 @@ async function docFinder(catalog, fromProvider) {
491
641
  const raw = await lowerRawTopic(catalog, entry);
492
642
  title = raw.doc.title ?? title;
493
643
  summary = raw.doc.description ?? summary;
644
+ if (summaries) {
645
+ summary = await linkSummary(
646
+ catalog,
647
+ tree,
648
+ providerOf(entry),
649
+ summary,
650
+ );
651
+ }
494
652
  } catch {
495
653
  // The topic budget check reports a topic that does not load; the
496
654
  // link still opens it.
@@ -516,8 +674,20 @@ async function docFinder(catalog, fromProvider) {
516
674
  parsed.kind,
517
675
  parsed.name,
518
676
  );
519
- if (link)
677
+ if (link) {
678
+ // The summary is the target doc's own text, so its links resolve
679
+ // against the target's provider, never the linking doc's: a Core
680
+ // component's against the CLI's docs, like its other fields.
681
+ if (summaries && link.summary.includes('{@link')) {
682
+ link.summary = await linkSummary(
683
+ catalog,
684
+ tree,
685
+ provider === CORE_COMPONENT_PROVIDER ? CLI_PROVIDER_ID : provider,
686
+ link.summary,
687
+ );
688
+ }
520
689
  return {link: {target, ...link}, kind: parsed.kind, typed: null};
690
+ }
521
691
  }
522
692
  const searchType =
523
693
  parsed.kind === 'component'
@@ -531,6 +701,54 @@ async function docFinder(catalog, fromProvider) {
531
701
  };
532
702
  }
533
703
 
704
+ /**
705
+ * What a link written as a bare name (`{@link deploying}`) should say
706
+ * instead: the exact target to write when a topic or tree doc has that
707
+ * name, or that none does.
708
+ * @param {string} error the parse error
709
+ * @param {string} target the target as written
710
+ * @param {DocsCatalog} catalog
711
+ * @param {Map<string, any>} identities
712
+ * @param {string} fromProvider
713
+ * @returns {string}
714
+ */
715
+ function bareLinkHint(error, target, catalog, identities, fromProvider) {
716
+ const name = typeof target === 'string' ? target.trim() : '';
717
+ if (!name || name.includes(':') || /\s/.test(name)) return error;
718
+ /** @param {string} provider */
719
+ const normal = provider => {
720
+ try {
721
+ return normalizeProviderId(provider);
722
+ } catch {
723
+ return provider;
724
+ }
725
+ };
726
+ const from = normal(fromProvider);
727
+ /** @param {string} provider @param {string} kind @param {string} named */
728
+ const written = (provider, kind, named) =>
729
+ `{@link ${normal(provider) === from ? '' : `${provider}:`}${kind}:${named}}`;
730
+ const entry = catalog.resolve(name);
731
+ if (entry) {
732
+ return `${error}. "${name}" is a topic: write \`${written(entry.providerId ?? entry.package, 'generic', entry.name)}\`.`;
733
+ }
734
+ const node = [...identities.values()].find(
735
+ each => String(each.name).toLowerCase() === name.toLowerCase(),
736
+ );
737
+ if (node) {
738
+ return `${error}. "${name}" is a ${node.kind === 'generic' ? 'topic' : `${node.kind} doc`}: write \`${written(node.providerId, node.kind, node.name)}\`.`;
739
+ }
740
+ return `${error}, and no topic is named "${name}". Link a doc that exists, as \`{@link generic:<topic>}\` (\`astryx docs\` lists the topics), or remove the link.`;
741
+ }
742
+
743
+ /** The provider Core's components and templates belong to. */
744
+ const CORE_COMPONENT_PROVIDER = (() => {
745
+ try {
746
+ return normalizeProviderId(CORE_PACKAGE);
747
+ } catch {
748
+ return CORE_PACKAGE;
749
+ }
750
+ })();
751
+
534
752
  /** The doc kinds no docs tree holds: components and templates. */
535
753
  const CONTRIBUTED_KINDS = new Set(['component', 'page', 'block']);
536
754
 
@@ -861,7 +1079,7 @@ export async function docsLinkProblems(
861
1079
  for (const problem of found) {
862
1080
  if ((problem.include === true) !== references) continue;
863
1081
  problems.push(
864
- `${where}${problem.section ? ` \u00a7 ${problem.section}` : ''}: ${problem.message}`,
1082
+ `${where}${problem.section ? ` \u00a7 ${problem.section}` : ''}${problem.field ? ` (${problem.field})` : ''}: ${problem.message}`,
865
1083
  );
866
1084
  }
867
1085
  };
@@ -896,6 +1114,83 @@ export async function docsLinkProblems(
896
1114
  return problems;
897
1115
  }
898
1116
 
1117
+ /**
1118
+ * The catalog one integration package's docs and links read, as doctor checks
1119
+ * it before any app configures it: the CLI's topics, Core's and the package's
1120
+ * components and templates, and the package's own docs.
1121
+ * @param {any} integration
1122
+ * @param {{records: import('../../foundation/discovery/docs-discovery.mjs').DocsTopicRecord[], namespaces: import('../../foundation/doc-compiler/tree.mjs').TreeNamespaceInput[], guides: import('../../foundation/doc-compiler/tree.mjs').TreeDocInput[]} | null} discovered
1123
+ * @returns {DocsCatalog}
1124
+ */
1125
+ function packageCatalog(integration, discovered) {
1126
+ const catalog = DocsCatalog.fromBuiltins();
1127
+ catalog.setContributions(() => packageContributions(integration));
1128
+ if (discovered) {
1129
+ for (const record of discovered.records) catalog.add(record);
1130
+ catalog.addTreeInputs({
1131
+ namespaces: discovered.namespaces.map(input => ({...input, rank: 1})),
1132
+ guides: discovered.guides.map(input => ({...input, rank: 1})),
1133
+ });
1134
+ }
1135
+ return catalog;
1136
+ }
1137
+
1138
+ /**
1139
+ * What \`astryx doctor integration components\` checks of the links in one
1140
+ * integration's own component docs (spec:AST-047 FR9): each link in a
1141
+ * description, usage, best practice, or prop's or example's description that
1142
+ * names no doc. It prints as written, so each is a warning.
1143
+ * @param {any} integration a loaded integration
1144
+ * @param {Parameters<typeof packageCatalog>[1]} discovered the package's own
1145
+ * docs, which its components' links may name; null when it ships none
1146
+ * @returns {Promise<Array<{severity: 'warning', message: string}>>}
1147
+ */
1148
+ export async function packageComponentLinkProblems(integration, discovered) {
1149
+ const catalog = packageCatalog(integration, discovered);
1150
+ return (await componentLinkProblems(catalog, integration.name)).map(
1151
+ message => ({severity: /** @type {const} */ ('warning'), message}),
1152
+ );
1153
+ }
1154
+
1155
+ /**
1156
+ * Each link in a package's own component docs that names no doc. A family doc
1157
+ * that documents several components is read once.
1158
+ * @param {DocsCatalog} catalog
1159
+ * @param {string} owner the package whose component docs are read
1160
+ * @returns {Promise<string[]>}
1161
+ */
1162
+ async function componentLinkProblems(catalog, owner) {
1163
+ const contributions = await catalog.contributions();
1164
+ /** @type {string[]} */
1165
+ const problems = [];
1166
+ const seen = new Set();
1167
+ for (const record of contributions?.components ?? []) {
1168
+ if (record.package !== owner || !record.docPath) continue;
1169
+ if (seen.has(record.docPath)) continue;
1170
+ seen.add(record.docPath);
1171
+ /** @type {any} */
1172
+ let doc;
1173
+ try {
1174
+ doc = await loadComponentDoc(record.docPath);
1175
+ } catch {
1176
+ // The components check reports a doc that does not load.
1177
+ continue;
1178
+ }
1179
+ const linked = await linkComponentDoc(
1180
+ catalog,
1181
+ componentLinkProvider(record.package, record.providerId),
1182
+ doc,
1183
+ );
1184
+ const name = typeof doc?.name === 'string' ? doc.name : record.name;
1185
+ for (const problem of linked.problems) {
1186
+ problems.push(
1187
+ `component ${name}${problem.field ? ` (${problem.field})` : ''}: ${problem.message}`,
1188
+ );
1189
+ }
1190
+ }
1191
+ return problems;
1192
+ }
1193
+
899
1194
  /**
900
1195
  * What \`astryx doctor integration docs\` checks in one integration's docs: the
901
1196
  * docs tree they build beside the CLI's (namespaces, placements, routes) and
@@ -907,13 +1202,7 @@ export async function docsLinkProblems(
907
1202
  * @returns {Promise<Array<{severity: 'error' | 'warning', message: string}>>}
908
1203
  */
909
1204
  export async function packageDocsProblems(integration, discovered) {
910
- const catalog = DocsCatalog.fromBuiltins();
911
- catalog.setContributions(() => packageContributions(integration));
912
- for (const record of discovered.records) catalog.add(record);
913
- catalog.addTreeInputs({
914
- namespaces: discovered.namespaces.map(input => ({...input, rank: 1})),
915
- guides: discovered.guides.map(input => ({...input, rank: 1})),
916
- });
1205
+ const catalog = packageCatalog(integration, discovered);
917
1206
  const tree = await projectTree(catalog);
918
1207
  /** @type {Array<{severity: 'error' | 'warning', message: string}>} */
919
1208
  const problems = tree.diagnostics
@@ -1136,7 +1425,8 @@ export async function topicLinks(catalog, entry) {
1136
1425
  const tree = await projectTree(catalog);
1137
1426
  const node = tree.get(entry.tree ? (entry.route ?? entry.name) : entry.name);
1138
1427
  const placed =
1139
- node && (entry.tree ? node.kind === 'generic' : node.ref?.flatTopic === entry.name);
1428
+ node &&
1429
+ (entry.tree ? node.kind === 'generic' : node.ref?.flatTopic === entry.name);
1140
1430
  return placed ? placeLinks(tree, node) : {up: topicUp(entry)};
1141
1431
  }
1142
1432
 
@@ -1159,7 +1449,8 @@ export async function resolveDocsArgument(topic, {cwd} = {}) {
1159
1449
  const tree = await projectTree(catalog);
1160
1450
  const owner = nameOwner(tree, catalog, topic);
1161
1451
  if (owner == null) return {kind: 'unknown', catalog};
1162
- if (owner.kind === 'topic') return {kind: 'topic', catalog, entry: owner.entry};
1452
+ if (owner.kind === 'topic')
1453
+ return {kind: 'topic', catalog, entry: owner.entry};
1163
1454
  return treeArgument(catalog, tree, owner.node);
1164
1455
  }
1165
1456
 
@@ -1306,7 +1597,7 @@ export async function unknownTopicError(topic, catalog) {
1306
1597
  export function notLoaded(catalog) {
1307
1598
  const packages = [...new Set(catalog.issues.map(issue => issue.package))];
1308
1599
  if (packages.length === 0) return '';
1309
- return `. The docs of ${packages.join(', ')} did not load; run \`astryx doctor integration docs\` in that package to see why.`;
1600
+ return `. The docs of ${packages.join(', ')} did not load; run \`${formatCliCommand('doctor integration docs')}\` in that package to see why.`;
1310
1601
  }
1311
1602
 
1312
1603
  /**
@@ -1324,7 +1615,7 @@ export async function resolveTopicDocs(topic, options = {}) {
1324
1615
  if (found.kind !== 'topic') {
1325
1616
  throw found.kind === 'node'
1326
1617
  ? new AstryxError(
1327
- `"${found.node.route}" is a ${found.node.kind === 'namespace' ? 'namespace' : `${found.node.kind} doc`} in the docs tree, not a topic. Read it with \`astryx docs ${found.node.route}\`.`,
1618
+ `"${found.node.route}" is a ${found.node.kind === 'namespace' ? 'namespace' : `${found.node.kind} doc`} in the docs tree, not a topic. Read it with \`${formatCliCommand(`docs ${found.node.route}`)}\`.`,
1328
1619
  undefined,
1329
1620
  ERROR_CODES.ERR_UNKNOWN_TOPIC,
1330
1621
  )
@@ -1359,7 +1650,10 @@ export async function integrationDocTypes(integration, cwd) {
1359
1650
  if (report.status !== 'checked' || unread.length === 0) return report;
1360
1651
  // A root its reader cannot read serves no doc; say so rather than skip it.
1361
1652
  const rel = (/** @type {string} */ file) =>
1362
- path.relative(packageDir ?? cwd, file).split(path.sep).join('/') || '.';
1653
+ path
1654
+ .relative(packageDir ?? cwd, file)
1655
+ .split(path.sep)
1656
+ .join('/') || '.';
1363
1657
  return {
1364
1658
  ...report,
1365
1659
  unchecked: [
@@ -34,7 +34,8 @@ export const doc = {
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>',
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(['cli', 'global', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography', 'unorganized']);
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
 
@@ -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
  });
@@ -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;
@@ -276,9 +276,7 @@ describe('a reference block in a topic section', () => {
276
276
  expect(status).toBe(0);
277
277
  expect(stdout).toMatch(/^Field +\| Type +\| Required +\| Description/m);
278
278
  expect(stdout).toMatch(/^components +\| string +\| no +\| /m);
279
- expect(stdout).toContain(
280
- 'From Astryx Integration: `astryx docs authoring integration`',
281
- );
279
+ expect(stdout).toContain(' docs authoring integration`');
282
280
  },
283
281
  SLOW,
284
282
  );