@antomanc/aginit 0.1.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +245 -0
  3. package/THIRD_PARTY_NOTICES.md +36 -0
  4. package/bin/aginit.js +8 -0
  5. package/dist/adapters/agents-md.d.ts +8 -0
  6. package/dist/adapters/agents-md.d.ts.map +1 -0
  7. package/dist/adapters/agents-md.js +121 -0
  8. package/dist/adapters/agents-md.js.map +1 -0
  9. package/dist/adapters/browser.d.ts +5 -0
  10. package/dist/adapters/browser.d.ts.map +1 -0
  11. package/dist/adapters/browser.js +42 -0
  12. package/dist/adapters/browser.js.map +1 -0
  13. package/dist/adapters/git.d.ts +5 -0
  14. package/dist/adapters/git.d.ts.map +1 -0
  15. package/dist/adapters/git.js +90 -0
  16. package/dist/adapters/git.js.map +1 -0
  17. package/dist/adapters/graft.d.ts +14 -0
  18. package/dist/adapters/graft.d.ts.map +1 -0
  19. package/dist/adapters/graft.js +56 -0
  20. package/dist/adapters/graft.js.map +1 -0
  21. package/dist/adapters/package-manager.d.ts +20 -0
  22. package/dist/adapters/package-manager.d.ts.map +1 -0
  23. package/dist/adapters/package-manager.js +89 -0
  24. package/dist/adapters/package-manager.js.map +1 -0
  25. package/dist/adapters/skills.d.ts +29 -0
  26. package/dist/adapters/skills.d.ts.map +1 -0
  27. package/dist/adapters/skills.js +80 -0
  28. package/dist/adapters/skills.js.map +1 -0
  29. package/dist/cli/doctor.d.ts +2 -0
  30. package/dist/cli/doctor.d.ts.map +1 -0
  31. package/dist/cli/doctor.js +212 -0
  32. package/dist/cli/doctor.js.map +1 -0
  33. package/dist/cli/init.d.ts +3 -0
  34. package/dist/cli/init.d.ts.map +1 -0
  35. package/dist/cli/init.js +32 -0
  36. package/dist/cli/init.js.map +1 -0
  37. package/dist/cli/main.d.ts +3 -0
  38. package/dist/cli/main.d.ts.map +1 -0
  39. package/dist/cli/main.js +162 -0
  40. package/dist/cli/main.js.map +1 -0
  41. package/dist/cli/new.d.ts +15 -0
  42. package/dist/cli/new.d.ts.map +1 -0
  43. package/dist/cli/new.js +161 -0
  44. package/dist/cli/new.js.map +1 -0
  45. package/dist/cli/wizard.d.ts +31 -0
  46. package/dist/cli/wizard.d.ts.map +1 -0
  47. package/dist/cli/wizard.js +260 -0
  48. package/dist/cli/wizard.js.map +1 -0
  49. package/dist/config/defaults.d.ts +8 -0
  50. package/dist/config/defaults.d.ts.map +1 -0
  51. package/dist/config/defaults.js +122 -0
  52. package/dist/config/defaults.js.map +1 -0
  53. package/dist/config/schema.d.ts +40 -0
  54. package/dist/config/schema.d.ts.map +1 -0
  55. package/dist/config/schema.js +4 -0
  56. package/dist/config/schema.js.map +1 -0
  57. package/dist/config/validation.d.ts +11 -0
  58. package/dist/config/validation.d.ts.map +1 -0
  59. package/dist/config/validation.js +99 -0
  60. package/dist/config/validation.js.map +1 -0
  61. package/dist/index.d.ts +16 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +16 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/presets/adr.d.ts +5 -0
  66. package/dist/presets/adr.d.ts.map +1 -0
  67. package/dist/presets/adr.js +33 -0
  68. package/dist/presets/adr.js.map +1 -0
  69. package/dist/presets/cli.d.ts +3 -0
  70. package/dist/presets/cli.d.ts.map +1 -0
  71. package/dist/presets/cli.js +126 -0
  72. package/dist/presets/cli.js.map +1 -0
  73. package/dist/presets/generic.d.ts +3 -0
  74. package/dist/presets/generic.d.ts.map +1 -0
  75. package/dist/presets/generic.js +29 -0
  76. package/dist/presets/generic.js.map +1 -0
  77. package/dist/presets/registry.d.ts +6 -0
  78. package/dist/presets/registry.d.ts.map +1 -0
  79. package/dist/presets/registry.js +20 -0
  80. package/dist/presets/registry.js.map +1 -0
  81. package/dist/presets/testing.d.ts +6 -0
  82. package/dist/presets/testing.d.ts.map +1 -0
  83. package/dist/presets/testing.js +46 -0
  84. package/dist/presets/testing.js.map +1 -0
  85. package/dist/presets/types.d.ts +14 -0
  86. package/dist/presets/types.d.ts.map +1 -0
  87. package/dist/presets/types.js +2 -0
  88. package/dist/presets/types.js.map +1 -0
  89. package/dist/presets/web.d.ts +3 -0
  90. package/dist/presets/web.d.ts.map +1 -0
  91. package/dist/presets/web.js +84 -0
  92. package/dist/presets/web.js.map +1 -0
  93. package/dist/utils/fs.d.ts +13 -0
  94. package/dist/utils/fs.d.ts.map +1 -0
  95. package/dist/utils/fs.js +60 -0
  96. package/dist/utils/fs.js.map +1 -0
  97. package/dist/utils/logger.d.ts +10 -0
  98. package/dist/utils/logger.d.ts.map +1 -0
  99. package/dist/utils/logger.js +20 -0
  100. package/dist/utils/logger.js.map +1 -0
  101. package/dist/utils/shell.d.ts +17 -0
  102. package/dist/utils/shell.d.ts.map +1 -0
  103. package/dist/utils/shell.js +87 -0
  104. package/dist/utils/shell.js.map +1 -0
  105. package/package.json +71 -0
  106. package/src/adapters/agents-md.ts +143 -0
  107. package/src/adapters/browser.ts +49 -0
  108. package/src/adapters/git.ts +100 -0
  109. package/src/adapters/graft.ts +80 -0
  110. package/src/adapters/package-manager.ts +116 -0
  111. package/src/adapters/skills.ts +117 -0
  112. package/src/cli/doctor.ts +244 -0
  113. package/src/cli/init.ts +34 -0
  114. package/src/cli/main.ts +191 -0
  115. package/src/cli/new.ts +200 -0
  116. package/src/cli/wizard.ts +300 -0
  117. package/src/config/defaults.ts +137 -0
  118. package/src/config/schema.ts +44 -0
  119. package/src/config/validation.ts +96 -0
  120. package/src/index.ts +15 -0
  121. package/src/presets/adr.ts +37 -0
  122. package/src/presets/cli.ts +136 -0
  123. package/src/presets/generic.ts +32 -0
  124. package/src/presets/registry.ts +24 -0
  125. package/src/presets/testing.ts +56 -0
  126. package/src/presets/types.ts +15 -0
  127. package/src/presets/web.ts +99 -0
  128. package/src/utils/fs.ts +79 -0
  129. package/src/utils/logger.ts +20 -0
  130. package/src/utils/shell.ts +116 -0
package/src/cli/new.ts ADDED
@@ -0,0 +1,200 @@
1
+ import path from 'node:path';
2
+ import pc from 'picocolors';
3
+ import { getDefaultConfig } from '../config/defaults.js';
4
+ import {
5
+ AGINIT_CONFIG_FILENAME,
6
+ PresetType,
7
+ WebFramework,
8
+ PackageManager
9
+ } from '../config/schema.js';
10
+ import { getPreset } from '../presets/registry.js';
11
+ import { setupGit } from '../adapters/git.js';
12
+ import { setupAgentsMarkdown } from '../adapters/agents-md.js';
13
+ import { installAllSkills } from '../adapters/skills.js';
14
+ import { initGraft } from '../adapters/graft.js';
15
+ import { ensureDir, writeJsonFile } from '../utils/fs.js';
16
+ import {
17
+ readProjectConfig,
18
+ readPackageManifest,
19
+ validateConfig,
20
+ validateProjectName,
21
+ PRESETS,
22
+ FRAMEWORKS,
23
+ SUPPORTED_PACKAGE_MANAGERS
24
+ } from '../config/validation.js';
25
+ import { logger } from '../utils/logger.js';
26
+
27
+ export interface NewProjectOptions {
28
+ preset?: PresetType;
29
+ framework?: WebFramework;
30
+ packageManager?: PackageManager;
31
+ specWorkflow?: boolean;
32
+ skills?: boolean;
33
+ graft?: boolean;
34
+ git?: boolean;
35
+ dryRun?: boolean;
36
+ targetDir?: string;
37
+ silent?: boolean;
38
+ }
39
+
40
+ export async function createProject(
41
+ projectName: string,
42
+ options: NewProjectOptions = {}
43
+ ): Promise<boolean> {
44
+ validateProjectName(projectName);
45
+ if (options.preset !== undefined && !PRESETS.includes(options.preset))
46
+ throw new Error('Invalid preset.');
47
+ if (options.framework !== undefined && !FRAMEWORKS.includes(options.framework))
48
+ throw new Error('Invalid framework.');
49
+ if (
50
+ options.packageManager !== undefined &&
51
+ !SUPPORTED_PACKAGE_MANAGERS.includes(options.packageManager)
52
+ )
53
+ throw new Error('Invalid package manager.');
54
+ const defaultDir =
55
+ projectName.startsWith('@') && projectName.includes('/')
56
+ ? projectName.split('/').pop()!
57
+ : projectName;
58
+ const targetDir = path.resolve(options.targetDir || path.join(process.cwd(), defaultDir));
59
+ const existingConfig = readProjectConfig(targetDir);
60
+ const manifest = readPackageManifest(targetDir); // Validate before creating or modifying anything.
61
+ const presetName = options.preset ?? existingConfig?.preset ?? 'generic';
62
+ const framework =
63
+ options.framework ?? (presetName === 'web' ? existingConfig?.framework : undefined);
64
+ if (presetName !== 'web' && framework && framework !== 'none' && framework !== 'existing')
65
+ throw new Error('A web framework requires --preset web.');
66
+ if (presetName === 'web' && framework === 'existing' && !manifest)
67
+ throw new Error(
68
+ 'An existing web framework requires an existing package.json. Use --framework none for a new baseline.'
69
+ );
70
+ const packageManager = options.packageManager ?? existingConfig?.packageManager ?? 'pnpm';
71
+ const dryRun = !!options.dryRun;
72
+ const silent = !!options.silent;
73
+ const presetHandler = getPreset(presetName);
74
+ const defaults = getDefaultConfig(projectName, presetName, {
75
+ framework,
76
+ packageManager,
77
+ specWorkflow: options.specWorkflow
78
+ });
79
+ const config = validateConfig(
80
+ existingConfig
81
+ ? {
82
+ ...existingConfig,
83
+ name: projectName,
84
+ preset: presetName,
85
+ packageManager,
86
+ ...(presetName === 'web' ? { framework: framework ?? 'none' } : {}),
87
+ browser:
88
+ options.framework !== undefined || options.preset !== undefined
89
+ ? { ...existingConfig.browser, ...defaults.browser }
90
+ : existingConfig.browser,
91
+ skills:
92
+ options.specWorkflow !== undefined
93
+ ? {
94
+ ...existingConfig.skills,
95
+ workflow: defaults.skills.workflow,
96
+ sources: existingConfig.skills.sources.map((source) =>
97
+ source.package === 'mattpocock/skills'
98
+ ? {
99
+ ...source,
100
+ skills: defaults.skills.sources.find((s) => s.package === source.package)!
101
+ .skills
102
+ }
103
+ : source
104
+ )
105
+ }
106
+ : existingConfig.skills
107
+ }
108
+ : defaults
109
+ );
110
+ if (presetName !== 'web') delete config.framework;
111
+ if (options.graft === false) config.codebase = { ...config.codebase, graft: false };
112
+ if (options.skills === false && !existingConfig) config.skills.sources = [];
113
+ if (!silent)
114
+ logger.banner(
115
+ `Aginit — ${projectName}`,
116
+ `Preset: ${presetName} | PM: ${packageManager} | Target: ${targetDir}${dryRun ? ' (DRY RUN)' : ''}`
117
+ );
118
+ let complete = true;
119
+
120
+ const totalSteps = 6;
121
+ let currentStep = 1;
122
+
123
+ // Scaffold into the clean directory before Git adds files that upstream tools reject.
124
+ if (!silent) logger.step(currentStep++, totalSteps, `Scaffolding preset: ${presetHandler.name}`);
125
+ ensureDir(targetDir, dryRun);
126
+ await presetHandler.scaffold({ targetDir, projectName, config, dryRun, silent: true });
127
+ if (!silent) logger.success(`Scaffolded ${presetHandler.name} structure`);
128
+
129
+ if (!silent) logger.step(currentStep++, totalSteps, 'Configuring Git');
130
+ if (options.git !== false) {
131
+ const gitOk = await setupGit(targetDir, { dryRun, silent: true });
132
+ complete &&= gitOk;
133
+ if (gitOk && !silent) logger.success('Git repository initialized and .gitignore configured');
134
+ }
135
+
136
+ // Step 3: Write declarative project config
137
+ if (!silent) logger.step(currentStep++, totalSteps, 'Writing declarative project configuration');
138
+ writeJsonFile(path.join(targetDir, AGINIT_CONFIG_FILENAME), config, {
139
+ overwrite: true,
140
+ dryRun,
141
+ silent
142
+ });
143
+ if (!silent) logger.success(`Wrote ${AGINIT_CONFIG_FILENAME}`);
144
+
145
+ // Step 4: Write or update AGENTS.md intake contract
146
+ if (!silent) logger.step(currentStep++, totalSteps, 'Generating AGENTS.md intake guidance');
147
+ setupAgentsMarkdown(targetDir, config, { dryRun, silent });
148
+ if (!silent) logger.success('Configured AGENTS.md');
149
+
150
+ // Step 5: Install skills via skills.sh engine
151
+ if (!silent) logger.step(currentStep++, totalSteps, 'Installing upstream skills via skills.sh');
152
+ if (options.skills !== false && config.skills.sources.length > 0) {
153
+ const { installed, failed } = await installAllSkills(targetDir, config.skills.sources, {
154
+ agents: [config.agents.primary, config.agents.secondary],
155
+ dryRun,
156
+ silent
157
+ });
158
+ complete &&= failed.length === 0;
159
+ if (!silent) {
160
+ if (installed.length > 0) {
161
+ logger.success(`Installed skills: ${installed.join(', ')}`);
162
+ }
163
+ if (failed.length > 0) {
164
+ logger.warn(`Failed installing: ${failed.join(', ')}`);
165
+ }
166
+ }
167
+ } else if (!silent) {
168
+ logger.dim('Skills installation skipped (--no-skills or empty configuration)');
169
+ }
170
+
171
+ // Step 6: Codebase intelligence (Graft)
172
+ if (!silent) logger.step(currentStep++, totalSteps, 'Configuring codebase intelligence');
173
+ if (config.codebase.graft && options.graft !== false) {
174
+ const graftOk = await initGraft(targetDir, { dryRun, silent });
175
+ complete &&= graftOk;
176
+ if (graftOk && !silent) {
177
+ logger.success('Graft context graph initialized');
178
+ }
179
+ } else if (!silent) {
180
+ logger.dim('Graft setup skipped (--no-graft or codebase.graft: false)');
181
+ }
182
+
183
+ if (!silent) {
184
+ console.log();
185
+ if (complete) logger.success(pc.bold(`Project "${projectName}" is ready for development!`));
186
+ else
187
+ logger.warn(
188
+ `Project "${projectName}" was scaffolded with incomplete integrations. Resolve the warnings above and rerun aginit init.`
189
+ );
190
+ console.log();
191
+ console.log('Next steps:');
192
+ console.log(pc.cyan(` cd ${path.relative(process.cwd(), targetDir) || '.'}`));
193
+ console.log(pc.cyan(` ${packageManager} install`));
194
+ console.log(pc.cyan(' Open the repository in T3 Code'));
195
+ console.log(pc.dim(' Prompt the agent: ') + pc.bold(pc.green('"bootstrap this project"')));
196
+ console.log();
197
+ }
198
+
199
+ return complete;
200
+ }
@@ -0,0 +1,300 @@
1
+ import * as p from '@clack/prompts';
2
+ import pc from 'picocolors';
3
+ import { PresetType, WebFramework, PackageManager } from '../config/schema.js';
4
+ import { validateProjectName, readProjectConfig } from '../config/validation.js';
5
+ import { detectPackageManager } from '../adapters/package-manager.js';
6
+ import { createProject } from './new.js';
7
+ import { initCurrentDirectory } from './init.js';
8
+
9
+ export function isInteractive(): boolean {
10
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
11
+ }
12
+
13
+ function assertNotCancelled<T>(value: T | symbol): Exclude<T, symbol> {
14
+ if (p.isCancel(value)) {
15
+ p.cancel('Operation cancelled.');
16
+ process.exit(0);
17
+ }
18
+ return value as Exclude<T, symbol>;
19
+ }
20
+
21
+ export interface WizardNewAnswers {
22
+ projectName: string;
23
+ preset: PresetType;
24
+ framework: WebFramework;
25
+ packageManager: PackageManager;
26
+ specWorkflow: boolean;
27
+ }
28
+
29
+ export interface WizardInitAnswers {
30
+ preset: PresetType;
31
+ framework: WebFramework;
32
+ packageManager: PackageManager;
33
+ specWorkflow: boolean;
34
+ }
35
+
36
+ export async function promptNewProject(defaults?: {
37
+ projectName?: string;
38
+ preset?: PresetType;
39
+ framework?: WebFramework;
40
+ packageManager?: PackageManager;
41
+ specWorkflow?: boolean;
42
+ }): Promise<WizardNewAnswers> {
43
+ let projectName: string = defaults?.projectName || '';
44
+ if (!projectName) {
45
+ const res = await p.text({
46
+ message: 'What is your project name?',
47
+ placeholder: 'my-ai-project',
48
+ validate: (val) => {
49
+ if (!val || val.trim().length === 0) return 'Project name is required';
50
+ try {
51
+ validateProjectName(val.trim());
52
+ } catch (error) {
53
+ return error instanceof Error ? error.message : 'Invalid project name';
54
+ }
55
+ }
56
+ });
57
+ projectName = String(assertNotCancelled(res)).trim();
58
+ }
59
+
60
+ let preset = defaults?.preset;
61
+ if (!preset) {
62
+ const res = await p.select({
63
+ message: 'Select a project preset:',
64
+ initialValue: 'web',
65
+ options: [
66
+ {
67
+ value: 'web',
68
+ label: 'Web Application',
69
+ hint: 'React, Next.js, Vite, or agnostic + Vitest/Playwright'
70
+ },
71
+ { value: 'cli', label: 'CLI Tool', hint: 'TypeScript, Commander, Picocolors + Vitest' },
72
+ {
73
+ value: 'generic',
74
+ label: 'Generic / Existing Codebase',
75
+ hint: 'Codebase graph + agent intake guide'
76
+ }
77
+ ]
78
+ });
79
+ preset = assertNotCancelled(res) as PresetType;
80
+ }
81
+
82
+ let framework: WebFramework = defaults?.framework || 'none';
83
+ if (preset === 'web' && defaults?.framework === undefined) {
84
+ const res = await p.select({
85
+ message: 'Choose a web framework:',
86
+ initialValue: 'none',
87
+ options: [
88
+ {
89
+ value: 'none',
90
+ label: 'Framework-agnostic (Recommended)',
91
+ hint: 'Clean TypeScript + Vitest, zero bundler lock-in'
92
+ },
93
+ {
94
+ value: 'vite',
95
+ label: 'Vite',
96
+ hint: 'Official Vite React-TS scaffolder + Playwright E2E'
97
+ },
98
+ { value: 'next', label: 'Next.js', hint: 'Official create-next-app + Playwright E2E' }
99
+ ]
100
+ });
101
+ framework = assertNotCancelled(res) as WebFramework;
102
+ }
103
+
104
+ let specWorkflow = defaults?.specWorkflow;
105
+ if (specWorkflow === undefined) {
106
+ const res = await p.select({
107
+ message: 'Select AI engineering workflow:',
108
+ initialValue: 'minimal',
109
+ options: [
110
+ {
111
+ value: 'minimal',
112
+ label: 'Standard Workflow (Recommended)',
113
+ hint: 'TDD, Code Review, Diagnosing Bugs'
114
+ },
115
+ {
116
+ value: 'spec',
117
+ label: 'Spec & Tickets Workflow',
118
+ hint: 'Adds to-spec, to-tickets, implement-spec'
119
+ }
120
+ ]
121
+ });
122
+ const selected = assertNotCancelled(res);
123
+ specWorkflow = selected === 'spec';
124
+ }
125
+
126
+ let packageManager = defaults?.packageManager;
127
+ if (!packageManager) {
128
+ const res = await p.select({
129
+ message: 'Select package manager:',
130
+ initialValue: 'pnpm',
131
+ options: [
132
+ {
133
+ value: 'pnpm',
134
+ label: 'pnpm (Recommended)',
135
+ hint: 'Fast, disk-efficient & compliant workspace'
136
+ },
137
+ { value: 'npm', label: 'npm', hint: 'Standard Node.js package manager' },
138
+ { value: 'yarn', label: 'yarn', hint: 'Yarn package manager' },
139
+ { value: 'bun', label: 'bun', hint: 'Fast all-in-one JavaScript runtime & toolkit' }
140
+ ]
141
+ });
142
+ packageManager = assertNotCancelled(res) as PackageManager;
143
+ }
144
+
145
+ return {
146
+ projectName,
147
+ preset,
148
+ framework,
149
+ packageManager,
150
+ specWorkflow
151
+ };
152
+ }
153
+
154
+ export async function promptInitProject(defaults?: {
155
+ targetDir?: string;
156
+ preset?: PresetType;
157
+ framework?: WebFramework;
158
+ packageManager?: PackageManager;
159
+ specWorkflow?: boolean;
160
+ }): Promise<WizardInitAnswers> {
161
+ const targetDir = defaults?.targetDir || process.cwd();
162
+
163
+ let preset = defaults?.preset;
164
+ if (!preset) {
165
+ const res = await p.select({
166
+ message: 'Select project preset to configure in this directory:',
167
+ initialValue: 'web',
168
+ options: [
169
+ { value: 'web', label: 'Web Application', hint: 'Impeccable UI, agent-browser, Vitest' },
170
+ { value: 'cli', label: 'CLI Tool', hint: 'TypeScript, Vitest' },
171
+ {
172
+ value: 'generic',
173
+ label: 'Generic Repository',
174
+ hint: 'Codebase graph + agent intake guide'
175
+ }
176
+ ]
177
+ });
178
+ preset = assertNotCancelled(res) as PresetType;
179
+ }
180
+
181
+ let framework: WebFramework = defaults?.framework || 'existing';
182
+ if (preset === 'web' && defaults?.framework === undefined) {
183
+ const res = await p.select({
184
+ message: 'Select web framework setting:',
185
+ initialValue: 'existing',
186
+ options: [
187
+ {
188
+ value: 'existing',
189
+ label: 'Existing Web Setup (Recommended)',
190
+ hint: 'Preserve existing bundler and dependencies'
191
+ },
192
+ { value: 'none', label: 'Framework-agnostic', hint: 'Baseline TypeScript' },
193
+ { value: 'vite', label: 'Vite', hint: 'Vite React setup' },
194
+ { value: 'next', label: 'Next.js', hint: 'Next.js setup' }
195
+ ]
196
+ });
197
+ framework = assertNotCancelled(res) as WebFramework;
198
+ }
199
+
200
+ let specWorkflow = defaults?.specWorkflow;
201
+ if (specWorkflow === undefined) {
202
+ const res = await p.select({
203
+ message: 'Select AI engineering workflow:',
204
+ initialValue: 'minimal',
205
+ options: [
206
+ {
207
+ value: 'minimal',
208
+ label: 'Standard Workflow (Recommended)',
209
+ hint: 'TDD, Code Review, Diagnosing Bugs'
210
+ },
211
+ {
212
+ value: 'spec',
213
+ label: 'Spec & Tickets Workflow',
214
+ hint: 'Adds to-spec, to-tickets, implement-spec'
215
+ }
216
+ ]
217
+ });
218
+ const selected = assertNotCancelled(res);
219
+ specWorkflow = selected === 'spec';
220
+ }
221
+
222
+ // Auto-detect and preserve existing package manager without prompting
223
+ let packageManager = defaults?.packageManager;
224
+ if (!packageManager) {
225
+ const detected = detectPackageManager(targetDir);
226
+ if (detected) {
227
+ packageManager = detected;
228
+ } else {
229
+ const res = await p.select({
230
+ message: 'Select package manager for this project:',
231
+ initialValue: 'pnpm',
232
+ options: [
233
+ { value: 'pnpm', label: 'pnpm (Recommended)', hint: 'Fast, disk-efficient workspace' },
234
+ { value: 'npm', label: 'npm', hint: 'Standard Node.js package manager' },
235
+ { value: 'yarn', label: 'yarn', hint: 'Yarn package manager' },
236
+ { value: 'bun', label: 'bun', hint: 'Fast runtime and package manager' }
237
+ ]
238
+ });
239
+ packageManager = assertNotCancelled(res) as PackageManager;
240
+ }
241
+ }
242
+
243
+ return {
244
+ preset,
245
+ framework,
246
+ packageManager,
247
+ specWorkflow
248
+ };
249
+ }
250
+
251
+ export async function runInteractiveWizard(): Promise<void> {
252
+ p.intro(pc.bgCyan(pc.black(' aginit ')) + pc.dim(' — AI-First Project Bootstrap'));
253
+
254
+ const action = assertNotCancelled(
255
+ await p.select({
256
+ message: 'What would you like to do?',
257
+ initialValue: 'new',
258
+ options: [
259
+ {
260
+ value: 'new',
261
+ label: 'Create a brand new AI-first project',
262
+ hint: 'Scaffold in a new directory'
263
+ },
264
+ {
265
+ value: 'init',
266
+ label: 'Initialize AI capabilities in current directory',
267
+ hint: 'Add AGENTS.md, skills & Graft safely'
268
+ }
269
+ ]
270
+ })
271
+ );
272
+
273
+ let complete: boolean;
274
+ if (action === 'new') {
275
+ const answers = await promptNewProject();
276
+ p.outro(pc.cyan(`Scaffolding "${answers.projectName}"...`));
277
+ complete = await createProject(answers.projectName, {
278
+ preset: answers.preset,
279
+ framework: answers.framework,
280
+ packageManager: answers.packageManager,
281
+ specWorkflow: answers.specWorkflow
282
+ });
283
+ } else {
284
+ const saved = readProjectConfig(process.cwd());
285
+ if (saved) {
286
+ p.outro(pc.cyan('Configuring current directory using saved settings...'));
287
+ complete = await initCurrentDirectory();
288
+ } else {
289
+ const answers = await promptInitProject();
290
+ p.outro(pc.cyan('Configuring current directory...'));
291
+ complete = await initCurrentDirectory({
292
+ preset: answers.preset,
293
+ framework: answers.framework,
294
+ packageManager: answers.packageManager,
295
+ specWorkflow: answers.specWorkflow
296
+ });
297
+ }
298
+ }
299
+ if (!complete) process.exitCode = 1;
300
+ }
@@ -0,0 +1,137 @@
1
+ import { AginitConfig, PresetType, WebFramework, PackageManager } from './schema.js';
2
+
3
+ export interface DefaultConfigOptions {
4
+ framework?: WebFramework;
5
+ specWorkflow?: boolean;
6
+ packageManager?: PackageManager;
7
+ }
8
+
9
+ export function getDefaultConfig(
10
+ name: string,
11
+ preset: PresetType,
12
+ options: DefaultConfigOptions = {}
13
+ ): AginitConfig {
14
+ const specWorkflow = !!options.specWorkflow;
15
+ const packageManager = options.packageManager || 'pnpm';
16
+ const mattSkills = specWorkflow
17
+ ? ['tdd', 'code-review', 'diagnosing-bugs', 'to-spec', 'to-tickets', 'implement-spec']
18
+ : ['tdd', 'code-review', 'diagnosing-bugs'];
19
+
20
+ switch (preset) {
21
+ case 'web': {
22
+ const framework = options.framework || 'none';
23
+ const hasWebTarget = framework === 'vite' || framework === 'next';
24
+
25
+ return {
26
+ schemaVersion: '1.0.0',
27
+ name,
28
+ preset: 'web',
29
+ framework,
30
+ packageManager,
31
+ agents: {
32
+ primary: 'antigravity',
33
+ secondary: 'codex'
34
+ },
35
+ skills: {
36
+ workflow: specWorkflow ? 'spec' : 'minimal',
37
+ sources: [
38
+ {
39
+ package: 'mattpocock/skills',
40
+ skills: mattSkills
41
+ },
42
+ {
43
+ package: 'pbakaus/impeccable',
44
+ skills: ['impeccable']
45
+ },
46
+ {
47
+ package: 'vercel-labs/agent-browser',
48
+ skills: ['agent-browser']
49
+ }
50
+ ]
51
+ },
52
+ codebase: {
53
+ graft: true
54
+ },
55
+ browser: {
56
+ visualAgent: true,
57
+ playwright: hasWebTarget
58
+ },
59
+ docs: {
60
+ adr: true
61
+ },
62
+ github: {
63
+ ci: true
64
+ }
65
+ };
66
+ }
67
+
68
+ case 'cli':
69
+ return {
70
+ schemaVersion: '1.0.0',
71
+ name,
72
+ preset: 'cli',
73
+ packageManager,
74
+ agents: {
75
+ primary: 'antigravity',
76
+ secondary: 'codex'
77
+ },
78
+ skills: {
79
+ workflow: specWorkflow ? 'spec' : 'minimal',
80
+ sources: [
81
+ {
82
+ package: 'mattpocock/skills',
83
+ skills: mattSkills
84
+ }
85
+ ]
86
+ },
87
+ codebase: {
88
+ graft: true
89
+ },
90
+ browser: {
91
+ visualAgent: false,
92
+ playwright: false
93
+ },
94
+ docs: {
95
+ adr: true
96
+ },
97
+ github: {
98
+ ci: true
99
+ }
100
+ };
101
+
102
+ case 'generic':
103
+ default:
104
+ return {
105
+ schemaVersion: '1.0.0',
106
+ name,
107
+ preset: 'generic',
108
+ packageManager,
109
+ agents: {
110
+ primary: 'antigravity',
111
+ secondary: 'codex'
112
+ },
113
+ skills: {
114
+ workflow: specWorkflow ? 'spec' : 'minimal',
115
+ sources: [
116
+ {
117
+ package: 'mattpocock/skills',
118
+ skills: mattSkills
119
+ }
120
+ ]
121
+ },
122
+ codebase: {
123
+ graft: true
124
+ },
125
+ browser: {
126
+ visualAgent: false,
127
+ playwright: false
128
+ },
129
+ docs: {
130
+ adr: true
131
+ },
132
+ github: {
133
+ ci: false
134
+ }
135
+ };
136
+ }
137
+ }
@@ -0,0 +1,44 @@
1
+ export type PresetType = 'web' | 'cli' | 'generic';
2
+ export type WebFramework = 'none' | 'vite' | 'next' | 'existing';
3
+ export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
4
+
5
+ export interface SkillSourceConfig {
6
+ package: string;
7
+ skills: string[];
8
+ }
9
+
10
+ export interface AginitConfig {
11
+ schemaVersion: string;
12
+ name: string;
13
+ preset: PresetType;
14
+ framework?: WebFramework;
15
+ packageManager?: PackageManager;
16
+ agents: {
17
+ primary: string;
18
+ secondary: string;
19
+ };
20
+ skills: {
21
+ workflow?: 'minimal' | 'spec';
22
+ sources: SkillSourceConfig[];
23
+ };
24
+ codebase: {
25
+ graft: boolean;
26
+ };
27
+ browser: {
28
+ visualAgent: boolean;
29
+ playwright: boolean;
30
+ };
31
+ docs: {
32
+ adr: boolean;
33
+ };
34
+ github: {
35
+ ci: boolean;
36
+ };
37
+ }
38
+
39
+ // Backward-compatible alias
40
+ export type AIProjectConfig = AginitConfig;
41
+
42
+ export const AGINIT_CONFIG_FILENAME = 'aginit.config.json';
43
+ export const LEGACY_CONFIG_FILENAME = 'ai.config.json';
44
+ export const AI_CONFIG_FILENAME = AGINIT_CONFIG_FILENAME;