@antomanc/aginit 0.4.1 → 0.5.1
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 +39 -0
- package/README.md +116 -34
- package/THIRD_PARTY_NOTICES.md +92 -16
- package/dist/adapters/agent-docs.d.ts +35 -0
- package/dist/adapters/agent-docs.d.ts.map +1 -0
- package/dist/adapters/agent-docs.js +156 -0
- package/dist/adapters/agent-docs.js.map +1 -0
- package/dist/adapters/agents-md.d.ts +15 -1
- package/dist/adapters/agents-md.d.ts.map +1 -1
- package/dist/adapters/agents-md.js +146 -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 +197 -0
- package/src/adapters/agents-md.ts +171 -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/wizard.ts
CHANGED
|
@@ -3,6 +3,10 @@ import pc from 'picocolors';
|
|
|
3
3
|
import { PresetType, WebFramework, PackageManager } from '../config/schema.js';
|
|
4
4
|
import { validateProjectName, readProjectConfig } from '../config/validation.js';
|
|
5
5
|
import { detectPackageManager } from '../adapters/package-manager.js';
|
|
6
|
+
import { detectProject } from '../detect/index.js';
|
|
7
|
+
import { presetPlatform } from '../config/defaults.js';
|
|
8
|
+
import { CATALOG, PLATFORMS, defaultCapabilities, isNodeStack, supports } from '../registry/index.js';
|
|
9
|
+
import type { CapabilityCategory, Platform, ProfileFlags, Stack } from '../registry/index.js';
|
|
6
10
|
import { createProject } from './new.js';
|
|
7
11
|
import { initCurrentDirectory } from './init.js';
|
|
8
12
|
|
|
@@ -23,12 +27,14 @@ export interface WizardNewAnswers {
|
|
|
23
27
|
preset: PresetType;
|
|
24
28
|
framework: WebFramework;
|
|
25
29
|
packageManager: PackageManager;
|
|
30
|
+
profile: ProfileFlags;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
export interface WizardInitAnswers {
|
|
29
34
|
preset: PresetType;
|
|
30
35
|
framework: WebFramework;
|
|
31
36
|
packageManager: PackageManager;
|
|
37
|
+
profile: ProfileFlags;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
export async function promptNewProject(defaults?: {
|
|
@@ -36,6 +42,7 @@ export async function promptNewProject(defaults?: {
|
|
|
36
42
|
preset?: PresetType;
|
|
37
43
|
framework?: WebFramework;
|
|
38
44
|
packageManager?: PackageManager;
|
|
45
|
+
profile?: ProfileFlags;
|
|
39
46
|
}): Promise<WizardNewAnswers> {
|
|
40
47
|
let projectName: string = defaults?.projectName || '';
|
|
41
48
|
if (!projectName) {
|
|
@@ -54,27 +61,10 @@ export async function promptNewProject(defaults?: {
|
|
|
54
61
|
projectName = String(assertNotCancelled(res)).trim();
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
initialValue: 'web',
|
|
62
|
-
options: [
|
|
63
|
-
{
|
|
64
|
-
value: 'web',
|
|
65
|
-
label: 'Web Application',
|
|
66
|
-
hint: 'React, Next.js, Vite, or agnostic + Vitest/Playwright'
|
|
67
|
-
},
|
|
68
|
-
{ value: 'cli', label: 'CLI Tool', hint: 'TypeScript, Commander, Picocolors + Vitest' },
|
|
69
|
-
{
|
|
70
|
-
value: 'generic',
|
|
71
|
-
label: 'Generic / Existing Codebase',
|
|
72
|
-
hint: 'Codebase graph + agent intake guide'
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
});
|
|
76
|
-
preset = assertNotCancelled(res) as PresetType;
|
|
77
|
-
}
|
|
64
|
+
const platform = defaults?.profile?.platform ??
|
|
65
|
+
await promptPlatform(presetPlatform(defaults?.preset ?? 'web'));
|
|
66
|
+
const preset = defaults?.preset ??
|
|
67
|
+
(platform === 'web' ? 'web' : platform === 'cli' ? 'cli' : 'generic');
|
|
78
68
|
|
|
79
69
|
let framework: WebFramework = defaults?.framework || 'none';
|
|
80
70
|
if (preset === 'web' && defaults?.framework === undefined) {
|
|
@@ -84,8 +74,8 @@ export async function promptNewProject(defaults?: {
|
|
|
84
74
|
options: [
|
|
85
75
|
{
|
|
86
76
|
value: 'none',
|
|
87
|
-
label: '
|
|
88
|
-
hint: '
|
|
77
|
+
label: 'None',
|
|
78
|
+
hint: 'TypeScript baseline'
|
|
89
79
|
},
|
|
90
80
|
{
|
|
91
81
|
value: 'vite',
|
|
@@ -100,28 +90,17 @@ export async function promptNewProject(defaults?: {
|
|
|
100
90
|
|
|
101
91
|
let packageManager = defaults?.packageManager;
|
|
102
92
|
if (!packageManager) {
|
|
103
|
-
|
|
104
|
-
message: 'Select package manager:',
|
|
105
|
-
initialValue: 'pnpm',
|
|
106
|
-
options: [
|
|
107
|
-
{
|
|
108
|
-
value: 'pnpm',
|
|
109
|
-
label: 'pnpm (Recommended)',
|
|
110
|
-
hint: 'Fast, disk-efficient & compliant workspace'
|
|
111
|
-
},
|
|
112
|
-
{ value: 'npm', label: 'npm', hint: 'Standard Node.js package manager' },
|
|
113
|
-
{ value: 'yarn', label: 'yarn', hint: 'Yarn package manager' },
|
|
114
|
-
{ value: 'bun', label: 'bun', hint: 'Fast all-in-one JavaScript runtime & toolkit' }
|
|
115
|
-
]
|
|
116
|
-
});
|
|
117
|
-
packageManager = assertNotCancelled(res) as PackageManager;
|
|
93
|
+
packageManager = platform === 'mobile-native' ? 'pnpm' : await promptPackageManager();
|
|
118
94
|
}
|
|
119
95
|
|
|
96
|
+
const profile = await promptProfile(platform, 'unknown', framework, true,
|
|
97
|
+
{ ...defaults?.profile, platform });
|
|
120
98
|
return {
|
|
121
99
|
projectName,
|
|
122
100
|
preset,
|
|
123
101
|
framework,
|
|
124
|
-
packageManager
|
|
102
|
+
packageManager,
|
|
103
|
+
profile
|
|
125
104
|
};
|
|
126
105
|
}
|
|
127
106
|
|
|
@@ -130,72 +109,110 @@ export async function promptInitProject(defaults?: {
|
|
|
130
109
|
preset?: PresetType;
|
|
131
110
|
framework?: WebFramework;
|
|
132
111
|
packageManager?: PackageManager;
|
|
112
|
+
profile?: ProfileFlags;
|
|
133
113
|
}): Promise<WizardInitAnswers> {
|
|
134
114
|
const targetDir = defaults?.targetDir || process.cwd();
|
|
115
|
+
const detected = detectProject(targetDir);
|
|
116
|
+
const preset = defaults?.preset ?? 'generic';
|
|
117
|
+
const framework = defaults?.framework ?? 'existing';
|
|
118
|
+
const platform =
|
|
119
|
+
defaults?.profile?.platform ??
|
|
120
|
+
(preset !== 'generic' ? presetPlatform(preset) : detected.platform ?? 'cli');
|
|
121
|
+
const stack = detected.stack;
|
|
122
|
+
p.note(
|
|
123
|
+
stack === 'unknown'
|
|
124
|
+
? 'No stack detected. Choose a platform below.'
|
|
125
|
+
: `Detected ${stack}. Existing project files are preserved.`,
|
|
126
|
+
'Project'
|
|
127
|
+
);
|
|
128
|
+
const profile = await promptProfile(
|
|
129
|
+
platform, stack, framework,
|
|
130
|
+
preset !== 'generic' || detected.stack === 'unknown',
|
|
131
|
+
defaults?.profile
|
|
132
|
+
);
|
|
133
|
+
const packageManager =
|
|
134
|
+
defaults?.packageManager ?? detectPackageManager(targetDir) ??
|
|
135
|
+
(isNodeStack(stack) || (stack === 'unknown' && profile.platform !== 'mobile-native')
|
|
136
|
+
? await promptPackageManager()
|
|
137
|
+
: 'pnpm');
|
|
138
|
+
return { preset, framework, packageManager, profile };
|
|
139
|
+
}
|
|
135
140
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{ value: 'cli', label: 'CLI Tool', hint: 'TypeScript, Vitest' },
|
|
144
|
-
{
|
|
145
|
-
value: 'generic',
|
|
146
|
-
label: 'Generic Repository',
|
|
147
|
-
hint: 'Codebase graph + agent intake guide'
|
|
148
|
-
}
|
|
149
|
-
]
|
|
150
|
-
});
|
|
151
|
-
preset = assertNotCancelled(res) as PresetType;
|
|
152
|
-
}
|
|
141
|
+
async function promptPackageManager(): Promise<PackageManager> {
|
|
142
|
+
return assertNotCancelled(await p.select({
|
|
143
|
+
message: 'Package manager',
|
|
144
|
+
initialValue: 'pnpm',
|
|
145
|
+
options: ['pnpm', 'npm', 'yarn', 'bun'].map((value) => ({ value, label: value }))
|
|
146
|
+
})) as PackageManager;
|
|
147
|
+
}
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
149
|
+
async function promptPlatform(initialValue: Platform): Promise<Platform> {
|
|
150
|
+
const labels: Record<Platform, string> = {
|
|
151
|
+
web: 'Web',
|
|
152
|
+
'mobile-native': 'Native mobile',
|
|
153
|
+
'mobile-rn': 'React Native / Expo',
|
|
154
|
+
backend: 'Backend',
|
|
155
|
+
cli: 'CLI / library'
|
|
156
|
+
};
|
|
157
|
+
return assertNotCancelled(await p.select({
|
|
158
|
+
message: 'Platform',
|
|
159
|
+
initialValue,
|
|
160
|
+
options: PLATFORMS.map((value) => ({ value, label: labels[value] }))
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function promptProfile(
|
|
165
|
+
initialPlatform: Platform,
|
|
166
|
+
stack: Stack,
|
|
167
|
+
framework: WebFramework,
|
|
168
|
+
harness: boolean,
|
|
169
|
+
flags: ProfileFlags = {}
|
|
170
|
+
): Promise<ProfileFlags> {
|
|
171
|
+
const platform = flags.platform ?? await promptPlatform(initialPlatform);
|
|
172
|
+
const resolvedStack = stack === 'unknown' && platform !== 'mobile-native' ? 'node' : stack;
|
|
173
|
+
const defaults = defaultCapabilities({ platform, stack: resolvedStack, framework, harness });
|
|
174
|
+
const choose = async (category: CapabilityCategory, message: string, allowNone = false) => {
|
|
175
|
+
const entries = CATALOG.filter((c) =>
|
|
176
|
+
c.category === category && !c.addon && supports(c, platform) &&
|
|
177
|
+
(!c.requiresNodeInProjectRoot || isNodeStack(resolvedStack))
|
|
178
|
+
);
|
|
179
|
+
return assertNotCancelled(await p.select({
|
|
180
|
+
message,
|
|
181
|
+
initialValue:
|
|
182
|
+
[...defaults].reverse().find((id) => entries.some((c) => c.id === id)) ??
|
|
183
|
+
(allowNone ? 'none' : entries[0]?.id),
|
|
159
184
|
options: [
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
label: 'Existing Web Setup (Recommended)',
|
|
163
|
-
hint: 'Preserve existing bundler and dependencies'
|
|
164
|
-
},
|
|
165
|
-
{ value: 'none', label: 'Framework-agnostic', hint: 'Baseline TypeScript' },
|
|
166
|
-
{ value: 'vite', label: 'Vite', hint: 'Vite React setup' },
|
|
167
|
-
{ value: 'next', label: 'Next.js', hint: 'Next.js setup' }
|
|
185
|
+
...entries.map((c) => ({ value: c.id, label: c.name, hint: c.description })),
|
|
186
|
+
...(allowNone ? [{ value: 'none', label: 'None' }] : [])
|
|
168
187
|
]
|
|
169
|
-
});
|
|
170
|
-
framework = assertNotCancelled(res) as WebFramework;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Auto-detect and preserve existing package manager without prompting
|
|
174
|
-
let packageManager = defaults?.packageManager;
|
|
175
|
-
if (!packageManager) {
|
|
176
|
-
const detected = detectPackageManager(targetDir);
|
|
177
|
-
if (detected) {
|
|
178
|
-
packageManager = detected;
|
|
179
|
-
} else {
|
|
180
|
-
const res = await p.select({
|
|
181
|
-
message: 'Select package manager for this project:',
|
|
182
|
-
initialValue: 'pnpm',
|
|
183
|
-
options: [
|
|
184
|
-
{ value: 'pnpm', label: 'pnpm (Recommended)', hint: 'Fast, disk-efficient workspace' },
|
|
185
|
-
{ value: 'npm', label: 'npm', hint: 'Standard Node.js package manager' },
|
|
186
|
-
{ value: 'yarn', label: 'yarn', hint: 'Yarn package manager' },
|
|
187
|
-
{ value: 'bun', label: 'bun', hint: 'Fast runtime and package manager' }
|
|
188
|
-
]
|
|
189
|
-
});
|
|
190
|
-
packageManager = assertNotCancelled(res) as PackageManager;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
preset,
|
|
196
|
-
framework,
|
|
197
|
-
packageManager
|
|
188
|
+
}));
|
|
198
189
|
};
|
|
190
|
+
const methodology = flags.methodology ?? await choose('methodology', 'Methodology');
|
|
191
|
+
const design = flags.design ?? await choose('design', 'Design', true);
|
|
192
|
+
const testing = flags.testing ?? await choose('testing-engine', 'Testing engine');
|
|
193
|
+
const uiDriver = flags.uiDriver ?? await choose('ui-driver', 'UI driver', true);
|
|
194
|
+
const addons = flags.addons ?? assertNotCancelled(await p.multiselect({
|
|
195
|
+
message: 'Add-ons',
|
|
196
|
+
required: false,
|
|
197
|
+
options: CATALOG.filter((c) => c.addon && supports(c, platform) &&
|
|
198
|
+
(!c.requiresNodeInProjectRoot || isNodeStack(resolvedStack)))
|
|
199
|
+
.map((c) => ({ value: c.id, label: c.name, hint: c.description }))
|
|
200
|
+
}));
|
|
201
|
+
return { ...flags, platform, methodology, design, testing: testing as ProfileFlags['testing'], uiDriver, addons };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function confirmSetup(answers: WizardInitAnswers): Promise<boolean> {
|
|
205
|
+
const profile = answers.profile;
|
|
206
|
+
const name = (id: string | undefined) => CATALOG.find((c) => c.id === id)?.name ?? id;
|
|
207
|
+
p.note([
|
|
208
|
+
`Platform: ${profile.platform}`,
|
|
209
|
+
`Methodology: ${name(profile.methodology)}`,
|
|
210
|
+
`Design: ${name(profile.design)}`,
|
|
211
|
+
`Testing: ${name(profile.testing)}`,
|
|
212
|
+
`UI driver: ${name(profile.uiDriver)}`,
|
|
213
|
+
`Add-ons: ${profile.addons?.map(name).join(', ') || 'None'}`
|
|
214
|
+
].join('\n'), 'Setup');
|
|
215
|
+
return assertNotCancelled(await p.confirm({ message: 'Apply this setup?', initialValue: true }));
|
|
199
216
|
}
|
|
200
217
|
|
|
201
218
|
export async function runInteractiveWizard(): Promise<void> {
|
|
@@ -204,16 +221,16 @@ export async function runInteractiveWizard(): Promise<void> {
|
|
|
204
221
|
const action = assertNotCancelled(
|
|
205
222
|
await p.select({
|
|
206
223
|
message: 'What would you like to do?',
|
|
207
|
-
initialValue: 'new',
|
|
224
|
+
initialValue: detectProject(process.cwd()).platform ? 'init' : 'new',
|
|
208
225
|
options: [
|
|
209
226
|
{
|
|
210
227
|
value: 'new',
|
|
211
|
-
label: '
|
|
228
|
+
label: 'New project',
|
|
212
229
|
hint: 'Scaffold in a new directory'
|
|
213
230
|
},
|
|
214
231
|
{
|
|
215
232
|
value: 'init',
|
|
216
|
-
label: '
|
|
233
|
+
label: 'Current directory',
|
|
217
234
|
hint: 'Add AGENTS.md, skills & Graft safely'
|
|
218
235
|
}
|
|
219
236
|
]
|
|
@@ -223,11 +240,16 @@ export async function runInteractiveWizard(): Promise<void> {
|
|
|
223
240
|
let complete: boolean;
|
|
224
241
|
if (action === 'new') {
|
|
225
242
|
const answers = await promptNewProject();
|
|
243
|
+
if (!(await confirmSetup(answers))) {
|
|
244
|
+
p.outro('Setup cancelled.');
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
226
247
|
p.outro(pc.cyan(`Scaffolding "${answers.projectName}"...`));
|
|
227
248
|
complete = await createProject(answers.projectName, {
|
|
228
249
|
preset: answers.preset,
|
|
229
250
|
framework: answers.framework,
|
|
230
|
-
packageManager: answers.packageManager
|
|
251
|
+
packageManager: answers.packageManager,
|
|
252
|
+
profile: answers.profile
|
|
231
253
|
});
|
|
232
254
|
} else {
|
|
233
255
|
const saved = readProjectConfig(process.cwd());
|
|
@@ -236,11 +258,16 @@ export async function runInteractiveWizard(): Promise<void> {
|
|
|
236
258
|
complete = await initCurrentDirectory();
|
|
237
259
|
} else {
|
|
238
260
|
const answers = await promptInitProject();
|
|
261
|
+
if (!(await confirmSetup(answers))) {
|
|
262
|
+
p.outro('Setup cancelled.');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
239
265
|
p.outro(pc.cyan('Configuring current directory...'));
|
|
240
266
|
complete = await initCurrentDirectory({
|
|
241
267
|
preset: answers.preset,
|
|
242
268
|
framework: answers.framework,
|
|
243
|
-
packageManager: answers.packageManager
|
|
269
|
+
packageManager: answers.packageManager,
|
|
270
|
+
profile: answers.profile
|
|
244
271
|
});
|
|
245
272
|
}
|
|
246
273
|
}
|
package/src/config/defaults.ts
CHANGED
|
@@ -5,199 +5,77 @@ import {
|
|
|
5
5
|
PackageManager,
|
|
6
6
|
SkillSourceConfig
|
|
7
7
|
} from './schema.js';
|
|
8
|
+
import {
|
|
9
|
+
applyResolvedProfile,
|
|
10
|
+
isNodeStack,
|
|
11
|
+
MATT_POCOCK_SKILLS,
|
|
12
|
+
Platform,
|
|
13
|
+
ProfileFlags,
|
|
14
|
+
resolveCapabilities,
|
|
15
|
+
Stack
|
|
16
|
+
} from '../registry/index.js';
|
|
17
|
+
|
|
18
|
+
export { MATT_POCOCK_SKILLS };
|
|
8
19
|
|
|
9
20
|
export interface DefaultConfigOptions {
|
|
10
21
|
framework?: WebFramework;
|
|
11
22
|
packageManager?: PackageManager;
|
|
23
|
+
/** Defaults to the preset's platform (generic: cli). */
|
|
24
|
+
platform?: Platform;
|
|
25
|
+
/** Defaults to node: every preset scaffolds a Node project unless a stack is detected. */
|
|
26
|
+
stack?: Stack;
|
|
27
|
+
flags?: ProfileFlags;
|
|
28
|
+
/** Skip skill sources (`--no-skills`). */
|
|
29
|
+
skills?: boolean;
|
|
30
|
+
/** false when the preset will not scaffold a Vitest harness. */
|
|
31
|
+
harness?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function presetPlatform(preset: PresetType): Platform {
|
|
35
|
+
return preset === 'web' ? 'web' : 'cli';
|
|
12
36
|
}
|
|
13
37
|
|
|
14
38
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* The `misc` (rarely used) and `in-progress` categories are deliberately
|
|
19
|
-
* excluded. Re-evaluate when the upstream repository reshuffles categories.
|
|
39
|
+
* A fresh config: the preset's scaffolding settings plus the capabilities the
|
|
40
|
+
* registry enables for the platform, stack and profile flags.
|
|
20
41
|
*/
|
|
21
|
-
export const MATT_POCOCK_SKILLS = [
|
|
22
|
-
// engineering
|
|
23
|
-
'ask-matt',
|
|
24
|
-
'code-review',
|
|
25
|
-
'codebase-design',
|
|
26
|
-
'diagnosing-bugs',
|
|
27
|
-
'domain-modeling',
|
|
28
|
-
'grill-with-docs',
|
|
29
|
-
'implement',
|
|
30
|
-
'implement-spec',
|
|
31
|
-
'improve-codebase-architecture',
|
|
32
|
-
'pr',
|
|
33
|
-
'prototype',
|
|
34
|
-
'research',
|
|
35
|
-
'retro',
|
|
36
|
-
'setup-matt-pocock-skills',
|
|
37
|
-
'tdd',
|
|
38
|
-
'to-spec',
|
|
39
|
-
'to-tickets',
|
|
40
|
-
'triage',
|
|
41
|
-
'wayfinder',
|
|
42
|
-
'wizard',
|
|
43
|
-
// productivity
|
|
44
|
-
'grill-me',
|
|
45
|
-
'grilling',
|
|
46
|
-
'handoff',
|
|
47
|
-
'teach',
|
|
48
|
-
'to-questionnaire',
|
|
49
|
-
'wait-what',
|
|
50
|
-
'writing-for-agents'
|
|
51
|
-
] as const;
|
|
52
|
-
|
|
53
42
|
export function getDefaultConfig(
|
|
54
43
|
name: string,
|
|
55
44
|
preset: PresetType,
|
|
56
45
|
options: DefaultConfigOptions = {}
|
|
57
46
|
): AginitConfig {
|
|
58
47
|
const packageManager = options.packageManager || 'pnpm';
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{
|
|
91
|
-
package: 'pbakaus/impeccable',
|
|
92
|
-
skills: ['impeccable']
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
package: 'vercel-labs/agent-browser',
|
|
96
|
-
skills: ['agent-browser']
|
|
97
|
-
}
|
|
98
|
-
]
|
|
99
|
-
},
|
|
100
|
-
codebase: {
|
|
101
|
-
graft: true
|
|
102
|
-
},
|
|
103
|
-
browser: {
|
|
104
|
-
visualAgent: true,
|
|
105
|
-
playwright: hasWebTarget
|
|
106
|
-
},
|
|
107
|
-
docs: {
|
|
108
|
-
adr: true
|
|
109
|
-
},
|
|
110
|
-
github: {
|
|
111
|
-
ci: true
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
case 'cli':
|
|
117
|
-
return {
|
|
118
|
-
schemaVersion: '1.0.0',
|
|
119
|
-
name,
|
|
120
|
-
preset: 'cli',
|
|
121
|
-
packageManager,
|
|
122
|
-
agents: {
|
|
123
|
-
primary: 'antigravity',
|
|
124
|
-
secondary: 'codex',
|
|
125
|
-
claudeCode: true
|
|
126
|
-
},
|
|
127
|
-
skills: {
|
|
128
|
-
sources: [
|
|
129
|
-
{
|
|
130
|
-
package: 'mattpocock/skills',
|
|
131
|
-
skills: [...MATT_POCOCK_SKILLS]
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
package: 'blader/humanizer',
|
|
135
|
-
skills: ['humanizer']
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
package: 'dietrichgebert/ponytail',
|
|
139
|
-
skills: ['ponytail']
|
|
140
|
-
}
|
|
141
|
-
]
|
|
142
|
-
},
|
|
143
|
-
codebase: {
|
|
144
|
-
graft: true
|
|
145
|
-
},
|
|
146
|
-
browser: {
|
|
147
|
-
visualAgent: false,
|
|
148
|
-
playwright: false
|
|
149
|
-
},
|
|
150
|
-
docs: {
|
|
151
|
-
adr: true
|
|
152
|
-
},
|
|
153
|
-
github: {
|
|
154
|
-
ci: true
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
case 'generic':
|
|
159
|
-
default:
|
|
160
|
-
return {
|
|
161
|
-
schemaVersion: '1.0.0',
|
|
162
|
-
name,
|
|
163
|
-
preset: 'generic',
|
|
164
|
-
packageManager,
|
|
165
|
-
agents: {
|
|
166
|
-
primary: 'antigravity',
|
|
167
|
-
secondary: 'codex',
|
|
168
|
-
claudeCode: true
|
|
169
|
-
},
|
|
170
|
-
skills: {
|
|
171
|
-
sources: [
|
|
172
|
-
{
|
|
173
|
-
package: 'mattpocock/skills',
|
|
174
|
-
skills: [...MATT_POCOCK_SKILLS]
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
package: 'blader/humanizer',
|
|
178
|
-
skills: ['humanizer']
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
package: 'dietrichgebert/ponytail',
|
|
182
|
-
skills: ['ponytail']
|
|
183
|
-
}
|
|
184
|
-
]
|
|
185
|
-
},
|
|
186
|
-
codebase: {
|
|
187
|
-
graft: true
|
|
188
|
-
},
|
|
189
|
-
browser: {
|
|
190
|
-
visualAgent: false,
|
|
191
|
-
playwright: false
|
|
192
|
-
},
|
|
193
|
-
docs: {
|
|
194
|
-
adr: true
|
|
195
|
-
},
|
|
196
|
-
github: {
|
|
197
|
-
ci: false
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
}
|
|
48
|
+
const platform = options.platform ?? presetPlatform(preset);
|
|
49
|
+
const stack = options.stack ?? 'node';
|
|
50
|
+
const framework = preset === 'web' ? options.framework || 'none' : undefined;
|
|
51
|
+
const base: AginitConfig = {
|
|
52
|
+
schemaVersion: '1.0.0',
|
|
53
|
+
name,
|
|
54
|
+
preset,
|
|
55
|
+
...(framework ? { framework } : {}),
|
|
56
|
+
// Only Node projects have a package manager; the others use their host toolchain.
|
|
57
|
+
...(isNodeStack(stack) ? { packageManager } : {}),
|
|
58
|
+
platform,
|
|
59
|
+
stack,
|
|
60
|
+
agents: {
|
|
61
|
+
primary: 'antigravity',
|
|
62
|
+
secondary: 'codex',
|
|
63
|
+
claudeCode: true
|
|
64
|
+
},
|
|
65
|
+
skills: { sources: [] },
|
|
66
|
+
codebase: { graft: true },
|
|
67
|
+
browser: { visualAgent: false, playwright: false },
|
|
68
|
+
docs: { adr: true },
|
|
69
|
+
github: { ci: preset !== 'generic' }
|
|
70
|
+
};
|
|
71
|
+
const profile = resolveCapabilities({
|
|
72
|
+
platform,
|
|
73
|
+
stack,
|
|
74
|
+
framework,
|
|
75
|
+
harness: options.harness,
|
|
76
|
+
flags: options.flags
|
|
77
|
+
});
|
|
78
|
+
return applyResolvedProfile(base, profile, { skills: options.skills !== false });
|
|
201
79
|
}
|
|
202
80
|
|
|
203
81
|
/** The skill selections that older versions of aginit wrote as defaults. */
|
package/src/config/schema.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CustomCapabilityConfig, Platform, Stack } from '../registry/types.js';
|
|
2
|
+
|
|
1
3
|
export type PresetType = 'web' | 'cli' | 'generic';
|
|
2
4
|
export type WebFramework = 'none' | 'vite' | 'next' | 'existing';
|
|
3
5
|
export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
|
|
@@ -44,6 +46,19 @@ export interface AginitConfig {
|
|
|
44
46
|
github: {
|
|
45
47
|
ci: boolean;
|
|
46
48
|
};
|
|
49
|
+
/** Target platform. Missing in pre-v2 configs; detected from the project then. */
|
|
50
|
+
platform?: Platform;
|
|
51
|
+
/** Host toolchain. Missing in pre-v2 configs; detected from the project then. */
|
|
52
|
+
stack?: Stack;
|
|
53
|
+
/**
|
|
54
|
+
* Enabled capability ids from the registry (src/registry/catalog.ts).
|
|
55
|
+
* Missing in pre-v2 configs; inferred from skills.sources and the switches above.
|
|
56
|
+
*/
|
|
57
|
+
capabilities?: string[];
|
|
58
|
+
/** Skill repositories added on top of the registry; always enabled unless disabled. */
|
|
59
|
+
customCapabilities?: CustomCapabilityConfig[];
|
|
60
|
+
/** Capability ids to keep off, even when a preset or platform default would enable them. */
|
|
61
|
+
disabledCapabilities?: string[];
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
// Backward-compatible alias
|
package/src/config/validation.ts
CHANGED
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { fileExists, readJsonFile } from '../utils/fs.js';
|
|
3
3
|
import { AginitConfig, AGINIT_CONFIG_FILENAME, LEGACY_CONFIG_FILENAME } from './schema.js';
|
|
4
|
+
import { CATALOG } from '../registry/catalog.js';
|
|
5
|
+
import { PLATFORMS } from '../registry/index.js';
|
|
4
6
|
|
|
5
7
|
export const PRESETS = ['web', 'cli', 'generic'] as const;
|
|
6
8
|
export const FRAMEWORKS = ['none', 'vite', 'next', 'existing'] as const;
|
|
7
9
|
export const SUPPORTED_PACKAGE_MANAGERS = ['pnpm', 'npm', 'yarn', 'bun'] as const;
|
|
10
|
+
export const STACKS = [
|
|
11
|
+
'node',
|
|
12
|
+
'react-native',
|
|
13
|
+
'flutter',
|
|
14
|
+
'swift',
|
|
15
|
+
'kotlin',
|
|
16
|
+
'rust',
|
|
17
|
+
'python',
|
|
18
|
+
'go',
|
|
19
|
+
'unknown'
|
|
20
|
+
] as const;
|
|
21
|
+
const CATEGORIES = [
|
|
22
|
+
'methodology',
|
|
23
|
+
'discipline',
|
|
24
|
+
'design',
|
|
25
|
+
'codebase-graph',
|
|
26
|
+
'ui-driver',
|
|
27
|
+
'testing-engine',
|
|
28
|
+
'context-guard',
|
|
29
|
+
'custom'
|
|
30
|
+
] as const;
|
|
8
31
|
export function isRecord(value: unknown): value is Record<string, any> {
|
|
9
32
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10
33
|
}
|
|
@@ -55,6 +78,39 @@ export function validateConfig(value: unknown): AginitConfig {
|
|
|
55
78
|
validateUpstreamArgument(source.package, 'skill package');
|
|
56
79
|
for (const skill of source.skills) validateUpstreamArgument(skill, 'skill name');
|
|
57
80
|
}
|
|
81
|
+
if (value.platform !== undefined && !PLATFORMS.includes(value.platform)) fail('platform');
|
|
82
|
+
if (value.stack !== undefined && !STACKS.includes(value.stack)) fail('stack');
|
|
83
|
+
for (const key of ['capabilities', 'disabledCapabilities']) {
|
|
84
|
+
if (value[key] === undefined) continue;
|
|
85
|
+
if (!Array.isArray(value[key])) fail(key);
|
|
86
|
+
for (const id of value[key]) validateUpstreamArgument(id, `${key} entry`);
|
|
87
|
+
}
|
|
88
|
+
if (value.customCapabilities !== undefined) {
|
|
89
|
+
if (!Array.isArray(value.customCapabilities)) fail('customCapabilities');
|
|
90
|
+
const seen = new Set<string>();
|
|
91
|
+
for (const custom of value.customCapabilities) {
|
|
92
|
+
if (!isRecord(custom)) fail('customCapabilities entry');
|
|
93
|
+
validateUpstreamArgument(custom.id, 'custom capability id');
|
|
94
|
+
if (seen.has(custom.id) || CATALOG.some((entry) => entry.id === custom.id))
|
|
95
|
+
fail(`customCapabilities: duplicate id "${custom.id}"`);
|
|
96
|
+
seen.add(custom.id);
|
|
97
|
+
if (typeof custom.repo !== 'string' || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(custom.repo))
|
|
98
|
+
fail(`customCapabilities.${custom.id}.repo (expected owner/repo)`);
|
|
99
|
+
if (custom.skills !== undefined) {
|
|
100
|
+
if (!Array.isArray(custom.skills)) fail(`customCapabilities.${custom.id}.skills`);
|
|
101
|
+
for (const skill of custom.skills) validateUpstreamArgument(skill, 'skill name');
|
|
102
|
+
}
|
|
103
|
+
if (custom.category !== undefined && !CATEGORIES.includes(custom.category))
|
|
104
|
+
fail(`customCapabilities.${custom.id}.category`);
|
|
105
|
+
if (
|
|
106
|
+
custom.binary !== undefined &&
|
|
107
|
+
(!isRecord(custom.binary) ||
|
|
108
|
+
typeof custom.binary.install !== 'string' ||
|
|
109
|
+
!/^[a-zA-Z0-9._-]+$/.test(String(custom.binary.bin)))
|
|
110
|
+
)
|
|
111
|
+
fail(`customCapabilities.${custom.id}.binary`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
58
114
|
for (const [section, keys] of Object.entries({
|
|
59
115
|
codebase: ['graft'],
|
|
60
116
|
browser: ['visualAgent', 'playwright'],
|