@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.
- package/CHANGELOG.md +28 -0
- package/README.md +108 -28
- package/THIRD_PARTY_NOTICES.md +92 -16
- package/dist/adapters/agent-docs.d.ts +32 -0
- package/dist/adapters/agent-docs.d.ts.map +1 -0
- package/dist/adapters/agent-docs.js +146 -0
- package/dist/adapters/agent-docs.js.map +1 -0
- package/dist/adapters/agents-md.d.ts +13 -1
- package/dist/adapters/agents-md.d.ts.map +1 -1
- package/dist/adapters/agents-md.js +137 -120
- package/dist/adapters/agents-md.js.map +1 -1
- package/dist/adapters/e2e.d.ts +15 -0
- package/dist/adapters/e2e.d.ts.map +1 -0
- package/dist/adapters/e2e.js +55 -0
- package/dist/adapters/e2e.js.map +1 -0
- package/dist/adapters/skills.d.ts +5 -0
- package/dist/adapters/skills.d.ts.map +1 -1
- package/dist/adapters/skills.js +17 -0
- package/dist/adapters/skills.js.map +1 -1
- package/dist/cli/capabilities.d.ts +17 -0
- package/dist/cli/capabilities.d.ts.map +1 -0
- package/dist/cli/capabilities.js +149 -0
- package/dist/cli/capabilities.js.map +1 -0
- package/dist/cli/doctor.d.ts +16 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +90 -70
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +117 -20
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/new.d.ts +15 -1
- package/dist/cli/new.d.ts.map +1 -1
- package/dist/cli/new.js +157 -68
- package/dist/cli/new.js.map +1 -1
- package/dist/cli/wizard.d.ts +5 -0
- package/dist/cli/wizard.d.ts.map +1 -1
- package/dist/cli/wizard.js +104 -102
- package/dist/cli/wizard.js.map +1 -1
- package/dist/config/defaults.d.ts +14 -6
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +38 -174
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +14 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/validation.d.ts +1 -0
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +63 -0
- package/dist/config/validation.js.map +1 -1
- package/dist/detect/index.d.ts +18 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +120 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/presets/cli.d.ts.map +1 -1
- package/dist/presets/cli.js +7 -0
- package/dist/presets/cli.js.map +1 -1
- package/dist/presets/generic.d.ts.map +1 -1
- package/dist/presets/generic.js +4 -1
- package/dist/presets/generic.js.map +1 -1
- package/dist/presets/testing.d.ts +1 -1
- package/dist/presets/testing.d.ts.map +1 -1
- package/dist/presets/testing.js +22 -8
- package/dist/presets/testing.js.map +1 -1
- package/dist/presets/web.d.ts.map +1 -1
- package/dist/presets/web.js +5 -2
- package/dist/presets/web.js.map +1 -1
- package/dist/registry/catalog.d.ts +13 -0
- package/dist/registry/catalog.d.ts.map +1 -0
- package/dist/registry/catalog.js +544 -0
- package/dist/registry/catalog.js.map +1 -0
- package/dist/registry/index.d.ts +84 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +309 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/setup.d.ts +14 -0
- package/dist/registry/setup.d.ts.map +1 -0
- package/dist/registry/setup.js +25 -0
- package/dist/registry/setup.js.map +1 -0
- package/dist/registry/types.d.ts +115 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/package.json +3 -2
- package/src/adapters/agent-docs.ts +184 -0
- package/src/adapters/agents-md.ts +160 -137
- package/src/adapters/e2e.ts +58 -0
- package/src/adapters/skills.ts +18 -0
- package/src/cli/capabilities.ts +176 -0
- package/src/cli/doctor.ts +83 -66
- package/src/cli/init.ts +1 -1
- package/src/cli/main.ts +125 -20
- package/src/cli/new.ts +195 -74
- package/src/cli/wizard.ts +130 -103
- package/src/config/defaults.ts +57 -179
- package/src/config/schema.ts +15 -0
- package/src/config/validation.ts +56 -0
- package/src/detect/index.ts +134 -0
- package/src/index.ts +5 -0
- package/src/presets/cli.ts +6 -0
- package/src/presets/generic.ts +4 -1
- package/src/presets/testing.ts +29 -12
- package/src/presets/web.ts +4 -2
- package/src/registry/catalog.ts +569 -0
- package/src/registry/index.ts +395 -0
- package/src/registry/setup.ts +40 -0
- 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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
|
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
|
-
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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:
|
|
139
|
-
if (!silent) logger.step(currentStep++, totalSteps, 'Generating AGENTS.md
|
|
140
|
-
|
|
141
|
-
if (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
//
|
|
178
|
-
if (!silent) logger.step(currentStep++, totalSteps, '
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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
|
+
}
|