@nclamvn/vibecode-cli 1.0.0 → 1.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.
- package/bin/vibecode.js +36 -1
- package/package.json +1 -1
- package/src/commands/build.js +308 -0
- package/src/commands/plan.js +105 -0
- package/src/commands/review.js +290 -0
- package/src/commands/snapshot.js +252 -0
- package/src/commands/status.js +13 -2
- package/src/config/constants.js +26 -16
- package/src/config/templates.js +272 -1
- package/src/core/session.js +8 -1
- package/src/index.js +7 -0
- package/src/ui/output.js +3 -3
package/bin/vibecode.js
CHANGED
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
statusCommand,
|
|
13
13
|
lockCommand,
|
|
14
14
|
doctorCommand,
|
|
15
|
+
planCommand,
|
|
16
|
+
buildCommand,
|
|
17
|
+
reviewCommand,
|
|
18
|
+
snapshotCommand,
|
|
15
19
|
VERSION
|
|
16
20
|
} from '../src/index.js';
|
|
17
21
|
|
|
@@ -23,7 +27,7 @@ program
|
|
|
23
27
|
.version(VERSION);
|
|
24
28
|
|
|
25
29
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
-
// Commands
|
|
30
|
+
// Phase A Commands - Planning
|
|
27
31
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
32
|
|
|
29
33
|
program
|
|
@@ -58,6 +62,37 @@ program
|
|
|
58
62
|
.description('Check configuration and diagnose issues')
|
|
59
63
|
.action(doctorCommand);
|
|
60
64
|
|
|
65
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
// Phase B Commands - Execution
|
|
67
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
program
|
|
70
|
+
.command('plan')
|
|
71
|
+
.description('Create execution plan from locked contract')
|
|
72
|
+
.action(planCommand);
|
|
73
|
+
|
|
74
|
+
program
|
|
75
|
+
.command('build')
|
|
76
|
+
.description('Manage build process and capture evidence')
|
|
77
|
+
.option('-s, --start', 'Start the build process')
|
|
78
|
+
.option('-c, --complete', 'Mark build as complete')
|
|
79
|
+
.option('-e, --evidence', 'Capture evidence snapshot')
|
|
80
|
+
.action(buildCommand);
|
|
81
|
+
|
|
82
|
+
program
|
|
83
|
+
.command('review')
|
|
84
|
+
.description('Review build against acceptance criteria')
|
|
85
|
+
.option('--skip-manual', 'Skip manual verification prompts')
|
|
86
|
+
.action(reviewCommand);
|
|
87
|
+
|
|
88
|
+
program
|
|
89
|
+
.command('snapshot')
|
|
90
|
+
.description('Create release snapshot with version bump')
|
|
91
|
+
.option('--patch', 'Patch version bump (default)')
|
|
92
|
+
.option('--minor', 'Minor version bump')
|
|
93
|
+
.option('--major', 'Major version bump')
|
|
94
|
+
.action(snapshotCommand);
|
|
95
|
+
|
|
61
96
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
62
97
|
// Parse
|
|
63
98
|
// ─────────────────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - Build Command
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { exec } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
import { workspaceExists, getProjectName, loadState, saveState } from '../core/workspace.js';
|
|
11
|
+
import {
|
|
12
|
+
getCurrentSessionId,
|
|
13
|
+
getCurrentSessionPath,
|
|
14
|
+
writeSessionFile,
|
|
15
|
+
sessionFileExists
|
|
16
|
+
} from '../core/session.js';
|
|
17
|
+
import { getCurrentState, transitionTo } from '../core/state-machine.js';
|
|
18
|
+
import { getSpecHash } from '../core/contract.js';
|
|
19
|
+
import { STATES } from '../config/constants.js';
|
|
20
|
+
import { getBuildReportTemplate } from '../config/templates.js';
|
|
21
|
+
import { ensureDir, pathExists, appendToFile } from '../utils/files.js';
|
|
22
|
+
import { printBox, printError, printSuccess, printWarning, printNextStep } from '../ui/output.js';
|
|
23
|
+
|
|
24
|
+
const execAsync = promisify(exec);
|
|
25
|
+
|
|
26
|
+
export async function buildCommand(options = {}) {
|
|
27
|
+
try {
|
|
28
|
+
// Check workspace
|
|
29
|
+
if (!await workspaceExists()) {
|
|
30
|
+
printError('No Vibecode workspace found. Run `vibecode init` first.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const currentState = await getCurrentState();
|
|
35
|
+
const projectName = await getProjectName();
|
|
36
|
+
const sessionId = await getCurrentSessionId();
|
|
37
|
+
const sessionPath = await getCurrentSessionPath();
|
|
38
|
+
const specHash = await getSpecHash();
|
|
39
|
+
|
|
40
|
+
// Handle different build modes
|
|
41
|
+
if (options.start) {
|
|
42
|
+
await handleBuildStart(currentState, projectName, sessionId, sessionPath, specHash);
|
|
43
|
+
} else if (options.complete) {
|
|
44
|
+
await handleBuildComplete(currentState, projectName, sessionId, sessionPath, specHash);
|
|
45
|
+
} else if (options.evidence) {
|
|
46
|
+
await handleCaptureEvidence(currentState, sessionPath);
|
|
47
|
+
} else {
|
|
48
|
+
await handleBuildStatus(currentState, projectName, sessionId, sessionPath, specHash);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
} catch (error) {
|
|
52
|
+
printError(error.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function handleBuildStart(currentState, projectName, sessionId, sessionPath, specHash) {
|
|
58
|
+
const spinner = ora('Starting build...').start();
|
|
59
|
+
|
|
60
|
+
// Check state
|
|
61
|
+
if (currentState !== STATES.PLAN_CREATED && currentState !== STATES.REVIEW_FAILED) {
|
|
62
|
+
spinner.fail();
|
|
63
|
+
printError(`Cannot start build in state: ${currentState}`);
|
|
64
|
+
console.log('Run `vibecode plan` first to create execution plan.');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Create evidence directory
|
|
69
|
+
const evidencePath = path.join(sessionPath, 'evidence');
|
|
70
|
+
await ensureDir(evidencePath);
|
|
71
|
+
await ensureDir(path.join(evidencePath, 'screenshots'));
|
|
72
|
+
|
|
73
|
+
// Save build start time
|
|
74
|
+
const stateData = await loadState();
|
|
75
|
+
stateData.build_started = new Date().toISOString();
|
|
76
|
+
await saveState(stateData);
|
|
77
|
+
|
|
78
|
+
// Initialize build log
|
|
79
|
+
const logPath = path.join(evidencePath, 'build.log');
|
|
80
|
+
await appendToFile(logPath, `=== BUILD STARTED: ${stateData.build_started} ===\n`);
|
|
81
|
+
|
|
82
|
+
// Transition state
|
|
83
|
+
await transitionTo(STATES.BUILD_IN_PROGRESS, 'build_started');
|
|
84
|
+
|
|
85
|
+
spinner.succeed('Build started!');
|
|
86
|
+
|
|
87
|
+
const content = `🏗️ BUILD IN PROGRESS
|
|
88
|
+
|
|
89
|
+
Project: ${projectName}
|
|
90
|
+
Session: ${sessionId}
|
|
91
|
+
Spec Hash: ${specHash}
|
|
92
|
+
Started: ${stateData.build_started}
|
|
93
|
+
|
|
94
|
+
Evidence folder ready:
|
|
95
|
+
${evidencePath}/
|
|
96
|
+
├── build.log
|
|
97
|
+
└── screenshots/`;
|
|
98
|
+
|
|
99
|
+
console.log();
|
|
100
|
+
printBox(content, { borderColor: 'yellow' });
|
|
101
|
+
|
|
102
|
+
console.log();
|
|
103
|
+
console.log(chalk.cyan('📝 While building:'));
|
|
104
|
+
console.log(chalk.gray(' • Follow coder_pack.md instructions'));
|
|
105
|
+
console.log(chalk.gray(' • Capture evidence with `vibecode build --evidence`'));
|
|
106
|
+
console.log(chalk.gray(' • Complete with `vibecode build --complete`'));
|
|
107
|
+
|
|
108
|
+
printNextStep('Build your deliverables and run `vibecode build --complete` when done');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function handleBuildComplete(currentState, projectName, sessionId, sessionPath, specHash) {
|
|
112
|
+
const spinner = ora('Completing build...').start();
|
|
113
|
+
|
|
114
|
+
// Check state
|
|
115
|
+
if (currentState !== STATES.BUILD_IN_PROGRESS) {
|
|
116
|
+
spinner.fail();
|
|
117
|
+
printError(`Cannot complete build in state: ${currentState}`);
|
|
118
|
+
console.log('Run `vibecode build --start` first.');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const stateData = await loadState();
|
|
123
|
+
const startTime = stateData.build_started;
|
|
124
|
+
const endTime = new Date().toISOString();
|
|
125
|
+
|
|
126
|
+
// Capture final evidence
|
|
127
|
+
spinner.text = 'Capturing evidence...';
|
|
128
|
+
const evidencePath = path.join(sessionPath, 'evidence');
|
|
129
|
+
await captureGitDiff(evidencePath);
|
|
130
|
+
|
|
131
|
+
// Append to build log
|
|
132
|
+
const logPath = path.join(evidencePath, 'build.log');
|
|
133
|
+
await appendToFile(logPath, `\n=== BUILD COMPLETED: ${endTime} ===`);
|
|
134
|
+
|
|
135
|
+
// Check evidence collected
|
|
136
|
+
const evidence = await checkEvidence(evidencePath);
|
|
137
|
+
|
|
138
|
+
// Generate build report
|
|
139
|
+
spinner.text = 'Generating build report...';
|
|
140
|
+
const reportContent = getBuildReportTemplate(
|
|
141
|
+
projectName,
|
|
142
|
+
sessionId,
|
|
143
|
+
specHash,
|
|
144
|
+
startTime,
|
|
145
|
+
endTime,
|
|
146
|
+
evidence
|
|
147
|
+
);
|
|
148
|
+
await writeSessionFile('build_report.md', reportContent);
|
|
149
|
+
|
|
150
|
+
// Save end time
|
|
151
|
+
stateData.build_completed = endTime;
|
|
152
|
+
await saveState(stateData);
|
|
153
|
+
|
|
154
|
+
// Transition state
|
|
155
|
+
await transitionTo(STATES.BUILD_DONE, 'build_completed');
|
|
156
|
+
|
|
157
|
+
spinner.succeed('Build completed!');
|
|
158
|
+
|
|
159
|
+
const duration = Math.round((new Date(endTime) - new Date(startTime)) / 1000 / 60);
|
|
160
|
+
|
|
161
|
+
const content = `✅ BUILD COMPLETED
|
|
162
|
+
|
|
163
|
+
Project: ${projectName}
|
|
164
|
+
Duration: ${duration} minutes
|
|
165
|
+
Evidence collected:
|
|
166
|
+
${evidence.hasDiff ? ' ✅ changes.diff' : ' ⬜ changes.diff'}
|
|
167
|
+
${evidence.hasLog ? ' ✅ build.log' : ' ⬜ build.log'}
|
|
168
|
+
${evidence.screenshots > 0 ? ` ✅ ${evidence.screenshots} screenshots` : ' ⬜ No screenshots'}`;
|
|
169
|
+
|
|
170
|
+
console.log();
|
|
171
|
+
printBox(content, { borderColor: 'green' });
|
|
172
|
+
|
|
173
|
+
printNextStep('Run `vibecode review` to validate your build');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function handleCaptureEvidence(currentState, sessionPath) {
|
|
177
|
+
const spinner = ora('Capturing evidence...').start();
|
|
178
|
+
|
|
179
|
+
if (currentState !== STATES.BUILD_IN_PROGRESS) {
|
|
180
|
+
spinner.fail();
|
|
181
|
+
printError('Can only capture evidence during BUILD_IN_PROGRESS state');
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const evidencePath = path.join(sessionPath, 'evidence');
|
|
186
|
+
await ensureDir(evidencePath);
|
|
187
|
+
|
|
188
|
+
// Capture git diff
|
|
189
|
+
await captureGitDiff(evidencePath);
|
|
190
|
+
|
|
191
|
+
// Append to build log
|
|
192
|
+
const timestamp = new Date().toISOString();
|
|
193
|
+
await appendToFile(
|
|
194
|
+
path.join(evidencePath, 'build.log'),
|
|
195
|
+
`\n[${timestamp}] Evidence snapshot captured\n`
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
spinner.succeed('Evidence captured!');
|
|
199
|
+
|
|
200
|
+
const evidence = await checkEvidence(evidencePath);
|
|
201
|
+
console.log();
|
|
202
|
+
console.log(chalk.cyan('📁 Evidence collected:'));
|
|
203
|
+
console.log(chalk.gray(` ${evidence.hasDiff ? '✅' : '⬜'} changes.diff`));
|
|
204
|
+
console.log(chalk.gray(` ${evidence.hasLog ? '✅' : '⬜'} build.log`));
|
|
205
|
+
console.log(chalk.gray(` ${evidence.screenshots > 0 ? `✅ ${evidence.screenshots}` : '⬜ 0'} screenshots`));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function handleBuildStatus(currentState, projectName, sessionId, sessionPath, specHash) {
|
|
209
|
+
if (currentState === STATES.BUILD_IN_PROGRESS) {
|
|
210
|
+
const stateData = await loadState();
|
|
211
|
+
const evidencePath = path.join(sessionPath, 'evidence');
|
|
212
|
+
const evidence = await checkEvidence(evidencePath);
|
|
213
|
+
|
|
214
|
+
const elapsed = Math.round((new Date() - new Date(stateData.build_started)) / 1000 / 60);
|
|
215
|
+
|
|
216
|
+
const content = `🏗️ BUILD IN PROGRESS
|
|
217
|
+
|
|
218
|
+
Project: ${projectName}
|
|
219
|
+
Session: ${sessionId}
|
|
220
|
+
Started: ${stateData.build_started}
|
|
221
|
+
Elapsed: ${elapsed} minutes
|
|
222
|
+
|
|
223
|
+
Evidence:
|
|
224
|
+
${evidence.hasDiff ? ' ✅ changes.diff' : ' ⬜ changes.diff'}
|
|
225
|
+
${evidence.hasLog ? ' ✅ build.log' : ' ⬜ build.log'}
|
|
226
|
+
${evidence.screenshots > 0 ? ` ✅ ${evidence.screenshots} screenshots` : ' ⬜ No screenshots'}`;
|
|
227
|
+
|
|
228
|
+
console.log();
|
|
229
|
+
printBox(content, { borderColor: 'yellow' });
|
|
230
|
+
|
|
231
|
+
console.log();
|
|
232
|
+
console.log(chalk.cyan('Commands:'));
|
|
233
|
+
console.log(chalk.gray(' --evidence Capture current git diff'));
|
|
234
|
+
console.log(chalk.gray(' --complete Mark build as done'));
|
|
235
|
+
|
|
236
|
+
} else if (currentState === STATES.BUILD_DONE) {
|
|
237
|
+
printSuccess('Build already completed!');
|
|
238
|
+
printNextStep('Run `vibecode review` to validate');
|
|
239
|
+
|
|
240
|
+
} else {
|
|
241
|
+
printWarning(`Current state: ${currentState}`);
|
|
242
|
+
console.log('Run `vibecode build --start` to begin building.');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function captureGitDiff(evidencePath) {
|
|
247
|
+
try {
|
|
248
|
+
const { stdout } = await execAsync('git diff HEAD', { maxBuffer: 10 * 1024 * 1024 });
|
|
249
|
+
const diffPath = path.join(evidencePath, 'changes.diff');
|
|
250
|
+
|
|
251
|
+
if (stdout.trim()) {
|
|
252
|
+
const fs = await import('fs-extra');
|
|
253
|
+
await fs.default.writeFile(diffPath, stdout, 'utf-8');
|
|
254
|
+
} else {
|
|
255
|
+
// Try staged changes
|
|
256
|
+
const { stdout: stagedDiff } = await execAsync('git diff --cached', { maxBuffer: 10 * 1024 * 1024 });
|
|
257
|
+
if (stagedDiff.trim()) {
|
|
258
|
+
const fs = await import('fs-extra');
|
|
259
|
+
await fs.default.writeFile(diffPath, stagedDiff, 'utf-8');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
// Git might not be available, that's okay
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function checkEvidence(evidencePath) {
|
|
268
|
+
const result = {
|
|
269
|
+
hasDiff: false,
|
|
270
|
+
hasLog: false,
|
|
271
|
+
screenshots: 0,
|
|
272
|
+
filesChanged: 0,
|
|
273
|
+
linesAdded: 0,
|
|
274
|
+
linesRemoved: 0
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
result.hasDiff = await pathExists(path.join(evidencePath, 'changes.diff'));
|
|
279
|
+
result.hasLog = await pathExists(path.join(evidencePath, 'build.log'));
|
|
280
|
+
|
|
281
|
+
const screenshotsPath = path.join(evidencePath, 'screenshots');
|
|
282
|
+
if (await pathExists(screenshotsPath)) {
|
|
283
|
+
const fs = await import('fs-extra');
|
|
284
|
+
const files = await fs.default.readdir(screenshotsPath);
|
|
285
|
+
result.screenshots = files.filter(f => /\.(png|jpg|jpeg|gif)$/i.test(f)).length;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Parse git diff stats
|
|
289
|
+
if (result.hasDiff) {
|
|
290
|
+
try {
|
|
291
|
+
const { stdout } = await execAsync('git diff --stat HEAD');
|
|
292
|
+
const statsLine = stdout.split('\n').pop();
|
|
293
|
+
const match = statsLine?.match(/(\d+) files? changed(?:, (\d+) insertions?)?(?:, (\d+) deletions?)?/);
|
|
294
|
+
if (match) {
|
|
295
|
+
result.filesChanged = parseInt(match[1]) || 0;
|
|
296
|
+
result.linesAdded = parseInt(match[2]) || 0;
|
|
297
|
+
result.linesRemoved = parseInt(match[3]) || 0;
|
|
298
|
+
}
|
|
299
|
+
} catch (e) {
|
|
300
|
+
// Ignore git errors
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
// Ignore errors
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - Plan Command
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { workspaceExists, getProjectName } from '../core/workspace.js';
|
|
9
|
+
import {
|
|
10
|
+
getCurrentSessionId,
|
|
11
|
+
getCurrentSessionPath,
|
|
12
|
+
readSessionFile,
|
|
13
|
+
writeSessionFile,
|
|
14
|
+
sessionFileExists
|
|
15
|
+
} from '../core/session.js';
|
|
16
|
+
import { getCurrentState, transitionTo } from '../core/state-machine.js';
|
|
17
|
+
import { getSpecHash } from '../core/contract.js';
|
|
18
|
+
import { STATES } from '../config/constants.js';
|
|
19
|
+
import { getPlanTemplate, getCoderPackTemplate } from '../config/templates.js';
|
|
20
|
+
import { printBox, printError, printSuccess, printNextStep } from '../ui/output.js';
|
|
21
|
+
|
|
22
|
+
export async function planCommand(options = {}) {
|
|
23
|
+
const spinner = ora('Creating execution plan...').start();
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Check workspace
|
|
27
|
+
if (!await workspaceExists()) {
|
|
28
|
+
spinner.fail();
|
|
29
|
+
printError('No Vibecode workspace found. Run `vibecode init` first.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check state
|
|
34
|
+
const currentState = await getCurrentState();
|
|
35
|
+
if (currentState !== STATES.CONTRACT_LOCKED) {
|
|
36
|
+
spinner.fail();
|
|
37
|
+
printError(`Cannot create plan in state: ${currentState}`);
|
|
38
|
+
console.log('Contract must be locked first. Run `vibecode lock`.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Get session info
|
|
43
|
+
const projectName = await getProjectName();
|
|
44
|
+
const sessionId = await getCurrentSessionId();
|
|
45
|
+
const sessionPath = await getCurrentSessionPath();
|
|
46
|
+
const specHash = await getSpecHash();
|
|
47
|
+
|
|
48
|
+
// Read contract and blueprint
|
|
49
|
+
spinner.text = 'Reading contract...';
|
|
50
|
+
const contractContent = await readSessionFile('contract.md');
|
|
51
|
+
|
|
52
|
+
let blueprintContent = '';
|
|
53
|
+
if (await sessionFileExists('blueprint.md')) {
|
|
54
|
+
blueprintContent = await readSessionFile('blueprint.md');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Generate plan
|
|
58
|
+
spinner.text = 'Generating plan...';
|
|
59
|
+
const planContent = getPlanTemplate(projectName, sessionId, specHash, contractContent);
|
|
60
|
+
await writeSessionFile('plan.md', planContent);
|
|
61
|
+
|
|
62
|
+
// Generate coder pack
|
|
63
|
+
spinner.text = 'Generating coder pack...';
|
|
64
|
+
const coderPackContent = getCoderPackTemplate(
|
|
65
|
+
projectName,
|
|
66
|
+
sessionId,
|
|
67
|
+
specHash,
|
|
68
|
+
contractContent,
|
|
69
|
+
blueprintContent
|
|
70
|
+
);
|
|
71
|
+
await writeSessionFile('coder_pack.md', coderPackContent);
|
|
72
|
+
|
|
73
|
+
// Transition state
|
|
74
|
+
await transitionTo(STATES.PLAN_CREATED, 'plan_created');
|
|
75
|
+
|
|
76
|
+
spinner.succeed('Execution plan created!');
|
|
77
|
+
|
|
78
|
+
// Success output
|
|
79
|
+
const content = `📋 PLAN CREATED
|
|
80
|
+
|
|
81
|
+
Project: ${projectName}
|
|
82
|
+
Session: ${sessionId}
|
|
83
|
+
Spec Hash: ${specHash}
|
|
84
|
+
|
|
85
|
+
Files generated:
|
|
86
|
+
• plan.md - Execution steps
|
|
87
|
+
• coder_pack.md - Instructions for AI builder`;
|
|
88
|
+
|
|
89
|
+
console.log();
|
|
90
|
+
printBox(content, { borderColor: 'cyan' });
|
|
91
|
+
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(chalk.cyan('📁 Files:'));
|
|
94
|
+
console.log(chalk.gray(` ${sessionPath}/`));
|
|
95
|
+
console.log(chalk.gray(' ├── plan.md'));
|
|
96
|
+
console.log(chalk.gray(' └── coder_pack.md'));
|
|
97
|
+
|
|
98
|
+
printNextStep('Transfer coder_pack.md to Claude Code and run `vibecode build --start`');
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
spinner.fail('Failed to create plan');
|
|
102
|
+
printError(error.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|