@astryxdesign/cli 0.1.7-canary.c0ff997 → 0.1.7-canary.cbfb48e

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 (53) hide show
  1. package/docs/working-with-ai.doc.mjs +2 -2
  2. package/package.json +9 -9
  3. package/src/codemods/__tests__/registry.test.mjs +0 -1
  4. package/src/codemods/registry.mjs +0 -1
  5. package/src/codemods/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +7 -42
  6. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +0 -43
  7. package/src/codemods/transforms/v0.1.0/drop-xds-prefix-imports.mjs +3 -102
  8. package/src/codemods/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +6 -72
  9. package/src/commands/agent-docs.mjs +6 -80
  10. package/src/commands/agent-docs.test.mjs +6 -112
  11. package/src/commands/interactive-guard.test.mjs +1 -1
  12. package/src/commands/json-contract.test.mjs +1 -1
  13. package/src/commands/upgrade.mjs +27 -130
  14. package/src/commands/upgrade.test.mjs +0 -154
  15. package/src/types/upgrade.d.ts +2 -39
  16. package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
  17. package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
  18. package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
  19. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -4
  20. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
  21. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
  22. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
  23. package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
  24. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
  25. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
  26. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
  27. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
  28. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
  29. package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
  30. package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
  31. package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
  32. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
  33. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
  34. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +9 -5
  35. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
  36. package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
  37. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
  38. package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
  39. package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
  40. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +6 -2
  41. package/templates/blocks/components/Stack/StackFillItem.tsx +6 -2
  42. package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
  43. package/templates/pages/ai-chat/page.tsx +4 -4
  44. package/templates/pages/dashboard-portfolio/page.tsx +11 -3
  45. package/templates/pages/detail-page/page.tsx +12 -5
  46. package/templates/pages/documentation-design/page.tsx +1 -1
  47. package/templates/pages/messaging-shell/page.tsx +8 -6
  48. package/templates/pages/table-grouped/page.tsx +14 -9
  49. package/templates/pages/table-page/page.tsx +9 -7
  50. package/templates/pages/table-page-heatmap-status/page.tsx +13 -5
  51. package/src/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +0 -161
  52. package/src/codemods/transforms/v0.1.8/index.mjs +0 -19
  53. package/src/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +0 -234
@@ -42,13 +42,13 @@ export const docs = {
42
42
  },
43
43
  {
44
44
  type: 'prose',
45
- text: 'By default this creates `AGENTS.md` (the tool-agnostic standard most agents read). To target a specific tool\'s file instead:',
45
+ text: 'If you prefer to target a specific file format:',
46
46
  },
47
47
  {
48
48
  type: 'code',
49
49
  lang: 'bash',
50
50
  label: 'Manual options',
51
- code: `npx @astryxdesign/cli init --features agents --agent claude # .claude/CLAUDE.md
51
+ code: `npx @astryxdesign/cli init --features agents --agent claude # CLAUDE.md
52
52
  npx @astryxdesign/cli init --features agents --agent cursor # .cursorrules
53
53
  npx @astryxdesign/cli init --features agents --agent codex # AGENTS.md (Copilot, Codex, etc.)`,
54
54
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.1.7-canary.c0ff997",
3
+ "version": "0.1.7-canary.cbfb48e",
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",
@@ -79,10 +79,10 @@
79
79
  "zod": "^4.4.3"
80
80
  },
81
81
  "peerDependencies": {
82
- "@astryxdesign/charts": "0.1.7-canary.c0ff997",
83
- "@astryxdesign/core": "0.1.7-canary.c0ff997",
84
- "@astryxdesign/lab": "0.1.7-canary.c0ff997",
85
- "@astryxdesign/theme-neutral": "0.1.7-canary.c0ff997",
82
+ "@astryxdesign/charts": "0.1.7-canary.cbfb48e",
83
+ "@astryxdesign/core": "0.1.7-canary.cbfb48e",
84
+ "@astryxdesign/lab": "0.1.7-canary.cbfb48e",
85
+ "@astryxdesign/theme-neutral": "0.1.7-canary.cbfb48e",
86
86
  "gpt-tokenizer": "^3.4.0"
87
87
  },
88
88
  "peerDependenciesMeta": {
@@ -100,10 +100,10 @@
100
100
  }
101
101
  },
102
102
  "devDependencies": {
103
- "@astryxdesign/charts": "0.1.7-canary.c0ff997",
104
- "@astryxdesign/core": "0.1.7-canary.c0ff997",
105
- "@astryxdesign/lab": "0.1.7-canary.c0ff997",
106
- "@astryxdesign/theme-neutral": "0.1.7-canary.c0ff997",
103
+ "@astryxdesign/charts": "0.1.7-canary.cbfb48e",
104
+ "@astryxdesign/core": "0.1.7-canary.cbfb48e",
105
+ "@astryxdesign/lab": "0.1.7-canary.cbfb48e",
106
+ "@astryxdesign/theme-neutral": "0.1.7-canary.cbfb48e",
107
107
  "gpt-tokenizer": "^3.4.0"
108
108
  },
109
109
  "scripts": {
@@ -21,7 +21,6 @@ describe('registry', () => {
21
21
  '0.1.3',
22
22
  '0.1.5',
23
23
  '0.1.7',
24
- '0.1.8',
25
24
  ]);
26
25
  });
27
26
  });
@@ -22,7 +22,6 @@ const registry = new Map([
22
22
  ['0.1.3', () => import('./transforms/v0.1.3/index.mjs')],
23
23
  ['0.1.5', () => import('./transforms/v0.1.5/index.mjs')],
24
24
  ['0.1.7', () => import('./transforms/v0.1.7/index.mjs')],
25
- ['0.1.8', () => import('./transforms/v0.1.8/index.mjs')],
26
25
  ]);
27
26
 
28
27
  // Re-export from the shared utility so registry callers and other consumers
@@ -166,50 +166,15 @@ describe('drop-xds-prefix-imports', () => {
166
166
  expect(output).toContain('export const other = Card;');
167
167
  });
168
168
 
169
- it('un-prefixes override keys inside an @xds/core mock factory', async () => {
169
+ it('un-prefixes normally when there is NO local collision', async () => {
170
170
  const input = [
171
- `vi.mock('@xds/core/Text', async orig => ({`,
172
- ` ...(await orig<typeof import('@xds/core/Text')>()),`,
173
- ` useXDSTruncation: () => ({ref: vi.fn(), isTruncated: true, fullText: ''}),`,
174
- `}));`,
175
- ].join('\n');
176
- const output = await applyTransform(input);
177
- expect(output).toContain('useTruncation:');
178
- expect(output).not.toContain('useXDSTruncation');
179
- // This codemod does not touch the module-path string (that is the
180
- // module-specifiers codemod's job); the @xds/core/Text path stays here.
181
- expect(output).toContain(`vi.mock('@xds/core/Text'`);
182
- });
183
-
184
- it('un-prefixes component override keys inside a bare @xds/core jest.mock factory', async () => {
185
- const input = [
186
- `jest.mock('@xds/core', () => ({`,
187
- ` XDSButton: () => null,`,
188
- ` useXDSToast: () => ({}),`,
189
- `}));`,
190
- ].join('\n');
191
- const output = await applyTransform(input);
192
- expect(output).toContain('Button:');
193
- expect(output).toContain('useToast:');
194
- expect(output).not.toContain('XDSButton');
195
- expect(output).not.toContain('useXDSToast');
196
- });
197
-
198
- it('does NOT touch mock factory keys for a non-@xds package', async () => {
199
- const input = [
200
- `vi.mock('some-other-pkg', () => ({`,
201
- ` useXDSFoo: () => 1,`,
202
- `}));`,
171
+ `import {XDSCodeBlock} from '@xds/core/CodeBlock';`,
172
+ `export const App = () => <XDSCodeBlock code="x" />;`,
203
173
  ].join('\n');
204
174
  const output = await applyTransform(input);
205
- expect(output).toBe(input);
206
- });
207
-
208
- it('does NOT touch useXDS keys in an unrelated object literal (not a mock factory)', async () => {
209
- const input = [`const config = {`, ` useXDSWhatever: true,`, `};`].join(
210
- '\n',
211
- );
212
- const output = await applyTransform(input);
213
- expect(output).toBe(input);
175
+ expect(output).toContain('{CodeBlock}');
176
+ expect(output).toContain('@xds/core/CodeBlock');
177
+ expect(output).toContain('<CodeBlock code="x" />');
178
+ expect(output).not.toContain('AstryxCodeBlock');
214
179
  });
215
180
  });
@@ -89,47 +89,4 @@ describe('migrate-xds-module-specifiers', () => {
89
89
  expect(output).not.toContain('defaultTheme');
90
90
  expect(output).not.toContain('neutralTheme as');
91
91
  });
92
-
93
- it('rewrites the mocked module path in vi.mock (including the inline import() type arg)', async () => {
94
- const input = [
95
- "vi.mock('@xds/core/Text', async orig => ({",
96
- " ...(await orig<typeof import('@xds/core/Text')>()),",
97
- '}));',
98
- ].join('\n');
99
- const output = await applyTransform(input);
100
- expect(output).toMatch(/vi\.mock\(['"]@astryxdesign\/core\/Text['"]/);
101
- // The inline dynamic import() type argument is rewritten too.
102
- expect(output).toMatch(/import\(['"]@astryxdesign\/core\/Text['"]\)/);
103
- expect(output).not.toContain('@xds/');
104
- });
105
-
106
- it('rewrites the mocked module path in jest.mock (bare @xds/core)', async () => {
107
- const output = await applyTransform(
108
- "jest.mock('@xds/core', () => ({}));",
109
- 'test.ts',
110
- );
111
- expect(output).toMatch(/jest\.mock\(['"]@astryxdesign\/core['"]/);
112
- expect(output).not.toContain('@xds/');
113
- });
114
-
115
- it('rewrites vi.doMock / jest.doMock and a bare mock() call', async () => {
116
- const output = await applyTransform(
117
- [
118
- "vi.doMock('@xds/lab/Thing', () => ({}));",
119
- "jest.doMock('@xds/core/Text', () => ({}));",
120
- "mock('@xds/core', () => ({}));",
121
- ].join('\n'),
122
- 'test.ts',
123
- );
124
- expect(output).toMatch(/vi\.doMock\(['"]@astryxdesign\/lab\/Thing['"]/);
125
- expect(output).toMatch(/jest\.doMock\(['"]@astryxdesign\/core\/Text['"]/);
126
- expect(output).toMatch(/[^.]mock\(['"]@astryxdesign\/core['"]/);
127
- expect(output).not.toContain('@xds/');
128
- });
129
-
130
- it('does NOT rewrite the mock path for a non-@xds package', async () => {
131
- const input = "vi.mock('some-other-pkg', () => ({useXDSFoo: () => 1}));";
132
- const output = await applyTransform(input);
133
- expect(output).toBe(input);
134
- });
135
92
  });
@@ -35,19 +35,11 @@
35
35
  * including type references in generic type-argument positions such as
36
36
  * `useMemo<XDSTableColumn<Issue>[]>(...)`
37
37
  * 3. Re-exports from @xds/core: export {XDSButton} from '@xds/core/Button'
38
- * 4. Object-property keys inside a test-framework mock factory for an
39
- * `@xds/core` module: the partial-mock override in
40
- * `vi.mock('@xds/core/Text', async orig => ({...await orig(),
41
- * useXDSTruncation: () => ...}))` must be un-prefixed to `useTruncation`,
42
- * otherwise the key targets a name the renamed module no longer exports and
43
- * the mock silently overrides nothing.
44
38
  *
45
39
  * Does NOT touch:
46
40
  * - import source paths (`@xds/core/Button` stays -- subpath dirs are unchanged
47
41
  * by the prefix migration)
48
42
  * - identifiers not bound to an @xds/core import
49
- * - object-property keys outside an `@xds/core` mock factory (an unrelated
50
- * `{useXDSFoo: ...}` literal, or a mock of some other package, is untouched)
51
43
  * - the `XDSBaseProps`-style names only when they are NOT imported from core
52
44
  */
53
45
 
@@ -56,8 +48,7 @@ export const meta = {
56
48
  description:
57
49
  'Rewrites @xds/core imports and their usages from the prefixed names ' +
58
50
  '(XDSButton, useXDSTheme, XDSIconRegistry, XDSButtonProps) to their bare ' +
59
- 'names (Button, useTheme, IconRegistry, ButtonProps), including override ' +
60
- 'keys in a vi.mock/jest.mock factory for an @xds/core module. Only renames ' +
51
+ 'names (Button, useTheme, IconRegistry, ButtonProps). Only renames ' +
61
52
  'bindings imported from @xds/core, leaving unrelated identifiers untouched.',
62
53
  pr: '#2880',
63
54
  };
@@ -83,81 +74,6 @@ function bareName(name) {
83
74
  return null;
84
75
  }
85
76
 
86
- // A test-framework mock of an `@xds/core` module (`vi.mock('@xds/core/Text',
87
- // factory)`). We only rewrite override keys inside such a factory, so scope the
88
- // detection tightly: callee must be `vi.mock`/`vi.doMock`/`jest.mock`/
89
- // `jest.doMock` (or a bare `mock`) AND the first argument must be a string
90
- // literal that resolves to `@xds/core` (bare or subpath).
91
- const MOCK_METHOD_NAMES = new Set(['mock', 'doMock']);
92
- const MOCK_OBJECT_NAMES = new Set(['vi', 'jest']);
93
-
94
- function isMockCallee(callee) {
95
- if (
96
- callee.type === 'MemberExpression' &&
97
- !callee.computed &&
98
- callee.object.type === 'Identifier' &&
99
- MOCK_OBJECT_NAMES.has(callee.object.name) &&
100
- callee.property.type === 'Identifier' &&
101
- MOCK_METHOD_NAMES.has(callee.property.name)
102
- ) {
103
- return true;
104
- }
105
- return callee.type === 'Identifier' && callee.name === 'mock';
106
- }
107
-
108
- function isXdsCoreMockCall(node) {
109
- if (node.type !== 'CallExpression' || !isMockCallee(node.callee))
110
- return false;
111
- const [arg] = node.arguments;
112
- const value =
113
- arg && (arg.type === 'StringLiteral' || arg.type === 'Literal')
114
- ? arg.value
115
- : null;
116
- return typeof value === 'string' && XDS_CORE_SOURCE.test(value);
117
- }
118
-
119
- // Rename XDS-prefixed object-property KEYS (not values, not nested objects)
120
- // within the given AST subtree. Used only on a recognized @xds/core mock
121
- // factory, so the scope guard lives at the call site.
122
- function renameMockFactoryKeys(node, seen, onChange) {
123
- if (!node || typeof node !== 'object') return;
124
- if (Array.isArray(node)) {
125
- for (const child of node) renameMockFactoryKeys(child, seen, onChange);
126
- return;
127
- }
128
- if (seen.has(node)) return;
129
- seen.add(node);
130
-
131
- if (
132
- (node.type === 'ObjectProperty' || node.type === 'Property') &&
133
- !node.computed &&
134
- node.key &&
135
- node.key.type === 'Identifier'
136
- ) {
137
- const bare = bareName(node.key.name);
138
- if (bare && bare !== node.key.name) {
139
- node.key.name = bare;
140
- onChange();
141
- }
142
- }
143
-
144
- for (const key of Object.keys(node)) {
145
- if (
146
- key === 'loc' ||
147
- key === 'start' ||
148
- key === 'end' ||
149
- key === 'range' ||
150
- key === 'comments' ||
151
- key === 'leadingComments' ||
152
- key === 'trailingComments' ||
153
- key === 'tokens'
154
- ) {
155
- continue;
156
- }
157
- renameMockFactoryKeys(node[key], seen, onChange);
158
- }
159
- }
160
-
161
77
  export default function transformer(file, api) {
162
78
  const j = api.jscodeshift;
163
79
  const root = j(file.source);
@@ -274,26 +190,11 @@ export default function transformer(file, api) {
274
190
  }
275
191
  });
276
192
 
277
- // 3. Un-prefix override keys inside @xds/core mock factories. Independent of
278
- // the import bindings above: the override key is a factory object property,
279
- // not a reference to an imported binding, so it must match the renamed export
280
- // name of the mocked module regardless of what the file imports.
281
- const seenMockNodes = new Set();
282
- root.find(j.CallExpression).forEach(path => {
283
- if (!isXdsCoreMockCall(path.node)) return;
284
- // Only walk the factory argument(s), never the module-path string.
285
- for (const arg of path.node.arguments.slice(1)) {
286
- renameMockFactoryKeys(arg, seenMockNodes, () => {
287
- hasChanges = true;
288
- });
289
- }
290
- });
291
-
292
193
  if (localRenames.size === 0) {
293
194
  return hasChanges ? root.toSource() : undefined;
294
195
  }
295
196
 
296
- // 4. Rename references to renamed local bindings
197
+ // 3. Rename references to renamed local bindings
297
198
  // Identifiers (type refs, value refs, etc.)
298
199
  root.find(j.Identifier).forEach(path => {
299
200
  const newName = localRenames.get(path.node.name);
@@ -330,7 +231,7 @@ export default function transformer(file, api) {
330
231
  }
331
232
  });
332
233
 
333
- // 5. Rename TS type references in generic type-argument positions.
234
+ // 4. Rename TS type references in generic type-argument positions.
334
235
  //
335
236
  // `j.find(j.Identifier)` (and `j.find(j.TSTypeReference)`) do NOT visit
336
237
  // identifiers nested inside generic type arguments with the tsx/babel parser
@@ -12,9 +12,8 @@
12
12
  export const meta = {
13
13
  title: 'Migrate module specifiers from @xds/* to @astryxdesign/*',
14
14
  description:
15
- 'Updates JS/TS import, export, dynamic import, require, TS import-type, ' +
16
- 'and test-framework mock (vi.mock / jest.mock) module specifiers from ' +
17
- '@xds/* to the @astryxdesign/* packages used by Astryx v0.1.0.',
15
+ 'Updates JS/TS import, export, dynamic import, and require module ' +
16
+ 'specifiers from @xds/* to the @astryxdesign/* packages used by Astryx v0.1.0.',
18
17
  pr: '#3092',
19
18
  fileExtensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'],
20
19
  };
@@ -74,30 +73,6 @@ function isCollapsedThemeSource(value) {
74
73
  return false;
75
74
  }
76
75
 
77
- // Test-framework mock calls take the mocked module path as their first
78
- // argument (`vi.mock('@xds/core/Text', factory)`). That path is a plain string
79
- // literal -- not an ImportDeclaration source -- so it slips past the import/
80
- // export handlers and, left unrewritten, the mock would target the stale
81
- // `@xds/*` path and stop intercepting the renamed `@astryxdesign/*` import.
82
- // Recognized callees: `vi.mock`, `vi.doMock`, `jest.mock`, `jest.doMock`, and
83
- // a bare `mock(...)` (destructured from the test runner).
84
- const MOCK_METHOD_NAMES = new Set(['mock', 'doMock']);
85
- const MOCK_OBJECT_NAMES = new Set(['vi', 'jest']);
86
-
87
- function isMockCall(callee) {
88
- if (
89
- callee.type === 'MemberExpression' &&
90
- !callee.computed &&
91
- callee.object.type === 'Identifier' &&
92
- MOCK_OBJECT_NAMES.has(callee.object.name) &&
93
- callee.property.type === 'Identifier' &&
94
- MOCK_METHOD_NAMES.has(callee.property.name)
95
- ) {
96
- return true;
97
- }
98
- return callee.type === 'Identifier' && callee.name === 'mock';
99
- }
100
-
101
76
  function remapThemeExportNames(importPath, j) {
102
77
  let changed = false;
103
78
  importPath.node.specifiers = (importPath.node.specifiers || []).map(spec => {
@@ -143,53 +118,12 @@ export default function transformer(file, api) {
143
118
  const isRequire =
144
119
  path.node.callee.type === 'Identifier' &&
145
120
  path.node.callee.name === 'require';
146
- if (isDynamicImport || isRequire || isMockCall(path.node.callee)) {
147
- const [arg] = path.node.arguments;
148
- if (arg?.type === 'StringLiteral' || arg?.type === 'Literal') {
149
- hasChanges = rewriteLiteral(arg) || hasChanges;
150
- }
121
+ if (!isDynamicImport && !isRequire) return;
122
+ const [arg] = path.node.arguments;
123
+ if (arg?.type === 'StringLiteral' || arg?.type === 'Literal') {
124
+ hasChanges = rewriteLiteral(arg) || hasChanges;
151
125
  }
152
126
  });
153
127
 
154
- // TS `import(...)` TYPE specifiers -- e.g. the `import('@xds/core/Text')` in
155
- // `typeof import('@xds/core/Text')` -- parse to a `TSImportType` node, not a
156
- // dynamic-import CallExpression, so the handler above never reaches them.
157
- // ast-types' traversal also doesn't descend into a `TSImportType` nested in a
158
- // generic type-argument position (e.g. `orig<typeof import('@xds/core/Text')>()`),
159
- // so `j.find(j.TSImportType)` misses it. Walk the raw AST to cover every
160
- // position. Re-visiting a node the loop above handled is harmless: the
161
- // literal is already rewritten, so the second pass is a no-op.
162
- const seenTypeImportNodes = new Set();
163
- const rewriteTSImportTypes = node => {
164
- if (!node || typeof node !== 'object') return;
165
- if (Array.isArray(node)) {
166
- for (const child of node) rewriteTSImportTypes(child);
167
- return;
168
- }
169
- if (seenTypeImportNodes.has(node)) return;
170
- seenTypeImportNodes.add(node);
171
-
172
- if (node.type === 'TSImportType' && node.argument) {
173
- hasChanges = rewriteLiteral(node.argument) || hasChanges;
174
- }
175
-
176
- for (const key of Object.keys(node)) {
177
- if (
178
- key === 'loc' ||
179
- key === 'start' ||
180
- key === 'end' ||
181
- key === 'range' ||
182
- key === 'comments' ||
183
- key === 'leadingComments' ||
184
- key === 'trailingComments' ||
185
- key === 'tokens'
186
- ) {
187
- continue;
188
- }
189
- rewriteTSImportTypes(node[key]);
190
- }
191
- };
192
- rewriteTSImportTypes(root.get().node);
193
-
194
128
  return hasChanges ? root.toSource() : undefined;
195
129
  }
@@ -12,7 +12,7 @@
12
12
  * - Hermes Agent: .hermes.md or HERMES.md (existing), else AGENTS.md
13
13
  *
14
14
  * Auto-detect: discovers existing files and updates them in place.
15
- * Default (no existing files): creates AGENTS.md (the tool-agnostic standard).
15
+ * Default (no existing files): creates .claude/CLAUDE.md.
16
16
  *
17
17
  * --agent <tool>: target a specific tool preset (claude, cursor, codex, hermes, all)
18
18
  * --agent-docs-path <path>: explicit file path(s)
@@ -104,78 +104,6 @@ export function isAstryxInitialized(targetDir = process.cwd()) {
104
104
  return false;
105
105
  }
106
106
 
107
- /**
108
- * Parse the Astryx version a managed block was generated for, from its header
109
- * line ("Astryx v1.2.3 · N components"). Returns null when the block predates
110
- * the versioned header (e.g. a legacy XDS block) or has no header at all.
111
- *
112
- * @param {string} content File contents, or just the block text.
113
- * @returns {string|null}
114
- */
115
- export function parseBlockVersion(content) {
116
- const match = /Astryx v(\d+\.\d+\.\d+[^\s·]*)/.exec(content ?? '');
117
- return match ? match[1] : null;
118
- }
119
-
120
- /**
121
- * Read-only staleness assessment of the managed agent-docs block(s) against the
122
- * installed core version. This is the detection half of the `astryx upgrade`
123
- * agent-docs refresh: it never writes, so `upgrade` can run it on EVERY path —
124
- * including the up-to-date / no-codemods short-circuits — and decide whether to
125
- * rewrite a stale block, nudge an uninitialized repo, or stay silent.
126
- *
127
- * A managed block is:
128
- * - `stale` — it carries a legacy XDS marker, has no parseable version, or
129
- * records a version other than the installed one.
130
- * - `current` — every managed block already matches the installed version.
131
- * And the project is `missing` when no managed block exists anywhere (the repo
132
- * has agent-doc files without our markers, or none at all — i.e. never `init`ed).
133
- *
134
- * @param {string} targetDir
135
- * @param {string} [installedVersion] Defaults to the installed core version.
136
- * @returns {{
137
- * installedVersion: string,
138
- * status: 'missing' | 'stale' | 'current',
139
- * files: Array<{path: string, blockVersion: string|null, legacy: boolean, stale: boolean}>,
140
- * staleFiles: string[],
141
- * blockVersions: string[],
142
- * }}
143
- */
144
- export function inspectAgentDocs(targetDir, installedVersion) {
145
- const version = installedVersion ?? getXdsVersion(findCoreDir(targetDir));
146
- const files = [];
147
-
148
- for (const rel of discoverAgentDocs(targetDir)) {
149
- let content;
150
- try {
151
- content = fs.readFileSync(path.join(targetDir, rel), 'utf-8');
152
- } catch {
153
- continue; // Unreadable — treat as absent.
154
- }
155
- const hasNew = content.includes(MARKER_START);
156
- const hasLegacy = content.includes(LEGACY_MARKER_START);
157
- if (!hasNew && !hasLegacy) continue; // Not a block we manage.
158
-
159
- const legacy = !hasNew && hasLegacy;
160
- const blockVersion = parseBlockVersion(content);
161
- const stale = legacy || blockVersion == null || blockVersion !== version;
162
- files.push({path: rel, blockVersion, legacy, stale});
163
- }
164
-
165
- const staleEntries = files.filter(f => f.stale);
166
- const staleFiles = staleEntries.map(f => f.path);
167
- const blockVersions = [
168
- ...new Set(staleEntries.map(f => f.blockVersion).filter(Boolean)),
169
- ];
170
-
171
- let status;
172
- if (files.length === 0) status = 'missing';
173
- else if (staleFiles.length > 0) status = 'stale';
174
- else status = 'current';
175
-
176
- return {installedVersion: version, status, files, staleFiles, blockVersions};
177
- }
178
-
179
107
  /**
180
108
  * Resolve which file(s) to write for a given agent tool preset.
181
109
  * Searches for existing files first, falls back to default creation path.
@@ -511,7 +439,7 @@ export function removeAgentDocs(targetDir) {
511
439
  *
512
440
  * Strategy (when no agent/paths specified):
513
441
  * - Discover all existing agent doc files and update them
514
- * - If nothing found, create AGENTS.md as default (tool-agnostic standard)
442
+ * - If nothing found, create .claude/CLAUDE.md as default
515
443
  *
516
444
  * @param {string} targetDir
517
445
  * @param {object} [options]
@@ -586,16 +514,14 @@ export function installAgentDocs(targetDir, {zh = false, lang, agent, paths, onl
586
514
  return written;
587
515
  }
588
516
 
589
- // Nothing exists — create root AGENTS.md as the default (skip if onlyReplace).
590
- // AGENTS.md is the tool-agnostic standard (Codex/Copilot, Cursor, and most
591
- // agents read it), so it's the safe default. Claude-specific output is opt-in
592
- // via `--agent claude` (→ .claude/CLAUDE.md); `--agent all` writes both.
517
+ // Nothing exists — create .claude/CLAUDE.md as default (skip if onlyReplace)
593
518
  if (onlyReplace) return written;
594
519
 
595
- const defaultPath = AGENTS_MD;
520
+ const defaultPath = CLAUDE_DIR_MD;
521
+ fs.mkdirSync(path.join(targetDir, '.claude'), {recursive: true});
596
522
  injectXdsBlock(path.join(targetDir, defaultPath), compressedIndex, {
597
523
  createIfMissing: true,
598
- header: `# AGENTS.md\n\nProject-specific guidance for AI coding agents.`,
524
+ header: `# CLAUDE.md\n\nProject-specific guidance for AI coding agents.`,
599
525
  });
600
526
  written.push(defaultPath);
601
527
  return written;