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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/README.md +104 -71
  2. package/api/build/_adapter.d.mts +58 -0
  3. package/api/build/_adapter.mjs +127 -3
  4. package/api/build/blocks/blocks.d.mts +92 -0
  5. package/api/build/blocks/blocks.mjs +528 -0
  6. package/api/build/blocks/blocks.test.mjs +238 -0
  7. package/api/build/blocks/blocks.weights.json +1 -0
  8. package/api/build/build.mjs +25 -6
  9. package/api/build/build.type.mjs +1 -1
  10. package/api/build/kit/answer.d.mts +18 -0
  11. package/api/build/kit/answer.mjs +195 -0
  12. package/api/build/kit/answer.test.mjs +108 -0
  13. package/api/build/kit/kind.d.mts +25 -0
  14. package/api/build/kit/kind.mjs +170 -0
  15. package/api/build/kit/kit.d.mts +2 -4
  16. package/api/build/kit/kit.mjs +8 -398
  17. package/api/build/kit/rank.d.mts +3 -32
  18. package/api/build/kit/rank.mjs +25 -342
  19. package/api/build/kit/rank.test.mjs +2 -1
  20. package/api/build/kit/signals.d.mts +79 -0
  21. package/api/build/kit/signals.mjs +295 -0
  22. package/api/build/kit/start.d.mts +32 -0
  23. package/api/build/kit/start.mjs +163 -0
  24. package/api/build/kit/words.d.mts +72 -0
  25. package/api/build/kit/words.mjs +202 -0
  26. package/api/build/tree.d.mts +20 -0
  27. package/api/build/tree.mjs +53 -0
  28. package/api/build/tree.test.mjs +185 -0
  29. package/api/build/tree.weights.json +1 -0
  30. package/api/component/_adapter.mjs +39 -5
  31. package/api/component/component-replacement.test.mjs +1 -0
  32. package/api/component/component.mjs +17 -3
  33. package/api/component/component.test.mjs +15 -0
  34. package/api/component/doc-links.test.mjs +2 -2
  35. package/api/discover/_adapter.d.mts +1 -2
  36. package/api/discover/_adapter.mjs +42 -17
  37. package/api/discover/_adapter.test.mjs +42 -0
  38. package/api/discover/discover.mjs +0 -1
  39. package/api/docs/_adapter.d.mts +2 -2
  40. package/api/docs/_adapter.mjs +82 -23
  41. package/api/docs/docs-homes.test.mjs +127 -0
  42. package/api/docs/docs.doc.mjs +3 -3
  43. package/api/docs/docs.test.mjs +35 -19
  44. package/api/docs/integration-tree.test.mjs +20 -20
  45. package/api/docs/integrationDocs.test.mjs +1 -1
  46. package/api/docs/namespace-section.test.mjs +6 -6
  47. package/api/docs/reference-blocks.test.mjs +2 -2
  48. package/api/doctor/_adapter.d.mts +33 -13
  49. package/api/doctor/_adapter.mjs +55 -25
  50. package/api/doctor/doctor.d.mts +23 -5
  51. package/api/doctor/doctor.mjs +183 -40
  52. package/api/doctor/doctor.test.mjs +95 -12
  53. package/api/hook/hook.mjs +1 -1
  54. package/api/init/init.doc.mjs +20 -6
  55. package/api/init/init.test.mjs +18 -2
  56. package/api/init/init.type.d.mts +3 -3
  57. package/api/init/init.type.mjs +3 -3
  58. package/api/init/remove/remove.mjs +17 -4
  59. package/api/init/remove/remove.test.mjs +114 -2
  60. package/api/init/run/run.mjs +69 -6
  61. package/api/integration/_adapter.d.mts +8 -0
  62. package/api/integration/_adapter.mjs +21 -1
  63. package/api/integration/authoring-checks.mjs +83 -9
  64. package/api/integration/authoring-checks.test.mjs +220 -0
  65. package/api/integration/pack-check.mjs +123 -4
  66. package/api/integration/pack-check.test.mjs +87 -0
  67. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  68. package/api/integration/validate-integration-fixes.test.mjs +6 -5
  69. package/api/integration/validate-integration-gaps.test.mjs +1975 -0
  70. package/api/integration/validate-integration.d.mts +15 -2
  71. package/api/integration/validate-integration.mjs +298 -39
  72. package/api/integration/validate-integration.type.d.mts +90 -1
  73. package/api/integration/validate-integration.type.mjs +67 -2
  74. package/api/integration/validateIntegration.doc.mjs +1 -1
  75. package/api/search/ORDERING.md +28 -0
  76. package/api/search/_adapter.d.mts +82 -2
  77. package/api/search/_adapter.mjs +157 -10
  78. package/api/search/_adapter.test.mjs +173 -0
  79. package/api/search/_candidate-score.d.mts +40 -0
  80. package/api/search/_candidate-score.mjs +238 -0
  81. package/api/search/_cards.json +6098 -0
  82. package/api/search/_compound.d.mts +50 -0
  83. package/api/search/_compound.mjs +170 -0
  84. package/api/search/_doc-searcher.d.mts +4 -0
  85. package/api/search/_doc-searcher.mjs +23 -0
  86. package/api/search/_doc-searcher.test.mjs +36 -0
  87. package/api/search/_doc-searcher.weights.json +1 -0
  88. package/api/search/_doc-text.d.mts +30 -0
  89. package/api/search/_doc-text.mjs +87 -0
  90. package/api/search/_entries.d.mts +63 -0
  91. package/api/search/_entries.mjs +232 -0
  92. package/api/search/_entries.test.mjs +48 -0
  93. package/api/search/_features.d.mts +35 -0
  94. package/api/search/_features.mjs +155 -0
  95. package/api/search/_gather-components.d.mts +26 -0
  96. package/api/search/_gather-components.mjs +284 -0
  97. package/api/search/_gather-docs.d.mts +20 -0
  98. package/api/search/_gather-docs.mjs +254 -0
  99. package/api/search/_gather-hooks.d.mts +12 -0
  100. package/api/search/_gather-hooks.mjs +52 -0
  101. package/api/search/_gather-templates.d.mts +25 -0
  102. package/api/search/_gather-templates.mjs +107 -0
  103. package/api/search/_lexical.d.mts +135 -0
  104. package/api/search/_lexical.mjs +351 -0
  105. package/api/search/_main-searcher.d.mts +19 -0
  106. package/api/search/_main-searcher.mjs +115 -0
  107. package/api/search/_main-searcher.test.mjs +106 -0
  108. package/api/search/_main-searcher.weights.json +1 -0
  109. package/api/search/_module-doc.d.mts +32 -0
  110. package/api/search/_module-doc.mjs +78 -0
  111. package/api/search/_order.d.mts +32 -0
  112. package/api/search/_order.mjs +162 -0
  113. package/api/search/_order.test.mjs +72 -0
  114. package/api/search/_priority.d.mts +50 -0
  115. package/api/search/_priority.mjs +139 -0
  116. package/api/search/_query-words.d.mts +25 -0
  117. package/api/search/_query-words.mjs +92 -0
  118. package/api/search/_query.d.mts +65 -0
  119. package/api/search/_query.mjs +176 -0
  120. package/api/search/_result.d.mts +97 -0
  121. package/api/search/_result.mjs +150 -0
  122. package/api/search/_score.d.mts +60 -0
  123. package/api/search/_score.mjs +283 -0
  124. package/api/search/_synonyms.d.mts +21 -0
  125. package/api/search/_synonyms.mjs +67 -0
  126. package/api/search/_template-searcher.d.mts +4 -0
  127. package/api/search/_template-searcher.mjs +23 -0
  128. package/api/search/_template-searcher.test.mjs +40 -0
  129. package/api/search/_template-searcher.weights.json +1 -0
  130. package/api/search/_titles.d.mts +33 -0
  131. package/api/search/_titles.mjs +65 -0
  132. package/api/search/_words.d.mts +64 -0
  133. package/api/search/_words.mjs +157 -0
  134. package/api/search/search.d.mts +22 -305
  135. package/api/search/search.doc.mjs +8 -6
  136. package/api/search/search.mjs +56 -2482
  137. package/api/search/search.test.mjs +14 -14
  138. package/api/search/search.type.d.mts +6 -1
  139. package/api/search/search.type.mjs +6 -1
  140. package/api/search/tree.d.mts +15 -0
  141. package/api/search/tree.mjs +40 -0
  142. package/api/search/tree.test.mjs +66 -0
  143. package/api/search/tree.weights.json +1 -0
  144. package/api/template/template.mjs +5 -1
  145. package/api/theme/build/build.packed-old-core.test.mjs +1 -0
  146. package/api/upgrade/_adapter.d.mts +57 -9
  147. package/api/upgrade/_adapter.mjs +198 -28
  148. package/api/upgrade/registry/registry.d.mts +10 -4
  149. package/api/upgrade/registry/registry.mjs +33 -16
  150. package/api/upgrade/registry/registry.test.mjs +85 -0
  151. package/api/upgrade/run/run.d.mts +4 -2
  152. package/api/upgrade/run/run.mjs +13 -2
  153. package/api/upgrade/run/run.test.mjs +417 -3
  154. package/api/upgrade/upgrade.doc.mjs +10 -5
  155. package/api/upgrade/upgrade.mjs +13 -2
  156. package/api/upgrade/upgrade.test.mjs +194 -0
  157. package/api/upgrade/upgrade.type.d.mts +5 -3
  158. package/api/upgrade/upgrade.type.mjs +8 -6
  159. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  160. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  161. package/assets/docs/author-a-theme.doc.mjs +2 -2
  162. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  163. package/assets/docs/tree/add-a-component.doc.mjs +1 -1
  164. package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
  165. package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
  166. package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
  167. package/assets/docs/tree/api.doc.mjs +6 -0
  168. package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
  169. package/assets/docs/tree/block-template.doc.mjs +1 -1
  170. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  171. package/assets/docs/tree/building-blocks.doc.mjs +2 -2
  172. package/assets/docs/tree/check-the-props.doc.mjs +1 -1
  173. package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
  174. package/assets/docs/tree/checks.doc.mjs +3 -3
  175. package/assets/docs/tree/ci-and-containers.doc.mjs +13 -0
  176. package/assets/docs/tree/cli-command.doc.mjs +1 -1
  177. package/assets/docs/tree/cli.doc.mjs +1 -1
  178. package/assets/docs/tree/codemods.doc.mjs +1 -1
  179. package/assets/docs/tree/component-family.doc.mjs +1 -1
  180. package/assets/docs/tree/component-imports.doc.mjs +1 -1
  181. package/assets/docs/tree/components.doc.mjs +1 -1
  182. package/assets/docs/tree/configuration.doc.mjs +1 -1
  183. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
  184. package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
  185. package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
  186. package/assets/docs/tree/docs.doc.mjs +1 -1
  187. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  188. package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
  189. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  190. package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
  191. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  192. package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
  193. package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
  194. package/assets/docs/tree/global-integrations.doc.mjs +2 -2
  195. package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
  196. package/assets/docs/tree/help.doc.mjs +2 -2
  197. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  198. package/assets/docs/tree/links.doc.mjs +1 -1
  199. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  200. package/assets/docs/tree/page-template.doc.mjs +1 -1
  201. package/assets/docs/tree/publishing.doc.mjs +1 -1
  202. package/assets/docs/tree/quick-start.doc.mjs +1 -1
  203. package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
  204. package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
  207. package/assets/docs/tree/ship.doc.mjs +2 -2
  208. package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
  209. package/assets/docs/tree/single-component.doc.mjs +1 -1
  210. package/assets/docs/tree/start-a-template.doc.mjs +1 -1
  211. package/assets/docs/tree/subcomponent.doc.mjs +1 -1
  212. package/assets/docs/tree/template-assets.doc.mjs +1 -1
  213. package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
  214. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  215. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  216. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  217. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  218. package/assets/docs/tree/template-styles.doc.mjs +1 -1
  219. package/assets/docs/tree/templates.doc.mjs +1 -1
  220. package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
  221. package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
  222. package/assets/docs/tree/themes.doc.mjs +1 -1
  223. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  224. package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
  225. package/assets/docs/tree/upgrading.doc.mjs +1 -1
  226. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
  227. package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
  228. package/assets/docs/tree/versioning.doc.mjs +5 -1
  229. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  230. package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
  231. package/assets/docs/use-integrations.doc.mjs +120 -0
  232. package/assets/docs/working-with-ai.doc.mjs +6 -2
  233. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  234. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  235. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  236. package/authoring/debug/parse.d.mts +1 -1
  237. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  238. package/authoring/integration/integration.doc.mjs +1 -1
  239. package/authoring/integration/type.ts +1 -1
  240. package/clients/cli/bin/astryx.mjs +7 -78
  241. package/clients/cli/command-result-coverage.test.mjs +6 -5
  242. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  243. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  244. package/clients/cli/commands/component.test.mjs +6 -6
  245. package/clients/cli/commands/docs.doc.mjs +2 -2
  246. package/clients/cli/commands/docs.mjs +1 -1
  247. package/clients/cli/commands/docs.test.mjs +14 -14
  248. package/clients/cli/commands/doctor-integration.test.mjs +49 -1
  249. package/clients/cli/commands/doctor.doc.mjs +1 -1
  250. package/clients/cli/commands/doctor.mjs +40 -0
  251. package/clients/cli/commands/doctor.test.mjs +65 -0
  252. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  253. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  254. package/clients/cli/commands/init.behavior.test.mjs +230 -1
  255. package/clients/cli/commands/init.doc.mjs +28 -9
  256. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  257. package/clients/cli/commands/init.mjs +2 -2
  258. package/clients/cli/commands/integration-check.test.mjs +48 -0
  259. package/clients/cli/commands/integration.doc.mjs +1 -1
  260. package/clients/cli/commands/manifest.doc.mjs +1 -1
  261. package/clients/cli/commands/manifest.mjs +67 -0
  262. package/clients/cli/commands/outside-project.test.mjs +101 -1
  263. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  264. package/clients/cli/commands/postinstall.mjs +31 -0
  265. package/clients/cli/commands/setup-nudge.test.mjs +78 -0
  266. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
  267. package/clients/cli/commands/upgrade.doc.mjs +4 -2
  268. package/clients/cli/commands/upgrade.mjs +9 -2
  269. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  270. package/clients/cli/index.mjs +54 -94
  271. package/clients/cli/lib/component-format.mjs +1 -1
  272. package/clients/cli/lib/define-command.mjs +12 -7
  273. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  274. package/clients/cli/lib/manifest.test.mjs +12 -0
  275. package/clients/cli/lib/welcome-box.mjs +50 -0
  276. package/clients/cli/run.mjs +108 -0
  277. package/foundation/agent-docs/agent-doc-state.d.mts +32 -7
  278. package/foundation/agent-docs/agent-doc-state.mjs +58 -9
  279. package/foundation/agent-docs/agent-docs.d.mts +100 -12
  280. package/foundation/agent-docs/agent-docs.mjs +1017 -105
  281. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  282. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  283. package/foundation/agent-docs/computer-agent-text.d.mts +39 -2
  284. package/foundation/agent-docs/computer-agent-text.mjs +135 -8
  285. package/foundation/agent-docs/computer-agent-text.test.mjs +99 -2
  286. package/foundation/config/project.mjs +20 -22
  287. package/foundation/config/project.test.mjs +56 -0
  288. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  289. package/foundation/discovery/authoring-self-docs.mjs +16 -4
  290. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  291. package/foundation/discovery/authoring-surface.d.mts +1 -1
  292. package/foundation/discovery/authoring-surface.mjs +2 -2
  293. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  294. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  295. package/foundation/discovery/cli-self-docs.mjs +4 -3
  296. package/foundation/discovery/cli-self-docs.test.mjs +2 -2
  297. package/foundation/discovery/component-discovery.d.mts +37 -0
  298. package/foundation/discovery/component-discovery.mjs +80 -5
  299. package/foundation/discovery/component-loader.d.mts +1 -1
  300. package/foundation/discovery/docs-discovery.mjs +14 -1
  301. package/foundation/discovery/module-exports.d.mts +41 -0
  302. package/foundation/discovery/module-exports.mjs +253 -0
  303. package/foundation/discovery/runner-allowlist.d.mts +2 -4
  304. package/foundation/discovery/runner-allowlist.mjs +2 -4
  305. package/foundation/discovery/runner-commands.d.mts +77 -0
  306. package/foundation/discovery/runner-commands.mjs +294 -0
  307. package/foundation/discovery/runner-commands.test.mjs +128 -0
  308. package/foundation/discovery/stray-pointers.test.mjs +1 -1
  309. package/foundation/discovery/template-adapter.mjs +18 -1
  310. package/foundation/discovery/template-needs.mjs +1 -44
  311. package/foundation/discovery/theme-discovery.mjs +147 -3
  312. package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
  313. package/foundation/doc-compiler/read.mjs +59 -1
  314. package/foundation/doc-compiler/read.test.mjs +11 -2
  315. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  316. package/foundation/doc-compiler/tree.d.mts +32 -6
  317. package/foundation/doc-compiler/tree.mjs +77 -43
  318. package/foundation/doc-compiler/tree.test.mjs +7 -7
  319. package/foundation/fs/paths.d.mts +70 -8
  320. package/foundation/fs/paths.mjs +556 -38
  321. package/foundation/fs/paths.test.mjs +430 -54
  322. package/foundation/fs/read-record.d.mts +18 -0
  323. package/foundation/fs/read-record.mjs +131 -0
  324. package/foundation/fs/read-record.test.mjs +77 -0
  325. package/foundation/integrations/autolink.d.mts +2 -1
  326. package/foundation/integrations/autolink.mjs +4 -13
  327. package/foundation/integrations/cli-peer-version.d.mts +36 -0
  328. package/foundation/integrations/cli-peer-version.mjs +132 -0
  329. package/foundation/integrations/cli-peer-version.test.mjs +354 -0
  330. package/foundation/integrations/computer-integrations.d.mts +6 -3
  331. package/foundation/integrations/computer-integrations.mjs +38 -9
  332. package/foundation/integrations/contribution-inventory.d.mts +15 -20
  333. package/foundation/integrations/contribution-inventory.mjs +41 -5
  334. package/foundation/integrations/exports-subpaths.d.mts +57 -0
  335. package/foundation/integrations/exports-subpaths.mjs +113 -0
  336. package/foundation/integrations/integrations.d.mts +27 -1
  337. package/foundation/integrations/integrations.mjs +61 -2
  338. package/foundation/integrations/public-imports.d.mts +118 -0
  339. package/foundation/integrations/public-imports.mjs +1769 -0
  340. package/foundation/integrations/public-imports.test.mjs +1793 -0
  341. package/foundation/integrations/validate-contributions.d.mts +115 -0
  342. package/foundation/integrations/validate-contributions.mjs +1168 -13
  343. package/foundation/release/cache.test.mjs +24 -21
  344. package/foundation/release/global-state.d.mts +8 -4
  345. package/foundation/release/global-state.mjs +4 -2
  346. package/foundation/release/handoff.d.mts +23 -4
  347. package/foundation/release/handoff.mjs +175 -8
  348. package/foundation/release/notices.d.mts +62 -8
  349. package/foundation/release/notices.mjs +136 -25
  350. package/foundation/release/notices.test.mjs +21 -0
  351. package/foundation/release/run-context.mjs +14 -0
  352. package/foundation/response/response-types.doc.mjs +1 -1
  353. package/foundation/route/route.d.mts +285 -0
  354. package/foundation/route/route.mjs +324 -0
  355. package/foundation/route/route.test.mjs +153 -0
  356. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  357. package/foundation/runtime/locked-versions.d.mts +32 -0
  358. package/foundation/runtime/locked-versions.mjs +65 -0
  359. package/foundation/runtime/package-root.d.mts +91 -0
  360. package/foundation/runtime/package-root.mjs +174 -0
  361. package/foundation/runtime/package-set.d.mts +62 -0
  362. package/foundation/runtime/package-set.mjs +130 -0
  363. package/foundation/runtime/package-set.test.mjs +432 -0
  364. package/foundation/text/string-utils.d.mts +2 -1
  365. package/foundation/text/string-utils.mjs +16 -5
  366. package/foundation/text/suggest-order.d.mts +72 -0
  367. package/foundation/text/suggest-order.mjs +363 -0
  368. package/foundation/text/suggest-order.test.mjs +259 -0
  369. package/host/door-conformance.test.mjs +274 -0
  370. package/host/index.d.ts +116 -0
  371. package/host/index.mjs +295 -0
  372. package/host/index.test.mjs +302 -0
  373. package/package.json +14 -9
@@ -93,7 +93,7 @@ describe('docs() dispatcher routing', () => {
93
93
 
94
94
  it("lists the docs tree's namespaces in meta, so every data entry reads as a topic", async () => {
95
95
  const res = await docs();
96
- expect(res.meta.namespaces.map(entry => entry.topic)).toEqual(['cli', 'global', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography', 'unorganized']);
96
+ expect(res.meta.namespaces.map(entry => entry.topic)).toEqual(['authoring', 'cli', 'foundations', 'global', 'guides', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography']);
97
97
  for (const entry of res.data) {
98
98
  expect((await docs(entry.topic)).type).toBe('docs.detail');
99
99
  }
@@ -123,7 +123,13 @@ describe('docs() dispatcher routing', () => {
123
123
  kind: 'namespace',
124
124
  package: '@astryxdesign/cli',
125
125
  breadcrumb: [{route: 'cli', title: 'Astryx CLI'}],
126
- content: [],
126
+ // Its one block points to the host entry's guide.
127
+ content: [
128
+ {
129
+ type: 'prose',
130
+ text: expect.stringContaining('`astryx docs cli/host-entry`'),
131
+ },
132
+ ],
127
133
  });
128
134
  expect(r.data.slots.flatMap(slot => slot.children.map(c => c.route))).toEqual([
129
135
  'cli/api/functions',
@@ -152,8 +158,8 @@ describe('docs() dispatcher routing', () => {
152
158
  }, SLOW);
153
159
 
154
160
  it('a guide the tree places reads like a topic: the whole doc, its index, a section', async () => {
155
- // cli/integrations is a namespace of short guides; each guide reads like a topic.
156
- const integrations = await docs('cli/integrations');
161
+ // authoring is a namespace of short guides; each guide reads like a topic.
162
+ const integrations = await docs('authoring');
157
163
  expect(integrations.type).toBe('docs.node');
158
164
  const guide = placedGuide(integrations.data);
159
165
  expect((await docs(guide)).type).toBe('docs.detail');
@@ -172,7 +178,7 @@ describe('docs() dispatcher routing', () => {
172
178
  expect(leaf.links.up).toBe('astryx docs cli/api/functions');
173
179
  expect(leaf.links.previous).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
174
180
  expect(leaf.links.next).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
175
- const integrations = (await docs('cli/integrations')).data;
181
+ const integrations = (await docs('authoring')).data;
176
182
  const guide = placedGuide(integrations);
177
183
  const siblings = integrations.slots
178
184
  .find(slot => slot.children.some(child => child.route === guide))
@@ -181,7 +187,7 @@ describe('docs() dispatcher routing', () => {
181
187
  const index = await docs(guide, undefined, {index: true});
182
188
  // A guide moves across its namespace's slot, as any tree node does.
183
189
  expect(index.data.links).toEqual({
184
- up: 'astryx docs cli/integrations',
190
+ up: 'astryx docs authoring',
185
191
  ...(at > 0 ? {previous: `astryx docs ${siblings[at - 1]}`} : {}),
186
192
  ...(at < siblings.length - 1
187
193
  ? {next: `astryx docs ${siblings[at + 1]}`}
@@ -198,16 +204,22 @@ describe('docs() dispatcher routing', () => {
198
204
  expect(end.links.previous).toBe(
199
205
  `astryx docs ${guide} ${index.data.sections.at(-2).id}`,
200
206
  );
201
- // A flat topic's home is the Unorganized level, and it moves across it.
207
+ // A flat topic's home is the level for its category, and it moves across it.
202
208
  const flat = (await docs('principles')).data.links;
203
- expect(flat.up).toBe('astryx docs unorganized');
209
+ expect(flat.up).toBe('astryx docs guides');
204
210
  expect(flat.previous).toMatch(/^astryx docs [a-z-]+$/);
205
211
  expect(flat.next).toMatch(/^astryx docs [a-z-]+$/);
206
- const home = (await docs('unorganized')).data;
207
- expect(home).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
208
- expect(home.slots[0].children.map(child => child.route)).toEqual(
209
- (await docs()).data.map(entry => entry.topic),
210
- );
212
+ const guides = (await docs('guides')).data;
213
+ expect(guides).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
214
+ const foundations = (await docs('foundations')).data;
215
+ expect(foundations).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
216
+ // Between them the two levels hold every flat topic, each in list order.
217
+ const topics = (await docs()).data.map(entry => entry.topic);
218
+ const held = [guides, foundations].map(level => level.slots[0].children.map(child => child.route));
219
+ for (const routes of held) {
220
+ expect(routes).toEqual(topics.filter(topic => routes.includes(topic)));
221
+ }
222
+ expect(held.flat().sort()).toEqual([...topics].sort());
211
223
  }, SLOW);
212
224
 
213
225
  it('names a node by its doc identity; a generated level has id null', async () => {
@@ -234,10 +246,9 @@ describe('docs() dispatcher routing', () => {
234
246
  }, SLOW);
235
247
 
236
248
  it("the guide's old flat name is gone, and its error names the new route", async () => {
237
- await expect(docs('cli-integrations')).rejects.toMatchObject({
238
- code: 'ERR_UNKNOWN_TOPIC',
239
- suggestions: [expect.objectContaining({name: 'cli/integrations'})],
240
- });
249
+ const error = await docs('cli-integrations').catch(e => e);
250
+ expect(error.code).toBe('ERR_UNKNOWN_TOPIC');
251
+ expect(error.suggestions[0]).toMatchObject({name: 'authoring'});
241
252
  expect((await docs()).data.map(entry => entry.topic)).not.toContain(
242
253
  'cli-integrations',
243
254
  );
@@ -247,11 +258,16 @@ describe('docs() dispatcher routing', () => {
247
258
  const err = await docs('cli', 'zzzz-nope').catch(e => e);
248
259
  expect(err).toBeInstanceOf(AstryxError);
249
260
  expect(err.code).toBe('ERR_UNKNOWN_SECTION');
250
- // It names every guide below the namespace, at any depth.
251
261
  const names = err.suggestions.map(s => s.name);
252
262
  expect(names).toContain('cli/component-lookups');
253
- expect(names).toContain('cli/integrations/quick-start');
254
263
  expect(names.every(name => name.startsWith('cli/'))).toBe(true);
264
+ // It names every guide below the namespace, at any depth.
265
+ const deep = await docs('authoring', 'zzzz-nope').catch(e => e);
266
+ expect(deep.code).toBe('ERR_UNKNOWN_SECTION');
267
+ const below = deep.suggestions.map(s => s.name);
268
+ expect(below).toContain('authoring/quick-start');
269
+ expect(below).toContain('authoring/building-blocks/components/add-a-component');
270
+ expect(below.every(name => name.startsWith('authoring/'))).toBe(true);
255
271
  }, SLOW);
256
272
 
257
273
  it('an unknown route suggests the children of the deepest namespace it reaches', async () => {
@@ -246,7 +246,7 @@ describe('integration docs in the docs tree', () => {
246
246
  });
247
247
  scaffold({
248
248
  ...kit(),
249
- 'unorganized.doc.mjs': {...NAMESPACE, name: 'unorganized', title: 'Mine', summary: 'Mine.'},
249
+ 'guides.doc.mjs': {...NAMESPACE, name: 'guides', title: 'Mine', summary: 'Mine.'},
250
250
  'use-a-theme.doc.mjs': {...NAMESPACE, name: 'use-a-theme', title: 'Acme use-a-theme', summary: 'Acme use-a-theme.'},
251
251
  'cli.doc.mjs': flat('cli'),
252
252
  });
@@ -254,26 +254,26 @@ describe('integration docs in the docs tree', () => {
254
254
  expect(listed.meta.namespaces).toEqual(
255
255
  expect.arrayContaining([
256
256
  expect.objectContaining({topic: 'cli', package: '@astryxdesign/cli'}),
257
- expect.objectContaining({topic: 'unorganized', package: '@astryxdesign/cli'}),
257
+ expect.objectContaining({topic: 'guides', package: '@astryxdesign/cli'}),
258
258
  ]),
259
259
  );
260
- expect(listed.meta.namespaces.filter(n => ['use-a-theme', 'unorganized'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
260
+ expect(listed.meta.namespaces.filter(n => ['use-a-theme', 'guides'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
261
261
  expect(listed.data.map(entry => entry.topic)).not.toContain('cli');
262
262
  // Each name opens the CLI's doc, and a CLI topic keeps its home.
263
263
  expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
264
- expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
264
+ expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
265
265
  const tokens = await docs('use-a-theme', undefined, {cwd: tmpDir});
266
266
  expect(tokens.type).toBe('docs.detail');
267
- expect(tokens.data.links.up).toBe('astryx docs unorganized');
267
+ expect(tokens.data.links.up).toBe('astryx docs guides');
268
268
  // The project doctor and the package doctor both name the claims.
269
269
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
270
270
  expect(check.status).toBe('warn');
271
- expect(check.message).toContain('takes the route "unorganized", which the CLI\'s own docs keep');
271
+ expect(check.message).toContain('takes the route "guides", which the CLI\'s own docs keep');
272
272
  expect(check.message).toContain('takes the route "use-a-theme"');
273
273
  expect(check.message).toContain('both have the route "cli"');
274
274
  const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
275
275
  const graph = result.data.issues.filter(issue => issue.code === 'invalid_doc_graph').map(issue => issue.message).join('\n');
276
- expect(graph).toContain('takes the route "unorganized"');
276
+ expect(graph).toContain('takes the route "guides"');
277
277
  expect(graph).toContain('takes the route "use-a-theme"');
278
278
  expect(graph).toContain('route "cli"');
279
279
  }, SLOW);
@@ -294,16 +294,16 @@ describe('integration docs in the docs tree', () => {
294
294
  const nested = path.join(tmpDir, 'node_modules', '@acme', 'kit', 'docs', 'nested');
295
295
  fs.mkdirSync(nested, {recursive: true});
296
296
  fs.writeFileSync(
297
- path.join(nested, 'caps-unorganized.doc.mjs'),
298
- `export const docs = ${JSON.stringify(flat('Unorganized'), null, 2)};\n`,
297
+ path.join(nested, 'caps-guides.doc.mjs'),
298
+ `export const docs = ${JSON.stringify(flat('Guides'), null, 2)};\n`,
299
299
  );
300
300
  fs.writeFileSync(
301
301
  path.join(nested, 'caps-use-a-theme.doc.mjs'),
302
302
  `export const docs = ${JSON.stringify(flat('USE-A-THEME'), null, 2)};\n`,
303
303
  );
304
304
  expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
305
- expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
306
- expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs unorganized');
305
+ expect((await docs('guides', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
306
+ expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs guides');
307
307
  const listed = await docs(undefined, undefined, {cwd: tmpDir});
308
308
  expect(listed.data.map(entry => entry.topic.toLowerCase())).not.toContain('cli');
309
309
  // Search does not offer a topic whose route another doc owns.
@@ -314,10 +314,10 @@ describe('integration docs in the docs tree', () => {
314
314
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
315
315
  expect(check.status).toBe('warn');
316
316
  expect(check.message).toContain('route "CLI"');
317
- expect(check.message).toContain('takes the route "Unorganized"');
317
+ expect(check.message).toContain('takes the route "Guides"');
318
318
  // `USE-A-THEME` is the CLI's topic `use-a-theme` in another spelling: the CLI's wins.
319
319
  const tokens = await docs('USE-A-THEME', undefined, {cwd: tmpDir, index: true});
320
- expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs unorganized'}});
320
+ expect(tokens.data).toMatchObject({name: 'use-a-theme', links: {up: 'astryx docs guides'}});
321
321
  expect(tokens.data.title).not.toBe('Acme USE-A-THEME');
322
322
  const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
323
323
  const graph = result.data.issues
@@ -325,7 +325,7 @@ describe('integration docs in the docs tree', () => {
325
325
  .map(issue => issue.message)
326
326
  .join('\n');
327
327
  expect(graph).toContain('route "CLI"');
328
- expect(graph).toContain('takes the route "Unorganized"');
328
+ expect(graph).toContain('takes the route "Guides"');
329
329
  }, SLOW);
330
330
 
331
331
  it("keeps a replaced name for the topic that replaces it, over another integration's namespace", async () => {
@@ -420,9 +420,9 @@ describe('integration docs in the docs tree', () => {
420
420
  scaffold({
421
421
  ...kit(),
422
422
  'a-cli.doc.mjs': flat('cli'),
423
- 'a-unorganized.doc.mjs': flat('Unorganized'),
423
+ 'a-guides.doc.mjs': flat('Guides'),
424
424
  'z-b2.doc.mjs': flat('b2', {replaces: 'cli'}),
425
- 'z-u2.doc.mjs': flat('u2', {replaces: 'Unorganized'}),
425
+ 'z-u2.doc.mjs': flat('u2', {replaces: 'Guides'}),
426
426
  });
427
427
  // Another package carries the chain on: c3 replaces b2, which replaced cli.
428
428
  const three = path.join(tmpDir, 'node_modules', '@acme', 'three');
@@ -440,8 +440,8 @@ describe('integration docs in the docs tree', () => {
440
440
  for (const name of ['cli', 'CLI']) {
441
441
  expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
442
442
  }
443
- for (const name of ['unorganized', 'UNORGANIZED']) {
444
- expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
443
+ for (const name of ['guides', 'GUIDES']) {
444
+ expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'guides', package: '@astryxdesign/cli'});
445
445
  }
446
446
  // The replacement still answers to its own names.
447
447
  for (const name of ['b2', 'c3']) {
@@ -456,7 +456,7 @@ describe('integration docs in the docs tree', () => {
456
456
  const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
457
457
  expect(check.status).toBe('warn');
458
458
  expect(check.message).toContain('The topic "c3" answers to "cli" through replaces');
459
- expect(check.message).toContain('The topic "u2" answers to "unorganized" through replaces');
459
+ expect(check.message).toContain('The topic "u2" answers to "guides" through replaces');
460
460
  const inPackage = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
461
461
  const graph = inPackage.data.issues
462
462
  .filter(issue => issue.code === 'invalid_doc_graph')
@@ -519,7 +519,7 @@ describe('integration docs in the docs tree', () => {
519
519
  });
520
520
  const {data} = await docs('theme', 'acme-theming-notes', {cwd: tmpDir});
521
521
  // `generic:integrations` is the extension's own guide, never the CLI's
522
- // `cli/integrations`; a provider-qualified link reaches the CLI's topic.
522
+ // `authoring`; a provider-qualified link reaches the CLI's topic.
523
523
  expect(data.content[0].text).toBe(
524
524
  'See `astryx docs acme/integrations`, and `astryx docs tokens` for the tokens.',
525
525
  );
@@ -447,7 +447,7 @@ describe('integration-contributed topics', () => {
447
447
  // places it.
448
448
  expect(top).toContain('troubleshooting');
449
449
  expect(
450
- top.some(name => /^cli\/integrations\/(?:.+\/)?troubleshooting$/.test(name)),
450
+ top.some(name => /^authoring\/(?:.+\/)?troubleshooting$/.test(name)),
451
451
  top.join(', '),
452
452
  ).toBe(true);
453
453
  }, SLOW);
@@ -157,13 +157,13 @@ describe('a section read on a namespace', () => {
157
157
  expect(names).toContain('layout/side-panels');
158
158
  expect(names.every(name => name.startsWith('layout/'))).toBe(true);
159
159
  // At any depth: guides under nested namespaces are named, namespaces are not.
160
- const cli = await docs('cli', 'zzzz-nope').catch(e => e);
161
- expect(cli.code).toBe('ERR_UNKNOWN_SECTION');
162
- expect(cli.suggestions.map(s => s.name)).toContain(
163
- 'cli/integrations/quick-start',
160
+ const authoring = await docs('authoring', 'zzzz-nope').catch(e => e);
161
+ expect(authoring.code).toBe('ERR_UNKNOWN_SECTION');
162
+ expect(authoring.suggestions.map(s => s.name)).toContain(
163
+ 'authoring/building-blocks/components/add-a-component',
164
164
  );
165
- expect(cli.suggestions.map(s => s.name)).not.toContain(
166
- 'cli/integrations',
165
+ expect(authoring.suggestions.map(s => s.name)).not.toContain(
166
+ 'authoring/building-blocks',
167
167
  );
168
168
  },
169
169
  SLOW,
@@ -300,11 +300,11 @@ describe('a reference block that includes what it names', () => {
300
300
  });
301
301
 
302
302
  describe('what a reference block names', () => {
303
- it('resolves a CLI authoring schema by identity, to its section of `astryx docs authoring`', async () => {
303
+ it('resolves a CLI authoring schema by identity, to its section of the field reference', async () => {
304
304
  const resolve = await linkResolver(builtinCatalog(), CLI_PROVIDER_ID);
305
305
  expect(await resolve('schema:integration')).toMatchObject({
306
306
  id: createDocId(CLI_PROVIDER_ID, 'schema', 'integration'),
307
- route: 'authoring',
307
+ route: 'authoring/field-reference',
308
308
  title: 'Astryx Integration',
309
309
  command: 'astryx docs authoring integration',
310
310
  });
@@ -64,8 +64,11 @@ export function computerIntegrationsOutside(cwd: string): Promise<{
64
64
  */
65
65
  export function computerIntegrationsToAdd(cwd: string, loadedNames: string[]): Promise<import("../../foundation/integrations/computer-integrations.mjs").ComputerIntegrationCandidate[]>;
66
66
  /**
67
- * The computer-level agent text's setting and its state on disk.
68
- * @returns {{settings: import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings, entries: Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState, link?: true}>}}
67
+ * The computer-level agent text's setting, its state on disk, and the command
68
+ * the skill file tells agents to run and the install step it records for when
69
+ * that command is not found (each null when there is no file, or it names
70
+ * none).
71
+ * @returns {{settings: import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings, entries: Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState, link?: true}>, command: string | null, install: string | null}}
69
72
  */
70
73
  export function computerAgentTextState(): {
71
74
  settings: import("../../foundation/env/user-settings.mjs").ComputerAgentTextSettings;
@@ -74,6 +77,8 @@ export function computerAgentTextState(): {
74
77
  state: import("../../foundation/agent-docs/computer-agent-text.mjs").ComputerAgentTextState;
75
78
  link?: true;
76
79
  }>;
80
+ command: string | null;
81
+ install: string | null;
77
82
  };
78
83
  /**
79
84
  * The release facts doctor reports, read here so the checks stay pure
@@ -83,7 +88,7 @@ export function computerAgentTextState(): {
83
88
  * command that upgrades it.
84
89
  * @param {string} cwd
85
90
  * @param {{project: boolean}} options
86
- * @returns {{answeredBy: {cli: string, core: string | null, copy: string}, latest: string | null, globalBehind: ReturnType<typeof globalBehind> | null, projectLag: ReturnType<typeof projectLag> | null, lastNoticeSkip: ReturnType<typeof lastNoticeSkip>, lastCheckFailure: ReturnType<typeof lastCheckFailure>, stateLock: ReturnType<typeof stateLockHolder>, searchPathCommands: Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade: string | null}>}}
91
+ * @returns {{answeredBy: {cli: string, core: string | null, copy: string}, latest: string | null, globalBehind: ReturnType<typeof globalBehind> | null, projectLag: ReturnType<typeof projectLag> | null, lastNoticeSkip: ReturnType<typeof lastNoticeSkip>, lastCheckFailure: ReturnType<typeof lastCheckFailure>, stateLock: ReturnType<typeof stateLockHolder>, searchPathCommands: Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade: string | null, runner: boolean}>}}
87
92
  */
88
93
  export function releaseFacts(cwd: string, { project }: {
89
94
  project: boolean;
@@ -101,6 +106,7 @@ export function releaseFacts(cwd: string, { project }: {
101
106
  stateLock: ReturnType<typeof stateLockHolder>;
102
107
  searchPathCommands: Array<import("../../foundation/env/search-path.mjs").SearchPathCommand & {
103
108
  upgrade: string | null;
109
+ runner: boolean;
104
110
  }>;
105
111
  };
106
112
  /** Whether `cwd` is outside every project. */
@@ -108,13 +114,14 @@ export function outsideProject(cwd: string): boolean;
108
114
  /**
109
115
  * The commands that bring a project's own CLI and Core to one release, with
110
116
  * the project's package manager: Core up to the CLI, then its codemods, when
111
- * the CLI is newer; else the CLI to the Core's release.
117
+ * the CLI is newer; else the CLI to the Core's release. Null when no
118
+ * command fits (see `alignCliAndCore`).
112
119
  * @param {string} cwd
113
120
  * @param {string} cli
114
121
  * @param {string} core
115
- * @returns {string}
122
+ * @returns {string | null}
116
123
  */
117
- export function alignCommand(cwd: string, cli: string, core: string): string;
124
+ export function alignCommand(cwd: string, cli: string, core: string): string | null;
118
125
  /**
119
126
  * The Core release the project at `cwd` names: installed, else locked, else
120
127
  * declared; the version the daily hint and notice compare against (spec
@@ -131,19 +138,32 @@ export function projectCoreVersion(cwd: string): string | null;
131
138
  export function projectHasOwnCli(cwd: string): boolean;
132
139
  /**
133
140
  * The command that adds the CLI at `version` with the project's package
134
- * manager.
141
+ * manager, and the Core it matches: from a folder whose package.json declares
142
+ * no Astryx package, in the Astryx project above at that project's Core; null
143
+ * when there is none (see `cliInstallAdvice`).
135
144
  * @param {string} cwd
136
145
  * @param {string} version
137
- * @returns {string}
146
+ * @returns {{command: string, core: string} | null}
138
147
  */
139
- export function addCliCommandFor(cwd: string, version: string): string;
148
+ export function addCliCommandFor(cwd: string, version: string): {
149
+ command: string;
150
+ core: string;
151
+ } | null;
140
152
  /**
141
- * The command that adds a package with the folder's package manager, read
142
- * from its lockfiles and `packageManager` field.
153
+ * The command that adds a package to the project of `cwd`; null in a folder
154
+ * that belongs to no project or whose package.json is not the project's (see
155
+ * `projectAddCommand`).
143
156
  * @param {string} cwd
144
- * @returns {(name: string) => string}
157
+ * @returns {((name: string) => string) | null}
158
+ */
159
+ export function installCommandFor(cwd: string): ((name: string) => string) | null;
160
+ /**
161
+ * Whether `cwd` is inside a project whose package.json is not the project's,
162
+ * so advice points at the project's folder (see `installFolder`).
163
+ * @param {string} cwd
164
+ * @returns {boolean}
145
165
  */
146
- export function installCommandFor(cwd: string): (name: string) => string;
166
+ export function insideProjectElsewhere(cwd: string): boolean;
147
167
  export { resolveRecordedTheme } from "../theme/theme.mjs";
148
168
  export { collectUnloadedFonts } from "../theme/build/font-warning.mjs";
149
169
  export const SOURCE_EXTENSIONS: Set<string>;
@@ -10,8 +10,10 @@ import {
10
10
  stateLockHolder,
11
11
  } from '../../foundation/release/global-state.mjs';
12
12
  import {
13
- addCliCommand,
14
13
  alignCliAndCore,
14
+ cliInstallAdvice,
15
+ installFolder,
16
+ projectAddCommand,
15
17
  globalBehind,
16
18
  globalUpgradeCommand,
17
19
  lastNoticeSkip,
@@ -19,16 +21,18 @@ import {
19
21
  } from '../../foundation/release/notices.mjs';
20
22
  import {
21
23
  coreVersionOf,
24
+ installPlaceOf,
22
25
  isGlobalCopy,
23
- projectRootOf,
24
26
  } from '../../foundation/release/choose.mjs';
25
27
  import {readReleaseFacts} from '../../foundation/release/project.mjs';
26
- import {detectPackageManager} from '../../foundation/env/package-manager.mjs';
27
28
  import {astryxCommandsOnSearchPath} from '../../foundation/env/search-path.mjs';
28
29
  import {readDeclaredDependencies} from '../../foundation/integrations/autolink.mjs';
29
30
  import {
31
+ computerSkillFile,
30
32
  displayHomePath,
31
33
  inspectComputerAgentText,
34
+ skillCommandOf,
35
+ skillInstallStepOf,
32
36
  } from '../../foundation/agent-docs/computer-agent-text.mjs';
33
37
  import {computerAgentTextSettings} from '../../foundation/env/user-settings.mjs';
34
38
  import * as fs from 'node:fs';
@@ -291,12 +295,29 @@ function declaredPackageNames(cwd) {
291
295
  }
292
296
 
293
297
  /**
294
- * The computer-level agent text's setting and its state on disk.
295
- * @returns {{settings: import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings, entries: Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState, link?: true}>}}
298
+ * The computer-level agent text's setting, its state on disk, and the command
299
+ * the skill file tells agents to run and the install step it records for when
300
+ * that command is not found (each null when there is no file, or it names
301
+ * none).
302
+ * @returns {{settings: import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings, entries: Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState, link?: true}>, command: string | null, install: string | null}}
296
303
  */
297
304
  export function computerAgentTextState() {
298
305
  const settings = computerAgentTextSettings();
299
- return {settings, entries: inspectComputerAgentText({links: settings.links})};
306
+ let command = null;
307
+ let install = null;
308
+ try {
309
+ const text = fs.readFileSync(computerSkillFile(), 'utf8');
310
+ command = skillCommandOf(text);
311
+ install = skillInstallStepOf(text);
312
+ } catch {
313
+ // No skill file, or one that cannot be read: no command to check.
314
+ }
315
+ return {
316
+ settings,
317
+ entries: inspectComputerAgentText({links: settings.links}),
318
+ command,
319
+ install,
320
+ };
300
321
  }
301
322
 
302
323
  export {displayHomePath};
@@ -309,7 +330,7 @@ export {displayHomePath};
309
330
  * command that upgrades it.
310
331
  * @param {string} cwd
311
332
  * @param {{project: boolean}} options
312
- * @returns {{answeredBy: {cli: string, core: string | null, copy: string}, latest: string | null, globalBehind: ReturnType<typeof globalBehind> | null, projectLag: ReturnType<typeof projectLag> | null, lastNoticeSkip: ReturnType<typeof lastNoticeSkip>, lastCheckFailure: ReturnType<typeof lastCheckFailure>, stateLock: ReturnType<typeof stateLockHolder>, searchPathCommands: Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade: string | null}>}}
333
+ * @returns {{answeredBy: {cli: string, core: string | null, copy: string}, latest: string | null, globalBehind: ReturnType<typeof globalBehind> | null, projectLag: ReturnType<typeof projectLag> | null, lastNoticeSkip: ReturnType<typeof lastNoticeSkip>, lastCheckFailure: ReturnType<typeof lastCheckFailure>, stateLock: ReturnType<typeof stateLockHolder>, searchPathCommands: Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade: string | null, runner: boolean}>}}
313
334
  */
314
335
  export function releaseFacts(cwd, {project}) {
315
336
  const answered = answeredBy(cwd);
@@ -336,6 +357,9 @@ export function releaseFacts(cwd, {project}) {
336
357
  searchPathCommands: astryxCommandsOnSearchPath().map(row => ({
337
358
  ...row,
338
359
  upgrade: row.cliRoot ? globalUpgradeCommand(row.cliRoot) : null,
360
+ // A package runner's temporary install, which it puts first on the
361
+ // search path only for the run it starts.
362
+ runner: row.cliRoot ? installPlaceOf(row.cliRoot).runner : false,
339
363
  })),
340
364
  };
341
365
  }
@@ -348,11 +372,12 @@ export function outsideProject(/** @type {string} */ cwd) {
348
372
  /**
349
373
  * The commands that bring a project's own CLI and Core to one release, with
350
374
  * the project's package manager: Core up to the CLI, then its codemods, when
351
- * the CLI is newer; else the CLI to the Core's release.
375
+ * the CLI is newer; else the CLI to the Core's release. Null when no
376
+ * command fits (see `alignCliAndCore`).
352
377
  * @param {string} cwd
353
378
  * @param {string} cli
354
379
  * @param {string} core
355
- * @returns {string}
380
+ * @returns {string | null}
356
381
  */
357
382
  export function alignCommand(cwd, cli, core) {
358
383
  return alignCliAndCore({cwd, cli, core});
@@ -380,30 +405,35 @@ export function projectHasOwnCli(cwd) {
380
405
 
381
406
  /**
382
407
  * The command that adds the CLI at `version` with the project's package
383
- * manager.
408
+ * manager, and the Core it matches: from a folder whose package.json declares
409
+ * no Astryx package, in the Astryx project above at that project's Core; null
410
+ * when there is none (see `cliInstallAdvice`).
384
411
  * @param {string} cwd
385
412
  * @param {string} version
386
- * @returns {string}
413
+ * @returns {{command: string, core: string} | null}
387
414
  */
388
415
  export function addCliCommandFor(cwd, version) {
389
- return addCliCommand(projectRootOf(readReleaseFacts(cwd)) ?? cwd, version);
416
+ const advice = cliInstallAdvice({cwd, core: version});
417
+ return advice?.command ? {command: advice.command, core: advice.core} : null;
390
418
  }
391
419
 
392
420
  /**
393
- * The command that adds a package with the folder's package manager, read
394
- * from its lockfiles and `packageManager` field.
421
+ * The command that adds a package to the project of `cwd`; null in a folder
422
+ * that belongs to no project or whose package.json is not the project's (see
423
+ * `projectAddCommand`).
395
424
  * @param {string} cwd
396
- * @returns {(name: string) => string}
425
+ * @returns {((name: string) => string) | null}
397
426
  */
398
427
  export function installCommandFor(cwd) {
399
- const pm = detectPackageManager(cwd);
400
- const verb =
401
- pm === 'pnpm'
402
- ? 'pnpm add'
403
- : pm === 'yarn'
404
- ? 'yarn add'
405
- : pm === 'bun'
406
- ? 'bun add'
407
- : 'npm install';
408
- return name => `${verb} ${name}`;
428
+ return projectAddCommand(cwd);
429
+ }
430
+
431
+ /**
432
+ * Whether `cwd` is inside a project whose package.json is not the project's,
433
+ * so advice points at the project's folder (see `installFolder`).
434
+ * @param {string} cwd
435
+ * @returns {boolean}
436
+ */
437
+ export function insideProjectElsewhere(cwd) {
438
+ return installFolder(cwd)?.moved === true;
409
439
  }
@@ -188,6 +188,10 @@ export function checkCliCommand(ctx: DoctorContext): DoctorCheck;
188
188
  * each file of the computer-level agent text against this release's rendering
189
189
  * @property {import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings} [agentTextSettings]
190
190
  * the person's choices about the computer-level agent text
191
+ * @property {string | null} [agentTextCommand] the command the skill file
192
+ * tells agents to run, or null
193
+ * @property {string | null} [agentTextInstall] the install step the skill
194
+ * file records for when that command is not found, or null
191
195
  * @property {string} [cwd] the folder doctor runs in, for the printed fix
192
196
  * @property {import('../../foundation/release/notices.mjs').GlobalBehind | null} [globalBehind]
193
197
  * the CLI installed for the computer, when it is older than the newest
@@ -200,7 +204,7 @@ export function checkCliCommand(ctx: DoctorContext): DoctorCheck;
200
204
  * the newest update notice that did not print, and why (diagnostic only)
201
205
  * @property {{pid: number | null, host: string | null, since: number} | null} [stateLock]
202
206
  * who holds the state file's lock now (diagnostic only)
203
- * @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null}>} [searchPathCommands]
207
+ * @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null, runner?: boolean}>} [searchPathCommands]
204
208
  * every `astryx` on the search path, with the command that upgrades it
205
209
  * the `astryx` commands on the search path, in order
206
210
  * @property {import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]} [computerIntegrations]
@@ -259,15 +263,18 @@ export function checkComputerIntegrations(ctx: ComputerContext): DoctorCheck;
259
263
  * Inside a project, the integrations installed for the computer that the
260
264
  * project does not install: available, never used (spec AST-081 FR12).
261
265
  * Always info.
262
- * @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: (name: string) => string}} input
266
+ * @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: ((name: string) => string) | null, elsewhere?: boolean}} input
263
267
  * `install`: the command that adds a package with the project's package
264
- * manager (read by the adapter)
268
+ * manager (read by the adapter); null when the folder belongs to no
269
+ * project, or `elsewhere`: its package.json is not the project's, where the
270
+ * fix points at the project's folder
265
271
  * @returns {DoctorCheck}
266
272
  */
267
- export function checkComputerIntegrationsAvailable({ installed, candidates, install }: {
273
+ export function checkComputerIntegrationsAvailable({ installed, candidates, install, elsewhere }: {
268
274
  installed: Set<string>;
269
275
  candidates: import("../../foundation/integrations/computer-integrations.mjs").ComputerIntegrationCandidate[];
270
- install: (name: string) => string;
276
+ install: ((name: string) => string) | null;
277
+ elsewhere?: boolean;
271
278
  }): DoctorCheck;
272
279
  /**
273
280
  * Run all diagnostic checks and return a structured report.
@@ -443,6 +450,16 @@ export type ComputerContext = {
443
450
  * the person's choices about the computer-level agent text
444
451
  */
445
452
  agentTextSettings?: import("../../foundation/env/user-settings.mjs").ComputerAgentTextSettings | undefined;
453
+ /**
454
+ * the command the skill file
455
+ * tells agents to run, or null
456
+ */
457
+ agentTextCommand?: string | null | undefined;
458
+ /**
459
+ * the install step the skill
460
+ * file records for when that command is not found, or null
461
+ */
462
+ agentTextInstall?: string | null | undefined;
446
463
  /**
447
464
  * the folder doctor runs in, for the printed fix
448
465
  */
@@ -484,6 +501,7 @@ export type ComputerContext = {
484
501
  */
485
502
  searchPathCommands?: (import("../../foundation/env/search-path.mjs").SearchPathCommand & {
486
503
  upgrade?: string | null;
504
+ runner?: boolean;
487
505
  })[] | undefined;
488
506
  /**
489
507
  * the integrations installed beside the running CLI