@astryxdesign/cli 0.1.7-canary.fb9c68c → 0.1.7

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 (52) hide show
  1. package/README.md +19 -115
  2. package/docs/getting-started.doc.mjs +9 -9
  3. package/docs/integration-authoring.md +105 -0
  4. package/docs/migration.doc.mjs +18 -18
  5. package/docs/principles.doc.dense.mjs +1 -1
  6. package/docs/principles.doc.mjs +6 -6
  7. package/docs/principles.doc.zh.mjs +1 -1
  8. package/docs/styling-libraries.doc.mjs +3 -3
  9. package/docs/styling.doc.mjs +4 -4
  10. package/docs/theme.doc.dense.mjs +2 -2
  11. package/docs/theme.doc.mjs +7 -7
  12. package/docs/theme.doc.zh.mjs +1 -1
  13. package/docs/tokens.doc.mjs +1 -1
  14. package/docs/working-with-ai.doc.mjs +18 -18
  15. package/package.json +10 -11
  16. package/src/api/doctor.mjs +3 -3
  17. package/src/codemods/ensure-jscodeshift.mjs +27 -11
  18. package/src/codemods/run-codemod.mjs +1 -1
  19. package/src/codemods/runner.mjs +2 -2
  20. package/src/commands/agent-docs.mjs +14 -56
  21. package/src/commands/agent-docs.test.mjs +4 -11
  22. package/src/commands/build-theme.mjs +71 -10
  23. package/src/commands/build.mjs +15 -15
  24. package/src/commands/component/index.mjs +4 -4
  25. package/src/commands/discover.mjs +5 -7
  26. package/src/commands/docs.mjs +4 -4
  27. package/src/commands/hook/index.mjs +4 -4
  28. package/src/commands/init.mjs +152 -48
  29. package/src/commands/init.next-steps.test.mjs +1 -1
  30. package/src/commands/interactive-guard.test.mjs +22 -19
  31. package/src/commands/json-contract.test.mjs +1 -1
  32. package/src/commands/layout.mjs +1 -1
  33. package/src/commands/search.mjs +4 -4
  34. package/src/commands/swizzle.mjs +34 -11
  35. package/src/commands/template.mjs +31 -11
  36. package/src/commands/upgrade.mjs +6 -9
  37. package/src/commands/upgrade.test.mjs +1 -1
  38. package/src/index.mjs +6 -40
  39. package/src/lib/component-format.mjs +1 -2
  40. package/src/utils/interactive.mjs +76 -0
  41. package/src/utils/interactive.test.mjs +70 -0
  42. package/src/utils/package-manager.mjs +0 -78
  43. package/src/utils/package-manager.test.mjs +1 -108
  44. package/src/utils/path-safety.mjs +18 -0
  45. package/src/utils/update-check.mjs +1 -2
  46. package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
  47. package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +7 -2
  48. package/docs/cli-integrations.doc.mjs +0 -150
  49. package/scripts/postinstall.mjs +0 -74
  50. package/src/commands/cli-postinstall.test.mjs +0 -42
  51. package/src/commands/setup-nudge.test.mjs +0 -108
  52. package/src/lib/term-log.mjs +0 -48
package/README.md CHANGED
@@ -2,19 +2,15 @@
2
2
 
3
3
  The CLI is the primary interface for working with the design system, for humans and machines alike. It provides component documentation, design tokens, page templates, theming tools, and upgrade codemods, all accessible via terminal commands, a typed JSON API, or programmatic imports. AI agents and build tools use the same API that powers the CLI, enabling end-to-end frontend development loops.
4
4
 
5
- Run it one-off with the scoped package (works whether or not it's installed):
6
-
7
5
  ```bash
8
- npx @astryxdesign/cli --help
9
- npx @astryxdesign/cli search button
10
- npx @astryxdesign/cli component Button
11
- npx @astryxdesign/cli docs tokens
12
- npx @astryxdesign/cli docs migration
13
- npx @astryxdesign/cli template --list
6
+ npx astryx --help
7
+ npx astryx search button
8
+ npx astryx component Button
9
+ npx astryx docs tokens
10
+ npx astryx docs migration
11
+ npx astryx template --list
14
12
  ```
15
13
 
16
- Once it's a project dependency (`npm install -D @astryxdesign/cli`), drop the scope and use the shorter `astryx` — e.g. `npx astryx component Button` or `pnpm exec astryx component Button`. Bare `astryx` resolves to an unrelated npm package until the CLI is installed, so prefer the scoped form above for first-run/one-off use.
17
-
18
14
  ## Finding things: `astryx search`
19
15
 
20
16
  When you don't know whether what you need is a component, a hook, a docs topic,
@@ -24,29 +20,27 @@ fuzzy matching for typos) and tagged with their domain plus the follow-up
24
20
  command to run:
25
21
 
26
22
  ```bash
27
- $ astryx search button
23
+ $ npx astryx search button
28
24
 
29
25
  Results for "button" (20):
30
26
 
31
27
  [component] Button
32
28
  Button triggers an action when clicked. Use it for form submissions…
33
- → astryx component Button
29
+ npx astryx component Button
34
30
 
35
31
  [component] IconButton
36
32
  A button that shows only an icon with no visible text…
37
- → astryx component IconButton
33
+ npx astryx component IconButton
38
34
 
39
35
  [hook] useClickableContainer
40
36
  Makes a container element clickable while preserving nested…
41
- → astryx hook useClickableContainer
37
+ npx astryx hook useClickableContainer
42
38
 
43
39
  [template] Banner — Collapsible
44
40
  Combine an action button, dismiss control, and expandable detail area…
45
- → astryx template BannerCollapsibleContent
41
+ npx astryx template BannerCollapsibleContent
46
42
  ```
47
43
 
48
- (The CLI prints the follow-up commands with your actual runner — `npx astryx …` when installed, or `npx @astryxdesign/cli …` when run one-off.)
49
-
50
44
  Options:
51
45
 
52
46
  - `--type <component|hook|doc|template>`: restrict to a single domain
@@ -421,7 +415,7 @@ failures (warnings are fine) and `1` when any check fails. That makes it
421
415
  usable directly as a CI step:
422
416
 
423
417
  ```yaml
424
- - run: npx @astryxdesign/cli doctor
418
+ - run: npx astryx doctor
425
419
  ```
426
420
 
427
421
  Use `--json` for a structured envelope (`{ apiVersion, type: "doctor",
@@ -429,103 +423,13 @@ data: { checks, summary } }`) that AI agents and scripts can parse.
429
423
 
430
424
  ## Configuration
431
425
 
432
- The CLI reads an optional `astryx.config.{ts,mjs,js}` from your project root
433
- (a sibling of `package.json`). Every field is optional; with no config file the
434
- CLI runs on defaults.
426
+ The CLI reads from an optional `astryx.config.mjs` in your project root:
435
427
 
436
- ```typescript
437
- import {createConfig} from '@astryxdesign/core/config';
438
-
439
- export default createConfig({
440
- integrations: ['@acme/astryx-widgets'],
428
+ ```javascript
429
+ export default {
430
+ templates: {
431
+ get: async id => fetchTemplateFromAPI(id),
432
+ },
441
433
  issuesUrl: 'https://github.com/your-org/your-repo/issues',
442
- });
443
- ```
444
-
445
- `createConfig` is a type-preserving helper: it returns its argument unchanged
446
- and exists only to give the config file editor autocomplete and type-checking. A
447
- plain `export default {}` object works identically. It's exported from
448
- `@astryxdesign/core` (not the CLI) so your config file gets type feedback
449
- without depending on the CLI; the same helper is re-exported from
450
- `@astryxdesign/cli/config` for back-compat.
451
-
452
- | Field | Type | Purpose |
453
- | ----------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- |
454
- | `integrations` | `string[]` | Integration package names to load (see [Integrations](#integrations)). |
455
- | `issuesUrl` | `string` | Where "report an issue" links point for your project. Defaults to the core issue tracker. |
456
- | `hooks.postCodemod` | `PostCodemodHook[]` | Commands to run after `astryx upgrade` applies codemods (e.g. reinstall, rebuild, reformat). |
457
- | `experimental.xle.components` | `Record<string, XleComponent>` | Register app-local components so layout (XLE) expressions can reference them by name. Unstable. |
458
-
459
- The config is validated against a strict schema when the CLI loads it, so an
460
- unknown field is a hard error rather than a silent no-op. `astryx doctor`
461
- reports whether the config loads cleanly.
462
-
463
- ## Integrations
464
-
465
- An **integration** is any npm package that contributes its own components,
466
- templates, and upgrade codemods to Astryx. The CLI surfaces them next to core's,
467
- through the same commands, so a consumer can `astryx component`,
468
- `astryx template`, and `astryx upgrade` across core and every integration
469
- uniformly. Use it to ship a first-party add-on, publish a third-party component
470
- library, or share an internal design-system package across apps.
471
-
472
- The system runs on two files, each with a small typed API:
473
-
474
- | File | Written by | Role |
475
- | -------------------------------- | ---------- | ----------------------------------------- |
476
- | `astryx.config.{ts,mjs,js}` | Consumer | Lists which integration packages to load. |
477
- | `astryx.integration.{ts,mjs,js}` | Author | Declares what a package contributes. |
478
-
479
- The consumer side is the `integrations` field of [`astryx.config`](#configuration).
480
- The author side is the integration manifest below.
481
-
482
- ### The integration manifest
483
-
484
- A package becomes an integration by exporting a manifest from
485
- `astryx.integration.{ts,mjs,js}` at its root (a sibling of `package.json`). The
486
- manifest points at where each kind of contribution lives; identity (name,
487
- version) comes from `package.json`, not the manifest.
488
-
489
- ```typescript
490
- import {createIntegration} from '@astryxdesign/core/authoring';
491
-
492
- export default createIntegration({
493
- components: './components',
494
- templates: './templates',
495
- codemods: './codemods',
496
- issuesUrl: 'https://github.com/acme/widgets/issues',
497
- });
498
- ```
499
-
500
- | Field | Type | Purpose |
501
- | ------------ | -------- | --------------------------------------------------------------------- |
502
- | `components` | `string` | Directory holding the package's components and their `.doc.*` files. |
503
- | `templates` | `string` | Directory holding the package's page/block templates. |
504
- | `codemods` | `string` | Directory holding upgrade codemods run by `astryx upgrade`. |
505
- | `issuesUrl` | `string` | Where "report an issue" links for this package's contributions point. |
506
-
507
- Every field is optional; declare only the roots the package ships.
508
- `createIntegration` is a type-preserving helper (editor autocomplete and
509
- type-checking); it lives in `@astryxdesign/core/authoring` and is re-exported
510
- from `@astryxdesign/cli/integration` for back-compat.
511
-
512
- ### How it works
513
-
514
- Every command loads the consumer's `astryx.config`, resolves each listed
515
- integration's manifest from `node_modules`, and discovers its contributions.
516
- Everything is validated against one strict schema at the load boundary, so the
517
- CLI presents core and integration contributions through a single, uniform
518
- surface.
519
-
520
- Discovery is resilient: a broken or misconfigured integration is skipped with a
521
- one-line warning on stderr instead of crashing the CLI, and it never corrupts a
522
- `--json` envelope. To inspect problems, run
523
- `astryx validate-integration <package>` for a detailed report on one package, or
524
- `astryx doctor` for an overall health check.
525
-
526
- For the full authoring walkthrough (component doc format, template packaging
527
- and `exports` requirements, and codemod authoring), see the guide:
528
-
529
- ```bash
530
- astryx docs cli-integrations
434
+ };
531
435
  ```
@@ -21,7 +21,7 @@ export const docs = {
21
21
  type: 'code',
22
22
  lang: 'text',
23
23
  label: 'Paste this into your AI',
24
- code: 'Install @astryxdesign/core, @astryxdesign/theme-neutral, and @astryxdesign/cli in this project, then run `npx @astryxdesign/cli init` to set up agent docs. Read the generated files to learn the conventions.',
24
+ code: 'Install @astryxdesign/core, @astryxdesign/theme-neutral, and @astryxdesign/cli in this project. Run `npx astryx init` to set up agent docs. Read the generated files to learn the conventions.',
25
25
  },
26
26
  ],
27
27
  },
@@ -40,7 +40,7 @@ export const docs = {
40
40
  },
41
41
  {
42
42
  type: 'prose',
43
- text: "Then run `astryx init` to install the AI agent cheat sheet (AGENTS.md/CLAUDE.md). It's non-interactive — no prompts — so it's safe for AI agents, CI, and scripts. Add `--all` for pointers to the theme and page-building workflows.",
43
+ text: 'Then run the init wizard to set up AI agent docs, pick a starter template, and learn about theming.',
44
44
  },
45
45
  {
46
46
  type: 'code',
@@ -67,11 +67,11 @@ export const docs = {
67
67
  },
68
68
  {
69
69
  type: 'prose',
70
- text: 'Available themes: @astryxdesign/theme-neutral (muted minimal, a good starting point), @astryxdesign/theme-butter, @astryxdesign/theme-chocolate, @astryxdesign/theme-gothic (dark-only), @astryxdesign/theme-matcha, @astryxdesign/theme-stone, and @astryxdesign/theme-y2k. See `astryx docs theme` for the full theming guide.',
70
+ text: 'Available themes: @astryxdesign/theme-neutral (muted minimal, a good starting point), @astryxdesign/theme-butter, @astryxdesign/theme-chocolate, @astryxdesign/theme-gothic (dark-only), @astryxdesign/theme-matcha, @astryxdesign/theme-stone, and @astryxdesign/theme-y2k. See `npx astryx docs theme` for the full theming guide.',
71
71
  },
72
72
  {
73
73
  type: 'prose',
74
- text: 'These stylesheets are cascade-layered: the reset loads in @layer reset and component styles in @layer astryx-base. If your project has existing global CSS, a legacy reset, or Tailwind, declare the layer order explicitly and assign every stylesheet to a layer deliberately: unlayered styles and later layers both override astryx-base regardless of specificity. See the Cascade Layer Safety section in `astryx docs migration` before building screens.',
74
+ text: 'These stylesheets are cascade-layered: the reset loads in @layer reset and component styles in @layer astryx-base. If your project has existing global CSS, a legacy reset, or Tailwind, declare the layer order explicitly and assign every stylesheet to a layer deliberately: unlayered styles and later layers both override astryx-base regardless of specificity. See the Cascade Layer Safety section in `npx astryx docs migration` before building screens.',
75
75
  },
76
76
  ],
77
77
  },
@@ -172,11 +172,11 @@ pnpm dev`,
172
172
  type: 'code',
173
173
  lang: 'bash',
174
174
  label: 'Terminal',
175
- code: `astryx component # list all components
176
- astryx component Button # props, usage, theming for Button
177
- astryx docs # list all doc topics
178
- astryx template --list # available page templates
179
- astryx docs tokens # spacing, color, radius reference`,
175
+ code: `npx astryx component # list all components
176
+ npx astryx component Button # props, usage, theming for Button
177
+ npx astryx docs # list all doc topics
178
+ npx astryx template --list # available page templates
179
+ npx astryx docs tokens # spacing, color, radius reference`,
180
180
  },
181
181
  ],
182
182
  },
@@ -0,0 +1,105 @@
1
+ # Authoring an Astryx Integration
2
+
3
+ > **Status:** working notes. This should eventually move to the public wiki
4
+ > alongside the rest of the integration-authoring guidance; it lives here for
5
+ > now so it ships and is versioned with the CLI.
6
+
7
+ An **Integration** is an npm package that contributes components, templates, and/or
8
+ codemods to a consumer's design-system workflow. Consumers install the 3rd party
9
+ package, add a line to their astryx.config file:
10
+
11
+ ```js
12
+ import {createConfig} from '@astryxdesign/cli/config';
13
+
14
+ export default createConfig({
15
+ integrations: ['@acme/astryx-widgets'],
16
+ ...
17
+ });
18
+ ```
19
+
20
+ Then the integration's components and templates will be surfaced alongside Astryx
21
+ components in the Astryx CLI.
22
+
23
+ ```sh
24
+ astryx component AcmeCarousel --props
25
+ astryx component --list --package @acme/astryx-widgets
26
+ ```
27
+
28
+ ## The Integration File
29
+
30
+ In order to register your package as an Astryx Integration, create an
31
+ `astryx.integration.{ts,mjs,js}` file as a sibling to your `package.json`. This file
32
+ tells Astryx where to find your components, templates, codemods, etc.
33
+
34
+ ```js
35
+ // astryx.integration.{ts,mjs,js}
36
+ import {createIntegration} from '@astryxdesign/cli/integration';
37
+
38
+ export default createIntegration({
39
+ components: './components',
40
+ templates: './templates',
41
+ codemods: './codemods',
42
+ issuesUrl: 'https://github.com/acme/widgets/issues',
43
+ });
44
+ ```
45
+
46
+ ## Components
47
+
48
+ Your components themselves may be exported from your library as you see fit (consumers
49
+ will still import them from your package) but Astryx CLI will look for a .doc.{ts,mjs,js}
50
+ file with the same stem e.g. `AcmeCarousel.tsx` and `AcmeCarousel.doc.ts`.
51
+
52
+ ```js
53
+ // AcmeCarousel.doc.ts
54
+ import {createComponentDoc} from '@astryxdesign/cli/doc';
55
+
56
+ export default createComponentDoc({
57
+ name: 'AcmeCarousel',
58
+ description: '...',
59
+ ...
60
+ });
61
+ ```
62
+
63
+ ## Templates
64
+
65
+ Templates are typically not exported from the package directly, but instead accessed
66
+ via the Astryx CLI. Consumers can look through your templates and materialize them
67
+ into their apps.
68
+
69
+ You define a template with the `createPageTemplate` (for full pages) or `createBlockTemplate`
70
+ (for smaller chunks). e.g. `AcmeLandingPage.tsx`, `AcmeLandingPage.template.ts`
71
+
72
+ ```js
73
+ // AcmeLandingPage.template.ts
74
+ import {createPageTemplate} from '@astryxdesign/cli/template';
75
+
76
+ export default createPageTemplate({
77
+ ...
78
+ });
79
+ ```
80
+
81
+ Note that, since the CLI needs access to the template source code, you need to make sure
82
+ that it is included in your published package. This will also allow us to render previews
83
+ of templates in the future by bundling your template into a doc site build.
84
+
85
+ Typically, this is done via the package.json `exports` key.
86
+
87
+ ```jsonc
88
+ {
89
+ "exports": {
90
+ // ...
91
+ "./templates/*.tsx": "./templates/*.tsx",
92
+ },
93
+ }
94
+ ```
95
+
96
+ In order to verify that it's working, you can test importing the template component like this:
97
+
98
+ ```ts
99
+ import('@acme/astryx-widgets/templates/AcmeLandingPage.tsx');
100
+ ```
101
+
102
+ Import **with the `.tsx` extension** — an extensionless specifier won't resolve
103
+ under `moduleResolution: bundler`. The extensionful `"./templates/*.tsx"` export
104
+ above is what lets that import type-check without consumers enabling
105
+ `allowImportingTsExtensions`.
@@ -54,18 +54,18 @@ export const docs = {
54
54
  type: 'code',
55
55
  lang: 'bash',
56
56
  label: 'Migration-oriented CLI pass',
57
- code: `astryx docs migration
58
- astryx docs theme
59
- astryx docs styling
60
- astryx template --list --type block
61
- astryx template AppShellTopNavWithSideNav --skeleton
62
- astryx template PopoverSettingsPanel --skeleton
63
- astryx component AppShell
64
- astryx component SideNav
65
- astryx component TopNav
66
- astryx component CommandPalette
67
- astryx component Button
68
- astryx component TextInput`,
57
+ code: `npx astryx docs migration
58
+ npx astryx docs theme
59
+ npx astryx docs styling
60
+ npx astryx template --list --type block
61
+ npx astryx template AppShellTopNavWithSideNav --skeleton
62
+ npx astryx template PopoverSettingsPanel --skeleton
63
+ npx astryx component AppShell
64
+ npx astryx component SideNav
65
+ npx astryx component TopNav
66
+ npx astryx component CommandPalette
67
+ npx astryx component Button
68
+ npx astryx component TextInput`,
69
69
  },
70
70
  {
71
71
  type: 'prose',
@@ -75,8 +75,8 @@ astryx component TextInput`,
75
75
  type: 'code',
76
76
  lang: 'bash',
77
77
  label: 'Dense and JSON modes',
78
- code: `astryx docs migration --dense
79
- astryx component Button --json`,
78
+ code: `npx astryx docs migration --dense
79
+ npx astryx component Button --json`,
80
80
  },
81
81
  ],
82
82
  },
@@ -371,10 +371,10 @@ if (getComputedStyle(button).paddingInline === '0px') {
371
371
  code: `We are migrating this existing Tailwind/shadcn app to Astryx incrementally.
372
372
 
373
373
  First run:
374
- - astryx docs migration --dense
375
- - astryx docs theme --dense
376
- - astryx docs styling --dense
377
- - astryx template AppShellTopNavWithSideNav --skeleton
374
+ - npx astryx docs migration --dense
375
+ - npx astryx docs theme --dense
376
+ - npx astryx docs styling --dense
377
+ - npx astryx template AppShellTopNavWithSideNav --skeleton
378
378
 
379
379
  Then migrate one route or shell surface at a time. Keep business logic and routing intact. Replace shadcn/Radix/Tailwind primitives with Astryx components, remove hardcoded colors, verify light and dark mode, and take screenshots before moving to the next surface.`,
380
380
  },
@@ -9,6 +9,6 @@ export const docsDense = {
9
9
  { section: 'Rules', title: 'Rules', content: [{ type: 'list', items: ['use components', 'frame-first layout: shell + region budgets before content (astryx docs layout)', 'dense data = rows (Table, List/Item) not Cards; Card = widgets/galleries/settings groups', 'StyleX or Tailwind for styling', 'semantic tokens only', 'CSS vars for colors', 'controlled form inputs', 'useLinkComponent() for navigation'] }] },
10
10
  { section: 'Styling Approach', title: 'Styling', content: [{ type: 'prose', text: 'xstyle prop for component overrides. StyleX or Tailwind for layout. See astryx docs styling.' }] },
11
11
  { section: 'Anti-Patterns', title: 'Anti-Patterns', content: [{ type: 'list', items: ['no inline styles on raw elements', 'no hardcoded colors — use tokens or Tailwind semantic classes', 'no hardcoded spacing', 'no hardcoded <a> — use useLinkComponent()', 'no Card-wrapped list items — frame first, rows for dense data (astryx docs layout)', 'no decorative Badge — StatusDot/Token for status', 'read docs before inventing props'] }] },
12
- { section: 'Design Tokens', title: 'Tokens', content: [{ type: 'prose', text: 'run astryx docs tokens for full reference' }] },
12
+ { section: 'Design Tokens', title: 'Tokens', content: [{ type: 'prose', text: 'run npx astryx docs tokens for full reference' }] },
13
13
  ],
14
14
  };
@@ -39,10 +39,10 @@ export const docs = {
39
39
  style: 'ordered',
40
40
  items: [
41
41
  'Use components for everything they cover',
42
- 'Layout is frame-first: pick the shell and budget regions before writing content (see \`astryx docs layout\`)',
42
+ 'Layout is frame-first: pick the shell and budget regions before writing content (see \`npx astryx docs layout\`)',
43
43
  'Dense data renders as rows (Table, List/Item), edge-to-edge with dividers; Card is for widgets, galleries, and settings groups',
44
- 'StyleX or Tailwind for custom styling; both are first-class (see \`astryx docs styling\`)',
45
- 'Semantic tokens, not hardcoded values (see \`astryx docs tokens\`)',
44
+ 'StyleX or Tailwind for custom styling; both are first-class (see \`npx astryx docs styling\`)',
45
+ 'Semantic tokens, not hardcoded values (see \`npx astryx docs tokens\`)',
46
46
  'CSS custom properties for colors, not hex values',
47
47
  'Form inputs are controlled (value + onChange)',
48
48
  'Use useLinkComponent() for navigation so consumers can plug in their framework router via LinkProvider',
@@ -60,7 +60,7 @@ export const docs = {
60
60
  },
61
61
  {
62
62
  type: 'prose',
63
- text: 'See \`astryx docs styling\` for the complete guide with examples.',
63
+ text: 'See \`npx astryx docs styling\` for the complete guide with examples.',
64
64
  },
65
65
  ],
66
66
  },
@@ -76,7 +76,7 @@ export const docs = {
76
76
  'Hardcoded colors (#fff). Use var(--color-*) or Tailwind semantic classes (text-primary, bg-surface)',
77
77
  'Hardcoded spacing (16px). Use spacing tokens or Tailwind spacing utilities',
78
78
  'Hardcoded <a> elements. Use useLinkComponent() so consumers can swap in their framework router via LinkProvider',
79
- 'Wrapping every list item or page section in a Card. Decide the frame first; dense data renders as rows (see \`astryx docs layout\`)',
79
+ 'Wrapping every list item or page section in a Card. Decide the frame first; dense data renders as rows (see \`npx astryx docs layout\`)',
80
80
  'Badge as decoration. Reserve Badge for counts and enumerated states; use StatusDot or Token for status',
81
81
  'Inventing props. Read component docs first',
82
82
  ],
@@ -89,7 +89,7 @@ export const docs = {
89
89
  content: [
90
90
  {
91
91
  type: 'prose',
92
- text: 'The design system provides semantic design tokens for spacing, color, radius, shadow, typography, and size. Tokens adapt to the active theme and color mode. Run \`astryx docs tokens\` for the full reference with all values.',
92
+ text: 'The design system provides semantic design tokens for spacing, color, radius, shadow, typography, and size. Tokens adapt to the active theme and color mode. Run \`npx astryx docs tokens\` for the full reference with all values.',
93
93
  },
94
94
  ],
95
95
  },
@@ -9,6 +9,6 @@ export const docsZh = {
9
9
  { section: 'Rules', title: '规则', content: [{ type: 'list', items: ['所有支持的场景都使用 XDS 组件', '布局采用框架优先:先选定外壳并规划区域尺寸,再编写内容(见 astryx docs layout)', '密集数据使用行(Table、List/Item)通栏渲染;Card 用于小部件、画廊和设置分组', '使用 StyleX 或 Tailwind 进行样式设置', '使用语义化令牌,不使用硬编码值', '使用 CSS 变量设置颜色,不使用十六进制值', '表单输入为受控组件(value + onChange)', '使用 useLinkComponent() 进行导航'] }] },
10
10
  { section: 'Styling Approach', title: '样式方法', content: [{ type: 'prose', text: '组件覆盖使用 xstyle 属性。布局使用 StyleX 或 Tailwind。详见 astryx docs styling。' }] },
11
11
  { section: 'Anti-Patterns', title: '反模式', content: [{ type: 'list', items: ['不要在原始元素上使用内联样式', '不要硬编码颜色 — 使用令牌或 Tailwind 语义类', '不要硬编码间距', '不要硬编码 <a> 元素 — 使用 useLinkComponent()', '不要把每个列表项都包在 Card 里 — 先定框架,密集数据用行渲染(见 astryx docs layout)', '不要把 Badge 当装饰 — 状态请使用 StatusDot 或 Token', '不要自创属性。先阅读组件文档'] }] },
12
- { section: 'Design Tokens', title: '设计令牌', content: [{ type: 'prose', text: '运行 astryx docs tokens 查看完整参考' }] },
12
+ { section: 'Design Tokens', title: '设计令牌', content: [{ type: 'prose', text: '运行 npx astryx docs tokens 查看完整参考' }] },
13
13
  ],
14
14
  };
@@ -24,7 +24,7 @@ export const docs = {
24
24
  },
25
25
  {
26
26
  type: 'prose',
27
- text: 'For available token names and values, run `astryx docs tokens`. Focused references are also available with `astryx docs color`, `astryx docs spacing`, `astryx docs shape`, `astryx docs typography`, `astryx docs elevation`, and `astryx docs motion`.',
27
+ text: 'For available token names and values, run `npx astryx docs tokens`. Focused references are also available with `npx astryx docs color`, `npx astryx docs spacing`, `npx astryx docs shape`, `npx astryx docs typography`, `npx astryx docs elevation`, and `npx astryx docs motion`.',
28
28
  },
29
29
  ],
30
30
  },
@@ -452,10 +452,10 @@ function RevenueChart({data}: {data: Array<{x: string; y: number}>}) {
452
452
  type: 'list',
453
453
  style: 'ordered',
454
454
  items: [
455
- 'Import the reset/base CSS and a theme CSS file early enough for first paint. For production SSR, prefer built themes from `astryx theme build` or published `/built` theme imports plus `theme.css`.',
455
+ 'Import the reset/base CSS and a theme CSS file early enough for first paint. For production SSR, prefer built themes from `npx astryx theme build` or published `/built` theme imports plus `theme.css`.',
456
456
  'Choose one owner for color mode. Theme uses `data-theme="light|dark"` and `color-scheme` to resolve `light-dark()` tokens.',
457
457
  'Map the external library\'s semantic layer to system variables by intent, not by exact naming. For example, MUI `background.paper` maps to `--color-background-surface`.',
458
- 'Use `astryx docs tokens` and focused token docs when building mappings. Keep mappings small at first: text, surface/body/card/popover, border, accent, status, spacing, radius, typography, shadow.',
458
+ 'Use `npx astryx docs tokens` and focused token docs when building mappings. Keep mappings small at first: text, surface/body/card/popover, border, accent, status, spacing, radius, typography, shadow.',
459
459
  'Use token resolver APIs only for non-CSS APIs that need resolved values.',
460
460
  ],
461
461
  },
@@ -30,7 +30,7 @@ export const docs = {
30
30
  },
31
31
  {
32
32
  type: 'prose',
33
- text: 'All approaches resolve to the same design tokens, so theming and dark mode work regardless of which you choose. For external styling libraries, run `astryx docs styling-libraries`; it covers Tailwind, StyleX, Panda, Chakra, MUI, CSS-in-JS, CSS Modules, Sass, and `useTheme()` for non-CSS processing.',
33
+ text: 'All approaches resolve to the same design tokens, so theming and dark mode work regardless of which you choose. For external styling libraries, run `npx astryx docs styling-libraries`; it covers Tailwind, StyleX, Panda, Chakra, MUI, CSS-in-JS, CSS Modules, Sass, and `useTheme()` for non-CSS processing.',
34
34
  },
35
35
  ],
36
36
  },
@@ -118,7 +118,7 @@ const overrides = stylex.create({
118
118
  },
119
119
  {
120
120
  type: 'prose',
121
- text: 'The bridge is pure CSS with zero JS. Theme changes (dark mode, custom themes) apply automatically because the utilities reference the same CSS custom properties that components use. This is the paved Tailwind path; for other styling libraries that follow the same aliasing pattern, run `astryx docs styling-libraries`.',
121
+ text: 'The bridge is pure CSS with zero JS. Theme changes (dark mode, custom themes) apply automatically because the utilities reference the same CSS custom properties that components use. This is the paved Tailwind path; for other styling libraries that follow the same aliasing pattern, run `npx astryx docs styling-libraries`.',
122
122
  },
123
123
  ],
124
124
  },
@@ -263,7 +263,7 @@ const overrides = stylex.create({
263
263
  },
264
264
  {
265
265
  type: 'prose',
266
- text: 'For systematic theming, use defineTheme component overrides instead of raw CSS selectors. defineTheme keeps the higher-level `prop:value` API (`variant:primary`, `size:sm`) and handles selector generation for you. Run `astryx docs theme` for the full theming guide.',
266
+ text: 'For systematic theming, use defineTheme component overrides instead of raw CSS selectors. defineTheme keeps the higher-level `prop:value` API (`variant:primary`, `size:sm`) and handles selector generation for you. Run `npx astryx docs theme` for the full theming guide.',
267
267
  },
268
268
  ],
269
269
  },
@@ -334,7 +334,7 @@ const styles = stylex.create({
334
334
  },
335
335
  {
336
336
  type: 'prose',
337
- text: 'See `astryx docs tokens` for the full token reference (all spacing, color, radius, shadow, and typography tokens with values). See `astryx docs theme` for how to override tokens via defineTheme.',
337
+ text: 'See `npx astryx docs tokens` for the full token reference (all spacing, color, radius, shadow, and typography tokens with values). See `npx astryx docs theme` for how to override tokens via defineTheme.',
338
338
  },
339
339
  ],
340
340
  },
@@ -10,9 +10,9 @@ export const docsDense = {
10
10
  { section: 'Theme Props', title: 'Props', content: [null] },
11
11
  { section: 'Creating a Custom Theme', title: 'Custom Theme', content: [{ type: 'prose', text: 'CLI wizard or manual defineTheme. only override tokens that differ.' }, null] },
12
12
  { section: 'defineTheme', title: 'defineTheme', content: [{ type: 'prose', text: 'scale configs (color, typography, radius, motion) + explicit token overrides + component overrides. color derives full palette from accent hex via HCT.' }, null, null] },
13
- { section: 'Component Style Overrides', title: 'Component Overrides', content: [{ type: 'prose', text: 'components field uses semantic component keys + style keys (base, variant:value, stateName), not raw selectors. for external CSS, prefer data-* selectors from `astryx docs styling`. write standard CSS (borderRadius, padding) — pipeline expands to internal vars. public vars (--button-press-scale etc) set directly. private vars (--_*) cannot be set — use CSS properties. run `astryx component <Name>` for details.' }, null, null, null, null] },
13
+ { section: 'Component Style Overrides', title: 'Component Overrides', content: [{ type: 'prose', text: 'components field uses semantic component keys + style keys (base, variant:value, stateName), not raw selectors. for external CSS, prefer data-* selectors from `astryx docs styling`. write standard CSS (borderRadius, padding) — pipeline expands to internal vars. public vars (--button-press-scale etc) set directly. private vars (--_*) cannot be set — use CSS properties. run `npx astryx component <Name>` for details.' }, null, null, null, null] },
14
14
  { section: 'Custom Variants', title: 'Custom Variants', content: [{ type: 'prose', text: 'any unknown prop:value in components becomes a new variant. astryx theme build generates TS augmentations. works on any extensible prop axis (variant, status, etc).' }, null, null, null, null] },
15
- { section: 'Building Themes for Production', title: 'Build for Production', content: [{ type: 'prose', text: 'astryx theme build compiles defineTheme to static CSS. outputs .css + .js (__built:true) + .d.ts.' }, null, null, null, null] },
15
+ { section: 'Building Themes for Production', title: 'Build for Production', content: [{ type: 'prose', text: 'npx astryx theme build compiles defineTheme to static CSS. outputs .css + .js (__built:true) + .d.ts.' }, null, null, null, null] },
16
16
  { section: 'Runtime vs Built Themes', title: 'Runtime vs Built', content: [{ type: 'prose', text: 'runtime: useInsertionEffect injects styles client-side. built: static CSS on first paint. USE /built + theme.css FOR SSR.' }, null, null, null] },
17
17
  { section: 'Light/Dark Mode', title: 'Light/Dark', content: [{ type: 'prose', text: 'light-dark() in token values via [light, dark] tuples. mode=system follows OS.' }, null, null] },
18
18
  { section: 'Nesting Themes', title: 'Nesting', content: [{ type: 'prose', text: 'wrap sections in separate <Theme> providers' }, null] },
@@ -148,7 +148,7 @@ function App() {
148
148
  type: 'code',
149
149
  lang: 'bash',
150
150
  label: 'Scaffold with CLI',
151
- code: 'astryx theme',
151
+ code: 'npx astryx theme',
152
152
  },
153
153
  ],
154
154
  },
@@ -287,7 +287,7 @@ const brandTheme = defineTheme({
287
287
  },
288
288
  {
289
289
  type: 'prose',
290
- text: 'Run `astryx component <Name>` to see a component\'s theming targets, public CSS variables, and which standard CSS properties are supported.',
290
+ text: 'Run `npx astryx component <Name>` to see a component\'s theming targets, public CSS variables, and which standard CSS properties are supported.',
291
291
  },
292
292
  {
293
293
  type: 'list',
@@ -361,13 +361,13 @@ const brandTheme = defineTheme({
361
361
  content: [
362
362
  {
363
363
  type: 'prose',
364
- text: '`astryx theme build` compiles a defineTheme file into production-ready artifacts. Recommended for SSR apps (Next.js, Remix) where styles must be present on first paint.',
364
+ text: '`npx astryx theme build` compiles a defineTheme file into production-ready artifacts. Recommended for SSR apps (Next.js, Remix) where styles must be present on first paint.',
365
365
  },
366
366
  {
367
367
  type: 'code',
368
368
  lang: 'bash',
369
369
  label: 'Build a theme',
370
- code: 'astryx theme build ./src/themes/ocean.ts',
370
+ code: 'npx astryx theme build ./src/themes/ocean.ts',
371
371
  },
372
372
  {
373
373
  type: 'prose',
@@ -432,7 +432,7 @@ import './themes/ocean.css';
432
432
  [
433
433
  'Import (custom theme)',
434
434
  'defineTheme() directly',
435
- "Built .js + .css from `astryx theme build`",
435
+ "Built .js + .css from `npx astryx theme build`",
436
436
  ],
437
437
  [
438
438
  'How it works',
@@ -462,7 +462,7 @@ import './themes/ocean.css';
462
462
  items: [
463
463
  'Use the /built subpath + theme.css for production SSR apps.',
464
464
  'Use runtime themes during development for fast iteration.',
465
- 'Run `astryx theme build` for custom themes to get the built artifacts.',
465
+ 'Run `npx astryx theme build` for custom themes to get the built artifacts.',
466
466
  ],
467
467
  },
468
468
  {
@@ -610,7 +610,7 @@ function ChartConfig() {
610
610
  },
611
611
  {
612
612
  type: 'prose',
613
- text: 'See `astryx docs styling-libraries` for styling-library interop and `astryx docs tokens` for the full token reference.',
613
+ text: 'See `npx astryx docs styling-libraries` for styling-library interop and `npx astryx docs tokens` for the full token reference.',
614
614
  },
615
615
  ],
616
616
  },
@@ -10,7 +10,7 @@ export const docsZh = {
10
10
  { section: 'Theme Props', title: 'Theme 属性', content: [null] },
11
11
  { section: 'Creating a Custom Theme', title: '创建自定义主题', content: [{ type: 'prose', text: '使用 CLI 向导(推荐)或手动 defineTheme。只覆盖与默认值不同的令牌。' }, null] },
12
12
  { section: 'defineTheme', title: 'defineTheme', content: [{ type: 'prose', text: '支持比例配置(typography、radius、motion)+ 显式令牌覆盖 + 组件覆盖。' }, null, null] },
13
- { section: 'Building Themes for Production', title: '生产构建', content: [{ type: 'prose', text: 'astryx theme build 将 defineTheme 编译为静态 CSS。输出 .css + .js(__built:true)+ .d.ts。' }, null, null, null, null] },
13
+ { section: 'Building Themes for Production', title: '生产构建', content: [{ type: 'prose', text: 'npx astryx theme build 将 defineTheme 编译为静态 CSS。输出 .css + .js(__built:true)+ .d.ts。' }, null, null, null, null] },
14
14
  { section: 'Runtime vs Built Themes', title: '运行时 vs 构建', content: [{ type: 'prose', text: '运行时:useInsertionEffect 在客户端注入样式。构建:静态 CSS 在首次渲染时就存在。SSR 应用请使用 /built + theme.css。' }, null, null, null] },
15
15
  { section: 'Light/Dark Mode', title: '亮/暗模式', content: [{ type: 'prose', text: "令牌值使用 [light, dark] 元组实现自动模式切换。Theme 上 mode='system'(默认)跟随系统偏好。" }, null, null] },
16
16
  { section: 'Nesting Themes', title: '嵌套主题', content: [{ type: 'prose', text: '将不同部分包裹在独立的 <Theme> 提供者中。' }, null] },
@@ -1068,7 +1068,7 @@ export const docs = {
1068
1068
  },
1069
1069
  {
1070
1070
  "type": "prose",
1071
- "text": "See `astryx docs styling` for how to apply tokens via xstyle, className, and compound component patterns. See `astryx docs theme` for overriding tokens with defineTheme."
1071
+ "text": "See `npx astryx docs styling` for how to apply tokens via xstyle, className, and compound component patterns. See `npx astryx docs theme` for overriding tokens with defineTheme."
1072
1072
  }
1073
1073
  ]
1074
1074
  }