@astryxdesign/cli 0.1.6 → 0.1.7-canary.04cd8f7

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 (107) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +115 -19
  3. package/docs/cli-integrations.doc.mjs +150 -0
  4. package/docs/getting-started.doc.mjs +9 -9
  5. package/docs/internationalization.doc.mjs +243 -0
  6. package/docs/layout.doc.dense.mjs +5 -0
  7. package/docs/migration.doc.mjs +18 -18
  8. package/docs/principles.doc.dense.mjs +5 -5
  9. package/docs/principles.doc.mjs +6 -6
  10. package/docs/principles.doc.zh.mjs +5 -5
  11. package/docs/styling-libraries.doc.mjs +3 -3
  12. package/docs/styling.doc.mjs +4 -4
  13. package/docs/theme.doc.dense.mjs +12 -12
  14. package/docs/theme.doc.mjs +7 -7
  15. package/docs/theme.doc.zh.mjs +10 -10
  16. package/docs/tokens.doc.dense.mjs +6 -7
  17. package/docs/tokens.doc.mjs +1 -1
  18. package/docs/tokens.doc.zh.mjs +6 -7
  19. package/docs/working-with-ai.doc.mjs +18 -18
  20. package/package.json +13 -10
  21. package/src/api/docOverlays.test.mjs +133 -0
  22. package/src/api/docs.mjs +14 -2
  23. package/src/api/doctor.mjs +3 -3
  24. package/src/api/integration-block-exports.test.mjs +240 -0
  25. package/src/api/template-suffix.test.mjs +246 -0
  26. package/src/api/template.mjs +104 -28
  27. package/src/api/validate-integration.mjs +0 -8
  28. package/src/codemods/__tests__/registry.test.mjs +1 -0
  29. package/src/codemods/ensure-jscodeshift.mjs +11 -27
  30. package/src/codemods/registry.mjs +1 -0
  31. package/src/codemods/run-codemod.mjs +1 -1
  32. package/src/codemods/runner.mjs +2 -2
  33. package/src/codemods/transforms/v0.1.7/__tests__/migrate-table-tableprops-to-direct-props.test.mjs +120 -0
  34. package/src/codemods/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs +112 -0
  35. package/src/codemods/transforms/v0.1.7/index.mjs +27 -0
  36. package/src/codemods/transforms/v0.1.7/migrate-table-tableprops-to-direct-props.mjs +188 -0
  37. package/src/codemods/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs +197 -0
  38. package/src/commands/agent-docs.mjs +21 -8
  39. package/src/commands/agent-docs.test.mjs +31 -4
  40. package/src/commands/build-theme.mjs +10 -71
  41. package/src/commands/build.mjs +15 -15
  42. package/src/commands/component/index.mjs +4 -4
  43. package/src/commands/discover.mjs +7 -5
  44. package/src/commands/docs.mjs +4 -4
  45. package/src/commands/hook/index.mjs +4 -4
  46. package/src/commands/init.mjs +48 -152
  47. package/src/commands/init.next-steps.test.mjs +1 -1
  48. package/src/commands/interactive-guard.test.mjs +19 -22
  49. package/src/commands/json-contract.test.mjs +1 -1
  50. package/src/commands/layout.mjs +1 -1
  51. package/src/commands/search.mjs +4 -4
  52. package/src/commands/swizzle.mjs +11 -34
  53. package/src/commands/template.mjs +11 -31
  54. package/src/commands/upgrade.mjs +9 -6
  55. package/src/commands/upgrade.test.mjs +1 -1
  56. package/src/config.mjs +5 -14
  57. package/src/doc.mjs +27 -0
  58. package/src/doc.test.mjs +383 -0
  59. package/src/index.mjs +5 -6
  60. package/src/integration.mjs +4 -15
  61. package/src/lib/component-discovery.importpath.test.mjs +59 -0
  62. package/src/lib/component-discovery.mjs +15 -5
  63. package/src/lib/component-format.mjs +47 -14
  64. package/src/lib/component-format.test.mjs +95 -1
  65. package/src/lib/component-loader.mjs +104 -2
  66. package/src/lib/componentDocOverlay.test.mjs +111 -0
  67. package/src/lib/config-schema.mjs +0 -30
  68. package/src/lib/hook-format.mjs +8 -3
  69. package/src/lib/term-log.mjs +48 -0
  70. package/src/lib/xle/registry.mjs +0 -5
  71. package/src/schemas/doc-schema.mjs +226 -0
  72. package/src/schemas/template-schema.mjs +47 -0
  73. package/src/template.mjs +9 -67
  74. package/src/types/config.d.ts +11 -66
  75. package/src/types/doc.d.ts +23 -0
  76. package/src/types/integration.d.ts +7 -18
  77. package/src/types/template-api.d.ts +14 -50
  78. package/src/utils/package-manager.mjs +78 -0
  79. package/src/utils/package-manager.test.mjs +108 -1
  80. package/src/utils/path-safety.mjs +0 -18
  81. package/src/utils/update-check.mjs +2 -1
  82. package/templates/blocks/components/Avatar/AvatarGroup.tsx +5 -7
  83. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -6
  84. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +3 -5
  85. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +8 -6
  86. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -5
  87. package/templates/blocks/components/ChatComposerInput/ChatComposerInputControlledInput.tsx +1 -1
  88. package/templates/blocks/components/ChatComposerInput/ChatComposerInputDisabled.tsx +1 -1
  89. package/templates/blocks/components/ChatComposerInput/ChatComposerInputMentionTrigger.tsx +1 -1
  90. package/templates/blocks/components/ChatComposerInput/ChatComposerInputMultipleTriggers.tsx +1 -1
  91. package/templates/blocks/components/ChatComposerInput/ChatComposerInputShowcase.tsx +1 -1
  92. package/templates/blocks/components/ChatComposerInput/ChatComposerInputSlashCommands.tsx +1 -1
  93. package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
  94. package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
  95. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenLiveRegion.doc.mjs +14 -0
  96. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenLiveRegion.tsx +41 -0
  97. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenShowcase.doc.mjs +13 -0
  98. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenShowcase.tsx +78 -0
  99. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenStructuralHeading.doc.mjs +14 -0
  100. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenStructuralHeading.tsx +38 -0
  101. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenSupplementaryContext.doc.mjs +14 -0
  102. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenSupplementaryContext.tsx +47 -0
  103. package/templates/pages/ide/page.tsx +35 -41
  104. package/templates/pages/theme-showcase/page.tsx +7 -7
  105. package/templates/themes/neutral/neutralTheme.ts +63 -32
  106. package/src/utils/interactive.mjs +0 -76
  107. package/src/utils/interactive.test.mjs +0 -70
@@ -16,7 +16,7 @@
16
16
  * astryx search button --json Typed JSON envelope
17
17
  */
18
18
 
19
- import {getRunPrefix} from '../utils/package-manager.mjs';
19
+ import {getCliInvocation, formatCliCommand} from '../utils/package-manager.mjs';
20
20
  import {jsonOut, humanLog} from '../lib/json.mjs';
21
21
  import {cliError} from '../lib/cli-error.mjs';
22
22
  import {search as searchApi, SEARCH_DOMAINS} from '../api/search.mjs';
@@ -63,7 +63,7 @@ export function registerSearch(program) {
63
63
  if (json) return jsonOut(result.type, result.data);
64
64
 
65
65
  // ── Text output ──────────────────────────────────────────────
66
- const run = getRunPrefix();
66
+ const run = getCliInvocation();
67
67
  const {query: q, results} = result.data;
68
68
 
69
69
  // No matches is a valid, successful outcome — clean message, exit 0.
@@ -71,7 +71,7 @@ export function registerSearch(program) {
71
71
  humanLog('');
72
72
  humanLog(`No results for "${q}".`);
73
73
  humanLog('');
74
- humanLog(`Try a broader term, or browse: ${run} astryx component --list`);
74
+ humanLog(`Try a broader term, or browse: ${run} component --list`);
75
75
  humanLog('');
76
76
  return;
77
77
  }
@@ -86,7 +86,7 @@ export function registerSearch(program) {
86
86
  if (r.description) {
87
87
  humanLog(` ${r.description}`);
88
88
  }
89
- humanLog(` → ${run} ${r.command}`);
89
+ humanLog(` → ${formatCliCommand(r.command)}`);
90
90
  if (options.detail) {
91
91
  if (r.import) humanLog(` import: ${r.import}`);
92
92
  humanLog(` match: ${r.reason} (score ${r.score})`);
@@ -15,18 +15,16 @@
15
15
 
16
16
  import * as fs from 'node:fs';
17
17
  import * as path from 'node:path';
18
- import * as p from '@clack/prompts';
19
18
  import {findCoreDir, listComponents} from '../utils/paths.mjs';
20
19
  import {
21
20
  assertWithin,
22
21
  PathSafetyError,
23
- isNonInteractive,
24
22
  } from '../utils/path-safety.mjs';
25
23
  import {jsonOut, humanLog} from '../lib/json.mjs';
26
24
  import {cliError} from '../lib/cli-error.mjs';
27
25
  import {ERROR_CODES} from '../lib/error-codes.mjs';
28
26
  import {checkGhCli} from '../utils/github.mjs';
29
- import {getRunPrefix} from '../utils/package-manager.mjs';
27
+ import {getCliInvocation} from '../utils/package-manager.mjs';
30
28
  import {Project} from '../lib/project.mjs';
31
29
  import {
32
30
  CORE_PACKAGE,
@@ -99,14 +97,6 @@ function buildFeedback(component, issuesUrl) {
99
97
  return feedback;
100
98
  }
101
99
 
102
- function isCancel(value) {
103
- if (p.isCancel(value)) {
104
- p.cancel('Cancelled.');
105
- process.exit(0);
106
- }
107
- return value;
108
- }
109
-
110
100
  /**
111
101
  * Load the configured integrations + core issues URL for `cwd`, swallowing any
112
102
  * config errors so swizzle never hard-fails on a malformed/absent config. An
@@ -190,6 +180,7 @@ export function registerSwizzle(program) {
190
180
  .action(async (component, options) => {
191
181
  const coreDir = findCoreDir(process.cwd());
192
182
  const json = program.opts().json || false;
183
+ const run = getCliInvocation();
193
184
 
194
185
  if (!coreDir) {
195
186
  cliError(
@@ -207,10 +198,10 @@ export function registerSwizzle(program) {
207
198
  for (const name of components) {
208
199
  humanLog(` ${name}`);
209
200
  }
210
- humanLog(`\nUsage: astryx swizzle <component>\n`);
211
- humanLog('Example: astryx swizzle Button');
201
+ humanLog(`\nUsage: ${run} swizzle <component>\n`);
202
+ humanLog(`Example: ${run} swizzle Button`);
212
203
  humanLog(
213
- ' astryx swizzle XDSButton (XDS prefix also works)\n',
204
+ ` ${run} swizzle XDSButton (XDS prefix also works)\n`,
214
205
  );
215
206
  return;
216
207
  }
@@ -314,25 +305,11 @@ export function registerSwizzle(program) {
314
305
 
315
306
  if (existingFiles.length > 0 && !options.overwrite) {
316
307
  const relOutputForMsg = path.relative(process.cwd(), outputDir) || '.';
317
- if (json || isNonInteractive({json})) {
318
- const msg =
319
- `Refusing to overwrite ${existingFiles.length} existing file(s) in ${relOutputForMsg}/. ` +
320
- `Re-run with --overwrite (or -f) to replace them.`;
321
- cliError(msg, {code: ERROR_CODES.ERR_FILE_EXISTS});
322
- return;
323
- }
324
- const confirmed = isCancel(
325
- await p.confirm({
326
- message:
327
- `Overwrite ${existingFiles.length} existing file(s) in ${relOutputForMsg}/? ` +
328
- `(${existingFiles.slice(0, 3).join(', ')}${existingFiles.length > 3 ? ', …' : ''})`,
329
- initialValue: false,
330
- }),
331
- );
332
- if (!confirmed) {
333
- humanLog('Aborted. Re-run with --overwrite to replace files.');
334
- return;
335
- }
308
+ const msg =
309
+ `Refusing to overwrite ${existingFiles.length} existing file(s) in ${relOutputForMsg}/. ` +
310
+ `Re-run with --overwrite (or -f) to replace them.`;
311
+ cliError(msg, {code: ERROR_CODES.ERR_FILE_EXISTS});
312
+ return;
336
313
  }
337
314
 
338
315
  fs.mkdirSync(outputDir, {recursive: true});
@@ -411,7 +388,7 @@ export function registerSwizzle(program) {
411
388
  humanLog(
412
389
  ' Without one they render unstyled (no error). See setup per framework:',
413
390
  );
414
- humanLog(` ${getRunPrefix()} astryx docs styling`);
391
+ humanLog(` ${run} docs styling`);
415
392
  humanLog(
416
393
  ' Next.js note: the StyleX Babel plugin disables SWC and breaks next/font —',
417
394
  );
@@ -6,25 +6,16 @@
6
6
 
7
7
  import * as path from 'node:path';
8
8
  import * as fs from 'node:fs';
9
- import * as p from '@clack/prompts';
10
- import {isNonInteractive} from '../utils/path-safety.mjs';
11
9
  import {jsonOut, humanLog} from '../lib/json.mjs';
12
10
  import {cliError} from '../lib/cli-error.mjs';
13
11
  import {ERROR_CODES} from '../lib/error-codes.mjs';
14
12
  import {template as templateApi} from '../api/template.mjs';
15
13
  import {Project} from '../lib/project.mjs';
16
14
  import {warnOnIntegrationIssues} from '../lib/integration-warnings.mjs';
15
+ import {getCliInvocation} from '../utils/package-manager.mjs';
17
16
 
18
17
  export {discoverTemplates, listTemplates} from '../api/template.mjs';
19
18
 
20
- function isCancel(value) {
21
- if (p.isCancel(value)) {
22
- p.cancel('Cancelled.');
23
- process.exit(0);
24
- }
25
- return value;
26
- }
27
-
28
19
  export function registerTemplate(program) {
29
20
  program
30
21
  .command('template [name] [path]')
@@ -36,6 +27,7 @@ export function registerTemplate(program) {
36
27
  .option('-f, --overwrite', 'Overwrite existing files without prompting')
37
28
  .action(async (name, targetPath, options) => {
38
29
  const json = program.opts().json || false;
30
+ const run = getCliInvocation();
39
31
 
40
32
  // Non-blocking nudge: if any configured integration has validation
41
33
  // issues, print one compact line to stderr pointing at
@@ -59,23 +51,11 @@ export function registerTemplate(program) {
59
51
  const collision = await detectTemplateCollision(name, targetPath);
60
52
  if (collision && !options.overwrite) {
61
53
  const rel = path.relative(process.cwd(), collision) || collision;
62
- if (json || isNonInteractive({json})) {
63
- const msg =
64
- `Refusing to overwrite existing file ${rel}. ` +
65
- `Re-run with --overwrite (or -f) to replace it.`;
66
- cliError(msg, {code: ERROR_CODES.ERR_FILE_EXISTS});
67
- return;
68
- }
69
- const confirmed = isCancel(
70
- await p.confirm({
71
- message: `Overwrite existing file ${rel}?`,
72
- initialValue: false,
73
- }),
74
- );
75
- if (!confirmed) {
76
- humanLog('Aborted. Re-run with --overwrite to replace the file.');
77
- return;
78
- }
54
+ const msg =
55
+ `Refusing to overwrite existing file ${rel}. ` +
56
+ `Re-run with --overwrite (or -f) to replace it.`;
57
+ cliError(msg, {code: ERROR_CODES.ERR_FILE_EXISTS});
58
+ return;
79
59
  }
80
60
  }
81
61
 
@@ -120,10 +100,10 @@ export function registerTemplate(program) {
120
100
  for (const t of blocks) renderEntry(t);
121
101
  }
122
102
  humanLog('\nUsage:');
123
- humanLog(' astryx template <id> [target-path] Scaffold page or block');
124
- humanLog(' astryx template <id> --skeleton Layout reference');
125
- humanLog(' astryx template --list --type block List only blocks');
126
- humanLog(' astryx template --list --package <pkg> List from one package\n');
103
+ humanLog(` ${run} template <id> [target-path] Scaffold page or block`);
104
+ humanLog(` ${run} template <id> --skeleton Layout reference`);
105
+ humanLog(` ${run} template --list --type block List only blocks`);
106
+ humanLog(` ${run} template --list --package <pkg> List from one package\n`);
127
107
  break;
128
108
  }
129
109
 
@@ -37,7 +37,7 @@ import * as fs from 'node:fs';
37
37
  import * as path from 'node:path';
38
38
  import {execFile} from 'node:child_process';
39
39
  import {promisify} from 'node:util';
40
- import * as p from '@clack/prompts';
40
+ import * as p from '../lib/term-log.mjs';
41
41
  import {ensureJscodeshift} from '../codemods/ensure-jscodeshift.mjs';
42
42
  import {getTransformsBetween, latestVersion} from '../codemods/registry.mjs';
43
43
  import {runCodemods} from '../codemods/runner.mjs';
@@ -47,7 +47,7 @@ import {
47
47
  } from '../codemods/integration-discovery.mjs';
48
48
  import {runIntegrationCodemods} from '../codemods/integration-runner.mjs';
49
49
  import {installAgentDocs, discoverAgentDocs} from './agent-docs.mjs';
50
- import {getRunPrefix} from '../utils/package-manager.mjs';
50
+ import {getCliInvocation, formatCliCommand} from '../utils/package-manager.mjs';
51
51
  import {isValidSemver, semverGte} from '../utils/semver.mjs';
52
52
  import {jsonOut, jsonError} from '../lib/json.mjs';
53
53
  import {Project} from '../lib/project.mjs';
@@ -176,7 +176,7 @@ export function registerUpgrade(program) {
176
176
 
177
177
  if (!options.list && !options.from) {
178
178
  const msg =
179
- 'Missing required --from. Install the target version first, then run `astryx upgrade --from <old-version>`.';
179
+ `Missing required --from. Install the target version first, then run \`${getCliInvocation()} upgrade --from <old-version>\`.`;
180
180
  if (json)
181
181
  return jsonError(msg, undefined, ERROR_CODES.ERR_INVALID_ARGUMENT);
182
182
  p.log.error(msg);
@@ -237,7 +237,7 @@ export function registerUpgrade(program) {
237
237
  const installed = detectInstalledTargetVersion();
238
238
  if (!installed) {
239
239
  const msg =
240
- 'Could not find installed @astryxdesign/core (or legacy @xds/core). Install the target version first, then rerun `astryx upgrade --from <old-version>`.';
240
+ `Could not find installed @astryxdesign/core (or legacy @xds/core). Install the target version first, then rerun \`${getCliInvocation()} upgrade --from <old-version>\`.`;
241
241
  if (json)
242
242
  return jsonError(msg, undefined, ERROR_CODES.ERR_VERSION_DETECT);
243
243
  p.log.error(msg);
@@ -390,6 +390,9 @@ export function registerUpgrade(program) {
390
390
  const codemodFlags = coreConfigCodemodNames
391
391
  .map(name => `--codemod ${name}`)
392
392
  .join(' ');
393
+ // Canonical (bare) form — this is a structured, machine-executable
394
+ // field in the --json envelope. The human print below is made
395
+ // install-aware via formatCliCommand.
393
396
  const suggestedCommand = `astryx upgrade --from ${currentVersion} ${codemodFlags} --apply`;
394
397
  const guidance =
395
398
  'Your astryx.config currently fails strict validation, but a pending ' +
@@ -409,7 +412,7 @@ export function registerUpgrade(program) {
409
412
  });
410
413
  }
411
414
  p.log.warn(guidance);
412
- p.log.info(` ${suggestedCommand}`);
415
+ p.log.info(` ${formatCliCommand(suggestedCommand)}`);
413
416
  p.log.info(
414
417
  'Integrations are skipped in this preview; they will be processed on the --apply run.',
415
418
  );
@@ -619,7 +622,7 @@ export function registerUpgrade(program) {
619
622
  } catch {
620
623
  if (!json) {
621
624
  p.log.warn(
622
- `Could not update agent docs. Run \`${getRunPrefix()} astryx init --features agents\` to update manually.`,
625
+ `Could not update agent docs. Run \`${getCliInvocation()} init --features agents\` to update manually.`,
623
626
  );
624
627
  }
625
628
  }
@@ -24,7 +24,7 @@ beforeEach(() => {
24
24
  logCalls.push(args.join(' '));
25
25
  });
26
26
  vi.spyOn(console, 'error').mockImplementation(() => {});
27
- // @clack/prompts writes directly to process.stdout — capture that too.
27
+ // Some human logs are written straight to process.stdout — capture that too.
28
28
  vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
29
29
  stdoutCalls.push(typeof chunk === 'string' ? chunk : chunk.toString());
30
30
  return true;
package/src/config.mjs CHANGED
@@ -1,18 +1,9 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * Type-preserving helper for the Astryx config file.
5
- *
6
- * This is an intentionally tiny runtime identity function: it returns its
7
- * argument unchanged. Its value is the exported TypeScript surface from
8
- * `@astryxdesign/cli/config`, so config files get editor/type feedback without
9
- * coupling to CLI internals. Validation is NOT performed here — it happens at
10
- * the load boundary (see `loadModuleWithSchema` + `AstryxConfigSchema`).
11
- *
12
- * @template {import('./types/config').AstryxConfig} T
13
- * @param {T} config
14
- * @returns {T}
4
+ * Re-export of the config-authoring helper, which now lives in
5
+ * `@astryxdesign/core/config` so an app's config file gets type feedback
6
+ * without depending on the CLI. Kept here so existing
7
+ * `@astryxdesign/cli/config` imports continue to work unchanged.
15
8
  */
16
- export function createConfig(config) {
17
- return config;
18
- }
9
+ export {createConfig} from '@astryxdesign/core/config';
package/src/doc.mjs ADDED
@@ -0,0 +1,27 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Doc-authoring API (public `@astryxdesign/cli/doc`).
5
+ *
6
+ * The `createComponentDoc`/`createFunctionDoc`/`createDoc` authoring helpers now
7
+ * live in `@astryxdesign/core/authoring` and are re-exported here so existing
8
+ * `@astryxdesign/cli/doc` imports keep working. The Zod load-boundary schemas
9
+ * live in `./schemas/doc-schema.mjs` (core-free) and are re-exported here for
10
+ * back-compat; internal hot-path code imports them from the schema module
11
+ * directly so it never depends on core's built `dist/`.
12
+ */
13
+
14
+ export {
15
+ createComponentDoc,
16
+ createFunctionDoc,
17
+ createDoc,
18
+ } from '@astryxdesign/core/authoring';
19
+
20
+ export {
21
+ ComponentDocKindSchema,
22
+ FunctionDocKindSchema,
23
+ GenericDocKindSchema,
24
+ StampedDocSchema,
25
+ LegacyDocSchema,
26
+ ComponentDocSchema,
27
+ } from './schemas/doc-schema.mjs';