@nclamvn/vibecode-cli 2.0.0 → 2.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/.vibecode/learning/fixes.json +1 -0
- package/.vibecode/learning/preferences.json +1 -0
- package/README.md +310 -49
- package/SESSION_NOTES.md +154 -0
- package/bin/vibecode.js +212 -2
- package/package.json +5 -2
- package/src/agent/decomposition.js +476 -0
- package/src/agent/index.js +391 -0
- package/src/agent/memory.js +542 -0
- package/src/agent/orchestrator.js +917 -0
- package/src/agent/self-healing.js +516 -0
- package/src/commands/agent.js +349 -0
- package/src/commands/ask.js +230 -0
- package/src/commands/assist.js +413 -0
- package/src/commands/build.js +345 -4
- package/src/commands/debug.js +565 -0
- package/src/commands/docs.js +167 -0
- package/src/commands/git.js +1024 -0
- package/src/commands/go.js +387 -0
- package/src/commands/learn.js +294 -0
- package/src/commands/migrate.js +341 -0
- package/src/commands/plan.js +8 -2
- package/src/commands/refactor.js +205 -0
- package/src/commands/review.js +126 -1
- package/src/commands/security.js +229 -0
- package/src/commands/shell.js +486 -0
- package/src/commands/test.js +194 -0
- package/src/commands/undo.js +281 -0
- package/src/commands/watch.js +556 -0
- package/src/commands/wizard.js +322 -0
- package/src/config/constants.js +5 -1
- package/src/config/templates.js +146 -15
- package/src/core/backup.js +325 -0
- package/src/core/error-analyzer.js +237 -0
- package/src/core/fix-generator.js +195 -0
- package/src/core/iteration.js +226 -0
- package/src/core/learning.js +295 -0
- package/src/core/session.js +18 -2
- package/src/core/test-runner.js +281 -0
- package/src/debug/analyzer.js +329 -0
- package/src/debug/evidence.js +228 -0
- package/src/debug/fixer.js +348 -0
- package/src/debug/image-analyzer.js +304 -0
- package/src/debug/index.js +378 -0
- package/src/debug/verifier.js +346 -0
- package/src/index.js +89 -0
- package/src/providers/claude-code.js +12 -7
- package/src/ui/__tests__/error-translator.test.js +390 -0
- package/src/ui/dashboard.js +364 -0
- package/src/ui/error-translator.js +775 -0
- package/src/utils/image.js +222 -0
package/src/commands/build.js
CHANGED
|
@@ -20,14 +20,29 @@ import { getCurrentState, transitionTo } from '../core/state-machine.js';
|
|
|
20
20
|
import { getSpecHash } from '../core/contract.js';
|
|
21
21
|
import { STATES } from '../config/constants.js';
|
|
22
22
|
import { getBuildReportTemplate } from '../config/templates.js';
|
|
23
|
-
import { ensureDir, pathExists, appendToFile, readMarkdown } from '../utils/files.js';
|
|
23
|
+
import { ensureDir, pathExists, appendToFile, readMarkdown, writeJson } from '../utils/files.js';
|
|
24
24
|
import { printBox, printError, printSuccess, printWarning, printNextStep } from '../ui/output.js';
|
|
25
|
+
import { showError, inlineError } from '../ui/error-translator.js';
|
|
26
|
+
import { BackupManager } from '../core/backup.js';
|
|
25
27
|
import {
|
|
26
28
|
spawnClaudeCode,
|
|
27
29
|
isClaudeCodeAvailable,
|
|
28
30
|
buildPromptWithContext,
|
|
29
31
|
getProviderInfo
|
|
30
32
|
} from '../providers/index.js';
|
|
33
|
+
// Phase D: Iterative Build
|
|
34
|
+
import { runTests, formatTestResults } from '../core/test-runner.js';
|
|
35
|
+
import { analyzeErrors, formatErrors, createErrorSummary } from '../core/error-analyzer.js';
|
|
36
|
+
import { generateFixPrompt, areErrorsFixable, estimateFixComplexity } from '../core/fix-generator.js';
|
|
37
|
+
import {
|
|
38
|
+
createIterationState,
|
|
39
|
+
recordIteration,
|
|
40
|
+
canContinue,
|
|
41
|
+
finalizeIterationState,
|
|
42
|
+
saveIterationState,
|
|
43
|
+
formatIterationSummary,
|
|
44
|
+
logIteration
|
|
45
|
+
} from '../core/iteration.js';
|
|
31
46
|
|
|
32
47
|
const execAsync = promisify(exec);
|
|
33
48
|
|
|
@@ -46,7 +61,10 @@ export async function buildCommand(options = {}) {
|
|
|
46
61
|
const specHash = await getSpecHash();
|
|
47
62
|
|
|
48
63
|
// Handle different build modes
|
|
49
|
-
if (options.
|
|
64
|
+
if (options.iterate) {
|
|
65
|
+
// Phase D: Iterative Build
|
|
66
|
+
await handleIterativeBuild(currentState, projectName, sessionId, sessionPath, specHash, options);
|
|
67
|
+
} else if (options.auto) {
|
|
50
68
|
await handleAutoBuild(currentState, projectName, sessionId, sessionPath, specHash, options);
|
|
51
69
|
} else if (options.start) {
|
|
52
70
|
await handleBuildStart(currentState, projectName, sessionId, sessionPath, specHash);
|
|
@@ -59,7 +77,7 @@ export async function buildCommand(options = {}) {
|
|
|
59
77
|
}
|
|
60
78
|
|
|
61
79
|
} catch (error) {
|
|
62
|
-
|
|
80
|
+
showError(error, { verbose: options.verbose });
|
|
63
81
|
process.exit(1);
|
|
64
82
|
}
|
|
65
83
|
}
|
|
@@ -69,6 +87,10 @@ export async function buildCommand(options = {}) {
|
|
|
69
87
|
* "Contract LOCKED = License to build"
|
|
70
88
|
*/
|
|
71
89
|
async function handleAutoBuild(currentState, projectName, sessionId, sessionPath, specHash, options) {
|
|
90
|
+
// Create backup before build
|
|
91
|
+
const backup = new BackupManager();
|
|
92
|
+
await backup.createBackup('build-auto');
|
|
93
|
+
|
|
72
94
|
// Check state - must be PLAN_CREATED or BUILD_IN_PROGRESS or REVIEW_FAILED
|
|
73
95
|
const validStates = [STATES.PLAN_CREATED, STATES.BUILD_IN_PROGRESS, STATES.REVIEW_FAILED];
|
|
74
96
|
if (!validStates.includes(currentState)) {
|
|
@@ -211,9 +233,328 @@ ${evidence.screenshots > 0 ? ` ✅ ${evidence.screenshots} screenshots` : '
|
|
|
211
233
|
|
|
212
234
|
} catch (error) {
|
|
213
235
|
await appendToFile(logPath, `\nERROR: ${error.message}\n`);
|
|
214
|
-
|
|
236
|
+
showError(error);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Handle --iterate mode: Build-Test-Fix loop
|
|
243
|
+
* "Build until tests pass or max iterations reached"
|
|
244
|
+
*/
|
|
245
|
+
async function handleIterativeBuild(currentState, projectName, sessionId, sessionPath, specHash, options) {
|
|
246
|
+
const maxIterations = options.max || 3;
|
|
247
|
+
const strictMode = options.strict || false;
|
|
248
|
+
|
|
249
|
+
// Create backup before iterative build
|
|
250
|
+
const backup = new BackupManager();
|
|
251
|
+
await backup.createBackup('build-iterate');
|
|
252
|
+
|
|
253
|
+
// Check state - must be PLAN_CREATED or BUILD_IN_PROGRESS or REVIEW_FAILED
|
|
254
|
+
const validStates = [STATES.PLAN_CREATED, STATES.BUILD_IN_PROGRESS, STATES.REVIEW_FAILED];
|
|
255
|
+
if (!validStates.includes(currentState)) {
|
|
256
|
+
printError(`Cannot iterate in state: ${currentState}`);
|
|
257
|
+
console.log('Run `vibecode plan` first to create execution plan.');
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Check if Claude Code is available
|
|
262
|
+
const available = await isClaudeCodeAvailable();
|
|
263
|
+
if (!available) {
|
|
264
|
+
printError('Claude Code CLI not found.');
|
|
265
|
+
console.log(chalk.gray('Install with: npm install -g @anthropic-ai/claude-code'));
|
|
215
266
|
process.exit(1);
|
|
216
267
|
}
|
|
268
|
+
|
|
269
|
+
// Check coder_pack.md exists
|
|
270
|
+
if (!await sessionFileExists('coder_pack.md')) {
|
|
271
|
+
printError('coder_pack.md not found. Run `vibecode plan` first.');
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Setup directories
|
|
276
|
+
const evidencePath = path.join(sessionPath, 'evidence');
|
|
277
|
+
await ensureDir(evidencePath);
|
|
278
|
+
await ensureDir(path.join(evidencePath, 'screenshots'));
|
|
279
|
+
const iterationDir = path.join(sessionPath, 'iterations');
|
|
280
|
+
await ensureDir(iterationDir);
|
|
281
|
+
const logPath = path.join(evidencePath, 'build.log');
|
|
282
|
+
|
|
283
|
+
// Initialize iteration state
|
|
284
|
+
let iterationState = createIterationState(sessionId, maxIterations);
|
|
285
|
+
|
|
286
|
+
// Save initial state
|
|
287
|
+
const stateData = await loadState();
|
|
288
|
+
const startTime = new Date().toISOString();
|
|
289
|
+
stateData.build_started = startTime;
|
|
290
|
+
stateData.build_provider = 'claude-code';
|
|
291
|
+
stateData.build_mode = 'iterate';
|
|
292
|
+
stateData.max_iterations = maxIterations;
|
|
293
|
+
await saveState(stateData);
|
|
294
|
+
|
|
295
|
+
// Transition to BUILD_IN_PROGRESS if not already
|
|
296
|
+
if (currentState !== STATES.BUILD_IN_PROGRESS) {
|
|
297
|
+
await transitionTo(STATES.BUILD_IN_PROGRESS, 'iterative_build_started');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Load coder pack
|
|
301
|
+
const originalCoderPack = await readSessionFile('coder_pack.md');
|
|
302
|
+
|
|
303
|
+
// Log start
|
|
304
|
+
await appendToFile(logPath, `\n${'='.repeat(60)}\n`);
|
|
305
|
+
await appendToFile(logPath, `ITERATIVE BUILD STARTED: ${startTime}\n`);
|
|
306
|
+
await appendToFile(logPath, `Max Iterations: ${maxIterations}\n`);
|
|
307
|
+
await appendToFile(logPath, `Strict Mode: ${strictMode}\n`);
|
|
308
|
+
await appendToFile(logPath, `${'='.repeat(60)}\n\n`);
|
|
309
|
+
|
|
310
|
+
// Show starting message
|
|
311
|
+
const providerInfo = getProviderInfo();
|
|
312
|
+
|
|
313
|
+
const content = `🔄 ITERATIVE BUILD
|
|
314
|
+
|
|
315
|
+
Project: ${projectName}
|
|
316
|
+
Session: ${sessionId}
|
|
317
|
+
Spec Hash: ${specHash}
|
|
318
|
+
|
|
319
|
+
Provider: ${providerInfo.name}
|
|
320
|
+
Max Iterations: ${maxIterations}
|
|
321
|
+
Strict Mode: ${strictMode ? 'Yes' : 'No'}
|
|
322
|
+
|
|
323
|
+
Starting build-test-fix loop...`;
|
|
324
|
+
|
|
325
|
+
console.log();
|
|
326
|
+
printBox(content, { borderColor: 'magenta' });
|
|
327
|
+
console.log();
|
|
328
|
+
|
|
329
|
+
// Build-Test-Fix Loop
|
|
330
|
+
let currentPrompt = await buildPromptWithContext(originalCoderPack, process.cwd());
|
|
331
|
+
let loopResult = { success: false, reason: '' };
|
|
332
|
+
|
|
333
|
+
while (true) {
|
|
334
|
+
const iteration = iterationState.currentIteration + 1;
|
|
335
|
+
const iterationStart = Date.now();
|
|
336
|
+
|
|
337
|
+
console.log(chalk.cyan(`\n${'─'.repeat(60)}`));
|
|
338
|
+
console.log(chalk.cyan(`│ ITERATION ${iteration}/${maxIterations}`));
|
|
339
|
+
console.log(chalk.cyan(`${'─'.repeat(60)}\n`));
|
|
340
|
+
|
|
341
|
+
await logIteration(logPath, iteration, 'Starting iteration');
|
|
342
|
+
|
|
343
|
+
// Step 1: Run Claude Code
|
|
344
|
+
console.log(chalk.yellow('▶ Running Claude Code...'));
|
|
345
|
+
console.log();
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
const buildResult = await spawnClaudeCode(currentPrompt, {
|
|
349
|
+
cwd: process.cwd(),
|
|
350
|
+
logPath: logPath
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
console.log();
|
|
354
|
+
await logIteration(logPath, iteration, `Claude Code exited with code: ${buildResult.code}`);
|
|
355
|
+
|
|
356
|
+
// Capture evidence for this iteration
|
|
357
|
+
await captureGitDiff(evidencePath);
|
|
358
|
+
const iterEvidencePath = path.join(iterationDir, `iteration-${iteration}-diff.txt`);
|
|
359
|
+
try {
|
|
360
|
+
const { stdout } = await execAsync('git diff HEAD', { maxBuffer: 10 * 1024 * 1024 });
|
|
361
|
+
if (stdout.trim()) {
|
|
362
|
+
const fs = await import('fs-extra');
|
|
363
|
+
await fs.default.writeFile(iterEvidencePath, stdout, 'utf-8');
|
|
364
|
+
}
|
|
365
|
+
} catch (e) { /* ignore */ }
|
|
366
|
+
|
|
367
|
+
// Step 2: Run Tests
|
|
368
|
+
console.log(chalk.yellow('▶ Running tests...'));
|
|
369
|
+
const spinner = ora('Testing...').start();
|
|
370
|
+
|
|
371
|
+
const testResult = await runTests(process.cwd());
|
|
372
|
+
const iterationDuration = Date.now() - iterationStart;
|
|
373
|
+
|
|
374
|
+
if (testResult.passed) {
|
|
375
|
+
spinner.succeed('All tests passed!');
|
|
376
|
+
|
|
377
|
+
// Record successful iteration
|
|
378
|
+
iterationState = recordIteration(iterationState, {
|
|
379
|
+
passed: true,
|
|
380
|
+
errorCount: 0,
|
|
381
|
+
errorTypes: [],
|
|
382
|
+
affectedFiles: [],
|
|
383
|
+
duration: iterationDuration,
|
|
384
|
+
action: 'build'
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Finalize as success
|
|
388
|
+
iterationState = finalizeIterationState(iterationState, 'success');
|
|
389
|
+
await saveIterationState(sessionPath, iterationState);
|
|
390
|
+
|
|
391
|
+
loopResult = { success: true, reason: 'All tests passed' };
|
|
392
|
+
break;
|
|
393
|
+
|
|
394
|
+
} else {
|
|
395
|
+
spinner.fail(`Tests failed: ${testResult.summary.failed}/${testResult.summary.total}`);
|
|
396
|
+
|
|
397
|
+
// Step 3: Analyze Errors
|
|
398
|
+
const analyzedErrors = analyzeErrors(testResult);
|
|
399
|
+
const summary = createErrorSummary(analyzedErrors);
|
|
400
|
+
|
|
401
|
+
console.log();
|
|
402
|
+
console.log(formatErrors(analyzedErrors));
|
|
403
|
+
|
|
404
|
+
await logIteration(logPath, iteration, `Found ${analyzedErrors.length} errors`);
|
|
405
|
+
|
|
406
|
+
// Save error analysis for this iteration
|
|
407
|
+
await writeJson(path.join(iterationDir, `iteration-${iteration}-errors.json`), {
|
|
408
|
+
iteration,
|
|
409
|
+
timestamp: new Date().toISOString(),
|
|
410
|
+
summary,
|
|
411
|
+
errors: analyzedErrors
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Record failed iteration
|
|
415
|
+
iterationState = recordIteration(iterationState, {
|
|
416
|
+
passed: false,
|
|
417
|
+
errorCount: analyzedErrors.length,
|
|
418
|
+
errorTypes: [...new Set(analyzedErrors.map(e => e.type))],
|
|
419
|
+
affectedFiles: [...new Set(analyzedErrors.filter(e => e.file).map(e => e.file))],
|
|
420
|
+
duration: iterationDuration,
|
|
421
|
+
action: 'build'
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Check if errors are fixable
|
|
425
|
+
const fixableCheck = areErrorsFixable(analyzedErrors);
|
|
426
|
+
if (!fixableCheck.fixable) {
|
|
427
|
+
console.log(chalk.red(`\n⚠️ ${fixableCheck.reason}`));
|
|
428
|
+
await logIteration(logPath, iteration, `Errors not fixable: ${fixableCheck.reason}`);
|
|
429
|
+
|
|
430
|
+
iterationState = finalizeIterationState(iterationState, 'unfixable');
|
|
431
|
+
await saveIterationState(sessionPath, iterationState);
|
|
432
|
+
|
|
433
|
+
loopResult = { success: false, reason: fixableCheck.reason };
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Check if we can continue
|
|
438
|
+
const continueCheck = canContinue(iterationState);
|
|
439
|
+
if (!continueCheck.canContinue) {
|
|
440
|
+
console.log(chalk.yellow(`\n⚠️ ${continueCheck.reason}`));
|
|
441
|
+
await logIteration(logPath, iteration, continueCheck.reason);
|
|
442
|
+
|
|
443
|
+
iterationState = finalizeIterationState(iterationState, 'max_reached');
|
|
444
|
+
await saveIterationState(sessionPath, iterationState);
|
|
445
|
+
|
|
446
|
+
loopResult = { success: false, reason: continueCheck.reason };
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Step 4: Generate Fix Prompt
|
|
451
|
+
const complexity = estimateFixComplexity(analyzedErrors);
|
|
452
|
+
console.log(chalk.gray(`\nFix complexity: ${complexity}`));
|
|
453
|
+
console.log(chalk.yellow(`\n▶ Generating fix prompt for iteration ${iteration + 1}...`));
|
|
454
|
+
|
|
455
|
+
currentPrompt = generateFixPrompt(analyzedErrors, originalCoderPack, iteration + 1);
|
|
456
|
+
|
|
457
|
+
// Save fix prompt for evidence
|
|
458
|
+
await writeSessionFile(`iterations/fix-prompt-${iteration + 1}.md`, currentPrompt);
|
|
459
|
+
|
|
460
|
+
await logIteration(logPath, iteration, 'Generated fix prompt for next iteration');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
} catch (error) {
|
|
464
|
+
console.log('\n' + inlineError(error));
|
|
465
|
+
await logIteration(logPath, iteration, `Error: ${error.message}`);
|
|
466
|
+
|
|
467
|
+
iterationState = finalizeIterationState(iterationState, 'error');
|
|
468
|
+
await saveIterationState(sessionPath, iterationState);
|
|
469
|
+
|
|
470
|
+
loopResult = { success: false, reason: error.message };
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Final Summary
|
|
476
|
+
const endTime = new Date().toISOString();
|
|
477
|
+
await appendToFile(logPath, `\n${'='.repeat(60)}\n`);
|
|
478
|
+
await appendToFile(logPath, `ITERATIVE BUILD COMPLETED: ${endTime}\n`);
|
|
479
|
+
await appendToFile(logPath, `Result: ${loopResult.success ? 'SUCCESS' : 'FAILED'}\n`);
|
|
480
|
+
await appendToFile(logPath, `Iterations: ${iterationState.currentIteration}\n`);
|
|
481
|
+
await appendToFile(logPath, `${'='.repeat(60)}\n`);
|
|
482
|
+
|
|
483
|
+
// Save final iteration state
|
|
484
|
+
await saveIterationState(sessionPath, iterationState);
|
|
485
|
+
|
|
486
|
+
// Check evidence
|
|
487
|
+
const evidence = await checkEvidence(evidencePath);
|
|
488
|
+
|
|
489
|
+
// Generate build report
|
|
490
|
+
const reportContent = getBuildReportTemplate(
|
|
491
|
+
projectName,
|
|
492
|
+
sessionId,
|
|
493
|
+
specHash,
|
|
494
|
+
startTime,
|
|
495
|
+
endTime,
|
|
496
|
+
evidence
|
|
497
|
+
);
|
|
498
|
+
await writeSessionFile('build_report.md', reportContent);
|
|
499
|
+
|
|
500
|
+
// Update state - RELOAD to get current state (after BUILD_IN_PROGRESS transition)
|
|
501
|
+
const finalStateData = await loadState();
|
|
502
|
+
finalStateData.build_completed = endTime;
|
|
503
|
+
finalStateData.iterations = iterationState.currentIteration;
|
|
504
|
+
finalStateData.iteration_result = loopResult.success ? 'success' : 'failed';
|
|
505
|
+
await saveState(finalStateData);
|
|
506
|
+
|
|
507
|
+
console.log();
|
|
508
|
+
console.log(chalk.cyan('─'.repeat(60)));
|
|
509
|
+
console.log();
|
|
510
|
+
|
|
511
|
+
if (loopResult.success) {
|
|
512
|
+
await transitionTo(STATES.BUILD_DONE, 'iterative_build_success');
|
|
513
|
+
|
|
514
|
+
const duration = Math.round((new Date(endTime) - new Date(startTime)) / 1000 / 60);
|
|
515
|
+
|
|
516
|
+
const successContent = `✅ ITERATIVE BUILD SUCCESS
|
|
517
|
+
|
|
518
|
+
Project: ${projectName}
|
|
519
|
+
Iterations: ${iterationState.currentIteration}/${maxIterations}
|
|
520
|
+
Duration: ${duration} minutes
|
|
521
|
+
Result: All tests passed!
|
|
522
|
+
|
|
523
|
+
Evidence:
|
|
524
|
+
${evidence.hasDiff ? ' ✅ changes.diff' : ' ⬜ changes.diff'}
|
|
525
|
+
${evidence.hasLog ? ' ✅ build.log' : ' ⬜ build.log'}
|
|
526
|
+
✅ ${iterationState.currentIteration} iteration records`;
|
|
527
|
+
|
|
528
|
+
printBox(successContent, { borderColor: 'green' });
|
|
529
|
+
printNextStep('Run `vibecode review` to validate your build');
|
|
530
|
+
|
|
531
|
+
} else {
|
|
532
|
+
// Still transition to BUILD_DONE but with failure note
|
|
533
|
+
await transitionTo(STATES.BUILD_DONE, 'iterative_build_completed_with_errors');
|
|
534
|
+
|
|
535
|
+
const failContent = `⚠️ ITERATIVE BUILD INCOMPLETE
|
|
536
|
+
|
|
537
|
+
Project: ${projectName}
|
|
538
|
+
Iterations: ${iterationState.currentIteration}/${maxIterations}
|
|
539
|
+
Result: ${loopResult.reason}
|
|
540
|
+
|
|
541
|
+
Evidence saved in:
|
|
542
|
+
${iterationDir}/
|
|
543
|
+
|
|
544
|
+
Check iteration logs for details.`;
|
|
545
|
+
|
|
546
|
+
printBox(failContent, { borderColor: 'yellow' });
|
|
547
|
+
|
|
548
|
+
if (strictMode) {
|
|
549
|
+
printError('Strict mode: Build failed with errors');
|
|
550
|
+
process.exit(1);
|
|
551
|
+
} else {
|
|
552
|
+
console.log(chalk.gray('\nYou can:'));
|
|
553
|
+
console.log(chalk.gray(' • Run `vibecode build --iterate` to try again'));
|
|
554
|
+
console.log(chalk.gray(' • Run `vibecode review` to review current state'));
|
|
555
|
+
console.log(chalk.gray(' • Fix errors manually and run `vibecode build --complete`'));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
217
558
|
}
|
|
218
559
|
|
|
219
560
|
async function handleBuildStart(currentState, projectName, sessionId, sessionPath, specHash) {
|