@astryxdesign/cli 0.6.3-canary.ea2f048 → 0.6.3-canary.ee13359

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 (571) hide show
  1. package/README.md +114 -76
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/build.doc.mjs +4 -3
  4. package/api/build/build.test.mjs +14 -3
  5. package/api/build/build.type.d.mts +36 -2
  6. package/api/build/build.type.mjs +25 -4
  7. package/api/build/help/help.d.mts +8 -5
  8. package/api/build/help/help.mjs +56 -6
  9. package/api/component/_adapter.d.mts +6 -12
  10. package/api/component/_adapter.mjs +20 -10
  11. package/api/component/component.doc.mjs +13 -3
  12. package/api/component/component.mjs +91 -14
  13. package/api/component/component.test.mjs +38 -0
  14. package/api/component/component.type.d.mts +22 -11
  15. package/api/component/component.type.mjs +32 -24
  16. package/api/component/detail/blocks/blocks.d.mts +2 -1
  17. package/api/component/detail/blocks/blocks.mjs +4 -3
  18. package/api/component/list/list.d.mts +0 -5
  19. package/api/component/list/list.mjs +40 -11
  20. package/api/discover/discover.doc.mjs +2 -1
  21. package/api/discover/discover.type.d.mts +4 -4
  22. package/api/discover/discover.type.mjs +10 -10
  23. package/api/docs/_adapter.d.mts +230 -41
  24. package/api/docs/_adapter.mjs +734 -108
  25. package/api/docs/compiled-topics.test.mjs +78 -0
  26. package/api/docs/detail/detail.mjs +22 -63
  27. package/api/docs/detail/section/section.d.mts +1 -1
  28. package/api/docs/detail/section/section.mjs +54 -19
  29. package/api/docs/detail/section/section.test.mjs +50 -0
  30. package/api/docs/docs.d.mts +10 -3
  31. package/api/docs/docs.doc.mjs +54 -16
  32. package/api/docs/docs.mjs +53 -10
  33. package/api/docs/docs.test.mjs +164 -4
  34. package/api/docs/docs.type.d.mts +205 -5
  35. package/api/docs/docs.type.mjs +137 -11
  36. package/api/docs/index/index.d.mts +18 -0
  37. package/api/docs/index/index.mjs +40 -0
  38. package/api/docs/index/index.test.mjs +62 -0
  39. package/api/docs/integration-tree.test.mjs +547 -0
  40. package/api/docs/integrationDocs.test.mjs +114 -8
  41. package/api/docs/list/list.mjs +28 -12
  42. package/api/docs/node/node.d.mts +43 -0
  43. package/api/docs/node/node.mjs +192 -0
  44. package/api/doctor/doctor.d.mts +99 -1
  45. package/api/doctor/doctor.doc.mjs +1 -0
  46. package/api/doctor/doctor.mjs +544 -1
  47. package/api/doctor/doctor.test.mjs +610 -1
  48. package/api/gap-report/gap-report.doc.mjs +8 -4
  49. package/api/hook/_adapter.mjs +19 -5
  50. package/api/hook/hook.doc.mjs +1 -0
  51. package/api/hook/hook.type.d.mts +3 -3
  52. package/api/hook/hook.type.mjs +11 -11
  53. package/api/hook/list/list.d.mts +2 -2
  54. package/api/hook/list/list.mjs +69 -17
  55. package/api/index.d.mts +1 -1
  56. package/api/index.mjs +1 -0
  57. package/api/init/init.doc.mjs +6 -1
  58. package/api/init/init.test.mjs +41 -1
  59. package/api/init/remove/remove.mjs +1 -1
  60. package/api/init/run/run.mjs +20 -10
  61. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  62. package/api/integration/add-contribution.d.mts +2 -1
  63. package/api/integration/add-contribution.mjs +130 -15
  64. package/api/integration/add-contribution.test.mjs +258 -7
  65. package/api/integration/add-theme.mjs +34 -64
  66. package/api/integration/add-theme.test.mjs +105 -21
  67. package/api/integration/authoring-checks.mjs +108 -31
  68. package/api/integration/authoring-checks.test.mjs +171 -6
  69. package/api/integration/authoring-checks.type.d.mts +3 -1
  70. package/api/integration/authoring-checks.type.mjs +3 -1
  71. package/api/integration/integration-authoring.type.d.mts +3 -1
  72. package/api/integration/integration-authoring.type.mjs +2 -0
  73. package/api/integration/integration-block-exports.test.mjs +10 -6
  74. package/api/integration/integrationAdd.doc.mjs +14 -4
  75. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  76. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  77. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  78. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  79. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  80. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  81. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  82. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  83. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  84. package/api/integration/integrationTemplateConflicts.doc.mjs +7 -5
  85. package/api/integration/pack-check.mjs +83 -7
  86. package/api/integration/pack-check.test.mjs +387 -47
  87. package/api/integration/pack-check.type.d.mts +26 -2
  88. package/api/integration/pack-check.type.mjs +14 -1
  89. package/api/integration/summarizeIssues.doc.mjs +1 -0
  90. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  91. package/api/integration/validate-integration.mjs +52 -102
  92. package/api/integration/validate-integration.test.mjs +179 -26
  93. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  94. package/api/integration/validateIntegration.doc.mjs +3 -2
  95. package/api/json/assertResponse.doc.mjs +1 -0
  96. package/api/json/envelope-types.test.mjs +76 -0
  97. package/api/json/index.ts +2 -0
  98. package/api/json/isError.doc.mjs +1 -0
  99. package/api/json/parseResponse.doc.mjs +3 -2
  100. package/api/layout/_adapter.mjs +20 -5
  101. package/api/layout/expand/expand.mjs +7 -5
  102. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  103. package/api/layout/grammar/grammar.mjs +2 -1
  104. package/api/layout/layoutCheck.doc.mjs +1 -0
  105. package/api/layout/layoutExpand.doc.mjs +2 -1
  106. package/api/layout/layoutGrammar.doc.mjs +1 -0
  107. package/api/search/search-return-type.test.mjs +54 -0
  108. package/api/search/search.d.mts +29 -11
  109. package/api/search/search.doc.mjs +8 -2
  110. package/api/search/search.mjs +337 -41
  111. package/api/search/search.test.mjs +124 -1
  112. package/api/search/search.type.d.mts +15 -3
  113. package/api/search/search.type.mjs +5 -2
  114. package/api/swizzle/copy/copy.mjs +28 -11
  115. package/api/swizzle/swizzle.doc.mjs +2 -1
  116. package/api/swizzle/swizzle.type.d.mts +2 -2
  117. package/api/swizzle/swizzle.type.mjs +2 -2
  118. package/api/template/copy/copy.mjs +17 -23
  119. package/api/template/copy/copy.test.mjs +17 -0
  120. package/api/template/list/list.mjs +1 -0
  121. package/api/template/template-integration.test.mjs +1022 -3
  122. package/api/template/template-suffix.test.mjs +41 -21
  123. package/api/template/template.d.mts +1 -1
  124. package/api/template/template.doc.mjs +30 -8
  125. package/api/template/template.mjs +45 -8
  126. package/api/template/template.type.d.mts +12 -14
  127. package/api/template/template.type.mjs +15 -14
  128. package/api/theme/_adapter.d.mts +2 -3
  129. package/api/theme/_adapter.mjs +4 -5
  130. package/api/theme/add/add.binary.test.mjs +84 -0
  131. package/api/theme/add/add.mjs +20 -3
  132. package/api/theme/add/add.staging.test.mjs +66 -0
  133. package/api/theme/add/add.test.mjs +14 -1
  134. package/api/theme/build/build.mjs +133 -42
  135. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  136. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  137. package/api/theme/build/build.test.mjs +127 -0
  138. package/api/theme/build/font-warning.mjs +3 -3
  139. package/api/theme/build/font-warning.test.mjs +5 -2
  140. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  141. package/api/theme/integration-themes.test.mjs +39 -28
  142. package/api/theme/list/list.test.mjs +19 -20
  143. package/api/theme/listThemes.doc.mjs +6 -5
  144. package/api/theme/palette/generate/generate.mjs +8 -3
  145. package/api/theme/palette/generate/generate.test.mjs +96 -0
  146. package/api/theme/palette/generate/generator.d.mts +10 -13
  147. package/api/theme/palette/generate/generator.mjs +15 -4
  148. package/api/theme/palette/generate/generator.test.mjs +10 -0
  149. package/api/theme/template/template.mjs +11 -2
  150. package/api/theme/template/template.test.mjs +20 -0
  151. package/api/theme/theme.type.d.mts +170 -11
  152. package/api/theme/theme.type.mjs +94 -27
  153. package/api/theme/themeAdd.doc.mjs +4 -3
  154. package/api/theme/themeBuild.doc.mjs +8 -4
  155. package/api/theme/themeList.doc.mjs +6 -3
  156. package/api/theme/themeListAvailable.doc.mjs +5 -3
  157. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  158. package/api/theme/themeTargets.doc.mjs +1 -0
  159. package/api/theme/themeTemplate.doc.mjs +6 -2
  160. package/api/upgrade/_adapter.d.mts +32 -5
  161. package/api/upgrade/_adapter.mjs +139 -22
  162. package/api/upgrade/list/list.mjs +2 -1
  163. package/api/upgrade/list/list.test.mjs +73 -0
  164. package/api/upgrade/project-context.test.mjs +272 -0
  165. package/api/upgrade/provider-agreement.test.mjs +152 -0
  166. package/api/upgrade/run/run.mjs +356 -59
  167. package/api/upgrade/status/status.mjs +2 -2
  168. package/api/upgrade/upgrade.doc.mjs +12 -5
  169. package/api/upgrade/upgrade.type.d.mts +43 -5
  170. package/api/upgrade/upgrade.type.mjs +27 -11
  171. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  172. package/assets/codemods/integration-discovery.mjs +48 -4
  173. package/assets/codemods/integration-discovery.test.mjs +73 -0
  174. package/assets/codemods/integration-runner.mjs +56 -4
  175. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  176. package/assets/codemods/run-codemod.mjs +177 -34
  177. package/assets/codemods/runner.mjs +350 -102
  178. package/assets/codemods/term-log.mjs +32 -8
  179. package/assets/codemods/term-log.test.mjs +19 -1
  180. package/assets/codemods/transform-prop.mjs +109 -0
  181. package/assets/codemods/transform-prop.test.mjs +95 -0
  182. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  183. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  184. package/assets/codemods/transforms/next/index.mjs +19 -1
  185. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  186. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  187. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  188. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  189. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  190. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  191. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  192. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  193. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  194. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  195. package/assets/docs/README.md +9 -0
  196. package/assets/docs/authoring.doc.mjs +14 -0
  197. package/assets/docs/getting-started.doc.mjs +2 -2
  198. package/assets/docs/principles.doc.mjs +6 -6
  199. package/assets/docs/styling-libraries.doc.mjs +3 -3
  200. package/assets/docs/styling.doc.mjs +4 -4
  201. package/assets/docs/theme.doc.mjs +4 -4
  202. package/assets/docs/tokens.doc.mjs +1 -1
  203. package/assets/docs/tree/api.doc.mjs +30 -0
  204. package/assets/docs/tree/cli.doc.mjs +23 -0
  205. package/assets/docs/tree/commands.doc.mjs +25 -0
  206. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +124 -25
  207. package/assets/docs/tree/integrations.test.mjs +62 -0
  208. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  209. package/assets/docs/working-with-ai.doc.mjs +1 -1
  210. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  211. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  212. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  213. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  214. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  215. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  216. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  217. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  218. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  219. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  220. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  221. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  222. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  223. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  224. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  225. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  226. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  227. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  228. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  229. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  230. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  231. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  232. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  233. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  234. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  235. package/authoring/_shared/contract.ts +22 -0
  236. package/authoring/codemod/codemod.doc.mjs +7 -2
  237. package/authoring/codemod/parse.d.mts +8 -8
  238. package/authoring/codemod/parse.mjs +8 -6
  239. package/authoring/codemod/type.ts +12 -0
  240. package/authoring/config/config.doc.mjs +2 -2
  241. package/authoring/config/debug-composition.test.mjs +92 -0
  242. package/authoring/config/parse.d.mts +13 -13
  243. package/authoring/config/parse.mjs +8 -8
  244. package/authoring/config/type.ts +18 -6
  245. package/authoring/debug/debug.doc.d.mts +11 -0
  246. package/authoring/debug/debug.doc.mjs +182 -0
  247. package/authoring/debug/parse.d.mts +8 -8
  248. package/authoring/debug/parse.mjs +3 -3
  249. package/authoring/doctypes/_schema.d.mts +718 -23
  250. package/authoring/doctypes/_schema.mjs +519 -39
  251. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  252. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  253. package/authoring/doctypes/base/type.ts +41 -0
  254. package/authoring/doctypes/command/command.doc.mjs +4 -3
  255. package/authoring/doctypes/command/parse.d.mts +2 -2
  256. package/authoring/doctypes/command/parse.mjs +1 -1
  257. package/authoring/doctypes/command/type.ts +5 -4
  258. package/authoring/doctypes/component/component.doc.mjs +6 -3
  259. package/authoring/doctypes/component/parse.d.mts +2 -2
  260. package/authoring/doctypes/component/parse.mjs +1 -1
  261. package/authoring/doctypes/component/type.ts +6 -5
  262. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  263. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  264. package/authoring/doctypes/enum/parse.d.mts +2 -2
  265. package/authoring/doctypes/enum/parse.mjs +1 -1
  266. package/authoring/doctypes/enum/type.ts +4 -2
  267. package/authoring/doctypes/function/function.doc.mjs +7 -2
  268. package/authoring/doctypes/function/parse.d.mts +2 -2
  269. package/authoring/doctypes/function/parse.mjs +1 -1
  270. package/authoring/doctypes/function/type.ts +9 -4
  271. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  272. package/authoring/doctypes/hook/parse.d.mts +2 -2
  273. package/authoring/doctypes/hook/parse.mjs +1 -1
  274. package/authoring/doctypes/hook/type.ts +5 -4
  275. package/authoring/doctypes/legacy.d.mts +8 -6
  276. package/authoring/doctypes/legacy.mjs +5 -4
  277. package/authoring/doctypes/load-contract.test.mjs +208 -0
  278. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  279. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  280. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  281. package/authoring/doctypes/namespace/parse.mjs +25 -0
  282. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  283. package/authoring/doctypes/namespace/type.ts +74 -0
  284. package/authoring/doctypes/parse.d.mts +22 -18
  285. package/authoring/doctypes/parse.mjs +22 -11
  286. package/authoring/doctypes/parse.test.mjs +77 -3
  287. package/authoring/doctypes/reference/parse.d.mts +2 -2
  288. package/authoring/doctypes/reference/parse.mjs +8 -5
  289. package/authoring/doctypes/reference/reference.doc.mjs +20 -5
  290. package/authoring/doctypes/reference/type.ts +53 -5
  291. package/authoring/doctypes/schema/parse.d.mts +2 -2
  292. package/authoring/doctypes/schema/parse.mjs +1 -1
  293. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  294. package/authoring/doctypes/schema/type.ts +4 -4
  295. package/authoring/doctypes/template/parse.d.mts +94 -1
  296. package/authoring/doctypes/template/parse.mjs +40 -2
  297. package/authoring/doctypes/template/parse.test.mjs +26 -2
  298. package/authoring/doctypes/template/template.doc.mjs +13 -3
  299. package/authoring/doctypes/template/type.ts +13 -2
  300. package/authoring/doctypes/theme/parse.d.mts +35 -0
  301. package/authoring/doctypes/theme/parse.mjs +76 -0
  302. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  303. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  304. package/authoring/doctypes/theme/type.ts +42 -0
  305. package/authoring/doctypes/types.ts +12 -10
  306. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  307. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  308. package/authoring/gap-report/parse.d.mts +10 -10
  309. package/authoring/gap-report/parse.mjs +6 -6
  310. package/authoring/gap-report/type.ts +1 -1
  311. package/authoring/identity/identity.doc.d.mts +9 -0
  312. package/authoring/identity/identity.doc.mjs +61 -0
  313. package/authoring/identity/type.ts +132 -0
  314. package/authoring/index.d.mts +2 -0
  315. package/authoring/index.d.ts +52 -17
  316. package/authoring/index.mjs +3 -1
  317. package/authoring/integration/integration.doc.mjs +15 -8
  318. package/authoring/integration/parse.d.mts +2 -2
  319. package/authoring/integration/parse.mjs +1 -1
  320. package/authoring/integration/parse.test.mjs +10 -1
  321. package/authoring/integration/schema.d.mts +6 -4
  322. package/authoring/integration/schema.mjs +9 -3
  323. package/authoring/integration/type.ts +19 -8
  324. package/authoring/shadcn/receipt.d.mts +6 -6
  325. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  326. package/clients/cli/command-load-failure.test.mjs +83 -0
  327. package/clients/cli/commands/blog.doc.mjs +1 -1
  328. package/clients/cli/commands/blog.mjs +23 -8
  329. package/clients/cli/commands/blog.test.mjs +42 -1
  330. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  331. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  332. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  333. package/clients/cli/commands/build-theme.mjs +16 -50
  334. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  335. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  336. package/clients/cli/commands/build.doc.mjs +5 -2
  337. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  338. package/clients/cli/commands/build.mjs +37 -49
  339. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  340. package/clients/cli/commands/build.text-fields.test.mjs +40 -0
  341. package/clients/cli/commands/component/index.mjs +3 -8
  342. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  343. package/clients/cli/commands/component-package.test.mjs +46 -0
  344. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  345. package/clients/cli/commands/component.doc.mjs +1 -1
  346. package/clients/cli/commands/component.test.mjs +19 -0
  347. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  348. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  349. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  350. package/clients/cli/commands/discover.doc.mjs +5 -3
  351. package/clients/cli/commands/discover.mjs +4 -4
  352. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  353. package/clients/cli/commands/docs.doc.mjs +28 -6
  354. package/clients/cli/commands/docs.mjs +238 -24
  355. package/clients/cli/commands/docs.test.mjs +193 -1
  356. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  357. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  358. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  359. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  360. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  361. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  362. package/clients/cli/commands/doctor-integration.test.mjs +83 -8
  363. package/clients/cli/commands/doctor.doc.mjs +1 -1
  364. package/clients/cli/commands/doctor.mjs +30 -25
  365. package/clients/cli/commands/doctor.test.mjs +42 -0
  366. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  367. package/clients/cli/commands/gap-report.test.mjs +72 -0
  368. package/clients/cli/commands/hook/index.mjs +7 -17
  369. package/clients/cli/commands/hook.doc.mjs +1 -1
  370. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  371. package/clients/cli/commands/init.doc.mjs +20 -9
  372. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  373. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  374. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  375. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  376. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  377. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  378. package/clients/cli/commands/integration.doc.mjs +1 -1
  379. package/clients/cli/commands/integration.mjs +1 -0
  380. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  381. package/clients/cli/commands/json-contract.test.mjs +33 -0
  382. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  383. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  384. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  385. package/clients/cli/commands/layout.doc.mjs +3 -3
  386. package/clients/cli/commands/layout.mjs +21 -9
  387. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  388. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  389. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  390. package/clients/cli/commands/manifest.doc.mjs +1 -1
  391. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  392. package/clients/cli/commands/search.doc.mjs +7 -4
  393. package/clients/cli/commands/search.mjs +28 -9
  394. package/clients/cli/commands/search.test.mjs +75 -0
  395. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  396. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  397. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  398. package/clients/cli/commands/template.doc.mjs +52 -13
  399. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  400. package/clients/cli/commands/template.mjs +4 -91
  401. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  402. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  403. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  404. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  405. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  406. package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
  407. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  408. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  409. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  410. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  411. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  412. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  413. package/clients/cli/commands/theme.doc.mjs +1 -1
  414. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  415. package/clients/cli/commands/upgrade.doc.mjs +22 -10
  416. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  417. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  418. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  419. package/clients/cli/commands/upgrade.mjs +29 -7
  420. package/clients/cli/formatters/index.mjs +164 -1
  421. package/clients/cli/formatters/index.test.mjs +97 -0
  422. package/clients/cli/index.mjs +21 -30
  423. package/clients/cli/latest-version-env.test.mjs +50 -0
  424. package/clients/cli/lib/cli-error.test.mjs +7 -0
  425. package/clients/cli/lib/component-format.mjs +9 -9
  426. package/clients/cli/lib/component-format.test.mjs +1 -1
  427. package/clients/cli/lib/define-command.mjs +32 -6
  428. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  429. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  430. package/clients/cli/lib/hook-format.mjs +19 -10
  431. package/clients/cli/lib/json-shim.mjs +38 -2
  432. package/clients/cli/lib/json-shim.test.mjs +83 -0
  433. package/clients/cli/lib/manifest.d.ts +2 -0
  434. package/clients/cli/lib/manifest.mjs +36 -2
  435. package/clients/cli/lib/manifest.test.mjs +17 -0
  436. package/foundation/agent-docs/agent-docs.d.mts +4 -0
  437. package/foundation/agent-docs/agent-docs.mjs +70 -3
  438. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  439. package/foundation/agent-docs/agent-docs.test.mjs +10 -1
  440. package/foundation/config/integration-debug.test.mjs +28 -3
  441. package/foundation/config/project-themes.test.mjs +11 -19
  442. package/foundation/config/project.d.mts +20 -11
  443. package/foundation/config/project.mjs +263 -91
  444. package/foundation/config/project.test.mjs +270 -21
  445. package/foundation/discovery/authoring-self-docs.d.mts +75 -0
  446. package/foundation/discovery/authoring-self-docs.mjs +224 -0
  447. package/foundation/discovery/authoring-self-docs.test.mjs +165 -0
  448. package/foundation/discovery/authoring-surface.d.mts +74 -0
  449. package/foundation/discovery/authoring-surface.mjs +525 -0
  450. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  451. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  452. package/foundation/discovery/cli-self-docs.mjs +490 -0
  453. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  454. package/foundation/discovery/component-discovery.d.mts +39 -1
  455. package/foundation/discovery/component-discovery.mjs +50 -1
  456. package/foundation/discovery/component-loader.d.mts +35 -38
  457. package/foundation/discovery/component-loader.mjs +53 -222
  458. package/foundation/discovery/docs-discovery.d.mts +116 -11
  459. package/foundation/discovery/docs-discovery.mjs +389 -108
  460. package/foundation/discovery/docs-discovery.test.mjs +325 -20
  461. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  462. package/foundation/discovery/docs-output-budget.mjs +50 -0
  463. package/foundation/discovery/docs-section-key.d.mts +116 -0
  464. package/foundation/discovery/docs-section-key.mjs +322 -0
  465. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  466. package/foundation/discovery/template-adapter.d.mts +113 -11
  467. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  468. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  469. package/foundation/discovery/template-adapter.mjs +774 -83
  470. package/foundation/discovery/template-adapter.test.mjs +57 -0
  471. package/foundation/discovery/theme-discovery.d.mts +67 -7
  472. package/foundation/discovery/theme-discovery.mjs +916 -186
  473. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  474. package/foundation/discovery/theming-targets.test.mjs +4 -0
  475. package/foundation/doc-compiler/bundle.d.mts +47 -0
  476. package/foundation/doc-compiler/bundle.mjs +278 -0
  477. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  478. package/foundation/doc-compiler/compile.d.mts +343 -0
  479. package/foundation/doc-compiler/compile.mjs +558 -0
  480. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  481. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  482. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  483. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  484. package/foundation/doc-compiler/import.d.mts +24 -0
  485. package/foundation/doc-compiler/import.mjs +59 -0
  486. package/foundation/doc-compiler/inputs.d.mts +102 -0
  487. package/foundation/doc-compiler/inputs.mjs +291 -0
  488. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  489. package/foundation/doc-compiler/ir.d.mts +22 -0
  490. package/foundation/doc-compiler/ir.mjs +471 -0
  491. package/foundation/doc-compiler/lenses.d.mts +34 -0
  492. package/foundation/doc-compiler/lenses.mjs +128 -0
  493. package/foundation/doc-compiler/links.d.mts +135 -0
  494. package/foundation/doc-compiler/links.mjs +253 -0
  495. package/foundation/doc-compiler/links.test.mjs +139 -0
  496. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  497. package/foundation/doc-compiler/overlays.d.mts +37 -0
  498. package/foundation/doc-compiler/overlays.mjs +206 -0
  499. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  500. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  501. package/foundation/doc-compiler/read.d.mts +127 -0
  502. package/foundation/doc-compiler/read.mjs +325 -0
  503. package/foundation/doc-compiler/read.test.mjs +313 -0
  504. package/foundation/doc-compiler/source.d.mts +33 -0
  505. package/foundation/doc-compiler/source.mjs +128 -0
  506. package/foundation/doc-compiler/tree.d.mts +288 -0
  507. package/foundation/doc-compiler/tree.mjs +876 -0
  508. package/foundation/doc-compiler/tree.test.mjs +598 -0
  509. package/foundation/fs/file-protection.d.mts +33 -0
  510. package/foundation/fs/file-protection.mjs +825 -0
  511. package/foundation/fs/file-protection.test.mjs +250 -0
  512. package/foundation/fs/module-loader.d.mts +1 -0
  513. package/foundation/fs/module-loader.mjs +50 -1
  514. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  515. package/foundation/fs/path-safety.d.mts +3 -2
  516. package/foundation/fs/path-safety.mjs +49 -19
  517. package/foundation/fs/path-safety.test.mjs +50 -0
  518. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  519. package/foundation/identity/provider-identity.d.mts +90 -0
  520. package/foundation/identity/provider-identity.mjs +320 -0
  521. package/foundation/identity/provider-identity.test.mjs +254 -0
  522. package/foundation/identity/providers.d.mts +7 -0
  523. package/foundation/identity/providers.mjs +16 -0
  524. package/foundation/integrations/autolink.d.mts +58 -1
  525. package/foundation/integrations/autolink.mjs +143 -45
  526. package/foundation/integrations/autolink.test.mjs +1 -1
  527. package/foundation/integrations/cli-requirement.d.mts +45 -0
  528. package/foundation/integrations/cli-requirement.mjs +154 -0
  529. package/foundation/integrations/cli-requirement.test.mjs +109 -0
  530. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  531. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  532. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  533. package/foundation/integrations/contribution-inventory.mjs +27 -24
  534. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  535. package/foundation/integrations/integration-warnings.d.mts +9 -2
  536. package/foundation/integrations/integration-warnings.mjs +52 -21
  537. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  538. package/foundation/integrations/integrations.d.mts +49 -2
  539. package/foundation/integrations/integrations.mjs +81 -8
  540. package/foundation/integrations/integrations.test.mjs +384 -1
  541. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  542. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  543. package/foundation/integrations/provider-resolution.d.mts +152 -0
  544. package/foundation/integrations/provider-resolution.mjs +576 -0
  545. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  546. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  547. package/foundation/integrations/theme-descriptor.mjs +44 -0
  548. package/foundation/integrations/validate-contributions.d.mts +2 -0
  549. package/foundation/integrations/validate-contributions.mjs +131 -29
  550. package/foundation/response/base.d.ts +8 -4
  551. package/foundation/response/error-codes.d.mts +3 -1
  552. package/foundation/response/error-codes.d.ts +2 -0
  553. package/foundation/response/error-codes.doc.mjs +13 -4
  554. package/foundation/response/error-codes.mjs +8 -2
  555. package/foundation/response/error-codes.test.mjs +137 -10
  556. package/foundation/response/json-contract.test.mjs +57 -17
  557. package/foundation/response/json.d.mts +4 -2
  558. package/foundation/response/json.mjs +8 -10
  559. package/foundation/response/response-types.doc.mjs +26 -16
  560. package/foundation/response/response-types.doc.test.mjs +158 -0
  561. package/foundation/response/response.doc.mjs +1 -1
  562. package/foundation/text/string-utils.mjs +22 -10
  563. package/foundation/xle/expand.d.mts +2 -0
  564. package/foundation/xle/expand.mjs +4 -3
  565. package/foundation/xle/expand.test.mjs +54 -0
  566. package/foundation/xle/xle.test.mjs +13 -0
  567. package/package.json +10 -11
  568. package/assets/templates/themes/manifest.json +0 -95
  569. package/clients/cli/lib/update-check.mjs +0 -83
  570. package/clients/cli/lib/update-check.test.mjs +0 -137
  571. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -50,11 +50,11 @@
50
50
  * queries they have nothing to do with.
51
51
  */
52
52
 
53
- import {pathToFileURL} from 'node:url';
53
+ import {readDocView} from '../../foundation/doc-compiler/read.mjs';
54
54
  import {findCoreDir} from '../../foundation/fs/paths.mjs';
55
55
  import {
56
56
  discoverComponents,
57
- discoverIntegrationComponents,
57
+ discoverValidIntegrationComponents,
58
58
  findComponentReadme,
59
59
  resolveImportPath,
60
60
  resolveIntegrationImportPath,
@@ -66,7 +66,20 @@ import {
66
66
  import {loadIntegrationsSafely} from '../component/_adapter.mjs';
67
67
  import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
68
68
  import {discoverTemplates, extractComponents} from '../template/template.mjs';
69
- import {loadDocsCatalog, loadTopicDoc} from '../docs/_adapter.mjs';
69
+ import {templateLookupIds} from '../../foundation/discovery/template-adapter.mjs';
70
+ import {
71
+ guideEntry,
72
+ loadDocsCatalog,
73
+ lowerTopic,
74
+ projectTree,
75
+ holdsOwnName,
76
+ } from '../docs/_adapter.mjs';
77
+ import {unlinkText} from '../../foundation/doc-compiler/links.mjs';
78
+ import {nodeView} from '../docs/node/node.mjs';
79
+ import {
80
+ sectionKey,
81
+ sectionSummary,
82
+ } from '../../foundation/discovery/docs-section-key.mjs';
70
83
  import {AstryxError} from '../error.mjs';
71
84
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
72
85
  import {setResultCoverage} from './coverage.mjs';
@@ -84,8 +97,18 @@ import {setResultCoverage} from './coverage.mjs';
84
97
  * @property {string[]} [guidance]
85
98
  * @property {string} [_import]
86
99
  * @property {string} [_title]
100
+ * @property {string} [_topic] - A doc result's topic or docs-tree route.
101
+ * @property {string} [_section] - A doc result's section key, when it is one section.
102
+ * @property {string} [_command] - The command that reads exactly this doc part.
103
+ * @property {string} [_parent] - The command that opens the level above a doc
104
+ * part: its topic's section list, or the docs-tree namespace it sits in.
105
+ * @property {string} [_package] - The npm package that authored a docs-tree
106
+ * doc part. Flat topics carry none: an extension's sections can come from
107
+ * another package.
87
108
  * @property {string} [_displayName]
88
109
  * @property {'page'|'block'} [_kind]
110
+ * @property {string} [_resultName]
111
+ * @property {string} [_commandName]
89
112
  */
90
113
 
91
114
  /**
@@ -528,16 +551,26 @@ export function scoreCandidate(
528
551
  }
529
552
 
530
553
  /**
531
- * Load a doc module's `docs`/`doc` export, swallowing errors.
554
+ * A component or hook doc, compiled, or null when it cannot be read.
532
555
  * @param {string} docPath
533
556
  * @param {string} [exportName]
557
+ * @param {'components' | 'hooks'} [root]
534
558
  * @returns {Promise<any>}
535
559
  */
536
- async function loadModuleDoc(docPath, exportName = 'docs') {
560
+ async function loadModuleDoc(
561
+ docPath,
562
+ exportName = 'docs',
563
+ root = 'components',
564
+ ) {
537
565
  try {
538
- const mod = await import(pathToFileURL(docPath).href);
539
566
  // Support both the stamped default export and the legacy named export.
540
- return mod?.default ?? mod[exportName] ?? null;
567
+ return (
568
+ (await readDocView(docPath, {
569
+ root,
570
+ loader: 'native',
571
+ exports: ['default', exportName],
572
+ })) ?? null
573
+ );
541
574
  } catch {
542
575
  return null;
543
576
  }
@@ -637,7 +670,8 @@ async function gatherIntegrationComponents(cwd) {
637
670
  /** @type {Candidate[]} */
638
671
  const candidates = [];
639
672
  for (const integration of loadedIntegrations) {
640
- for (const rec of discoverIntegrationComponents(integration)) {
673
+ const {components} = await discoverValidIntegrationComponents(integration);
674
+ for (const rec of components) {
641
675
  const doc = await loadModuleDoc(rec.docPath);
642
676
  candidates.push({
643
677
  domain: 'component',
@@ -701,7 +735,7 @@ async function gatherHooks(coreDir) {
701
735
  let description = '';
702
736
  let importPath = '@astryxdesign/core/hooks';
703
737
  if (docPath) {
704
- const doc = await loadModuleDoc(docPath);
738
+ const doc = await loadModuleDoc(docPath, 'docs', 'hooks');
705
739
  if (doc) {
706
740
  keywords = Array.isArray(doc.keywords) ? doc.keywords : [];
707
741
  description = doc.usage?.description || doc.description || '';
@@ -720,7 +754,11 @@ async function gatherHooks(coreDir) {
720
754
  }
721
755
 
722
756
  /**
723
- * Build doc-topic candidates: topic name + description + section prose.
757
+ * Build doc candidates at the grain a reader reads them: each section of a
758
+ * topic, whose command reads just that section; each topic as a whole, whose
759
+ * command lists its sections; and each docs-tree node by its route. The tree's
760
+ * guides split into sections like topics, and its typed docs also match by
761
+ * their own name, so `assertResponse` finds `cli/api/functions/assert-response`.
724
762
  *
725
763
  * Reads the project's catalog rather than the CLI's own docs directory, so a
726
764
  * topic an integration contributed (or replaced) is searchable exactly like a
@@ -732,44 +770,274 @@ async function gatherHooks(coreDir) {
732
770
  async function gatherDocs(cwd) {
733
771
  /** @type {Candidate[]} */
734
772
  const candidates = [];
735
- let entries;
773
+ let catalog;
736
774
  try {
737
- entries = (await loadDocsCatalog(cwd)).entries();
775
+ catalog = await loadDocsCatalog(cwd);
738
776
  } catch {
739
777
  return candidates;
740
778
  }
741
- for (const entry of entries) {
742
- let doc = null;
779
+ let tree = null;
780
+ try {
781
+ tree = await projectTree(catalog);
782
+ } catch {
783
+ // `astryx doctor` reports a tree that fails to build; search still
784
+ // indexes the topics.
785
+ }
786
+ for (const entry of catalog.entries()) {
787
+ // A topic whose name opens another doc (spec:AST-046 FR11) is not
788
+ // offered: every hit's command must open the hit.
789
+ if (tree && !holdsOwnName(tree, catalog, entry)) continue;
790
+ let lowered = null;
743
791
  try {
744
- doc = await loadTopicDoc(entry);
792
+ lowered = await lowerTopic(catalog, entry);
745
793
  } catch {
746
794
  // A topic that cannot be loaded is reported by the commands that own
747
795
  // integration issues; search just cannot index it.
748
796
  }
749
- let description = '';
750
- /** @type {string[]} */
751
- const prose = [];
752
- if (doc) {
753
- description = doc.description || '';
754
- for (const section of doc.sections || []) {
755
- if (section.title) prose.push(section.title);
756
- for (const block of section.content || []) {
757
- if (block.type === 'prose' && block.text) prose.push(block.text);
758
- }
797
+ const doc = lowered?.doc ?? null;
798
+ // A flat topic lives in the Unorganized level; its hits say so, and name
799
+ // the package each section came from.
800
+ const home = tree?.get(entry.name);
801
+ const placed = home?.ref?.flatTopic === entry.name ? home : null;
802
+ /** @type {Map<string, string>} */
803
+ const packages = new Map([
804
+ [entry.providerId ?? entry.package, entry.package],
805
+ ...entry.extensions.map(
806
+ ext => /** @type {[string, string]} */ ([ext.providerId ?? ext.package, ext.package]),
807
+ ),
808
+ ]);
809
+ candidates.push(
810
+ ...topicCandidates(
811
+ entry.name,
812
+ doc,
813
+ entry.title,
814
+ '',
815
+ placed && tree
816
+ ? [
817
+ ...tree.ancestors(placed).map(a => a.title),
818
+ doc?.title || entry.title || entry.name,
819
+ ].join(' › ')
820
+ : undefined,
821
+ placed ? `astryx docs ${placed.parent}` : undefined,
822
+ entry.package,
823
+ key =>
824
+ packages.get(lowered?.sectionProviders?.[key] ?? '') ?? entry.package,
825
+ ),
826
+ );
827
+ }
828
+ if (tree == null) return candidates;
829
+ for (const node of tree.nodes.values()) {
830
+ // A flat topic is indexed above, as a topic.
831
+ if (node.ref?.flatTopic) continue;
832
+ // A tree hit names where it lives: its ancestors' titles, then its own.
833
+ const path = [...tree.ancestors(node).map(a => a.title), node.title];
834
+ if (node.kind === 'generic') {
835
+ let doc = null;
836
+ try {
837
+ doc = (await lowerTopic(catalog, guideEntry(node))).doc;
838
+ } catch {
839
+ // As above: the owning commands report it.
759
840
  }
841
+ candidates.push(
842
+ ...topicCandidates(
843
+ node.route,
844
+ doc,
845
+ node.title,
846
+ node.summary,
847
+ path.join(' › '),
848
+ node.parent == null ? undefined : `astryx docs ${node.parent}`,
849
+ node.provider,
850
+ ),
851
+ );
852
+ continue;
853
+ }
854
+ const selfDoc = /** @type {any} */ (node.ref)?.selfDoc;
855
+ // A typed doc's content is what `astryx docs <route>` prints. The first
856
+ // column of its tables names what the doc defines (an error code, an
857
+ // option, a parameter), so each is a keyword the doc answers to.
858
+ /** @type {any[]} */
859
+ const content = (await nodeView(catalog, tree, node)).content ?? [];
860
+ /** @type {string[]} */
861
+ const defined = [];
862
+ for (const block of content) {
863
+ if (block.type !== 'table' || !Array.isArray(block.rows)) continue;
864
+ for (const row of block.rows)
865
+ if (row[0] != null) defined.push(plain(row[0]));
760
866
  }
761
867
  candidates.push({
762
868
  domain: 'doc',
763
- name: entry.name,
764
- keywords: [],
765
- description,
766
- prose,
767
- _title: doc?.title || entry.title || entry.name,
869
+ name: node.name,
870
+ keywords: [
871
+ node.route.slice(node.route.lastIndexOf('/') + 1),
872
+ ...(Array.isArray(selfDoc?.keywords) ? selfDoc.keywords : []),
873
+ ...defined,
874
+ ...codeTerms({content}),
875
+ ],
876
+ description: node.summary || '',
877
+ prose: sectionProse({title: node.title, content}),
878
+ _topic: node.route,
879
+ _title: path.join(' › '),
880
+ _command: `astryx docs ${node.route}`,
881
+ _parent: node.parent == null ? 'astryx docs' : `astryx docs ${node.parent}`,
882
+ _package: node.provider,
768
883
  });
769
884
  }
770
885
  return candidates;
771
886
  }
772
887
 
888
+ /**
889
+ * The words one section says: its prose, headings, and list items.
890
+ * @param {any} section
891
+ * @returns {string[]}
892
+ */
893
+ function sectionProse(section) {
894
+ /** @type {string[]} */
895
+ const prose = [];
896
+ if (section?.title) prose.push(section.title);
897
+ for (const block of section?.content || []) {
898
+ if ((block.type === 'prose' || block.type === 'heading') && block.text) {
899
+ prose.push(block.text);
900
+ } else if (block.type === 'list' && Array.isArray(block.items)) {
901
+ for (const item of block.items) {
902
+ const text = typeof item === 'string' ? item : item?.text;
903
+ if (typeof text === 'string') prose.push(text);
904
+ }
905
+ } else if (block.type === 'table' && Array.isArray(block.rows)) {
906
+ for (const row of block.rows) prose.push(row.map(plain).join(' '));
907
+ } else if (block.type === 'code' && typeof block.code === 'string') {
908
+ prose.push([block.label, block.code].filter(Boolean).join(' '));
909
+ }
910
+ }
911
+ return prose;
912
+ }
913
+
914
+ /**
915
+ * The identifiers a doc part names in code ticks (`token-ref`,
916
+ * `ERR_UNKNOWN_SECTION`). Each is a keyword: a reader who types one exactly
917
+ * wants the part that defines or explains it.
918
+ * @param {any} part - a section, or `{content}` of a typed doc
919
+ * @returns {string[]}
920
+ */
921
+ function codeTerms(part) {
922
+ /** @type {Set<string>} */
923
+ const terms = new Set();
924
+ /** @param {unknown} text */
925
+ const scan = text => {
926
+ for (const m of String(text ?? '').matchAll(/`([^`\s]{2,40})`/g)) {
927
+ terms.add(m[1]);
928
+ }
929
+ };
930
+ for (const block of part?.content || []) {
931
+ if (block.type === 'prose') scan(block.text);
932
+ else if (block.type === 'list' && Array.isArray(block.items)) {
933
+ for (const item of block.items) {
934
+ scan(typeof item === 'string' ? item : item?.text);
935
+ }
936
+ } else if (block.type === 'table' && Array.isArray(block.rows)) {
937
+ for (const row of block.rows) for (const cell of row) scan(cell);
938
+ }
939
+ }
940
+ return [...terms];
941
+ }
942
+
943
+ /**
944
+ * The headings inside a section. Each names a subsection, so a query that
945
+ * names one should find the section as surely as one that names its title.
946
+ * @param {any} section
947
+ * @returns {string[]}
948
+ */
949
+ function headings(section) {
950
+ return (section?.content || [])
951
+ .filter(
952
+ (/** @type {any} */ block) => block.type === 'heading' && block.text,
953
+ )
954
+ .map((/** @type {any} */ block) => String(block.text));
955
+ }
956
+
957
+ /**
958
+ * A table cell as plain words, without its code ticks.
959
+ * @param {unknown} cell
960
+ * @returns {string}
961
+ */
962
+ function plain(cell) {
963
+ return unlinkText(String(cell ?? '')).replaceAll('`', '');
964
+ }
965
+
966
+ /**
967
+ * The candidates one topic yields: the topic itself, and one per section when
968
+ * it has more than one. A topic's command lists its sections, and a section's
969
+ * command reads only that section, so a hit never costs a whole-topic read.
970
+ * @param {string} name - the topic name, or a placed guide's route
971
+ * @param {any} doc - the lowered topic, or null when it did not load
972
+ * @param {string} [title]
973
+ * @param {string} [summary]
974
+ * @param {string} [path] - where the topic lives in the docs tree, as titles
975
+ * joined by ` › `; a flat topic is its own title
976
+ * @param {string} [parent] - the command that opens the level above the
977
+ * topic: its namespace, or the Unorganized level for a flat topic
978
+ * @param {string} [pkg] - the npm package that authored the topic
979
+ * @param {(key: string) => string} [sectionPackage] - the npm package a
980
+ * section came from: an extension's section names the extension's package
981
+ * @returns {Candidate[]}
982
+ */
983
+ function topicCandidates(
984
+ name,
985
+ doc,
986
+ title,
987
+ summary = '',
988
+ path,
989
+ parent,
990
+ pkg,
991
+ sectionPackage,
992
+ ) {
993
+ /** @type {any[]} */
994
+ const sections = doc?.sections ?? [];
995
+ const docTitle = path || doc?.title || title || name;
996
+ const split = sections.length > 1;
997
+ /** @type {Candidate[]} */
998
+ const out = [
999
+ {
1000
+ domain: 'doc',
1001
+ name,
1002
+ keywords: [
1003
+ ...(doc?.title || title ? [doc?.title || title] : []),
1004
+ ...(Array.isArray(doc?.keywords) ? doc.keywords : []),
1005
+ ],
1006
+ description: doc?.description || summary,
1007
+ prose: split
1008
+ ? sections.map(section => section.title).filter(Boolean)
1009
+ : sections.flatMap(sectionProse),
1010
+ _topic: name,
1011
+ _title: docTitle,
1012
+ _command: split ? `astryx docs ${name} --index` : `astryx docs ${name}`,
1013
+ ...(parent ? {_parent: parent} : {}),
1014
+ ...(pkg ? {_package: pkg} : {}),
1015
+ },
1016
+ ];
1017
+ if (!split) return out;
1018
+ for (const section of sections) {
1019
+ const key = sectionKey(section);
1020
+ out.push({
1021
+ domain: 'doc',
1022
+ name: key,
1023
+ keywords: [
1024
+ ...(section.title ? [section.title] : []),
1025
+ ...headings(section),
1026
+ ...codeTerms(section),
1027
+ ],
1028
+ description: sectionSummary(section),
1029
+ prose: sectionProse(section),
1030
+ _topic: name,
1031
+ _section: key,
1032
+ _title: `${docTitle} › ${section.title}`,
1033
+ _command: `astryx docs ${name} ${key}`,
1034
+ _parent: `astryx docs ${name} --index`,
1035
+ ...((sectionPackage?.(key) ?? pkg) ? {_package: sectionPackage?.(key) ?? pkg} : {}),
1036
+ });
1037
+ }
1038
+ return out;
1039
+ }
1040
+
773
1041
  /**
774
1042
  * Build template candidates (page + block) from the template discovery API.
775
1043
  * @param {string} cwd
@@ -783,6 +1051,13 @@ async function gatherTemplates(cwd) {
783
1051
  return [];
784
1052
  }
785
1053
  return templates.map(t => {
1054
+ // A replacement's target is its canonical unqualified lookup id. Keep the
1055
+ // integration-owned id as a keyword and response label, but score and print
1056
+ // commands against the id that `template()` resolves back to this entry.
1057
+ // This matters for replacement chains: one replacement's own id can be the
1058
+ // target of another, so using that shadowed id as the command would select
1059
+ // the other template.
1060
+ const commandName = t.replaces ?? t.dirName;
786
1061
  // Blocks ship an authored componentsUsed; page templates don't, so derive
787
1062
  // them from the source. Category words (e.g. "Dashboard - Analytics") are
788
1063
  // strong intent signal for pages, which otherwise only index on name +
@@ -795,6 +1070,7 @@ async function gatherTemplates(cwd) {
795
1070
  const keywords = Array.isArray(t.componentsUsed)
796
1071
  ? [...t.componentsUsed]
797
1072
  : [];
1073
+ keywords.push(...templateLookupIds(t).filter(id => id !== commandName));
798
1074
  /** @type {string[]} */
799
1075
  let weakKeywords = [];
800
1076
  if (t.type === 'page') {
@@ -810,12 +1086,14 @@ async function gatherTemplates(cwd) {
810
1086
  }
811
1087
  return {
812
1088
  domain: 'template',
813
- name: t.dirName,
1089
+ name: commandName,
814
1090
  keywords,
815
1091
  weakKeywords,
816
1092
  description: t.description || '',
817
1093
  _displayName: t.name,
818
1094
  _kind: t.type, // 'page' | 'block'
1095
+ _resultName: t.dirName,
1096
+ _commandName: commandName,
819
1097
  };
820
1098
  });
821
1099
  }
@@ -834,7 +1112,7 @@ async function gatherTemplates(cwd) {
834
1112
  function toResult(c, score, reason, matchedTerms, queryTerms) {
835
1113
  const base = {
836
1114
  domain: c.domain,
837
- name: c.name,
1115
+ name: c._resultName ?? c.name,
838
1116
  score,
839
1117
  reason,
840
1118
  description: c.description || '',
@@ -856,10 +1134,16 @@ function toResult(c, score, reason, matchedTerms, queryTerms) {
856
1134
  };
857
1135
  break;
858
1136
  case 'doc':
1137
+ // A doc result names its topic or route, plus the section when the
1138
+ // hit is one section; its command reads exactly that part.
859
1139
  result = {
860
1140
  ...base,
1141
+ name: c._topic ?? c.name,
1142
+ ...(c._section ? {section: c._section} : {}),
861
1143
  title: c._title,
862
- command: `astryx docs ${c.name}`,
1144
+ command: c._command ?? `astryx docs ${c.name}`,
1145
+ ...(c._parent ? {parent: c._parent} : {}),
1146
+ ...(c._package ? {package: c._package} : {}),
863
1147
  };
864
1148
  break;
865
1149
  case 'template':
@@ -867,7 +1151,7 @@ function toResult(c, score, reason, matchedTerms, queryTerms) {
867
1151
  ...base,
868
1152
  displayName: c._displayName,
869
1153
  kind: c._kind,
870
- command: `astryx template ${c.name}`,
1154
+ command: `astryx template ${c._commandName ?? c.name} --type ${c._kind}`,
871
1155
  };
872
1156
  break;
873
1157
  default:
@@ -884,7 +1168,7 @@ function toResult(c, score, reason, matchedTerms, queryTerms) {
884
1168
  * @param {string} [options.cwd]
885
1169
  * @param {'component'|'hook'|'doc'|'template'} [options.type] - Restrict to one domain.
886
1170
  * @param {number} [options.limit] - Max results (default 20).
887
- * @returns {Promise<{type: 'search', data: {query: string, matchCount: number, results: Array<object>}}>}
1171
+ * @returns {Promise<import('./search.type.mjs').SearchResponse>}
888
1172
  */
889
1173
  export async function search(query, options = {}) {
890
1174
  const {cwd = process.cwd(), type, limit = 20} = options;
@@ -919,17 +1203,26 @@ export async function search(query, options = {}) {
919
1203
  const term = String(query).trim().toLowerCase();
920
1204
  const tokens = tokenizeQuery(term);
921
1205
 
922
- const coreDir = findCoreDir(cwd);
923
- if (!coreDir) {
924
- throw new AstryxError('Could not find @astryxdesign/core package');
1206
+ // `astryx docs` reads docs without @astryxdesign/core, so a docs-only
1207
+ // search must too. Every other domain reads core.
1208
+ const docsOnly = type === 'doc';
1209
+ const coreDir = docsOnly ? null : findCoreDir(cwd);
1210
+ if (!docsOnly && !coreDir) {
1211
+ throw new AstryxError(
1212
+ 'Could not find @astryxdesign/core package',
1213
+ undefined,
1214
+ ERROR_CODES.ERR_CORE_NOT_FOUND,
1215
+ );
925
1216
  }
926
1217
 
927
1218
  // Gather candidates from each requested domain in parallel.
928
1219
  /** @param {string} d */
929
1220
  const wants = d => !type || type === d;
930
1221
  const [components, hooks, docTopics, templates] = await Promise.all([
931
- wants('component') ? gatherComponents(coreDir, cwd) : [],
932
- wants('hook') ? gatherHooks(coreDir) : [],
1222
+ wants('component')
1223
+ ? gatherComponents(/** @type {string} */ (coreDir), cwd)
1224
+ : [],
1225
+ wants('hook') ? gatherHooks(/** @type {string} */ (coreDir)) : [],
933
1226
  wants('doc') ? gatherDocs(cwd) : [],
934
1227
  wants('template') ? gatherTemplates(cwd) : [],
935
1228
  ]);
@@ -971,7 +1264,10 @@ export async function search(query, options = {}) {
971
1264
  data: {
972
1265
  query: String(query).trim(),
973
1266
  matchCount: scored.length,
974
- results: limited,
1267
+ // toResult gives every domain its command and domain fields.
1268
+ results: /** @type {import('./search.type.mjs').SearchResultEntry[]} */ (
1269
+ limited
1270
+ ),
975
1271
  },
976
1272
  };
977
1273
  }
@@ -21,6 +21,7 @@
21
21
 
22
22
  import {describe, it, expect} from 'vitest';
23
23
  import * as fs from 'node:fs';
24
+ import * as os from 'node:os';
24
25
  import * as path from 'node:path';
25
26
  import {fileURLToPath} from 'node:url';
26
27
  import {
@@ -70,6 +71,111 @@ describe('search leaf — envelope + ranking', () => {
70
71
  }, SLOW);
71
72
  });
72
73
 
74
+ describe('search leaf — per-domain result fields', () => {
75
+ it('carries import for components and hooks, title for docs, displayName and kind for templates', async () => {
76
+ const r = await search('theme', {cwd, limit: 60});
77
+ expect(new Set(r.data.results.map(res => res.domain))).toEqual(
78
+ new Set(SEARCH_DOMAINS),
79
+ );
80
+ for (const res of r.data.results) {
81
+ expect(typeof res.command).toBe('string');
82
+ expect(typeof res.description).toBe('string');
83
+ if (res.domain === 'component' || res.domain === 'hook') {
84
+ expect(res.import).toMatch(/\S/);
85
+ } else if (res.domain === 'doc') {
86
+ expect(res.title).toMatch(/\S/);
87
+ const read = `astryx docs ${res.name}`;
88
+ expect([read, `${read} --index`, `${read} ${res.section}`]).toContain(res.command);
89
+ } else {
90
+ expect(res.displayName).toMatch(/\S/);
91
+ expect(['page', 'block']).toContain(res.kind);
92
+ }
93
+ }
94
+ }, SLOW);
95
+ });
96
+
97
+ describe('search leaf — docs at the grain a reader reads them', () => {
98
+ it(
99
+ 'finds one section of a guide, and a docs-tree leaf by its own name',
100
+ async () => {
101
+ const guide = await search('codemod protected files', {cwd, type: 'doc'});
102
+ expect(guide.data.results.slice(0, 3)).toContainEqual(
103
+ expect.objectContaining({
104
+ domain: 'doc',
105
+ name: 'cli/integrations',
106
+ section: 'codemods',
107
+ title: 'Astryx CLI › CLI Integrations › Codemods',
108
+ parent: 'astryx docs cli/integrations --index',
109
+ command: 'astryx docs cli/integrations codemods',
110
+ }),
111
+ );
112
+ const block = await search('token-ref', {cwd});
113
+ expect(block.data.results[0]).toMatchObject({
114
+ name: 'authoring',
115
+ section: 'reference-doc',
116
+ command: 'astryx docs authoring reference-doc',
117
+ });
118
+ const fn = await search('assertResponse', {cwd, type: 'doc'});
119
+ expect(fn.data.results[0]).toMatchObject({
120
+ name: 'cli/api/functions/assert-response',
121
+ title: 'Astryx CLI › API › Functions › assertResponse()',
122
+ parent: 'astryx docs cli/api/functions',
123
+ command: 'astryx docs cli/api/functions/assert-response',
124
+ });
125
+ expect(fn.data.results[0]).not.toHaveProperty('section');
126
+ },
127
+ SLOW,
128
+ );
129
+
130
+ it(
131
+ 'gives a top-level namespace hit the topic list as its parent',
132
+ async () => {
133
+ for (const [query, route] of [['unorganized', 'unorganized'], ['Astryx CLI', 'cli']]) {
134
+ const r = await search(query, {cwd, type: 'doc'});
135
+ expect(r.data.results).toContainEqual(
136
+ expect.objectContaining({
137
+ name: route,
138
+ command: `astryx docs ${route}`,
139
+ parent: 'astryx docs',
140
+ }),
141
+ );
142
+ }
143
+ },
144
+ SLOW,
145
+ );
146
+
147
+ it(
148
+ 'points a topic hit at its index, never a whole-topic read',
149
+ async () => {
150
+ const r = await search('cli/integrations', {cwd, type: 'doc'});
151
+ expect(r.data.results[0]).toMatchObject({
152
+ name: 'cli/integrations',
153
+ command: 'astryx docs cli/integrations --index',
154
+ });
155
+ expect(r.data.results[0]).not.toHaveProperty('section');
156
+ },
157
+ SLOW,
158
+ );
159
+
160
+ it(
161
+ 'searches docs where @astryxdesign/core is not installed',
162
+ async () => {
163
+ const bare = fs.mkdtempSync(
164
+ path.join(os.tmpdir(), 'astryx-search-bare-'),
165
+ );
166
+ try {
167
+ const r = await search('assertResponse', {cwd: bare, type: 'doc'});
168
+ expect(r.data.results[0].name).toBe(
169
+ 'cli/api/functions/assert-response',
170
+ );
171
+ } finally {
172
+ fs.rmSync(bare, {recursive: true, force: true});
173
+ }
174
+ },
175
+ SLOW,
176
+ );
177
+ });
178
+
73
179
  describe('search leaf — matchCount is the total, not the cap', () => {
74
180
  it('reports every match while `results` stays bounded by the limit', async () => {
75
181
  // The regression: `matchCount` used to be `results.length`, so a query
@@ -160,6 +266,17 @@ describe('search leaf — error paths (pinned)', () => {
160
266
  search('button', {cwd, type: /** @type {any} */ ('bogus')}),
161
267
  ).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
162
268
  }, SLOW);
269
+
270
+ it('throws ERR_CORE_NOT_FOUND when @astryxdesign/core cannot be found', async () => {
271
+ const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-search-no-core-'));
272
+ try {
273
+ await expect(search('button', {cwd: empty})).rejects.toMatchObject({
274
+ code: 'ERR_CORE_NOT_FOUND',
275
+ });
276
+ } finally {
277
+ fs.rmSync(empty, {recursive: true, force: true});
278
+ }
279
+ }, SLOW);
163
280
  });
164
281
 
165
282
  describe('search leaf — limit validation (API matches the CLI contract)', () => {
@@ -213,12 +330,18 @@ describe('search leaf — integration components', () => {
213
330
  );
214
331
  fs.writeFileSync(
215
332
  path.join(widgetsDir, 'components', 'FancyGizmo.doc.mjs'),
216
- `export const docs = {
333
+ `export default {
334
+ type: 'component',
217
335
  name: 'FancyGizmo',
218
336
  keywords: ['gizmo', 'widget'],
219
337
  usage: {description: 'A fancy gizmo widget.'},
338
+ props: [],
220
339
  };\n`,
221
340
  );
341
+ fs.writeFileSync(
342
+ path.join(widgetsDir, 'components', 'FancyGizmo.tsx'),
343
+ `export function FancyGizmo() { return null; }\n`,
344
+ );
222
345
 
223
346
  return dir;
224
347
  }