@astryxdesign/cli 0.6.4 → 0.6.5-canary.031021b

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 (288) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +97 -90
  3. package/api/build/build.doc.mjs +6 -1
  4. package/api/build/build.test.mjs +22 -0
  5. package/api/build/kit/kit.mjs +44 -5
  6. package/api/component/_adapter.d.mts +25 -0
  7. package/api/component/_adapter.mjs +59 -5
  8. package/api/component/component.d.mts +6 -3
  9. package/api/component/component.doc.mjs +37 -17
  10. package/api/component/component.mjs +249 -9
  11. package/api/component/component.type.d.mts +25 -0
  12. package/api/component/component.type.mjs +44 -0
  13. package/api/discover/_adapter.d.mts +114 -6
  14. package/api/discover/_adapter.mjs +372 -17
  15. package/api/discover/_adapter.test.mjs +215 -0
  16. package/api/discover/_catalog-view.d.mts +115 -0
  17. package/api/discover/_catalog-view.mjs +203 -0
  18. package/api/discover/_catalog-view.test.mjs +128 -0
  19. package/api/discover/detail/detail.d.mts +18 -6
  20. package/api/discover/detail/detail.mjs +67 -13
  21. package/api/discover/detail/detail.test.mjs +85 -0
  22. package/api/discover/detail/item/item.d.mts +26 -0
  23. package/api/discover/detail/item/item.mjs +78 -0
  24. package/api/discover/detail/item/item.test.mjs +73 -0
  25. package/api/discover/discover.d.mts +3 -9
  26. package/api/discover/discover.doc.mjs +61 -18
  27. package/api/discover/discover.mjs +220 -36
  28. package/api/discover/discover.test.mjs +11 -2
  29. package/api/discover/discover.type.d.mts +147 -8
  30. package/api/discover/discover.type.mjs +102 -12
  31. package/api/discover/list/list.d.mts +20 -6
  32. package/api/discover/list/list.mjs +45 -12
  33. package/api/discover/list/list.test.mjs +46 -0
  34. package/api/discover/search/search.d.mts +18 -16
  35. package/api/discover/search/search.mjs +102 -56
  36. package/api/discover/search/search.test.mjs +144 -10
  37. package/api/docs/_adapter.d.mts +8 -3
  38. package/api/docs/_adapter.mjs +14 -6
  39. package/api/docs/docOverlays.test.mjs +27 -1
  40. package/api/docs/docs.doc.mjs +2 -2
  41. package/api/doctor/doctor.d.mts +8 -3
  42. package/api/doctor/doctor.doc.mjs +17 -8
  43. package/api/doctor/doctor.mjs +90 -9
  44. package/api/doctor/doctor.test.mjs +122 -10
  45. package/api/doctor/doctor.type.d.mts +1 -1
  46. package/api/doctor/doctor.type.mjs +1 -1
  47. package/api/gap-report/gap-report.doc.mjs +19 -10
  48. package/api/hook/hook.doc.mjs +6 -3
  49. package/api/index.d.mts +1 -0
  50. package/api/index.mjs +5 -3
  51. package/api/init/init.doc.mjs +17 -12
  52. package/api/integration/add-helpers.d.mts +5 -2
  53. package/api/integration/add-helpers.mjs +36 -9
  54. package/api/integration/add-theme.mjs +22 -1
  55. package/api/integration/add-theme.test.mjs +34 -0
  56. package/api/integration/authoring-checks.mjs +2 -2
  57. package/api/integration/integrationPackCheck.doc.mjs +3 -3
  58. package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
  59. package/api/integration/pack-check.mjs +82 -9
  60. package/api/integration/pack-check.test.mjs +90 -0
  61. package/api/integration/pack-check.type.mjs +1 -1
  62. package/api/json/assertResponse.doc.mjs +1 -1
  63. package/api/json/isError.doc.mjs +1 -1
  64. package/api/search/search.d.mts +27 -1
  65. package/api/search/search.doc.mjs +2 -2
  66. package/api/search/search.mjs +228 -16
  67. package/api/swizzle/swizzle.doc.mjs +7 -5
  68. package/api/template/copy/copy.mjs +1 -1
  69. package/api/template/copy/copy.test.mjs +9 -0
  70. package/api/template/template.doc.mjs +2 -1
  71. package/api/theme/add/add.mjs +17 -25
  72. package/api/theme/add/add.rollback.test.mjs +158 -0
  73. package/api/theme/add/add.staging.test.mjs +40 -23
  74. package/api/theme/build/build.family.test.mjs +7 -12
  75. package/api/theme/build/build.mjs +8 -18
  76. package/api/theme/build/build.rollback.test.mjs +148 -0
  77. package/api/theme/generateTonalPalette.doc.mjs +1 -2
  78. package/api/theme/listThemes.doc.mjs +1 -1
  79. package/api/theme/themeAdd.doc.mjs +9 -10
  80. package/api/theme/themeBuild.doc.mjs +13 -13
  81. package/api/theme/themeList.doc.mjs +1 -1
  82. package/api/theme/themeListAvailable.doc.mjs +2 -1
  83. package/api/theme/themePaletteGenerate.doc.mjs +15 -8
  84. package/api/theme/themeTargets.doc.mjs +3 -2
  85. package/api/theme/themeTemplate.doc.mjs +2 -1
  86. package/api/upgrade/run/files-changed.test.mjs +111 -0
  87. package/api/upgrade/run/run.mjs +5 -3
  88. package/api/upgrade/upgrade.doc.mjs +24 -22
  89. package/api/upgrade/upgrade.type.mjs +2 -2
  90. package/assets/codemods/__tests__/runner.test.mjs +3 -1
  91. package/assets/codemods/file-count.test.mjs +163 -0
  92. package/assets/codemods/integration-runner.mjs +3 -3
  93. package/assets/codemods/runner.mjs +5 -4
  94. package/assets/docs/README.md +4 -2
  95. package/assets/docs/browser-support.doc.mjs +11 -11
  96. package/assets/docs/color.doc.mjs +8 -2
  97. package/assets/docs/elevation.doc.mjs +6 -4
  98. package/assets/docs/getting-started.doc.mjs +5 -16
  99. package/assets/docs/icons.doc.mjs +2 -21
  100. package/assets/docs/illustrations.doc.mjs +7 -15
  101. package/assets/docs/internationalization.doc.mjs +7 -5
  102. package/assets/docs/layout.doc.dense.mjs +130 -82
  103. package/assets/docs/layout.doc.mjs +133 -77
  104. package/assets/docs/migration.doc.mjs +19 -21
  105. package/assets/docs/motion.doc.mjs +16 -3
  106. package/assets/docs/principles.doc.dense.mjs +5 -5
  107. package/assets/docs/principles.doc.mjs +8 -0
  108. package/assets/docs/principles.doc.zh.mjs +6 -6
  109. package/assets/docs/shape.doc.mjs +8 -3
  110. package/assets/docs/spacing.doc.mjs +7 -2
  111. package/assets/docs/styling-libraries.doc.mjs +6 -2
  112. package/assets/docs/styling.doc.mjs +19 -23
  113. package/assets/docs/theme.doc.dense.mjs +58 -18
  114. package/assets/docs/theme.doc.mjs +57 -47
  115. package/assets/docs/theme.doc.zh.mjs +9 -8
  116. package/assets/docs/tokens.doc.dense.mjs +2 -2
  117. package/assets/docs/tokens.doc.mjs +389 -8
  118. package/assets/docs/tokens.doc.zh.mjs +2 -2
  119. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  120. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  121. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  122. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  123. package/assets/docs/tree/block-template.doc.mjs +130 -0
  124. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  125. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  126. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  127. package/assets/docs/tree/checks.doc.mjs +119 -0
  128. package/assets/docs/tree/codemods.doc.mjs +147 -0
  129. package/assets/docs/tree/component-family.doc.mjs +113 -0
  130. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  131. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  132. package/assets/docs/tree/components.doc.mjs +23 -0
  133. package/assets/docs/tree/configuration.doc.mjs +23 -0
  134. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  135. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  136. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  137. package/assets/docs/tree/docs.doc.mjs +21 -0
  138. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  139. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  140. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  141. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  142. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  143. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  144. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  145. package/assets/docs/tree/help.doc.mjs +16 -0
  146. package/assets/docs/tree/integrations.doc.mjs +25 -451
  147. package/assets/docs/tree/links.doc.mjs +98 -0
  148. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  149. package/assets/docs/tree/page-template.doc.mjs +71 -0
  150. package/assets/docs/tree/publishing.doc.mjs +111 -0
  151. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  152. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  153. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  154. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  155. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  156. package/assets/docs/tree/ship.doc.mjs +16 -0
  157. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  158. package/assets/docs/tree/single-component.doc.mjs +165 -0
  159. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  160. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  161. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  162. package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
  163. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  164. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  165. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  166. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  167. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  168. package/assets/docs/tree/templates.doc.mjs +34 -0
  169. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  170. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  171. package/assets/docs/tree/themes.doc.mjs +39 -0
  172. package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
  173. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  174. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  175. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  176. package/assets/docs/tree/versioning.doc.mjs +161 -0
  177. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  178. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  179. package/assets/docs/typography.doc.mjs +24 -4
  180. package/assets/docs/working-with-ai.doc.mjs +30 -22
  181. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  182. package/authoring/config/config.doc.mjs +9 -1
  183. package/authoring/config/parse.d.mts +2 -0
  184. package/authoring/config/parse.mjs +19 -0
  185. package/authoring/config/parse.test.mjs +8 -0
  186. package/authoring/config/type.ts +11 -0
  187. package/authoring/discover/discover.doc.d.mts +13 -0
  188. package/authoring/discover/discover.doc.mjs +138 -0
  189. package/authoring/discover/parse.d.mts +24 -0
  190. package/authoring/discover/parse.mjs +128 -0
  191. package/authoring/discover/parse.test.mjs +124 -0
  192. package/authoring/discover/type.ts +87 -0
  193. package/authoring/doctypes/_schema.d.mts +3 -2
  194. package/authoring/doctypes/_schema.mjs +6 -0
  195. package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
  196. package/authoring/doctypes/base/type.ts +4 -2
  197. package/authoring/doctypes/component/component.doc.mjs +6 -0
  198. package/authoring/doctypes/component/type.ts +8 -0
  199. package/authoring/doctypes/reference/reference.doc.mjs +7 -0
  200. package/authoring/doctypes/reference/type.ts +5 -0
  201. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  202. package/authoring/doctypes/template/template.doc.mjs +1 -1
  203. package/authoring/doctypes/template/type.ts +2 -2
  204. package/authoring/index.d.mts +1 -0
  205. package/authoring/index.d.ts +10 -0
  206. package/authoring/index.mjs +1 -0
  207. package/authoring/integration/integration.doc.mjs +12 -10
  208. package/clients/cli/commands/component/index.mjs +152 -55
  209. package/clients/cli/commands/component-batch.test.mjs +341 -0
  210. package/clients/cli/commands/component-ownership.test.mjs +89 -0
  211. package/clients/cli/commands/component.doc.mjs +27 -9
  212. package/clients/cli/commands/discover.doc.mjs +53 -9
  213. package/clients/cli/commands/discover.mjs +393 -118
  214. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  215. package/clients/cli/commands/docs.doc.mjs +1 -1
  216. package/clients/cli/commands/docs.mjs +60 -17
  217. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -2
  218. package/clients/cli/commands/doctor-integration.test.mjs +53 -0
  219. package/clients/cli/commands/doctor.doc.mjs +3 -1
  220. package/clients/cli/commands/doctor.mjs +49 -5
  221. package/clients/cli/commands/gap-report.doc.mjs +10 -9
  222. package/clients/cli/commands/init.doc.mjs +9 -6
  223. package/clients/cli/commands/integration-add.doc.mjs +9 -9
  224. package/clients/cli/commands/integration-authoring.test.mjs +61 -10
  225. package/clients/cli/commands/integration-pack.doc.mjs +5 -9
  226. package/clients/cli/commands/integration-real-world.test.mjs +1 -1
  227. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  228. package/clients/cli/commands/integration.doc.mjs +4 -4
  229. package/clients/cli/commands/integration.mjs +74 -43
  230. package/clients/cli/commands/manifest.doc.mjs +1 -1
  231. package/clients/cli/commands/search.doc.mjs +10 -3
  232. package/clients/cli/commands/search.mjs +21 -2
  233. package/clients/cli/commands/search.test.mjs +21 -4
  234. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  235. package/clients/cli/commands/template.doc.mjs +1 -1
  236. package/clients/cli/commands/text-json-parity.test.mjs +7 -1
  237. package/clients/cli/commands/theme-add.doc.mjs +1 -1
  238. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -2
  239. package/clients/cli/commands/theme-palette.doc.mjs +1 -2
  240. package/clients/cli/commands/theme-targets.doc.mjs +2 -2
  241. package/clients/cli/commands/theme.doc.mjs +2 -1
  242. package/clients/cli/commands/upgrade.doc.mjs +62 -3
  243. package/clients/cli/index.mjs +28 -6
  244. package/clients/cli/lib/define-command.mjs +28 -4
  245. package/clients/cli/lib/define-command.test.mjs +54 -0
  246. package/clients/cli/lib/exit-codes.test.mjs +17 -1
  247. package/clients/cli/lib/json-shim.mjs +24 -14
  248. package/clients/cli/lib/manifest.mjs +18 -5
  249. package/clients/cli/lib/manifest.test.mjs +5 -2
  250. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  251. package/foundation/agent-docs/agent-docs.mjs +1 -1
  252. package/foundation/discovery/authoring-self-docs.mjs +1 -0
  253. package/foundation/discovery/authoring-self-docs.test.mjs +6 -2
  254. package/foundation/discovery/cli-self-docs.mjs +16 -2
  255. package/foundation/discovery/cli-self-docs.test.mjs +20 -0
  256. package/foundation/discovery/docs-discovery.mjs +5 -1
  257. package/foundation/discovery/docs-discovery.test.mjs +21 -0
  258. package/foundation/discovery/docs-section-key.d.mts +1 -1
  259. package/foundation/discovery/docs-section-key.mjs +1 -1
  260. package/foundation/doc-compiler/doc-loads.test.mjs +3 -2
  261. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  262. package/foundation/doc-compiler/tree.d.mts +4 -0
  263. package/foundation/doc-compiler/tree.mjs +6 -1
  264. package/foundation/integrations/cli-requirement.d.mts +26 -6
  265. package/foundation/integrations/cli-requirement.mjs +46 -11
  266. package/foundation/integrations/cli-requirement.test.mjs +7 -2
  267. package/foundation/integrations/contribution-inventory.mjs +1 -1
  268. package/foundation/integrations/integrations.d.mts +14 -1
  269. package/foundation/integrations/integrations.mjs +41 -1
  270. package/foundation/integrations/integrations.test.mjs +31 -0
  271. package/foundation/response/batch.type.d.mts +33 -0
  272. package/foundation/response/batch.type.mjs +34 -0
  273. package/foundation/response/error-codes.doc.mjs +6 -8
  274. package/foundation/response/error-codes.test.mjs +30 -5
  275. package/foundation/response/response-types.doc.d.mts +4 -3
  276. package/foundation/response/response-types.doc.mjs +40 -10
  277. package/foundation/response/response-types.doc.test.mjs +23 -0
  278. package/foundation/response/response.doc.mjs +11 -10
  279. package/package.json +9 -9
  280. package/api/docs/docs.test.mjs +0 -243
  281. package/api/docs/integration-tree.test.mjs +0 -555
  282. package/api/docs/integrationDocs.test.mjs +0 -314
  283. package/api/search/search.test.mjs +0 -512
  284. package/assets/docs/tree/integrations.test.mjs +0 -62
  285. package/assets/docs/tree/writing-docs.doc.mjs +0 -286
  286. package/clients/cli/commands/docs.test.mjs +0 -294
  287. package/foundation/agent-docs/agent-docs.test.mjs +0 -1159
  288. package/foundation/doc-compiler/tree.test.mjs +0 -598
@@ -18,21 +18,22 @@ export const doc = {
18
18
  'Non-interactive project setup (no prompts, so it behaves the same for humans, ' +
19
19
  'agents, and CI). By default it installs the AGENTS.md/CLAUDE.md agent-docs, ' +
20
20
  'including guidance from configured integrations, and prints getting-started ' +
21
- 'guidance; features/--all add theme and page-building ' +
22
- 'guidance and write an annotated theme template.',
21
+ "steps. --features and --all print only the chosen features' guidance (no " +
22
+ 'getting-started steps); the theme feature also writes an annotated theme template.',
23
23
  fn: 'init',
24
24
  options: [
25
25
  {
26
26
  flag: '--features <list>',
27
27
  param: 'options.features',
28
28
  description:
29
- 'Comma-separated features to install (agents, theme, template). An unknown feature exits 1 with ERR_UNKNOWN_FEATURE. ' +
30
- 'Ignored with --all or --remove-agents',
29
+ 'Comma-separated features: agents (agent docs), theme (writes theme.template.ts), template (prints the page-building commands; writes no file). ' +
30
+ 'An unknown feature exits 1 with ERR_UNKNOWN_FEATURE. Ignored with --all or --remove-agents',
31
31
  },
32
32
  {
33
33
  flag: '--all',
34
34
  param: 'options.all',
35
- description: 'Install all features (agents, theme, template); overrides --features',
35
+ description:
36
+ 'Install all features (agents, theme, template); overrides --features. Prints their guidance instead of the getting-started steps',
36
37
  },
37
38
  {
38
39
  flag: '--remove-agents',
@@ -47,7 +48,9 @@ export const doc = {
47
48
  param: 'options.agent',
48
49
  choices: ['claude', 'cursor', 'codex', 'hermes', 'muse', 'all'],
49
50
  description:
50
- 'Target AI tool for agent docs: claude, cursor, codex, hermes, muse, all. An unknown tool exits 1 with ERR_UNKNOWN_AGENT. ' +
51
+ 'Target AI tool for agent docs: claude (CLAUDE.md or .claude/CLAUDE.md, else creates .claude/CLAUDE.md), cursor (.cursorrules if present, else AGENTS.md), ' +
52
+ 'codex and muse (AGENTS.md), hermes (.hermes.md or HERMES.md if present, else AGENTS.md), all (every existing agent doc, else AGENTS.md and .claude/CLAUDE.md). ' +
53
+ 'An unknown tool exits 1 with ERR_UNKNOWN_AGENT. ' +
51
54
  'Used only when agent docs are installed (the default, --all, or --features agents); --agent-docs-path takes precedence',
52
55
  },
53
56
  {
@@ -8,7 +8,7 @@ export const doc = {
8
8
  namespace: 'cli/commands',
9
9
  summary: 'Add one working contribution to an integration package',
10
10
  description:
11
- 'Writes the complete minimum shape the selected contribution needs, creates the integration manifest on first use, declares the root only after a valid contribution exists, and verifies the result through the same discovery contract the packed-package check uses.',
11
+ 'Writes the files one contribution needs, creates the integration manifest on first use, and declares a root only after a contribution the CLI can read exists behind it. A component or template import also needs an `exports` entry: add writes one only when package.json already has an `exports` map, so start a new package with `"exports": {}`. See {@link generic:quick-start}.',
12
12
  fn: 'integrationAdd',
13
13
  args: [
14
14
  {
@@ -60,10 +60,14 @@ export const doc = {
60
60
  flag: '--to <version>',
61
61
  param: 'options.to',
62
62
  description:
63
- 'Exact semver the codemod migrates to (e.g. 1.2.0); required for codemod and only valid there',
63
+ 'Exact semver of the @astryxdesign/core version whose upgrade runs the codemod (e.g. 0.7.0); required for codemod and only valid there',
64
64
  },
65
65
  ],
66
66
  examples: [
67
+ {
68
+ label: 'Preview',
69
+ cli: 'astryx integration add component AcmeWidget --dry-run --json',
70
+ },
67
71
  {
68
72
  label: 'Add a component',
69
73
  cli: 'astryx integration add component AcmeWidget',
@@ -71,7 +75,7 @@ export const doc = {
71
75
  {label: 'Add a doc topic', cli: 'astryx integration add doc deploying'},
72
76
  {
73
77
  label: 'Add a page template',
74
- cli: 'astryx integration add template dashboard',
78
+ cli: 'astryx integration add template acme-dashboard',
75
79
  },
76
80
  {
77
81
  label: 'Add a block template',
@@ -87,7 +91,7 @@ export const doc = {
87
91
  },
88
92
  {
89
93
  label: 'Add a guide to the package\'s own docs section',
90
- cli: 'astryx integration add doc deploying --parent acme',
94
+ cli: 'astryx integration add doc releasing --parent acme',
91
95
  },
92
96
  {
93
97
  label: 'Add a codemod',
@@ -98,10 +102,6 @@ export const doc = {
98
102
  cli: "astryx integration add agent-doc 'Run acme verify before finishing.'",
99
103
  },
100
104
  {label: 'Add a source theme', cli: 'astryx integration add theme ocean'},
101
- {
102
- label: 'Preview',
103
- cli: 'astryx integration add component AcmeWidget --dry-run --json',
104
- },
105
105
  ],
106
106
  exitCodes: [
107
107
  {code: 0, when: 'the contribution is written or the dry run succeeds'},
@@ -110,5 +110,5 @@ export const doc = {
110
110
  when: 'the kind, name, options, package, or target files are invalid or conflict',
111
111
  },
112
112
  ],
113
- related: ['integration pack', 'doctor integration validate', 'theme add'],
113
+ related: ['integration verify', 'doctor integration validate', 'theme add'],
114
114
  };
@@ -127,10 +127,7 @@ describe('integration authoring CLI', () => {
127
127
  );
128
128
  expect(added.status).toBe(0);
129
129
 
130
- const checked = await runCli(
131
- ['integration', 'pack', '--check', '--json'],
132
- tmpDir,
133
- );
130
+ const checked = await runCli(['integration', 'verify', '--json'], tmpDir);
134
131
  // Without an exports map, the extensionless import cannot resolve —
135
132
  // pack-check must fail, not false-green.
136
133
  expect(checked.status).not.toBe(0);
@@ -150,13 +147,67 @@ describe('integration authoring CLI', () => {
150
147
  );
151
148
  });
152
149
 
153
- it('requires the explicit --check gate on pack', async () => {
154
- const result = await runCli(['integration', 'pack', '--json'], tmpDir);
155
- expect(result.status).not.toBe(0);
156
- expect(parseEnvelope(result.stdout)).toMatchObject({
157
- code: 'ERR_INVALID_ARGUMENT',
158
- error: 'Pass --check to verify the integration tarball.',
150
+ it('keeps `integration pack --check` as a deprecated alias of `integration verify`', async () => {
151
+ // The old spelling runs the same check: the same JSON, the same exit code.
152
+ const verify = await runCli(['integration', 'verify', '--json'], tmpDir);
153
+ const old = await runCli(
154
+ ['integration', 'pack', '--check', '--json'],
155
+ tmpDir,
156
+ );
157
+ expect(old.status).toBe(verify.status);
158
+ const verifyEnvelope = parseEnvelope(verify.stdout);
159
+ const oldEnvelope = parseEnvelope(old.stdout);
160
+ expect(oldEnvelope.type).toBe('integration.pack-check');
161
+ expect(oldEnvelope.type).toBe(verifyEnvelope.type);
162
+ expect(oldEnvelope.data.packable).toBe(verifyEnvelope.data.packable);
163
+ expect(oldEnvelope.data.issues).toEqual(verifyEnvelope.data.issues);
164
+ // The global flag may come first, as agents usually write it.
165
+ const lead = await runCli(
166
+ ['--json', 'integration', 'pack', '--check'],
167
+ tmpDir,
168
+ );
169
+ expect(parseEnvelope(lead.stdout).type).toBe('integration.pack-check');
170
+ // In text, it says to use the new name, on stderr, so stdout is the same.
171
+ const text = await runCli(['integration', 'pack', '--check'], tmpDir);
172
+ const verifyText = await runCli(['integration', 'verify'], tmpDir);
173
+ expect(text.status).toBe(verifyText.status);
174
+ expect(text.stdout).toBe(verifyText.stdout);
175
+ expect(text.stderr).toContain('`integration pack --check` is deprecated');
176
+ expect(text.stderr).toContain('astryx integration verify');
177
+ // Without --check it fails, as it did, and names both spellings.
178
+ const bare = await runCli(['integration', 'pack'], tmpDir);
179
+ expect(bare.status).not.toBe(0);
180
+ expect(bare.stderr).toContain('--check');
181
+ expect(bare.stderr).toContain('astryx integration verify');
182
+ // Help lists it, marked deprecated: nothing is hidden.
183
+ const help = await runCli(['integration', '--help'], tmpDir);
184
+ expect(help.stdout).toMatch(
185
+ /pack .*Deprecated: the old name of `integration verify`/,
186
+ );
187
+ // `verify` itself takes no --check.
188
+ const flag = await runCli(['integration', 'verify', '--check'], tmpDir);
189
+ expect(flag.status).not.toBe(0);
190
+ expect(flag.stderr).toContain("unknown option '--check'");
191
+ // An unknown subcommand with a flag names the subcommand, in text and JSON.
192
+ const unknown = await runCli(['integration', 'bogus', '--check'], tmpDir);
193
+ expect(unknown.status).not.toBe(0);
194
+ expect(unknown.stderr).toContain("unknown subcommand 'integration bogus'");
195
+ expect(unknown.stderr).toMatch(/verify\s+\(available subcommand\)/);
196
+ const unknownJson = await runCli(
197
+ ['integration', 'bogus', '--check', '--json'],
198
+ tmpDir,
199
+ );
200
+ expect(parseEnvelope(unknownJson.stdout)).toMatchObject({
201
+ code: 'ERR_UNKNOWN_SUBCOMMAND',
202
+ error: "unknown subcommand 'integration bogus'",
203
+ suggestions: expect.arrayContaining([
204
+ expect.objectContaining({name: 'verify'}),
205
+ ]),
159
206
  });
207
+ // A flag alone is an unknown option, not an unknown subcommand.
208
+ const flagOnly = await runCli(['integration', '--bogus'], tmpDir);
209
+ expect(flagOnly.status).not.toBe(0);
210
+ expect(flagOnly.stderr).toContain("unknown option '--bogus'");
160
211
  });
161
212
 
162
213
  it('refuses kind-specific options on another kind', async () => {
@@ -6,22 +6,18 @@ export const doc = {
6
6
  name: 'integration pack',
7
7
  displayName: 'astryx integration pack',
8
8
  namespace: 'cli/commands',
9
- summary: 'Prove the packed integration is what consumers receive',
9
+ summary: 'Deprecated: the old name of `integration verify`',
10
10
  description:
11
- 'Runs the package lifecycle, packs with npm, checks every required contribution file against the real tarball, extracts it into a scratch consumer, and compares the local and packed contribution inventories through one shared contract.',
11
+ '`astryx integration pack --check` is the name this check had before {@link command:integration verify}. It still runs the same check, with the same output, JSON, and exit codes, and prints a note that names `integration verify`. It will be removed in a later release.',
12
12
  fn: 'integrationPackCheck',
13
13
  options: [
14
14
  {
15
15
  flag: '--check',
16
- description: 'Run the packed-package verification gate',
16
+ description: 'Run the check. Required, as before.',
17
17
  },
18
18
  ],
19
19
  examples: [
20
- {label: 'Verify before publishing', cli: 'astryx integration pack --check'},
21
- {
22
- label: 'Machine-readable result',
23
- cli: 'astryx integration pack --check --json',
24
- },
20
+ {label: 'The old spelling', cli: 'astryx integration pack --check'},
25
21
  ],
26
22
  exitCodes: [
27
23
  {code: 0, when: 'the packed package exposes the same valid contributions'},
@@ -30,5 +26,5 @@ export const doc = {
30
26
  when: '--check is omitted or the tarball is incomplete or invalid',
31
27
  },
32
28
  ],
33
- related: ['integration add', 'doctor integration validate'],
29
+ related: ['integration verify'],
34
30
  };
@@ -214,7 +214,7 @@ export const oceanTheme = defineTheme({
214
214
  ]);
215
215
 
216
216
  const checked = await runCli(
217
- ['integration', 'pack', '--check', '--json'],
217
+ ['integration', 'verify', '--json'],
218
218
  providerDir,
219
219
  );
220
220
  expect(checked.status, checked.stderr).toBe(0);
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').CommandDoc} */
4
+ export const doc = {
5
+ type: 'command',
6
+ name: 'integration verify',
7
+ displayName: 'astryx integration verify',
8
+ namespace: 'cli/commands',
9
+ summary: 'Check the package the way npm will publish it, before you publish',
10
+ description:
11
+ 'Packs the package with npm, unpacks the tarball into a temporary app without installing its dependencies, and checks that the app sees the same components, templates, themes, docs, and codemods as the package, that every public import resolves, and that the package declares a CLI new enough to read it. It publishes nothing and leaves no tarball behind. It runs the package\'s own pack lifecycle scripts, as `npm pack` does.',
12
+ fn: 'integrationPackCheck',
13
+ examples: [
14
+ {label: 'Check before publishing', cli: 'astryx integration verify'},
15
+ {label: 'Machine-readable result', cli: 'astryx integration verify --json'},
16
+ ],
17
+ exitCodes: [
18
+ {code: 0, when: 'the packed package exposes the same valid contributions'},
19
+ {code: 1, when: 'the tarball is incomplete or invalid'},
20
+ ],
21
+ related: ['integration add', 'doctor integration validate'],
22
+ };
@@ -8,16 +8,16 @@ export const doc = {
8
8
  namespace: 'cli/commands',
9
9
  summary: 'Author and verify an Astryx integration package',
10
10
  description:
11
- 'Add contributions that are valid on arrival, then prove the packed package exposes the same contributions a consumer will receive.',
12
- subcommands: ['add', 'pack'],
11
+ 'Add contributions to your package, then check the packed package the way an app receives it. The guides start at {@link namespace:integrations}.',
12
+ subcommands: ['add', 'verify', 'pack'],
13
13
  examples: [
14
14
  {
15
15
  label: 'Add a component',
16
16
  cli: 'astryx integration add component AcmeWidget',
17
17
  },
18
18
  {
19
- label: 'Check the package tarball',
20
- cli: 'astryx integration pack --check',
19
+ label: 'Check the package before publishing',
20
+ cli: 'astryx integration verify',
21
21
  },
22
22
  ],
23
23
  exitCodes: [
@@ -12,6 +12,7 @@ import {cliError} from '../lib/cli-error.mjs';
12
12
  import {defineCommand} from '../lib/define-command.mjs';
13
13
  import {doc as integrationGroup} from './integration.doc.mjs';
14
14
  import {doc as integrationAddCommand} from './integration-add.doc.mjs';
15
+ import {doc as integrationVerifyCommand} from './integration-verify.doc.mjs';
15
16
  import {doc as integrationPackCommand} from './integration-pack.doc.mjs';
16
17
  import {doc as integrationAddFn} from '../../../api/integration/integrationAdd.doc.mjs';
17
18
  import {doc as integrationPackCheckFn} from '../../../api/integration/integrationPackCheck.doc.mjs';
@@ -24,8 +25,16 @@ import {doc as integrationPackCheckFn} from '../../../api/integration/integratio
24
25
  */
25
26
  function showGroupOrUnknown(command, label, options, invoked) {
26
27
  const extras = invoked?.args ?? [];
27
- if (extras.length > 0) {
28
- return cliError(`unknown subcommand '${label} ${String(extras[0])}'`, {
28
+ // allowUnknownOption keeps an unknown flag among the args: a word there is
29
+ // an unknown subcommand, and a flag alone is an unknown option.
30
+ const word = extras.find(arg => !String(arg).startsWith('-'));
31
+ if (word == null && extras.length > 0) {
32
+ return cliError(`unknown option '${String(extras[0])}'`, {
33
+ code: ERROR_CODES.ERR_INVALID_OPTION,
34
+ });
35
+ }
36
+ if (word != null) {
37
+ return cliError(`unknown subcommand '${label} ${String(word)}'`, {
29
38
  suggestions: (command.commands ?? []).map(child => ({
30
39
  name: child.name(),
31
40
  reason: 'available subcommand',
@@ -37,6 +46,48 @@ function showGroupOrUnknown(command, label, options, invoked) {
37
46
  return NO_RESULT_SET;
38
47
  }
39
48
 
49
+ /**
50
+ * Run `integration verify` and print its result, as text or JSON.
51
+ * @param {import('commander').Command} program
52
+ */
53
+ async function verifyPackage(program) {
54
+ const result = await integrationPackCheck({cwd: process.cwd()});
55
+ if (program.opts().json) {
56
+ jsonOut(result);
57
+ } else {
58
+ const {name, version, packable, tarball, inventory, issues} = result.data;
59
+ const identity = [name, version].filter(Boolean).join('@');
60
+ const blocks = [
61
+ section(
62
+ packable
63
+ ? 'Integration package ready'
64
+ : 'Integration package check failed',
65
+ ),
66
+ text(`${packable ? '[ok]' : '[fail]'} ${identity || 'local package'}`),
67
+ ];
68
+ if (tarball != null) {
69
+ blocks.push(
70
+ text(
71
+ `${tarball.fileCount} packed files; ${inventory.packedFiles}/${inventory.expectedFiles} required files present.`,
72
+ ),
73
+ );
74
+ }
75
+ if (issues.length > 0) {
76
+ blocks.push(
77
+ list(
78
+ issues.map(
79
+ issue =>
80
+ `[${issue.severity === 'error' ? 'fail' : 'warn'}] ${issue.message}`,
81
+ ),
82
+ ),
83
+ );
84
+ }
85
+ emit(...blocks);
86
+ }
87
+ if (!result.data.packable) process.exitCode = 1;
88
+ return NO_RESULT_SET;
89
+ }
90
+
40
91
  /** @param {import('commander').Command} program */
41
92
  export function registerIntegration(program) {
42
93
  /** @type {import('commander').Command} */
@@ -45,6 +96,10 @@ export function registerIntegration(program) {
45
96
  action: (options, command) =>
46
97
  showGroupOrUnknown(integration, 'integration', options, command),
47
98
  });
99
+ // An unknown subcommand given with a flag reports the unknown subcommand
100
+ // and lists the ones the group has, not the unknown option. Each subcommand
101
+ // still parses its own options.
102
+ integration.allowUnknownOption(true);
48
103
 
49
104
  defineCommand(integration, integrationAddCommand, {
50
105
  fn: integrationAddFn,
@@ -102,53 +157,29 @@ export function registerIntegration(program) {
102
157
  },
103
158
  });
104
159
 
160
+ defineCommand(integration, integrationVerifyCommand, {
161
+ fn: integrationPackCheckFn,
162
+ action: async () => verifyPackage(program),
163
+ });
164
+ // The name this check had before `integration verify`. It stays as a
165
+ // deprecated alias, listed as one in help, so scripts that call it keep
166
+ // working; it runs the same check with the same output and exit codes.
105
167
  defineCommand(integration, integrationPackCommand, {
106
168
  fn: integrationPackCheckFn,
107
169
  action: async options => {
108
170
  if (!options.check) {
109
- return cliError('Pass --check to verify the integration tarball.', {
110
- code: ERROR_CODES.ERR_INVALID_ARGUMENT,
111
- });
171
+ return cliError(
172
+ 'Pass --check to verify the integration tarball, or run `astryx integration verify`.',
173
+ {code: ERROR_CODES.ERR_INVALID_ARGUMENT},
174
+ );
112
175
  }
113
-
114
- const result = await integrationPackCheck({cwd: process.cwd()});
115
- if (program.opts().json) {
116
- jsonOut(result);
117
- } else {
118
- const {name, version, packable, tarball, inventory, issues} =
119
- result.data;
120
- const identity = [name, version].filter(Boolean).join('@');
121
- const blocks = [
122
- section(
123
- packable
124
- ? 'Integration package ready'
125
- : 'Integration package check failed',
126
- ),
127
- text(
128
- `${packable ? '[ok]' : '[fail]'} ${identity || 'local package'}`,
129
- ),
130
- ];
131
- if (tarball != null) {
132
- blocks.push(
133
- text(
134
- `${tarball.fileCount} packed files; ${inventory.packedFiles}/${inventory.expectedFiles} required files present.`,
135
- ),
136
- );
137
- }
138
- if (issues.length > 0) {
139
- blocks.push(
140
- list(
141
- issues.map(
142
- issue =>
143
- `[${issue.severity === 'error' ? 'fail' : 'warn'}] ${issue.message}`,
144
- ),
145
- ),
146
- );
147
- }
148
- emit(...blocks);
176
+ // stderr, and only in text: JSON callers get the same envelope as verify.
177
+ if (!program.opts().json) {
178
+ console.error(
179
+ 'Note: `integration pack --check` is deprecated. Run `astryx integration verify`: it runs the same check.',
180
+ );
149
181
  }
150
- if (!result.data.packable) process.exitCode = 1;
151
- return NO_RESULT_SET;
182
+ return verifyPackage(program);
152
183
  },
153
184
  });
154
185
  }
@@ -20,7 +20,7 @@ export const doc = {
20
20
  'tooling to introspect. Intended to be run with --json.',
21
21
  examples: [
22
22
  {label: 'Full manifest', cli: 'astryx manifest --json'},
23
- {label: 'Shorthand', cli: 'astryx --json'},
23
+ {label: 'The same manifest, under data.manifest (type "help")', cli: 'astryx --json'},
24
24
  ],
25
25
  exitCodes: [
26
26
  {code: 0, when: 'success'},
@@ -16,9 +16,12 @@ export const doc = {
16
16
  summary: 'Search components, hooks, docs, and templates in one ranked list',
17
17
  description:
18
18
  'Terminal front-end to search(): prints one ranked, greppable list across ' +
19
- 'every content domain, each row carrying a follow-up command to act on it.',
19
+ 'every content domain, each row carrying a follow-up command to act on it. ' +
20
+ 'Outside an app, where @astryxdesign/core is not installed, it searches the docs.',
20
21
  fn: 'search',
21
- args: [{name: 'query', param: 'query', required: true}],
22
+ // Every word after `search` is the query: `astryx search dark mode` searches
23
+ // for "dark mode", with no quotes needed.
24
+ args: [{name: 'query', param: 'query', required: true, variadic: true}],
22
25
  options: [
23
26
  {
24
27
  flag: '--type <domain>',
@@ -38,6 +41,10 @@ export const doc = {
38
41
  ],
39
42
  examples: [
40
43
  {label: 'Ranked results', cli: 'astryx search button'},
44
+ {
45
+ label: 'Several words, no quotes',
46
+ cli: 'astryx search dark mode --type doc',
47
+ },
41
48
  {
42
49
  label: 'Filter + JSON',
43
50
  cli: 'astryx search "data table" --type template --json',
@@ -47,7 +54,7 @@ export const doc = {
47
54
  {code: 0, when: 'success (including zero matches)'},
48
55
  {
49
56
  code: 1,
50
- when: 'invalid --type, a --limit that is not a positive integer, or @astryxdesign/core cannot be found',
57
+ when: 'invalid --type, a --limit that is not a positive integer, or --type component, hook, or template where @astryxdesign/core cannot be found',
51
58
  },
52
59
  ],
53
60
  related: ['component', 'hook', 'docs', 'template', 'build'],
@@ -14,6 +14,7 @@
14
14
  *
15
15
  * Usage:
16
16
  * astryx search button Ranked results across all domains
17
+ * astryx search dark mode Every word is part of the query
17
18
  * astryx search modal --type component Filter to a single domain
18
19
  * astryx search forms --limit 5 Cap the result count
19
20
  * astryx search button --verbose Also print score / reason
@@ -31,6 +32,7 @@ import {cliError} from '../lib/cli-error.mjs';
31
32
  import {defineCommand} from '../lib/define-command.mjs';
32
33
  import {search as searchApi} from '../../../api/search/search.mjs';
33
34
  import {Project} from '../../../foundation/config/project.mjs';
35
+ import {findCoreDir} from '../../../foundation/fs/paths.mjs';
34
36
  import {warnOnIntegrationIssues} from '../../../foundation/integrations/integration-warnings.mjs';
35
37
  import {doc as searchCommand} from './search.doc.mjs';
36
38
  import {doc as searchFn} from '../../../api/search/search.doc.mjs';
@@ -42,10 +44,13 @@ export function registerSearch(program) {
42
44
  defineCommand(program, searchCommand, {
43
45
  fn: searchFn,
44
46
  action: async (
45
- /** @type {string} */ query,
47
+ /** @type {string[] | string} */ words,
46
48
  /** @type {{type?: import('../../../api/search/search.type.mjs').SearchDomain, limit?: string, verbose?: boolean}} */ options,
47
49
  ) => {
48
50
  const json = program.opts().json || false;
51
+ // The query is variadic: `astryx search dark mode` is one query, "dark
52
+ // mode". Taking only the first word dropped the rest without a word.
53
+ const query = Array.isArray(words) ? words.join(' ') : words;
49
54
 
50
55
  try {
51
56
  const project = await Project.load(process.cwd());
@@ -99,12 +104,25 @@ export function registerSearch(program) {
99
104
  // ── Text output ──────────────────────────────────────────────
100
105
  const run = getCliInvocation();
101
106
  const {query: q, matchCount, results} = result.data;
107
+ // Outside an app an open search covers the docs alone. Say so, so a
108
+ // docs-only list does not read as "Astryx has no such component".
109
+ const note =
110
+ !options.type && !findCoreDir(process.cwd())
111
+ ? [
112
+ text(
113
+ '@astryxdesign/core is not installed here, so only the docs were searched.',
114
+ ),
115
+ ]
116
+ : [];
102
117
 
103
118
  // No matches is a valid, successful outcome — clean message, exit 0.
104
119
  if (results.length === 0) {
105
120
  emit(
106
121
  text(`No results for "${q}".`),
107
- text(`Try a broader term, or browse: ${run} component --list`),
122
+ ...note,
123
+ text(
124
+ `Try a broader term, or browse: ${run} ${note.length > 0 ? 'docs' : 'component --list'}`,
125
+ ),
108
126
  );
109
127
  return answered;
110
128
  }
@@ -155,6 +173,7 @@ export function registerSearch(program) {
155
173
  fields,
156
174
  format: {command: formatCliCommand, parent: formatCliCommand},
157
175
  }),
176
+ ...note,
158
177
  );
159
178
  return answered;
160
179
  },
@@ -191,6 +191,18 @@ describe('search CLI — exit codes + JSON contract', () => {
191
191
  expect(r.stdout).toContain('No results');
192
192
  });
193
193
 
194
+ it('takes every word after `search` as one query', async () => {
195
+ // Commander took only the first word, so `search dark mode` searched for
196
+ // "dark" and dropped "mode" without a word.
197
+ const json = await runCli(['--json', 'search', 'dark', 'mode', '--type', 'doc'], REPO_ROOT);
198
+ expect(json.status).toBe(0);
199
+ const env = JSON.parse(json.stdout);
200
+ expect(env.data.query).toBe('dark mode');
201
+ expect(env.data.results[0]).toMatchObject({name: 'theme', section: 'light-dark-mode'});
202
+ const text = await runCli(['search', 'dark', 'mode', '--type', 'doc'], REPO_ROOT);
203
+ expect(text.stdout).toContain('Results for "dark mode"');
204
+ }, SCAN_TIMEOUT);
205
+
194
206
  it('exits 1 for an invalid --type', async () => {
195
207
  const r = await runCli(['search', 'x', '--type', 'bogus'], REPO_ROOT);
196
208
  expect(r.status).toBe(1);
@@ -299,14 +311,19 @@ describe('search CLI — exit codes + JSON contract', () => {
299
311
  expect(r.stdout).toContain('reason:');
300
312
  });
301
313
 
302
- it('exits 1 with ERR_CORE_NOT_FOUND when no @astryxdesign/core is reachable', async () => {
314
+ it('searches the docs when no @astryxdesign/core is reachable, and exits 1 for --type component', async () => {
303
315
  const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-search-cli-no-core-'));
304
316
  try {
305
- const json = await runCli(['--json', 'search', 'button'], empty);
317
+ const open = await runCli(['--json', 'search', 'make', 'an', 'integration'], empty);
318
+ expect(open.status).toBe(0);
319
+ expect(JSON.parse(open.stdout).data.results[0]).toMatchObject({domain: 'doc'});
320
+ // The text says the search covered the docs alone.
321
+ const text = await runCli(['search', 'button'], empty);
322
+ expect(text.status).toBe(0);
323
+ expect(text.stdout).toContain('only the docs were searched');
324
+ const json = await runCli(['--json', 'search', 'button', '--type', 'component'], empty);
306
325
  expect(json.status).toBe(1);
307
326
  expect(JSON.parse(json.stdout)).toMatchObject({code: 'ERR_CORE_NOT_FOUND'});
308
- const text = await runCli(['search', 'button'], empty);
309
- expect(text.status).toBe(1);
310
327
  } finally {
311
328
  fs.rmSync(empty, {recursive: true, force: true});
312
329
  }
@@ -46,7 +46,7 @@ export const doc = {
46
46
  ],
47
47
  examples: [
48
48
  {label: 'List swizzlable components', cli: 'astryx swizzle --list'},
49
- {label: 'Eject a component', cli: 'astryx swizzle XDSButton'},
49
+ {label: 'Eject a component', cli: 'astryx swizzle Button'},
50
50
  ],
51
51
  exitCodes: [
52
52
  {code: 0, when: 'success'},
@@ -14,7 +14,7 @@ export const doc = {
14
14
  name: 'template',
15
15
  displayName: 'astryx template',
16
16
  namespace: 'cli/commands',
17
- summary: 'Inject a page or block template',
17
+ summary: 'List, show, or scaffold page and block templates',
18
18
  description:
19
19
  'One entry point for the template family: with no name it lists the discovered ' +
20
20
  'templates; with a name it shows the source or a layout skeleton, or scaffolds it ' +
@@ -372,9 +372,15 @@ const CASES = [
372
372
  skipFieldChecks: true,
373
373
  },
374
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`.
375
382
  name: 'integration pack',
376
383
  args: ['integration', 'pack', '--check'],
377
- // Needs a packable project; pack itself may exit differently.
378
384
  skipFieldChecks: true,
379
385
  },
380
386
  // ── Layout command: remove these cases when the layout command is deleted ──
@@ -41,7 +41,7 @@ export const doc = {
41
41
  examples: [
42
42
  {label: 'Scaffold a theme', cli: 'astryx theme add matcha'},
43
43
  {
44
- label: 'Select an integration theme',
44
+ label: 'Pick the owner when two packages ship the same slug',
45
45
  cli: 'astryx theme add ocean --package @acme/themes',
46
46
  },
47
47
  ],