@astryxdesign/cli 0.7.2 → 0.7.3-canary.0bf23bd

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 (337) hide show
  1. package/README.md +104 -71
  2. package/api/build/_adapter.d.mts +58 -0
  3. package/api/build/_adapter.mjs +115 -3
  4. package/api/build/blocks/blocks.d.mts +42 -0
  5. package/api/build/blocks/blocks.mjs +169 -0
  6. package/api/build/blocks/blocks.test.mjs +108 -0
  7. package/api/build/blocks/blocks.weights.json +1 -0
  8. package/api/build/build.mjs +25 -6
  9. package/api/build/kit/answer.d.mts +14 -0
  10. package/api/build/kit/answer.mjs +85 -0
  11. package/api/build/kit/answer.test.mjs +38 -0
  12. package/api/build/kit/kind.d.mts +25 -0
  13. package/api/build/kit/kind.mjs +170 -0
  14. package/api/build/kit/kit.d.mts +2 -4
  15. package/api/build/kit/kit.mjs +8 -398
  16. package/api/build/kit/rank.d.mts +3 -32
  17. package/api/build/kit/rank.mjs +25 -342
  18. package/api/build/kit/rank.test.mjs +2 -1
  19. package/api/build/kit/signals.d.mts +60 -0
  20. package/api/build/kit/signals.mjs +284 -0
  21. package/api/build/kit/start.d.mts +32 -0
  22. package/api/build/kit/start.mjs +163 -0
  23. package/api/build/kit/words.d.mts +72 -0
  24. package/api/build/kit/words.mjs +202 -0
  25. package/api/build/tree.d.mts +20 -0
  26. package/api/build/tree.mjs +52 -0
  27. package/api/build/tree.test.mjs +177 -0
  28. package/api/build/tree.weights.json +1 -0
  29. package/api/component/component.mjs +17 -3
  30. package/api/component/component.test.mjs +15 -0
  31. package/api/component/doc-links.test.mjs +2 -2
  32. package/api/discover/_adapter.mjs +36 -9
  33. package/api/discover/_adapter.test.mjs +42 -0
  34. package/api/docs/_adapter.d.mts +2 -2
  35. package/api/docs/_adapter.mjs +78 -23
  36. package/api/docs/docs-homes.test.mjs +127 -0
  37. package/api/docs/docs.doc.mjs +3 -3
  38. package/api/docs/docs.test.mjs +35 -19
  39. package/api/docs/integration-tree.test.mjs +20 -20
  40. package/api/docs/integrationDocs.test.mjs +1 -1
  41. package/api/docs/namespace-section.test.mjs +6 -6
  42. package/api/docs/reference-blocks.test.mjs +2 -2
  43. package/api/doctor/doctor.mjs +102 -24
  44. package/api/doctor/doctor.test.mjs +37 -12
  45. package/api/hook/hook.mjs +1 -1
  46. package/api/init/init.doc.mjs +20 -6
  47. package/api/init/init.test.mjs +18 -2
  48. package/api/init/init.type.d.mts +3 -3
  49. package/api/init/init.type.mjs +3 -3
  50. package/api/init/remove/remove.mjs +17 -4
  51. package/api/init/remove/remove.test.mjs +114 -2
  52. package/api/init/run/run.mjs +69 -6
  53. package/api/integration/_adapter.d.mts +8 -0
  54. package/api/integration/_adapter.mjs +21 -1
  55. package/api/integration/authoring-checks.mjs +83 -9
  56. package/api/integration/authoring-checks.test.mjs +220 -0
  57. package/api/integration/pack-check.mjs +123 -4
  58. package/api/integration/pack-check.test.mjs +87 -0
  59. package/api/integration/validate-integration-case-disk.test.mjs +111 -0
  60. package/api/integration/validate-integration-gaps.test.mjs +1964 -0
  61. package/api/integration/validate-integration.d.mts +11 -2
  62. package/api/integration/validate-integration.mjs +250 -32
  63. package/api/integration/validate-integration.type.d.mts +59 -1
  64. package/api/integration/validate-integration.type.mjs +46 -2
  65. package/api/integration/validateIntegration.doc.mjs +1 -1
  66. package/api/search/ORDERING.md +28 -0
  67. package/api/search/_adapter.d.mts +82 -2
  68. package/api/search/_adapter.mjs +157 -10
  69. package/api/search/_adapter.test.mjs +173 -0
  70. package/api/search/_candidate-score.d.mts +40 -0
  71. package/api/search/_candidate-score.mjs +238 -0
  72. package/api/search/_cards.json +6098 -0
  73. package/api/search/_compound.d.mts +50 -0
  74. package/api/search/_compound.mjs +170 -0
  75. package/api/search/_doc-searcher.d.mts +4 -0
  76. package/api/search/_doc-searcher.mjs +23 -0
  77. package/api/search/_doc-searcher.test.mjs +36 -0
  78. package/api/search/_doc-searcher.weights.json +1 -0
  79. package/api/search/_doc-text.d.mts +30 -0
  80. package/api/search/_doc-text.mjs +87 -0
  81. package/api/search/_entries.d.mts +52 -0
  82. package/api/search/_entries.mjs +214 -0
  83. package/api/search/_features.d.mts +35 -0
  84. package/api/search/_features.mjs +155 -0
  85. package/api/search/_gather-components.d.mts +26 -0
  86. package/api/search/_gather-components.mjs +284 -0
  87. package/api/search/_gather-docs.d.mts +20 -0
  88. package/api/search/_gather-docs.mjs +254 -0
  89. package/api/search/_gather-hooks.d.mts +12 -0
  90. package/api/search/_gather-hooks.mjs +52 -0
  91. package/api/search/_gather-templates.d.mts +25 -0
  92. package/api/search/_gather-templates.mjs +107 -0
  93. package/api/search/_lexical.d.mts +135 -0
  94. package/api/search/_lexical.mjs +351 -0
  95. package/api/search/_main-searcher.d.mts +19 -0
  96. package/api/search/_main-searcher.mjs +115 -0
  97. package/api/search/_main-searcher.test.mjs +106 -0
  98. package/api/search/_main-searcher.weights.json +1 -0
  99. package/api/search/_module-doc.d.mts +32 -0
  100. package/api/search/_module-doc.mjs +78 -0
  101. package/api/search/_order.d.mts +32 -0
  102. package/api/search/_order.mjs +162 -0
  103. package/api/search/_order.test.mjs +72 -0
  104. package/api/search/_priority.d.mts +50 -0
  105. package/api/search/_priority.mjs +139 -0
  106. package/api/search/_query-words.d.mts +25 -0
  107. package/api/search/_query-words.mjs +92 -0
  108. package/api/search/_query.d.mts +65 -0
  109. package/api/search/_query.mjs +176 -0
  110. package/api/search/_result.d.mts +97 -0
  111. package/api/search/_result.mjs +150 -0
  112. package/api/search/_score.d.mts +60 -0
  113. package/api/search/_score.mjs +283 -0
  114. package/api/search/_synonyms.d.mts +21 -0
  115. package/api/search/_synonyms.mjs +67 -0
  116. package/api/search/_template-searcher.d.mts +4 -0
  117. package/api/search/_template-searcher.mjs +23 -0
  118. package/api/search/_template-searcher.test.mjs +40 -0
  119. package/api/search/_template-searcher.weights.json +1 -0
  120. package/api/search/_titles.d.mts +33 -0
  121. package/api/search/_titles.mjs +65 -0
  122. package/api/search/_words.d.mts +64 -0
  123. package/api/search/_words.mjs +157 -0
  124. package/api/search/search.d.mts +22 -305
  125. package/api/search/search.doc.mjs +8 -6
  126. package/api/search/search.mjs +56 -2482
  127. package/api/search/search.test.mjs +14 -14
  128. package/api/search/search.type.d.mts +6 -1
  129. package/api/search/search.type.mjs +6 -1
  130. package/api/search/tree.d.mts +15 -0
  131. package/api/search/tree.mjs +40 -0
  132. package/api/search/tree.test.mjs +66 -0
  133. package/api/search/tree.weights.json +1 -0
  134. package/api/theme/build/build.packed-old-core.test.mjs +1 -0
  135. package/api/upgrade/_adapter.d.mts +57 -9
  136. package/api/upgrade/_adapter.mjs +198 -28
  137. package/api/upgrade/registry/registry.d.mts +10 -4
  138. package/api/upgrade/registry/registry.mjs +33 -16
  139. package/api/upgrade/registry/registry.test.mjs +85 -0
  140. package/api/upgrade/run/run.d.mts +4 -2
  141. package/api/upgrade/run/run.mjs +13 -2
  142. package/api/upgrade/run/run.test.mjs +417 -3
  143. package/api/upgrade/upgrade.doc.mjs +10 -5
  144. package/api/upgrade/upgrade.mjs +13 -2
  145. package/api/upgrade/upgrade.test.mjs +194 -0
  146. package/api/upgrade/upgrade.type.d.mts +5 -3
  147. package/api/upgrade/upgrade.type.mjs +8 -6
  148. package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
  149. package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
  150. package/assets/docs/author-a-theme.doc.mjs +2 -2
  151. package/assets/docs/is-my-code-good.doc.mjs +287 -0
  152. package/assets/docs/tree/add-a-component.doc.mjs +1 -1
  153. package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
  154. package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
  155. package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
  156. package/assets/docs/tree/api.doc.mjs +6 -0
  157. package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
  158. package/assets/docs/tree/block-template.doc.mjs +1 -1
  159. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  160. package/assets/docs/tree/building-blocks.doc.mjs +2 -2
  161. package/assets/docs/tree/check-the-props.doc.mjs +1 -1
  162. package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
  163. package/assets/docs/tree/checks.doc.mjs +2 -2
  164. package/assets/docs/tree/cli-command.doc.mjs +1 -1
  165. package/assets/docs/tree/cli.doc.mjs +1 -1
  166. package/assets/docs/tree/codemods.doc.mjs +1 -1
  167. package/assets/docs/tree/component-family.doc.mjs +1 -1
  168. package/assets/docs/tree/component-imports.doc.mjs +1 -1
  169. package/assets/docs/tree/components.doc.mjs +1 -1
  170. package/assets/docs/tree/configuration.doc.mjs +1 -1
  171. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
  172. package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
  173. package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
  174. package/assets/docs/tree/docs.doc.mjs +1 -1
  175. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  176. package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
  177. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  178. package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
  179. package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
  180. package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
  181. package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
  182. package/assets/docs/tree/global-integrations.doc.mjs +2 -2
  183. package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
  184. package/assets/docs/tree/help.doc.mjs +2 -2
  185. package/assets/docs/tree/host-entry.doc.mjs +128 -0
  186. package/assets/docs/tree/links.doc.mjs +1 -1
  187. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  188. package/assets/docs/tree/page-template.doc.mjs +1 -1
  189. package/assets/docs/tree/publishing.doc.mjs +1 -1
  190. package/assets/docs/tree/quick-start.doc.mjs +1 -1
  191. package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
  192. package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
  193. package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
  194. package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
  195. package/assets/docs/tree/ship.doc.mjs +2 -2
  196. package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
  197. package/assets/docs/tree/single-component.doc.mjs +1 -1
  198. package/assets/docs/tree/start-a-template.doc.mjs +1 -1
  199. package/assets/docs/tree/subcomponent.doc.mjs +1 -1
  200. package/assets/docs/tree/template-assets.doc.mjs +1 -1
  201. package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
  202. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  203. package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
  204. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  205. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  206. package/assets/docs/tree/template-styles.doc.mjs +1 -1
  207. package/assets/docs/tree/templates.doc.mjs +1 -1
  208. package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
  209. package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
  210. package/assets/docs/tree/themes.doc.mjs +1 -1
  211. package/assets/docs/tree/tokens-data.doc.mjs +2 -2
  212. package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
  213. package/assets/docs/tree/upgrading.doc.mjs +1 -1
  214. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
  215. package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
  216. package/assets/docs/tree/versioning.doc.mjs +1 -1
  217. package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
  218. package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
  219. package/assets/docs/use-integrations.doc.mjs +120 -0
  220. package/assets/docs/working-with-ai.doc.mjs +6 -2
  221. package/assets/templates/themes/butter/butterTheme.ts +4 -2
  222. package/assets/templates/themes/stone/stoneTheme.ts +4 -2
  223. package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
  224. package/authoring/debug/parse.d.mts +1 -1
  225. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  226. package/authoring/integration/integration.doc.mjs +1 -1
  227. package/authoring/integration/type.ts +1 -1
  228. package/clients/cli/bin/astryx.mjs +7 -78
  229. package/clients/cli/command-result-coverage.test.mjs +6 -5
  230. package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
  231. package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
  232. package/clients/cli/commands/component.test.mjs +6 -6
  233. package/clients/cli/commands/docs.doc.mjs +2 -2
  234. package/clients/cli/commands/docs.mjs +1 -1
  235. package/clients/cli/commands/docs.test.mjs +14 -14
  236. package/clients/cli/commands/doctor.mjs +30 -0
  237. package/clients/cli/commands/doctor.test.mjs +65 -0
  238. package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
  239. package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
  240. package/clients/cli/commands/init.behavior.test.mjs +230 -1
  241. package/clients/cli/commands/init.doc.mjs +28 -9
  242. package/clients/cli/commands/init.flag-help.test.mjs +1 -0
  243. package/clients/cli/commands/init.mjs +2 -2
  244. package/clients/cli/commands/integration-check.test.mjs +48 -0
  245. package/clients/cli/commands/integration.doc.mjs +1 -1
  246. package/clients/cli/commands/manifest.doc.mjs +1 -1
  247. package/clients/cli/commands/manifest.mjs +67 -0
  248. package/clients/cli/commands/outside-project.test.mjs +2 -1
  249. package/clients/cli/commands/postinstall.doc.mjs +23 -0
  250. package/clients/cli/commands/postinstall.mjs +31 -0
  251. package/clients/cli/commands/setup-nudge.test.mjs +61 -0
  252. package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
  253. package/clients/cli/commands/upgrade.doc.mjs +4 -2
  254. package/clients/cli/commands/upgrade.mjs +9 -2
  255. package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
  256. package/clients/cli/index.mjs +29 -86
  257. package/clients/cli/lib/component-format.mjs +1 -1
  258. package/clients/cli/lib/define-command.mjs +12 -7
  259. package/clients/cli/lib/exit-codes.test.mjs +5 -0
  260. package/clients/cli/lib/manifest.test.mjs +12 -0
  261. package/clients/cli/lib/welcome-box.mjs +50 -0
  262. package/clients/cli/run.mjs +108 -0
  263. package/foundation/agent-docs/agent-doc-state.d.mts +20 -7
  264. package/foundation/agent-docs/agent-doc-state.mjs +35 -8
  265. package/foundation/agent-docs/agent-docs.d.mts +100 -12
  266. package/foundation/agent-docs/agent-docs.mjs +1012 -100
  267. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
  268. package/foundation/agent-docs/agent-docs.test.mjs +683 -39
  269. package/foundation/config/project.mjs +20 -22
  270. package/foundation/config/project.test.mjs +56 -0
  271. package/foundation/discovery/authoring-self-docs.d.mts +7 -0
  272. package/foundation/discovery/authoring-self-docs.mjs +16 -4
  273. package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
  274. package/foundation/discovery/authoring-surface.d.mts +1 -1
  275. package/foundation/discovery/authoring-surface.mjs +2 -2
  276. package/foundation/discovery/authoring-surface.test.mjs +1 -1
  277. package/foundation/discovery/cli-self-docs.d.mts +2 -1
  278. package/foundation/discovery/cli-self-docs.mjs +4 -3
  279. package/foundation/discovery/cli-self-docs.test.mjs +2 -2
  280. package/foundation/discovery/component-discovery.d.mts +37 -0
  281. package/foundation/discovery/component-discovery.mjs +80 -5
  282. package/foundation/discovery/component-loader.d.mts +1 -1
  283. package/foundation/discovery/docs-discovery.mjs +14 -1
  284. package/foundation/discovery/module-exports.d.mts +41 -0
  285. package/foundation/discovery/module-exports.mjs +253 -0
  286. package/foundation/discovery/runner-allowlist.d.mts +2 -4
  287. package/foundation/discovery/runner-allowlist.mjs +2 -4
  288. package/foundation/discovery/runner-commands.d.mts +77 -0
  289. package/foundation/discovery/runner-commands.mjs +294 -0
  290. package/foundation/discovery/runner-commands.test.mjs +128 -0
  291. package/foundation/discovery/stray-pointers.test.mjs +1 -1
  292. package/foundation/discovery/template-adapter.mjs +18 -1
  293. package/foundation/discovery/template-needs.mjs +1 -44
  294. package/foundation/discovery/theme-discovery.mjs +147 -3
  295. package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
  296. package/foundation/doc-compiler/read.mjs +59 -1
  297. package/foundation/doc-compiler/read.test.mjs +11 -2
  298. package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
  299. package/foundation/doc-compiler/tree.d.mts +32 -6
  300. package/foundation/doc-compiler/tree.mjs +77 -43
  301. package/foundation/doc-compiler/tree.test.mjs +7 -7
  302. package/foundation/fs/paths.d.mts +70 -8
  303. package/foundation/fs/paths.mjs +556 -38
  304. package/foundation/fs/paths.test.mjs +430 -54
  305. package/foundation/fs/read-record.d.mts +18 -0
  306. package/foundation/fs/read-record.mjs +131 -0
  307. package/foundation/fs/read-record.test.mjs +77 -0
  308. package/foundation/integrations/autolink.d.mts +2 -1
  309. package/foundation/integrations/autolink.mjs +4 -13
  310. package/foundation/integrations/computer-integrations.d.mts +6 -3
  311. package/foundation/integrations/computer-integrations.mjs +38 -9
  312. package/foundation/integrations/contribution-inventory.d.mts +15 -20
  313. package/foundation/integrations/contribution-inventory.mjs +41 -5
  314. package/foundation/integrations/integrations.d.mts +27 -1
  315. package/foundation/integrations/integrations.mjs +61 -2
  316. package/foundation/integrations/validate-contributions.d.mts +115 -0
  317. package/foundation/integrations/validate-contributions.mjs +1168 -13
  318. package/foundation/release/handoff.d.mts +23 -4
  319. package/foundation/release/handoff.mjs +175 -8
  320. package/foundation/release/run-context.mjs +14 -0
  321. package/foundation/response/response-types.doc.mjs +1 -1
  322. package/foundation/route/route.d.mts +285 -0
  323. package/foundation/route/route.mjs +324 -0
  324. package/foundation/route/route.test.mjs +153 -0
  325. package/foundation/runtime/hosted-runtime.test.mjs +403 -0
  326. package/foundation/runtime/locked-versions.d.mts +32 -0
  327. package/foundation/runtime/locked-versions.mjs +65 -0
  328. package/foundation/runtime/package-root.d.mts +91 -0
  329. package/foundation/runtime/package-root.mjs +174 -0
  330. package/foundation/runtime/package-set.d.mts +62 -0
  331. package/foundation/runtime/package-set.mjs +130 -0
  332. package/foundation/runtime/package-set.test.mjs +432 -0
  333. package/host/door-conformance.test.mjs +274 -0
  334. package/host/index.d.ts +116 -0
  335. package/host/index.mjs +295 -0
  336. package/host/index.test.mjs +302 -0
  337. package/package.json +14 -9
@@ -9,7 +9,7 @@
9
9
  * the one adoption rule in its package that matches its group and kind. A
10
10
  * placement that fails withdraws the doc; it never falls back to adoption. A
11
11
  * doc with neither is a flat topic: it keeps its flat name as its route, and its
12
- * home is the generated Unorganized level. The CLI keeps its own routes: an
12
+ * home is the generated level for its category. The CLI keeps its own routes: an
13
13
  * integration's node that would take one is withdrawn with a diagnostic.
14
14
  *
15
15
  * @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
@@ -117,19 +117,39 @@ export const KIND_GROUPS: Readonly<Record<string, {
117
117
  */
118
118
  /**
119
119
  * A flat topic: a reference topic that no namespace places. The tree gives it
120
- * a home in the generated Unorganized level, under its own name.
120
+ * a home in the generated level for its category (Guides or Foundations),
121
+ * under its own name.
121
122
  * @typedef {object} TreeTopicInput
122
123
  * @property {string} provider the package that owns the topic
123
124
  * @property {string} providerId the provider's ProviderId
124
125
  * @property {string} name the topic's name, which stays its route
125
126
  * @property {string} title
126
127
  * @property {string} summary
128
+ * @property {string | null} [category] the topic's sidebar group:
129
+ * `foundations` puts it in Foundations; anything else, in Guides
127
130
  * @property {string} source where the topic comes from, for diagnostics
128
131
  * @property {string[]} [aliases] every other name the topic answers to: the
129
132
  * topics it replaced, directly or through a chain
130
133
  */
131
- /** The route of the generated level that holds every flat topic. */
132
- export const UNORGANIZED: "unorganized";
134
+ /**
135
+ * The generated levels that hold the flat topics, by category
136
+ * (spec:AST-046 FR12). A topic keeps its own name as its route; its level is
137
+ * only where it sits. Readers see these titles in a topic's path, so each is
138
+ * a plain name for what the topics are.
139
+ */
140
+ export const TOPIC_LEVELS: Readonly<{
141
+ guides: Readonly<{
142
+ route: "guides";
143
+ title: "Guides";
144
+ summary: "Guides that stand on their own: getting started, principles, theming, and working with AI. Each topic keeps its own name; open one by it.";
145
+ }>;
146
+ foundations: Readonly<{
147
+ route: "foundations";
148
+ title: "Foundations";
149
+ summary: "Color, elevation, icons, illustrations, motion, shape, and spacing: the visual foundations every component builds on. Each topic keeps its own name; open one by it.";
150
+ }>;
151
+ }>;
152
+ export function topicLevel(category: string | null | undefined): "guides" | "foundations";
133
153
  export type NamespaceDoc = import("../../authoring/doctypes/namespace/type").NamespaceDoc;
134
154
  export type DocPlacement = import("../../authoring/doctypes/base/type").DocPlacement;
135
155
  export type CompilerDiagnostic = import("./diagnostics.mjs").CompilerDiagnostic;
@@ -200,7 +220,8 @@ export type TreeSlot = {
200
220
  };
201
221
  /**
202
222
  * A flat topic: a reference topic that no namespace places. The tree gives it
203
- * a home in the generated Unorganized level, under its own name.
223
+ * a home in the generated level for its category (Guides or Foundations),
224
+ * under its own name.
204
225
  */
205
226
  export type TreeTopicInput = {
206
227
  /**
@@ -217,6 +238,11 @@ export type TreeTopicInput = {
217
238
  name: string;
218
239
  title: string;
219
240
  summary: string;
241
+ /**
242
+ * the topic's sidebar group:
243
+ * `foundations` puts it in Foundations; anything else, in Guides
244
+ */
245
+ category?: string | null | undefined;
220
246
  /**
221
247
  * where the topic comes from, for diagnostics
222
248
  */
@@ -265,7 +291,7 @@ export type TreeNode = {
265
291
  order: number | null;
266
292
  /**
267
293
  * made by the compiler (a `groupBy: 'kind'`
268
- * level, or the Unorganized level), not authored
294
+ * level, or a flat topics' level), not authored
269
295
  */
270
296
  generated: boolean;
271
297
  /**
@@ -12,7 +12,7 @@
12
12
  * @position Between discovery and the readers: `astryx docs <route>`,
13
13
  * `astryx doctor`, and the docsite build all read this tree. The CLI's docs
14
14
  * and each integration's have a home here, and a flat topic's home is the
15
- * generated Unorganized level.
15
+ * generated level for its category: Guides or Foundations.
16
16
  * A namespace never scans files and never lists its children: a child names
17
17
  * its parent, or a namespace adopts a discovery group.
18
18
  */
@@ -113,20 +113,49 @@ export const KIND_GROUPS = Object.freeze({
113
113
 
114
114
  /**
115
115
  * A flat topic: a reference topic that no namespace places. The tree gives it
116
- * a home in the generated Unorganized level, under its own name.
116
+ * a home in the generated level for its category (Guides or Foundations),
117
+ * under its own name.
117
118
  * @typedef {object} TreeTopicInput
118
119
  * @property {string} provider the package that owns the topic
119
120
  * @property {string} providerId the provider's ProviderId
120
121
  * @property {string} name the topic's name, which stays its route
121
122
  * @property {string} title
122
123
  * @property {string} summary
124
+ * @property {string | null} [category] the topic's sidebar group:
125
+ * `foundations` puts it in Foundations; anything else, in Guides
123
126
  * @property {string} source where the topic comes from, for diagnostics
124
127
  * @property {string[]} [aliases] every other name the topic answers to: the
125
128
  * topics it replaced, directly or through a chain
126
129
  */
127
130
 
128
- /** The route of the generated level that holds every flat topic. */
129
- export const UNORGANIZED = 'unorganized';
131
+ /**
132
+ * The generated levels that hold the flat topics, by category
133
+ * (spec:AST-046 FR12). A topic keeps its own name as its route; its level is
134
+ * only where it sits. Readers see these titles in a topic's path, so each is
135
+ * a plain name for what the topics are.
136
+ */
137
+ export const TOPIC_LEVELS = Object.freeze({
138
+ guides: Object.freeze({
139
+ route: 'guides',
140
+ title: 'Guides',
141
+ summary:
142
+ 'Guides that stand on their own: getting started, principles, theming, and working with AI. Each topic keeps its own name; open one by it.',
143
+ }),
144
+ foundations: Object.freeze({
145
+ route: 'foundations',
146
+ title: 'Foundations',
147
+ summary:
148
+ 'Color, elevation, icons, illustrations, motion, shape, and spacing: the visual foundations every component builds on. Each topic keeps its own name; open one by it.',
149
+ }),
150
+ });
151
+
152
+ /**
153
+ * The generated level a flat topic sits in.
154
+ * @param {string | null | undefined} category
155
+ * @returns {'guides' | 'foundations'}
156
+ */
157
+ export const topicLevel = category =>
158
+ category === 'foundations' ? 'foundations' : 'guides';
130
159
 
131
160
  /**
132
161
  * @typedef {object} TreeNode
@@ -145,7 +174,7 @@ export const UNORGANIZED = 'unorganized';
145
174
  * @property {string | null} slot the parent slot this node sits in
146
175
  * @property {number | null} order
147
176
  * @property {boolean} generated made by the compiler (a `groupBy: 'kind'`
148
- * level, or the Unorganized level), not authored
177
+ * level, or a flat topics' level), not authored
149
178
  * @property {TreeSlot[]} slots a namespace's slots; empty for a leaf
150
179
  * @property {string} source
151
180
  * @property {any} [ref]
@@ -216,7 +245,7 @@ function resolveParent(parent, provider, declared) {
216
245
  * the one adoption rule in its package that matches its group and kind. A
217
246
  * placement that fails withdraws the doc; it never falls back to adoption. A
218
247
  * doc with neither is a flat topic: it keeps its flat name as its route, and its
219
- * home is the generated Unorganized level. The CLI keeps its own routes: an
248
+ * home is the generated level for its category. The CLI keeps its own routes: an
220
249
  * integration's node that would take one is withdrawn with a diagnostic.
221
250
  *
222
251
  * @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
@@ -237,10 +266,15 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
237
266
  );
238
267
 
239
268
  // Routes the CLI's own docs keep (spec:AST-046 FR11): the name of each of
240
- // its flat topics, and the generated Unorganized level. Its namespaces keep
241
- // theirs by rank, because they go into the tree first. Routes compare
242
- // without case, as topic names do, so `CLI` claims `cli`.
243
- const cliRoutes = new Set(topics.length > 0 ? [UNORGANIZED] : []);
269
+ // its flat topics, and the generated levels that hold flat topics. Its
270
+ // namespaces keep theirs by rank, because they go into the tree first.
271
+ // Routes compare without case, as topic names do, so `CLI` claims `cli`.
272
+ /** @type {Set<string>} */
273
+ const cliRoutes = new Set(
274
+ topics.length > 0
275
+ ? Object.values(TOPIC_LEVELS).map(level => level.route)
276
+ : [],
277
+ );
244
278
  for (const topic of topics) {
245
279
  if (topic.provider === CLI_PROVIDER)
246
280
  cliRoutes.add(topic.name.toLowerCase());
@@ -592,20 +626,21 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
592
626
  );
593
627
  }
594
628
 
595
- // The generated Unorganized level (spec:AST-046 FR12): every flat topic sits
596
- // here, in the order the topic list reads, so every doc has a home in the
597
- // tree. A topic keeps its own name as its route.
598
- if (topics.length > 0) {
629
+ // The generated levels (spec:AST-046 FR12): every flat topic sits in the
630
+ // level for its category, in the order the topic list reads, so every doc
631
+ // has a named home in the tree. A topic keeps its own name as its route.
632
+ for (const [key, level] of Object.entries(TOPIC_LEVELS)) {
633
+ const members = topics.filter(topic => topicLevel(topic.category) === key);
634
+ if (members.length === 0) continue;
599
635
  const home = {
600
636
  id: null,
601
- route: UNORGANIZED,
637
+ route: level.route,
602
638
  kind: 'namespace',
603
639
  provider: CLI_PROVIDER,
604
640
  providerId: CLI_PROVIDER_ID,
605
- name: UNORGANIZED,
606
- title: 'Unorganized',
607
- summary:
608
- 'Every topic that no section places yet. Each keeps its own name; open one by it.',
641
+ name: level.route,
642
+ title: level.title,
643
+ summary: level.summary,
609
644
  parent: null,
610
645
  slot: null,
611
646
  order: null,
@@ -613,30 +648,29 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
613
648
  slots: [{name: 'topics', title: 'Topics', children: []}],
614
649
  source: 'generated',
615
650
  };
616
- if (addNode(home, {provider: CLI_PROVIDER, source: 'generated'})) {
617
- topics.forEach((topic, i) => {
618
- addNode(
619
- {
620
- id: createDocId(topic.providerId, 'generic', topic.name),
621
- route: topic.name,
622
- kind: 'generic',
623
- provider: topic.provider,
624
- providerId: topic.providerId,
625
- name: topic.name,
626
- title: topic.title,
627
- summary: topic.summary,
628
- parent: UNORGANIZED,
629
- slot: 'topics',
630
- order: i,
631
- generated: false,
632
- slots: [],
633
- source: topic.source,
634
- ref: {flatTopic: topic.name},
635
- },
636
- topic,
637
- );
638
- });
639
- }
651
+ if (!addNode(home, {provider: CLI_PROVIDER, source: 'generated'})) continue;
652
+ members.forEach((topic, i) => {
653
+ addNode(
654
+ {
655
+ id: createDocId(topic.providerId, 'generic', topic.name),
656
+ route: topic.name,
657
+ kind: 'generic',
658
+ provider: topic.provider,
659
+ providerId: topic.providerId,
660
+ name: topic.name,
661
+ title: topic.title,
662
+ summary: topic.summary,
663
+ parent: level.route,
664
+ slot: 'topics',
665
+ order: i,
666
+ generated: false,
667
+ slots: [],
668
+ source: topic.source,
669
+ ref: {flatTopic: topic.name},
670
+ },
671
+ topic,
672
+ );
673
+ });
640
674
  }
641
675
 
642
676
  // Children, per slot, in reading order: order, then title, then id.
@@ -154,21 +154,21 @@ describe('buildDocsTree', () => {
154
154
  source: `${provider}/${name}.doc.mjs`,
155
155
  });
156
156
  const cliNs = {...ns('cli'), provider: CLI, providerId: CLI, source: `${CLI}/tree/cli.doc.mjs`};
157
- // An integration's topics named `CLI` and `UNORGANIZED` claim the CLI's
158
- // namespace and the generated level; both are withdrawn.
157
+ // An integration's topics named `CLI` and `GUIDES` claim the CLI's
158
+ // namespace and a generated level; both are withdrawn.
159
159
  const tree = buildDocsTree({
160
160
  namespaces: [cliNs],
161
161
  docs: [],
162
- topics: [topic('theme', CLI), topic('CLI'), topic('UNORGANIZED')],
162
+ topics: [topic('theme', CLI), topic('CLI'), topic('GUIDES')],
163
163
  });
164
164
  expect(tree.get('cli')?.provider).toBe(CLI);
165
- expect(tree.get('unorganized')?.provider).toBe(CLI);
165
+ expect(tree.get('guides')?.provider).toBe(CLI);
166
166
  expect(routes(tree)).not.toContain('CLI');
167
- expect(routes(tree)).not.toContain('UNORGANIZED');
167
+ expect(routes(tree)).not.toContain('GUIDES');
168
168
  expect(problems(tree)).toEqual(
169
169
  expect.arrayContaining([
170
170
  ['duplicate_route', expect.stringContaining('both have the route "CLI"')],
171
- ['duplicate_route', expect.stringContaining('takes the route "UNORGANIZED", which the CLI\'s own docs keep')],
171
+ ['duplicate_route', expect.stringContaining('takes the route "GUIDES", which the CLI\'s own docs keep')],
172
172
  ]),
173
173
  );
174
174
  // It names both docs as their authors know them, never by artifact id,
@@ -502,7 +502,7 @@ describe("the CLI's own docs tree", () => {
502
502
  async () => {
503
503
  const tree = await loadDocsTree({fresh: true});
504
504
  expect(tree.diagnostics).toEqual([]);
505
- expect(tree.roots().map(node => node.route)).toEqual(['cli', 'global', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography']);
505
+ expect(tree.roots().map(node => node.route)).toEqual(['authoring', 'cli', 'global', 'internationalization', 'layout', 'migration', 'styling', 'styling-libraries', 'tokens', 'typography']);
506
506
  // Every slot child is a node one level below the namespace that places
507
507
  // it, and every node but the root is placed. Read from the tree, so a
508
508
  // restructure of the guides does not need this test edited.
@@ -51,17 +51,58 @@ export function findCarriedCoreDir(startDir: string, { fetch }?: {
51
51
  fetch?: boolean;
52
52
  }): string | null;
53
53
  /**
54
- * Find packages/core directory by walking up from startDir.
55
- * Also checks node_modules/@astryxdesign/core for installed usage.
56
- *
57
- * The project's Core only: in the folder or four above it, the reach every
58
- * released version used, else from the folder of the package.json that makes
59
- * the folder part of a project, however deep the folder is.
54
+ * The project's own @astryxdesign/core, never a carried one: found from the
55
+ * folder (see {@link findNearbyCoreDir}), else from the folder of the
56
+ * package.json that makes the folder part of a project, however deep the
57
+ * folder is.
60
58
  *
61
59
  * @param {string} [startDir]
62
60
  * @returns {string | null}
63
61
  */
64
62
  export function findProjectCoreDir(startDir?: string): string | null;
63
+ /**
64
+ * The project root: the directory of the nearest package.json at or above
65
+ * `startDir`, or null when there is none.
66
+ *
67
+ * @param {string} startDir
68
+ * @returns {string|null}
69
+ */
70
+ export function findPackageRoot(startDir: string): string | null;
71
+ /**
72
+ * The Astryx project `startDir` belongs to: the nearest folder at or above it
73
+ * whose package.json declares an Astryx package (`@astryxdesign/*`, or the
74
+ * legacy `@xds/*`), or that a workspace whose root declares one lists as a
75
+ * member. The search stops at a repository root, and it ends at the home
76
+ * folder without counting it. Returns null when no folder qualifies.
77
+ *
78
+ * @param {string} startDir
79
+ * @returns {string|null}
80
+ */
81
+ export function findAstryxProject(startDir: string): string | null;
82
+ /**
83
+ * The workspace root (`spec:AST-048` FR15): the nearest directory at or above
84
+ * `startDir` that declares a workspace, by a `pnpm-workspace.yaml` or a
85
+ * package.json `workspaces` field; outside a workspace, the directory of the
86
+ * nearest package.json; with no package.json, `startDir` itself.
87
+ *
88
+ * @param {string} startDir
89
+ * @returns {string}
90
+ */
91
+ export function findWorkspaceRoot(startDir: string): string;
92
+ /**
93
+ * The nearest `node_modules/<name>` at or above `startDir`, found the way
94
+ * Node's resolver finds a package, and the folder whose node_modules holds it.
95
+ * It searches every folder up to the filesystem root and does not ask
96
+ * Plug'n'Play.
97
+ *
98
+ * @param {string} startDir
99
+ * @param {string} name bare package name; callers reject path segments first
100
+ * @returns {{packageDir: string, hostDir: string}|null}
101
+ */
102
+ export function findNodeModulesPackage(startDir: string, name: string): {
103
+ packageDir: string;
104
+ hostDir: string;
105
+ } | null;
65
106
  /**
66
107
  * Locate a package the project at `startDir` actually installed.
67
108
  *
@@ -73,14 +114,35 @@ export function findProjectCoreDir(startDir?: string): string | null;
73
114
  * Reading package.json off disk also sidesteps packages that don't export it,
74
115
  * so the version is always available to range-check.
75
116
  *
76
- * Walks the node_modules chain first, then asks PnP, which covers the Yarn
77
- * default layout where that chain does not exist.
117
+ * Searches the node_modules of `startDir` and the five folders above it, as
118
+ * released versions did, then on up to the workspace root of the Astryx
119
+ * project it belongs to. Then it asks PnP, which covers the Yarn default
120
+ * layout where that chain does not exist.
78
121
  *
79
122
  * @param {string} startDir
80
123
  * @param {string} name
81
124
  * @returns {string|null} the package directory, or null when not installed
82
125
  */
83
126
  export function findInstalledPackage(startDir: string, name: string): string | null;
127
+ /**
128
+ * The first of `names` the Astryx project of `startDir` installed, for a
129
+ * command that writes to the project (`upgrade`).
130
+ *
131
+ * It searches the node_modules of the project root, nearest name first. For
132
+ * a member its workspace lists, it then searches each folder above the
133
+ * project up to the workspace root, where the workspace installs the packages
134
+ * its members share; otherwise the search stops at the project root. Then it
135
+ * asks Plug'n'Play, in name order. With no Astryx project it looks only in the
136
+ * node_modules of `startDir` itself, as released versions did.
137
+ *
138
+ * @param {string} startDir
139
+ * @param {readonly string[]} names in order of preference
140
+ * @returns {{name: string, packageDir: string}|null}
141
+ */
142
+ export function findProjectPackageOf(startDir: string, names: readonly string[]): {
143
+ name: string;
144
+ packageDir: string;
145
+ } | null;
84
146
  /**
85
147
  * Find the monorepo root by looking for the root package.json
86
148
  * that has workspaces defined.