@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +175 -154
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/help/help.mjs +1 -1
  7. package/api/build/kit/kit.mjs +3 -11
  8. package/api/component/_adapter.d.mts +72 -1
  9. package/api/component/_adapter.mjs +212 -18
  10. package/api/component/component.doc.mjs +6 -1
  11. package/api/component/component.mjs +82 -15
  12. package/api/component/component.test.mjs +80 -0
  13. package/api/component/doc-links.test.mjs +386 -0
  14. package/api/component/integration-export-name.test.mjs +644 -0
  15. package/api/component/list/list.mjs +42 -4
  16. package/api/discover/_adapter.d.mts +132 -12
  17. package/api/discover/_adapter.mjs +488 -27
  18. package/api/discover/_adapter.test.mjs +599 -17
  19. package/api/discover/_catalog-view.d.mts +16 -5
  20. package/api/discover/_catalog-view.mjs +32 -8
  21. package/api/discover/detail/doc/doc.mjs +9 -1
  22. package/api/discover/discover.d.mts +11 -0
  23. package/api/discover/discover.doc.mjs +9 -7
  24. package/api/discover/discover.mjs +121 -19
  25. package/api/discover/discover.type.d.mts +20 -7
  26. package/api/discover/discover.type.mjs +17 -7
  27. package/api/discover/list/list.d.mts +4 -3
  28. package/api/discover/list/list.mjs +17 -10
  29. package/api/docs/_adapter.d.mts +74 -0
  30. package/api/docs/_adapter.mjs +553 -16
  31. package/api/docs/docs.doc.mjs +2 -1
  32. package/api/docs/docs.mjs +2 -1
  33. package/api/docs/docs.test.mjs +5 -2
  34. package/api/docs/integration-tree.test.mjs +22 -0
  35. package/api/docs/integrationDocs.test.mjs +124 -0
  36. package/api/docs/list/list.mjs +12 -2
  37. package/api/docs/reference-blocks.test.mjs +1 -3
  38. package/api/doctor/_adapter.d.mts +108 -0
  39. package/api/doctor/_adapter.mjs +223 -4
  40. package/api/doctor/doctor.d.mts +199 -0
  41. package/api/doctor/doctor.doc.mjs +3 -2
  42. package/api/doctor/doctor.mjs +530 -34
  43. package/api/doctor/doctor.test.mjs +180 -14
  44. package/api/doctor/release-checks.test.mjs +156 -0
  45. package/api/doctor/theme-checks.mjs +17 -4
  46. package/api/doctor/theme-checks.test.mjs +223 -7
  47. package/api/error.d.mts +10 -0
  48. package/api/error.mjs +25 -0
  49. package/api/gap-report/gap-report.d.mts +3 -0
  50. package/api/gap-report/gap-report.doc.mjs +11 -3
  51. package/api/gap-report/gap-report.mjs +219 -52
  52. package/api/gap-report/gap-report.test.mjs +233 -0
  53. package/api/gap-report/gap-report.type.d.mts +41 -0
  54. package/api/gap-report/gap-report.type.mjs +18 -0
  55. package/api/hook/_adapter.mjs +3 -11
  56. package/api/hook/hook.doc.mjs +4 -0
  57. package/api/hook/list/list.d.mts +1 -1
  58. package/api/index.d.mts +2 -0
  59. package/api/index.mjs +2 -0
  60. package/api/init/_adapter.d.mts +22 -0
  61. package/api/init/_adapter.mjs +59 -0
  62. package/api/init/init.d.mts +7 -5
  63. package/api/init/init.doc.mjs +28 -7
  64. package/api/init/init.mjs +28 -4
  65. package/api/init/init.type.d.mts +48 -3
  66. package/api/init/init.type.mjs +37 -3
  67. package/api/init/run/run.d.mts +1 -1
  68. package/api/init/run/run.mjs +17 -6
  69. package/api/init/user/user.d.mts +14 -0
  70. package/api/init/user/user.mjs +87 -0
  71. package/api/init/user/user.test.mjs +232 -0
  72. package/api/integration/_adapter.d.mts +45 -0
  73. package/api/integration/_adapter.mjs +112 -0
  74. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  75. package/api/integration/add-contribution.mjs +8 -4
  76. package/api/integration/add-contribution.test.mjs +4 -2
  77. package/api/integration/authoring-checks.mjs +110 -6
  78. package/api/integration/authoring-checks.test.mjs +808 -0
  79. package/api/integration/authoring-checks.type.d.mts +143 -0
  80. package/api/integration/authoring-checks.type.mjs +74 -2
  81. package/api/integration/check/check.d.mts +96 -0
  82. package/api/integration/check/check.mjs +357 -0
  83. package/api/integration/check/check.test.mjs +489 -0
  84. package/api/integration/integration-check.type.d.mts +118 -0
  85. package/api/integration/integration-check.type.mjs +84 -0
  86. package/api/integration/integrationCheck.doc.d.mts +10 -0
  87. package/api/integration/integrationCheck.doc.mjs +73 -0
  88. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  89. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  90. package/api/integration/pack-check.mjs +364 -120
  91. package/api/integration/pack-check.test.mjs +730 -10
  92. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  93. package/api/integration/validate-integration.d.mts +8 -0
  94. package/api/integration/validate-integration.mjs +63 -9
  95. package/api/integration/validate-integration.test.mjs +88 -8
  96. package/api/integration/validate-integration.type.d.mts +16 -0
  97. package/api/integration/validate-integration.type.mjs +14 -1
  98. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  99. package/api/integration/validateIntegration.doc.mjs +19 -3
  100. package/api/search/_adapter.d.mts +11 -0
  101. package/api/search/_adapter.mjs +25 -0
  102. package/api/search/search.d.mts +82 -13
  103. package/api/search/search.doc.mjs +8 -3
  104. package/api/search/search.domain-priority.test.mjs +108 -18
  105. package/api/search/search.integration-check.test.mjs +24 -0
  106. package/api/search/search.mjs +645 -64
  107. package/api/search/search.test.mjs +179 -1
  108. package/api/search/search.type.d.mts +14 -1
  109. package/api/search/search.type.mjs +6 -1
  110. package/api/swizzle/_adapter.mjs +2 -2
  111. package/api/swizzle/copy/copy.mjs +29 -15
  112. package/api/template/template-integration.test.mjs +1 -1
  113. package/api/template/template.test.mjs +120 -3
  114. package/api/theme/_adapter.d.mts +16 -0
  115. package/api/theme/_adapter.mjs +32 -5
  116. package/api/theme/build/build.d.mts +2 -1
  117. package/api/theme/build/build.family.test.mjs +64 -0
  118. package/api/theme/build/build.mjs +250 -38
  119. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  120. package/api/theme/build/font-warning.mjs +5 -3
  121. package/api/theme/build/font-warning.test.mjs +2 -1
  122. package/api/theme/remove/remove.test.mjs +2 -2
  123. package/api/theme/targets/targets.mjs +3 -10
  124. package/api/theme/themeBuild.doc.mjs +4 -4
  125. package/api/theme/themeTargets.doc.mjs +4 -0
  126. package/api/theme/use/use.test.mjs +1 -1
  127. package/api/upgrade/_adapter.d.mts +40 -2
  128. package/api/upgrade/_adapter.mjs +118 -5
  129. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  130. package/api/upgrade/run/run.mjs +35 -2
  131. package/api/upgrade/status/status.d.mts +21 -5
  132. package/api/upgrade/status/status.mjs +45 -8
  133. package/api/upgrade/upgrade.doc.mjs +6 -3
  134. package/api/upgrade/upgrade.mjs +5 -1
  135. package/api/upgrade/upgrade.type.d.mts +23 -0
  136. package/api/upgrade/upgrade.type.mjs +16 -1
  137. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  138. package/assets/codemods/registry.mjs +1 -0
  139. package/assets/codemods/runner.mjs +7 -1
  140. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  141. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  142. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  143. package/assets/discover/official-packages.json +367 -0
  144. package/assets/docs/README.md +10 -0
  145. package/assets/docs/author-a-theme.doc.mjs +3 -3
  146. package/assets/docs/browser-support.doc.mjs +1 -1
  147. package/assets/docs/getting-started.doc.mjs +26 -6
  148. package/assets/docs/styling-overview.doc.mjs +1 -1
  149. package/assets/docs/theme.doc.dense.mjs +1 -1
  150. package/assets/docs/theme.doc.mjs +2 -2
  151. package/assets/docs/theme.doc.zh.mjs +1 -1
  152. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  153. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  154. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  155. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  156. package/assets/docs/tree/block-template.doc.mjs +8 -20
  157. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  158. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  159. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  160. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  161. package/assets/docs/tree/checks.doc.mjs +32 -24
  162. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  163. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  164. package/assets/docs/tree/cli.doc.mjs +6 -0
  165. package/assets/docs/tree/codemods.doc.mjs +17 -7
  166. package/assets/docs/tree/commands.doc.mjs +7 -1
  167. package/assets/docs/tree/component-family.doc.mjs +8 -6
  168. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  169. package/assets/docs/tree/components.doc.mjs +7 -1
  170. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  171. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  172. package/assets/docs/tree/configuration.doc.mjs +7 -3
  173. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  174. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  175. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  176. package/assets/docs/tree/docs.doc.mjs +9 -3
  177. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  178. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  179. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  180. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  181. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  182. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  183. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  184. package/assets/docs/tree/global.doc.mjs +131 -0
  185. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  186. package/assets/docs/tree/install-once.doc.mjs +105 -0
  187. package/assets/docs/tree/integrations.doc.mjs +13 -1
  188. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  189. package/assets/docs/tree/layout.doc.mjs +6 -6
  190. package/assets/docs/tree/links.doc.mjs +7 -6
  191. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  192. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  193. package/assets/docs/tree/migration.doc.mjs +0 -1
  194. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  195. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  196. package/assets/docs/tree/page-template.doc.mjs +4 -8
  197. package/assets/docs/tree/problems.doc.mjs +205 -0
  198. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  199. package/assets/docs/tree/publishing.doc.mjs +6 -6
  200. package/assets/docs/tree/quick-start.doc.mjs +53 -27
  201. package/assets/docs/tree/reference.doc.mjs +192 -0
  202. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  203. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  204. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  207. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  208. package/assets/docs/tree/single-component.doc.mjs +15 -6
  209. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  210. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  211. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  212. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  213. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  214. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  215. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  216. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  217. package/assets/docs/tree/templates.doc.mjs +7 -1
  218. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  219. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  220. package/assets/docs/tree/themes.doc.mjs +4 -0
  221. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  222. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  223. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  224. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  225. package/assets/docs/tree/updates.doc.mjs +92 -0
  226. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  227. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  228. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  229. package/assets/docs/tree/versioning.doc.mjs +10 -9
  230. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  231. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  232. package/assets/docs/use-a-theme.doc.mjs +2 -2
  233. package/assets/docs/working-with-ai.doc.mjs +66 -13
  234. package/assets/theme.template.ts +1 -1
  235. package/authoring/codemod/codemod.doc.mjs +7 -3
  236. package/authoring/config/config.doc.mjs +9 -6
  237. package/authoring/config/type.ts +4 -2
  238. package/authoring/debug/parse.d.mts +5 -5
  239. package/authoring/discover/discover.doc.mjs +7 -1
  240. package/authoring/doctypes/_schema.d.mts +8 -3
  241. package/authoring/doctypes/_schema.mjs +1 -0
  242. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  243. package/authoring/doctypes/command/command.doc.mjs +20 -12
  244. package/authoring/doctypes/command/type.ts +14 -0
  245. package/authoring/doctypes/component/component.doc.mjs +30 -27
  246. package/authoring/doctypes/component/type.ts +21 -8
  247. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  248. package/authoring/doctypes/function/function.doc.mjs +9 -8
  249. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  250. package/authoring/doctypes/hook/type.ts +4 -0
  251. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  252. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  253. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  254. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  255. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  256. package/authoring/doctypes/template/parse.d.mts +6 -2
  257. package/authoring/doctypes/template/parse.mjs +3 -1
  258. package/authoring/doctypes/template/template.doc.mjs +3 -3
  259. package/authoring/doctypes/template/type.ts +22 -0
  260. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  261. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  262. package/authoring/identity/identity.doc.mjs +3 -3
  263. package/authoring/index.d.ts +2 -0
  264. package/authoring/integration/integration.doc.mjs +30 -6
  265. package/authoring/integration/parse.test.mjs +21 -0
  266. package/authoring/integration/schema.d.mts +16 -3
  267. package/authoring/integration/schema.mjs +34 -2
  268. package/authoring/integration/type.ts +12 -0
  269. package/clients/cli/bin/astryx.mjs +20 -3
  270. package/clients/cli/cli-command.test.mjs +166 -0
  271. package/clients/cli/commands/blog.doc.mjs +1 -0
  272. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  273. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  274. package/clients/cli/commands/build-theme.mjs +26 -13
  275. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  276. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  277. package/clients/cli/commands/build.doc.mjs +1 -0
  278. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  279. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  280. package/clients/cli/commands/component.doc.mjs +1 -0
  281. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  282. package/clients/cli/commands/discover.doc.mjs +9 -1
  283. package/clients/cli/commands/discover.mjs +144 -93
  284. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  285. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  286. package/clients/cli/commands/docs.doc.mjs +1 -0
  287. package/clients/cli/commands/docs.mjs +49 -19
  288. package/clients/cli/commands/docs.test.mjs +2 -2
  289. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  290. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  291. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  292. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  293. package/clients/cli/commands/doctor-integration.test.mjs +888 -3
  294. package/clients/cli/commands/doctor.doc.mjs +12 -2
  295. package/clients/cli/commands/doctor.mjs +292 -7
  296. package/clients/cli/commands/doctor.test.mjs +10 -4
  297. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  298. package/clients/cli/commands/gap-report.mjs +24 -2
  299. package/clients/cli/commands/gap-report.test.mjs +79 -0
  300. package/clients/cli/commands/hook.doc.mjs +1 -0
  301. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  302. package/clients/cli/commands/init.doc.mjs +29 -3
  303. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  304. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  305. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  306. package/clients/cli/commands/integration-check.test.mjs +441 -0
  307. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  308. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  309. package/clients/cli/commands/integration.doc.mjs +6 -2
  310. package/clients/cli/commands/integration.mjs +119 -7
  311. package/clients/cli/commands/json-contract.test.mjs +11 -2
  312. package/clients/cli/commands/manifest.doc.mjs +1 -0
  313. package/clients/cli/commands/outside-project.test.mjs +774 -0
  314. package/clients/cli/commands/search.doc.mjs +1 -0
  315. package/clients/cli/commands/search.mjs +16 -11
  316. package/clients/cli/commands/search.test.mjs +429 -296
  317. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  318. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  319. package/clients/cli/commands/swizzle.mjs +5 -3
  320. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  321. package/clients/cli/commands/template.doc.mjs +1 -0
  322. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  323. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  324. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  325. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  326. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  327. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  328. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  329. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  330. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  331. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  332. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  333. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  334. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  335. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  336. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  337. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  338. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  339. package/clients/cli/index.mjs +112 -16
  340. package/clients/cli/lib/cli-error.mjs +4 -1
  341. package/clients/cli/lib/component-format.test.mjs +1 -1
  342. package/clients/cli/lib/define-command.mjs +2 -2
  343. package/clients/cli/lib/json-shim.mjs +3 -1
  344. package/clients/cli/lib/manifest.d.ts +9 -0
  345. package/clients/cli/lib/manifest.mjs +17 -1
  346. package/clients/cli/lib/manifest.test.mjs +25 -0
  347. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  348. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  349. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  350. package/foundation/agent-docs/agent-docs.mjs +11 -9
  351. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  352. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  353. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  354. package/foundation/config/project.d.mts +35 -3
  355. package/foundation/config/project.mjs +226 -7
  356. package/foundation/config/project.test.mjs +66 -0
  357. package/foundation/config/theme-state.mjs +5 -4
  358. package/foundation/discovery/authoring-self-docs.mjs +2 -1
  359. package/foundation/discovery/cli-self-docs.mjs +20 -3
  360. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  361. package/foundation/discovery/component-discovery.d.mts +190 -10
  362. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  363. package/foundation/discovery/component-discovery.mjs +864 -56
  364. package/foundation/discovery/component-discovery.test.mjs +96 -0
  365. package/foundation/discovery/component-replacement.mjs +20 -1
  366. package/foundation/discovery/component-replacement.test.mjs +40 -0
  367. package/foundation/discovery/copied-passages.d.mts +216 -0
  368. package/foundation/discovery/copied-passages.mjs +720 -0
  369. package/foundation/discovery/copied-passages.test.mjs +124 -0
  370. package/foundation/discovery/doc-consistency.d.mts +34 -0
  371. package/foundation/discovery/doc-consistency.mjs +513 -0
  372. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  373. package/foundation/discovery/doc-fluff.d.mts +112 -0
  374. package/foundation/discovery/doc-fluff.mjs +328 -0
  375. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  376. package/foundation/discovery/doc-types.d.mts +157 -0
  377. package/foundation/discovery/doc-types.mjs +1231 -0
  378. package/foundation/discovery/doc-types.test.mjs +744 -0
  379. package/foundation/discovery/docs-discovery.d.mts +88 -0
  380. package/foundation/discovery/docs-discovery.mjs +83 -2
  381. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  382. package/foundation/discovery/integration-doc-files.mjs +231 -0
  383. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  384. package/foundation/discovery/module-exports.d.mts +27 -0
  385. package/foundation/discovery/module-exports.mjs +356 -31
  386. package/foundation/discovery/module-exports.test.mjs +172 -0
  387. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  388. package/foundation/discovery/package-tsconfig.mjs +228 -0
  389. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  390. package/foundation/discovery/project-typescript.d.mts +32 -0
  391. package/foundation/discovery/project-typescript.mjs +89 -0
  392. package/foundation/discovery/prop-drift.d.mts +297 -0
  393. package/foundation/discovery/prop-drift.mjs +2428 -0
  394. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  395. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  396. package/foundation/discovery/runner-allowlist.mjs +53 -0
  397. package/foundation/discovery/stray-pointers.d.mts +52 -0
  398. package/foundation/discovery/stray-pointers.mjs +293 -0
  399. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  400. package/foundation/discovery/template-adapter.mjs +74 -5
  401. package/foundation/discovery/template-needs.mjs +5 -2
  402. package/foundation/discovery/theme-imports.mjs +8 -4
  403. package/foundation/discovery/theme-imports.test.mjs +1 -1
  404. package/foundation/discovery/type-match.d.mts +53 -0
  405. package/foundation/discovery/type-match.mjs +660 -0
  406. package/foundation/discovery/type-match.test.mjs +169 -0
  407. package/foundation/discovery/type-text.d.mts +68 -0
  408. package/foundation/discovery/type-text.mjs +658 -0
  409. package/foundation/discovery/type-text.test.mjs +196 -0
  410. package/foundation/discovery/unresolved-references.d.mts +62 -0
  411. package/foundation/discovery/unresolved-references.mjs +790 -0
  412. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  413. package/foundation/doc-compiler/doc-loads.test.mjs +51 -1
  414. package/foundation/doc-compiler/inputs.mjs +27 -1
  415. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  416. package/foundation/doc-compiler/links.d.mts +41 -5
  417. package/foundation/doc-compiler/links.mjs +167 -28
  418. package/foundation/doc-compiler/links.test.mjs +97 -4
  419. package/foundation/doc-compiler/read.d.mts +1 -1
  420. package/foundation/doc-compiler/tree.mjs +30 -1
  421. package/foundation/doc-compiler/tree.test.mjs +8 -1
  422. package/foundation/env/cli-command.d.mts +83 -0
  423. package/foundation/env/cli-command.mjs +152 -0
  424. package/foundation/env/cli-command.test.mjs +129 -0
  425. package/foundation/env/node-version.test.mjs +15 -3
  426. package/foundation/env/package-manager.d.mts +93 -9
  427. package/foundation/env/package-manager.global.test.mjs +66 -0
  428. package/foundation/env/package-manager.mjs +184 -13
  429. package/foundation/env/package-manager.test.mjs +341 -15
  430. package/foundation/env/project-scope.d.mts +9 -0
  431. package/foundation/env/project-scope.mjs +33 -0
  432. package/foundation/env/search-path.d.mts +42 -0
  433. package/foundation/env/search-path.mjs +205 -0
  434. package/foundation/env/search-path.test.mjs +122 -0
  435. package/foundation/env/user-dirs.d.mts +39 -0
  436. package/foundation/env/user-dirs.mjs +93 -0
  437. package/foundation/env/user-dirs.test.mjs +72 -0
  438. package/foundation/env/user-settings.d.mts +46 -0
  439. package/foundation/env/user-settings.mjs +106 -0
  440. package/foundation/env/user-settings.test.mjs +64 -0
  441. package/foundation/fs/file-protection.mjs +15 -1
  442. package/foundation/fs/module-loader.d.mts +2 -1
  443. package/foundation/fs/module-loader.mjs +60 -4
  444. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  445. package/foundation/fs/module-loader.test.mjs +194 -0
  446. package/foundation/fs/path-compare.d.mts +33 -0
  447. package/foundation/fs/path-compare.mjs +73 -0
  448. package/foundation/fs/paths.d.mts +57 -1
  449. package/foundation/fs/paths.mjs +131 -3
  450. package/foundation/fs/paths.test.mjs +10 -1
  451. package/foundation/integrations/computer-integrations.d.mts +78 -0
  452. package/foundation/integrations/computer-integrations.mjs +316 -0
  453. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  454. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  455. package/foundation/integrations/contribution-inventory.mjs +56 -3
  456. package/foundation/integrations/integration-warnings.mjs +3 -2
  457. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  458. package/foundation/integrations/integrations.d.mts +25 -1
  459. package/foundation/integrations/integrations.mjs +46 -3
  460. package/foundation/integrations/issue.ts +6 -0
  461. package/foundation/integrations/validate-contributions.d.mts +2 -0
  462. package/foundation/integrations/validate-contributions.mjs +41 -1
  463. package/foundation/release/agent-text-worker.d.mts +4 -0
  464. package/foundation/release/agent-text-worker.mjs +52 -0
  465. package/foundation/release/cache.d.mts +310 -0
  466. package/foundation/release/cache.mjs +1216 -0
  467. package/foundation/release/cache.test.mjs +920 -0
  468. package/foundation/release/choose.d.mts +207 -0
  469. package/foundation/release/choose.mjs +677 -0
  470. package/foundation/release/choose.test.mjs +427 -0
  471. package/foundation/release/core-worker.d.mts +4 -0
  472. package/foundation/release/core-worker.mjs +38 -0
  473. package/foundation/release/global-state.d.mts +259 -0
  474. package/foundation/release/global-state.mjs +472 -0
  475. package/foundation/release/global-state.test.mjs +381 -0
  476. package/foundation/release/handoff.d.mts +60 -0
  477. package/foundation/release/handoff.e2e.test.mjs +278 -0
  478. package/foundation/release/handoff.mjs +357 -0
  479. package/foundation/release/lock-lease.d.mts +23 -0
  480. package/foundation/release/lock-lease.mjs +80 -0
  481. package/foundation/release/notices.d.mts +253 -0
  482. package/foundation/release/notices.mjs +596 -0
  483. package/foundation/release/notices.test.mjs +565 -0
  484. package/foundation/release/npm-guard.d.mts +4 -0
  485. package/foundation/release/npm-guard.mjs +126 -0
  486. package/foundation/release/project.d.mts +141 -0
  487. package/foundation/release/project.mjs +466 -0
  488. package/foundation/release/project.test.mjs +288 -0
  489. package/foundation/release/refresh-worker.d.mts +4 -0
  490. package/foundation/release/refresh-worker.mjs +27 -0
  491. package/foundation/release/run-context.d.mts +47 -0
  492. package/foundation/release/run-context.mjs +149 -0
  493. package/foundation/release/update-notice-env.d.mts +28 -0
  494. package/foundation/release/update-notice-env.mjs +39 -0
  495. package/foundation/response/base.d.ts +26 -3
  496. package/foundation/response/error-codes.d.mts +3 -1
  497. package/foundation/response/error-codes.doc.mjs +12 -0
  498. package/foundation/response/error-codes.mjs +17 -0
  499. package/foundation/response/error-codes.test.mjs +2 -0
  500. package/foundation/response/json-contract.test.mjs +7 -2
  501. package/foundation/response/json.mjs +4 -1
  502. package/foundation/response/response-types.doc.mjs +22 -11
  503. package/foundation/response/response-types.doc.test.mjs +46 -0
  504. package/foundation/response/response.doc.mjs +3 -3
  505. package/foundation/xle/browser-imports.test.mjs +74 -0
  506. package/foundation/xle/registry.mjs +4 -0
  507. package/foundation/xle/registry.test.mjs +28 -0
  508. package/package.json +11 -11
  509. package/scripts/postinstall.mjs +24 -5
@@ -18,7 +18,9 @@ export type BlockTemplateDoc = import("./type.js").BlockTemplateDoc;
18
18
  * Templates as they load. Integration templates already published omit
19
19
  * `displayName` and `aspectRatio` and group themselves under their own
20
20
  * `category`, so the loader accepts those (template discovery falls back to an
21
- * aspect ratio of 1). The published types keep asking authors for all three.
21
+ * aspect ratio of 1). The published `TemplateDoc` keeps asking authors for all
22
+ * three; `IntegrationTemplateDoc`, for an integration package's templates,
23
+ * takes the package's own `category`.
22
24
  */
23
25
  export type LoadedPageTemplateDoc = Omit<PageTemplateDoc, "displayName" | "category"> & {
24
26
  displayName?: string;
@@ -28,7 +30,9 @@ export type LoadedPageTemplateDoc = Omit<PageTemplateDoc, "displayName" | "categ
28
30
  * Templates as they load. Integration templates already published omit
29
31
  * `displayName` and `aspectRatio` and group themselves under their own
30
32
  * `category`, so the loader accepts those (template discovery falls back to an
31
- * aspect ratio of 1). The published types keep asking authors for all three.
33
+ * aspect ratio of 1). The published `TemplateDoc` keeps asking authors for all
34
+ * three; `IntegrationTemplateDoc`, for an integration package's templates,
35
+ * takes the package's own `category`.
32
36
  */
33
37
  export type LoadedBlockTemplateDoc = Omit<BlockTemplateDoc, "displayName" | "aspectRatio" | "category"> & {
34
38
  displayName?: string;
@@ -78,7 +78,9 @@ const blockTemplateSchema = z
78
78
  * Templates as they load. Integration templates already published omit
79
79
  * `displayName` and `aspectRatio` and group themselves under their own
80
80
  * `category`, so the loader accepts those (template discovery falls back to an
81
- * aspect ratio of 1). The published types keep asking authors for all three.
81
+ * aspect ratio of 1). The published `TemplateDoc` keeps asking authors for all
82
+ * three; `IntegrationTemplateDoc`, for an integration package's templates,
83
+ * takes the package's own `category`.
82
84
  *
83
85
  * @typedef {Omit<PageTemplateDoc, 'displayName' | 'category'>
84
86
  * & {displayName?: string, category?: string}} LoadedPageTemplateDoc
@@ -31,14 +31,14 @@ export const doc = {
31
31
  name: 'name',
32
32
  type: 'string',
33
33
  description:
34
- 'Stable identifier for block templates; change `displayName`, not `name`, to edit their visible label. For page templates it is a human-readable label, while the existing template-directory/CLI slug owns the default registry path.',
34
+ "Stable identifier for block templates; change `displayName`, not `name`, to edit their visible label in the gallery. For page templates it is a human-readable label, while the existing template-directory/CLI slug owns the default registry path. `astryx template --list` and `astryx search` print `name` as the label of both, and `astryx template <id>` finds a template by its id, never by `name`: an integration template's id is its path under the templates folder without the `.doc.*` suffix.",
35
35
  required: true,
36
36
  },
37
37
  {
38
38
  name: 'displayName',
39
39
  type: 'string',
40
40
  description:
41
- "Human-readable label for the gallery/CLI. Spaces out block names that mirror a PascalCase component ('ChatMessageMetadata' → 'Chat Message Metadata').",
41
+ "Human-readable label for the gallery. The CLI prints `name` instead; `astryx template --list --json` also returns an integration template's `displayName`. Spaces out block names that mirror a PascalCase component ('ChatMessageMetadata' → 'Chat Message Metadata').",
42
42
  required: true,
43
43
  },
44
44
  {
@@ -162,7 +162,7 @@ export default {
162
162
  notes: [
163
163
  {
164
164
  type: 'prose',
165
- text: 'When it loads, a template may leave out `displayName` and `aspectRatio` and use its own `category`, as integration templates already published do; a block with no `aspectRatio` previews at 1. Write to the type anyway; it is the contract.',
165
+ text: 'When it loads, a template may leave out `displayName` and `aspectRatio` and use its own `category`, as integration templates already published do; a block with no `aspectRatio` previews at 1. Write to the type anyway; it is the contract, and `astryx doctor integration validate` warns about an integration template that leaves out `displayName` or `aspectRatio`.',
166
166
  },
167
167
  {
168
168
  type: 'prose',
@@ -201,3 +201,25 @@ export type TemplateCategory =
201
201
  | 'Shell - Blank';
202
202
 
203
203
  export type TemplateDoc = PageTemplateDoc | BlockTemplateDoc;
204
+
205
+ /** A page template an integration package ships, with its own `category`. */
206
+ export interface IntegrationPageTemplateDoc extends Omit<
207
+ PageTemplateDoc,
208
+ 'category'
209
+ > {
210
+ category?: string;
211
+ }
212
+
213
+ /** A block template an integration package ships, with its own `category`. */
214
+ export interface IntegrationBlockTemplateDoc extends Omit<
215
+ BlockTemplateDoc,
216
+ 'category'
217
+ > {
218
+ category?: string;
219
+ }
220
+
221
+ /** The doc-type for an integration package's template metadata: TemplateDoc,
222
+ * with `category` the package's own string (bare `astryx template` groups
223
+ * the package's templates by it) instead of a TemplateCategory value. */
224
+ export type IntegrationTemplateDoc =
225
+ IntegrationPageTemplateDoc | IntegrationBlockTemplateDoc;
@@ -12,7 +12,7 @@ export const doc = {
12
12
  displayName: 'ThemeDoc',
13
13
  namespace: 'authoring',
14
14
  description:
15
- 'The strongly typed descriptor for one integration or CLI-bundled source theme.',
15
+ "The strongly typed descriptor for one source theme: bundled with the CLI, shipped by an integration, or kept in the project's src/themes, where `theme eject` writes one.",
16
16
  appliesTo: '<theme-source-stem>.doc.mjs',
17
17
  fields: [
18
18
  {
@@ -65,7 +65,7 @@ export default {
65
65
  notes: [
66
66
  {
67
67
  type: 'prose',
68
- text: 'ThemeDoc is static metadata. Default-export one object with literal string and boolean fields; discovery validates it without executing the descriptor or theme source.',
68
+ text: "ThemeDoc is static metadata. The descriptor holds one default-exported object of literal string and boolean fields, directly under a `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */` comment, and nothing else: without that comment, or with any other statement, it fails to load. Discovery validates it without executing the descriptor or theme source.",
69
69
  },
70
70
  {
71
71
  type: 'prose',
@@ -15,7 +15,7 @@ export const doc = {
15
15
  displayName: 'GapReportHandler',
16
16
  namespace: 'authoring',
17
17
  description:
18
- 'A handler for `astryx gap-report`: a plain object with an `audience` and a `handle` function. Set it as `gapReport` in astryx.config, or export it as `gapReport` from an integration manifest. Every handler runs: the project handler first, then each integration handler in config order.',
18
+ "A handler for `astryx gap-report`: a plain object with an `audience` and a `handle` function. Set it as `gapReport` in astryx.config, or export it as `gapReport` from an integration manifest. Handlers add up rather than replace each other: the project handler first, then each loaded integration's in load order (the `integrations` list, then autolinked ones), whichever package the report is about.",
19
19
  appliesTo:
20
20
  '`gapReport` in astryx.config.*, or the `gapReport` named export of astryx.integration.*',
21
21
  fields: [
@@ -104,7 +104,7 @@ export const doc = {
104
104
  name: 'report.target.version',
105
105
  type: 'string',
106
106
  description:
107
- 'The installed version. Null when it is not known.',
107
+ "The integration's version from its package.json. Null for Core, and when the package.json has none.",
108
108
  required: true,
109
109
  },
110
110
  {
@@ -12,7 +12,7 @@ export const doc = {
12
12
  displayName: 'Provider and artifact identity',
13
13
  namespace: 'authoring',
14
14
  description:
15
- 'Separates stable provider/artifact identity from package instances and runtime lifecycle state. Provider identity names integration manifests and settles provider conflicts. Docs-tree nodes are identified by doc identity; the tree covers the CLI\'s own docs. Artifact, instance, and compiler-input identities are defined for every provider-owned artifact; no command reads them.',
15
+ "Separates stable provider/artifact identity from package instances and runtime lifecycle state. Provider identity names integration manifests and settles provider conflicts. Docs-tree nodes are identified by doc identity; the tree covers the CLI's docs and each integration's. Artifact IDs for kinds outside the docs tree, provider instances, and compiler-input entries are defined for every provider-owned artifact; no command builds them.",
16
16
  appliesTo:
17
17
  'Integration manifests, provider conflicts, and docs-tree node ids.',
18
18
  fields: [
@@ -41,14 +41,14 @@ export const doc = {
41
41
  name: 'ProviderInstance',
42
42
  type: '{ id; providerId; packageName; packageVersion; sourceDigest }',
43
43
  description:
44
- 'One immutable package version and source/content digest. Installed, configured, loaded, selected, and healthy state is a separate runtime overlay.',
44
+ 'One immutable package version and source/content digest. It carries no installed, configured, loaded, selected, or healthy state.',
45
45
  required: true,
46
46
  },
47
47
  {
48
48
  name: 'AuthoredDocEntry',
49
49
  type: '{ id; provider; kind; stableName; source; authored }',
50
50
  description:
51
- 'Normalized compiler input. Discovery supplies stableName independently from the authored display name, source paths remain package-relative, and provider provenance plus the authored snapshot are immutable.',
51
+ 'Normalized compiler input. `stableName`, the key in its doc ID, is given separately from the authored display name; source paths remain package-relative, and provider provenance plus the authored snapshot are immutable.',
52
52
  required: true,
53
53
  },
54
54
  ],
@@ -28,6 +28,7 @@ export type {HookDoc} from './doctypes/types.js'; // useToast.doc.mjs
28
28
  export type {FunctionDoc} from './doctypes/types.js'; // search.doc.mjs (hook | api)
29
29
  export type {ReferenceDoc} from './doctypes/types.js'; // theming.doc.mjs
30
30
  export type {TemplateDoc} from './doctypes/types.js'; // Foo.doc.mjs
31
+ export type {IntegrationTemplateDoc} from './doctypes/types.js'; // an integration's Foo.doc.mjs
31
32
  export type {SchemaDoc} from './doctypes/types.js'; // config.doc.mjs (object shape)
32
33
  export type {CommandDoc} from './doctypes/types.js'; // search.doc.mjs (CLI command)
33
34
  export type {EnumDoc} from './doctypes/types.js'; // error-codes.doc.mjs (vocabulary)
@@ -162,6 +163,7 @@ export type {
162
163
  CommandArgDoc,
163
164
  CommandOptionDoc,
164
165
  CommandExampleDoc,
166
+ CommandOutsideProject,
165
167
  // enum
166
168
  EnumMemberDoc,
167
169
  } from './doctypes/types.js';
@@ -16,7 +16,7 @@ export const doc = {
16
16
  'The astryx.integration.* manifest that sits beside an integration ' +
17
17
  "package's package.json. It can preserve a stable provider identity across a package rename, " +
18
18
  "and points the CLI at the package's components, templates, codemods, doc topics, " +
19
- 'source themes, managed agent guidance, and issue tracker. Every field is optional.',
19
+ 'source themes, managed agent guidance, issue tracker, and the command its users run the CLI with. Every field is optional.',
20
20
  appliesTo: 'astryx.integration.{ts,mjs,js}',
21
21
  fields: [
22
22
  {
@@ -51,7 +51,7 @@ export const doc = {
51
51
  name: 'docs',
52
52
  type: 'string',
53
53
  description:
54
- 'The folder that holds your doc topics, relative to package.json. Every {topic}.doc.{ts,mjs,js} in it shows up in `astryx docs` next to the built-in topics; a topic can also set `replaces` or `extends` to take over a built-in topic or add to it.',
54
+ 'The folder that holds your doc topics, relative to package.json. Every {topic}.doc.{ts,mjs,js} under it shows up in `astryx docs`: a flat topic next to the built-in topics, where it can set `replaces` or `extends` to take over a built-in topic or add to it, and a guide with `placement` at its own route in the docs tree, under a namespace doc of the same package.',
55
55
  example: "'./docs'",
56
56
  },
57
57
  {
@@ -71,9 +71,24 @@ export const doc = {
71
71
  {
72
72
  name: 'issuesUrl',
73
73
  type: 'string',
74
- description: 'Where to file issues/feedback for this integration.',
74
+ description:
75
+ "Where people file issues for this package: an absolute URL, such as its GitHub issues page. A value that is not a URL fails the whole manifest; the scheme is not checked. Nothing warns when it is missing, but without it `astryx gap-report` about this package fails unless the project or a loaded integration has a gapReport handler, and `astryx swizzle` prints no feedback link for this package's components. When no handler is loaded, a github.com issues URL is filed with the GitHub CLI once the reporter passes `--confirm-public`; any other URL is returned for the reporter to open.",
75
76
  example: "'https://github.com/acme/widgets/issues'",
76
77
  },
78
+ {
79
+ name: 'docsiteUrl',
80
+ type: 'string',
81
+ description:
82
+ "Link to this integration's docs site, such as its home page. Catalogs that list the package may show it.",
83
+ example: "'https://widgets.acme.dev'",
84
+ },
85
+ {
86
+ name: 'cliCommand',
87
+ type: 'string',
88
+ description:
89
+ 'The command your users run the Astryx CLI with, when it is not their package manager, such as a wrapper your company ships. Every command the CLI prints in an app that loads your package starts with it, in place of `pnpm exec astryx` or `yarn astryx`: hints, errors, Doctor fixes, and doc text. One line, without a subcommand. If two loaded packages set different commands, neither is used and `astryx doctor` warns. An invalid value is ignored with an `invalid_cli_command` warning, and the rest of the manifest still loads. JSON output keeps commands bare.',
90
+ example: "'acme astryx'",
91
+ },
77
92
  ],
78
93
  examples: [
79
94
  {
@@ -92,6 +107,10 @@ export const doc = {
92
107
  },
93
108
  ],
94
109
  notes: [
110
+ {
111
+ type: 'prose',
112
+ text: "In global mode: a manifest loads the same way when users install your package for their computer, beside the global CLI, and then applies in folders outside any project; inside a project, only if the project installs it. Peer ranges for `@astryxdesign/core` and `@astryxdesign/cli` are checked against the global CLI's release. See {@link namespace:global} and {@link generic:global-integrations}.",
113
+ },
95
114
  {
96
115
  type: 'prose',
97
116
  text:
@@ -107,18 +126,23 @@ export const doc = {
107
126
  'trimmed, non-blank string of at most 240 Unicode code points with no ' +
108
127
  'line separators, control characters, NUL, or Astryx/XDS managed-marker ' +
109
128
  'text. The configured project may contain at most 32 integration lines ' +
110
- 'total.',
129
+ 'total. Write each command in a line as a bare `astryx` command; the ' +
130
+ 'managed block says once, before your lines, how the app starts the CLI.',
131
+ },
132
+ {
133
+ type: 'prose',
134
+ text: "Set `cliCommand` only when your users run the CLI with a command other than their package manager's, such as `acme astryx`. The CLI picks the command it prints in this order: the `cliCommand` of the loaded integrations when they name one command, then the command a host tool names, then the package manager's. Two different `cliCommand` values cancel out, and `astryx doctor` warns in its `cli-command` check. See `astryx docs cli/integrations/building-blocks/configuration/cli-command`.",
111
135
  },
112
136
  {
113
137
  type: 'prose',
114
- text: 'A themes root is forward-compatible but version-gated: a CLI released before this field ignores it with a warning and continues loading every contribution kind it understands. That older CLI cannot list or add the contributed themes.',
138
+ text: 'A themes root is version-gated: an older CLI lists and adds none of its themes. Depending on its age, that CLI ignores `themes` with an `unknown_manifest_key` warning and loads every other contribution kind, reports the root as invalid because it expects the earlier `manifest.json` theme catalog, or, if it is old enough to treat an unknown field as an error, rejects the whole manifest, so the package contributes nothing there.',
115
139
  },
116
140
  {
117
141
  type: 'prose',
118
142
  text:
119
143
  'Validate the manifest with `astryx doctor integration validate`. At the ' +
120
144
  'load boundary, a known field of the wrong type is an error, issuesUrl ' +
121
- 'must be a valid URL, and unknown fields become warnings so an older CLI ' +
145
+ 'and docsiteUrl must be valid URLs, and unknown fields become warnings so an older CLI ' +
122
146
  'can still load the fields it understands. Before publishing, also run ' +
123
147
  '`templates`, `components`, and `docs` under the same `doctor integration` ' +
124
148
  'group. Those leaves compare authored identities with Core and explain ' +
@@ -87,6 +87,27 @@ describe('parseIntegration (load boundary)', () => {
87
87
  expect(reason({issuesUrl: 'nope'})).toContain('issuesUrl');
88
88
  });
89
89
 
90
+ it('accepts a docsiteUrl as a known key', () => {
91
+ const manifest = {docsiteUrl: 'https://widgets.example.com'};
92
+ expect(parseIntegration(manifest)).toEqual(manifest);
93
+ expect(unknownIntegrationKeys(manifest)).toEqual([]);
94
+ });
95
+
96
+ it('rejects a non-URL docsiteUrl', () => {
97
+ expect(reason({docsiteUrl: 'nope'})).toContain('docsiteUrl');
98
+ });
99
+
100
+ it('accepts a cliCommand and rejects one that is not a single clean line', () => {
101
+ expect(parseIntegration({cliCommand: 'acme astryx'})).toEqual({
102
+ cliCommand: 'acme astryx',
103
+ });
104
+ expect(reason({cliCommand: ''})).toContain('cliCommand');
105
+ expect(reason({cliCommand: ' acme astryx'})).toContain('cliCommand');
106
+ expect(reason({cliCommand: 'acme\nastryx'})).toContain('cliCommand');
107
+ expect(reason({cliCommand: 'a'.repeat(121)})).toContain('120');
108
+ expect(reason({cliCommand: 42})).toContain('cliCommand');
109
+ });
110
+
90
111
  it('rejects a noncanonical providerId', () => {
91
112
  expect(reason({providerId: 'Acme Widgets'})).toContain('providerId');
92
113
  });
@@ -3,12 +3,12 @@
3
3
 
4
4
  /**
5
5
  * Parse every default-manifest field except the independently isolated
6
- * `agentDocs` contribution.
6
+ * `agentDocs` and `cliCommand` fields.
7
7
  * @param {unknown} input
8
8
  * @param {string} label
9
- * @returns {Omit<AstryxIntegration, 'agentDocs'>}
9
+ * @returns {Omit<AstryxIntegration, 'agentDocs' | 'cliCommand'>}
10
10
  */
11
- export function parseIntegrationBase(input: unknown, label: string): Omit<AstryxIntegration, "agentDocs">;
11
+ export function parseIntegrationBase(input: unknown, label: string): Omit<AstryxIntegration, "agentDocs" | "cliCommand">;
12
12
  /**
13
13
  * Parse only the optional agent-doc contribution.
14
14
  * @param {unknown} input
@@ -16,6 +16,15 @@ export function parseIntegrationBase(input: unknown, label: string): Omit<Astryx
16
16
  * @returns {NonNullable<AstryxIntegration['agentDocs']>}
17
17
  */
18
18
  export function parseAgentDocsField(input: unknown, label: string): NonNullable<AstryxIntegration["agentDocs"]>;
19
+ /**
20
+ * Parse only the optional `cliCommand` field. Isolated like `agentDocs`: an
21
+ * invalid command is ignored with a warning, and the rest of the manifest
22
+ * still contributes.
23
+ * @param {unknown} input
24
+ * @param {string} label
25
+ * @returns {string}
26
+ */
27
+ export function parseCliCommandField(input: unknown, label: string): string;
19
28
  /**
20
29
  * The manifest keys this CLI does not know, in the order they were authored.
21
30
  *
@@ -28,6 +37,7 @@ export function parseAgentDocsField(input: unknown, label: string): NonNullable<
28
37
  * @returns {string[]}
29
38
  */
30
39
  export function unknownIntegrationKeys(input: unknown): string[];
40
+ export const cliCommandSchema: z.ZodString;
31
41
  export const agentDocsSchema: z.ZodObject<{
32
42
  append: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
33
43
  }, z.core.$strip>;
@@ -39,6 +49,7 @@ export const integrationBaseSchema: z.ZodObject<{
39
49
  docs: z.ZodOptional<z.ZodString>;
40
50
  themes: z.ZodOptional<z.ZodString>;
41
51
  issuesUrl: z.ZodOptional<z.ZodString>;
52
+ docsiteUrl: z.ZodOptional<z.ZodString>;
42
53
  }, z.core.$strip>;
43
54
  export const integrationSchema: z.ZodObject<{
44
55
  providerId: z.ZodOptional<z.ZodString>;
@@ -48,9 +59,11 @@ export const integrationSchema: z.ZodObject<{
48
59
  docs: z.ZodOptional<z.ZodString>;
49
60
  themes: z.ZodOptional<z.ZodString>;
50
61
  issuesUrl: z.ZodOptional<z.ZodString>;
62
+ docsiteUrl: z.ZodOptional<z.ZodString>;
51
63
  agentDocs: z.ZodOptional<z.ZodObject<{
52
64
  append: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
53
65
  }, z.core.$strip>>;
66
+ cliCommand: z.ZodOptional<z.ZodString>;
54
67
  }, z.core.$strip>;
55
68
  /**
56
69
  * Compile-time drift-lock: sealed schema must infer exactly {@link AstryxIntegration}.
@@ -19,6 +19,7 @@ import {formatZodError} from '../_shared/errors.mjs';
19
19
  /** @typedef {import('./type.js').AstryxIntegration} AstryxIntegration */
20
20
 
21
21
  const MAX_AGENT_DOC_LINES = 8;
22
+ const MAX_CLI_COMMAND_CODE_POINTS = 120;
22
23
  const MAX_AGENT_DOC_LINE_CODE_POINTS = 240;
23
24
  const MANAGED_MARKER_TEXT = /(?:ASTRYX|XDS):(START|END)/u;
24
25
  const PROVIDER_ID_RE =
@@ -51,6 +52,21 @@ function invalidAgentDocLine(value) {
51
52
  return null;
52
53
  }
53
54
 
55
+ export const cliCommandSchema = z.string().superRefine((value, ctx) => {
56
+ const message = invalidAgentDocLine(value);
57
+ if (message) {
58
+ ctx.addIssue({code: 'custom', message});
59
+ return;
60
+ }
61
+ const codePoints = [...value].length;
62
+ if (codePoints > MAX_CLI_COMMAND_CODE_POINTS) {
63
+ ctx.addIssue({
64
+ code: 'custom',
65
+ message: `must contain at most ${MAX_CLI_COMMAND_CODE_POINTS} Unicode code points (received ${codePoints})`,
66
+ });
67
+ }
68
+ });
69
+
54
70
  const agentDocLineSchema = z.string().superRefine((value, ctx) => {
55
71
  const message = invalidAgentDocLine(value);
56
72
  if (message) ctx.addIssue({code: 'custom', message});
@@ -78,6 +94,7 @@ export const integrationBaseSchema = z.object({
78
94
  docs: z.string().optional(),
79
95
  themes: z.string().optional(),
80
96
  issuesUrl: z.string().url().optional(),
97
+ docsiteUrl: z.string().url().optional(),
81
98
  });
82
99
 
83
100
  // Unknown top-level keys are stripped rather than rejected. `.strict()` made a key from a
@@ -91,14 +108,15 @@ export const integrationBaseSchema = z.object({
91
108
  // IS an authoring mistake and still fails here.
92
109
  export const integrationSchema = integrationBaseSchema.extend({
93
110
  agentDocs: agentDocsSchema.optional(),
111
+ cliCommand: cliCommandSchema.optional(),
94
112
  });
95
113
 
96
114
  /**
97
115
  * Parse every default-manifest field except the independently isolated
98
- * `agentDocs` contribution.
116
+ * `agentDocs` and `cliCommand` fields.
99
117
  * @param {unknown} input
100
118
  * @param {string} label
101
- * @returns {Omit<AstryxIntegration, 'agentDocs'>}
119
+ * @returns {Omit<AstryxIntegration, 'agentDocs' | 'cliCommand'>}
102
120
  */
103
121
  export function parseIntegrationBase(input, label) {
104
122
  const result = integrationBaseSchema.safeParse(input);
@@ -118,6 +136,20 @@ export function parseAgentDocsField(input, label) {
118
136
  return result.data;
119
137
  }
120
138
 
139
+ /**
140
+ * Parse only the optional `cliCommand` field. Isolated like `agentDocs`: an
141
+ * invalid command is ignored with a warning, and the rest of the manifest
142
+ * still contributes.
143
+ * @param {unknown} input
144
+ * @param {string} label
145
+ * @returns {string}
146
+ */
147
+ export function parseCliCommandField(input, label) {
148
+ const result = cliCommandSchema.safeParse(input);
149
+ if (!result.success) throw new Error(formatZodError(label, result.error));
150
+ return result.data;
151
+ }
152
+
121
153
  /**
122
154
  * Compile-time drift-lock: sealed schema must infer exactly {@link AstryxIntegration}.
123
155
  *
@@ -44,6 +44,18 @@ export interface AstryxIntegration {
44
44
  };
45
45
  /** Where to file issues/feedback for this integration. */
46
46
  issuesUrl?: string;
47
+ /** Link to this integration's docs site, such as its home page. The CLI
48
+ * accepts it as a known field; catalogs that list the package may show
49
+ * it. */
50
+ docsiteUrl?: string;
51
+ /** The command that runs the Astryx CLI for this package's users, such as
52
+ * `acme astryx`. Every command the CLI prints in a project that loads
53
+ * this package starts with it, in place of the package-manager prefix
54
+ * (`pnpm exec astryx`, `yarn astryx`). One line, no subcommand. When two
55
+ * loaded integrations set different commands, neither is used and
56
+ * `astryx doctor` warns. An invalid value is ignored with a warning; the
57
+ * rest of the manifest still loads. JSON output keeps commands bare. */
58
+ cliCommand?: string;
47
59
  }
48
60
 
49
61
  /**
@@ -14,7 +14,7 @@
14
14
  // unsupported runtimes this guard protects against.
15
15
  //
16
16
  // Sibling package modules (e.g. `cli/`, `lib/`) are resolved by this bin's REAL
17
- // path. When the CLI is installed as a package, `npx astryx` runs this file
17
+ // path. When the CLI is installed as a package, the package manager runs this file
18
18
  // through the `node_modules/.bin/astryx` symlink, and some Node versions resolve
19
19
  // relative specifiers from the symlink's directory rather than the real package
20
20
  // — breaking bare `../…` imports with a cryptic ERR_MODULE_NOT_FOUND.
@@ -53,10 +53,24 @@ if (!isNodeVersionSupported(process.versions.node)) {
53
53
  process.exit(1);
54
54
  }
55
55
 
56
+ // Global mode: choose the release that answers this folder and, when it is
57
+ // not this copy, hand the run to it before anything the project provides (its
58
+ // astryx.config, integrations, or Core) is loaded. Returns only when this copy
59
+ // answers. See foundation/release/handoff.mjs and spec AST-081 FR2 and FR9.
60
+ const {startRun} = await importSrc('../../foundation/release/handoff.mjs');
61
+ await startRun({
62
+ cliRoot: join(binDir, '..', '..', '..'),
63
+ argv: process.argv.slice(2),
64
+ });
65
+
56
66
  // Imports that transitively load `styleText` must happen AFTER the gate above,
57
67
  // so they are dynamically imported here rather than at the top of the module.
58
- const {program, loadProjectDebugHandler, handleVersionJsonPreflight} =
59
- await importSrc('index.mjs');
68
+ const {
69
+ program,
70
+ loadProjectDebugHandler,
71
+ loadProjectForHelp,
72
+ handleVersionJsonPreflight,
73
+ } = await importSrc('index.mjs');
60
74
  const {isJsonMode, toErrorEnvelope} = await importSrc('../../foundation/response/json.mjs');
61
75
  const {handleCommanderError} = await importSrc('lib/json-shim.mjs');
62
76
  const {setOutcome} = await importSrc('../../foundation/debug/index.mjs');
@@ -107,6 +121,9 @@ process.on('uncaughtException', handleFatal);
107
121
  // Pick up the project's `debug` function before parsing, so parse errors and
108
122
  // `--help` — which short-circuit before any hook runs — are reported too.
109
123
  await loadProjectDebugHandler();
124
+ // Help prints its commands while Commander parses, so a help run reads the
125
+ // project's declared `cliCommand` here.
126
+ await loadProjectForHelp();
110
127
 
111
128
  // `--version --json` answers and exits without Commander, so it runs here —
112
129
  // after the handler exists, or the run would go unrecorded.
@@ -0,0 +1,166 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * Every printed command starts with the project's CLI command: the door a host
5
+ * sets, or the `cliCommand` a loaded integration declares. JSON keeps commands
6
+ * bare.
7
+ */
8
+
9
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
10
+ import {spawnSync} from 'node:child_process';
11
+ import * as fs from 'node:fs';
12
+ import * as os from 'node:os';
13
+ import * as path from 'node:path';
14
+ import {runCli} from '../../test-utils/run-cli.mjs';
15
+ import {
16
+ hasRecordedProject,
17
+ runWithCliDoor,
18
+ } from '../../foundation/env/cli-command.mjs';
19
+ import {getCliInvocation} from '../../foundation/env/package-manager.mjs';
20
+ import {loadProjectForHelp} from './index.mjs';
21
+
22
+ const BIN = path.resolve(import.meta.dirname, 'bin', 'astryx.mjs');
23
+
24
+ /** @type {string} */
25
+ let tmpDir;
26
+
27
+ beforeEach(() => {
28
+ // Repo-local, so Vite permits importing the integration manifest.
29
+ tmpDir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-cli-command-'));
30
+ });
31
+
32
+ afterEach(() => {
33
+ fs.rmSync(tmpDir, {recursive: true, force: true});
34
+ });
35
+
36
+ /**
37
+ * An app that installs one integration declaring `cliCommand`, with no
38
+ * astryx.config: the integration is autolinked.
39
+ * @param {string} cliCommand
40
+ */
41
+ function appWithIntegration(cliCommand) {
42
+ fs.writeFileSync(
43
+ path.join(tmpDir, 'package.json'),
44
+ JSON.stringify({name: 'app', dependencies: {'@acme/x': '1.0.0'}}),
45
+ );
46
+ fs.writeFileSync(path.join(tmpDir, 'AGENTS.md'), '<!-- ASTRYX:START -->\n');
47
+ const pkg = path.join(tmpDir, 'node_modules', '@acme', 'x');
48
+ fs.mkdirSync(pkg, {recursive: true});
49
+ fs.writeFileSync(
50
+ path.join(pkg, 'package.json'),
51
+ JSON.stringify({name: '@acme/x', version: '1.0.0'}),
52
+ );
53
+ fs.writeFileSync(
54
+ path.join(pkg, 'astryx.integration.mjs'),
55
+ `export default ${JSON.stringify({cliCommand})};\n`,
56
+ );
57
+ }
58
+
59
+ describe("an integration's cliCommand", () => {
60
+ it('starts the hints of a command that never loads the project itself', async () => {
61
+ appWithIntegration('acme astryx');
62
+ const {status, stderr} = await runCli(['theme', 'remove', 'nope'], tmpDir);
63
+ expect(status).toBe(1);
64
+ expect(stderr).toContain('`acme astryx theme add nope`');
65
+ });
66
+ });
67
+
68
+ describe('the setup nudge in a project with no CLI of its own', () => {
69
+ it('names the declared cliCommand for the step after installing the CLI (spec AST-081 FR5)', async () => {
70
+ // Outside this repository: the nudge stays quiet in the CLI's own checkout.
71
+ const app = fs.mkdtempSync(
72
+ path.join(os.tmpdir(), 'astryx-cli-command-nudge-'),
73
+ );
74
+ try {
75
+ // Only Core, of another release than the CLI that answers, an
76
+ // integration declaring cliCommand, and no agent docs yet.
77
+ fs.writeFileSync(
78
+ path.join(app, 'package.json'),
79
+ JSON.stringify({
80
+ name: 'app',
81
+ dependencies: {'@acme/x': '1.0.0', '@astryxdesign/core': '0.0.1'},
82
+ }),
83
+ );
84
+ fs.writeFileSync(path.join(app, 'package-lock.json'), '{}');
85
+ for (const [name, version, extra] of [
86
+ ['@acme/x', '1.0.0', 'acme astryx'],
87
+ ['@astryxdesign/core', '0.0.1', null],
88
+ ]) {
89
+ const dir = path.join(app, 'node_modules', ...name.split('/'));
90
+ fs.mkdirSync(dir, {recursive: true});
91
+ fs.writeFileSync(
92
+ path.join(dir, 'package.json'),
93
+ JSON.stringify({name, version}),
94
+ );
95
+ if (extra) {
96
+ fs.writeFileSync(
97
+ path.join(dir, 'astryx.integration.mjs'),
98
+ `export default ${JSON.stringify({cliCommand: extra})};\n`,
99
+ );
100
+ }
101
+ }
102
+
103
+ const {stderr} = await runCli(['docs', 'tokens'], app);
104
+ expect(stderr).toContain(
105
+ 'Next step: run `npm install @astryxdesign/cli@0.0.1`, then `acme astryx init`',
106
+ );
107
+ } finally {
108
+ fs.rmSync(app, {recursive: true, force: true});
109
+ }
110
+ });
111
+ });
112
+
113
+ describe('help', () => {
114
+ it('loads the project for a help run, and only for one', async () => {
115
+ appWithIntegration('acme astryx');
116
+ const cwd = process.cwd();
117
+ process.chdir(tmpDir);
118
+ try {
119
+ await loadProjectForHelp(['docs', 'theme']);
120
+ expect(hasRecordedProject(tmpDir)).toBe(false);
121
+ await loadProjectForHelp(['component', '--help']);
122
+ expect(getCliInvocation(tmpDir)).toBe('acme astryx');
123
+ } finally {
124
+ process.chdir(cwd);
125
+ }
126
+ });
127
+
128
+ it("prints the integration's command in `--help`", () => {
129
+ appWithIntegration('acme astryx');
130
+ const result = spawnSync(process.execPath, [BIN, '--help'], {
131
+ cwd: tmpDir,
132
+ encoding: 'utf-8',
133
+ });
134
+ expect(result.status).toBe(0);
135
+ expect(result.stdout).toContain('acme astryx search button');
136
+ });
137
+ });
138
+
139
+ describe("a host's door", () => {
140
+ it('prefixes doc commands in text and leaves them bare in JSON', async () => {
141
+ const text = await runWithCliDoor('acme astryx', () =>
142
+ runCli(['docs', 'getting-started', '--full']),
143
+ );
144
+ expect(text.stdout).toContain('acme astryx init');
145
+
146
+ const json = await runWithCliDoor('acme astryx', () =>
147
+ runCli(['docs', 'getting-started', '--json']),
148
+ );
149
+ expect(json.stdout).toContain('astryx init');
150
+ expect(json.stdout).not.toContain('acme astryx');
151
+ });
152
+
153
+ it('prefixes suggested commands in text and leaves them bare in JSON', async () => {
154
+ const text = await runWithCliDoor('acme astryx', () =>
155
+ runCli(['search', '']),
156
+ );
157
+ expect(text.stderr).toContain('acme astryx search button');
158
+
159
+ const json = await runWithCliDoor('acme astryx', () =>
160
+ runCli(['search', '', '--json']),
161
+ );
162
+ expect(JSON.parse(json.stdout).suggestions[0].name).toBe(
163
+ 'astryx search button',
164
+ );
165
+ });
166
+ });