@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.db52d98

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 (397) hide show
  1. package/README.md +38 -15
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/_adapter.d.mts +50 -0
  4. package/api/build/_adapter.mjs +60 -0
  5. package/api/build/build.doc.mjs +14 -7
  6. package/api/build/build.test.mjs +184 -6
  7. package/api/build/build.type.d.mts +57 -2
  8. package/api/build/build.type.mjs +30 -7
  9. package/api/build/help/help.d.mts +4 -0
  10. package/api/build/help/help.mjs +24 -11
  11. package/api/build/kit/kit.d.mts +4 -1
  12. package/api/build/kit/kit.mjs +165 -49
  13. package/api/build/kit/rank.d.mts +44 -0
  14. package/api/build/kit/rank.mjs +432 -0
  15. package/api/build/kit/rank.test.mjs +196 -0
  16. package/api/component/_adapter.d.mts +6 -12
  17. package/api/component/_adapter.mjs +20 -10
  18. package/api/component/component.doc.mjs +1 -0
  19. package/api/component/component.mjs +60 -12
  20. package/api/component/list/list.mjs +3 -2
  21. package/api/discover/discover.doc.mjs +1 -0
  22. package/api/docs/_adapter.d.mts +252 -34
  23. package/api/docs/_adapter.mjs +923 -132
  24. package/api/docs/detail/detail.mjs +11 -3
  25. package/api/docs/detail/section/section.mjs +24 -13
  26. package/api/docs/detail/section/section.test.mjs +15 -6
  27. package/api/docs/docs.d.mts +5 -3
  28. package/api/docs/docs.doc.mjs +39 -17
  29. package/api/docs/docs.mjs +44 -8
  30. package/api/docs/docs.test.mjs +158 -4
  31. package/api/docs/docs.type.d.mts +181 -2
  32. package/api/docs/docs.type.mjs +117 -3
  33. package/api/docs/index/index.mjs +11 -3
  34. package/api/docs/index/index.test.mjs +1 -1
  35. package/api/docs/integration-tree.test.mjs +555 -0
  36. package/api/docs/integrationDocs.test.mjs +14 -14
  37. package/api/docs/list/list.mjs +28 -12
  38. package/api/docs/node/node.d.mts +43 -0
  39. package/api/docs/node/node.mjs +192 -0
  40. package/api/docs/reference-blocks.test.mjs +406 -0
  41. package/api/doctor/doctor.d.mts +54 -4
  42. package/api/doctor/doctor.doc.mjs +1 -0
  43. package/api/doctor/doctor.mjs +331 -16
  44. package/api/doctor/doctor.test.mjs +420 -7
  45. package/api/gap-report/gap-report.doc.mjs +1 -0
  46. package/api/hook/_adapter.mjs +19 -5
  47. package/api/hook/hook.doc.mjs +1 -0
  48. package/api/hook/list/list.d.mts +1 -1
  49. package/api/hook/list/list.mjs +69 -17
  50. package/api/index.d.mts +1 -1
  51. package/api/index.mjs +1 -0
  52. package/api/init/init.doc.mjs +2 -1
  53. package/api/integration/add-contribution.d.mts +2 -1
  54. package/api/integration/add-contribution.mjs +114 -12
  55. package/api/integration/add-contribution.test.mjs +174 -3
  56. package/api/integration/add-theme.mjs +34 -64
  57. package/api/integration/add-theme.test.mjs +105 -21
  58. package/api/integration/authoring-checks.mjs +138 -28
  59. package/api/integration/authoring-checks.test.mjs +179 -7
  60. package/api/integration/authoring-checks.type.mjs +6 -1
  61. package/api/integration/integration-authoring.type.d.mts +2 -0
  62. package/api/integration/integration-authoring.type.mjs +2 -0
  63. package/api/integration/integration-block-exports.test.mjs +10 -6
  64. package/api/integration/integrationAdd.doc.mjs +7 -0
  65. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  66. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  67. package/api/integration/integrationAddComponent.doc.mjs +1 -0
  68. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  69. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  70. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  71. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  72. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  73. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  74. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  75. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  76. package/api/integration/pack-check.mjs +34 -0
  77. package/api/integration/pack-check.test.mjs +138 -47
  78. package/api/integration/pack-check.type.d.mts +26 -2
  79. package/api/integration/pack-check.type.mjs +14 -1
  80. package/api/integration/summarizeIssues.doc.mjs +1 -0
  81. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  82. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  83. package/api/integration/validate-integration.mjs +50 -102
  84. package/api/integration/validate-integration.test.mjs +88 -26
  85. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  86. package/api/integration/validateIntegration.doc.mjs +2 -1
  87. package/api/json/assertResponse.doc.mjs +1 -0
  88. package/api/json/index.ts +2 -0
  89. package/api/json/isError.doc.mjs +1 -0
  90. package/api/json/parseResponse.doc.mjs +1 -0
  91. package/api/layout/_adapter.mjs +20 -5
  92. package/api/layout/layoutCheck.doc.mjs +1 -0
  93. package/api/layout/layoutExpand.doc.mjs +1 -0
  94. package/api/layout/layoutGrammar.doc.mjs +1 -0
  95. package/api/search/search.d.mts +59 -1
  96. package/api/search/search.doc.mjs +5 -3
  97. package/api/search/search.mjs +458 -77
  98. package/api/search/search.test.mjs +91 -2
  99. package/api/search/search.type.d.mts +13 -1
  100. package/api/search/search.type.mjs +4 -1
  101. package/api/swizzle/swizzle.doc.mjs +1 -0
  102. package/api/template/list/list.mjs +1 -0
  103. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  104. package/api/template/template-integration.test.mjs +1072 -3
  105. package/api/template/template-suffix.test.mjs +41 -21
  106. package/api/template/template.doc.mjs +28 -7
  107. package/api/template/template.mjs +45 -8
  108. package/api/template/template.type.d.mts +6 -8
  109. package/api/template/template.type.mjs +3 -2
  110. package/api/theme/_adapter.d.mts +2 -3
  111. package/api/theme/_adapter.mjs +4 -5
  112. package/api/theme/add/add.binary.test.mjs +10 -17
  113. package/api/theme/add/add.test.mjs +14 -1
  114. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  115. package/api/theme/integration-themes.test.mjs +39 -28
  116. package/api/theme/list/list.test.mjs +19 -20
  117. package/api/theme/listThemes.doc.mjs +6 -5
  118. package/api/theme/template/template.test.mjs +5 -0
  119. package/api/theme/themeAdd.doc.mjs +4 -3
  120. package/api/theme/themeBuild.doc.mjs +1 -0
  121. package/api/theme/themeList.doc.mjs +6 -3
  122. package/api/theme/themeListAvailable.doc.mjs +5 -3
  123. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  124. package/api/theme/themeTargets.doc.mjs +1 -0
  125. package/api/theme/themeTemplate.doc.mjs +2 -1
  126. package/api/upgrade/_adapter.d.mts +32 -5
  127. package/api/upgrade/_adapter.mjs +97 -69
  128. package/api/upgrade/provider-agreement.test.mjs +152 -0
  129. package/api/upgrade/run/run.mjs +356 -59
  130. package/api/upgrade/upgrade.doc.mjs +6 -1
  131. package/api/upgrade/upgrade.type.d.mts +34 -0
  132. package/api/upgrade/upgrade.type.mjs +15 -0
  133. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  134. package/assets/codemods/integration-discovery.mjs +8 -2
  135. package/assets/codemods/integration-discovery.test.mjs +15 -0
  136. package/assets/codemods/integration-runner.mjs +56 -4
  137. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  138. package/assets/codemods/run-codemod.mjs +177 -34
  139. package/assets/codemods/runner.mjs +350 -102
  140. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  141. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  142. package/assets/codemods/transforms/next/index.mjs +19 -1
  143. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  144. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  145. package/assets/docs/getting-started.doc.mjs +2 -2
  146. package/assets/docs/layout.doc.dense.mjs +2 -2
  147. package/assets/docs/layout.doc.mjs +1 -1
  148. package/assets/docs/principles.doc.mjs +6 -6
  149. package/assets/docs/styling-libraries.doc.mjs +3 -3
  150. package/assets/docs/styling.doc.mjs +4 -4
  151. package/assets/docs/theme.doc.mjs +5 -5
  152. package/assets/docs/tokens.doc.mjs +1 -1
  153. package/assets/docs/tree/api.doc.mjs +30 -0
  154. package/assets/docs/tree/cli.doc.mjs +23 -0
  155. package/assets/docs/tree/commands.doc.mjs +25 -0
  156. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +66 -38
  157. package/assets/docs/tree/integrations.test.mjs +62 -0
  158. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  159. package/assets/docs/working-with-ai.doc.mjs +3 -3
  160. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  161. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  162. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  163. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  164. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  165. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  166. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  167. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  168. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  169. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  170. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  171. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  172. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  173. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  174. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  175. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  176. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  177. package/authoring/codemod/codemod.doc.mjs +1 -1
  178. package/authoring/codemod/type.ts +12 -0
  179. package/authoring/config/config.doc.mjs +1 -1
  180. package/authoring/debug/debug.doc.d.mts +11 -0
  181. package/authoring/debug/debug.doc.mjs +182 -0
  182. package/authoring/debug/parse.d.mts +3 -3
  183. package/authoring/doctypes/_schema.d.mts +119 -117
  184. package/authoring/doctypes/_schema.mjs +54 -3
  185. package/authoring/doctypes/base/graph-fields.doc.mjs +8 -6
  186. package/authoring/doctypes/base/type.ts +6 -5
  187. package/authoring/doctypes/command/command.doc.mjs +1 -1
  188. package/authoring/doctypes/command/type.ts +2 -2
  189. package/authoring/doctypes/component/type.ts +2 -2
  190. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  191. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  192. package/authoring/doctypes/enum/type.ts +1 -1
  193. package/authoring/doctypes/function/function.doc.mjs +3 -2
  194. package/authoring/doctypes/function/type.ts +3 -2
  195. package/authoring/doctypes/hook/type.ts +2 -2
  196. package/authoring/doctypes/load-contract.test.mjs +28 -2
  197. package/authoring/doctypes/namespace/namespace.doc.mjs +6 -10
  198. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  199. package/authoring/doctypes/namespace/type.ts +5 -2
  200. package/authoring/doctypes/parse.d.mts +4 -2
  201. package/authoring/doctypes/parse.mjs +10 -5
  202. package/authoring/doctypes/reference/reference.doc.mjs +35 -6
  203. package/authoring/doctypes/reference/type.ts +30 -13
  204. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  205. package/authoring/doctypes/schema/type.ts +1 -2
  206. package/authoring/doctypes/template/parse.d.mts +2 -0
  207. package/authoring/doctypes/template/parse.mjs +4 -0
  208. package/authoring/doctypes/template/parse.test.mjs +18 -0
  209. package/authoring/doctypes/template/template.doc.mjs +9 -3
  210. package/authoring/doctypes/template/type.ts +8 -0
  211. package/authoring/doctypes/theme/parse.d.mts +35 -0
  212. package/authoring/doctypes/theme/parse.mjs +76 -0
  213. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  214. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  215. package/authoring/doctypes/theme/type.ts +42 -0
  216. package/authoring/doctypes/types.ts +2 -1
  217. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  218. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  219. package/authoring/identity/identity.doc.mjs +2 -2
  220. package/authoring/index.d.mts +1 -0
  221. package/authoring/index.d.ts +7 -4
  222. package/authoring/index.mjs +2 -1
  223. package/authoring/integration/integration.doc.mjs +2 -2
  224. package/authoring/integration/type.ts +4 -10
  225. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  226. package/clients/cli/commands/blog.doc.mjs +1 -1
  227. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  228. package/clients/cli/commands/build-theme.mjs +11 -45
  229. package/clients/cli/commands/build.doc.mjs +12 -7
  230. package/clients/cli/commands/build.mjs +105 -67
  231. package/clients/cli/commands/build.text-fields.test.mjs +41 -0
  232. package/clients/cli/commands/component/index.mjs +1 -1
  233. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  234. package/clients/cli/commands/component.doc.mjs +1 -1
  235. package/clients/cli/commands/discover.broken-integration.test.mjs +7 -8
  236. package/clients/cli/commands/discover.doc.mjs +1 -1
  237. package/clients/cli/commands/discover.mjs +1 -1
  238. package/clients/cli/commands/docs.doc.mjs +21 -9
  239. package/clients/cli/commands/docs.mjs +184 -70
  240. package/clients/cli/commands/docs.test.mjs +120 -16
  241. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  242. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  243. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  244. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  245. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  246. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  247. package/clients/cli/commands/doctor.doc.mjs +1 -1
  248. package/clients/cli/commands/doctor.mjs +53 -16
  249. package/clients/cli/commands/gap-report.doc.mjs +1 -1
  250. package/clients/cli/commands/hook.doc.mjs +1 -1
  251. package/clients/cli/commands/init.doc.mjs +1 -1
  252. package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
  253. package/clients/cli/commands/integration-add.doc.mjs +11 -1
  254. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  255. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  256. package/clients/cli/commands/integration.doc.mjs +1 -1
  257. package/clients/cli/commands/integration.mjs +1 -0
  258. package/clients/cli/commands/layout-check.doc.mjs +1 -1
  259. package/clients/cli/commands/layout-expand.doc.mjs +1 -1
  260. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  261. package/clients/cli/commands/layout.doc.mjs +1 -1
  262. package/clients/cli/commands/manifest.doc.mjs +1 -1
  263. package/clients/cli/commands/search.doc.mjs +1 -1
  264. package/clients/cli/commands/search.mjs +11 -2
  265. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  266. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  267. package/clients/cli/commands/template.doc.mjs +24 -7
  268. package/clients/cli/commands/template.mjs +4 -91
  269. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  270. package/clients/cli/commands/theme-add.doc.mjs +2 -2
  271. package/clients/cli/commands/theme-build.doc.mjs +1 -1
  272. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  273. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  274. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  275. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  276. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  277. package/clients/cli/commands/theme-template.doc.mjs +1 -1
  278. package/clients/cli/commands/theme.doc.mjs +1 -1
  279. package/clients/cli/commands/upgrade.doc.mjs +3 -2
  280. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  281. package/clients/cli/commands/upgrade.mjs +29 -7
  282. package/clients/cli/formatters/index.mjs +2 -0
  283. package/clients/cli/formatters/index.test.mjs +6 -0
  284. package/clients/cli/index.mjs +8 -0
  285. package/clients/cli/lib/hook-format.mjs +14 -5
  286. package/clients/cli/lib/manifest.mjs +9 -2
  287. package/foundation/agent-docs/agent-docs.d.mts +3 -2
  288. package/foundation/agent-docs/agent-docs.mjs +13 -9
  289. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  290. package/foundation/config/project-themes.test.mjs +11 -19
  291. package/foundation/config/project.d.mts +20 -11
  292. package/foundation/config/project.mjs +123 -80
  293. package/foundation/config/project.test.mjs +144 -21
  294. package/foundation/discovery/authoring-self-docs.d.mts +18 -0
  295. package/foundation/discovery/authoring-self-docs.mjs +37 -15
  296. package/foundation/discovery/authoring-self-docs.test.mjs +25 -9
  297. package/foundation/discovery/authoring-surface.d.mts +74 -0
  298. package/foundation/discovery/authoring-surface.mjs +525 -0
  299. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  300. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  301. package/foundation/discovery/cli-self-docs.mjs +490 -0
  302. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  303. package/foundation/discovery/component-discovery.d.mts +38 -0
  304. package/foundation/discovery/component-discovery.mjs +48 -0
  305. package/foundation/discovery/component-loader.d.mts +35 -38
  306. package/foundation/discovery/component-loader.mjs +53 -222
  307. package/foundation/discovery/docs-discovery.d.mts +112 -11
  308. package/foundation/discovery/docs-discovery.mjs +231 -36
  309. package/foundation/discovery/docs-discovery.test.mjs +111 -32
  310. package/foundation/discovery/docs-output-budget.d.mts +2 -2
  311. package/foundation/discovery/docs-output-budget.mjs +1 -1
  312. package/foundation/discovery/docs-section-key.d.mts +28 -10
  313. package/foundation/discovery/docs-section-key.mjs +134 -33
  314. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  315. package/foundation/discovery/template-adapter.d.mts +99 -6
  316. package/foundation/discovery/template-adapter.mjs +480 -57
  317. package/foundation/discovery/template-adapter.test.mjs +57 -0
  318. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  319. package/foundation/discovery/template-conflict-release.mjs +40 -0
  320. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  321. package/foundation/discovery/theme-discovery.d.mts +67 -7
  322. package/foundation/discovery/theme-discovery.mjs +916 -186
  323. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  324. package/foundation/doc-compiler/bundle.d.mts +47 -0
  325. package/foundation/doc-compiler/bundle.mjs +278 -0
  326. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  327. package/foundation/doc-compiler/compile.d.mts +220 -39
  328. package/foundation/doc-compiler/compile.mjs +311 -15
  329. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  330. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  331. package/foundation/doc-compiler/doc-compiler.test.mjs +28 -1
  332. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  333. package/foundation/doc-compiler/import.d.mts +24 -0
  334. package/foundation/doc-compiler/import.mjs +59 -0
  335. package/foundation/doc-compiler/inputs.d.mts +102 -0
  336. package/foundation/doc-compiler/inputs.mjs +291 -0
  337. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  338. package/foundation/doc-compiler/ir.d.mts +13 -0
  339. package/foundation/doc-compiler/ir.mjs +196 -12
  340. package/foundation/doc-compiler/lenses.d.mts +8 -5
  341. package/foundation/doc-compiler/lenses.mjs +50 -4
  342. package/foundation/doc-compiler/links.d.mts +162 -0
  343. package/foundation/doc-compiler/links.mjs +294 -0
  344. package/foundation/doc-compiler/links.test.mjs +192 -0
  345. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  346. package/foundation/doc-compiler/overlays.d.mts +37 -0
  347. package/foundation/doc-compiler/overlays.mjs +206 -0
  348. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  349. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  350. package/foundation/doc-compiler/read.d.mts +127 -0
  351. package/foundation/doc-compiler/read.mjs +325 -0
  352. package/foundation/doc-compiler/read.test.mjs +313 -0
  353. package/foundation/doc-compiler/source.d.mts +33 -0
  354. package/foundation/doc-compiler/source.mjs +128 -0
  355. package/foundation/doc-compiler/tree.d.mts +288 -0
  356. package/foundation/doc-compiler/tree.mjs +876 -0
  357. package/foundation/doc-compiler/tree.test.mjs +598 -0
  358. package/foundation/fs/file-protection.d.mts +33 -0
  359. package/foundation/fs/file-protection.mjs +825 -0
  360. package/foundation/fs/file-protection.test.mjs +250 -0
  361. package/foundation/integrations/autolink.d.mts +58 -1
  362. package/foundation/integrations/autolink.mjs +143 -57
  363. package/foundation/integrations/autolink.test.mjs +1 -1
  364. package/foundation/integrations/cli-requirement.d.mts +45 -0
  365. package/foundation/integrations/cli-requirement.mjs +154 -0
  366. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  367. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  368. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  369. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  370. package/foundation/integrations/contribution-inventory.mjs +27 -24
  371. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  372. package/foundation/integrations/integration-warnings.d.mts +9 -2
  373. package/foundation/integrations/integration-warnings.mjs +51 -26
  374. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  375. package/foundation/integrations/integrations.d.mts +3 -0
  376. package/foundation/integrations/integrations.mjs +11 -97
  377. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  378. package/foundation/integrations/provider-resolution.d.mts +152 -0
  379. package/foundation/integrations/provider-resolution.mjs +576 -0
  380. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  381. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  382. package/foundation/integrations/theme-descriptor.mjs +44 -0
  383. package/foundation/integrations/validate-contributions.mjs +121 -29
  384. package/foundation/response/error-codes.d.mts +3 -1
  385. package/foundation/response/error-codes.d.ts +2 -0
  386. package/foundation/response/error-codes.doc.mjs +12 -2
  387. package/foundation/response/error-codes.mjs +7 -1
  388. package/foundation/response/error-codes.test.mjs +55 -11
  389. package/foundation/response/response-types.doc.d.mts +5 -1
  390. package/foundation/response/response-types.doc.mjs +20 -11
  391. package/foundation/response/response.doc.mjs +1 -1
  392. package/foundation/text/string-utils.d.mts +8 -0
  393. package/foundation/text/string-utils.mjs +40 -10
  394. package/foundation/xle/expand.mjs +1 -1
  395. package/foundation/xle/xle.test.mjs +13 -0
  396. package/package.json +10 -9
  397. package/assets/templates/themes/manifest.json +0 -95
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export type BuildPlaybookCommand = {
8
8
  /**
9
- * Bare subcommand with `<placeholder>` arguments (e.g. `template <name> --skeleton`) and no package-manager prefix — render it with your own CLI invocation.
9
+ * Bare subcommand with `<placeholder>` arguments (e.g. `template <name> <path>`) and no package-manager prefix — render it with your own CLI invocation.
10
10
  */
11
11
  command: string;
12
12
  /**
@@ -45,7 +45,61 @@ export type BuildHelpResponse = {
45
45
  };
46
46
  };
47
47
  /**
48
- * astryx --json build "<idea>" — the composition kit for what you're building.
48
+ * The page template a kit recommends starting from.
49
+ */
50
+ export type BuildStart = {
51
+ /**
52
+ * Template id, as `astryx template <name>` takes it.
53
+ */
54
+ name: string;
55
+ /**
56
+ * Human-facing template name.
57
+ */
58
+ displayName: string;
59
+ /**
60
+ * What the page is: its layout and the ideas it serves.
61
+ */
62
+ description: string;
63
+ /**
64
+ * The scaffold command that selects exactly this template, `astryx template <id> --type page <path>`: `<id>` is the Core id an integration replacement stands in for, else the template's own id, `<path>` is a placeholder for the file or folder to write the template to, and the `astryx` prefix is for the caller to replace with its own invocation.
65
+ */
66
+ command: string;
67
+ /**
68
+ * Why this template. The page ranker picks every start: it weighs each matched word by how rare it is among page templates, favors the family the idea's head names and the container it names ("in a modal"), and discounts words that only modify another. `direct` when its pick is also search's direct match (`directMatch`); `closest` when it is not; `fallback` when no template has the evidence to lead and the page starts from the app shell.
69
+ */
70
+ basis: "direct" | "closest" | "fallback";
71
+ /**
72
+ * One sentence saying the same as `basis`, for a reader.
73
+ */
74
+ reason: string;
75
+ /**
76
+ * The ranker's next closest page templates (≤2), for when the start's layout is wrong.
77
+ */
78
+ alternatives: BuildAlternative[];
79
+ };
80
+ /**
81
+ * A page template to consider instead of the start.
82
+ */
83
+ export type BuildAlternative = {
84
+ /**
85
+ * Template id, as `astryx template <name>` takes it.
86
+ */
87
+ name: string;
88
+ /**
89
+ * Human-facing template name.
90
+ */
91
+ displayName: string;
92
+ /**
93
+ * What the page is: its layout and the ideas it serves.
94
+ */
95
+ description: string;
96
+ /**
97
+ * The scaffold command, in the same form as the start's.
98
+ */
99
+ command: string;
100
+ };
101
+ /**
102
+ * astryx --json build "<idea>" — the page template to start from, and the kit around it.
49
103
  *
50
104
  * Entries are raw `SearchResultEntry` objects (no package-manager-prefixed
51
105
  * command strings — the CLI adds those); `frame`/`foundation` are static
@@ -58,6 +112,7 @@ export type BuildKitResponse = {
58
112
  hasResults: boolean;
59
113
  matchCount: number;
60
114
  directMatch: boolean;
115
+ start: BuildStart | null;
61
116
  pages: import("../search/search.type.mjs").SearchResultEntry[];
62
117
  blocks: import("../search/search.type.mjs").SearchResultEntry[];
63
118
  domain: import("../search/search.type.mjs").SearchResultEntry[];
@@ -3,14 +3,13 @@
3
3
  /**
4
4
  * @file Colocated types for the `build` command — source of truth for the
5
5
  * `build.help` (playbook) and `build.kit` (composition kit) JSON responses.
6
- * Re-exported by types/build.d.ts.
7
6
  */
8
7
 
9
8
  /**
10
9
  * A command the playbook tells the caller to run.
11
10
  *
12
11
  * @typedef {object} BuildPlaybookCommand
13
- * @property {string} command Bare subcommand with `<placeholder>` arguments (e.g. `template <name> --skeleton`) and no package-manager prefix — render it with your own CLI invocation.
12
+ * @property {string} command Bare subcommand with `<placeholder>` arguments (e.g. `template <name> <path>`) and no package-manager prefix — render it with your own CLI invocation.
14
13
  * @property {string} [purpose] What running it is for.
15
14
  */
16
15
 
@@ -37,7 +36,30 @@
37
36
  */
38
37
 
39
38
  /**
40
- * astryx --json build "<idea>" — the composition kit for what you're building.
39
+ * The page template a kit recommends starting from.
40
+ *
41
+ * @typedef {object} BuildStart
42
+ * @property {string} name Template id, as `astryx template <name>` takes it.
43
+ * @property {string} displayName Human-facing template name.
44
+ * @property {string} description What the page is: its layout and the ideas it serves.
45
+ * @property {string} command The scaffold command that selects exactly this template, `astryx template <id> --type page <path>`: `<id>` is the Core id an integration replacement stands in for, else the template's own id, `<path>` is a placeholder for the file or folder to write the template to, and the `astryx` prefix is for the caller to replace with its own invocation.
46
+ * @property {'direct' | 'closest' | 'fallback'} basis Why this template. The page ranker picks every start: it weighs each matched word by how rare it is among page templates, favors the family the idea's head names and the container it names ("in a modal"), and discounts words that only modify another. `direct` when its pick is also search's direct match (`directMatch`); `closest` when it is not; `fallback` when no template has the evidence to lead and the page starts from the app shell.
47
+ * @property {string} reason One sentence saying the same as `basis`, for a reader.
48
+ * @property {BuildAlternative[]} alternatives The ranker's next closest page templates (≤2), for when the start's layout is wrong.
49
+ */
50
+
51
+ /**
52
+ * A page template to consider instead of the start.
53
+ *
54
+ * @typedef {object} BuildAlternative
55
+ * @property {string} name Template id, as `astryx template <name>` takes it.
56
+ * @property {string} displayName Human-facing template name.
57
+ * @property {string} description What the page is: its layout and the ideas it serves.
58
+ * @property {string} command The scaffold command, in the same form as the start's.
59
+ */
60
+
61
+ /**
62
+ * astryx --json build "<idea>" — the page template to start from, and the kit around it.
41
63
  *
42
64
  * Entries are raw `SearchResultEntry` objects (no package-manager-prefixed
43
65
  * command strings — the CLI adds those); `frame`/`foundation` are static
@@ -47,14 +69,15 @@
47
69
  * @property {'build.kit'} type
48
70
  * @property {object} data
49
71
  * @property {string} data.query
50
- * @property {boolean} data.hasResults False when search returned nothing (renderer shows "No matches").
72
+ * @property {boolean} data.hasResults False when search returned nothing. The kit still names a template in `start`.
51
73
  * @property {number} data.matchCount Total ranked search matches for the query — counted before the search `limit`, the kit's score floors, and its per-group caps, so it is never a cap read back.
52
74
  * @property {boolean} data.directMatch True when the top page template is a confident direct match.
53
- * @property {import('../search/search.type.mjs').SearchResultEntry[]} data.pages Closest page templates (≤3). Each entry's `command` carries `--skeleton` when `directMatch` is false, so it recommends reading the layout rather than scaffolding it.
75
+ * @property {BuildStart | null} data.start The page template to start from: the ranker's pick, else the app shell. Null only when the kit is narrowed to components or hooks (`type`), or when the project has no page template to offer.
76
+ * @property {import('../search/search.type.mjs').SearchResultEntry[]} data.pages Closest page templates by search (≤3). Each entry's `command` carries `--skeleton` when `directMatch` is false, so it previews the layout; `start.command` is the scaffold.
54
77
  * @property {import('../search/search.type.mjs').SearchResultEntry[]} data.blocks Drop-in block patterns covering parts of the idea (≤5).
55
78
  * @property {import('../search/search.type.mjs').SearchResultEntry[]} data.domain Idea-specific components/hooks (≤6), excluding frame/foundation.
56
- * @property {string[]} data.frame Always-on page-shell component names.
57
- * @property {string[]} data.foundation Always-on layout/typography/action component names.
79
+ * @property {string[]} data.frame Always-on page-shell component names. Every page template already uses them.
80
+ * @property {string[]} data.foundation Always-on layout/typography/action component names. Every page template already uses them.
58
81
  * @property {{reason: string, commands: string[]}} [data.hint] Present only when the kit is thin. `reason` says why, `commands` are bare subcommands (e.g. `component --list`) for the caller to render with its own invocation — so a reader is never handed a command that does not resolve in their project.
59
82
  */
60
83
 
@@ -10,6 +10,10 @@
10
10
  * package-manager prefix, which keeps the JSON environment-agnostic; the CLI
11
11
  * renders each one with the caller's invocation, as it does build.kit's
12
12
  * `hint.commands`.
13
+ *
14
+ * The workflow starts every page from a template, because a template already
15
+ * has the frame, spacing, and section rhythm that a page composed from
16
+ * components has to rediscover.
13
17
  */
14
18
  /**
15
19
  * The page-building playbook (emitted when `build` runs with no query).
@@ -9,6 +9,10 @@
9
9
  * package-manager prefix, which keeps the JSON environment-agnostic; the CLI
10
10
  * renders each one with the caller's invocation, as it does build.kit's
11
11
  * `hint.commands`.
12
+ *
13
+ * The workflow starts every page from a template, because a template already
14
+ * has the frame, spacing, and section rhythm that a page composed from
15
+ * components has to rediscover.
12
16
  */
13
17
 
14
18
  /**
@@ -24,39 +28,48 @@ export function buildHelp() {
24
28
  title: 'How to build a page with Astryx',
25
29
  steps: [
26
30
  {
27
- title: "Find a starting point for what you're building",
31
+ title: 'Find the page template to start from',
28
32
  commands: [{command: 'build "<what you\'re building>"'}],
29
33
  returns:
30
- 'the closest [page] template, the [block]s that cover parts, and the [component]s to fill the gaps, with a recommended start',
31
- },
32
- {
33
- title: 'If a [page] template matches, scaffold it and adapt',
34
- commands: [{command: 'template <name> [path]'}],
34
+ 'the [page] template to start from (always one: the closest match, or the app shell when nothing matches), the next two templates, and the [block]s and [component]s for the parts it lacks',
35
35
  },
36
36
  {
37
- title: 'If nothing matches exactly, compose',
37
+ title: 'Scaffold that template into your project',
38
38
  commands: [
39
39
  {
40
- command: 'template <name> --skeleton',
41
- purpose: "study a close page's layout",
40
+ command: 'template <name> <path>',
41
+ purpose: 'write the page template to <path>',
42
42
  },
43
+ ],
44
+ },
45
+ {
46
+ title: 'Adapt it: keep its frame and spacing, replace its content',
47
+ commands: [
43
48
  {
44
49
  command: 'template <BlockName>',
45
- purpose: 'drop in each block from the kit',
50
+ purpose:
51
+ 'print a block to put inside a section, for a part the template lacks',
46
52
  },
47
53
  {
48
54
  command: 'component <Name>',
49
- purpose: 'fill remaining gaps (read props)',
55
+ purpose: 'read props before you change a component',
50
56
  },
51
57
  ],
52
58
  },
53
59
  ],
54
60
  rules: [
61
+ 'Start every page from a page template. Never lay out a page from scratch.',
62
+ 'Changing a page you already have? Keep it. Add blocks and components inside its sections.',
63
+ "Keep the template's page frame, gap, and padding values. Replace its data, copy, and sections.",
55
64
  'No <div>/raw HTML for layout — use VStack/HStack/Grid/Stack/Card etc.',
56
65
  'No style={{}} — use component props, and design tokens for values.',
57
66
  'Wrap the app in <Theme theme={...}> and import core reset.css + astryx.css.',
58
67
  ],
59
68
  related: [
69
+ {
70
+ command: 'template --list --type page',
71
+ purpose: 'every page template',
72
+ },
60
73
  {command: 'docs tokens', purpose: 'the design tokens'},
61
74
  {
62
75
  command: 'search <query>',
@@ -2,7 +2,7 @@
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
4
  /**
5
- * The grouped composition kit for what you're building.
5
+ * The page template to start from, and the kit around it.
6
6
  *
7
7
  * @param {string} query what you're building (e.g. "analytics dashboard")
8
8
  * @param {{cwd?: string, type?: import('../../search/search.type.mjs').SearchDomain, limit?: number}} [options]
@@ -13,3 +13,6 @@ export function buildKit(query: string, options?: {
13
13
  type?: import("../../search/search.type.mjs").SearchDomain;
14
14
  limit?: number;
15
15
  }): Promise<import("../build.type.mjs").BuildKitResponse>;
16
+ export type SearchResultEntry = import("../../search/search.type.mjs").SearchResultEntry;
17
+ export type BuildStart = import("../build.type.mjs").BuildStart;
18
+ export type PageTemplate = import("../_adapter.mjs").PageTemplate;
@@ -1,44 +1,57 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file build.kit leaf — the grouped composition kit and raw match count.
4
+ * @file build.kit leaf — the page template to start from, and the kit around it.
5
5
  *
6
- * Runs the unified search for the query and groups the results into a
7
- * composition KIT: the closest page templates, the blocks that cover parts,
8
- * and the domain components to fill gaps, plus the always-on frame + foundation.
6
+ * Every kit names a page template to START from: the page the page ranker
7
+ * (rank.mjs) puts first when it has the evidence to lead, else the app shell.
8
+ * The ranker is the only thing that picks the start, so one noisy signal —
9
+ * search matching "site" to a gallery's "side" — cannot choose the page. A
10
+ * template carries the page frame, the spacing, and the section rhythm; a page
11
+ * composed from components carries none of that, so the kit never recommends
12
+ * composing from scratch while a template exists. Next to the start it names
13
+ * the ranker's next two templates, then groups the unified search into the
14
+ * blocks that cover parts and the domain components to fill gaps, plus the
15
+ * always-on frame + foundation names. `pages` and `directMatch` keep search's
16
+ * own view for callers that read them.
9
17
  *
10
18
  * The kit carries RAW `SearchResultEntry` objects and static name arrays only —
11
19
  * never pre-formatted command strings. All CLI prefixing (formatCliCommand /
12
20
  * getCliInvocation) and the section prose live in the command renderer, so the
13
21
  * JSON shape stays package-manager-agnostic and stable across environments.
14
22
  *
15
- * The one adjustment it makes is on a page's `command`: when the top page is
16
- * not a direct match the kit appends `--skeleton`, so the field agrees with
17
- * the recommendation the kit itself computed. That is still not prefixing —
23
+ * Two commands are the kit's own: `start.command`, the scaffold (`astryx
24
+ * template <id> --type page <path>`, with `<path>` a placeholder), and the `--skeleton`
25
+ * a page entry carries when it is not a direct match, so a loose page reads
26
+ * as a layout preview rather than the thing to build. Neither is prefixing —
18
27
  * the invocation stays the renderer's job.
19
28
  */
20
29
 
21
30
  import {search} from '../../search/search.mjs';
22
31
  import {getResultCoverage} from '../../search/coverage.mjs';
32
+ import {loadPageTemplates} from '../_adapter.mjs';
33
+ import {pickAlternatives, pickStart, rankPages} from './rank.mjs';
23
34
 
24
35
  /** A page at/above this score is a confident direct match. */
25
36
  const PAGE_DIRECT = 95;
26
- /** Below this a page is too weak to offer even as a layout reference. */
37
+ /** Below this a page is too weak to offer at all. */
27
38
  const PAGE_FLOOR = 50;
28
- /** Below this a block/domain-component match is incidental noise. */
29
- const DOMAIN_FLOOR = 55;
30
39
  /**
31
- * How much of a multi-word query a result must cover to be offered as a PAGE.
32
- *
33
- * Score alone cannot carry this. A page's keywords include every component its
34
- * source renders, so `build "actionable warning banner"` scored `login`,
35
- * `contact-form` and `documentation-design` at 95 apiece — an exact keyword hit
36
- * (90) on "banner" alone, plus the coverage garnish, lands exactly on
37
- * PAGE_DIRECT. Three pages that are not warnings, presented as a direct match,
38
- * because each happens to render a Banner somewhere.
40
+ * Below this a block/domain-component match is incidental noise. A single
41
+ * description word in a multi-word idea scores 50 plus at most 7.5 of coverage
42
+ * garnish, so it stays below; a name or keyword hit clears it. `build "weekly
43
+ * brief"` used to offer Toast, Popover and TextInput because their
44
+ * descriptions say "brief".
45
+ */
46
+ const DOMAIN_FLOOR = 60;
47
+ /**
48
+ * How much of a multi-word query a page must cover to be offered on breadth.
39
49
  *
40
- * Coverage has to gate rather than garnish: matching one of three concepts is
41
- * not the same claim as matching three.
50
+ * Score alone cannot carry this. A page's derived keywords include every
51
+ * component its source renders, so `build "actionable warning banner"` once
52
+ * scored `login`, `contact-form` and `documentation-design` at 95 apiece — an
53
+ * exact hit on "banner" alone, plus the coverage garnish. Matching one of
54
+ * three concepts is not the same claim as matching three.
42
55
  */
43
56
  const PAGE_COVERAGE = 0.5;
44
57
  /**
@@ -50,12 +63,21 @@ const PAGE_COVERAGE = 0.5;
50
63
  * Astryx contains, which is exactly the failure `build` exists to prevent.
51
64
  */
52
65
  const THIN_KIT = 3;
66
+ /**
67
+ * Where a page starts when no page template matched: the first of these the
68
+ * project can scaffold. A top nav over empty, full-width content is the least
69
+ * opinionated frame that still has navigation; `blank` is the floor, with no
70
+ * chrome at all. Either one still hands the reader a page frame and its
71
+ * padding, which composing from components does not.
72
+ */
73
+ const FALLBACK_STARTS = ['shell-top-nav', 'blank'];
53
74
 
54
75
  /**
55
76
  * Always-surfaced primitives. Every page needs a shell + layout/typography/
56
77
  * action atoms, but these never keyword-match an idea ("dashboard" != "Stack"),
57
78
  * so search alone never returns them. Kept here (not the renderer) because they
58
79
  * are ALSO used to exclude these names from the idea-specific `domain` group.
80
+ * Every page template already uses them.
59
81
  */
60
82
  const FRAME = ['AppShell', 'TopNav', 'SideNav', 'Layout'];
61
83
  const FOUNDATION = [
@@ -75,7 +97,90 @@ const FOUNDATION = [
75
97
  const ALWAYS = new Set([...FRAME, ...FOUNDATION]);
76
98
 
77
99
  /**
78
- * The grouped composition kit for what you're building.
100
+ * @typedef {import('../../search/search.type.mjs').SearchResultEntry} SearchResultEntry
101
+ * @typedef {import('../build.type.mjs').BuildStart} BuildStart
102
+ * @typedef {import('../_adapter.mjs').PageTemplate} PageTemplate
103
+ */
104
+
105
+ /**
106
+ * A page template as the kit names it: the command that selects exactly that
107
+ * template, scaffolding into `<path>`, a placeholder for the file or folder to
108
+ * write it to.
109
+ * @param {PageTemplate} t
110
+ */
111
+ const asTemplate = t => ({
112
+ name: t.name,
113
+ displayName: t.displayName,
114
+ description: t.description,
115
+ command: `${t.command} <path>`,
116
+ });
117
+
118
+ /**
119
+ * The template to start from: the ready page the ranker puts first when it
120
+ * has the evidence to lead, else the first fallback shell the project can
121
+ * scaffold. Null only when the project has no page template to offer at all.
122
+ *
123
+ * `direct` means two independent signals agree: the ranker's pick is also
124
+ * search's direct match. The ranker sees only ready templates, so a template
125
+ * still marked not ready is never the start; when search matched one directly
126
+ * the reason names it, so the reader knows why the kit starts elsewhere.
127
+ *
128
+ * @param {import('./rank.mjs').RankedPage[]} ranked
129
+ * @param {SearchResultEntry[]} pages
130
+ * @param {boolean} directMatch
131
+ * @param {PageTemplate[]} catalog
132
+ * @returns {Omit<BuildStart, 'alternatives'> | null}
133
+ */
134
+ function chooseStart(ranked, pages, directMatch, catalog) {
135
+ const direct = directMatch ? pages[0].name : null;
136
+ const unready =
137
+ direct && !catalog.some(t => t.name === direct) ? direct : null;
138
+ // The reason never denies a match the same response reports: a direct
139
+ // match the ranker outweighed is named, and so are the loose page matches
140
+ // search listed when the kit falls back to the shell.
141
+ const loose = pages.map(p => `\`${p.name}\``).join(', ');
142
+ const pick = pickStart(ranked);
143
+ const closest = pick && catalog.find(t => t.name === pick.name);
144
+ if (closest) {
145
+ const agrees = closest.name === direct;
146
+ return {
147
+ ...asTemplate(closest),
148
+ basis: agrees ? 'direct' : 'closest',
149
+ reason: agrees
150
+ ? 'Matches the idea.'
151
+ : unready
152
+ ? `\`${unready}\` matches but is not ready yet; this is the closest ready template.`
153
+ : direct
154
+ ? `Search matched \`${direct}\` by name, but this template fits more of the idea.`
155
+ : 'The closest template; none is exactly this page.',
156
+ };
157
+ }
158
+ for (const id of FALLBACK_STARTS) {
159
+ const shell = catalog.find(t => t.name === id);
160
+ if (shell) {
161
+ // The shell can also be the ranker's best guess without the evidence to
162
+ // lead ("horizontal site navigation"); say so rather than "no match".
163
+ const nearest = ranked[0]?.name === shell.name && ranked[0].hits > 0;
164
+ return {
165
+ ...asTemplate(shell),
166
+ basis: 'fallback',
167
+ reason: unready
168
+ ? `\`${unready}\` matches but is not ready yet, so start from the app shell.`
169
+ : direct
170
+ ? `Search matched \`${direct}\` by name, but too little of the idea fits it, so start from the app shell.`
171
+ : nearest
172
+ ? 'No template is a clear match; the app shell is the closest.'
173
+ : loose
174
+ ? `Search matched ${loose} only loosely, so start from the app shell.`
175
+ : 'No template matched, so start from the app shell.',
176
+ };
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+
182
+ /**
183
+ * The page template to start from, and the kit around it.
79
184
  *
80
185
  * @param {string} query what you're building (e.g. "analytics dashboard")
81
186
  * @param {{cwd?: string, type?: import('../../search/search.type.mjs').SearchDomain, limit?: number}} [options]
@@ -98,7 +203,7 @@ export async function buildKit(query, options = {}) {
98
203
  const matchCount = result.data.matchCount;
99
204
 
100
205
  /**
101
- * Did this result answer enough of the query to stand as a page?
206
+ * Did this result answer enough of the query to stand as a page on breadth?
102
207
  * Single-concept queries have nothing to cover, so they always pass. Coverage
103
208
  * stays in a module-private WeakMap and never enters public search/build JSON.
104
209
  * @param {object} r
@@ -110,7 +215,7 @@ export async function buildKit(query, options = {}) {
110
215
  return (coverage?.matched ?? 0) / total >= PAGE_COVERAGE;
111
216
  };
112
217
 
113
- const pages = results
218
+ const matchedPages = results
114
219
  .filter(
115
220
  r =>
116
221
  r.domain === 'template' &&
@@ -135,32 +240,42 @@ export async function buildKit(query, options = {}) {
135
240
  !ALWAYS.has(r.name),
136
241
  )
137
242
  .slice(0, 6);
138
- const directMatch = pages.length > 0 && pages[0].score >= PAGE_DIRECT;
243
+ const directMatch =
244
+ matchedPages.length > 0 && matchedPages[0].score >= PAGE_DIRECT;
139
245
 
140
246
  /**
141
- * On a loose match, recommend reading the layout rather than scaffolding it.
142
- *
143
- * A page entry's `command` is what a caller runs next, and it was always the
144
- * scaffold command — `template <name>` — even when the kit had just decided
145
- * the top page was NOT a direct match. The renderer already says the right
146
- * thing to a human in that case: RECOMMENDED START prints
147
- * `template <name> --skeleton` and the PAGE TEMPLATES heading reads "use as
148
- * a layout reference". But prose is not what a program reads. A JSON caller
149
- * takes `command` and gets the scaffold, so the two audiences were given
150
- * opposite advice from the same kit.
151
- *
152
- * That matters most for the caller least able to notice. `template <name>`
153
- * emits the whole page, and an agent handed a full template it did not quite
154
- * ask for tends to adapt it anyway — which is how a request for one thing
155
- * comes back as a competent version of another. `--skeleton` gives the
156
- * layout without the invitation.
157
- *
158
- * Copied rather than mutated: these entries come from `search()` and are not
159
- * this function's to modify.
247
+ * On a loose match, a page entry's `command` previews the layout rather
248
+ * than printing the whole template: `--skeleton` gives the shape without
249
+ * presenting the page as the thing to build. The recommendation itself is
250
+ * `start`, which always scaffolds. Copied rather than mutated: these entries
251
+ * come from `search()` and are not this function's to modify.
160
252
  */
161
- const recommendedPages = directMatch
162
- ? pages
163
- : pages.map(page => ({...page, command: `${page.command} --skeleton`}));
253
+ const pages = directMatch
254
+ ? matchedPages
255
+ : matchedPages.map(page => ({
256
+ ...page,
257
+ command: `${page.command} --skeleton`,
258
+ }));
259
+
260
+ // A kit narrowed to components or hooks has no page to start from; every
261
+ // other kit does, so the reader is never left to compose a page from scratch.
262
+ const wantsPages = !type || type === 'template';
263
+ const catalog = wantsPages ? await loadPageTemplates(cwd) : [];
264
+ const ranked = wantsPages ? rankPages(query, catalog) : [];
265
+ const chosen = wantsPages
266
+ ? chooseStart(ranked, matchedPages, directMatch, catalog)
267
+ : null;
268
+ // Name the ranker's next two templates beside the start: the reader judges
269
+ // meaning better than keywords do, and an acceptable template is in these
270
+ // three far more often than it is the start alone.
271
+ /** @type {BuildStart | null} */
272
+ const start = chosen && {
273
+ ...chosen,
274
+ alternatives: pickAlternatives(ranked, chosen.name).flatMap(r => {
275
+ const t = catalog.find(c => c.name === r.name);
276
+ return t ? [asTemplate(t)] : [];
277
+ }),
278
+ };
164
279
 
165
280
  // What to try when the kit comes back thin. Keyword search over a design
166
281
  // system misses in a predictable way — the reader's words and the package's
@@ -185,12 +300,13 @@ export async function buildKit(query, options = {}) {
185
300
  type: 'build.kit',
186
301
  data: {
187
302
  query: result.data.query,
188
- // Distinguishes "search found nothing" (renderer shows "No matches")
189
- // from a weak-but-non-empty result set (renderer still shows the kit).
303
+ // Distinguishes "search found nothing" from a weak-but-non-empty result
304
+ // set. Either way the kit still names a template to start from.
190
305
  hasResults: matchCount > 0,
191
306
  matchCount,
192
307
  directMatch,
193
- pages: recommendedPages,
308
+ start,
309
+ pages,
194
310
  blocks,
195
311
  domain,
196
312
  frame: FRAME,
@@ -0,0 +1,44 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * @typedef {import('../_adapter.mjs').PageTemplate} PageTemplate
6
+ * @typedef {{name: string, score: number, hits: number, familyNamed: boolean, containerMatched: boolean}} RankedPage
7
+ */
8
+ /**
9
+ * Rank page templates against an idea, best first. Ties go to the template
10
+ * with the shorter id (the family's broader page), then by name.
11
+ *
12
+ * @param {string} query
13
+ * @param {PageTemplate[]} pages
14
+ * @returns {RankedPage[]}
15
+ */
16
+ export function rankPages(query: string, pages: PageTemplate[]): RankedPage[];
17
+ /**
18
+ * The next closest templates after the start, best first: the ones a reader
19
+ * should check the idea against when the start's shape is wrong. Each matched
20
+ * at least one term and scored at least half of what a start needs.
21
+ *
22
+ * @param {RankedPage[]} ranked
23
+ * @param {string} startName
24
+ * @param {number} [count]
25
+ * @returns {RankedPage[]}
26
+ */
27
+ export function pickAlternatives(ranked: RankedPage[], startName: string, count?: number): RankedPage[];
28
+ /**
29
+ * The template to start from, or null when the best one has too little
30
+ * evidence to lead and the page should start from the app shell. Evidence is
31
+ * two matched terms, the idea naming the template's family, or its container.
32
+ *
33
+ * @param {RankedPage[]} ranked
34
+ * @returns {RankedPage | null}
35
+ */
36
+ export function pickStart(ranked: RankedPage[]): RankedPage | null;
37
+ export type PageTemplate = import("../_adapter.mjs").PageTemplate;
38
+ export type RankedPage = {
39
+ name: string;
40
+ score: number;
41
+ hits: number;
42
+ familyNamed: boolean;
43
+ containerMatched: boolean;
44
+ };