@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
@@ -0,0 +1,53 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Where a runner may stand in front of an Astryx command in Astryx's own
5
+ * docs. Docs write commands bare (`astryx <command>`): the CLI prefixes each
6
+ * one with the reader's command when it prints a doc, and the docsite with
7
+ * `npx @astryxdesign/cli`. A few files show a runner on purpose, and some files
8
+ * are not docs at all. The rules, checked by test/runner-commands.test.mjs:
9
+ *
10
+ * - npx (or another download runner) with the unscoped name `astryx` is never
11
+ * written outside `skip`: it fetches an unrelated npm package.
12
+ * - In a doc (`*.doc.mjs`, and Core's docs.mjs), no runner precedes an Astryx
13
+ * command, except in `runnerExamples`, where `npx @astryxdesign/cli …` and a
14
+ * project's runner may (still never the unscoped name through npx).
15
+ *
16
+ * TODO(doctor-runner-check): the Doctor lane's integration-docs runner check
17
+ * (foundation/discovery/runner-commands.mjs) becomes the single rule; then the
18
+ * repo test runs that check over Core's and the CLI's own docs with this
19
+ * allowlist.
20
+ *
21
+ * @input nothing
22
+ * @output the allowlist
23
+ * @position packages/cli/foundation/discovery — data shared by the repo test
24
+ * and the Doctor runner check
25
+ */
26
+
27
+ export const RUNNER_COMMAND_ALLOWLIST = Object.freeze({
28
+ /** Files never scanned: release notes, tests, and the helpers that build runner forms. */
29
+ skip: Object.freeze([
30
+ /(^|\/)CHANGELOG\.md$/u,
31
+ /\.test\.[cm]?[jt]sx?$/u,
32
+ /(^|\/)__tests__\//u,
33
+ /^packages\/cli\/test\//u,
34
+ /^packages\/cli\/foundation\/env\/package-manager\.mjs$/u,
35
+ ]),
36
+ /** Docs that show a runner on purpose, and why. */
37
+ runnerExamples: Object.freeze({
38
+ 'packages/core/docs.mjs':
39
+ "Core's setup banner, for a project that has no CLI installed yet",
40
+ 'packages/cli/assets/docs/tree/updates.doc.mjs':
41
+ "quotes the CLI's own update notice, which names the project's runner",
42
+ 'packages/cli/assets/docs/tree/cli-command.doc.mjs':
43
+ 'explains how printed commands start, the pinned `npx @astryxdesign/cli@<version>` among them',
44
+ 'packages/cli/assets/docs/tree/who-answers.doc.mjs':
45
+ 'explains how printed commands start, the pinned `npx @astryxdesign/cli@<version>` among them',
46
+ 'packages/cli/assets/docs/tree/project-global-or-both.doc.mjs':
47
+ 'compares running the CLI with npx to installing it, and is found by searching for that command',
48
+ 'packages/cli/assets/docs/tree/install-once.doc.mjs':
49
+ 'names a pinned release, `npx @astryxdesign/cli@<version>`, which answers as that version',
50
+ 'packages/cli/clients/cli/commands/upgrade.doc.mjs':
51
+ 'quotes the command upgrade prints when the CLI is older than Core, pinned to the matching release',
52
+ }),
53
+ });
@@ -0,0 +1,52 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * The strings of a doc the CLI resolves links in (spec:AST-047 FR9). In a
6
+ * topic: its description and summary, then the text of prose and heading
7
+ * blocks, list items, and table cells in each section's content, with the
8
+ * section's title. In a component doc (any doc with no sections): every text
9
+ * field, such as its description, usage, best practices, and each prop's and
10
+ * example's description, with the field's path. Code is never read.
11
+ *
12
+ * @param {unknown} doc an authored doc object
13
+ * @returns {{text: string, section: string | null, field: string | null}[]}
14
+ */
15
+ export function linkableStrings(doc: unknown): {
16
+ text: string;
17
+ section: string | null;
18
+ field: string | null;
19
+ }[];
20
+ /**
21
+ * Every pointer span in one prose string, in order.
22
+ * @param {string} text
23
+ * @returns {string[]} the doc name each one points at
24
+ */
25
+ export function pointersIn(text: string): string[];
26
+ /**
27
+ * Each stray pointer in a package's topics and component docs.
28
+ *
29
+ * @param {{records: {name: string, path: string}[], guides?: {name: string, ref?: {topicFile?: string}}[], namespaces?: {doc?: {name?: string}}[], components?: {name: string, file: string}[]}} discovered
30
+ * @returns {Promise<import('../../api/integration/authoring-checks.type.mjs').StrayPointer[]>}
31
+ */
32
+ export function findStrayPointers(discovered: {
33
+ records: {
34
+ name: string;
35
+ path: string;
36
+ }[];
37
+ guides?: {
38
+ name: string;
39
+ ref?: {
40
+ topicFile?: string;
41
+ };
42
+ }[];
43
+ namespaces?: {
44
+ doc?: {
45
+ name?: string;
46
+ };
47
+ }[];
48
+ components?: {
49
+ name: string;
50
+ file: string;
51
+ }[];
52
+ }): Promise<import("../../api/integration/authoring-checks.type.mjs").StrayPointer[]>;
@@ -0,0 +1,293 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Stray doc pointers (architecture:cli-surface DEC-8): a code span in
5
+ * prose that is exactly `astryx docs <name>` for a doc that exists. The doc's
6
+ * `{@link}` prints the command that opens the doc and is checked by doctor's
7
+ * link check, so a written command is a pointer nothing checks.
8
+ *
9
+ * @input the docs a package ships, as discoverIntegrationDocs returns them
10
+ * @output each stray pointer, with the link that replaces it
11
+ * @position foundation/discovery, called through api/integration/_adapter.mjs
12
+ */
13
+
14
+ import fs from 'node:fs';
15
+
16
+ import {textFields} from '../doc-compiler/links.mjs';
17
+ import {builtinGuideFiles} from './docs-discovery.mjs';
18
+ import {
19
+ fileWords,
20
+ lineAtOffset,
21
+ loadQuietly,
22
+ locateWords,
23
+ textWords,
24
+ } from './copied-passages.mjs';
25
+
26
+ /**
27
+ * A code span that is exactly the command opening one doc. A command with
28
+ * more words, a flag, or a route is a walkthrough, not a pointer. A name holds
29
+ * what a topic name may (letters, digits, `_` and `-`), never opening with `-`.
30
+ */
31
+ const POINTER = /`astryx docs ([A-Za-z0-9_][A-Za-z0-9_-]*)`/g;
32
+
33
+ /** @type {Promise<Map<string, string>> | undefined} */
34
+ let coreKinds;
35
+
36
+ /**
37
+ * The CLI's own docs by name, each with the kind a link names it by: a
38
+ * namespace doc as `namespace`, a topic or guide as `generic`.
39
+ * @returns {Promise<Map<string, string>>}
40
+ */
41
+ function loadCoreKinds() {
42
+ coreKinds ??= (async () => {
43
+ const kinds = new Map();
44
+ for (const file of builtinGuideFiles()) {
45
+ const doc = await loadQuietly(file);
46
+ if (typeof doc?.name === 'string') {
47
+ kinds.set(doc.name, doc.type === 'namespace' ? 'namespace' : 'generic');
48
+ }
49
+ }
50
+ return kinds;
51
+ })();
52
+ return coreKinds;
53
+ }
54
+
55
+ /**
56
+ * The strings of a doc the CLI resolves links in (spec:AST-047 FR9). In a
57
+ * topic: its description and summary, then the text of prose and heading
58
+ * blocks, list items, and table cells in each section's content, with the
59
+ * section's title. In a component doc (any doc with no sections): every text
60
+ * field, such as its description, usage, best practices, and each prop's and
61
+ * example's description, with the field's path. Code is never read.
62
+ *
63
+ * @param {unknown} doc an authored doc object
64
+ * @returns {{text: string, section: string | null, field: string | null}[]}
65
+ */
66
+ export function linkableStrings(doc) {
67
+ /** @type {{text: string, section: string | null, field: string | null}[]} */
68
+ const strings = [];
69
+ if (doc == null || typeof doc !== 'object') return strings;
70
+ const top = /** @type {Record<string, any>} */ (doc);
71
+ if (!Array.isArray(top.sections)) {
72
+ for (const {field, text} of textFields(doc)) {
73
+ strings.push({text, section: null, field});
74
+ }
75
+ return strings;
76
+ }
77
+ for (const field of ['description', 'summary']) {
78
+ if (typeof top[field] === 'string') {
79
+ strings.push({text: top[field], section: null, field});
80
+ }
81
+ }
82
+ /**
83
+ * @param {unknown} value
84
+ * @param {string | null} section
85
+ */
86
+ const walk = (value, section) => {
87
+ if (Array.isArray(value)) {
88
+ for (const item of value) walk(item, section);
89
+ return;
90
+ }
91
+ if (value == null || typeof value !== 'object') return;
92
+ const record = /** @type {Record<string, any>} */ (value);
93
+ const title = typeof record.title === 'string' ? record.title : section;
94
+ if (Array.isArray(record.sections)) walk(record.sections, section);
95
+ if (!Array.isArray(record.content)) return;
96
+ for (const block of record.content) {
97
+ const add = (/** @type {unknown} */ text) => {
98
+ if (typeof text === 'string') {
99
+ strings.push({text, section: title, field: null});
100
+ }
101
+ };
102
+ switch (block?.type) {
103
+ case 'prose':
104
+ case 'heading':
105
+ add(block.text);
106
+ break;
107
+ case 'list':
108
+ (block.items ?? []).forEach(add);
109
+ break;
110
+ case 'table':
111
+ (block.headers ?? []).forEach(add);
112
+ for (const row of block.rows ?? []) row.forEach(add);
113
+ break;
114
+ default:
115
+ walk(block, title);
116
+ }
117
+ }
118
+ };
119
+ walk(doc, null);
120
+ return strings;
121
+ }
122
+
123
+ /**
124
+ * Every pointer span in one prose string, in order.
125
+ * @param {string} text
126
+ * @returns {string[]} the doc name each one points at
127
+ */
128
+ export function pointersIn(text) {
129
+ return [...text.matchAll(POINTER)].map(match => match[1]);
130
+ }
131
+
132
+ /**
133
+ * Where a string's words start among a file's words, from `from` on. A
134
+ * one-line string the file holds as a quoted literal is found at that
135
+ * literal, so a list item that is only `astryx docs theme` is not placed at a
136
+ * summary or code block that writes the same words.
137
+ *
138
+ * @param {string[]} lines the file's lines
139
+ * @param {{word: string, line: number}[]} file the file's words
140
+ * @param {string} text
141
+ * @param {{word: string}[]} words the string's words
142
+ * @param {number} from
143
+ * @returns {number}
144
+ */
145
+ function locateString(lines, file, text, words, from) {
146
+ /** @type {number[]} */
147
+ const starts = [];
148
+ for (let at = locateWords(file, words); at >= 0;) {
149
+ starts.push(at);
150
+ at = locateWords(file, words, at + 1);
151
+ }
152
+ if (starts.length === 0) return -1;
153
+ const literals = text.includes('\n')
154
+ ? []
155
+ : [`'${text}'`, `"${text}"`, `'${text.replace(/'/g, "\\'")}'`];
156
+ const quoted = starts.filter(at =>
157
+ literals.some(literal => lines[file[at].line - 1]?.includes(literal)),
158
+ );
159
+ const pool = quoted.length > 0 ? quoted : starts;
160
+ return pool.find(at => at >= from) ?? pool[0];
161
+ }
162
+
163
+ /**
164
+ * Each stray pointer in a package's topics and component docs.
165
+ *
166
+ * @param {{records: {name: string, path: string}[], guides?: {name: string, ref?: {topicFile?: string}}[], namespaces?: {doc?: {name?: string}}[], components?: {name: string, file: string}[]}} discovered
167
+ * @returns {Promise<import('../../api/integration/authoring-checks.type.mjs').StrayPointer[]>}
168
+ */
169
+ export async function findStrayPointers(discovered) {
170
+ /** @type {{name: string, file: string | undefined, kind: 'topic' | 'component'}[]} */
171
+ const topics = [
172
+ ...discovered.records.map(record => ({
173
+ name: record.name,
174
+ file: record.path,
175
+ kind: /** @type {const} */ ('topic'),
176
+ })),
177
+ ...(discovered.guides ?? []).map(guide => ({
178
+ name: guide.name,
179
+ file: guide.ref?.topicFile,
180
+ kind: /** @type {const} */ ('topic'),
181
+ })),
182
+ ];
183
+ /** @type {Map<string, string>} */
184
+ const own = new Map(topics.map(topic => [topic.name, 'generic']));
185
+ for (const namespace of discovered.namespaces ?? []) {
186
+ const name = namespace?.doc?.name;
187
+ if (typeof name === 'string' && !own.has(name)) own.set(name, 'namespace');
188
+ }
189
+ for (const component of discovered.components ?? []) {
190
+ topics.push({
191
+ name: component.name,
192
+ file: component.file,
193
+ kind: 'component',
194
+ });
195
+ }
196
+ const core = await loadCoreKinds();
197
+ // A topic that extends another has no route of its own: a link to it names
198
+ // the page it shows on, the topic it extends.
199
+ /** @type {Map<string, string>} */
200
+ const extendsOf = new Map();
201
+ for (const topic of topics) {
202
+ if (!topic.file) continue;
203
+ const doc = /** @type {any} */ (await loadQuietly(topic.file));
204
+ if (typeof doc?.extends === 'string')
205
+ extendsOf.set(topic.name, doc.extends);
206
+ }
207
+ /** @param {string} target */
208
+ const linkFor = target => {
209
+ const page = extendsOf.get(target);
210
+ if (page != null) {
211
+ if (own.has(page) && !extendsOf.has(page)) {
212
+ return `{@link ${own.get(page)}:${page}}`;
213
+ }
214
+ return core.has(page)
215
+ ? `{@link @astryxdesign/cli:${core.get(page)}:${page}}`
216
+ : null;
217
+ }
218
+ return own.has(target)
219
+ ? `{@link ${own.get(target)}:${target}}`
220
+ : core.has(target)
221
+ ? `{@link @astryxdesign/cli:${core.get(target)}:${target}}`
222
+ : null;
223
+ };
224
+ /** @type {import('../../api/integration/authoring-checks.type.mjs').StrayPointer[]} */
225
+ const found = [];
226
+ for (const topic of topics) {
227
+ if (!topic.file) continue;
228
+ const doc = await loadQuietly(topic.file);
229
+ if (!doc) continue;
230
+ /** @type {{word: string, line: number}[]} */
231
+ let source = [];
232
+ /** @type {string[]} */
233
+ let lines = [];
234
+ try {
235
+ const raw = fs.readFileSync(topic.file, 'utf8');
236
+ source = fileWords(raw);
237
+ lines = raw.split('\n');
238
+ } catch {
239
+ // No line numbers; the finding still names the section.
240
+ }
241
+ // A component doc is named by its own name: a family doc by the family.
242
+ const name =
243
+ topic.kind === 'component' && typeof doc.name === 'string'
244
+ ? doc.name
245
+ : topic.name;
246
+ const label =
247
+ topic.kind === 'component' ? `component "${name}"` : `"${name}"`;
248
+ // Each string is found by its whole run of words, from where the last
249
+ // one was found, so two strings that open alike keep their own lines.
250
+ let cursor = 0;
251
+ for (const {text, section, field} of linkableStrings(doc)) {
252
+ const words = textWords(text);
253
+ const index = locateString(lines, source, text, words, cursor);
254
+ if (index >= 0) cursor = index + words.length;
255
+ for (const match of text.matchAll(POINTER)) {
256
+ const target = match[1];
257
+ const link = linkFor(target);
258
+ if (!link) continue;
259
+ const command = `astryx docs ${target}`;
260
+ const line =
261
+ index < 0
262
+ ? null
263
+ : lineAtOffset(
264
+ source,
265
+ index,
266
+ words,
267
+ /** @type {number} */ (match.index) + 1,
268
+ );
269
+ const where = [
270
+ section ? `section "${section}"` : null,
271
+ field ? `field ${field}` : null,
272
+ line == null ? null : `line ${line}`,
273
+ ]
274
+ .filter(Boolean)
275
+ .join(', ');
276
+ found.push({
277
+ topic: name,
278
+ kind: topic.kind,
279
+ section,
280
+ field,
281
+ file: topic.file,
282
+ line,
283
+ pointer: command,
284
+ link,
285
+ message:
286
+ `${label}${where ? ` (${where})` : ''} points at a doc with the written command \`${command}\`. ` +
287
+ `Replace \`${command}\`, code ticks included, with ${link}: the CLI prints the command that opens the doc, and doctor checks the link.`,
288
+ });
289
+ }
290
+ }
291
+ }
292
+ return found;
293
+ }
@@ -0,0 +1,86 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+
5
+ import {linkableStrings, pointersIn} from './stray-pointers.mjs';
6
+
7
+ describe('pointersIn', () => {
8
+ it('finds a code span that is exactly the command opening one doc', () => {
9
+ expect(
10
+ pointersIn(
11
+ 'Read `astryx docs theme`, then `astryx docs layout-spacing`.',
12
+ ),
13
+ ).toEqual(['theme', 'layout-spacing']);
14
+ });
15
+
16
+ it('leaves a walkthrough alone: more words, a flag, or a route', () => {
17
+ expect(
18
+ pointersIn(
19
+ 'Run `astryx docs theme overview`, `astryx docs --json`, `astryx docs cli/integrations`, or `astryx docs`.',
20
+ ),
21
+ ).toEqual([]);
22
+ });
23
+
24
+ it('leaves the bare name and a runner-written command alone', () => {
25
+ expect(
26
+ pointersIn('See astryx docs theme, or `pnpm astryx docs theme`.'),
27
+ ).toEqual([]);
28
+ });
29
+ });
30
+
31
+ describe('linkableStrings', () => {
32
+ it("reads a topic's description and summary, then prose, headings, list items and table cells, not code", () => {
33
+ const strings = linkableStrings({
34
+ name: 'acme',
35
+ description: 'Read `astryx docs theme`.',
36
+ summary: 'In short.',
37
+ sections: [
38
+ {
39
+ title: 'Use it',
40
+ content: [
41
+ {type: 'prose', text: 'prose'},
42
+ {type: 'heading', level: 3, text: 'heading'},
43
+ {type: 'list', style: 'unordered', items: ['item']},
44
+ {type: 'table', headers: ['head'], rows: [['cell']]},
45
+ {type: 'code', lang: 'bash', code: 'astryx docs theme'},
46
+ ],
47
+ },
48
+ ],
49
+ });
50
+ expect(strings).toEqual([
51
+ {text: 'Read `astryx docs theme`.', section: null, field: 'description'},
52
+ {text: 'In short.', section: null, field: 'summary'},
53
+ {text: 'prose', section: 'Use it', field: null},
54
+ {text: 'heading', section: 'Use it', field: null},
55
+ {text: 'item', section: 'Use it', field: null},
56
+ {text: 'head', section: 'Use it', field: null},
57
+ {text: 'cell', section: 'Use it', field: null},
58
+ ]);
59
+ });
60
+
61
+ it("reads a component doc's text fields, not its names, types, defaults, or code", () => {
62
+ const strings = linkableStrings({
63
+ type: 'component',
64
+ name: 'AcmeButton',
65
+ displayName: 'Acme Button',
66
+ usage: {
67
+ description: 'usage',
68
+ bestPractices: [{guidance: true, description: 'practice'}],
69
+ },
70
+ props: [
71
+ {name: 'tone', type: 'string', default: "'a'", description: 'prop'},
72
+ ],
73
+ examples: [{label: 'example', code: 'astryx docs theme'}],
74
+ });
75
+ expect(strings).toEqual([
76
+ {text: 'usage', section: null, field: 'usage.description'},
77
+ {
78
+ text: 'practice',
79
+ section: null,
80
+ field: 'usage.bestPractices[0].description',
81
+ },
82
+ {text: 'prop', section: null, field: 'props[0].description'},
83
+ {text: 'example', section: null, field: 'examples[0].label'},
84
+ ]);
85
+ });
86
+ });
@@ -20,7 +20,10 @@ import * as path from 'node:path';
20
20
  import module from 'node:module';
21
21
  import {CLI_ROOT} from '../fs/paths.mjs';
22
22
  import {detectStylingSystem} from '../agent-docs/agent-docs.mjs';
23
- import {decidePackageManagerIn} from '../env/package-manager.mjs';
23
+ import {
24
+ decidePackageManagerIn,
25
+ formatCliCommand,
26
+ } from '../env/package-manager.mjs';
24
27
 
25
28
  // ── Known packages that a template may import without the user installing them.
26
29
  // react and react-dom are the framework; @astryxdesign/* is the design system
@@ -230,7 +233,7 @@ export function analyzeTemplateNeeds(source, cwd) {
230
233
  }
231
234
  if (stylexCompilerNeeded) {
232
235
  notes.push(
233
- 'This template uses StyleX. Your project needs a StyleX compiler plugin \u2014 see `astryx docs styling-overview` for setup steps.',
236
+ `This template uses StyleX. Your project needs a StyleX compiler plugin \u2014 see \`${formatCliCommand('docs styling-overview')}\` for setup steps.`,
234
237
  );
235
238
  }
236
239
 
@@ -19,6 +19,7 @@ import {moduleExportsName} from './module-exports.mjs';
19
19
  import {inspectPackageExport} from './package-exports.mjs';
20
20
  import {themeImportPackage} from './theme-discovery.mjs';
21
21
  import {isLocalThemeOwner, projectPath} from '../config/theme-state.mjs';
22
+ import {formatCliCommand} from '../env/package-manager.mjs';
22
23
 
23
24
  export class ThemeImportError extends Error {}
24
25
 
@@ -59,7 +60,7 @@ function resolveLocalTheme(theme, cwd) {
59
60
  path.relative(cwd, path.join(theme.sourceDir, theme.entry)),
60
61
  );
61
62
  throw new ThemeImportError(
62
- `Local theme "${theme.slug}" is not built. Run \`astryx theme build ${source}\` and try again. Missing: ${missing
63
+ `Local theme "${theme.slug}" is not built. Run \`${formatCliCommand(`theme build ${source}`, cwd)}\` and try again. Missing: ${missing
63
64
  .map(file => projectPath(path.relative(cwd, file)))
64
65
  .join(', ')}.`,
65
66
  );
@@ -68,8 +69,11 @@ function resolveLocalTheme(theme, cwd) {
68
69
  throw new ThemeImportError(
69
70
  `Local theme "${theme.slug}" built module ${projectPath(
70
71
  path.relative(cwd, moduleFile),
71
- )} does not export "${theme.exportName}". Rebuild it with \`astryx theme build ${projectPath(
72
- path.relative(cwd, path.join(theme.sourceDir, theme.entry)),
72
+ )} does not export "${theme.exportName}". Rebuild it with \`${formatCliCommand(
73
+ `theme build ${projectPath(
74
+ path.relative(cwd, path.join(theme.sourceDir, theme.entry)),
75
+ )}`,
76
+ cwd,
73
77
  )}\`.`,
74
78
  );
75
79
  }
@@ -130,7 +134,7 @@ function resolvePackageTheme(theme, cwd, ownerThemeCount) {
130
134
  findInstalledPackage(cwd, importPackage);
131
135
  if (!packageDir) {
132
136
  throw new ThemeImportError(
133
- `Theme package "${importPackage}" is not installed. Run \`npm install ${importPackage}\` (or yarn/pnpm/bun), then run \`astryx theme add ${theme.slug}\`.`,
137
+ `Theme package "${importPackage}" is not installed. Run \`npm install ${importPackage}\` (or yarn/pnpm/bun), then run \`${formatCliCommand(`theme add ${theme.slug}`, cwd)}\`.`,
134
138
  );
135
139
  }
136
140
  const pkg = readPackage(path.join(packageDir, 'package.json'));
@@ -148,7 +148,7 @@ describe('resolveThemeImports', () => {
148
148
  });
149
149
 
150
150
  expect(() => resolveThemeImports(theme, {cwd: dir})).toThrow(
151
- /astryx theme build src\/themes\/ocean\/oceanTheme\.ts/i,
151
+ / theme build src\/themes\/ocean\/oceanTheme\.ts`/i,
152
152
  );
153
153
  fs.writeFileSync(
154
154
  path.join(sourceDir, 'ocean.js'),
@@ -46,7 +46,7 @@ export function typeTextTooOld(ts) {
46
46
  const [major, minor] = String(ts.version).split('.').map(Number);
47
47
  return major > 4 || (major === 4 && minor >= 8)
48
48
  ? null
49
- : `TypeScript ${ts.version} is older than 4.8, the oldest the type comparison reads`;
49
+ : `TypeScript ${ts.version} is older than 4.8, the oldest the type comparison reads; install TypeScript 5.0 through 6 (\`npm install -D typescript@6\`), or on TypeScript 7 add \`@typescript/typescript6\`, to judge them`;
50
50
  }
51
51
 
52
52
  /** How tightly a printed type binds: a slot needs at least its level. */
@@ -176,7 +176,7 @@ describe('normalizeTypeText', () => {
176
176
  'string[]',
177
177
  ]);
178
178
  expect(typeTextTooOld({version: '4.7.4'})).toBe(
179
- 'TypeScript 4.7.4 is older than 4.8, the oldest the type comparison reads',
179
+ 'TypeScript 4.7.4 is older than 4.8, the oldest the type comparison reads; install TypeScript 5.0 through 6 (`npm install -D typescript@6`), or on TypeScript 7 add `@typescript/typescript6`, to judge them',
180
180
  );
181
181
  for (const version of ['4.8.4', '5.0.4', '6.0.3', ts.version]) {
182
182
  expect(typeTextTooOld({version})).toBeNull();
@@ -248,17 +248,41 @@ const RUNNERS = {
248
248
  runs: 'astryx.config, through the config parser',
249
249
  sites: ['loadModuleWithParser(..., parseConfig)'],
250
250
  },
251
+ 'foundation/fs/file-protection.mjs': {
252
+ runs: 'the ignore matcher (CommonJS), loaded when a resolver first reads an ignore file',
253
+ sites: ['require(ignore)'],
254
+ },
251
255
  'foundation/discovery/component-discovery.mjs': {
252
256
  runs: '@babel/parser, on first use, to read the members a family doc lists in its components without running the doc',
253
257
  sites: ['require(@babel/parser)'],
254
258
  },
259
+ 'foundation/discovery/copied-passages.mjs': {
260
+ runs: "the CLI's own guides and the package's topics, to compare their prose for passages two topics repeat",
261
+ sites: ['builtinGuideFiles', 'loadTopicModule'],
262
+ },
263
+ 'foundation/discovery/doc-consistency.mjs': {
264
+ runs: "a package's component docs and topics, to read the props, overlays, sections, and replaces/extends they declare",
265
+ sites: ['importDocModule ×2'],
266
+ },
267
+ 'foundation/discovery/doc-fluff.mjs': {
268
+ runs: "the CLI's own guides, to measure the median share of content words a topic's density is compared with",
269
+ sites: ['builtinGuideFiles'],
270
+ },
255
271
  'foundation/discovery/docs-discovery.mjs': {
256
272
  runs: 'a contributed topic, for its catalog fields: name, title, description, category, and relationships',
257
273
  sites: ['importDocModule'],
258
274
  },
275
+ 'foundation/discovery/stray-pointers.mjs': {
276
+ runs: "the CLI's own guides, for their names, to tell which written `astryx docs <name>` points at a doc that exists",
277
+ sites: ['builtinGuideFiles'],
278
+ },
259
279
  'foundation/discovery/project-typescript.mjs': {
260
- runs: "the project's own typescript, for the author checks that read source and docs with it, and its package.json for the version of one they cannot use",
261
- sites: ['require(typescript)', 'require(typescript/package.json)'],
280
+ runs: "the project's own typescript, for the author checks that read source and docs with it, and its package.json for the version of one they cannot use; beside TypeScript 7, which has no compiler API, the TypeScript 6 API package @typescript/typescript6",
281
+ sites: [
282
+ 'require(<computed>)',
283
+ 'require(typescript)',
284
+ 'require(typescript/package.json)',
285
+ ],
262
286
  },
263
287
  'foundation/discovery/template-adapter.mjs': {
264
288
  runs: '@babel/parser, to find the fixture references and page-local bindings in template source; and a template doc that does not validate, to read the replacement it declares',
@@ -299,6 +323,22 @@ const RUNNERS = {
299
323
  runs: "each installed integration's manifest",
300
324
  sites: ['importUserModule'],
301
325
  },
326
+ 'foundation/release/cache.mjs': {
327
+ runs: 'npm (under npm-guard.mjs), to install and look up CLI releases in the per-user cache; each installed release once, to check it starts and reports its version; and ps (tasklist on Windows), to confirm the process a stale lock records is node or npm before ending it',
328
+ sites: ['child_process.spawnSync ×5'],
329
+ },
330
+ 'foundation/release/npm-guard.mjs': {
331
+ runs: 'npm, in a process group of its own that it ends at the time limit, on Ctrl-C, or when the run that started it goes away',
332
+ sites: ['child_process.spawn'],
333
+ },
334
+ 'foundation/release/global-state.mjs': {
335
+ runs: "the background check of the registry's `latest` release, the agent-text step, and the step that installs the global copy's own Core into the release cache, each detached",
336
+ sites: ['child_process.spawn'],
337
+ },
338
+ 'foundation/release/handoff.mjs': {
339
+ runs: "the CLI release that answers a project's run, when it is not this copy",
340
+ sites: ['child_process.spawn'],
341
+ },
302
342
  'scripts/generate-cli-readme.mjs': {
303
343
  runs: '`astryx manifest` and the error-code and response-type docs, to write the README tables (build time, not shipped)',
304
344
  sites: ['child_process.spawnSync', 'import(<computed>)'],
@@ -109,7 +109,10 @@ export async function collectDocInputs(project) {
109
109
  list.add('components', record.name, record.package, record.docPath);
110
110
  }
111
111
 
112
- const coreDir = findCoreDir(project.cwd);
112
+ const coreDir =
113
+ typeof project.coreDir === 'function'
114
+ ? project.coreDir()
115
+ : findCoreDir(project.cwd);
113
116
  if (coreDir != null) {
114
117
  for (const name of Object.values(discoverHooks(coreDir)).flat()) {
115
118
  const file = findHookDoc(coreDir, name);