@astryxdesign/cli 0.1.7 → 0.1.8-canary.0c4d8d7

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 (134) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +115 -19
  3. package/docs/cli-integrations.doc.mjs +150 -0
  4. package/docs/elevation.doc.mjs +79 -1
  5. package/docs/getting-started.doc.mjs +9 -9
  6. package/docs/migration.doc.mjs +18 -18
  7. package/docs/principles.doc.dense.mjs +1 -1
  8. package/docs/principles.doc.mjs +6 -6
  9. package/docs/principles.doc.zh.mjs +1 -1
  10. package/docs/styling-libraries.doc.mjs +3 -3
  11. package/docs/styling.doc.mjs +4 -4
  12. package/docs/theme.doc.dense.mjs +2 -2
  13. package/docs/theme.doc.mjs +7 -7
  14. package/docs/theme.doc.zh.mjs +1 -1
  15. package/docs/tokens.doc.mjs +1 -1
  16. package/docs/working-with-ai.doc.mjs +19 -19
  17. package/package.json +13 -11
  18. package/scripts/postinstall.mjs +74 -0
  19. package/src/api/doctor.mjs +3 -3
  20. package/src/api/error.mjs +2 -2
  21. package/src/codemods/__tests__/registry.test.mjs +1 -0
  22. package/src/codemods/ensure-jscodeshift.mjs +11 -27
  23. package/src/codemods/registry.mjs +1 -0
  24. package/src/codemods/run-codemod.mjs +1 -1
  25. package/src/codemods/runner.mjs +2 -2
  26. package/src/codemods/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
  27. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
  28. package/src/codemods/transforms/v0.1.0/drop-xds-prefix-imports.mjs +102 -3
  29. package/src/codemods/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +72 -6
  30. package/src/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
  31. package/src/codemods/transforms/v0.1.8/index.mjs +19 -0
  32. package/src/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +234 -0
  33. package/src/commands/agent-docs.mjs +136 -20
  34. package/src/commands/agent-docs.test.mjs +123 -10
  35. package/src/commands/build-theme.mjs +10 -71
  36. package/src/commands/build.mjs +15 -15
  37. package/src/commands/cli-postinstall.test.mjs +42 -0
  38. package/src/commands/component/index.mjs +4 -4
  39. package/src/commands/discover.mjs +7 -5
  40. package/src/commands/docs.mjs +4 -4
  41. package/src/commands/hook/index.mjs +4 -4
  42. package/src/commands/init.mjs +48 -152
  43. package/src/commands/init.next-steps.test.mjs +1 -1
  44. package/src/commands/interactive-guard.test.mjs +19 -22
  45. package/src/commands/json-contract.test.mjs +2 -2
  46. package/src/commands/layout.mjs +1 -1
  47. package/src/commands/search.mjs +4 -4
  48. package/src/commands/setup-nudge.test.mjs +108 -0
  49. package/src/commands/swizzle.mjs +12 -35
  50. package/src/commands/template.mjs +11 -31
  51. package/src/commands/upgrade.mjs +138 -32
  52. package/src/commands/upgrade.test.mjs +155 -1
  53. package/src/index.mjs +40 -6
  54. package/src/lib/cli-error.mjs +2 -2
  55. package/src/lib/component-format.mjs +2 -1
  56. package/src/lib/json-shim.mjs +1 -1
  57. package/src/lib/json.mjs +3 -3
  58. package/src/lib/term-log.mjs +48 -0
  59. package/src/types/api.d.ts +4 -9
  60. package/src/types/base.d.ts +24 -3
  61. package/src/types/build.d.ts +23 -0
  62. package/src/types/index.d.ts +1 -0
  63. package/src/types/swizzle.d.ts +4 -0
  64. package/src/types/template-api.d.ts +4 -1
  65. package/src/types/upgrade.d.ts +39 -2
  66. package/src/utils/package-manager.mjs +108 -4
  67. package/src/utils/package-manager.test.mjs +108 -1
  68. package/src/utils/path-safety.mjs +0 -18
  69. package/src/utils/update-check.mjs +5 -4
  70. package/src/utils/update-check.test.mjs +3 -3
  71. package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
  72. package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
  73. package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
  74. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -4
  75. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
  76. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
  77. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
  78. package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
  79. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
  80. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
  81. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
  82. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
  83. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
  84. package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
  85. package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
  86. package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
  87. package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
  88. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
  89. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
  90. package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
  91. package/templates/blocks/components/Card/CardElevations.tsx +32 -0
  92. package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
  93. package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
  94. package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
  95. package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
  96. package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
  97. package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
  98. package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
  99. package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
  100. package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
  101. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
  102. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
  103. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
  104. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
  105. package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
  106. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
  107. package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
  108. package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
  109. package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
  110. package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
  111. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
  112. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
  113. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
  114. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
  115. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
  116. package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
  117. package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
  118. package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
  119. package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
  120. package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
  121. package/templates/blocks/components/Thumbnail/ThumbnailElevated.doc.mjs +14 -0
  122. package/templates/blocks/components/Thumbnail/ThumbnailElevated.tsx +31 -0
  123. package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
  124. package/templates/pages/ai-chat/page.tsx +4 -4
  125. package/templates/pages/dashboard-portfolio/page.tsx +3 -11
  126. package/templates/pages/detail-page/page.tsx +5 -12
  127. package/templates/pages/documentation-design/page.tsx +1 -1
  128. package/templates/pages/messaging-shell/page.tsx +6 -8
  129. package/templates/pages/table-grouped/page.tsx +9 -14
  130. package/templates/pages/table-page/page.tsx +7 -9
  131. package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
  132. package/docs/integration-authoring.md +0 -105
  133. package/src/utils/interactive.mjs +0 -76
  134. package/src/utils/interactive.test.mjs +0 -70
@@ -8,8 +8,8 @@
8
8
  * - An updated JS module that references the built className
9
9
  *
10
10
  * Usage:
11
- * npx astryx theme build ./src/themes/ocean.ts
12
- * npx astryx theme build ./src/themes/ocean.ts --out ./dist/ocean.css
11
+ * astryx theme build ./src/themes/ocean.ts
12
+ * astryx theme build ./src/themes/ocean.ts --out ./dist/ocean.css
13
13
  */
14
14
 
15
15
  import * as fs from 'node:fs';
@@ -17,16 +17,15 @@ import * as path from 'node:path';
17
17
  import {pathToFileURL, fileURLToPath} from 'node:url';
18
18
  import {spawn} from 'node:child_process';
19
19
  import {createJiti} from 'jiti';
20
- import {getRunPrefix} from '../utils/package-manager.mjs';
20
+ import {getCliInvocation} from '../utils/package-manager.mjs';
21
21
  import {
22
22
  sanitizeName,
23
23
  PathSafetyError,
24
- isNonInteractive,
25
24
  } from '../utils/path-safety.mjs';
26
25
  import {jsonOut, humanLog} from '../lib/json.mjs';
27
26
  import {cliError} from '../lib/cli-error.mjs';
28
27
  import {ERROR_CODES} from '../lib/error-codes.mjs';
29
- import {themeAdd, listThemes} from '../api/theme-add.mjs';
28
+ import {themeAdd} from '../api/theme-add.mjs';
30
29
 
31
30
  // Import shared theme processing from core. `astryx theme build` MUST produce the
32
31
  // exact same CSS as the `<Theme>` runtime, so it has exactly one generation
@@ -500,7 +499,7 @@ function generateBuiltModule(themeDef, iconInfo) {
500
499
  .join('\n');
501
500
 
502
501
  return `${iconImport}/**
503
- * ${themeDef.name} theme — built by \`${getRunPrefix()} astryx theme build\`
502
+ * ${themeDef.name} theme — built by \`${getCliInvocation()} theme build\`
504
503
  * Import the CSS file alongside this module:
505
504
  *
506
505
  * import { ${toIdentifier(themeDef.name)}Theme } from './${themeDef.name}';
@@ -1130,7 +1129,7 @@ Or with a <link> tag:
1130
1129
  if (t.description) humanLog(` ${t.description}`);
1131
1130
  }
1132
1131
  humanLog('\nUsage:');
1133
- humanLog(' astryx theme add <slug> [target-path] Scaffold a theme file you own\n');
1132
+ humanLog(` ${getCliInvocation()} theme add <slug> [target-path] Scaffold a theme file you own\n`);
1134
1133
  });
1135
1134
 
1136
1135
  theme
@@ -1141,32 +1140,9 @@ Or with a <link> tag:
1141
1140
  .action(async (slug, targetPath, options) => {
1142
1141
  const json = program.opts().json || false;
1143
1142
 
1144
- // Only prompt with a real TTY on stdin a piped/redirected stdin would
1145
- // make clack hang. Non-interactive callers fall through to the API's
1146
- // ERR_FILE_EXISTS guard.
1147
- const interactive =
1148
- !json && !isNonInteractive({json}) && Boolean(process.stdin.isTTY);
1149
- if (slug && !options.list && !options.overwrite && interactive) {
1150
- const collision = await detectThemeCollision(slug, targetPath);
1151
- if (collision) {
1152
- const rel = path.relative(process.cwd(), collision) || collision;
1153
- const p = await import('@clack/prompts');
1154
- const confirmed = await p.confirm({
1155
- message: `Overwrite existing file ${rel}?`,
1156
- initialValue: false,
1157
- });
1158
- if (p.isCancel(confirmed)) {
1159
- p.cancel('Cancelled.');
1160
- return;
1161
- }
1162
- if (!confirmed) {
1163
- humanLog('Aborted. Re-run with --overwrite to replace the file.');
1164
- return;
1165
- }
1166
- options.overwrite = true;
1167
- }
1168
- }
1169
-
1143
+ // The CLI is non-interactive: never prompt to confirm an overwrite.
1144
+ // Existing files require an explicit --overwrite; otherwise themeAdd's
1145
+ // ERR_FILE_EXISTS guard rejects the write.
1170
1146
  let result;
1171
1147
  try {
1172
1148
  result = await themeAdd(slug, {
@@ -1191,7 +1167,7 @@ Or with a <link> tag:
1191
1167
  if (t.description) humanLog(` ${t.description}`);
1192
1168
  }
1193
1169
  humanLog('\nUsage:');
1194
- humanLog(' astryx theme add <slug> [target-path] Scaffold a theme file you own\n');
1170
+ humanLog(` ${getCliInvocation()} theme add <slug> [target-path] Scaffold a theme file you own\n`);
1195
1171
  return;
1196
1172
  }
1197
1173
 
@@ -1219,40 +1195,3 @@ This is your copy of the ${displayName} theme — edit ${entry} to make it your
1219
1195
  });
1220
1196
  }
1221
1197
 
1222
- /**
1223
- * First existing file that scaffolding <slug> into <targetPath> would clobber,
1224
- * or null. Used to prompt before invoking the API; the API re-validates and
1225
- * owns any authoritative error.
1226
- *
1227
- * @param {string} slug
1228
- * @param {string} [targetPath]
1229
- * @returns {Promise<string|null>}
1230
- */
1231
- async function detectThemeCollision(slug, targetPath) {
1232
- let themes;
1233
- try {
1234
- themes = listThemes();
1235
- } catch {
1236
- return null;
1237
- }
1238
- const match = themes.find(t => t.slug.toLowerCase() === slug.toLowerCase());
1239
- if (!match) return null;
1240
-
1241
- const rawTarget = targetPath || path.join('src', 'themes', match.slug);
1242
- let resolvedDir;
1243
- try {
1244
- // Fail soft (null) on traversal; the API surfaces the real error.
1245
- const {assertWithin} = await import('../utils/path-safety.mjs');
1246
- resolvedDir = assertWithin(rawTarget, process.cwd(), {
1247
- label: 'theme target path',
1248
- });
1249
- } catch {
1250
- return null;
1251
- }
1252
-
1253
- for (const name of match.files) {
1254
- const dest = path.join(resolvedDir, name);
1255
- if (fs.existsSync(dest)) return dest;
1256
- }
1257
- return null;
1258
- }
@@ -15,7 +15,7 @@
15
15
  * the whole CLI, use `astryx search <query>` instead.
16
16
  */
17
17
 
18
- import {getRunPrefix} from '../utils/package-manager.mjs';
18
+ import {getCliInvocation, formatCliCommand} from '../utils/package-manager.mjs';
19
19
  import {jsonOut, humanLog} from '../lib/json.mjs';
20
20
  import {cliError} from '../lib/cli-error.mjs';
21
21
  import {search as searchApi} from '../api/search.mjs';
@@ -47,25 +47,25 @@ function printPlaybook(run) {
47
47
  'How to build a page with Astryx',
48
48
  '',
49
49
  "1. Find a starting point for what you're building:",
50
- ` ${run} astryx build "<what you're building>"`,
50
+ ` ${run} build "<what you're building>"`,
51
51
  ' → returns the closest [page] template, the [block]s that cover parts,',
52
52
  ' and the [component]s to fill the gaps, with a "Compose:" suggestion.',
53
53
  '',
54
54
  '2. If a [page] template matches → scaffold it and adapt:',
55
- ` ${run} astryx template <name> [path]`,
55
+ ` ${run} template <name> [path]`,
56
56
  '',
57
57
  '3. If nothing matches exactly → compose:',
58
- ` ${run} astryx template <name> --skeleton # study a close page's layout`,
59
- ` ${run} astryx template <BlockName> # drop in each block from the kit`,
60
- ` ${run} astryx component <Name> # fill remaining gaps (read props)`,
58
+ ` ${run} template <name> --skeleton # study a close page's layout`,
59
+ ` ${run} template <BlockName> # drop in each block from the kit`,
60
+ ` ${run} component <Name> # fill remaining gaps (read props)`,
61
61
  '',
62
62
  '4. Rules (keep it on-system):',
63
63
  ' - No <div>/raw HTML for layout — use VStack/HStack/Grid/Stack/Card etc.',
64
- ' - No style={{}} — use component props; design tokens via `astryx docs tokens`.',
64
+ ` - No style={{}} — use component props; design tokens via \`${run} docs tokens\`.`,
65
65
  ' - Wrap the app in <Theme theme={...}> and import core reset.css + astryx.css.',
66
66
  '',
67
- `Tip: \`${run} astryx build "<idea>"\` is the fastest way in. For a neutral`,
68
- `lookup of any component/doc/template, use \`${run} astryx search <query>\`.`,
67
+ `Tip: \`${run} build "<idea>"\` is the fastest way in. For a neutral`,
68
+ `lookup of any component/doc/template, use \`${run} search <query>\`.`,
69
69
  '',
70
70
  ];
71
71
  for (const l of lines) humanLog(l);
@@ -79,7 +79,7 @@ export function registerBuild(program) {
79
79
  .option('--limit <n>', 'Max candidates to draw from (default 60)')
80
80
  .option('--detail', 'Verbose output (include import paths and match reason)')
81
81
  .action(async (query, options) => {
82
- const run = getRunPrefix();
82
+ const run = getCliInvocation();
83
83
  const json = program.opts().json || false;
84
84
 
85
85
  // No query → print the playbook (the "how to build" skill).
@@ -115,7 +115,7 @@ export function registerBuild(program) {
115
115
  if (results.length === 0) {
116
116
  humanLog('');
117
117
  humanLog(`No matches for "${q}".`);
118
- humanLog(`Try a broader term, or browse: ${run} astryx component --list`);
118
+ humanLog(`Try a broader term, or browse: ${run} component --list`);
119
119
  humanLog('');
120
120
  return;
121
121
  }
@@ -138,7 +138,7 @@ export function registerBuild(program) {
138
138
  humanLog('');
139
139
  humanLog(` [${label}] ${display}`);
140
140
  if (r.description) humanLog(` ${r.description}`);
141
- humanLog(` → ${run} ${r.command}`);
141
+ humanLog(` → ${formatCliCommand(r.command)}`);
142
142
  if (options.detail) {
143
143
  if (r.import) humanLog(` import: ${r.import}`);
144
144
  humanLog(` match: ${r.reason} (score ${r.score})`);
@@ -151,9 +151,9 @@ export function registerBuild(program) {
151
151
  // START — the single recommended path.
152
152
  humanLog('');
153
153
  if (directMatch) {
154
- humanLog(`START → Scaffold the \`${pages[0].name}\` page template, then adapt: ${run} astryx template ${pages[0].name} ./src/App.tsx`);
154
+ humanLog(`START → Scaffold the \`${pages[0].name}\` page template, then adapt: ${run} template ${pages[0].name} ./src/App.tsx`);
155
155
  } else if (pages.length) {
156
- humanLog(`START → No exact page template. Use \`${pages[0].name}\` as a layout reference (${run} astryx template ${pages[0].name} --skeleton) and compose the pieces below.`);
156
+ humanLog(`START → No exact page template. Use \`${pages[0].name}\` as a layout reference (${run} template ${pages[0].name} --skeleton) and compose the pieces below.`);
157
157
  } else {
158
158
  humanLog(`START → No page template fits. Frame with AppShell and compose the blocks + components below.`);
159
159
  }
@@ -168,7 +168,7 @@ export function registerBuild(program) {
168
168
  // FRAME — always (the page shell).
169
169
  humanLog('');
170
170
  humanLog(`FRAME — page shell (always): ${FRAME.join(', ')}`);
171
- humanLog(` full-page → AppShell; or Layout + SideNav/TopNav. ${run} astryx component AppShell`);
171
+ humanLog(` full-page → AppShell; or Layout + SideNav/TopNav. ${run} component AppShell`);
172
172
 
173
173
  // BLOCKS — idea-specific composed patterns.
174
174
  if (blocks.length) {
@@ -0,0 +1,42 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Guardrail tests for the @astryxdesign/cli postinstall nudge (layer 2).
5
+ *
6
+ * Tests the pure decision matrix (shouldNudge) — nudges for a real dependency
7
+ * install when not set up; stays quiet in the monorepo/source, during npx's
8
+ * transient fetch (path _npx or npm_command=exec), and once set up.
9
+ */
10
+
11
+ import {describe, it, expect} from 'vitest';
12
+ import {shouldNudge} from '../../scripts/postinstall.mjs';
13
+
14
+ const DEP = '/proj/node_modules/@astryxdesign/cli/scripts/postinstall.mjs'; // real dep install
15
+ const NPX = '/Users/x/.npm/_npx/a1b2/node_modules/@astryxdesign/cli/scripts/postinstall.mjs';
16
+ const REPO = '/repo/packages/cli/scripts/postinstall.mjs'; // monorepo/source
17
+
18
+ describe('cli postinstall — shouldNudge', () => {
19
+ it('nudges for a real dependency install when not set up', () => {
20
+ expect(shouldNudge({scriptPath: DEP, npmCommand: 'install', isSetUp: false})).toBe(true);
21
+ });
22
+
23
+ it('quiet in the monorepo/source (not under node_modules)', () => {
24
+ expect(shouldNudge({scriptPath: REPO, npmCommand: 'install', isSetUp: false})).toBe(false);
25
+ });
26
+
27
+ it('quiet during npx transient install (path contains _npx)', () => {
28
+ expect(shouldNudge({scriptPath: NPX, npmCommand: 'install', isSetUp: false})).toBe(false);
29
+ });
30
+
31
+ it('quiet during npx (npm_command=exec) — avoids double-nudge before init', () => {
32
+ expect(shouldNudge({scriptPath: DEP, npmCommand: 'exec', isSetUp: false})).toBe(false);
33
+ });
34
+
35
+ it('quiet once the project is already set up', () => {
36
+ expect(shouldNudge({scriptPath: DEP, npmCommand: 'install', isSetUp: true})).toBe(false);
37
+ });
38
+
39
+ it('quiet with no script path (defensive)', () => {
40
+ expect(shouldNudge({})).toBe(false);
41
+ });
42
+ });
@@ -18,7 +18,7 @@ import {
18
18
  formatBriefAll,
19
19
  } from '../../lib/component-format.mjs';
20
20
  import {resolveTheme} from '../../lib/resolve-theme.mjs';
21
- import {getRunPrefix} from '../../utils/package-manager.mjs';
21
+ import {getCliInvocation} from '../../utils/package-manager.mjs';
22
22
  import {jsonOut, humanLog} from '../../lib/json.mjs';
23
23
  import {cliError} from '../../lib/cli-error.mjs';
24
24
  import {ERROR_CODES} from '../../lib/error-codes.mjs';
@@ -39,7 +39,7 @@ export function registerComponent(program) {
39
39
  .option('--blocks', 'List example blocks: showcase, examples, and related')
40
40
  .option('--package <name>', 'Scope lookup to an external package (e.g. @acme/xds-widgets)')
41
41
  .action(async (name, options) => {
42
- const run = getRunPrefix();
42
+ const run = getCliInvocation();
43
43
  const zh = program.opts().zh || false;
44
44
  const dense = program.opts().dense || false;
45
45
  const lang = program.opts().lang || null;
@@ -142,7 +142,7 @@ export function registerComponent(program) {
142
142
  }
143
143
  humanLog('');
144
144
  humanLog(`Import from the path shown (e.g. import {Button} from '@astryxdesign/core/Button')`);
145
- humanLog(`Usage: ${run} astryx component <name>`);
145
+ humanLog(`Usage: ${run} component <name>`);
146
146
  humanLog('');
147
147
  }
148
148
  break;
@@ -165,7 +165,7 @@ export function registerComponent(program) {
165
165
  humanLog('');
166
166
  }
167
167
  humanLog(`Import from the path shown (e.g. import {Button} from '@astryxdesign/core/Button')`);
168
- humanLog(`Usage: ${run} astryx component <name>`);
168
+ humanLog(`Usage: ${run} component <name>`);
169
169
  humanLog('');
170
170
  break;
171
171
  }
@@ -14,6 +14,7 @@ import {formatFull, formatBrief, formatCompact} from '../lib/component-format.mj
14
14
  import {jsonOut, humanLog} from '../lib/json.mjs';
15
15
  import {cliError} from '../lib/cli-error.mjs';
16
16
  import {discover as discoverApi} from '../api/discover.mjs';
17
+ import {getCliInvocation} from '../utils/package-manager.mjs';
17
18
 
18
19
  export function registerDiscover(program) {
19
20
  program
@@ -25,6 +26,7 @@ export function registerDiscover(program) {
25
26
  const json = program.opts().json || false;
26
27
  const lang = program.opts().lang || null;
27
28
  const zh = program.opts().zh || false;
29
+ const run = getCliInvocation();
28
30
 
29
31
  let result;
30
32
  try {
@@ -80,9 +82,9 @@ export function registerDiscover(program) {
80
82
  humanLog('');
81
83
  }
82
84
  humanLog('Usage:');
83
- humanLog(' astryx discover <package> Browse a package');
84
- humanLog(' astryx discover <package>/Component View component docs');
85
- humanLog(' astryx discover <search> Search all packages');
85
+ humanLog(` ${run} discover <package> Browse a package`);
86
+ humanLog(` ${run} discover <package>/Component View component docs`);
87
+ humanLog(` ${run} discover <search> Search all packages`);
86
88
  humanLog('');
87
89
  }
88
90
  break;
@@ -99,7 +101,7 @@ export function registerDiscover(program) {
99
101
  humanLog('');
100
102
  for (const comp of result.data.components) humanLog(' ' + comp);
101
103
  humanLog('');
102
- humanLog('Usage: astryx discover ' + result.data.name + '/<ComponentName>');
104
+ humanLog(`Usage: ${run} discover ` + result.data.name + '/<ComponentName>');
103
105
  humanLog('');
104
106
  break;
105
107
  }
@@ -122,7 +124,7 @@ export function registerDiscover(program) {
122
124
  humanLog('Found ' + result.data.matches.length + ' matches for "' + result.data.query + '":');
123
125
  humanLog('');
124
126
  for (const m of result.data.matches) {
125
- humanLog(' astryx discover ' + m.package + '/' + m.component);
127
+ humanLog(` ${run} discover ` + m.package + '/' + m.component);
126
128
  }
127
129
  humanLog('');
128
130
  break;
@@ -12,7 +12,7 @@
12
12
  * astryx docs <topic> <section> Print one section
13
13
  */
14
14
 
15
- import {getRunPrefix} from '../utils/package-manager.mjs';
15
+ import {getCliInvocation} from '../utils/package-manager.mjs';
16
16
  import {jsonOut, humanLog} from '../lib/json.mjs';
17
17
  import {cliError} from '../lib/cli-error.mjs';
18
18
  import {docs as docsApi} from '../api/docs.mjs';
@@ -105,7 +105,7 @@ export function registerDocs(program) {
105
105
  .command('docs [topic] [section]')
106
106
  .description('Print reference docs')
107
107
  .action(async (topic, section) => {
108
- const run = getRunPrefix();
108
+ const run = getCliInvocation();
109
109
  const lang = program.opts().lang || null;
110
110
  const zh = program.opts().zh || false;
111
111
  const dense = program.opts().dense || false;
@@ -130,8 +130,8 @@ export function registerDocs(program) {
130
130
  for (const entry of result.data) {
131
131
  humanLog(` ${entry.topic.padEnd(14)} ${entry.description}`);
132
132
  }
133
- humanLog(`\nUsage: ${run} astryx docs <topic>`);
134
- humanLog(` ${run} astryx docs <topic> <section>\n`);
133
+ humanLog(`\nUsage: ${run} docs <topic>`);
134
+ humanLog(` ${run} docs <topic> <section>\n`);
135
135
  break;
136
136
  }
137
137
 
@@ -12,7 +12,7 @@ import {
12
12
  formatHookBrief,
13
13
  formatHookParams,
14
14
  } from '../../lib/hook-format.mjs';
15
- import {getRunPrefix} from '../../utils/package-manager.mjs';
15
+ import {getCliInvocation} from '../../utils/package-manager.mjs';
16
16
  import {jsonOut, humanLog} from '../../lib/json.mjs';
17
17
  import {cliError} from '../../lib/cli-error.mjs';
18
18
  import {ERROR_CODES} from '../../lib/error-codes.mjs';
@@ -27,7 +27,7 @@ export function registerHook(program) {
27
27
  .option('--category <category>', 'List hooks in a specific category')
28
28
  .option('--params', 'Print only the parameters table')
29
29
  .action(async (name, options) => {
30
- const run = getRunPrefix();
30
+ const run = getCliInvocation();
31
31
  const zh = program.opts().zh || false;
32
32
  const lang = program.opts().lang || null;
33
33
  const detailSource = program.getOptionValueSource('detail');
@@ -76,7 +76,7 @@ export function registerHook(program) {
76
76
  for (const h of hookNames) humanLog(` ${h}`);
77
77
  }
78
78
  humanLog('');
79
- humanLog(`Usage: ${run} astryx hook <name>`);
79
+ humanLog(`Usage: ${run} hook <name>`);
80
80
  humanLog('');
81
81
  }
82
82
  break;
@@ -93,7 +93,7 @@ export function registerHook(program) {
93
93
  }
94
94
  humanLog('');
95
95
  }
96
- humanLog(`Usage: ${run} astryx hook <name>`);
96
+ humanLog(`Usage: ${run} hook <name>`);
97
97
  humanLog('');
98
98
  break;
99
99
  }