@antomanc/aginit 0.4.1 → 0.5.0

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 (112) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +108 -28
  3. package/THIRD_PARTY_NOTICES.md +92 -16
  4. package/dist/adapters/agent-docs.d.ts +32 -0
  5. package/dist/adapters/agent-docs.d.ts.map +1 -0
  6. package/dist/adapters/agent-docs.js +146 -0
  7. package/dist/adapters/agent-docs.js.map +1 -0
  8. package/dist/adapters/agents-md.d.ts +13 -1
  9. package/dist/adapters/agents-md.d.ts.map +1 -1
  10. package/dist/adapters/agents-md.js +137 -120
  11. package/dist/adapters/agents-md.js.map +1 -1
  12. package/dist/adapters/e2e.d.ts +15 -0
  13. package/dist/adapters/e2e.d.ts.map +1 -0
  14. package/dist/adapters/e2e.js +55 -0
  15. package/dist/adapters/e2e.js.map +1 -0
  16. package/dist/adapters/skills.d.ts +5 -0
  17. package/dist/adapters/skills.d.ts.map +1 -1
  18. package/dist/adapters/skills.js +17 -0
  19. package/dist/adapters/skills.js.map +1 -1
  20. package/dist/cli/capabilities.d.ts +17 -0
  21. package/dist/cli/capabilities.d.ts.map +1 -0
  22. package/dist/cli/capabilities.js +149 -0
  23. package/dist/cli/capabilities.js.map +1 -0
  24. package/dist/cli/doctor.d.ts +16 -0
  25. package/dist/cli/doctor.d.ts.map +1 -1
  26. package/dist/cli/doctor.js +90 -70
  27. package/dist/cli/doctor.js.map +1 -1
  28. package/dist/cli/init.js +1 -1
  29. package/dist/cli/init.js.map +1 -1
  30. package/dist/cli/main.d.ts.map +1 -1
  31. package/dist/cli/main.js +117 -20
  32. package/dist/cli/main.js.map +1 -1
  33. package/dist/cli/new.d.ts +15 -1
  34. package/dist/cli/new.d.ts.map +1 -1
  35. package/dist/cli/new.js +157 -68
  36. package/dist/cli/new.js.map +1 -1
  37. package/dist/cli/wizard.d.ts +5 -0
  38. package/dist/cli/wizard.d.ts.map +1 -1
  39. package/dist/cli/wizard.js +104 -102
  40. package/dist/cli/wizard.js.map +1 -1
  41. package/dist/config/defaults.d.ts +14 -6
  42. package/dist/config/defaults.d.ts.map +1 -1
  43. package/dist/config/defaults.js +38 -174
  44. package/dist/config/defaults.js.map +1 -1
  45. package/dist/config/schema.d.ts +14 -0
  46. package/dist/config/schema.d.ts.map +1 -1
  47. package/dist/config/schema.js.map +1 -1
  48. package/dist/config/validation.d.ts +1 -0
  49. package/dist/config/validation.d.ts.map +1 -1
  50. package/dist/config/validation.js +63 -0
  51. package/dist/config/validation.js.map +1 -1
  52. package/dist/detect/index.d.ts +18 -0
  53. package/dist/detect/index.d.ts.map +1 -0
  54. package/dist/detect/index.js +120 -0
  55. package/dist/detect/index.js.map +1 -0
  56. package/dist/index.d.ts +5 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +5 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/presets/cli.d.ts.map +1 -1
  61. package/dist/presets/cli.js +7 -0
  62. package/dist/presets/cli.js.map +1 -1
  63. package/dist/presets/generic.d.ts.map +1 -1
  64. package/dist/presets/generic.js +4 -1
  65. package/dist/presets/generic.js.map +1 -1
  66. package/dist/presets/testing.d.ts +1 -1
  67. package/dist/presets/testing.d.ts.map +1 -1
  68. package/dist/presets/testing.js +22 -8
  69. package/dist/presets/testing.js.map +1 -1
  70. package/dist/presets/web.d.ts.map +1 -1
  71. package/dist/presets/web.js +5 -2
  72. package/dist/presets/web.js.map +1 -1
  73. package/dist/registry/catalog.d.ts +13 -0
  74. package/dist/registry/catalog.d.ts.map +1 -0
  75. package/dist/registry/catalog.js +544 -0
  76. package/dist/registry/catalog.js.map +1 -0
  77. package/dist/registry/index.d.ts +84 -0
  78. package/dist/registry/index.d.ts.map +1 -0
  79. package/dist/registry/index.js +309 -0
  80. package/dist/registry/index.js.map +1 -0
  81. package/dist/registry/setup.d.ts +14 -0
  82. package/dist/registry/setup.d.ts.map +1 -0
  83. package/dist/registry/setup.js +25 -0
  84. package/dist/registry/setup.js.map +1 -0
  85. package/dist/registry/types.d.ts +115 -0
  86. package/dist/registry/types.d.ts.map +1 -0
  87. package/dist/registry/types.js +2 -0
  88. package/dist/registry/types.js.map +1 -0
  89. package/package.json +3 -2
  90. package/src/adapters/agent-docs.ts +184 -0
  91. package/src/adapters/agents-md.ts +160 -137
  92. package/src/adapters/e2e.ts +58 -0
  93. package/src/adapters/skills.ts +18 -0
  94. package/src/cli/capabilities.ts +176 -0
  95. package/src/cli/doctor.ts +83 -66
  96. package/src/cli/init.ts +1 -1
  97. package/src/cli/main.ts +125 -20
  98. package/src/cli/new.ts +195 -74
  99. package/src/cli/wizard.ts +130 -103
  100. package/src/config/defaults.ts +57 -179
  101. package/src/config/schema.ts +15 -0
  102. package/src/config/validation.ts +56 -0
  103. package/src/detect/index.ts +134 -0
  104. package/src/index.ts +5 -0
  105. package/src/presets/cli.ts +6 -0
  106. package/src/presets/generic.ts +4 -1
  107. package/src/presets/testing.ts +29 -12
  108. package/src/presets/web.ts +4 -2
  109. package/src/registry/catalog.ts +569 -0
  110. package/src/registry/index.ts +395 -0
  111. package/src/registry/setup.ts +40 -0
  112. package/src/registry/types.ts +109 -0
package/src/cli/new.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import path from 'node:path';
2
2
  import pc from 'picocolors';
3
- import { getDefaultConfig, upgradeLegacySkillConfig } from '../config/defaults.js';
3
+ import { getDefaultConfig, presetPlatform, upgradeLegacySkillConfig } from '../config/defaults.js';
4
4
  import {
5
+ AginitConfig,
5
6
  AGINIT_CONFIG_FILENAME,
6
7
  PresetType,
7
8
  WebFramework,
@@ -11,14 +12,28 @@ import { getPreset } from '../presets/registry.js';
11
12
  import { setupGit } from '../adapters/git.js';
12
13
  import { setupAgentsMarkdown, setupClaudeMarkdown } from '../adapters/agents-md.js';
13
14
  import { claudeCodeEnabled, installAllSkills, skillAgents } from '../adapters/skills.js';
14
- import { initGraft } from '../adapters/graft.js';
15
15
  import { ignoreVendoredSkills } from '../adapters/tool-ignores.js';
16
+ import { agentBrowserStubInstalled } from '../adapters/agent-browser.js';
17
+ import { microDocPath, projectProfile, resolvePlatformStack, setupMicroDocs } from '../adapters/agent-docs.js';
18
+ import { detectProject } from '../detect/index.js';
16
19
  import {
17
- agentBrowserConfigured,
18
- agentBrowserStubInstalled,
19
- setupAgentBrowser
20
- } from '../adapters/agent-browser.js';
21
- import { ensureDir, writeJsonFile } from '../utils/fs.js';
20
+ activeCapabilities,
21
+ applyResolvedProfile,
22
+ CapabilityDescriptor,
23
+ e2eDirFor,
24
+ hasProfileFlags,
25
+ inferCapabilities,
26
+ isNodeStack,
27
+ MicroDoc,
28
+ Platform,
29
+ PLATFORMS,
30
+ ProfileFlags,
31
+ resolveCapabilities,
32
+ Stack
33
+ } from '../registry/index.js';
34
+ import { SETUP_LABELS, SETUPS } from '../registry/setup.js';
35
+ import { commandExists } from '../utils/shell.js';
36
+ import { ensureDir, fileExists, writeJsonFile } from '../utils/fs.js';
22
37
  import {
23
38
  readProjectConfig,
24
39
  readPackageManifest,
@@ -40,6 +55,103 @@ export interface NewProjectOptions {
40
55
  dryRun?: boolean;
41
56
  targetDir?: string;
42
57
  silent?: boolean;
58
+ /** v2 profile flags: --platform, --methodology, --design, --testing, --ui-driver, ... */
59
+ profile?: ProfileFlags;
60
+ }
61
+
62
+ /**
63
+ * Work out the config to save. A saved config is reused as written, so plain
64
+ * reruns are deterministic; profile flags (and --preset/--framework for the
65
+ * browser switches) are applied on top of it.
66
+ */
67
+ function resolveConfig(
68
+ projectName: string,
69
+ targetDir: string,
70
+ options: NewProjectOptions,
71
+ existingConfig: AginitConfig | null,
72
+ manifest: Record<string, any> | null
73
+ ): AginitConfig {
74
+ const flags = options.profile ?? {};
75
+ const detected = detectProject(targetDir);
76
+ const saved = existingConfig ? resolvePlatformStack(existingConfig, targetDir) : null;
77
+ const presetHint = options.preset ?? existingConfig?.preset;
78
+ const platform: Platform =
79
+ flags.platform ??
80
+ existingConfig?.platform ??
81
+ (options.preset && options.preset !== 'generic'
82
+ ? presetPlatform(options.preset)
83
+ : (saved?.platform ?? detected.platform ?? presetPlatform(presetHint ?? 'generic')));
84
+ const stack: Stack =
85
+ existingConfig?.stack ??
86
+ (detected.stack !== 'unknown'
87
+ ? detected.stack
88
+ : platform === 'mobile-native'
89
+ ? 'unknown'
90
+ : 'node');
91
+ const presetName = options.preset ?? existingConfig?.preset ?? 'generic';
92
+ const framework =
93
+ options.framework ?? (presetName === 'web' ? existingConfig?.framework : undefined);
94
+ if (presetName !== 'web' && framework && framework !== 'none' && framework !== 'existing')
95
+ throw new Error('A web framework requires --preset web.');
96
+ if (presetName === 'web' && framework === 'existing' && !manifest)
97
+ throw new Error(
98
+ 'An existing web framework requires an existing package.json. Use --framework none for a new baseline.'
99
+ );
100
+ if (!isNodeStack(stack) && options.preset && options.preset !== 'generic')
101
+ throw new Error(
102
+ `--preset ${options.preset} scaffolds a Node.js project, but this is a ${stack} project. ` +
103
+ 'Use --preset generic (the default) to keep the project root free of package.json.'
104
+ );
105
+ const packageManager = options.packageManager ?? existingConfig?.packageManager ?? 'pnpm';
106
+ const defaults = getDefaultConfig(projectName, presetName, {
107
+ framework,
108
+ packageManager,
109
+ platform,
110
+ stack,
111
+ flags,
112
+ skills: options.skills !== false,
113
+ // A generic preset leaves an existing package.json (and its test runner) alone.
114
+ harness: !(presetName === 'generic' && manifest !== null)
115
+ });
116
+ if (!existingConfig) return validateConfig(defaults);
117
+
118
+ let config: AginitConfig = {
119
+ ...existingConfig,
120
+ name: projectName,
121
+ preset: presetName,
122
+ ...(isNodeStack(stack) || existingConfig.packageManager !== undefined ? { packageManager } : {}),
123
+ ...(presetName === 'web' ? { framework: framework ?? 'none' } : {}),
124
+ browser:
125
+ options.framework !== undefined || options.preset !== undefined
126
+ ? { ...existingConfig.browser, ...defaults.browser }
127
+ : existingConfig.browser,
128
+ skills: upgradeLegacySkillConfig(existingConfig.skills)
129
+ };
130
+ if (hasProfileFlags(flags)) {
131
+ const base = existingConfig.capabilities ?? inferCapabilities(existingConfig);
132
+ const profile = resolveCapabilities(
133
+ {
134
+ platform,
135
+ stack,
136
+ framework,
137
+ base,
138
+ basePlatform: saved!.platform,
139
+ flags,
140
+ custom: existingConfig.customCapabilities
141
+ },
142
+ existingConfig.disabledCapabilities
143
+ );
144
+ config = applyResolvedProfile({ ...config, platform, stack }, profile, {
145
+ skills: true,
146
+ previous: [...base, ...(existingConfig.customCapabilities ?? []).map((c) => c.id)]
147
+ });
148
+ } else if (config.capabilities && config.browser.playwright !== existingConfig.browser.playwright) {
149
+ // --framework turned the Playwright switch; keep the capability list in step.
150
+ config.capabilities = config.browser.playwright
151
+ ? [...config.capabilities, 'playwright']
152
+ : config.capabilities.filter((id) => id !== 'playwright');
153
+ }
154
+ return validateConfig(config);
43
155
  }
44
156
 
45
157
  export async function createProject(
@@ -56,6 +168,8 @@ export async function createProject(
56
168
  !SUPPORTED_PACKAGE_MANAGERS.includes(options.packageManager)
57
169
  )
58
170
  throw new Error('Invalid package manager.');
171
+ if (options.profile?.platform !== undefined && !PLATFORMS.includes(options.profile.platform))
172
+ throw new Error(`Invalid platform. Valid platforms are: ${PLATFORMS.join(', ')}`);
59
173
  const defaultDir =
60
174
  projectName.startsWith('@') && projectName.includes('/')
61
175
  ? projectName.split('/').pop()!
@@ -63,54 +177,35 @@ export async function createProject(
63
177
  const targetDir = path.resolve(options.targetDir || path.join(process.cwd(), defaultDir));
64
178
  const existingConfig = readProjectConfig(targetDir);
65
179
  const manifest = readPackageManifest(targetDir); // Validate before creating or modifying anything.
66
- const presetName = options.preset ?? existingConfig?.preset ?? 'generic';
67
- const framework =
68
- options.framework ?? (presetName === 'web' ? existingConfig?.framework : undefined);
69
- if (presetName !== 'web' && framework && framework !== 'none' && framework !== 'existing')
70
- throw new Error('A web framework requires --preset web.');
71
- if (presetName === 'web' && framework === 'existing' && !manifest)
72
- throw new Error(
73
- 'An existing web framework requires an existing package.json. Use --framework none for a new baseline.'
74
- );
75
- const packageManager = options.packageManager ?? existingConfig?.packageManager ?? 'pnpm';
180
+ const config = resolveConfig(projectName, targetDir, options, existingConfig, manifest);
181
+ if (config.preset !== 'web') delete config.framework;
182
+ if (options.graft === false) config.codebase = { ...config.codebase, graft: false };
183
+ if (options.skills === false && !existingConfig) config.skills.sources = [];
184
+ const presetName = config.preset;
185
+ const packageManager = config.packageManager ?? 'pnpm';
186
+ const { platform, stack } = resolvePlatformStack(config, targetDir);
76
187
  const dryRun = !!options.dryRun;
77
188
  const silent = !!options.silent;
78
189
  const presetHandler = getPreset(presetName);
79
- const defaults = getDefaultConfig(projectName, presetName, {
80
- framework,
81
- packageManager
82
- });
83
- const config = validateConfig(
84
- existingConfig
85
- ? {
86
- ...existingConfig,
87
- name: projectName,
88
- preset: presetName,
89
- packageManager,
90
- ...(presetName === 'web' ? { framework: framework ?? 'none' } : {}),
91
- browser:
92
- options.framework !== undefined || options.preset !== undefined
93
- ? { ...existingConfig.browser, ...defaults.browser }
94
- : existingConfig.browser,
95
- skills: upgradeLegacySkillConfig(existingConfig.skills)
96
- }
97
- : defaults
98
- );
99
- if (presetName !== 'web') delete config.framework;
100
- if (options.graft === false) config.codebase = { ...config.codebase, graft: false };
101
- if (options.skills === false && !existingConfig) config.skills.sources = [];
190
+ const active = activeCapabilities(config);
102
191
  if (!silent)
103
192
  logger.banner(
104
193
  `Aginit — ${projectName}`,
105
- `Preset: ${presetName} | PM: ${packageManager} | Target: ${targetDir}${dryRun ? ' (DRY RUN)' : ''}`
194
+ `Preset: ${presetName} | Platform: ${platform} (${stack})${isNodeStack(stack) ? ` | PM: ${packageManager}` : ''} | Target: ${targetDir}${dryRun ? ' (DRY RUN)' : ''}`
106
195
  );
196
+ if (!silent) logger.dim(`Capabilities: ${active.map((c) => c.id).join(', ') || 'none'}`);
107
197
  let complete = true;
108
198
 
109
- // The agent-browser skill stub is inert without its CLI and browser
110
- // binaries, so provisioning them gets its own step when the skill applies.
111
- const agentBrowserWanted =
112
- agentBrowserConfigured(config.skills.sources) || agentBrowserStubInstalled(targetDir);
113
- const totalSteps = agentBrowserWanted ? 7 : 6;
199
+ const installSkills = options.skills !== false && config.skills.sources.length > 0;
200
+ // Upstream setups (agent-browser runtime, e2e, Graft) in registry order, Graft last
201
+ // so its first index sees every generated file.
202
+ const setups = active
203
+ .flatMap((capability) =>
204
+ capability.install.flatMap((step) => (step.kind === 'setup' ? [step.setup] : []))
205
+ )
206
+ .filter((setup) => !(setup === 'graft' && options.graft === false))
207
+ .sort((a, b) => Number(a === 'graft') - Number(b === 'graft'));
208
+ const totalSteps = 6 + setups.length;
114
209
  let currentStep = 1;
115
210
 
116
211
  // Scaffold into the clean directory before Git adds files that upstream tools reject.
@@ -135,15 +230,14 @@ export async function createProject(
135
230
  });
136
231
  if (!silent) logger.success(`Wrote ${AGINIT_CONFIG_FILENAME}`);
137
232
 
138
- // Step 4: Write or update AGENTS.md intake contract
139
- if (!silent) logger.step(currentStep++, totalSteps, 'Generating AGENTS.md intake guidance');
140
- setupAgentsMarkdown(targetDir, config, { dryRun, silent });
141
- if (claudeCodeEnabled(config)) setupClaudeMarkdown(targetDir, { dryRun, silent });
142
- if (!silent) logger.success('Configured AGENTS.md');
233
+ // Step 4: AGENTS.md (task routing) and the docs/agents/ micro-docs it routes to
234
+ if (!silent) logger.step(currentStep++, totalSteps, 'Generating AGENTS.md and docs/agents/');
235
+ const docs = syncAgentDocs(targetDir, config, { dryRun, silent });
236
+ if (!silent) logger.success(`Configured AGENTS.md${docs.length ? ` and ${docs.map(microDocPath).join(', ')}` : ''}`);
143
237
 
144
238
  // Step 5: Install skills via skills.sh engine
145
239
  if (!silent) logger.step(currentStep++, totalSteps, 'Installing upstream skills via skills.sh');
146
- if (options.skills !== false && config.skills.sources.length > 0) {
240
+ if (installSkills) {
147
241
  const { installed, failed } = await installAllSkills(targetDir, config.skills.sources, {
148
242
  agents: skillAgents(config),
149
243
  dryRun,
@@ -161,33 +255,28 @@ export async function createProject(
161
255
  } else if (!silent) {
162
256
  logger.dim('Skills installation skipped (--no-skills or empty configuration)');
163
257
  }
164
- if ((options.skills !== false && config.skills.sources.length > 0) || agentBrowserWanted) {
258
+ const agentBrowserStub = agentBrowserStubInstalled(targetDir);
259
+ if (installSkills || agentBrowserStub) {
165
260
  const advice = ignoreVendoredSkills(targetDir, { dryRun, silent: true });
166
261
  if (!silent) for (const line of advice) logger.warn(line);
167
262
  }
263
+ // A stub installed earlier still needs its runtime, even when skills are skipped now.
264
+ if (agentBrowserStub && !setups.includes('agent-browser')) setups.unshift('agent-browser');
168
265
 
169
- // Provision the agent-browser runtime the skill stub drives
170
- if (agentBrowserWanted) {
171
- if (!silent) logger.step(currentStep++, totalSteps, 'Provisioning agent-browser runtime');
172
- const abOk = await setupAgentBrowser({ dryRun, silent, cwd: targetDir });
173
- complete &&= abOk;
174
- if (!silent && abOk) logger.success('agent-browser runtime ready (CLI + browser)');
266
+ for (const setup of setups) {
267
+ if (!silent) logger.step(currentStep++, totalSteps, SETUP_LABELS[setup]);
268
+ const ok = await SETUPS[setup]({ targetDir, config, platform, stack, dryRun, silent });
269
+ complete &&= ok;
270
+ if (ok && !silent) logger.success(`${setup} ready`);
175
271
  }
176
272
 
177
- // Codebase intelligence (Graft)
178
- if (!silent) logger.step(currentStep++, totalSteps, 'Configuring codebase intelligence');
179
- if (config.codebase.graft && options.graft !== false) {
180
- const graftOk = await initGraft(targetDir, {
181
- dryRun,
182
- silent,
183
- claude: claudeCodeEnabled(config)
184
- });
185
- complete &&= graftOk;
186
- if (graftOk && !silent) {
187
- logger.success('Graft context graph initialized');
188
- }
189
- } else if (!silent) {
190
- logger.dim('Graft setup skipped (--no-graft or codebase.graft: false)');
273
+ // CLIs aginit does not install: report the missing ones with their install command.
274
+ if (!silent) logger.step(currentStep++, totalSteps, 'Checking capability CLIs');
275
+ const missing = await missingBinaries(active, setups);
276
+ if (!silent) {
277
+ if (missing.length === 0) logger.success('Every capability CLI is available');
278
+ for (const { name, bin, install } of missing)
279
+ logger.warn(`${name} needs the \`${bin}\` CLI: ${install}`);
191
280
  }
192
281
 
193
282
  if (!silent) {
@@ -201,7 +290,10 @@ export async function createProject(
201
290
  console.log('Next steps:');
202
291
  const relativeTarget = path.relative(process.cwd(), targetDir);
203
292
  if (relativeTarget) console.log(pc.cyan(` cd ${relativeTarget}`));
204
- console.log(pc.cyan(` ${packageManager} install`));
293
+ if (isNodeStack(stack) && (manifest || fileExists(path.join(targetDir, 'package.json')) || dryRun))
294
+ console.log(pc.cyan(` ${packageManager} install`));
295
+ if (active.some((c) => c.id === 'e2e') && e2eDirFor(stack))
296
+ console.log(pc.cyan(` (cd ${e2eDirFor(stack)} && npm install)`));
205
297
  console.log(pc.cyan(' Open the repository in your AI coding agent'));
206
298
  console.log(pc.dim(' Prompt the agent: ') + pc.bold(pc.green('"bootstrap this project"')));
207
299
  console.log();
@@ -209,3 +301,32 @@ export async function createProject(
209
301
 
210
302
  return complete;
211
303
  }
304
+
305
+ /** Binaries of active capabilities that are not on PATH (setups report their own). */
306
+ export async function missingBinaries(
307
+ active: CapabilityDescriptor[],
308
+ setups: string[]
309
+ ): Promise<Array<{ name: string; bin: string; install: string }>> {
310
+ const missing: Array<{ name: string; bin: string; install: string }> = [];
311
+ for (const capability of active) {
312
+ if (capability.install.some((step) => step.kind === 'setup' && setups.includes(step.setup)))
313
+ continue;
314
+ for (const step of capability.install)
315
+ if (step.kind === 'binary' && !(await commandExists(step.bin)))
316
+ missing.push({ name: capability.name, bin: step.bin, install: step.install });
317
+ }
318
+ return missing;
319
+ }
320
+
321
+ /** Refresh AGENTS.md, CLAUDE.md and docs/agents/ from the config. */
322
+ export function syncAgentDocs(
323
+ targetDir: string,
324
+ config: AginitConfig,
325
+ options: { dryRun?: boolean; silent?: boolean } = {}
326
+ ): MicroDoc[] {
327
+ const scripts = readPackageManifest(targetDir)?.scripts;
328
+ const docs = setupMicroDocs(targetDir, projectProfile(config, { targetDir, scripts }), options);
329
+ setupAgentsMarkdown(targetDir, config, { ...options, docs });
330
+ if (claudeCodeEnabled(config)) setupClaudeMarkdown(targetDir, options);
331
+ return docs;
332
+ }