@astryxdesign/cli 0.6.4-canary.9143f03 → 0.6.4-canary.9cc70a9

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 (58) hide show
  1. package/README.md +6 -10
  2. package/api/index.d.mts +0 -2
  3. package/api/index.mjs +0 -2
  4. package/api/json/index.ts +0 -1
  5. package/api/template/template-integration.test.mjs +1 -65
  6. package/api/template/template.mjs +1 -1
  7. package/api/upgrade/run/run.mjs +1 -1
  8. package/authoring/config/config.doc.mjs +1 -1
  9. package/authoring/config/type.ts +2 -2
  10. package/authoring/doctypes/command/command.doc.mjs +1 -1
  11. package/authoring/doctypes/command/type.ts +1 -1
  12. package/clients/cli/command-result-coverage.test.mjs +7 -7
  13. package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
  14. package/clients/cli/commands/text-json-parity.test.mjs +0 -17
  15. package/clients/cli/index.mjs +0 -4
  16. package/clients/cli/lib/exit-codes.test.mjs +1 -8
  17. package/clients/cli/lib/json-shim.test.mjs +6 -20
  18. package/clients/cli/lib/manifest.mjs +0 -8
  19. package/foundation/discovery/template-adapter.mjs +1 -1
  20. package/foundation/doc-compiler/doc-loads.test.mjs +0 -12
  21. package/foundation/response/response-types.doc.mjs +0 -17
  22. package/foundation/xle/browser.d.mts +3 -3
  23. package/foundation/xle/browser.mjs +3 -3
  24. package/foundation/xle/expand.mjs +2 -2
  25. package/foundation/xle/parse.mjs +1 -1
  26. package/foundation/xle/print.mjs +2 -2
  27. package/foundation/xle/splice.mjs +1 -1
  28. package/package.json +9 -9
  29. package/api/layout/_adapter.d.mts +0 -34
  30. package/api/layout/_adapter.mjs +0 -148
  31. package/api/layout/check/check.d.mts +0 -16
  32. package/api/layout/check/check.mjs +0 -40
  33. package/api/layout/expand/expand.d.mts +0 -22
  34. package/api/layout/expand/expand.mjs +0 -155
  35. package/api/layout/expand/expand.path-safety.test.mjs +0 -53
  36. package/api/layout/grammar/grammar.d.mts +0 -13
  37. package/api/layout/grammar/grammar.mjs +0 -87
  38. package/api/layout/layout.d.mts +0 -6
  39. package/api/layout/layout.mjs +0 -17
  40. package/api/layout/layout.test.mjs +0 -297
  41. package/api/layout/layout.type.d.mts +0 -89
  42. package/api/layout/layout.type.mjs +0 -103
  43. package/api/layout/layoutCheck.doc.d.mts +0 -11
  44. package/api/layout/layoutCheck.doc.mjs +0 -85
  45. package/api/layout/layoutExpand.doc.d.mts +0 -11
  46. package/api/layout/layoutExpand.doc.mjs +0 -107
  47. package/api/layout/layoutGrammar.doc.d.mts +0 -11
  48. package/api/layout/layoutGrammar.doc.mjs +0 -57
  49. package/clients/cli/commands/layout-check.doc.mjs +0 -65
  50. package/clients/cli/commands/layout-expand.doc.mjs +0 -83
  51. package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
  52. package/clients/cli/commands/layout.doc.mjs +0 -34
  53. package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
  54. package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
  55. package/clients/cli/commands/layout.mjs +0 -275
  56. package/clients/cli/commands/layout.path-help.test.mjs +0 -33
  57. package/clients/cli/commands/layout.stdin-cap.test.mjs +0 -47
  58. package/clients/cli/commands/layout.text-fields.test.mjs +0 -39
package/README.md CHANGED
@@ -89,7 +89,6 @@ Options:
89
89
  | `hook` | List hooks or print hook docs |
90
90
  | `init` | Initialize the design system in your project |
91
91
  | `integration` | Author and verify an Astryx integration package |
92
- | `layout` | Generate XDS layouts from compressed expressions (XLE/XLO) |
93
92
  | `search` | Search components, hooks, docs, and templates in one ranked list |
94
93
  | `swizzle` | Copy component source for customization |
95
94
  | `template` | Inject a page or block template |
@@ -475,9 +474,6 @@ Every response has a `type` discriminant. The full set is below (generated from
475
474
  | `integration.template-conflicts` | The integration identity, structural issues, and non-blocking Core template-id conflicts as {id, severity: warning, integrationPackage, integrationType, integrationName, coreMatches, message, command}. |
476
475
  | `integration.component-conflicts` | The integration identity, structural issues, and non-blocking conflicts where an integration component name is also owned by Core; each conflict includes the exact package-qualified command. |
477
476
  | `integration.doc-conflicts` | The integration identity, structural issues, and Core doc overlaps. Each finding includes `severity` (`info` \| `error`) and `relationship` (`replaces` \| `extends` \| `accidental`). |
478
- | `layout.expand` | The expansion: parsed form, generated TSX code, componentsUsed, states (count of useState hooks scaffolded), todos, blocksReferenced (each {name, mode}), warnings, and written (the output path, or null when nothing was written). |
479
- | `layout.check` | The validation result: a valid flag, the detected form, errors (each with line/col, message, formatted text, and suggestions), warnings, and the expression re-printed in both canonical surfaces (compact and outline). |
480
- | `layout.grammar` | The XLE/XLO grammar cheatsheet: a text field with the full reference plus an aliases map (short name → canonical component) generated from this install's registry. |
481
477
 
482
478
  <!-- END GENERATED: response-types -->
483
479
  <!-- Generated by scripts/generate-cli-readme.mjs from the response-types EnumDoc. Run `pnpm -F @astryxdesign/cli readme`. -->
@@ -578,12 +574,12 @@ There is no factory: write a plain object. For editor autocomplete and
578
574
  type-checking, annotate it with the `AstryxConfig` type exported from
579
575
  `@astryxdesign/cli/authoring`.
580
576
 
581
- | Field | Type | Purpose |
582
- | ----------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- |
583
- | `integrations` | `string[]` | Integration package names to load (see [Integrations](#integrations)). |
584
- | `issuesUrl` | `string` | Where "report an issue" links point for your project. Defaults to the core issue tracker. |
585
- | `hooks.postCodemod` | `PostCodemodHook[]` | Commands to run after `astryx upgrade` applies codemods (e.g. reinstall, rebuild, reformat). |
586
- | `experimental.xle.components` | `Record<string, XleComponent>` | Register app-local components so layout (XLE) expressions can reference them by name. Unstable. |
577
+ | Field | Type | Purpose |
578
+ | ----------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
579
+ | `integrations` | `string[]` | Integration package names to load (see [Integrations](#integrations)). |
580
+ | `issuesUrl` | `string` | Where "report an issue" links point for your project. Defaults to the core issue tracker. |
581
+ | `hooks.postCodemod` | `PostCodemodHook[]` | Commands to run after `astryx upgrade` applies codemods (e.g. reinstall, rebuild, reformat). |
582
+ | `experimental.xle.components` | `Record<string, XleComponent>` | No effect. Its only reader was the removed `layout` command. Still accepted so existing configs keep loading; delete it. |
587
583
 
588
584
  The config is validated against a strict schema when the CLI loads it, so an
589
585
  unknown field is a hard error rather than a silent no-op. `astryx doctor`
package/api/index.d.mts CHANGED
@@ -33,14 +33,12 @@ 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";
37
36
  export * from "./integration/integration-authoring.type.mjs";
38
37
  export * from "./integration/pack-check.type.mjs";
39
38
  export * from "./integration/validate-integration.type.mjs";
40
39
  export * from "./integration/authoring-checks.type.mjs";
41
40
  export type Logger = import("./logger.mjs").Logger;
42
41
  export { themeBuild, themeAdd, themeTemplate, themeList, themeListAvailable, themeTargets, themePaletteGenerate, generateTonalPalette, listThemes } from "./theme/theme.mjs";
43
- export { layoutExpand, layoutCheck, layoutGrammar } from "./layout/layout.mjs";
44
42
  export { integrationAdd, integrationAddAgentDoc, integrationAddCodemod, integrationAddComponent, integrationAddDoc, integrationAddTemplate } from "./integration/add-contribution.mjs";
45
43
  export { validateIntegration, summarizeIssues } from "./integration/validate-integration.mjs";
46
44
  export { integrationTemplateConflicts, integrationComponentConflicts, integrationDocConflicts } from "./integration/authoring-checks.mjs";
package/api/index.mjs CHANGED
@@ -44,7 +44,6 @@ 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';
48
47
  export {
49
48
  integrationAdd,
50
49
  integrationAddAgentDoc,
@@ -93,7 +92,6 @@ export * from './gap-report/gap-report.type.mjs';
93
92
  export * from './upgrade/upgrade.type.mjs';
94
93
  export * from './init/init.type.mjs';
95
94
  export * from './doctor/doctor.type.mjs';
96
- export * from './layout/layout.type.mjs';
97
95
  export * from './integration/integration-authoring.type.mjs';
98
96
  export * from './integration/pack-check.type.mjs';
99
97
  export * from './integration/validate-integration.type.mjs';
package/api/json/index.ts CHANGED
@@ -26,7 +26,6 @@ export type * from '../gap-report/gap-report.type.mjs';
26
26
  export type * from '../upgrade/upgrade.type.mjs';
27
27
  export type * from '../init/init.type.mjs';
28
28
  export type * from '../doctor/doctor.type.mjs';
29
- export type * from '../layout/layout.type.mjs';
30
29
  export type * from '../integration/validate-integration.type.mjs';
31
30
  export type * from '../integration/authoring-checks.type.mjs';
32
31
  export type * from '../integration/pack-check.type.mjs';
@@ -19,7 +19,6 @@ import {
19
19
  } from './template.mjs';
20
20
  import {search} from '../search/search.mjs';
21
21
  import {build} from '../build/build.mjs';
22
- import {layoutExpand} from '../layout/layout.mjs';
23
22
  import {runCli} from '../../test-utils/run-cli.mjs';
24
23
 
25
24
  let tmpDir;
@@ -518,53 +517,7 @@ describe('integration template discovery', () => {
518
517
  });
519
518
  });
520
519
 
521
- it('resolves a replacement block through the layout alias', async () => {
522
- const pkgDir = installWidgets(tmpDir);
523
- writeTemplate(pkgDir, 'acme-card-callout', {
524
- kind: 'block',
525
- source:
526
- 'export default function AcmeCardCallout() { return <span>Acme replacement block</span>; }\n',
527
- });
528
- declareReplaces(pkgDir, {
529
- 'acme-card-callout': 'CardCallout',
530
- });
531
-
532
- const accidental = path.join(tmpDir, 'node_modules', '@acme', 'extra');
533
- fs.mkdirSync(path.join(accidental, 'templates'), {recursive: true});
534
- fs.writeFileSync(
535
- path.join(accidental, 'package.json'),
536
- JSON.stringify({name: '@acme/extra', version: '1.0.0'}),
537
- );
538
- fs.writeFileSync(
539
- path.join(accidental, 'astryx.integration.mjs'),
540
- `export default {templates: './templates'};\n`,
541
- );
542
- writeTemplate(accidental, 'CardCallout', {
543
- kind: 'block',
544
- body: `export default {type: 'block', name: 'ZZZ accidental block', description: 'collision'};\n`,
545
- source:
546
- 'export default function Accidental() { return <span>Accidental block</span>; }\n',
547
- });
548
- fs.writeFileSync(
549
- path.join(tmpDir, 'astryx.config.mjs'),
550
- `export default { integrations: ['@acme/widgets', '@acme/extra'] };\n`,
551
- );
552
-
553
- const result = await layoutExpand('C{card-callout}', {
554
- name: 'ReplacementLayout',
555
- cwd: tmpDir,
556
- });
557
-
558
- expect(result.data.code).toContain('Acme replacement block');
559
- expect(result.data.code).not.toContain('Accidental block');
560
- expect(result.data.blocksReferenced).toEqual(
561
- expect.arrayContaining([
562
- expect.objectContaining({name: 'CardCallout', mode: 'splice'}),
563
- ]),
564
- );
565
- }, 30_000);
566
-
567
- it('resolves chained block aliases consistently in template and layout', async () => {
520
+ it('resolves chained block aliases consistently in template', async () => {
568
521
  const [firstTarget, secondTarget] = (await discoverCoreTemplates()).filter(
569
522
  candidate => candidate.type === 'block',
570
523
  );
@@ -592,29 +545,12 @@ describe('integration template discovery', () => {
592
545
  cwd: tmpDir,
593
546
  });
594
547
  expect(firstTemplate.data.source).toContain('First chain replacement');
595
- const layoutId = id =>
596
- id.replace(/([a-z0-9])([A-Z])/gu, '$1-$2').toLowerCase();
597
- const firstLayout = await layoutExpand(
598
- `C{${layoutId(firstTarget.dirName)}}`,
599
- {
600
- cwd: tmpDir,
601
- },
602
- );
603
- expect(firstLayout.data.code).toContain('First chain replacement');
604
- expect(firstLayout.data.code).not.toContain('Final chain replacement');
605
548
 
606
549
  const secondTemplate = await template(secondTarget.dirName, {
607
550
  show: true,
608
551
  cwd: tmpDir,
609
552
  });
610
553
  expect(secondTemplate.data.source).toContain('Final chain replacement');
611
- const secondLayout = await layoutExpand(
612
- `C{${layoutId(secondTarget.dirName)}}`,
613
- {
614
- cwd: tmpDir,
615
- },
616
- );
617
- expect(secondLayout.data.code).toContain('Final chain replacement');
618
554
  }, 30_000);
619
555
 
620
556
  it('keeps the old discovery behavior when no replacement is declared', async () => {
@@ -8,7 +8,7 @@
8
8
  * the requested one, and routes to a leaf (list/show/skeleton/copy/cdn). The shared
9
9
  * discovery/IO + cross-command helpers live in `foundation/discovery/template-adapter.mjs` and are
10
10
  * RE-EXPORTED here so external import paths (`api/template/template.mjs`) —
11
- * used by component, layout, search, init, discover, Doctor integration, and
11
+ * used by component, search, init, discover, Doctor integration, and
12
12
  * lib/project — keep resolving unchanged.
13
13
  *
14
14
  * @position api/template — the template dispatcher + barrel; leaves live under
@@ -114,7 +114,7 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
114
114
  // Resolve the source dir against the API's cwd (not process.cwd()) so a
115
115
  // programmatic caller in another directory scans the right tree. Confine it to
116
116
  // cwd: --apply rewrites files in place, so a `..`-escaping or out-of-tree
117
- // absolute --path must be rejected (parity with template/theme/swizzle/layout,
117
+ // absolute --path must be rejected (parity with template/theme/swizzle,
118
118
  // and this is the most destructive command). allowAbsolute permits an absolute
119
119
  // path that still resolves inside cwd.
120
120
  let path_;
@@ -77,7 +77,7 @@ export const doc = {
77
77
  name: 'experimental.xle.components',
78
78
  type: 'Record<string, XleComponent>',
79
79
  description:
80
- 'Custom components the layout expander (XLE) may emit, keyed by tag.',
80
+ 'No effect. Its only reader was the removed `layout` command. The key is still accepted so existing configs keep loading; delete it.',
81
81
  },
82
82
  ],
83
83
  },
@@ -115,8 +115,8 @@ export interface AstryxConfig {
115
115
  /** Experimental XLE (layout expression) configuration. */
116
116
  xle?: {
117
117
  /**
118
- * Register app-local components so XLE layout expressions can
119
- * reference them by name via {hint}. Keyed by component name.
118
+ * No effect. Its only reader was the removed `layout` command. Still
119
+ * accepted so existing configs keep loading; delete it.
120
120
  */
121
121
  components?: Record<string, XleComponent>;
122
122
  };
@@ -151,7 +151,7 @@ export const doc = {
151
151
  name: 'subcommands',
152
152
  type: 'string[]',
153
153
  description:
154
- 'Subcommand names (for command groups like `theme` / `layout`).',
154
+ 'Subcommand names (for command groups like `theme`).',
155
155
  },
156
156
  {
157
157
  name: 'examples',
@@ -75,7 +75,7 @@ export interface CommandDoc extends AuthoredDocGraphFields {
75
75
  args?: CommandArgDoc[];
76
76
  /** Flags/options. */
77
77
  options?: CommandOptionDoc[];
78
- /** Subcommand names (for command groups like `theme` / `layout`). */
78
+ /** Subcommand names (for command groups like `theme`). */
79
79
  subcommands?: string[];
80
80
  /** Terminal examples. */
81
81
  examples?: CommandExampleDoc[];
@@ -29,17 +29,17 @@ import {program} from './index.mjs';
29
29
  import {reportsResult, reportsResultVia} from './lib/define-command.mjs';
30
30
 
31
31
  /**
32
- * Commands with no action of their own: bare `astryx layout` prints its
33
- * subcommand list and does nothing else, so there is no run to report on.
32
+ * Commands with no action of their own: a group that prints its subcommand
33
+ * list and does nothing else has no run to report on.
34
34
  *
35
35
  * Pinned as a SET rather than skipped silently — if a command joins this list,
36
36
  * that is a real change to what the CLI does and it should be read, not
37
- * absorbed. (`theme` is deliberately NOT here: it HAS an action — the one that
38
- * rejects an unknown subcommand — so it goes through the converter like any
39
- * other. Its bare form prints help and never returns from that action, which
40
- * the recorder covers where help is recorded, not here.)
37
+ * absorbed. Every group ships an action today: `theme`, for instance, HAS one
38
+ * — the one that rejects an unknown subcommand — so it goes through the
39
+ * converter like any other. Its bare form prints help and never returns from
40
+ * that action, which the recorder covers where help is recorded, not here.
41
41
  */
42
- const NO_ACTION_OF_THEIR_OWN = ['layout'];
42
+ const NO_ACTION_OF_THEIR_OWN = [];
43
43
 
44
44
  /**
45
45
  * Commands that record for themselves instead of returning a descriptor.
@@ -179,9 +179,9 @@ describe('DebugEvent result summary', () => {
179
179
  it(
180
180
  'says so explicitly when a command has no result set',
181
181
  async () => {
182
- // `layout check` returns a verdict on one expression: nothing was looked
182
+ // Bare `integration` prints its subcommand list: nothing was looked
183
183
  // up, and the run says that rather than leaving four ambiguous nulls.
184
- const {event} = await runWithDebug(['layout', 'check', 'VStack>Text']);
184
+ const {event} = await runWithDebug(['integration']);
185
185
  expect(event.output).toMatchObject({
186
186
  resultKind: 'none',
187
187
  resultCount: null,
@@ -377,23 +377,6 @@ const CASES = [
377
377
  // Needs a packable project; pack itself may exit differently.
378
378
  skipFieldChecks: true,
379
379
  },
380
- // ── Layout command: remove these cases when the layout command is deleted ──
381
- {
382
- name: 'layout check',
383
- args: ['layout', 'check', 'Button'],
384
- skipFieldChecks: true,
385
- },
386
- {
387
- name: 'layout expand',
388
- args: ['layout', 'expand', 'Button'],
389
- skipFieldChecks: true,
390
- },
391
- {
392
- name: 'layout grammar',
393
- args: ['layout', 'grammar'],
394
- skipFieldChecks: true,
395
- },
396
- // ── End layout cases ──
397
380
  {
398
381
  name: 'manifest',
399
382
  args: ['manifest'],
@@ -103,9 +103,6 @@ export const JSON_SUPPORTED = new Set([
103
103
  'doctor integration templates',
104
104
  'doctor integration components',
105
105
  'doctor integration docs',
106
- 'layout expand',
107
- 'layout check',
108
- 'layout grammar',
109
106
  ]);
110
107
 
111
108
  /**
@@ -264,7 +261,6 @@ const commands = [
264
261
  {name: 'gap-report', path: './commands/gap-report.mjs', register: 'registerGapReport'},
265
262
  // agent-docs folded into init — functions still importable from agent-docs.mjs
266
263
  {name: 'template', path: './commands/template.mjs', register: 'registerTemplate'},
267
- {name: 'layout', path: './commands/layout.mjs', register: 'registerLayout'},
268
264
  {name: 'upgrade', path: './commands/upgrade.mjs', register: 'registerUpgrade'},
269
265
  {name: 'theme', path: './commands/build-theme.mjs', register: 'registerTheme'},
270
266
  {name: 'integration', path: './commands/integration.mjs', register: 'registerIntegration'},
@@ -34,7 +34,7 @@ manifest.commands.forEach(walk);
34
34
 
35
35
  describe('command exit codes', () => {
36
36
  it('every CommandDoc documents its exit codes', () => {
37
- expect(commandDocs.length).toBeGreaterThan(30);
37
+ expect(commandDocs.length).toBeGreaterThan(25);
38
38
  for (const doc of commandDocs) {
39
39
  expect(doc.exitCodes?.length, doc.name).toBeGreaterThan(0);
40
40
  }
@@ -54,13 +54,6 @@ describe('command exit codes', () => {
54
54
  },
55
55
  );
56
56
 
57
- it('bare `astryx layout` exits 1 in both modes, as documented', async () => {
58
- const doc = commandDocs.find((d) => d.name === 'layout');
59
- expect(doc.exitCodes.find((e) => e.code === 1)?.when).toMatch(/^no subcommand/);
60
- expect((await runCli(['layout'])).status).toBe(1);
61
- expect((await runCli(['layout', '--json'])).status).toBe(1);
62
- });
63
-
64
57
  it('`astryx discover` with a blank query exits 1 only when packages are discovered', async () => {
65
58
  const doc = commandDocs.find((d) => d.name === 'discover');
66
59
  expect(doc.exitCodes.find((e) => e.code === 1)?.when).toMatch(/blank query when packages are discovered/);
@@ -225,23 +225,6 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
225
225
  expect(parsed.error).toMatch(/bogus/);
226
226
  });
227
227
 
228
- it('astryx layout --json (group, no subcommand) emits ERR_MISSING_ARGUMENT, exit 1', async () => {
229
- const {status, stdout, stderr} = await runCli(['layout', '--json']);
230
- expect(status).toBe(1);
231
- expect(stderr).toBe('');
232
- const parsed = parseJson(stdout);
233
- expect(parsed).not.toHaveProperty('type');
234
- expect(parsed.code).toBe('ERR_MISSING_ARGUMENT');
235
- expect(parsed.suggestions.map((s) => s.name)).toContain('layout expand');
236
- });
237
-
238
- it('astryx layout (no --json) still prints help to stderr, exit 1', async () => {
239
- const {status, stdout, stderr} = await runCli(['layout']);
240
- expect(status).toBe(1);
241
- expect(stdout).toBe('');
242
- expect(stderr).toMatch(/Usage: astryx layout/);
243
- });
244
-
245
228
  it('the real binary emits the same envelope for help bogus --json', () => {
246
229
  // One program per process, so the root's own outputHelp patch is used here.
247
230
  const bin = fileURLToPath(new URL('../bin/astryx.mjs', import.meta.url));
@@ -257,6 +240,9 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
257
240
  });
258
241
 
259
242
  it('a group added after install gets the same error envelope', () => {
243
+ // This is the only coverage of the no-subcommand path: every group the CLI
244
+ // ships has an action of its own (see command-result-coverage.test.mjs), so
245
+ // a group without one has to be built here.
260
246
  const program = new Command('astryx');
261
247
  installJsonShim(program);
262
248
  // Added later, so only the prototype-level patch covers its outputHelp.
@@ -282,11 +268,11 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
282
268
  expect(parsed.suggestions).toEqual([{name: 'late child', reason: 'available subcommand'}]);
283
269
  });
284
270
 
285
- it('astryx help layout --json still emits the help envelope, exit 0', async () => {
286
- const {status, stdout} = await runCli(['help', 'layout', '--json']);
271
+ it('astryx help theme --json still emits the help envelope, exit 0', async () => {
272
+ const {status, stdout} = await runCli(['help', 'theme', '--json']);
287
273
  expect(status).toBe(0);
288
274
  const parsed = parseJson(stdout);
289
275
  expect(parsed.type).toBe('help');
290
- expect(parsed.data.command).toBe('astryx layout');
276
+ expect(parsed.data.command).toBe('astryx theme');
291
277
  });
292
278
  });
@@ -100,9 +100,6 @@ export const RESPONSE_TYPES = {
100
100
  'doctor integration templates': ['integration.template-conflicts'],
101
101
  'doctor integration components': ['integration.component-conflicts'],
102
102
  'doctor integration docs': ['integration.doc-conflicts'],
103
- 'layout expand': ['layout.expand'],
104
- 'layout check': ['layout.check'],
105
- 'layout grammar': ['layout.grammar'],
106
103
  };
107
104
 
108
105
  /**
@@ -183,11 +180,6 @@ const EXAMPLES = {
183
180
  'astryx doctor integration docs @acme/widgets --json',
184
181
  ],
185
182
  init: ['astryx init', 'astryx init --all --json'],
186
- 'layout expand': [
187
- `astryx layout expand 'V[g6] > C{card-callout}*4' ./src/Page.tsx`,
188
- ],
189
- 'layout check': [`astryx layout check 'A[cp6] > L > LC > S[p6]' --json`],
190
- 'layout grammar': ['astryx layout grammar'],
191
183
  };
192
184
 
193
185
  /**
@@ -4,7 +4,7 @@
4
4
  * @file Shared template discovery + IO.
5
5
  *
6
6
  * Owns everything the template leaves (list/show/skeleton/copy) AND other
7
- * commands (component, layout, search, init, discover, Doctor integration)
7
+ * commands (component, search, init, discover, Doctor integration)
8
8
  * share: template discovery across core/external/integration sources, the
9
9
  * template-spec loaders, and the cross-command helpers (stripTemplateAssetRefs,
10
10
  * findShowcase, findRelatedBlocks, extractComponents, listTemplates). The
@@ -191,18 +191,6 @@ const RUNNERS = {
191
191
  'import ./integration.doc.mjs',
192
192
  ],
193
193
  },
194
- 'clients/cli/commands/layout.mjs': {
195
- runs: SELF_DOCS,
196
- sites: [
197
- 'import ../../../api/layout/layoutCheck.doc.mjs',
198
- 'import ../../../api/layout/layoutExpand.doc.mjs',
199
- 'import ../../../api/layout/layoutGrammar.doc.mjs',
200
- 'import ./layout-check.doc.mjs',
201
- 'import ./layout-expand.doc.mjs',
202
- 'import ./layout-grammar.doc.mjs',
203
- 'import ./layout.doc.mjs',
204
- ],
205
- },
206
194
  'clients/cli/commands/search.mjs': {
207
195
  runs: SELF_DOCS,
208
196
  sites: [
@@ -318,22 +318,5 @@ export const doc = {
318
318
  description:
319
319
  'The integration identity, structural issues, and Core doc overlaps. Each finding includes `severity` (`info` | `error`) and `relationship` (`replaces` | `extends` | `accidental`).',
320
320
  },
321
-
322
- // layout (XLE/XLO)
323
- {
324
- value: 'layout.expand',
325
- description:
326
- 'The expansion: parsed form, generated TSX code, componentsUsed, states (count of useState hooks scaffolded), todos, blocksReferenced (each {name, mode}), warnings, and written (the output path, or null when nothing was written).',
327
- },
328
- {
329
- value: 'layout.check',
330
- description:
331
- 'The validation result: a valid flag, the detected form, errors (each with line/col, message, formatted text, and suggestions), warnings, and the expression re-printed in both canonical surfaces (compact and outline).',
332
- },
333
- {
334
- value: 'layout.grammar',
335
- description:
336
- "The XLE/XLO grammar cheatsheet: a text field with the full reference plus an aliases map (short name → canonical component) generated from this install's registry.",
337
- },
338
321
  ],
339
322
  };
@@ -2,8 +2,8 @@
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
4
  /**
5
- * Validate an expression and return both canonical surfaces — the browser
6
- * twin of `layout check`. Never throws on invalid input; returns the errors.
5
+ * Validate an expression and return both canonical surfaces. Never throws on
6
+ * invalid input; returns the errors.
7
7
  *
8
8
  * @param {string} expression
9
9
  * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
@@ -19,7 +19,7 @@ export function checkExpression(expression: string, registry: import("./xle-ast"
19
19
  loose?: boolean | undefined;
20
20
  }): import("./browser").CheckResult;
21
21
  /**
22
- * Validate + expand to TSX — the browser twin of `layout expand`.
22
+ * Validate + expand to TSX.
23
23
  * Returns either {code, ...} or {errors} (never writes files).
24
24
  *
25
25
  * @param {string} expression
@@ -44,8 +44,8 @@ function formatIssue(issue) {
44
44
  }
45
45
 
46
46
  /**
47
- * Validate an expression and return both canonical surfaces — the browser
48
- * twin of `layout check`. Never throws on invalid input; returns the errors.
47
+ * Validate an expression and return both canonical surfaces. Never throws on
48
+ * invalid input; returns the errors.
49
49
  *
50
50
  * @param {string} expression
51
51
  * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
@@ -85,7 +85,7 @@ export function checkExpression(expression, registry, opts = {}) {
85
85
  }
86
86
 
87
87
  /**
88
- * Validate + expand to TSX — the browser twin of `layout expand`.
88
+ * Validate + expand to TSX.
89
89
  * Returns either {code, ...} or {errors} (never writes files).
90
90
  *
91
91
  * @param {string} expression
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * @input validated doc (nodes carry .bound) + registry
15
15
  * @output expand() → {code, componentsUsed, states, todos}
16
- * @position lib/xle — last stage; api/layout.mjs orchestrates
16
+ * @position lib/xle — last stage; the browser barrel orchestrates
17
17
  */
18
18
 
19
19
  import {PAYLOAD_PROPS} from './validate.mjs';
@@ -751,7 +751,7 @@ export function expand(doc, registry, options = {}) {
751
751
  : [];
752
752
 
753
753
  const code = [
754
- `// Generated by \`astryx layout expand\` — this file is the artifact; edit freely.`,
754
+ `// Generated by the Astryx XLE expander — this file is the artifact; edit freely.`,
755
755
  ...importLines,
756
756
  ...blockSection,
757
757
  '',
@@ -302,7 +302,7 @@ function parseAttrToken(token, line) {
302
302
  * Guard against unbounded recursion in the compact parser. A layout tree this
303
303
  * deep is never hand-authored; without the cap the recursive descent blows the
304
304
  * JS call stack and surfaces a raw RangeError (→ ERR_UNKNOWN, no line/col)
305
- * instead of a located ERR_LAYOUT_PARSE. The counter is module-level so it
305
+ * instead of a located parse error. The counter is module-level so it
306
306
  * spans group / attribute sub-streams; each parse entry point resets it.
307
307
  */
308
308
  const MAX_COMPACT_DEPTH = 512;
@@ -3,8 +3,8 @@
3
3
  /**
4
4
  * @file XLE canonical printers — AST → compact (XLE) or outline (XLO) text.
5
5
  *
6
- * Used by `astryx layout check --form …` so either party (agent or human)
7
- * can request the other surface, and by round-trip conformance tests.
6
+ * Used by `checkExpression` so either party (agent or human) can request the
7
+ * other surface, and by round-trip conformance tests.
8
8
  * Printing is best-effort canonical: spelling variants the lexer
9
9
  * normalized are emitted in canonical form.
10
10
  *
@@ -18,7 +18,7 @@
18
18
  *
19
19
  * @input block TSX source (splice) or a name+importPath (import)
20
20
  * @output prepareSpliceModule / parseImportStatements + import-merge helpers
21
- * @position lib/xle — used by expand.mjs; sources gathered in api/layout.mjs
21
+ * @position lib/xle — used by expand.mjs; sources gathered by the caller
22
22
  */
23
23
 
24
24
  const IMPORT_RE =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.6.4-canary.9143f03",
3
+ "version": "0.6.4-canary.9cc70a9",
4
4
  "displayName": "CLI",
5
5
  "description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
6
6
  "author": "Meta Open Source",
@@ -101,10 +101,10 @@
101
101
  "zod": "^4.4.3"
102
102
  },
103
103
  "peerDependencies": {
104
- "@astryxdesign/charts": "0.6.4-canary.9143f03",
105
- "@astryxdesign/core": "0.6.4-canary.9143f03",
106
- "@astryxdesign/lab": "0.6.4-canary.9143f03",
107
- "@astryxdesign/theme-neutral": "0.6.4-canary.9143f03"
104
+ "@astryxdesign/charts": "0.6.4-canary.9cc70a9",
105
+ "@astryxdesign/core": "0.6.4-canary.9cc70a9",
106
+ "@astryxdesign/lab": "0.6.4-canary.9cc70a9",
107
+ "@astryxdesign/theme-neutral": "0.6.4-canary.9cc70a9"
108
108
  },
109
109
  "peerDependenciesMeta": {
110
110
  "@astryxdesign/charts": {
@@ -121,10 +121,10 @@
121
121
  }
122
122
  },
123
123
  "devDependencies": {
124
- "@astryxdesign/charts": "0.6.4-canary.9143f03",
125
- "@astryxdesign/core": "0.6.4-canary.9143f03",
126
- "@astryxdesign/lab": "0.6.4-canary.9143f03",
127
- "@astryxdesign/theme-neutral": "0.6.4-canary.9143f03",
124
+ "@astryxdesign/charts": "0.6.4-canary.9cc70a9",
125
+ "@astryxdesign/core": "0.6.4-canary.9cc70a9",
126
+ "@astryxdesign/lab": "0.6.4-canary.9cc70a9",
127
+ "@astryxdesign/theme-neutral": "0.6.4-canary.9cc70a9",
128
128
  "@heroicons/react": "^2.2.0",
129
129
  "@stylexjs/stylex": "^0.19.0",
130
130
  "@types/babel__core": "^7.20.5",