@astryxdesign/cli 0.6.3 → 0.6.4-canary.078fd25

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 (728) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +152 -107
  3. package/api/blog/blog.doc.mjs +1 -0
  4. package/api/build/_adapter.d.mts +50 -0
  5. package/api/build/_adapter.mjs +60 -0
  6. package/api/build/build.doc.mjs +22 -10
  7. package/api/build/build.test.mjs +219 -8
  8. package/api/build/build.type.d.mts +91 -2
  9. package/api/build/build.type.mjs +52 -8
  10. package/api/build/help/help.d.mts +12 -5
  11. package/api/build/help/help.mjs +69 -6
  12. package/api/build/kit/kit.d.mts +4 -1
  13. package/api/build/kit/kit.mjs +208 -53
  14. package/api/build/kit/rank.d.mts +44 -0
  15. package/api/build/kit/rank.mjs +432 -0
  16. package/api/build/kit/rank.test.mjs +196 -0
  17. package/api/component/_adapter.d.mts +31 -12
  18. package/api/component/_adapter.mjs +79 -15
  19. package/api/component/component.d.mts +6 -3
  20. package/api/component/component.doc.mjs +49 -19
  21. package/api/component/component.mjs +339 -22
  22. package/api/component/component.test.mjs +38 -0
  23. package/api/component/component.type.d.mts +47 -11
  24. package/api/component/component.type.mjs +76 -24
  25. package/api/component/detail/blocks/blocks.d.mts +2 -1
  26. package/api/component/detail/blocks/blocks.mjs +4 -3
  27. package/api/component/list/list.d.mts +0 -5
  28. package/api/component/list/list.mjs +40 -11
  29. package/api/discover/_adapter.d.mts +114 -6
  30. package/api/discover/_adapter.mjs +372 -17
  31. package/api/discover/_adapter.test.mjs +215 -0
  32. package/api/discover/_catalog-view.d.mts +115 -0
  33. package/api/discover/_catalog-view.mjs +203 -0
  34. package/api/discover/_catalog-view.test.mjs +128 -0
  35. package/api/discover/detail/detail.d.mts +18 -6
  36. package/api/discover/detail/detail.mjs +67 -13
  37. package/api/discover/detail/detail.test.mjs +85 -0
  38. package/api/discover/detail/item/item.d.mts +26 -0
  39. package/api/discover/detail/item/item.mjs +78 -0
  40. package/api/discover/detail/item/item.test.mjs +73 -0
  41. package/api/discover/discover.d.mts +3 -9
  42. package/api/discover/discover.doc.mjs +62 -18
  43. package/api/discover/discover.mjs +220 -36
  44. package/api/discover/discover.test.mjs +11 -2
  45. package/api/discover/discover.type.d.mts +150 -11
  46. package/api/discover/discover.type.mjs +107 -17
  47. package/api/discover/list/list.d.mts +20 -6
  48. package/api/discover/list/list.mjs +45 -12
  49. package/api/discover/list/list.test.mjs +46 -0
  50. package/api/discover/search/search.d.mts +18 -16
  51. package/api/discover/search/search.mjs +102 -56
  52. package/api/discover/search/search.test.mjs +144 -10
  53. package/api/docs/_adapter.d.mts +277 -41
  54. package/api/docs/_adapter.mjs +993 -108
  55. package/api/docs/compiled-topics.test.mjs +78 -0
  56. package/api/docs/detail/detail.mjs +22 -63
  57. package/api/docs/detail/section/section.d.mts +1 -1
  58. package/api/docs/detail/section/section.mjs +54 -19
  59. package/api/docs/detail/section/section.test.mjs +50 -0
  60. package/api/docs/docOverlays.test.mjs +27 -1
  61. package/api/docs/docs.d.mts +10 -3
  62. package/api/docs/docs.doc.mjs +55 -16
  63. package/api/docs/docs.mjs +53 -10
  64. package/api/docs/docs.type.d.mts +221 -5
  65. package/api/docs/docs.type.mjs +153 -11
  66. package/api/docs/index/index.d.mts +18 -0
  67. package/api/docs/index/index.mjs +40 -0
  68. package/api/docs/index/index.test.mjs +62 -0
  69. package/api/docs/list/list.mjs +28 -12
  70. package/api/docs/node/node.d.mts +43 -0
  71. package/api/docs/node/node.mjs +192 -0
  72. package/api/docs/reference-blocks.test.mjs +406 -0
  73. package/api/doctor/doctor.d.mts +104 -1
  74. package/api/doctor/doctor.doc.mjs +18 -8
  75. package/api/doctor/doctor.mjs +635 -7
  76. package/api/doctor/doctor.test.mjs +732 -11
  77. package/api/doctor/doctor.type.d.mts +1 -1
  78. package/api/doctor/doctor.type.mjs +1 -1
  79. package/api/gap-report/gap-report.doc.mjs +27 -14
  80. package/api/hook/_adapter.mjs +19 -5
  81. package/api/hook/hook.doc.mjs +7 -3
  82. package/api/hook/hook.type.d.mts +3 -3
  83. package/api/hook/hook.type.mjs +11 -11
  84. package/api/hook/list/list.d.mts +2 -2
  85. package/api/hook/list/list.mjs +69 -17
  86. package/api/index.d.mts +2 -1
  87. package/api/index.mjs +6 -3
  88. package/api/init/init.doc.mjs +22 -12
  89. package/api/init/init.test.mjs +41 -1
  90. package/api/init/remove/remove.mjs +1 -1
  91. package/api/init/run/run.mjs +20 -10
  92. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  93. package/api/integration/add-contribution.d.mts +2 -1
  94. package/api/integration/add-contribution.mjs +130 -15
  95. package/api/integration/add-contribution.test.mjs +258 -7
  96. package/api/integration/add-helpers.d.mts +5 -2
  97. package/api/integration/add-helpers.mjs +36 -9
  98. package/api/integration/add-theme.mjs +56 -65
  99. package/api/integration/add-theme.test.mjs +139 -21
  100. package/api/integration/authoring-checks.mjs +138 -28
  101. package/api/integration/authoring-checks.test.mjs +179 -7
  102. package/api/integration/authoring-checks.type.mjs +6 -1
  103. package/api/integration/integration-authoring.type.d.mts +3 -1
  104. package/api/integration/integration-authoring.type.mjs +2 -0
  105. package/api/integration/integration-block-exports.test.mjs +10 -6
  106. package/api/integration/integrationAdd.doc.mjs +14 -4
  107. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  108. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  109. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  110. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  111. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  112. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  113. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  114. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  115. package/api/integration/integrationPackCheck.doc.mjs +5 -4
  116. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  117. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  118. package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
  119. package/api/integration/pack-check.mjs +160 -11
  120. package/api/integration/pack-check.test.mjs +477 -47
  121. package/api/integration/pack-check.type.d.mts +26 -2
  122. package/api/integration/pack-check.type.mjs +15 -2
  123. package/api/integration/summarizeIssues.doc.mjs +1 -0
  124. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  126. package/api/integration/validate-integration.mjs +52 -102
  127. package/api/integration/validate-integration.test.mjs +179 -26
  128. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  129. package/api/integration/validateIntegration.doc.mjs +3 -2
  130. package/api/json/assertResponse.doc.mjs +2 -1
  131. package/api/json/envelope-types.test.mjs +76 -0
  132. package/api/json/index.ts +2 -0
  133. package/api/json/isError.doc.mjs +2 -1
  134. package/api/json/parseResponse.doc.mjs +3 -2
  135. package/api/layout/_adapter.mjs +20 -5
  136. package/api/layout/expand/expand.mjs +7 -5
  137. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  138. package/api/layout/grammar/grammar.mjs +2 -1
  139. package/api/layout/layoutCheck.doc.mjs +1 -0
  140. package/api/layout/layoutExpand.doc.mjs +2 -1
  141. package/api/layout/layoutGrammar.doc.mjs +1 -0
  142. package/api/search/search-return-type.test.mjs +54 -0
  143. package/api/search/search.d.mts +89 -12
  144. package/api/search/search.doc.mjs +8 -2
  145. package/api/search/search.mjs +697 -97
  146. package/api/search/search.type.d.mts +15 -3
  147. package/api/search/search.type.mjs +5 -2
  148. package/api/swizzle/copy/copy.mjs +28 -11
  149. package/api/swizzle/swizzle.doc.mjs +8 -5
  150. package/api/swizzle/swizzle.type.d.mts +2 -2
  151. package/api/swizzle/swizzle.type.mjs +2 -2
  152. package/api/template/copy/copy.mjs +18 -24
  153. package/api/template/copy/copy.test.mjs +26 -0
  154. package/api/template/list/list.mjs +1 -0
  155. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  156. package/api/template/template-integration.test.mjs +1072 -3
  157. package/api/template/template-suffix.test.mjs +41 -21
  158. package/api/template/template.d.mts +1 -1
  159. package/api/template/template.doc.mjs +32 -9
  160. package/api/template/template.mjs +45 -8
  161. package/api/template/template.type.d.mts +12 -14
  162. package/api/template/template.type.mjs +15 -14
  163. package/api/theme/_adapter.d.mts +2 -3
  164. package/api/theme/_adapter.mjs +4 -5
  165. package/api/theme/add/add.binary.test.mjs +84 -0
  166. package/api/theme/add/add.mjs +31 -22
  167. package/api/theme/add/add.rollback.test.mjs +158 -0
  168. package/api/theme/add/add.staging.test.mjs +83 -0
  169. package/api/theme/add/add.test.mjs +14 -1
  170. package/api/theme/build/build.family.test.mjs +7 -12
  171. package/api/theme/build/build.mjs +140 -59
  172. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  173. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  174. package/api/theme/build/build.rollback.test.mjs +148 -0
  175. package/api/theme/build/build.test.mjs +127 -0
  176. package/api/theme/build/font-warning.mjs +3 -3
  177. package/api/theme/build/font-warning.test.mjs +5 -2
  178. package/api/theme/generateTonalPalette.doc.mjs +2 -2
  179. package/api/theme/integration-themes.test.mjs +39 -28
  180. package/api/theme/list/list.test.mjs +19 -20
  181. package/api/theme/listThemes.doc.mjs +6 -5
  182. package/api/theme/palette/generate/generate.mjs +8 -3
  183. package/api/theme/palette/generate/generate.test.mjs +96 -0
  184. package/api/theme/palette/generate/generator.d.mts +10 -13
  185. package/api/theme/palette/generate/generator.mjs +15 -4
  186. package/api/theme/palette/generate/generator.test.mjs +10 -0
  187. package/api/theme/template/template.mjs +11 -2
  188. package/api/theme/template/template.test.mjs +20 -0
  189. package/api/theme/theme.type.d.mts +170 -11
  190. package/api/theme/theme.type.mjs +94 -27
  191. package/api/theme/themeAdd.doc.mjs +12 -12
  192. package/api/theme/themeBuild.doc.mjs +21 -17
  193. package/api/theme/themeList.doc.mjs +6 -3
  194. package/api/theme/themeListAvailable.doc.mjs +6 -3
  195. package/api/theme/themePaletteGenerate.doc.mjs +16 -8
  196. package/api/theme/themeTargets.doc.mjs +4 -2
  197. package/api/theme/themeTemplate.doc.mjs +8 -3
  198. package/api/upgrade/_adapter.d.mts +32 -5
  199. package/api/upgrade/_adapter.mjs +139 -22
  200. package/api/upgrade/list/list.mjs +2 -1
  201. package/api/upgrade/list/list.test.mjs +73 -0
  202. package/api/upgrade/project-context.test.mjs +272 -0
  203. package/api/upgrade/provider-agreement.test.mjs +152 -0
  204. package/api/upgrade/run/files-changed.test.mjs +111 -0
  205. package/api/upgrade/run/run.mjs +358 -59
  206. package/api/upgrade/status/status.mjs +2 -2
  207. package/api/upgrade/upgrade.doc.mjs +32 -23
  208. package/api/upgrade/upgrade.type.d.mts +43 -5
  209. package/api/upgrade/upgrade.type.mjs +29 -13
  210. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  211. package/assets/codemods/__tests__/runner.test.mjs +332 -8
  212. package/assets/codemods/file-count.test.mjs +163 -0
  213. package/assets/codemods/integration-discovery.mjs +48 -4
  214. package/assets/codemods/integration-discovery.test.mjs +73 -0
  215. package/assets/codemods/integration-runner.mjs +59 -7
  216. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  217. package/assets/codemods/registry.mjs +1 -0
  218. package/assets/codemods/run-codemod.mjs +177 -34
  219. package/assets/codemods/runner.mjs +353 -104
  220. package/assets/codemods/term-log.mjs +32 -8
  221. package/assets/codemods/term-log.test.mjs +19 -1
  222. package/assets/codemods/transform-prop.mjs +109 -0
  223. package/assets/codemods/transform-prop.test.mjs +95 -0
  224. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  225. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  226. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  227. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  228. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  229. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  230. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  231. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  232. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  233. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  234. package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
  235. package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
  236. package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
  237. package/assets/docs/README.md +12 -1
  238. package/assets/docs/authoring.doc.mjs +14 -0
  239. package/assets/docs/browser-support.doc.mjs +11 -11
  240. package/assets/docs/color.doc.mjs +8 -2
  241. package/assets/docs/elevation.doc.mjs +6 -4
  242. package/assets/docs/getting-started.doc.mjs +6 -17
  243. package/assets/docs/icons.doc.mjs +2 -21
  244. package/assets/docs/illustrations.doc.mjs +7 -15
  245. package/assets/docs/internationalization.doc.mjs +7 -5
  246. package/assets/docs/layout.doc.dense.mjs +132 -84
  247. package/assets/docs/layout.doc.mjs +134 -78
  248. package/assets/docs/migration.doc.mjs +19 -21
  249. package/assets/docs/motion.doc.mjs +16 -3
  250. package/assets/docs/principles.doc.dense.mjs +5 -5
  251. package/assets/docs/principles.doc.mjs +14 -6
  252. package/assets/docs/principles.doc.zh.mjs +6 -6
  253. package/assets/docs/shape.doc.mjs +8 -3
  254. package/assets/docs/spacing.doc.mjs +7 -2
  255. package/assets/docs/styling-libraries.doc.mjs +10 -6
  256. package/assets/docs/styling.doc.mjs +22 -26
  257. package/assets/docs/theme.doc.dense.mjs +58 -18
  258. package/assets/docs/theme.doc.mjs +60 -50
  259. package/assets/docs/theme.doc.zh.mjs +9 -8
  260. package/assets/docs/tokens.doc.dense.mjs +2 -2
  261. package/assets/docs/tokens.doc.mjs +390 -9
  262. package/assets/docs/tokens.doc.zh.mjs +2 -2
  263. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  264. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  265. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  266. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  267. package/assets/docs/tree/api.doc.mjs +30 -0
  268. package/assets/docs/tree/block-template.doc.mjs +130 -0
  269. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  270. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  271. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  272. package/assets/docs/tree/checks.doc.mjs +119 -0
  273. package/assets/docs/tree/cli.doc.mjs +23 -0
  274. package/assets/docs/tree/codemods.doc.mjs +147 -0
  275. package/assets/docs/tree/commands.doc.mjs +25 -0
  276. package/assets/docs/tree/component-family.doc.mjs +113 -0
  277. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  278. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  279. package/assets/docs/tree/components.doc.mjs +23 -0
  280. package/assets/docs/tree/configuration.doc.mjs +23 -0
  281. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  282. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  283. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  284. package/assets/docs/tree/docs.doc.mjs +21 -0
  285. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  286. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  287. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  288. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  289. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  290. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  291. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  292. package/assets/docs/tree/help.doc.mjs +16 -0
  293. package/assets/docs/tree/integrations.doc.mjs +40 -0
  294. package/assets/docs/tree/links.doc.mjs +98 -0
  295. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  296. package/assets/docs/tree/page-template.doc.mjs +71 -0
  297. package/assets/docs/tree/publishing.doc.mjs +111 -0
  298. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  299. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  300. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  301. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  302. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  303. package/assets/docs/tree/ship.doc.mjs +16 -0
  304. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  305. package/assets/docs/tree/single-component.doc.mjs +165 -0
  306. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  307. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  308. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  309. package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
  310. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  311. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  312. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  313. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  314. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  315. package/assets/docs/tree/templates.doc.mjs +34 -0
  316. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  317. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  318. package/assets/docs/tree/themes.doc.mjs +39 -0
  319. package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
  320. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  321. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  322. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  323. package/assets/docs/tree/versioning.doc.mjs +161 -0
  324. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  325. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  326. package/assets/docs/typography.doc.mjs +24 -4
  327. package/assets/docs/working-with-ai.doc.mjs +34 -26
  328. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  329. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  330. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  331. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  332. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  333. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  334. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  335. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  336. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  337. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  338. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  339. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  340. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  341. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  342. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  343. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  344. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  345. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  346. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  347. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  348. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  349. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  350. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  351. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
  352. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
  353. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
  354. package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
  355. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
  356. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
  357. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
  358. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
  359. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
  360. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
  361. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  362. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  363. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  364. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  365. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  366. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  367. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  368. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  369. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  370. package/authoring/_shared/contract.ts +22 -0
  371. package/authoring/codemod/codemod.doc.mjs +7 -2
  372. package/authoring/codemod/parse.d.mts +8 -8
  373. package/authoring/codemod/parse.mjs +8 -6
  374. package/authoring/codemod/type.ts +12 -0
  375. package/authoring/config/config.doc.mjs +11 -3
  376. package/authoring/config/debug-composition.test.mjs +92 -0
  377. package/authoring/config/parse.d.mts +15 -13
  378. package/authoring/config/parse.mjs +27 -8
  379. package/authoring/config/parse.test.mjs +8 -0
  380. package/authoring/config/type.ts +29 -6
  381. package/authoring/debug/debug.doc.d.mts +11 -0
  382. package/authoring/debug/debug.doc.mjs +182 -0
  383. package/authoring/debug/parse.d.mts +8 -8
  384. package/authoring/debug/parse.mjs +3 -3
  385. package/authoring/discover/discover.doc.d.mts +13 -0
  386. package/authoring/discover/discover.doc.mjs +138 -0
  387. package/authoring/discover/parse.d.mts +24 -0
  388. package/authoring/discover/parse.mjs +128 -0
  389. package/authoring/discover/parse.test.mjs +124 -0
  390. package/authoring/discover/type.ts +87 -0
  391. package/authoring/doctypes/_schema.d.mts +792 -24
  392. package/authoring/doctypes/_schema.mjs +549 -39
  393. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  394. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  395. package/authoring/doctypes/base/type.ts +43 -0
  396. package/authoring/doctypes/command/command.doc.mjs +4 -3
  397. package/authoring/doctypes/command/parse.d.mts +2 -2
  398. package/authoring/doctypes/command/parse.mjs +1 -1
  399. package/authoring/doctypes/command/type.ts +5 -4
  400. package/authoring/doctypes/component/component.doc.mjs +12 -3
  401. package/authoring/doctypes/component/parse.d.mts +2 -2
  402. package/authoring/doctypes/component/parse.mjs +1 -1
  403. package/authoring/doctypes/component/type.ts +14 -5
  404. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  405. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  406. package/authoring/doctypes/enum/parse.d.mts +2 -2
  407. package/authoring/doctypes/enum/parse.mjs +1 -1
  408. package/authoring/doctypes/enum/type.ts +4 -2
  409. package/authoring/doctypes/function/function.doc.mjs +7 -2
  410. package/authoring/doctypes/function/parse.d.mts +2 -2
  411. package/authoring/doctypes/function/parse.mjs +1 -1
  412. package/authoring/doctypes/function/type.ts +9 -4
  413. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  414. package/authoring/doctypes/hook/parse.d.mts +2 -2
  415. package/authoring/doctypes/hook/parse.mjs +1 -1
  416. package/authoring/doctypes/hook/type.ts +5 -4
  417. package/authoring/doctypes/legacy.d.mts +8 -6
  418. package/authoring/doctypes/legacy.mjs +5 -4
  419. package/authoring/doctypes/load-contract.test.mjs +233 -0
  420. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  421. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  422. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  423. package/authoring/doctypes/namespace/parse.mjs +25 -0
  424. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  425. package/authoring/doctypes/namespace/type.ts +74 -0
  426. package/authoring/doctypes/parse.d.mts +22 -18
  427. package/authoring/doctypes/parse.mjs +22 -11
  428. package/authoring/doctypes/parse.test.mjs +77 -3
  429. package/authoring/doctypes/reference/parse.d.mts +2 -2
  430. package/authoring/doctypes/reference/parse.mjs +8 -5
  431. package/authoring/doctypes/reference/reference.doc.mjs +55 -6
  432. package/authoring/doctypes/reference/type.ts +75 -7
  433. package/authoring/doctypes/schema/parse.d.mts +2 -2
  434. package/authoring/doctypes/schema/parse.mjs +1 -1
  435. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  436. package/authoring/doctypes/schema/type.ts +4 -4
  437. package/authoring/doctypes/template/parse.d.mts +94 -1
  438. package/authoring/doctypes/template/parse.mjs +40 -2
  439. package/authoring/doctypes/template/parse.test.mjs +26 -2
  440. package/authoring/doctypes/template/template.doc.mjs +13 -3
  441. package/authoring/doctypes/template/type.ts +13 -2
  442. package/authoring/doctypes/theme/parse.d.mts +35 -0
  443. package/authoring/doctypes/theme/parse.mjs +76 -0
  444. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  445. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  446. package/authoring/doctypes/theme/type.ts +42 -0
  447. package/authoring/doctypes/types.ts +12 -10
  448. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  449. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  450. package/authoring/gap-report/parse.d.mts +10 -10
  451. package/authoring/gap-report/parse.mjs +6 -6
  452. package/authoring/gap-report/type.ts +1 -1
  453. package/authoring/identity/identity.doc.d.mts +9 -0
  454. package/authoring/identity/identity.doc.mjs +61 -0
  455. package/authoring/identity/type.ts +132 -0
  456. package/authoring/index.d.mts +3 -0
  457. package/authoring/index.d.ts +62 -17
  458. package/authoring/index.mjs +4 -1
  459. package/authoring/integration/integration.doc.mjs +22 -13
  460. package/authoring/integration/parse.d.mts +2 -2
  461. package/authoring/integration/parse.mjs +1 -1
  462. package/authoring/integration/parse.test.mjs +10 -1
  463. package/authoring/integration/schema.d.mts +6 -4
  464. package/authoring/integration/schema.mjs +9 -3
  465. package/authoring/integration/type.ts +19 -8
  466. package/authoring/shadcn/receipt.d.mts +6 -6
  467. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  468. package/clients/cli/command-load-failure.test.mjs +83 -0
  469. package/clients/cli/commands/blog.doc.mjs +1 -1
  470. package/clients/cli/commands/blog.mjs +23 -8
  471. package/clients/cli/commands/blog.test.mjs +42 -1
  472. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  473. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  474. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  475. package/clients/cli/commands/build-theme.mjs +16 -50
  476. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  477. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  478. package/clients/cli/commands/build.doc.mjs +16 -8
  479. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  480. package/clients/cli/commands/build.mjs +137 -114
  481. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  482. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  483. package/clients/cli/commands/component/index.mjs +153 -61
  484. package/clients/cli/commands/component-batch.test.mjs +341 -0
  485. package/clients/cli/commands/component-ownership.test.mjs +92 -3
  486. package/clients/cli/commands/component-package.test.mjs +46 -0
  487. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  488. package/clients/cli/commands/component.doc.mjs +28 -10
  489. package/clients/cli/commands/component.test.mjs +19 -0
  490. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  491. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  492. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  493. package/clients/cli/commands/discover.doc.mjs +55 -9
  494. package/clients/cli/commands/discover.mjs +393 -118
  495. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  496. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  497. package/clients/cli/commands/docs.doc.mjs +28 -6
  498. package/clients/cli/commands/docs.mjs +295 -38
  499. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  500. package/clients/cli/commands/doctor-integration-docs.doc.mjs +6 -5
  501. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  502. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  503. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  504. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  505. package/clients/cli/commands/doctor-integration.test.mjs +143 -8
  506. package/clients/cli/commands/doctor.doc.mjs +4 -2
  507. package/clients/cli/commands/doctor.mjs +108 -37
  508. package/clients/cli/commands/doctor.test.mjs +42 -0
  509. package/clients/cli/commands/gap-report.doc.mjs +27 -15
  510. package/clients/cli/commands/gap-report.test.mjs +72 -0
  511. package/clients/cli/commands/hook/index.mjs +7 -17
  512. package/clients/cli/commands/hook.doc.mjs +1 -1
  513. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  514. package/clients/cli/commands/init.doc.mjs +24 -10
  515. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  516. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  517. package/clients/cli/commands/integration-add.doc.mjs +39 -13
  518. package/clients/cli/commands/integration-authoring.test.mjs +74 -19
  519. package/clients/cli/commands/integration-pack.doc.mjs +6 -10
  520. package/clients/cli/commands/integration-real-world.test.mjs +4 -10
  521. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  522. package/clients/cli/commands/integration.doc.mjs +5 -5
  523. package/clients/cli/commands/integration.mjs +75 -43
  524. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  525. package/clients/cli/commands/json-contract.test.mjs +33 -0
  526. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  527. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  528. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  529. package/clients/cli/commands/layout.doc.mjs +3 -3
  530. package/clients/cli/commands/layout.mjs +21 -9
  531. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  532. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  533. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  534. package/clients/cli/commands/manifest.doc.mjs +2 -2
  535. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  536. package/clients/cli/commands/search.doc.mjs +16 -6
  537. package/clients/cli/commands/search.mjs +49 -11
  538. package/clients/cli/commands/search.test.mjs +92 -0
  539. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  540. package/clients/cli/commands/swizzle.doc.mjs +4 -3
  541. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  542. package/clients/cli/commands/template.doc.mjs +53 -14
  543. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  544. package/clients/cli/commands/template.mjs +4 -91
  545. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  546. package/clients/cli/commands/text-json-parity.test.mjs +725 -0
  547. package/clients/cli/commands/theme-add.doc.mjs +5 -4
  548. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  549. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  550. package/clients/cli/commands/theme-palette-generate.doc.mjs +12 -7
  551. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  552. package/clients/cli/commands/theme-palette.doc.mjs +2 -3
  553. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  554. package/clients/cli/commands/theme-targets.doc.mjs +3 -3
  555. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  556. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  557. package/clients/cli/commands/theme.doc.mjs +3 -2
  558. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  559. package/clients/cli/commands/upgrade.doc.mjs +83 -12
  560. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  561. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  562. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  563. package/clients/cli/commands/upgrade.mjs +29 -7
  564. package/clients/cli/formatters/index.mjs +164 -1
  565. package/clients/cli/formatters/index.test.mjs +97 -0
  566. package/clients/cli/index.mjs +47 -34
  567. package/clients/cli/latest-version-env.test.mjs +50 -0
  568. package/clients/cli/lib/cli-error.test.mjs +7 -0
  569. package/clients/cli/lib/component-format.mjs +9 -9
  570. package/clients/cli/lib/component-format.test.mjs +1 -1
  571. package/clients/cli/lib/define-command.mjs +56 -6
  572. package/clients/cli/lib/define-command.test.mjs +54 -0
  573. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  574. package/clients/cli/lib/exit-codes.test.mjs +113 -0
  575. package/clients/cli/lib/hook-format.mjs +19 -10
  576. package/clients/cli/lib/json-shim.mjs +62 -16
  577. package/clients/cli/lib/json-shim.test.mjs +83 -0
  578. package/clients/cli/lib/manifest.d.ts +2 -0
  579. package/clients/cli/lib/manifest.mjs +53 -6
  580. package/clients/cli/lib/manifest.test.mjs +22 -2
  581. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  582. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  583. package/foundation/agent-docs/agent-docs.mjs +83 -13
  584. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  585. package/foundation/config/integration-debug.test.mjs +28 -3
  586. package/foundation/config/project-themes.test.mjs +11 -19
  587. package/foundation/config/project.d.mts +20 -11
  588. package/foundation/config/project.mjs +263 -91
  589. package/foundation/config/project.test.mjs +270 -21
  590. package/foundation/discovery/authoring-self-docs.d.mts +87 -0
  591. package/foundation/discovery/authoring-self-docs.mjs +237 -0
  592. package/foundation/discovery/authoring-self-docs.test.mjs +174 -0
  593. package/foundation/discovery/authoring-surface.d.mts +74 -0
  594. package/foundation/discovery/authoring-surface.mjs +525 -0
  595. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  596. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  597. package/foundation/discovery/cli-self-docs.mjs +504 -0
  598. package/foundation/discovery/cli-self-docs.test.mjs +395 -0
  599. package/foundation/discovery/component-discovery.d.mts +39 -1
  600. package/foundation/discovery/component-discovery.mjs +50 -1
  601. package/foundation/discovery/component-loader.d.mts +35 -38
  602. package/foundation/discovery/component-loader.mjs +53 -222
  603. package/foundation/discovery/docs-discovery.d.mts +119 -11
  604. package/foundation/discovery/docs-discovery.mjs +427 -108
  605. package/foundation/discovery/docs-discovery.test.mjs +386 -20
  606. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  607. package/foundation/discovery/docs-output-budget.mjs +50 -0
  608. package/foundation/discovery/docs-section-key.d.mts +116 -0
  609. package/foundation/discovery/docs-section-key.mjs +322 -0
  610. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  611. package/foundation/discovery/template-adapter.d.mts +113 -11
  612. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  613. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  614. package/foundation/discovery/template-adapter.mjs +774 -83
  615. package/foundation/discovery/template-adapter.test.mjs +57 -0
  616. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  617. package/foundation/discovery/template-conflict-release.mjs +40 -0
  618. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  619. package/foundation/discovery/theme-discovery.d.mts +67 -7
  620. package/foundation/discovery/theme-discovery.mjs +916 -186
  621. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  622. package/foundation/discovery/theming-targets.test.mjs +4 -0
  623. package/foundation/doc-compiler/bundle.d.mts +47 -0
  624. package/foundation/doc-compiler/bundle.mjs +278 -0
  625. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  626. package/foundation/doc-compiler/compile.d.mts +343 -0
  627. package/foundation/doc-compiler/compile.mjs +558 -0
  628. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  629. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  630. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  631. package/foundation/doc-compiler/doc-loads.test.mjs +1643 -0
  632. package/foundation/doc-compiler/import.d.mts +24 -0
  633. package/foundation/doc-compiler/import.mjs +59 -0
  634. package/foundation/doc-compiler/inputs.d.mts +102 -0
  635. package/foundation/doc-compiler/inputs.mjs +291 -0
  636. package/foundation/doc-compiler/inputs.test.mjs +298 -0
  637. package/foundation/doc-compiler/ir.d.mts +22 -0
  638. package/foundation/doc-compiler/ir.mjs +471 -0
  639. package/foundation/doc-compiler/lenses.d.mts +36 -0
  640. package/foundation/doc-compiler/lenses.mjs +173 -0
  641. package/foundation/doc-compiler/links.d.mts +162 -0
  642. package/foundation/doc-compiler/links.mjs +294 -0
  643. package/foundation/doc-compiler/links.test.mjs +192 -0
  644. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  645. package/foundation/doc-compiler/overlays.d.mts +37 -0
  646. package/foundation/doc-compiler/overlays.mjs +206 -0
  647. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  648. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  649. package/foundation/doc-compiler/read.d.mts +127 -0
  650. package/foundation/doc-compiler/read.mjs +325 -0
  651. package/foundation/doc-compiler/read.test.mjs +313 -0
  652. package/foundation/doc-compiler/source.d.mts +33 -0
  653. package/foundation/doc-compiler/source.mjs +128 -0
  654. package/foundation/doc-compiler/tree.d.mts +292 -0
  655. package/foundation/doc-compiler/tree.mjs +881 -0
  656. package/foundation/fs/file-protection.d.mts +33 -0
  657. package/foundation/fs/file-protection.mjs +825 -0
  658. package/foundation/fs/file-protection.test.mjs +250 -0
  659. package/foundation/fs/module-loader.d.mts +1 -0
  660. package/foundation/fs/module-loader.mjs +50 -1
  661. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  662. package/foundation/fs/path-safety.d.mts +3 -2
  663. package/foundation/fs/path-safety.mjs +49 -19
  664. package/foundation/fs/path-safety.test.mjs +50 -0
  665. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  666. package/foundation/identity/provider-identity.d.mts +90 -0
  667. package/foundation/identity/provider-identity.mjs +320 -0
  668. package/foundation/identity/provider-identity.test.mjs +254 -0
  669. package/foundation/identity/providers.d.mts +7 -0
  670. package/foundation/identity/providers.mjs +16 -0
  671. package/foundation/integrations/autolink.d.mts +58 -1
  672. package/foundation/integrations/autolink.mjs +143 -45
  673. package/foundation/integrations/autolink.test.mjs +1 -1
  674. package/foundation/integrations/cli-requirement.d.mts +65 -0
  675. package/foundation/integrations/cli-requirement.mjs +189 -0
  676. package/foundation/integrations/cli-requirement.test.mjs +89 -0
  677. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  678. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  679. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  680. package/foundation/integrations/contribution-inventory.mjs +28 -25
  681. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  682. package/foundation/integrations/integration-warnings.d.mts +9 -2
  683. package/foundation/integrations/integration-warnings.mjs +52 -21
  684. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  685. package/foundation/integrations/integrations.d.mts +63 -3
  686. package/foundation/integrations/integrations.mjs +122 -9
  687. package/foundation/integrations/integrations.test.mjs +415 -1
  688. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  689. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  690. package/foundation/integrations/provider-resolution.d.mts +152 -0
  691. package/foundation/integrations/provider-resolution.mjs +576 -0
  692. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  693. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  694. package/foundation/integrations/theme-descriptor.mjs +44 -0
  695. package/foundation/integrations/validate-contributions.d.mts +2 -0
  696. package/foundation/integrations/validate-contributions.mjs +131 -29
  697. package/foundation/response/base.d.ts +8 -4
  698. package/foundation/response/batch.type.d.mts +33 -0
  699. package/foundation/response/batch.type.mjs +34 -0
  700. package/foundation/response/error-codes.d.mts +3 -1
  701. package/foundation/response/error-codes.d.ts +2 -0
  702. package/foundation/response/error-codes.doc.mjs +19 -12
  703. package/foundation/response/error-codes.mjs +8 -2
  704. package/foundation/response/error-codes.test.mjs +166 -14
  705. package/foundation/response/json-contract.test.mjs +57 -17
  706. package/foundation/response/json.d.mts +4 -2
  707. package/foundation/response/json.mjs +8 -10
  708. package/foundation/response/response-types.doc.d.mts +7 -2
  709. package/foundation/response/response-types.doc.mjs +69 -25
  710. package/foundation/response/response-types.doc.test.mjs +181 -0
  711. package/foundation/response/response.doc.mjs +12 -11
  712. package/foundation/text/string-utils.d.mts +8 -0
  713. package/foundation/text/string-utils.mjs +40 -10
  714. package/foundation/xle/expand.d.mts +2 -0
  715. package/foundation/xle/expand.mjs +4 -3
  716. package/foundation/xle/expand.test.mjs +54 -0
  717. package/foundation/xle/xle.test.mjs +13 -0
  718. package/package.json +10 -11
  719. package/api/docs/docs.test.mjs +0 -83
  720. package/api/docs/integrationDocs.test.mjs +0 -208
  721. package/api/search/search.test.mjs +0 -389
  722. package/assets/docs/cli-integrations.doc.mjs +0 -367
  723. package/assets/templates/themes/manifest.json +0 -95
  724. package/clients/cli/commands/docs.test.mjs +0 -102
  725. package/clients/cli/lib/update-check.mjs +0 -83
  726. package/clients/cli/lib/update-check.test.mjs +0 -137
  727. package/clients/cli/update-hint-commands.test.mjs +0 -54
  728. package/foundation/agent-docs/agent-docs.test.mjs +0 -1141
@@ -0,0 +1,725 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Text/JSON parity — every command's human output is a projection of its
5
+ * JSON envelope.
6
+ *
7
+ * Architecture: cli-surface INV4, INV5. Spec: AST-042 FR1.
8
+ *
9
+ * The test:
10
+ * 1. Enumerates every JSON-capable command from the live manifest and fails
11
+ * when a command has no parity case. A new command must add one.
12
+ * 2. Runs each case in text mode and --json mode via the in-process harness.
13
+ * 3. Checks:
14
+ * a. Every `key: value` record line in the text names a key that exists
15
+ * in the JSON data (criterion 1 — text shows no fact JSON lacks).
16
+ * b. Every JSON leaf field appears in the text, unless the allowlist
17
+ * forgives it with a reason (criterion 2).
18
+ *
19
+ * Allowlist entries are stale-checked: an entry that forgives a field that
20
+ * does not appear anywhere in the JSON output FAILS the test, so the
21
+ * allowlist shrinks over time.
22
+ *
23
+ * DO NOT add allowlist entries without a reason. Headings and invocation-
24
+ * prefixed hints are the only categories that are structurally OK to forgive;
25
+ * everything else is a divergence that should be fixed.
26
+ */
27
+
28
+ import {describe, it, expect, beforeAll, afterAll} from 'vitest';
29
+ import * as fs from 'node:fs';
30
+ import * as path from 'node:path';
31
+ import * as os from 'node:os';
32
+ import {fileURLToPath} from 'node:url';
33
+ import {runCli} from '../../../test-utils/run-cli.mjs';
34
+
35
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
36
+ const REPO_ROOT = path.resolve(__dirname, '../../../../..');
37
+
38
+ // ─── Helpers ────────────────────────────────────────────────────────────────
39
+
40
+ /**
41
+ * Normalize a text value for comparison: collapse whitespace, strip the
42
+ * package-manager invocation prefix, and undo ASCII normalization.
43
+ * @param {string} s
44
+ * @returns {string}
45
+ */
46
+ function normalize(s) {
47
+ return s
48
+ .replace(/\s+/g, ' ')
49
+ .replace(/(npx|pnpm exec|yarn dlx|bunx)\s+astryx/g, 'astryx')
50
+ .replace(/[\u2014\u2013]/g, '-')
51
+ .replace(/[\u2018\u2019]/g, "'")
52
+ .replace(/[\u201C\u201D]/g, '"')
53
+ .replace(/\u2026/g, '...')
54
+ .trim();
55
+ }
56
+
57
+ /**
58
+ * Extract `key: value` record lines from text output. The formatter always
59
+ * produces `key: value` (padded) or `key: value`.
60
+ *
61
+ * Lines whose key is a known hint prefix (e.g. "Usage:") are excluded —
62
+ * those are invocation hints allowed by INV4, not data records.
63
+ * @param {string} text
64
+ * @returns {Map<string, string[]>}
65
+ */
66
+ function extractRecordKeys(text) {
67
+ const HINT_PREFIXES = new Set(['Usage', 'Summary', 'Read', 'Example', 'Tip']);
68
+ /** @type {Map<string, string[]>} */
69
+ const map = new Map();
70
+ for (const line of text.split('\n')) {
71
+ // Match "word-key: value" but not URLs, headings, or code fences
72
+ const m = line.match(/^(\w[\w-]*):\s{1,}\S/);
73
+ if (!m) continue;
74
+ const key = m[1];
75
+ if (HINT_PREFIXES.has(key)) continue;
76
+ const value = line.slice(line.indexOf(':', key.length) + 1).trim();
77
+ if (!map.has(key)) map.set(key, []);
78
+ map.get(key).push(normalize(value));
79
+ }
80
+ return map;
81
+ }
82
+
83
+ /**
84
+ * Extract bulleted list items from text output (`- item`).
85
+ * @param {string} text
86
+ * @returns {string[]}
87
+ */
88
+ function extractListItems(text) {
89
+ return text
90
+ .split('\n')
91
+ .filter(line => /^- \S/.test(line))
92
+ .map(line => normalize(line.slice(2)));
93
+ }
94
+
95
+ /**
96
+ * Extract standalone text blocks — lines that are not record lines, list
97
+ * items, section headings, hint lines, or blank. These correspond to
98
+ * `text(...)` formatter calls and must carry facts from the JSON.
99
+ * @param {string} text
100
+ * @returns {string[]}
101
+ */
102
+ function extractTextBlocks(text) {
103
+ const HINT_PREFIXES = /^(Usage|Summary|Read|Example|Tip|Import from|Related blocks|Each key|Props take|One component|No results|Try a|Browse instead|No failures|All checks|Some checks|Pass --\w)[:.]?/i;
104
+ const lines = text.split('\n');
105
+ /** @type {string[]} */
106
+ const blocks = [];
107
+ for (let i = 0; i < lines.length; i++) {
108
+ const trimmed = lines[i].trim();
109
+ if (!trimmed) continue;
110
+ // Skip record lines
111
+ if (/^\w[\w-]*:\s{1,}\S/.test(trimmed)) continue;
112
+ // Skip list items
113
+ if (/^- \S/.test(trimmed)) continue;
114
+ // Skip hints
115
+ if (HINT_PREFIXES.test(trimmed)) continue;
116
+ // Skip lines that look like code, commands, or status tokens
117
+ if (trimmed.startsWith('`') || trimmed.startsWith('$')) continue;
118
+ if (trimmed.startsWith('[ok]') || trimmed.startsWith('[skip]') ||
119
+ trimmed.startsWith('[fail]') || trimmed.startsWith('[warn]') ||
120
+ trimmed.startsWith('!') || trimmed.startsWith('(')) continue;
121
+ // Skip continuation lines (indented, part of a wrapped record or list)
122
+ if (/^\s{2,}\S/.test(lines[i])) continue;
123
+ // Skip section headings: a line preceded by blank (or start) that belongs
124
+ // to a block followed by blank. Section blocks can be multi-line (heading
125
+ // + subtitle), so check whether THIS line's block ends before a blank.
126
+ // Only skip short, heading-like text (no sentence punctuation) to avoid
127
+ // suppressing real text() facts.
128
+ const prevBlank = i === 0 || !lines[i - 1]?.trim();
129
+ const nextBlank = i === lines.length - 1 || !lines[i + 1]?.trim();
130
+ const looksLikeHeading = trimmed.length <= 80 && !/[.!?]$/.test(trimmed);
131
+ // Single-line heading: blank before AND after, and heading-like
132
+ if (prevBlank && nextBlank && looksLikeHeading) continue;
133
+ // Multi-line heading block: blank before this line, heading-like
134
+ if (prevBlank && !nextBlank && looksLikeHeading) {
135
+ let j = i + 1;
136
+ while (j < lines.length && lines[j]?.trim()) j++;
137
+ if (j - i <= 3) continue;
138
+ }
139
+ // Subtitle line: preceded by a heading-like line preceded by blank
140
+ if (!prevBlank && nextBlank && i >= 1) {
141
+ const prevLine = lines[i - 1]?.trim() ?? '';
142
+ const prevPrevBlank = i < 2 || !lines[i - 2]?.trim();
143
+ if (prevPrevBlank && prevLine.length <= 80 && !/[.!?]$/.test(prevLine)) continue;
144
+ }
145
+ blocks.push(normalize(trimmed));
146
+ }
147
+ return blocks;
148
+ }
149
+
150
+ /**
151
+ * Collect every leaf string value from JSON data so we can verify text content
152
+ * appears somewhere in the JSON.
153
+ * @param {unknown} obj
154
+ * @returns {Set<string>}
155
+ */
156
+ function jsonLeafValues(obj) {
157
+ /** @type {Set<string>} */
158
+ const values = new Set();
159
+ if (obj == null) return values;
160
+ if (typeof obj === 'string') { values.add(normalize(obj)); return values; }
161
+ if (typeof obj === 'number' || typeof obj === 'boolean') { values.add(String(obj)); return values; }
162
+ if (Array.isArray(obj)) { for (const item of obj) { for (const v of jsonLeafValues(item)) values.add(v); } return values; }
163
+ if (typeof obj === 'object') { for (const value of Object.values(obj)) { for (const v of jsonLeafValues(value)) values.add(v); } }
164
+ return values;
165
+ }
166
+
167
+ /**
168
+ * Collect every PRIMITIVE leaf key from a JSON value. Returns keys whose
169
+ * values are strings, numbers, booleans, or arrays of primitives. Does NOT
170
+ * return intermediate container keys (objects, arrays of objects).
171
+ * @param {unknown} obj
172
+ * @returns {Set<string>}
173
+ */
174
+ function jsonLeafKeys(obj) {
175
+ /** @type {Set<string>} */
176
+ const keys = new Set();
177
+ if (obj == null || typeof obj !== 'object') return keys;
178
+ if (Array.isArray(obj)) {
179
+ for (const item of obj) {
180
+ if (item != null && typeof item === 'object' && !Array.isArray(item)) {
181
+ for (const k of jsonLeafKeys(item)) keys.add(k);
182
+ }
183
+ }
184
+ return keys;
185
+ }
186
+ for (const [key, value] of Object.entries(obj)) {
187
+ if (value == null || typeof value !== 'object') {
188
+ keys.add(key);
189
+ } else if (Array.isArray(value)) {
190
+ if (value.length > 0 && typeof value[0] !== 'object') {
191
+ keys.add(key);
192
+ } else {
193
+ for (const item of value) {
194
+ if (item != null && typeof item === 'object' && !Array.isArray(item)) {
195
+ for (const k of jsonLeafKeys(item)) keys.add(k);
196
+ }
197
+ }
198
+ }
199
+ } else {
200
+ for (const k of jsonLeafKeys(value)) keys.add(k);
201
+ }
202
+ }
203
+ return keys;
204
+ }
205
+
206
+ /**
207
+ * Map each leaf key to the set of values it takes across the JSON data.
208
+ * Used for the JSON→text value-presence check on inline-layout commands.
209
+ * @param {unknown} obj
210
+ * @returns {Map<string, Set<string>>}
211
+ */
212
+ function jsonKeyValues(obj) {
213
+ /** @type {Map<string, Set<string>>} */
214
+ const map = new Map();
215
+ function walk(/** @type {unknown} */ node) {
216
+ if (node == null || typeof node !== 'object') return;
217
+ if (Array.isArray(node)) { for (const item of node) walk(item); return; }
218
+ for (const [key, value] of Object.entries(node)) {
219
+ if (value == null) continue;
220
+ if (typeof value !== 'object') {
221
+ if (!map.has(key)) map.set(key, new Set());
222
+ map.get(key).add(normalize(String(value)));
223
+ } else if (Array.isArray(value)) {
224
+ if (value.length > 0 && typeof value[0] !== 'object') {
225
+ if (!map.has(key)) map.set(key, new Set());
226
+ for (const v of value) map.get(key).add(normalize(String(v)));
227
+ } else {
228
+ for (const item of value) walk(item);
229
+ }
230
+ } else {
231
+ walk(value);
232
+ }
233
+ }
234
+ }
235
+ walk(obj);
236
+ return map;
237
+ }
238
+
239
+ /**
240
+ * Check whether a JSON object (at any depth) contains a given key name.
241
+ * Used for the stale-allowlist check: the field must exist SOMEWHERE in the
242
+ * full JSON output even if our leaf extractor skips it.
243
+ * @param {unknown} obj
244
+ * @param {string} target
245
+ * @returns {boolean}
246
+ */
247
+ function jsonContainsKey(obj, target) {
248
+ if (obj == null || typeof obj !== 'object') return false;
249
+ if (Array.isArray(obj)) return obj.some(item => jsonContainsKey(item, target));
250
+ for (const [key, value] of Object.entries(obj)) {
251
+ if (key === target) return true;
252
+ if (jsonContainsKey(value, target)) return true;
253
+ }
254
+ return false;
255
+ }
256
+
257
+ // ─── Test cases ─────────────────────────────────────────────────────────────
258
+
259
+ /**
260
+ * @typedef {object} ParityCase
261
+ * @property {string} name - The manifest command name.
262
+ * @property {string[]} args - CLI args after `astryx`.
263
+ * @property {string} [cwd] - Working directory; defaults to REPO_ROOT.
264
+ * @property {(dir: string) => void} [setup] - Prepare a tmpDir before the run.
265
+ * @property {string[]} [jsonFieldAllowlist] - JSON keys forgiven from text.
266
+ * @property {boolean} [skipFieldChecks] - Skip both record-key and field checks.
267
+ * @property {boolean} [errorExpected] - The command is expected to error.
268
+ */
269
+
270
+ /** @type {ParityCase[]} */
271
+ const CASES = [
272
+ {
273
+ name: 'blog',
274
+ args: ['blog'],
275
+ // Blog fetches the network feed. In CI the feed is unreachable, so
276
+ // the command errors. The envelope shape is still checked.
277
+ errorExpected: true,
278
+ skipFieldChecks: true,
279
+ },
280
+ {
281
+ name: 'build',
282
+ args: ['build'],
283
+ // PR #6566 fixes the playbook divergence.
284
+ skipFieldChecks: true,
285
+ jsonFieldAllowlist: [
286
+ 'playbook — PR #6566 adds full playbook fields to the JSON envelope',
287
+ ],
288
+ },
289
+ {
290
+ name: 'component',
291
+ args: ['component', '--list'],
292
+ // #6507 touches this handler; divergences deferred.
293
+ skipFieldChecks: true,
294
+ jsonFieldAllowlist: [
295
+ 'detail — internal detail-level tag, not a user-facing datum',
296
+ ],
297
+ },
298
+ {
299
+ name: 'discover',
300
+ args: ['discover'],
301
+ cwd: '__TMP__',
302
+ // Empty result (no config). The meta.configured field is projected as
303
+ // prose in the text.
304
+ skipFieldChecks: true,
305
+ jsonFieldAllowlist: [
306
+ 'configured — expressed as prose "No integrations configured"',
307
+ ],
308
+ },
309
+ {
310
+ name: 'docs',
311
+ args: ['docs'],
312
+ jsonFieldAllowlist: [
313
+ 'topic — inline layout lead column, not a key: value record',
314
+ 'description — inline layout trailing column',
315
+ ],
316
+ },
317
+ {
318
+ name: 'doctor',
319
+ args: ['doctor'],
320
+ jsonFieldAllowlist: [
321
+ 'fix — only present on checks that have a remediation',
322
+ 'pass — shown in prose "Summary: N passed, ..."',
323
+ 'warn — shown in prose "Summary: ..., N warnings"',
324
+ 'fail — shown in prose "Summary: ..., N failures"',
325
+ 'info — shown in prose "Summary: ..., N info" when nonzero',
326
+ ],
327
+ },
328
+ {
329
+ name: 'doctor integration validate',
330
+ args: ['doctor', 'integration', 'validate'],
331
+ skipFieldChecks: true,
332
+ },
333
+ {
334
+ name: 'doctor integration components',
335
+ args: ['doctor', 'integration', 'components'],
336
+ skipFieldChecks: true,
337
+ },
338
+ {
339
+ name: 'doctor integration docs',
340
+ args: ['doctor', 'integration', 'docs'],
341
+ skipFieldChecks: true,
342
+ },
343
+ {
344
+ name: 'doctor integration templates',
345
+ args: ['doctor', 'integration', 'templates'],
346
+ skipFieldChecks: true,
347
+ },
348
+ {
349
+ name: 'gap-report',
350
+ args: ['gap-report', '--list-categories'],
351
+ },
352
+ {
353
+ name: 'hook',
354
+ args: ['hook', '--list', '--detail', 'compact'],
355
+ jsonFieldAllowlist: [
356
+ 'detail — internal detail-level tag, not a user-facing datum',
357
+ 'import — shown inside the code() formatted block, not as a record',
358
+ ],
359
+ },
360
+ {
361
+ name: 'init',
362
+ args: ['init'],
363
+ cwd: '__TMP__',
364
+ // Init emits text via the API logger, not the formatter kit.
365
+ skipFieldChecks: true,
366
+ },
367
+ {
368
+ name: 'integration add',
369
+ args: ['integration', 'add', 'component', 'TestComp', '--dry-run'],
370
+ // Needs a valid integration project to work; errors without one.
371
+ errorExpected: true,
372
+ skipFieldChecks: true,
373
+ },
374
+ {
375
+ name: 'integration verify',
376
+ args: ['integration', 'verify'],
377
+ // Needs a packable project; pack itself may exit differently.
378
+ skipFieldChecks: true,
379
+ },
380
+ {
381
+ // The deprecated alias of `integration verify`.
382
+ name: 'integration pack',
383
+ args: ['integration', 'pack', '--check'],
384
+ skipFieldChecks: true,
385
+ },
386
+ // ── Layout command: remove these cases when the layout command is deleted ──
387
+ {
388
+ name: 'layout check',
389
+ args: ['layout', 'check', 'Button'],
390
+ skipFieldChecks: true,
391
+ },
392
+ {
393
+ name: 'layout expand',
394
+ args: ['layout', 'expand', 'Button'],
395
+ skipFieldChecks: true,
396
+ },
397
+ {
398
+ name: 'layout grammar',
399
+ args: ['layout', 'grammar'],
400
+ skipFieldChecks: true,
401
+ },
402
+ // ── End layout cases ──
403
+ {
404
+ name: 'manifest',
405
+ args: ['manifest'],
406
+ // Manifest describes the CLI itself; exempt (AST-042 FR1).
407
+ skipFieldChecks: true,
408
+ },
409
+ {
410
+ name: 'search',
411
+ args: ['search', 'button'],
412
+ jsonFieldAllowlist: [
413
+ 'matchCount — stated in section heading "Results for ... (N)"',
414
+ 'query — stated in section heading',
415
+ 'score — only shown with --verbose',
416
+ 'reason — only shown with --verbose',
417
+ 'kind — internal domain subtype, not shown in default text',
418
+ ],
419
+ },
420
+ {
421
+ name: 'swizzle',
422
+ args: ['swizzle', '--list'],
423
+ skipFieldChecks: true,
424
+ },
425
+ {
426
+ name: 'template',
427
+ args: ['template', '--list'],
428
+ // #6265 touches this handler; template id fix deferred.
429
+ skipFieldChecks: true,
430
+ jsonFieldAllowlist: [
431
+ 'id — not shown in text records (#6265)',
432
+ 'isReady — folded into name as "(WIP)" suffix (#6265)',
433
+ ],
434
+ },
435
+ {
436
+ name: 'theme add',
437
+ args: ['theme', 'add', '--list'],
438
+ // Themes are rendered as list items, not records.
439
+ skipFieldChecks: true,
440
+ },
441
+ {
442
+ name: 'theme build',
443
+ args: ['theme', 'build', 'nonexistent.ts'],
444
+ errorExpected: true,
445
+ skipFieldChecks: true,
446
+ },
447
+ {
448
+ name: 'theme list',
449
+ args: ['theme', 'list'],
450
+ skipFieldChecks: true,
451
+ },
452
+ {
453
+ name: 'theme palette generate',
454
+ args: ['theme', 'palette', 'generate', 'nonexistent.json'],
455
+ errorExpected: true,
456
+ skipFieldChecks: true,
457
+ },
458
+ {
459
+ name: 'theme targets',
460
+ args: ['theme', 'targets'],
461
+ jsonFieldAllowlist: [
462
+ 'filter — null when no filter given; not shown',
463
+ 'componentCount — shown in section heading subtitle',
464
+ ],
465
+ },
466
+ {
467
+ name: 'theme template',
468
+ args: ['theme', 'template'],
469
+ cwd: '__TMP__',
470
+ jsonFieldAllowlist: [
471
+ 'written — stated in status token ([ok] / [skip])',
472
+ 'path — stated in the "[ok] Wrote ..." line',
473
+ 'reason — absent; only in skip envelopes',
474
+ ],
475
+ },
476
+ {
477
+ name: 'upgrade',
478
+ args: ['upgrade', '--list'],
479
+ cwd: '__TMP__',
480
+ },
481
+ ];
482
+
483
+ // ─── Suite ──────────────────────────────────────────────────────────────────
484
+
485
+ describe('text-json-parity', () => {
486
+ /** @type {string[]} */
487
+ let manifestCommands;
488
+ /** @type {string} */
489
+ let tmpDir;
490
+
491
+ beforeAll(async () => {
492
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-parity-'));
493
+ const {stdout} = await runCli(['manifest', '--json'], {cwd: REPO_ROOT});
494
+ const manifest = JSON.parse(stdout);
495
+ manifestCommands = manifest.data.jsonSupported;
496
+ });
497
+
498
+ afterAll(() => {
499
+ fs.rmSync(tmpDir, {recursive: true, force: true});
500
+ });
501
+
502
+ // ── Gate: every JSON-capable command has a parity case ──────────────
503
+ it('every JSON-capable command in the manifest has a parity case', () => {
504
+ const covered = new Set(CASES.map(c => c.name));
505
+ const missing = manifestCommands.filter(cmd => !covered.has(cmd));
506
+ expect(
507
+ missing,
508
+ `Add a parity case for these commands:\n${missing.join('\n')}`,
509
+ ).toEqual([]);
510
+ });
511
+
512
+ it('every parity case names a real manifest command', () => {
513
+ const real = new Set(manifestCommands);
514
+ const stale = CASES.filter(c => !real.has(c.name)).map(c => c.name);
515
+ expect(stale).toEqual([]);
516
+ });
517
+
518
+ // ── Per-command parity checks ──────────────────────────────────────
519
+ for (const tc of CASES) {
520
+ describe(tc.name, () => {
521
+ /** @type {{text: string, json: any, textStatus: number, jsonStatus: number}} */
522
+ let run;
523
+
524
+ beforeAll(async () => {
525
+ let cwd = tc.cwd === '__TMP__' ? tmpDir : (tc.cwd || REPO_ROOT);
526
+ if (tc.cwd === '__TMP__') {
527
+ const sub = path.join(tmpDir, tc.name.replace(/\s+/g, '-'));
528
+ fs.mkdirSync(sub, {recursive: true});
529
+ if (tc.setup) tc.setup(sub);
530
+ cwd = sub;
531
+ }
532
+
533
+ // Run sequentially: runCli uses process.chdir, which is global
534
+ // state and races under Promise.all.
535
+ const textResult = await runCli(tc.args, {cwd});
536
+ const jsonResult = await runCli([...tc.args, '--json'], {cwd});
537
+
538
+ let jsonData;
539
+ try {
540
+ jsonData = JSON.parse(jsonResult.stdout);
541
+ } catch {
542
+ jsonData = null;
543
+ }
544
+
545
+ run = {
546
+ text: textResult.stdout,
547
+ json: jsonData,
548
+ textStatus: textResult.status,
549
+ jsonStatus: jsonResult.status,
550
+ };
551
+ });
552
+
553
+ it('JSON output is a valid envelope', () => {
554
+ expect(run.json).not.toBeNull();
555
+ const isSuccess = run.json?.type != null;
556
+ const isError = run.json?.error != null;
557
+ expect(isSuccess || isError).toBe(true);
558
+ });
559
+
560
+ it('exit codes match between text and JSON mode', () => {
561
+ expect(run.textStatus).toBe(run.jsonStatus);
562
+ });
563
+
564
+ if (!tc.skipFieldChecks && !tc.errorExpected) {
565
+ it('every text record key exists in the JSON data', () => {
566
+ if (!run.json?.data) return;
567
+ const textKeys = extractRecordKeys(run.text);
568
+ const jsonKeys = jsonLeafKeys(run.json.data);
569
+ if (run.json.meta) {
570
+ for (const k of jsonLeafKeys(run.json.meta)) jsonKeys.add(k);
571
+ }
572
+ const violations = [];
573
+ for (const key of textKeys.keys()) {
574
+ if (!jsonKeys.has(key)) {
575
+ violations.push(key);
576
+ }
577
+ }
578
+ expect(
579
+ violations,
580
+ `Text record keys not in JSON:\n${violations.join(', ')}`,
581
+ ).toEqual([]);
582
+ });
583
+
584
+ it('every JSON leaf field appears in the text or is allowlisted', () => {
585
+ if (!run.json?.data) return;
586
+ const textKeys = extractRecordKeys(run.text);
587
+ const jsonKeys = jsonLeafKeys(run.json.data);
588
+ const keyVals = jsonKeyValues(run.json.data);
589
+ const allowedKeys = new Set(
590
+ (tc.jsonFieldAllowlist || []).map(e => e.split(' — ')[0].trim()),
591
+ );
592
+
593
+ const missing = [];
594
+ for (const key of jsonKeys) {
595
+ const inRecords = textKeys.has(key);
596
+ // Check for `key:` as a field label at start of line.
597
+ const asLabel = new RegExp(`(?:^|\\n)\\s*${key}:`, 'm').test(run.text);
598
+ // For inline records (no labels): check if THIS KEY's values
599
+ // appear in the text. This catches inline-layout projections
600
+ // where the key name is only in the section subtitle.
601
+ const myVals = keyVals.get(key) ?? new Set();
602
+ const valuesInText = !inRecords && !asLabel && [...myVals].some(v =>
603
+ v.length > 2 && run.text.includes(v),
604
+ );
605
+ const allowed = allowedKeys.has(key);
606
+ if (!inRecords && !asLabel && !valuesInText && !allowed) {
607
+ missing.push(key);
608
+ }
609
+ }
610
+ expect(
611
+ missing,
612
+ `JSON fields not in text and not allowlisted:\n${missing.join(', ')}`,
613
+ ).toEqual([]);
614
+ });
615
+
616
+ it('text list items and block content appear in JSON data', () => {
617
+ if (!run.json?.data) return;
618
+ const jsonValues = jsonLeafValues(run.json.data);
619
+ if (run.json.meta) {
620
+ for (const v of jsonLeafValues(run.json.meta)) jsonValues.add(v);
621
+ }
622
+ const items = extractListItems(run.text);
623
+ const textBlocks = extractTextBlocks(run.text);
624
+ const violations = [];
625
+ for (const item of items) {
626
+ // Each list item should match (or be a substring of) some JSON value.
627
+ const found = [...jsonValues].some(
628
+ jv => jv === item || jv.includes(item) || item.includes(jv),
629
+ );
630
+ if (!found) {
631
+ violations.push(`[list] ${item.slice(0, 80)}`);
632
+ }
633
+ }
634
+ for (const block of textBlocks) {
635
+ // Each text block should contain at least one word that appears in
636
+ // the JSON values. A block with no JSON overlap is a fact the
637
+ // envelope does not carry. Numbers (even short) count because
638
+ // they are data.
639
+ const words = block.split(/\s+/).filter(w =>
640
+ w.length > 3 || /^\d+$/.test(w),
641
+ );
642
+ const anyOverlap = words.some(w =>
643
+ [...jsonValues].some(jv => jv.includes(w)),
644
+ );
645
+ if (!anyOverlap && words.length > 0) {
646
+ violations.push(`[text] ${block.slice(0, 80)}`);
647
+ }
648
+ }
649
+ expect(
650
+ violations,
651
+ `Text content not found in JSON data:\n${violations.join('\n')}`,
652
+ ).toEqual([]);
653
+ });
654
+ }
655
+
656
+ // Stale allowlist check
657
+ if (tc.jsonFieldAllowlist && tc.jsonFieldAllowlist.length > 0) {
658
+ it('allowlist entries are not stale', () => {
659
+ if (!run.json) return;
660
+ const searchTarget = run.json.data ?? run.json;
661
+ const stale = [];
662
+ for (const entry of tc.jsonFieldAllowlist) {
663
+ const key = entry.split(' — ')[0].trim();
664
+ if (!jsonContainsKey(searchTarget, key) && !jsonContainsKey(run.json.meta, key)) {
665
+ stale.push(entry);
666
+ }
667
+ }
668
+ expect(
669
+ stale,
670
+ `Stale allowlist entries — remove them:\n${stale.join('\n')}`,
671
+ ).toEqual([]);
672
+ });
673
+ }
674
+ });
675
+ }
676
+
677
+ // ── Upgrade failure-path regression tests ────────────────────────
678
+ // The upgrade handler silences the logger for --list and replays the error
679
+ // in the catch. These tests prove both list and non-list failures print
680
+ // the error exactly once and exit 1, in both text and --json mode.
681
+ describe('upgrade failure paths', () => {
682
+ it('upgrade --list --registry prints error once on stderr and exits 1 (text)', async () => {
683
+ const sub = path.join(tmpDir, 'upgrade-list-fail');
684
+ fs.mkdirSync(sub, {recursive: true});
685
+ const r = await runCli(['upgrade', '--list', '--registry'], {cwd: sub});
686
+ expect(r.status).toBe(1);
687
+ // The error message should appear exactly once across stdout+stderr.
688
+ const combined = r.stdout + r.stderr;
689
+ const occurrences = combined.split('cannot be used together').length - 1;
690
+ expect(occurrences, 'error should appear exactly once').toBe(1);
691
+ });
692
+
693
+ it('upgrade --list --registry emits one error envelope in --json mode', async () => {
694
+ const sub = path.join(tmpDir, 'upgrade-list-fail-json');
695
+ fs.mkdirSync(sub, {recursive: true});
696
+ const r = await runCli(['upgrade', '--list', '--registry', '--json'], {cwd: sub});
697
+ expect(r.status).toBe(1);
698
+ const parsed = JSON.parse(r.stdout);
699
+ expect(parsed).toHaveProperty('error');
700
+ expect(parsed).not.toHaveProperty('type');
701
+ });
702
+
703
+ it('non-list upgrade failure prints error once on stderr and exits 1 (text)', async () => {
704
+ const sub = path.join(tmpDir, 'upgrade-nonlist-fail');
705
+ fs.mkdirSync(sub, {recursive: true});
706
+ const r = await runCli(['upgrade', '--from', 'notsemver'], {cwd: sub});
707
+ expect(r.status).toBe(1);
708
+ // The error should appear exactly once.
709
+ const combined = r.stdout + r.stderr;
710
+ const lines = combined.split('\n').filter(l => l.includes('notsemver') || l.includes('ERR'));
711
+ // At most one line carries the error; zero is OK if the API formats
712
+ // differently, but more than one means duplication.
713
+ expect(lines.length, 'error should not be duplicated').toBeLessThanOrEqual(1);
714
+ });
715
+
716
+ it('non-list upgrade failure emits one error envelope in --json mode', async () => {
717
+ const sub = path.join(tmpDir, 'upgrade-nonlist-fail-json');
718
+ fs.mkdirSync(sub, {recursive: true});
719
+ const r = await runCli(['upgrade', '--from', 'notsemver', '--json'], {cwd: sub});
720
+ expect(r.status).toBe(1);
721
+ const parsed = JSON.parse(r.stdout);
722
+ expect(parsed).toHaveProperty('error');
723
+ });
724
+ });
725
+ });