@nclamvn/vibecode-cli 1.8.1 → 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/SESSION_NOTES.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # VIBECODE CLI - SESSION NOTES
2
- > Cập nhật: 2025-12-22
2
+ > Cập nhật: 2025-12-22 (Latest)
3
3
 
4
4
  ---
5
5
 
@@ -20,8 +20,9 @@
20
20
  - CLI: https://github.com/nclamvn/vibecode-cli
21
21
  - Docs: https://github.com/nclamvn/vibecode-docs
22
22
 
23
- 4. **NPM Package** - Deprecated (beta warning)
23
+ 4. **NPM Package**
24
24
  - Package: @nclamvn/vibecode-cli
25
+ - Version: **1.8.1** (latest)
25
26
  - Status: Deprecated với message cảnh báo beta
26
27
 
27
28
  5. **UI Fixes**
@@ -30,6 +31,12 @@
30
31
  - Theme toggle icon thu nhỏ 60%
31
32
  - Default: Light mode
32
33
 
34
+ 6. **Bug Fix: Version Hardcoded** ✅ FIXED
35
+ - File: `src/config/constants.js`
36
+ - Before: `export const VERSION = '1.0.1'` (hardcoded)
37
+ - After: `export const VERSION = pkg.version` (dynamic)
38
+ - Published: v1.8.1
39
+
33
40
  ---
34
41
 
35
42
  ## 🚧 ĐANG LÀM
@@ -37,7 +44,10 @@
37
44
  ### Deploy Render
38
45
  - Repo: nclamvn/vibecode-docs
39
46
  - File: render.yaml đã có
40
- - **BƯỚC TIẾP THEO**: Điền `build` vào Publish Directory rồi click Deploy
47
+ - URL Dashboard: https://dashboard.render.com/static/new
48
+ - **BƯỚC TIẾP THEO**:
49
+ 1. Điền `build` vào Publish Directory
50
+ 2. Click "Deploy Static Site"
41
51
 
42
52
  ---
43
53
 
@@ -46,8 +56,9 @@
46
56
  ```
47
57
  /Users/mac/vibecode-cli/
48
58
  ├── src/ # CLI source (26 commands)
59
+ │ └── config/constants.js # VERSION đọc từ package.json
49
60
  ├── bin/vibecode.js # Entry point
50
- ├── package.json # v1.8.0
61
+ ├── package.json # v1.8.1
51
62
  ├── docs-site/ # Docusaurus site (separate git repo)
52
63
  │ ├── src/pages/index.tsx # Landing page
53
64
  │ ├── docs/ # English docs
@@ -61,13 +72,16 @@
61
72
  ## 🔧 COMMANDS THƯỜNG DÙNG
62
73
 
63
74
  ```bash
64
- # Dev server
75
+ # Dev server docs
65
76
  cd /Users/mac/vibecode-cli/docs-site
66
77
  npm start
67
78
 
68
- # Build
79
+ # Build docs
69
80
  npm run build
70
81
 
82
+ # Test CLI version
83
+ node bin/vibecode.js --version
84
+
71
85
  # Push docs
72
86
  cd /Users/mac/vibecode-cli/docs-site
73
87
  git add . && git commit -m "message" && git push
@@ -76,6 +90,10 @@ git add . && git commit -m "message" && git push
76
90
  cd /Users/mac/vibecode-cli
77
91
  git add . && git commit -m "message" && git push
78
92
 
93
+ # Publish npm (khi cần)
94
+ npm version patch
95
+ npm publish
96
+
79
97
  # Bỏ deprecate npm khi sẵn sàng
80
98
  npm deprecate @nclamvn/vibecode-cli ""
81
99
  ```
@@ -86,6 +104,7 @@ npm deprecate @nclamvn/vibecode-cli ""
86
104
 
87
105
  | Metric | Value |
88
106
  |--------|-------|
107
+ | CLI Version | 1.8.1 |
89
108
  | CLI Commands | 26 |
90
109
  | Lines of Code | 18,612 |
91
110
  | JS Files | 167 |
@@ -95,7 +114,7 @@ npm deprecate @nclamvn/vibecode-cli ""
95
114
 
96
115
  ## 🎯 VIỆC CẦN LÀM TIẾP
97
116
 
98
- 1. [ ] Hoàn thành deploy Render
117
+ 1. [ ] Hoàn thành deploy Render (điền `build` → Deploy)
99
118
  2. [ ] Test site trên production URL
100
119
  3. [ ] Phase L: Unit Tests & TypeScript (optional)
101
120
  4. [ ] Khi sẵn sàng: Bỏ deprecate npm package
@@ -104,11 +123,23 @@ npm deprecate @nclamvn/vibecode-cli ""
104
123
 
105
124
  ## 🔗 LINKS
106
125
 
107
- - Landing EN: http://localhost:3000/
108
- - Landing VI: http://localhost:3000/vi/
109
- - GitHub CLI: https://github.com/nclamvn/vibecode-cli
110
- - GitHub Docs: https://github.com/nclamvn/vibecode-docs
111
- - NPM: https://www.npmjs.com/package/@nclamvn/vibecode-cli
126
+ | Resource | URL |
127
+ |----------|-----|
128
+ | Landing Local EN | http://localhost:3000/ |
129
+ | Landing Local VI | http://localhost:3000/vi/ |
130
+ | GitHub CLI | https://github.com/nclamvn/vibecode-cli |
131
+ | GitHub Docs | https://github.com/nclamvn/vibecode-docs |
132
+ | NPM Package | https://www.npmjs.com/package/@nclamvn/vibecode-cli |
133
+ | Render Dashboard | https://dashboard.render.com |
134
+
135
+ ---
136
+
137
+ ## 📝 LỊCH SỬ SESSION
138
+
139
+ | Thời gian | Việc đã làm |
140
+ |-----------|-------------|
141
+ | Session 1 | Landing page, i18n, UI fixes |
142
+ | Session 2 | GitHub push, npm deprecate, version bug fix |
112
143
 
113
144
  ---
114
145
 
@@ -116,4 +147,8 @@ npm deprecate @nclamvn/vibecode-cli ""
116
147
 
117
148
  Chỉ cần nói: **"tiếp tục"** hoặc **"continue"**
118
149
 
150
+ Hoặc cụ thể hơn:
151
+ - "tiếp tục deploy render"
152
+ - "đọc SESSION_NOTES.md và cho tôi biết trạng thái"
153
+
119
154
  Claude sẽ đọc file này và biết cần làm gì tiếp.
package/bin/vibecode.js CHANGED
@@ -146,12 +146,14 @@ program
146
146
  // ─────────────────────────────────────────────────────────────────────────────
147
147
 
148
148
  program
149
- .command('agent <description>')
149
+ .command('agent [description...]')
150
150
  .description('Agent mode: autonomous multi-module builder with self-healing')
151
151
  .option('-n, --new', 'Create new project directory')
152
+ .option('-r, --resume', 'Resume from last stopped module')
153
+ .option('--from <n>', 'Resume from specific module number', parseInt)
154
+ .option('-s, --status', 'Show current agent progress')
152
155
  .option('-v, --verbose', 'Show detailed progress')
153
156
  .option('--analyze', 'Analyze project structure without building')
154
- .option('--status', 'Show agent status and memory stats')
155
157
  .option('--report', 'Export memory report to markdown')
156
158
  .option('--clear', 'Clear agent memory')
157
159
  .option('--force', 'Force operation (for --clear)')
@@ -160,7 +162,11 @@ program
160
162
  .option('--skip-tests', 'Skip tests after each module')
161
163
  .option('--continue', 'Continue on module failure')
162
164
  .option('--stdout', 'Output report to stdout (for --report)')
163
- .action(agentCommand);
165
+ .action((description, options) => {
166
+ // Join variadic description
167
+ const desc = Array.isArray(description) ? description.join(' ') : description;
168
+ agentCommand(desc, options);
169
+ });
164
170
 
165
171
  // ─────────────────────────────────────────────────────────────────────────────
166
172
  // Phase G Commands - Debug Mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nclamvn/vibecode-cli",
3
- "version": "1.8.1",
3
+ "version": "2.1.0",
4
4
  "description": "Build software with discipline - AI coding with guardrails",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -11,7 +11,13 @@ import fs from 'fs-extra';
11
11
  import { DecompositionEngine, createDecompositionEngine } from './decomposition.js';
12
12
  import { MemoryEngine, createMemoryEngine } from './memory.js';
13
13
  import { SelfHealingEngine, createSelfHealingEngine } from './self-healing.js';
14
- import { Orchestrator, createOrchestrator, ORCHESTRATOR_STATES } from './orchestrator.js';
14
+ import {
15
+ Orchestrator,
16
+ createOrchestrator,
17
+ ORCHESTRATOR_STATES,
18
+ loadProgress,
19
+ loadDecomposition
20
+ } from './orchestrator.js';
15
21
 
16
22
  /**
17
23
  * Vibecode Agent Class
@@ -213,6 +219,64 @@ export class VibecodeAgent {
213
219
  console.log();
214
220
  }
215
221
 
222
+ /**
223
+ * Resume a previously interrupted build
224
+ */
225
+ async resume(options = {}) {
226
+ if (!this.initialized) {
227
+ await this.initialize();
228
+ }
229
+
230
+ // Load progress to show header
231
+ const progress = await loadProgress(this.projectPath);
232
+ if (!progress) {
233
+ console.log(chalk.yellow('\n📭 No previous session found.\n'));
234
+ console.log(chalk.gray(' Start new build: vibecode agent "description" --new\n'));
235
+ return null;
236
+ }
237
+
238
+ this.showResumeHeader(progress, options);
239
+
240
+ try {
241
+ this.buildResult = await this.orchestrator.resumeBuild(options);
242
+ this.showResults(this.buildResult);
243
+ return this.buildResult;
244
+ } catch (error) {
245
+ console.error(chalk.red(`\nAgent resume failed: ${error.message}`));
246
+ throw error;
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Show resume header
252
+ */
253
+ showResumeHeader(progress, options) {
254
+ const fromModule = options.fromModule !== undefined
255
+ ? options.fromModule + 1
256
+ : progress.currentModule + 1;
257
+ const totalModules = progress.totalModules;
258
+ const completed = progress.completedModules?.length || progress.currentModule || 0;
259
+
260
+ console.log();
261
+ console.log(chalk.cyan('╭' + '─'.repeat(68) + '╮'));
262
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
263
+ console.log(chalk.cyan('│') + chalk.bold.white(' 🔄 RESUMING AGENT') + ' '.repeat(48) + chalk.cyan('│'));
264
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
265
+
266
+ const projectLine = ` Project: ${progress.projectName}`;
267
+ console.log(chalk.cyan('│') + chalk.white(projectLine) + ' '.repeat(Math.max(0, 66 - projectLine.length)) + chalk.cyan('│'));
268
+
269
+ const progressLine = ` Progress: ${completed}/${totalModules} modules completed`;
270
+ console.log(chalk.cyan('│') + chalk.white(progressLine) + ' '.repeat(Math.max(0, 66 - progressLine.length)) + chalk.cyan('│'));
271
+
272
+ const resumeLine = ` Resuming from module ${fromModule}`;
273
+ console.log(chalk.cyan('│') + chalk.yellow(resumeLine) + ' '.repeat(Math.max(0, 66 - resumeLine.length)) + chalk.cyan('│'));
274
+
275
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
276
+ console.log(chalk.cyan('╰' + '─'.repeat(68) + '╯'));
277
+ console.log();
278
+ }
279
+
216
280
  /**
217
281
  * Quick build helper
218
282
  */
@@ -321,5 +385,7 @@ export {
321
385
  createSelfHealingEngine,
322
386
  Orchestrator,
323
387
  createOrchestrator,
324
- ORCHESTRATOR_STATES
388
+ ORCHESTRATOR_STATES,
389
+ loadProgress,
390
+ loadDecomposition
325
391
  };
@@ -15,6 +15,67 @@ import { ProgressDashboard } from '../ui/dashboard.js';
15
15
  import { translateError, showError, inlineError } from '../ui/error-translator.js';
16
16
  import { BackupManager } from '../core/backup.js';
17
17
 
18
+ /**
19
+ * Progress file for resume functionality
20
+ */
21
+ const PROGRESS_FILE = '.vibecode/agent-progress.json';
22
+ const DECOMPOSITION_FILE = '.vibecode/agent-decomposition.json';
23
+
24
+ /**
25
+ * Save agent progress to file
26
+ */
27
+ export async function saveProgress(projectPath, progress) {
28
+ const progressPath = path.join(projectPath, PROGRESS_FILE);
29
+ await fs.ensureDir(path.dirname(progressPath));
30
+ await fs.writeFile(progressPath, JSON.stringify(progress, null, 2));
31
+ }
32
+
33
+ /**
34
+ * Load agent progress from file
35
+ */
36
+ export async function loadProgress(projectPath) {
37
+ try {
38
+ const progressPath = path.join(projectPath, PROGRESS_FILE);
39
+ const content = await fs.readFile(progressPath, 'utf-8');
40
+ return JSON.parse(content);
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Clear agent progress file
48
+ */
49
+ export async function clearProgress(projectPath) {
50
+ try {
51
+ await fs.unlink(path.join(projectPath, PROGRESS_FILE));
52
+ } catch {
53
+ // Ignore if file doesn't exist
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Save decomposition for resume
59
+ */
60
+ export async function saveDecomposition(projectPath, decomposition) {
61
+ const decompositionPath = path.join(projectPath, DECOMPOSITION_FILE);
62
+ await fs.ensureDir(path.dirname(decompositionPath));
63
+ await fs.writeFile(decompositionPath, JSON.stringify(decomposition, null, 2));
64
+ }
65
+
66
+ /**
67
+ * Load decomposition from file
68
+ */
69
+ export async function loadDecomposition(projectPath) {
70
+ try {
71
+ const decompositionPath = path.join(projectPath, DECOMPOSITION_FILE);
72
+ const content = await fs.readFile(decompositionPath, 'utf-8');
73
+ return JSON.parse(content);
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+
18
79
  /**
19
80
  * Orchestrator states
20
81
  */
@@ -186,6 +247,13 @@ export class Orchestrator {
186
247
 
187
248
  const decomposition = await this.decompositionEngine.decompose(description, options);
188
249
 
250
+ // Save decomposition for resume functionality
251
+ await saveDecomposition(this.projectPath, {
252
+ ...decomposition,
253
+ description,
254
+ startedAt: new Date().toISOString()
255
+ });
256
+
189
257
  // Store in memory
190
258
  if (this.memoryEngine) {
191
259
  await this.memoryEngine.setProjectContext({
@@ -201,11 +269,13 @@ export class Orchestrator {
201
269
  // Step 2: Build modules in order
202
270
  this.setState(ORCHESTRATOR_STATES.BUILDING);
203
271
 
204
- const results = await this.buildModules(decomposition);
272
+ const results = await this.buildModules(decomposition, options);
205
273
 
206
274
  // Step 3: Final summary
207
275
  if (results.success) {
208
276
  this.setState(ORCHESTRATOR_STATES.COMPLETED);
277
+ // Clear progress on success
278
+ await clearProgress(this.projectPath);
209
279
  } else {
210
280
  this.setState(ORCHESTRATOR_STATES.FAILED);
211
281
  }
@@ -219,41 +289,149 @@ export class Orchestrator {
219
289
  }
220
290
  }
221
291
 
292
+ /**
293
+ * Resume build from previous progress
294
+ */
295
+ async resumeBuild(options = {}) {
296
+ this.buildState.startTime = Date.now();
297
+
298
+ // Load progress
299
+ const progress = await loadProgress(this.projectPath);
300
+ if (!progress) {
301
+ throw new Error('No previous progress found. Start a new build with: vibecode agent "description"');
302
+ }
303
+
304
+ // Load decomposition
305
+ const savedDecomposition = await loadDecomposition(this.projectPath);
306
+ if (!savedDecomposition) {
307
+ throw new Error('No decomposition found. Start a new build with: vibecode agent "description"');
308
+ }
309
+
310
+ try {
311
+ // Restore decomposition engine state
312
+ await this.decompositionEngine.decompose(savedDecomposition.description, options);
313
+
314
+ // Update module statuses from progress
315
+ for (const mod of progress.modules) {
316
+ if (mod.status === 'done') {
317
+ this.decompositionEngine.updateModuleStatus(mod.id, 'completed', {
318
+ files: mod.files || []
319
+ });
320
+ this.buildState.completedModules.push(mod.id);
321
+ }
322
+ }
323
+
324
+ // Store in memory
325
+ if (this.memoryEngine) {
326
+ await this.memoryEngine.setProjectContext({
327
+ description: progress.description,
328
+ type: savedDecomposition.projectType,
329
+ complexity: savedDecomposition.estimatedComplexity,
330
+ totalModules: savedDecomposition.totalModules
331
+ });
332
+ }
333
+
334
+ await this.log(`Resuming from module ${progress.currentModule + 1}`);
335
+
336
+ // Determine start index
337
+ const startIndex = options.fromModule !== undefined
338
+ ? options.fromModule
339
+ : progress.currentModule;
340
+
341
+ // Build remaining modules
342
+ this.setState(ORCHESTRATOR_STATES.BUILDING);
343
+ const results = await this.buildModules(savedDecomposition, {
344
+ ...options,
345
+ startIndex
346
+ });
347
+
348
+ // Final summary
349
+ if (results.success) {
350
+ this.setState(ORCHESTRATOR_STATES.COMPLETED);
351
+ await clearProgress(this.projectPath);
352
+ } else {
353
+ this.setState(ORCHESTRATOR_STATES.FAILED);
354
+ }
355
+
356
+ return this.generateBuildReport(savedDecomposition, results);
357
+
358
+ } catch (error) {
359
+ this.setState(ORCHESTRATOR_STATES.FAILED);
360
+ await this.log(`Resume failed: ${error.message}`, 'error');
361
+ throw error;
362
+ }
363
+ }
364
+
222
365
  /**
223
366
  * Build all modules in dependency order
224
367
  */
225
- async buildModules(decomposition) {
368
+ async buildModules(decomposition, options = {}) {
226
369
  const results = {
227
370
  success: true,
228
371
  modules: {},
229
372
  totalTime: 0
230
373
  };
231
374
 
375
+ // Determine start index for resume
376
+ const startIndex = options.startIndex || 0;
377
+ const buildOrder = decomposition.buildOrder;
378
+
232
379
  // Create and start dashboard if enabled
233
380
  if (this.config.useDashboard) {
234
381
  this.dashboard = new ProgressDashboard({
235
- title: 'VIBECODE AGENT',
382
+ title: startIndex > 0 ? 'VIBECODE AGENT (RESUME)' : 'VIBECODE AGENT',
236
383
  projectName: path.basename(this.projectPath),
237
384
  mode: `Agent (${decomposition.totalModules} modules)`
238
385
  });
239
386
 
240
- // Set modules for dashboard
241
- this.dashboard.setModules(decomposition.buildOrder.map(id => {
387
+ // Set modules for dashboard with correct status for resumed builds
388
+ this.dashboard.setModules(buildOrder.map((id, idx) => {
242
389
  const mod = this.decompositionEngine.getModule(id);
243
- return { name: mod?.name || id };
390
+ return {
391
+ name: mod?.name || id,
392
+ status: idx < startIndex ? 'completed' : 'pending'
393
+ };
244
394
  }));
245
395
 
246
396
  this.dashboard.start();
397
+
398
+ // Show resume message
399
+ if (startIndex > 0) {
400
+ this.dashboard.addLog(`Resuming from module ${startIndex + 1}: ${buildOrder[startIndex]}`);
401
+ }
247
402
  }
248
403
 
249
404
  try {
250
- for (const moduleId of decomposition.buildOrder) {
405
+ for (let i = startIndex; i < buildOrder.length; i++) {
406
+ const moduleId = buildOrder[i];
407
+
251
408
  // Check if we should stop
252
409
  if (this.state === ORCHESTRATOR_STATES.PAUSED) {
253
410
  await this.log('Build paused');
254
411
  break;
255
412
  }
256
413
 
414
+ // Save progress before building this module
415
+ await saveProgress(this.projectPath, {
416
+ projectName: path.basename(this.projectPath),
417
+ description: decomposition.description,
418
+ totalModules: decomposition.totalModules,
419
+ completedModules: this.buildState.completedModules,
420
+ currentModule: i,
421
+ modules: buildOrder.map((id, idx) => {
422
+ const mod = this.decompositionEngine.getModule(id);
423
+ return {
424
+ id,
425
+ name: mod?.name || id,
426
+ status: idx < i ? 'done' : idx === i ? 'building' : 'pending',
427
+ files: mod?.files || []
428
+ };
429
+ }),
430
+ startedAt: decomposition.startedAt || new Date().toISOString(),
431
+ lastUpdated: new Date().toISOString(),
432
+ error: null
433
+ });
434
+
257
435
  // Check if module can be built (dependencies satisfied)
258
436
  if (!this.decompositionEngine.canBuildModule(moduleId)) {
259
437
  const depStatus = decomposition.dependencyGraph[moduleId];
@@ -295,11 +473,37 @@ export class Orchestrator {
295
473
  }
296
474
  }
297
475
 
476
+ // Save progress after module completion
477
+ await saveProgress(this.projectPath, {
478
+ projectName: path.basename(this.projectPath),
479
+ description: decomposition.description,
480
+ totalModules: decomposition.totalModules,
481
+ completedModules: this.buildState.completedModules,
482
+ currentModule: moduleResult.success ? i + 1 : i,
483
+ failedModule: moduleResult.success ? null : i,
484
+ modules: buildOrder.map((id, idx) => {
485
+ const mod = this.decompositionEngine.getModule(id);
486
+ const status = idx < i ? 'done'
487
+ : idx === i ? (moduleResult.success ? 'done' : 'failed')
488
+ : 'pending';
489
+ return {
490
+ id,
491
+ name: mod?.name || id,
492
+ status,
493
+ files: mod?.files || []
494
+ };
495
+ }),
496
+ startedAt: decomposition.startedAt || new Date().toISOString(),
497
+ lastUpdated: new Date().toISOString(),
498
+ error: moduleResult.success ? null : moduleResult.error
499
+ });
500
+
298
501
  if (!moduleResult.success) {
299
502
  results.success = false;
300
503
 
301
504
  if (!this.config.continueOnFailure) {
302
505
  await this.log(`Stopping build due to module failure: ${moduleId}`, 'error');
506
+ console.log(chalk.yellow(`\n💡 Resume later with: vibecode agent --resume\n`));
303
507
  break;
304
508
  }
305
509
  }
@@ -7,7 +7,7 @@ import chalk from 'chalk';
7
7
  import path from 'path';
8
8
  import fs from 'fs-extra';
9
9
 
10
- import { createAgent } from '../agent/index.js';
10
+ import { createAgent, loadProgress } from '../agent/index.js';
11
11
  import { printError, printSuccess } from '../ui/output.js';
12
12
  import { isClaudeCodeAvailable } from '../providers/index.js';
13
13
 
@@ -16,6 +16,14 @@ import { isClaudeCodeAvailable } from '../providers/index.js';
16
16
  * vibecode agent "description" [options]
17
17
  */
18
18
  export async function agentCommand(description, options = {}) {
19
+ // Handle description as array (from commander variadic)
20
+ const desc = Array.isArray(description) ? description.join(' ') : description;
21
+
22
+ // Handle sub-commands that don't need Claude Code check first
23
+ if (options.status) {
24
+ return showAgentStatus(options);
25
+ }
26
+
19
27
  // Check for Claude Code
20
28
  const claudeAvailable = await isClaudeCodeAvailable();
21
29
  if (!claudeAvailable) {
@@ -24,8 +32,24 @@ export async function agentCommand(description, options = {}) {
24
32
  process.exit(1);
25
33
  }
26
34
 
27
- // Validate description
28
- if (!description || description.trim().length < 5) {
35
+ // Handle resume
36
+ if (options.resume) {
37
+ return resumeCommand(options);
38
+ }
39
+
40
+ // Validate description for non-resume commands
41
+ if (!desc || desc.trim().length < 5) {
42
+ // Check if there's a session to resume
43
+ const progress = await loadProgress(process.cwd());
44
+ if (progress) {
45
+ console.log(chalk.cyan('\n📦 Found existing session:'));
46
+ console.log(chalk.white(` Project: ${progress.projectName}`));
47
+ console.log(chalk.white(` Progress: ${progress.completedModules?.length || progress.currentModule}/${progress.totalModules} modules\n`));
48
+ console.log(chalk.gray(' Resume: vibecode agent --resume'));
49
+ console.log(chalk.gray(' Status: vibecode agent --status\n'));
50
+ return;
51
+ }
52
+
29
53
  printError('Description too short. Please provide more details.');
30
54
  console.log(chalk.gray('Example: vibecode agent "SaaS dashboard with auth, billing, and analytics"'));
31
55
  process.exit(1);
@@ -33,11 +57,7 @@ export async function agentCommand(description, options = {}) {
33
57
 
34
58
  // Handle sub-commands
35
59
  if (options.analyze) {
36
- return analyzeCommand(description, options);
37
- }
38
-
39
- if (options.status) {
40
- return statusCommand(options);
60
+ return analyzeCommand(desc, options);
41
61
  }
42
62
 
43
63
  if (options.report) {
@@ -49,7 +69,7 @@ export async function agentCommand(description, options = {}) {
49
69
  }
50
70
 
51
71
  // Main build flow
52
- return buildCommand(description, options);
72
+ return buildCommand(desc, options);
53
73
  }
54
74
 
55
75
  /**
@@ -134,59 +154,133 @@ async function analyzeCommand(description, options) {
134
154
  }
135
155
 
136
156
  /**
137
- * Show agent status
157
+ * Show agent status with resume info
138
158
  */
139
- async function statusCommand(options) {
159
+ async function showAgentStatus(options) {
160
+ const cwd = process.cwd();
161
+ const progress = await loadProgress(cwd);
162
+
163
+ if (!progress) {
164
+ console.log(chalk.yellow('\n📭 No active agent session.\n'));
165
+ console.log(chalk.gray(' Start new: vibecode agent "description" --new\n'));
166
+ return;
167
+ }
168
+
169
+ console.log();
170
+ console.log(chalk.cyan('╭' + '─'.repeat(68) + '╮'));
171
+ console.log(chalk.cyan('│') + chalk.bold.white(' 🤖 AGENT STATUS') + ' '.repeat(50) + chalk.cyan('│'));
172
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
173
+
174
+ const projectLine = ` Project: ${progress.projectName}`;
175
+ console.log(chalk.cyan('│') + chalk.white(projectLine) + ' '.repeat(Math.max(0, 66 - projectLine.length)) + chalk.cyan('│'));
176
+
177
+ const completed = progress.completedModules?.length || progress.currentModule || 0;
178
+ const progressLine = ` Progress: ${completed}/${progress.totalModules} modules`;
179
+ console.log(chalk.cyan('│') + chalk.white(progressLine) + ' '.repeat(Math.max(0, 66 - progressLine.length)) + chalk.cyan('│'));
180
+
181
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
182
+
183
+ // Show modules with status
184
+ for (const mod of progress.modules || []) {
185
+ let icon, color;
186
+ switch (mod.status) {
187
+ case 'done':
188
+ icon = chalk.green('✓');
189
+ color = chalk.green;
190
+ break;
191
+ case 'building':
192
+ icon = chalk.yellow('◐');
193
+ color = chalk.yellow;
194
+ break;
195
+ case 'failed':
196
+ icon = chalk.red('✗');
197
+ color = chalk.red;
198
+ break;
199
+ default:
200
+ icon = chalk.gray('○');
201
+ color = chalk.gray;
202
+ }
203
+ const modLine = ` ${icon} ${color(mod.name)}`;
204
+ // Approximate length without ANSI codes
205
+ const approxLen = 5 + mod.name.length;
206
+ console.log(chalk.cyan('│') + modLine + ' '.repeat(Math.max(0, 66 - approxLen)) + chalk.cyan('│'));
207
+ }
208
+
209
+ if (progress.error) {
210
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
211
+ const errorLine = ` Error: ${progress.error.substring(0, 55)}`;
212
+ console.log(chalk.cyan('│') + chalk.red(errorLine) + ' '.repeat(Math.max(0, 66 - errorLine.length)) + chalk.cyan('│'));
213
+ }
214
+
215
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
216
+
217
+ const timeLine = ` Last updated: ${new Date(progress.lastUpdated).toLocaleString()}`;
218
+ console.log(chalk.cyan('│') + chalk.gray(timeLine) + ' '.repeat(Math.max(0, 66 - timeLine.length)) + chalk.cyan('│'));
219
+
220
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
221
+ console.log(chalk.cyan('│') + chalk.yellow(' 💡 Resume: vibecode agent --resume') + ' '.repeat(29) + chalk.cyan('│'));
222
+ console.log(chalk.cyan('│') + ' '.repeat(68) + chalk.cyan('│'));
223
+ console.log(chalk.cyan('╰' + '─'.repeat(68) + '╯'));
224
+ console.log();
225
+
226
+ // Output JSON if requested
227
+ if (options.json) {
228
+ console.log(JSON.stringify(progress, null, 2));
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Resume agent from last stopped module
234
+ */
235
+ async function resumeCommand(options) {
236
+ const cwd = process.cwd();
237
+
238
+ // Check for progress
239
+ const progress = await loadProgress(cwd);
240
+ if (!progress) {
241
+ console.log(chalk.yellow('\n📭 No session to resume.\n'));
242
+ console.log(chalk.gray(' Start new: vibecode agent "description" --new\n'));
243
+ return;
244
+ }
245
+
246
+ // Create agent and resume
140
247
  const agent = createAgent({
141
- projectPath: process.cwd()
248
+ projectPath: cwd,
249
+ verbose: options.verbose || false
142
250
  });
143
251
 
144
252
  try {
145
- await agent.initialize();
146
- const status = agent.getStatus();
147
-
148
- console.log();
149
- console.log(chalk.cyan('Agent Status'));
150
- console.log(chalk.gray('─'.repeat(40)));
151
- console.log();
152
-
153
- console.log(` Initialized: ${status.initialized ? chalk.green('Yes') : chalk.red('No')}`);
154
- console.log(` Project: ${status.projectPath}`);
155
-
156
- if (status.memoryStats) {
157
- console.log();
158
- console.log(chalk.cyan('Memory Stats'));
159
- console.log(chalk.gray('─'.repeat(40)));
160
- console.log(` Modules: ${status.memoryStats.modulesCompleted}/${status.memoryStats.modulesTotal} completed`);
161
- console.log(` Decisions: ${status.memoryStats.decisionsCount}`);
162
- console.log(` Patterns: ${status.memoryStats.patternsCount}`);
163
- console.log(` Errors: ${status.memoryStats.errorsFixed}/${status.memoryStats.errorsTotal} fixed`);
164
- console.log(` Files: ${status.memoryStats.filesCreated}`);
165
- }
253
+ // Determine from module
254
+ const fromModule = options.from ? parseInt(options.from) - 1 : undefined;
166
255
 
167
- if (status.healingStats) {
168
- console.log();
169
- console.log(chalk.cyan('Self-Healing Stats'));
170
- console.log(chalk.gray('─'.repeat(40)));
171
- console.log(` Attempts: ${status.healingStats.total}`);
172
- console.log(` Success: ${status.healingStats.successful}`);
173
- console.log(` Failed: ${status.healingStats.failed}`);
174
- console.log(` Rate: ${status.healingStats.successRate}`);
175
- }
256
+ const resumeOptions = {
257
+ maxModuleRetries: options.maxRetries || 3,
258
+ testAfterEachModule: !options.skipTests,
259
+ continueOnFailure: options.continue || false,
260
+ fromModule
261
+ };
176
262
 
177
- console.log();
263
+ const result = await agent.resume(resumeOptions);
178
264
 
179
- // Output JSON if requested
180
- if (options.json) {
181
- console.log(JSON.stringify(status, null, 2));
265
+ // Exit with appropriate code
266
+ if (result && !result.success) {
267
+ process.exit(1);
182
268
  }
183
269
 
184
270
  } catch (error) {
185
- printError(`Status failed: ${error.message}`);
271
+ printError(`Resume failed: ${error.message}`);
272
+ console.log(chalk.gray('Check .vibecode/agent/orchestrator.log for details.'));
186
273
  process.exit(1);
187
274
  }
188
275
  }
189
276
 
277
+ /**
278
+ * Legacy status command (for compatibility)
279
+ */
280
+ async function statusCommand(options) {
281
+ return showAgentStatus(options);
282
+ }
283
+
190
284
  /**
191
285
  * Export memory report
192
286
  */