@astryxdesign/cli 0.6.4-canary.06c8fa3 → 0.6.4-canary.0e1fbdb

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 (254) hide show
  1. package/README.md +49 -40
  2. package/api/build/build.doc.mjs +6 -1
  3. package/api/build/build.test.mjs +22 -0
  4. package/api/build/kit/kit.mjs +44 -5
  5. package/api/component/component.doc.mjs +14 -7
  6. package/api/docs/_adapter.d.mts +8 -3
  7. package/api/docs/_adapter.mjs +14 -6
  8. package/api/docs/docOverlays.test.mjs +27 -1
  9. package/api/docs/docs.doc.mjs +2 -2
  10. package/api/doctor/doctor.doc.mjs +17 -8
  11. package/api/doctor/doctor.type.d.mts +1 -1
  12. package/api/doctor/doctor.type.mjs +1 -1
  13. package/api/gap-report/gap-report.doc.mjs +19 -10
  14. package/api/hook/hook.doc.mjs +6 -3
  15. package/api/index.d.mts +2 -0
  16. package/api/index.mjs +3 -1
  17. package/api/init/init.doc.mjs +17 -12
  18. package/api/integration/add-theme.mjs +22 -1
  19. package/api/integration/add-theme.test.mjs +34 -0
  20. package/api/integration/authoring-checks.mjs +2 -2
  21. package/api/integration/integrationPackCheck.doc.mjs +3 -3
  22. package/api/integration/pack-check.lifecycle-output.test.mjs +2 -0
  23. package/api/integration/pack-check.mjs +54 -6
  24. package/api/integration/pack-check.test.mjs +90 -0
  25. package/api/integration/pack-check.type.mjs +1 -1
  26. package/api/json/assertResponse.doc.mjs +1 -1
  27. package/api/json/index.ts +1 -0
  28. package/api/json/isError.doc.mjs +1 -1
  29. package/api/layout/_adapter.d.mts +34 -0
  30. package/api/layout/_adapter.mjs +148 -0
  31. package/api/layout/check/check.d.mts +16 -0
  32. package/api/layout/check/check.mjs +40 -0
  33. package/api/layout/expand/expand.d.mts +22 -0
  34. package/api/layout/expand/expand.mjs +155 -0
  35. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  36. package/api/layout/grammar/grammar.d.mts +13 -0
  37. package/api/layout/grammar/grammar.mjs +87 -0
  38. package/api/layout/layout.d.mts +6 -0
  39. package/api/layout/layout.mjs +17 -0
  40. package/api/layout/layout.test.mjs +297 -0
  41. package/api/layout/layout.type.d.mts +89 -0
  42. package/api/layout/layout.type.mjs +103 -0
  43. package/api/layout/layoutCheck.doc.d.mts +11 -0
  44. package/api/layout/layoutCheck.doc.mjs +85 -0
  45. package/api/layout/layoutExpand.doc.d.mts +11 -0
  46. package/api/layout/layoutExpand.doc.mjs +107 -0
  47. package/api/layout/layoutGrammar.doc.d.mts +11 -0
  48. package/api/layout/layoutGrammar.doc.mjs +57 -0
  49. package/api/search/search.d.mts +27 -1
  50. package/api/search/search.doc.mjs +2 -2
  51. package/api/search/search.mjs +228 -16
  52. package/api/swizzle/swizzle.doc.mjs +7 -5
  53. package/api/template/copy/copy.mjs +1 -1
  54. package/api/template/copy/copy.test.mjs +9 -0
  55. package/api/template/template-integration.test.mjs +65 -1
  56. package/api/template/template.doc.mjs +2 -1
  57. package/api/template/template.mjs +1 -1
  58. package/api/theme/generateTonalPalette.doc.mjs +1 -2
  59. package/api/theme/listThemes.doc.mjs +1 -1
  60. package/api/theme/themeAdd.doc.mjs +9 -10
  61. package/api/theme/themeBuild.doc.mjs +13 -13
  62. package/api/theme/themeList.doc.mjs +1 -1
  63. package/api/theme/themeListAvailable.doc.mjs +2 -1
  64. package/api/theme/themePaletteGenerate.doc.mjs +15 -8
  65. package/api/theme/themeTargets.doc.mjs +3 -2
  66. package/api/theme/themeTemplate.doc.mjs +2 -1
  67. package/api/upgrade/run/run.mjs +1 -1
  68. package/api/upgrade/upgrade.doc.mjs +24 -22
  69. package/assets/docs/README.md +4 -2
  70. package/assets/docs/browser-support.doc.mjs +11 -11
  71. package/assets/docs/color.doc.mjs +8 -2
  72. package/assets/docs/elevation.doc.mjs +6 -4
  73. package/assets/docs/getting-started.doc.mjs +5 -16
  74. package/assets/docs/icons.doc.mjs +2 -21
  75. package/assets/docs/illustrations.doc.mjs +7 -15
  76. package/assets/docs/layout.doc.dense.mjs +130 -82
  77. package/assets/docs/layout.doc.mjs +133 -77
  78. package/assets/docs/migration.doc.mjs +19 -21
  79. package/assets/docs/motion.doc.mjs +16 -3
  80. package/assets/docs/principles.doc.dense.mjs +5 -5
  81. package/assets/docs/principles.doc.mjs +8 -0
  82. package/assets/docs/principles.doc.zh.mjs +6 -6
  83. package/assets/docs/shape.doc.mjs +8 -3
  84. package/assets/docs/spacing.doc.mjs +7 -2
  85. package/assets/docs/styling-libraries.doc.mjs +6 -2
  86. package/assets/docs/styling.doc.mjs +19 -23
  87. package/assets/docs/theme.doc.dense.mjs +58 -18
  88. package/assets/docs/theme.doc.mjs +56 -46
  89. package/assets/docs/theme.doc.zh.mjs +9 -8
  90. package/assets/docs/tokens.doc.dense.mjs +2 -2
  91. package/assets/docs/tokens.doc.mjs +389 -8
  92. package/assets/docs/tokens.doc.zh.mjs +2 -2
  93. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  94. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  95. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  96. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  97. package/assets/docs/tree/block-template.doc.mjs +130 -0
  98. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  99. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  100. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  101. package/assets/docs/tree/checks.doc.mjs +119 -0
  102. package/assets/docs/tree/codemods.doc.mjs +147 -0
  103. package/assets/docs/tree/component-family.doc.mjs +113 -0
  104. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  105. package/assets/docs/tree/components.doc.mjs +23 -0
  106. package/assets/docs/tree/configuration.doc.mjs +23 -0
  107. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  108. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  109. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  110. package/assets/docs/tree/docs.doc.mjs +21 -0
  111. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  112. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  113. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  114. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  115. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  116. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  117. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  118. package/assets/docs/tree/help.doc.mjs +16 -0
  119. package/assets/docs/tree/integrations.doc.mjs +25 -470
  120. package/assets/docs/tree/links.doc.mjs +98 -0
  121. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  122. package/assets/docs/tree/page-template.doc.mjs +71 -0
  123. package/assets/docs/tree/publishing.doc.mjs +111 -0
  124. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  125. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  126. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  127. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  128. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  129. package/assets/docs/tree/ship.doc.mjs +16 -0
  130. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  131. package/assets/docs/tree/single-component.doc.mjs +165 -0
  132. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  133. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  134. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  135. package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
  136. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  137. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  138. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  139. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  140. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  141. package/assets/docs/tree/templates.doc.mjs +34 -0
  142. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  143. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  144. package/assets/docs/tree/themes.doc.mjs +39 -0
  145. package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
  146. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  147. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  148. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  149. package/assets/docs/tree/versioning.doc.mjs +161 -0
  150. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  151. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  152. package/assets/docs/typography.doc.mjs +24 -4
  153. package/assets/docs/working-with-ai.doc.mjs +30 -22
  154. package/authoring/config/config.doc.mjs +2 -2
  155. package/authoring/config/type.ts +2 -2
  156. package/authoring/doctypes/_schema.d.mts +3 -2
  157. package/authoring/doctypes/_schema.mjs +6 -0
  158. package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
  159. package/authoring/doctypes/base/type.ts +4 -2
  160. package/authoring/doctypes/command/command.doc.mjs +1 -1
  161. package/authoring/doctypes/command/type.ts +1 -1
  162. package/authoring/doctypes/component/component.doc.mjs +6 -0
  163. package/authoring/doctypes/component/type.ts +8 -0
  164. package/authoring/doctypes/reference/reference.doc.mjs +7 -0
  165. package/authoring/doctypes/reference/type.ts +5 -0
  166. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  167. package/authoring/doctypes/template/template.doc.mjs +1 -1
  168. package/authoring/doctypes/template/type.ts +2 -2
  169. package/authoring/integration/integration.doc.mjs +12 -10
  170. package/clients/cli/command-result-coverage.test.mjs +7 -7
  171. package/clients/cli/commands/component.doc.mjs +4 -3
  172. package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
  173. package/clients/cli/commands/docs.doc.mjs +1 -1
  174. package/clients/cli/commands/docs.mjs +60 -17
  175. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -2
  176. package/clients/cli/commands/doctor-integration.test.mjs +53 -0
  177. package/clients/cli/commands/doctor.doc.mjs +3 -1
  178. package/clients/cli/commands/doctor.mjs +49 -5
  179. package/clients/cli/commands/gap-report.doc.mjs +10 -9
  180. package/clients/cli/commands/init.doc.mjs +9 -6
  181. package/clients/cli/commands/integration-add.doc.mjs +9 -9
  182. package/clients/cli/commands/integration-authoring.test.mjs +61 -10
  183. package/clients/cli/commands/integration-pack.doc.mjs +5 -9
  184. package/clients/cli/commands/integration-real-world.test.mjs +1 -1
  185. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  186. package/clients/cli/commands/integration.doc.mjs +4 -4
  187. package/clients/cli/commands/integration.mjs +74 -43
  188. package/clients/cli/commands/layout-check.doc.mjs +65 -0
  189. package/clients/cli/commands/layout-expand.doc.mjs +83 -0
  190. package/clients/cli/commands/layout-grammar.doc.mjs +30 -0
  191. package/clients/cli/commands/layout.doc.mjs +34 -0
  192. package/clients/cli/commands/layout.error-codes.test.mjs +66 -0
  193. package/clients/cli/commands/layout.exit-parity.test.mjs +41 -0
  194. package/clients/cli/commands/layout.mjs +275 -0
  195. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  196. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  197. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  198. package/clients/cli/commands/manifest.doc.mjs +1 -1
  199. package/clients/cli/commands/search.doc.mjs +10 -3
  200. package/clients/cli/commands/search.mjs +21 -2
  201. package/clients/cli/commands/search.test.mjs +21 -4
  202. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  203. package/clients/cli/commands/template.doc.mjs +1 -1
  204. package/clients/cli/commands/text-json-parity.test.mjs +24 -1
  205. package/clients/cli/commands/theme-add.doc.mjs +1 -1
  206. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -2
  207. package/clients/cli/commands/theme-palette.doc.mjs +1 -2
  208. package/clients/cli/commands/theme-targets.doc.mjs +2 -2
  209. package/clients/cli/commands/theme.doc.mjs +2 -1
  210. package/clients/cli/commands/upgrade.doc.mjs +62 -3
  211. package/clients/cli/index.mjs +32 -6
  212. package/clients/cli/lib/define-command.mjs +28 -4
  213. package/clients/cli/lib/define-command.test.mjs +54 -0
  214. package/clients/cli/lib/exit-codes.test.mjs +25 -2
  215. package/clients/cli/lib/json-shim.test.mjs +20 -6
  216. package/clients/cli/lib/manifest.mjs +23 -5
  217. package/foundation/agent-docs/agent-docs.mjs +1 -1
  218. package/foundation/discovery/authoring-self-docs.test.mjs +6 -2
  219. package/foundation/discovery/cli-self-docs.mjs +16 -2
  220. package/foundation/discovery/cli-self-docs.test.mjs +20 -0
  221. package/foundation/discovery/docs-discovery.mjs +5 -1
  222. package/foundation/discovery/docs-discovery.test.mjs +21 -0
  223. package/foundation/discovery/docs-section-key.d.mts +1 -1
  224. package/foundation/discovery/docs-section-key.mjs +1 -1
  225. package/foundation/discovery/template-adapter.mjs +1 -1
  226. package/foundation/doc-compiler/doc-loads.test.mjs +15 -2
  227. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  228. package/foundation/doc-compiler/tree.d.mts +4 -0
  229. package/foundation/doc-compiler/tree.mjs +6 -1
  230. package/foundation/integrations/cli-requirement.d.mts +26 -6
  231. package/foundation/integrations/cli-requirement.mjs +46 -11
  232. package/foundation/integrations/cli-requirement.test.mjs +7 -2
  233. package/foundation/integrations/contribution-inventory.mjs +1 -1
  234. package/foundation/response/error-codes.doc.mjs +6 -8
  235. package/foundation/response/error-codes.test.mjs +30 -5
  236. package/foundation/response/response-types.doc.d.mts +4 -3
  237. package/foundation/response/response-types.doc.mjs +42 -6
  238. package/foundation/response/response.doc.mjs +11 -10
  239. package/foundation/xle/browser.d.mts +3 -3
  240. package/foundation/xle/browser.mjs +3 -3
  241. package/foundation/xle/expand.mjs +2 -2
  242. package/foundation/xle/parse.mjs +1 -1
  243. package/foundation/xle/print.mjs +2 -2
  244. package/foundation/xle/splice.mjs +1 -1
  245. package/package.json +9 -9
  246. package/api/docs/docs.test.mjs +0 -245
  247. package/api/docs/integration-tree.test.mjs +0 -555
  248. package/api/docs/integrationDocs.test.mjs +0 -314
  249. package/api/search/search.test.mjs +0 -530
  250. package/assets/docs/tree/integrations.test.mjs +0 -62
  251. package/assets/docs/tree/writing-docs.doc.mjs +0 -286
  252. package/clients/cli/commands/docs.test.mjs +0 -323
  253. package/foundation/agent-docs/agent-docs.test.mjs +0 -1159
  254. package/foundation/doc-compiler/tree.test.mjs +0 -606
@@ -23,7 +23,7 @@ export type DoctorCheck = {
23
23
  */
24
24
  message: string;
25
25
  /**
26
- * - Actionable remediation, present when status is not 'pass'.
26
+ * - Actionable remediation: always present on 'warn' and 'fail'; some 'info' checks carry one too.
27
27
  */
28
28
  fix?: string | undefined;
29
29
  };
@@ -19,7 +19,7 @@
19
19
  * @property {string} label - Human-readable check name.
20
20
  * @property {DoctorStatus} status
21
21
  * @property {string} message - One-line result summary.
22
- * @property {string} [fix] - Actionable remediation, present when status is not 'pass'.
22
+ * @property {string} [fix] - Actionable remediation: always present on 'warn' and 'fail'; some 'info' checks carry one too.
23
23
  */
24
24
 
25
25
  /**
@@ -12,12 +12,16 @@ export const doc = {
12
12
  name: 'gapReport',
13
13
  namespace: 'cli/api',
14
14
  displayName: 'gapReport()',
15
- summary: 'Route a design-system gap through the fan-out handler composition.',
15
+ summary:
16
+ 'Report a missing or hard-to-use design-system capability to the package that owns it.',
16
17
  description:
17
- 'Creates a normalized gap report and fans it out to every effective handler: the project config handler first, then each loaded integration handler in config order, deduplicated by handle function identity. Each handler receives a structuredClone of the report and an AbortSignal, then runs in its own worker with a 30 s timeout and stdout redirected to stderr. A timed-out worker is terminated before the next handler starts, so process.exit, process.exitCode, and late continuations cannot affect the CLI process. A public handler requires confirmPublic per handler; internal handlers always run. When no handlers exist, a built-in GitHub/routed-only fallback runs. The aggregate response carries ordered deliveries with per-handler outcomes.',
18
+ 'Sends a gap report to every configured handler: the project config handler first, then each integration handler in config order. ' +
19
+ 'Each handler has 30 s to finish, and its output goes to stderr. Public handlers run only with confirmPublic; internal handlers always run. ' +
20
+ "With no handler, it files a GitHub issue for the owning package only with confirmPublic (without it nothing is sent), or returns the package's issues URL when that is not on GitHub. " +
21
+ 'The report records whether an agent or a person ran it, and the response lists each handler outcome in order.',
18
22
  importPath: '@astryxdesign/cli/api',
19
23
  signature:
20
- 'gapReport(component?: string, options?: GapReportOptions): Promise<GapReportCategoriesResponse | GapReportReceiptResponse>',
24
+ 'gapReport(component: string | undefined, options?: GapReportOptions): Promise<GapReportCategoriesResponse | GapReportReceiptResponse>',
21
25
  keywords: [
22
26
  'gap',
23
27
  'report',
@@ -56,13 +60,13 @@ export const doc = {
56
60
  name: 'options.package',
57
61
  type: 'string',
58
62
  description:
59
- 'Explicit owning package when automatic routing is ambiguous.',
63
+ 'Package that owns the gap: @astryxdesign/core, or a loaded integration by package name or config entry. Overrides automatic owner routing; required when more than one package provides the component.',
60
64
  },
61
65
  {
62
66
  name: 'options.confirmPublic',
63
67
  type: 'boolean',
64
68
  description:
65
- 'Explicitly consent to invoking public handlers or creating a GitHub issue.',
69
+ 'Allow public delivery: public handlers run, and with no handler a GitHub issue is filed through the gh CLI.',
66
70
  default: 'false',
67
71
  },
68
72
  {
@@ -77,6 +81,7 @@ export const doc = {
77
81
  type: 'string',
78
82
  description:
79
83
  'Directory used to load project config and component ownership.',
84
+ default: 'process.cwd()',
80
85
  },
81
86
  ],
82
87
  returns: [
@@ -87,17 +92,21 @@ export const doc = {
87
92
  {
88
93
  type: 'gap-report.file',
89
94
  description:
90
- 'An aggregate receipt with per-handler deliveries, filedCount/routedOnlyCount totals, and overall status.',
95
+ 'Receipt: status (filed, partial, failed, routed_only, consent_required, skipped), package, issuesUrl, ordered deliveries (handlerType, handler, audience, status, url, message), filedCount, and routedOnlyCount.',
91
96
  },
92
97
  ],
93
98
  throws: [
99
+ {
100
+ code: 'ERR_MISSING_ARGUMENT',
101
+ when: 'component, category, or reason is missing, blank, or not a string (unless listCategories is true)',
102
+ },
94
103
  {
95
104
  code: 'ERR_UNKNOWN_CATEGORY',
96
105
  when: 'category is not one of the fixed gap-report values',
97
106
  },
98
107
  {
99
108
  code: 'ERR_INVALID_ARGUMENT',
100
- when: 'a field value is invalid',
109
+ when: 'component is over 120 characters, category is over 80, reason is over 2000, or detail is not a string or is over 8000 characters',
101
110
  },
102
111
  {
103
112
  code: 'ERR_AMBIGUOUS_COMPONENT',
@@ -109,7 +118,7 @@ export const doc = {
109
118
  },
110
119
  {
111
120
  code: 'ERR_NOT_FOUND',
112
- when: 'no handler and no issues URL available',
121
+ when: 'no report handler is configured and the owning package has no issues URL',
113
122
  },
114
123
  ],
115
124
  examples: [
@@ -122,8 +131,8 @@ export const doc = {
122
131
  code: "const receipt = await gapReport('Button', {category: 'missing_variant', reason: 'Need a compact size'});",
123
132
  },
124
133
  {
125
- label: 'Confirm public filing',
126
- code: "await gapReport('Button', {category: 'docs_gap', reason: 'Missing keyboard example', confirmPublic: true});",
134
+ label: 'Name the owning package',
135
+ code: "const receipt = await gapReport('Button', {category: 'docs_gap', reason: 'Missing keyboard example', package: '@astryxdesign/core'});",
127
136
  },
128
137
  ],
129
138
  command: 'gap-report',
@@ -34,6 +34,7 @@ export const doc = {
34
34
  name: 'options.cwd',
35
35
  type: 'string',
36
36
  description: 'Directory to resolve @astryxdesign/core from.',
37
+ default: 'process.cwd()',
37
38
  },
38
39
  {
39
40
  name: 'options.list',
@@ -43,7 +44,8 @@ export const doc = {
43
44
  {
44
45
  name: 'options.category',
45
46
  type: 'string',
46
- description: 'List only hooks in this category.',
47
+ description:
48
+ "List only the hooks in this category, a key of the unfiltered list such as 'Media' or 'Focus'.",
47
49
  },
48
50
  {
49
51
  name: 'options.params',
@@ -54,7 +56,8 @@ export const doc = {
54
56
  name: 'options.detail',
55
57
  type: "'full' | 'compact' | 'brief'",
56
58
  description: 'Detail level for list views.',
57
- default: "'full' for a named hook, 'brief' for list views",
59
+ default:
60
+ "'full' for a named hook; 'brief' for lists (returned as data.detail: 'names')",
58
61
  },
59
62
  {
60
63
  name: 'options.lang',
@@ -104,7 +107,7 @@ export const doc = {
104
107
  },
105
108
  {
106
109
  label: 'Browse a category',
107
- code: "await hook(undefined, {category: 'State', detail: 'compact'});",
110
+ code: "await hook(undefined, {category: 'Media', detail: 'compact'});",
108
111
  },
109
112
  ],
110
113
  command: 'hook',
package/api/index.d.mts CHANGED
@@ -33,12 +33,14 @@ export * from "./gap-report/gap-report.type.mjs";
33
33
  export * from "./upgrade/upgrade.type.mjs";
34
34
  export * from "./init/init.type.mjs";
35
35
  export * from "./doctor/doctor.type.mjs";
36
+ export * from "./layout/layout.type.mjs";
36
37
  export * from "./integration/integration-authoring.type.mjs";
37
38
  export * from "./integration/pack-check.type.mjs";
38
39
  export * from "./integration/validate-integration.type.mjs";
39
40
  export * from "./integration/authoring-checks.type.mjs";
40
41
  export type Logger = import("./logger.mjs").Logger;
41
42
  export { themeBuild, themeAdd, themeTemplate, themeList, themeListAvailable, themeTargets, themePaletteGenerate, generateTonalPalette, listThemes } from "./theme/theme.mjs";
43
+ export { layoutExpand, layoutCheck, layoutGrammar } from "./layout/layout.mjs";
42
44
  export { integrationAdd, integrationAddAgentDoc, integrationAddCodemod, integrationAddComponent, integrationAddDoc, integrationAddTemplate } from "./integration/add-contribution.mjs";
43
45
  export { validateIntegration, summarizeIssues } from "./integration/validate-integration.mjs";
44
46
  export { integrationTemplateConflicts, integrationComponentConflicts, integrationDocConflicts } from "./integration/authoring-checks.mjs";
package/api/index.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * @file Programmatic API for the Astryx CLI.
5
5
  *
6
- * Every function returns the same { type, data } envelope that `xds --json` outputs.
6
+ * Every function returns the same { type, data } envelope that `astryx --json` outputs.
7
7
  * Errors throw AstryxError (with optional .suggestions).
8
8
  *
9
9
  * @example
@@ -44,6 +44,7 @@ export {gapReport} from './gap-report/gap-report.mjs';
44
44
  export {upgrade} from './upgrade/upgrade.mjs';
45
45
  export {init} from './init/init.mjs';
46
46
  export {doctor} from './doctor/doctor.mjs';
47
+ export {layoutExpand, layoutCheck, layoutGrammar} from './layout/layout.mjs';
47
48
  export {
48
49
  integrationAdd,
49
50
  integrationAddAgentDoc,
@@ -92,6 +93,7 @@ export * from './gap-report/gap-report.type.mjs';
92
93
  export * from './upgrade/upgrade.type.mjs';
93
94
  export * from './init/init.type.mjs';
94
95
  export * from './doctor/doctor.type.mjs';
96
+ export * from './layout/layout.type.mjs';
95
97
  export * from './integration/integration-authoring.type.mjs';
96
98
  export * from './integration/pack-check.type.mjs';
97
99
  export * from './integration/validate-integration.type.mjs';
@@ -19,10 +19,9 @@ export const doc = {
19
19
  'Sets a project up with NO prompts, so it behaves identically for humans, ' +
20
20
  'agents, CI, and piped I/O. By default it installs the AGENTS.md/CLAUDE.md ' +
21
21
  'agent-docs cheat sheet, including guidance from configured integrations, and ' +
22
- 'prints getting-started guidance; `features` / ' +
23
- '`all` add theme and page-building guidance and can scaffold a starter ' +
24
- 'template. With `removeAgents` it removes the managed agent-docs block ' +
25
- 'instead of installing.',
22
+ "prints getting-started guidance; `features` / `all` print only the chosen features' " +
23
+ 'guidance instead (the theme feature also writes the annotated theme template). ' +
24
+ 'With `removeAgents` it removes the managed agent-docs block instead of installing.',
26
25
  importPath: '@astryxdesign/cli/api',
27
26
  signature:
28
27
  'init(options?: InitOptions, ctx?: {cwd?: string}): Promise<InitRunResponse | InitRemoveResponse>',
@@ -32,7 +31,7 @@ export const doc = {
32
31
  name: 'options.features',
33
32
  type: 'string',
34
33
  description:
35
- 'Comma-separated features to install: agents (agent docs), theme (writes the annotated theme.template.ts), template (page-template guidance).',
34
+ 'Comma-separated features to install: agents (agent docs), theme (writes the annotated theme.template.ts), template (the page-building commands; writes a page only with templateName).',
36
35
  },
37
36
  {
38
37
  name: 'options.all',
@@ -47,7 +46,8 @@ export const doc = {
47
46
  {
48
47
  name: 'options.agent',
49
48
  type: 'string',
50
- description: 'Agent preset: claude, cursor, codex, hermes, muse, all.',
49
+ description:
50
+ 'Agent preset: claude, cursor, codex, hermes, muse, all. Used only when the agents feature runs.',
51
51
  },
52
52
  {
53
53
  name: 'options.agentDocsPath',
@@ -58,9 +58,14 @@ export const doc = {
58
58
  name: 'options.templateName',
59
59
  type: 'string',
60
60
  description:
61
- 'Scaffold a named page template (programmatic only; the CLI never sets it).',
61
+ 'Scaffold this page template to src/pages/<name>/page.tsx. Used only when the template feature runs (features includes template, or all); otherwise ignored. Programmatic only; the CLI never sets it.',
62
+ },
63
+ {
64
+ name: 'ctx.cwd',
65
+ type: 'string',
66
+ description: 'Directory to set up.',
67
+ default: 'process.cwd()',
62
68
  },
63
- {name: 'ctx.cwd', type: 'string', description: 'Directory to set up.'},
64
69
  ],
65
70
  returns: [
66
71
  {
@@ -71,13 +76,13 @@ export const doc = {
71
76
  {
72
77
  type: 'init.remove',
73
78
  description:
74
- 'Confirmation that the managed agent-docs block was removed (`data.removed: true`), returned when `removeAgents` is set.',
79
+ 'Returned when `removeAgents` is set. `data.removed` is always true, even when no managed block was found.',
75
80
  },
76
81
  ],
77
82
  throws: [
78
83
  {
79
84
  code: 'ERR_UNKNOWN_AGENT',
80
- when: '`agent` is not one of claude, cursor, codex, hermes, muse, all',
85
+ when: 'the agents feature runs (default mode, features includes agents, or all) and `agent` is not one of claude, cursor, codex, hermes, muse, all',
81
86
  },
82
87
  {
83
88
  code: 'ERR_UNKNOWN_FEATURE',
@@ -85,7 +90,7 @@ export const doc = {
85
90
  },
86
91
  {
87
92
  code: 'ERR_UNKNOWN_TEMPLATE',
88
- when: '`templateName` matches no bundled template',
93
+ when: 'the template feature runs and `templateName` matches no bundled template',
89
94
  },
90
95
  {
91
96
  code: 'ERR_FILE_EXISTS',
@@ -93,7 +98,7 @@ export const doc = {
93
98
  },
94
99
  {
95
100
  code: 'ERR_PATH_TRAVERSAL',
96
- when: 'the template output path resolves outside cwd, for example through a symlinked src directory',
101
+ when: 'the template output path resolves outside cwd (for example through a symlinked src directory), or, with removeAgents, a managed agent-docs file resolves outside cwd through a symlink',
97
102
  },
98
103
  ],
99
104
  examples: [
@@ -24,6 +24,10 @@ import {
24
24
  import {loadManifestObject} from '../../foundation/integrations/integrations.mjs';
25
25
  import {themeDescriptorSource} from '../../foundation/integrations/theme-descriptor.mjs';
26
26
  import {assertContributionVisible} from '../../foundation/integrations/contribution-inventory.mjs';
27
+ import {
28
+ themesCliProblem,
29
+ withDocsTreeCli,
30
+ } from '../../foundation/integrations/cli-requirement.mjs';
27
31
  import {
28
32
  applyWrites,
29
33
  findPackageDir,
@@ -233,11 +237,28 @@ export async function integrationAddTheme(name, options = {}) {
233
237
  createOnly: true,
234
238
  },
235
239
  ];
236
- const packageUpdate = packageJsonUpdate(
240
+ let packageUpdate = packageJsonUpdate(
237
241
  packageFile,
238
242
  rootPath,
239
243
  path.basename(manifestFile),
240
244
  );
245
+ // A CLI older than the one that reads typed theme descriptors rejects the
246
+ // themes root and withholds the package's themes and docs. Declare the CLI
247
+ // that reads them as a peer, so an older one is flagged at install instead.
248
+ {
249
+ const expectedOriginal =
250
+ packageUpdate?.expectedOriginal ?? fs.readFileSync(packageFile);
251
+ const text = packageUpdate?.contents ?? expectedOriginal.toString('utf-8');
252
+ const current = JSON.parse(text);
253
+ if (themesCliProblem(current) != null) {
254
+ packageUpdate = {
255
+ contents:
256
+ JSON.stringify(withDocsTreeCli(current), null, 2) +
257
+ (text.endsWith('\n') ? '\n' : ''),
258
+ expectedOriginal,
259
+ };
260
+ }
261
+ }
241
262
  if (packageUpdate != null) {
242
263
  plans.push({
243
264
  path: packageFile,
@@ -77,6 +77,40 @@ describe('integrationAddTheme', () => {
77
77
  expect((await validateLocalIntegration(tmpDir)).issues).toEqual([]);
78
78
  });
79
79
 
80
+ it('declares the optional CLI peer that reads typed theme descriptors', async () => {
81
+ setup({includeFiles: false});
82
+ const result = await integrationAddTheme('ocean', {cwd: tmpDir});
83
+ expect(result.data.files).toContain('package.json');
84
+ const pkg = JSON.parse(
85
+ fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
86
+ );
87
+ expect(pkg.peerDependencies).toEqual({'@astryxdesign/cli': '>=0.7.0'});
88
+ expect(pkg.peerDependenciesMeta).toEqual({
89
+ '@astryxdesign/cli': {optional: true},
90
+ });
91
+ });
92
+
93
+ it('keeps a CLI peer that already reads typed theme descriptors', async () => {
94
+ const pkg = {
95
+ name: '@acme/themes',
96
+ version: '1.0.0',
97
+ peerDependencies: {'@astryxdesign/cli': '^0.7.2'},
98
+ };
99
+ fs.writeFileSync(
100
+ path.join(tmpDir, 'package.json'),
101
+ `${JSON.stringify(pkg, null, 2)}\n`,
102
+ );
103
+ fs.writeFileSync(
104
+ path.join(tmpDir, 'astryx.integration.mjs'),
105
+ 'export default {};\n',
106
+ );
107
+ const result = await integrationAddTheme('ocean', {cwd: tmpDir});
108
+ expect(result.data.files).not.toContain('package.json');
109
+ expect(
110
+ JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8')),
111
+ ).toEqual(pkg);
112
+ });
113
+
80
114
  it('dry-runs the identical receipt without writing anything', async () => {
81
115
  setup();
82
116
  const beforeManifest = fs.readFileSync(
@@ -368,11 +368,11 @@ export async function integrationDocConflicts(pkg, options = {}) {
368
368
  // and placed guides this package adds to the docs tree, and every link in
369
369
  // its docs (spec:AST-046, spec:AST-047).
370
370
  if (errors.length === 0) {
371
- for (const message of await packageDocsProblems(
371
+ for (const {severity, message} of await packageDocsProblems(
372
372
  /** @type {{name: string}} */ (resolved.integration),
373
373
  discovered,
374
374
  )) {
375
- issues.push({code: 'invalid_doc_graph', severity: 'warning', message});
375
+ issues.push({code: 'invalid_doc_graph', severity, message});
376
376
  }
377
377
 
378
378
  // A reference block includes content rather than linking to it, so one
@@ -7,13 +7,13 @@ export const doc = {
7
7
  name: 'integrationPackCheck',
8
8
  namespace: 'cli/api',
9
9
  displayName: 'integrationPackCheck()',
10
- summary: 'Prove an integration package survives npm packing.',
10
+ summary: 'Check an integration package the way npm will publish it.',
11
11
  description:
12
12
  "Validates the local integration, runs the package lifecycle, packs with npm, checks required files against npm's authoritative tarball list, extracts the real tarball into a scratch consumer, compares local and packed contribution inventories, and resolves every packed component through its documented public import to verify that module exports the component. A package that ships a namespace doc or a placed guide, or has a template that sets `replaces`, fails unless its `@astryxdesign/cli` peer range admits only CLIs that read them.",
13
13
  importPath: '@astryxdesign/cli/api',
14
14
  signature:
15
15
  'integrationPackCheck(options?: IntegrationPackCheckOptions): Promise<IntegrationPackCheckResponse>',
16
- keywords: ['integration', 'pack', 'check', 'publish', 'tarball', 'consumer'],
16
+ keywords: ['verify', 'pack', 'publish', 'tarball', 'consumer'],
17
17
  params: [
18
18
  {
19
19
  name: 'options.cwd',
@@ -31,6 +31,6 @@ export const doc = {
31
31
  examples: [
32
32
  {label: 'Check the local package', code: 'await integrationPackCheck();'},
33
33
  ],
34
- command: 'integration pack',
34
+ command: 'integration verify',
35
35
  related: ['integrationAdd', 'validateIntegration'],
36
36
  };
@@ -24,6 +24,8 @@ function writeThemePackage(scripts) {
24
24
  name: '@acme/widgets',
25
25
  version: '1.0.0',
26
26
  files: ['astryx.integration.mjs', 'themes'],
27
+ peerDependencies: {'@astryxdesign/cli': '>=0.7.0'},
28
+ peerDependenciesMeta: {'@astryxdesign/cli': {optional: true}},
27
29
  scripts,
28
30
  },
29
31
  null,
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file `astryx integration pack --check` — verify an integration package is
4
+ * @file `astryx integration verify` — verify an integration package is
5
5
  * ready to publish by cross-referencing its declared contributions against the
6
6
  * real npm tarball.
7
7
  *
@@ -30,8 +30,13 @@ import {resolvePackageDir} from '../../foundation/integrations/integrations.mjs'
30
30
  import {
31
31
  docsTreeCliProblem,
32
32
  replacesCliProblem,
33
+ sectionIdsCliProblem,
34
+ themesCliProblem,
33
35
  } from '../../foundation/integrations/cli-requirement.mjs';
34
- import {discoverIntegrationDocs} from '../../foundation/discovery/docs-discovery.mjs';
36
+ import {
37
+ discoverIntegrationDocs,
38
+ loadTopicModule,
39
+ } from '../../foundation/discovery/docs-discovery.mjs';
35
40
  import {
36
41
  discoverIntegrationComponents,
37
42
  resolveIntegrationImportPath,
@@ -333,6 +338,23 @@ function moduleExportsName(file, exportName, seen = new Set()) {
333
338
  return found;
334
339
  }
335
340
 
341
+ /**
342
+ * Whether any of these doc files has a section that sets `id`.
343
+ * @param {string[]} files
344
+ * @returns {Promise<boolean>}
345
+ */
346
+ async function setsSectionIds(files) {
347
+ for (const file of files) {
348
+ if (typeof file !== 'string') continue;
349
+ const doc = /** @type {any} */ (await loadTopicModule(file).catch(() => null));
350
+ const sections = Array.isArray(doc?.sections) ? doc.sections : [];
351
+ if (sections.some((/** @type {any} */ section) => section?.id != null)) {
352
+ return true;
353
+ }
354
+ }
355
+ return false;
356
+ }
357
+
336
358
  /**
337
359
  * Resolve package specifiers through Node's real ESM resolver from the scratch
338
360
  * consumer. Resolution does not execute the target module, so source `.tsx`
@@ -625,19 +647,31 @@ export async function integrationPackCheck(options = {}) {
625
647
  // (spec:AST-046 FR11): an older CLI can hide every doc topic the package
626
648
  // ships, so the declared CLI range must admit only CLIs that read it.
627
649
  if (loaded.docs) {
628
- const {namespaces, guides} = await discoverIntegrationDocs(loaded).catch(
629
- () => ({namespaces: [], guides: []}),
630
- );
650
+ const {records, namespaces, guides} = await discoverIntegrationDocs(
651
+ loaded,
652
+ ).catch(() => ({records: [], namespaces: [], guides: []}));
631
653
  const problem =
632
654
  namespaces.length > 0 || guides.length > 0
633
655
  ? docsTreeCliProblem(pkg)
634
656
  : null;
635
657
  if (problem != null) {
636
658
  issues.push(error('docs_tree_needs_cli', problem));
659
+ } else if (
660
+ await setsSectionIds([
661
+ ...records.map(record => record.path),
662
+ ...guides.map(guide => /** @type {any} */ (guide.ref).topicFile),
663
+ ])
664
+ ) {
665
+ // A section `id` is also a field an older CLI rejects, hiding the
666
+ // package's doc topics; the same peer range fixes both.
667
+ const idProblem = sectionIdsCliProblem(pkg);
668
+ if (idProblem != null) {
669
+ issues.push(error('section_ids_need_cli', idProblem));
670
+ }
637
671
  }
638
672
  }
639
673
  // A template that sets `replaces` needs a CLI that reads the field
640
- // (spec:AST-035): an older CLI withholds the package's templates and docs.
674
+ // (spec:AST-035): an older CLI drops that template and hides the package's docs.
641
675
  if (loaded.templates) {
642
676
  const found = await discoverIntegrationTemplatesForOne(loaded).catch(
643
677
  () => ({templates: [], errors: []}),
@@ -650,6 +684,12 @@ export async function integrationPackCheck(options = {}) {
650
684
  const problem = setsReplaces ? replacesCliProblem(pkg) : null;
651
685
  if (problem != null) issues.push(error('replaces_needs_cli', problem));
652
686
  }
687
+ // A theme needs a CLI that reads typed theme descriptors: an older CLI
688
+ // rejects the themes root and withholds the package's themes and docs.
689
+ if (localIdentities.themes.length > 0) {
690
+ const problem = themesCliProblem(pkg);
691
+ if (problem != null) issues.push(error('themes_need_cli', problem));
692
+ }
653
693
 
654
694
  // Temp resources — always cleaned up
655
695
  const tgzTmpDir = fs.mkdtempSync(
@@ -682,6 +722,14 @@ export async function integrationPackCheck(options = {}) {
682
722
  // package's already-installed dependencies. The unique suffix makes
683
723
  // concurrent checks independent.
684
724
  scratchBase = fs.mkdtempSync(path.join(packageDir, '.astryx-pack-check-'));
725
+ // The consumer's own package.json makes it the package scope for its
726
+ // imports. Without one, Node resolves the package's name through the
727
+ // SOURCE package.json (self-reference), so an export target left out of
728
+ // the tarball would still resolve.
729
+ fs.writeFileSync(
730
+ path.join(scratchBase, 'package.json'),
731
+ `${JSON.stringify({name: 'astryx-verify-consumer', private: true})}\n`,
732
+ );
685
733
 
686
734
  // Cross-reference file inventory vs pack list
687
735
  if (!packResult.packedPaths.has(fileInv.manifest)) {
@@ -36,6 +36,8 @@ function writePackage({
36
36
  scripts,
37
37
  } = {}) {
38
38
  const pkg = {name, version};
39
+ // A theme needs a CLI that reads typed theme descriptors.
40
+ if (themes) pkg.peerDependencies = {'@astryxdesign/cli': '>=0.7.0'};
39
41
  if (files !== undefined) pkg.files = files;
40
42
  if (scripts !== undefined) pkg.scripts = scripts;
41
43
  fs.writeFileSync(
@@ -94,6 +96,30 @@ describe('integrationPackCheck', () => {
94
96
  );
95
97
  });
96
98
 
99
+ it('fails a package that ships a theme on a CLI range that cannot read it', async () => {
100
+ writePackage({files: ['astryx.integration.mjs', 'themes']});
101
+ const pkgFile = path.join(tmpDir, 'package.json');
102
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
103
+ delete pkg.peerDependencies;
104
+ fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
105
+
106
+ const missing = await integrationPackCheck({cwd: tmpDir});
107
+ expect(missing.data.packable).toBe(false);
108
+ expect(missing.data.issues).toContainEqual(
109
+ expect.objectContaining({
110
+ code: 'themes_need_cli',
111
+ message: expect.stringContaining('ships a theme'),
112
+ }),
113
+ );
114
+
115
+ pkg.peerDependencies = {'@astryxdesign/cli': '^0.6.3'};
116
+ fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
117
+ const old = await integrationPackCheck({cwd: tmpDir});
118
+ expect(old.data.issues).toContainEqual(
119
+ expect.objectContaining({code: 'themes_need_cli'}),
120
+ );
121
+ });
122
+
97
123
  it('fails when a theme entry omits its inferred runtime export', async () => {
98
124
  writePackage({files: ['astryx.integration.mjs', 'themes']});
99
125
  fs.writeFileSync(
@@ -193,6 +219,39 @@ describe('integrationPackCheck', () => {
193
219
  );
194
220
  });
195
221
 
222
+ it('resolves public imports in the packed package, not the source', async () => {
223
+ // The root export's target is left out of `files`: the source package
224
+ // resolves it, but an app that installs the tarball cannot.
225
+ fs.writeFileSync(
226
+ path.join(tmpDir, 'package.json'),
227
+ `${JSON.stringify({
228
+ name: '@acme/widgets',
229
+ version: '1.0.0',
230
+ files: ['astryx.integration.mjs'],
231
+ exports: {'.': './index.mjs'},
232
+ })}\n`,
233
+ );
234
+ fs.writeFileSync(
235
+ path.join(tmpDir, 'index.mjs'),
236
+ "export {AcmeWidget} from './components/AcmeWidget.tsx';\n",
237
+ );
238
+ await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
239
+ const docFile = path.join(tmpDir, 'components', 'AcmeWidget.doc.mjs');
240
+ const doc = fs.readFileSync(docFile, 'utf-8');
241
+ expect(doc).toContain('@acme/widgets/components/AcmeWidget');
242
+ fs.writeFileSync(
243
+ docFile,
244
+ doc.replace('@acme/widgets/components/AcmeWidget', '@acme/widgets'),
245
+ );
246
+
247
+ const result = await integrationPackCheck({cwd: tmpDir});
248
+
249
+ expect(result.data.packable).toBe(false);
250
+ expect(result.data.issues).toContainEqual(
251
+ expect.objectContaining({code: 'component_export_missing'}),
252
+ );
253
+ });
254
+
196
255
  it('fails when packed template source is hidden by package exports', async () => {
197
256
  writePackage({
198
257
  manifest: "export default {templates: './templates'};\n",
@@ -336,6 +395,37 @@ describe('integrationPackCheck', () => {
336
395
  expect(await codes()).not.toContain('docs_tree_needs_cli');
337
396
  }, 120_000);
338
397
 
398
+ it('fails a package whose doc section sets id on a CLI range that rejects the field', async () => {
399
+ writePackage({manifest: "export default {docs: './docs'};\n", themes: false});
400
+ fs.mkdirSync(path.join(tmpDir, 'docs'), {recursive: true});
401
+ const topic = (/** @type {string} */ section) =>
402
+ `export default {type: 'generic', name: 'notes', title: 'Notes', description: 'Notes.', sections: [${section}]};\n`;
403
+ const file = path.join(tmpDir, 'docs', 'notes.doc.mjs');
404
+ const codes = async () =>
405
+ (await integrationPackCheck({cwd: tmpDir})).data.issues.map(
406
+ (/** @type {{code: string}} */ issue) => issue.code,
407
+ );
408
+ fs.writeFileSync(
409
+ file,
410
+ topic("{title: 'Take notes', content: [{type: 'prose', text: 'Notes.'}]}"),
411
+ );
412
+ expect(await codes()).not.toContain('section_ids_need_cli');
413
+ // A fresh file name: the module loader caches a path once it is imported.
414
+ fs.rmSync(file);
415
+ fs.writeFileSync(
416
+ path.join(tmpDir, 'docs', 'notes-with-ids.doc.mjs'),
417
+ topic(
418
+ "{id: 'take-notes', title: 'Take notes', content: [{type: 'prose', text: 'Notes.'}]}",
419
+ ),
420
+ );
421
+ expect(await codes()).toContain('section_ids_need_cli');
422
+ const pkgFile = path.join(tmpDir, 'package.json');
423
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
424
+ pkg.peerDependencies = {'@astryxdesign/cli': '>=0.7.0'};
425
+ fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
426
+ expect(await codes()).not.toContain('section_ids_need_cli');
427
+ }, 120_000);
428
+
339
429
  it('fails a package with a template that sets replaces on a CLI range that rejects the field', async () => {
340
430
  writePackage({manifest: "export default {templates: './templates'};\n", themes: false});
341
431
  fs.mkdirSync(path.join(tmpDir, 'templates'), {recursive: true});
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file Colocated types for `astryx integration pack --check`.
4
+ * @file Colocated types for `astryx integration verify`.
5
5
  */
6
6
 
7
7
  /**
@@ -49,7 +49,7 @@ export const doc = {
49
49
  throws: [
50
50
  {
51
51
  code: 'Error',
52
- when: 'the CLI returned an error envelope (the CLI message is rethrown), or the response `type` is not expectedType',
52
+ when: 'a plain Error with no code: the CLI returned an error envelope (its message is rethrown; code and suggestions are dropped), or the response `type` is not expectedType',
53
53
  },
54
54
  ],
55
55
  examples: [