@nclamvn/vibecode-cli 2.0.0 → 2.2.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 (53) hide show
  1. package/.vibecode/learning/fixes.json +1 -0
  2. package/.vibecode/learning/preferences.json +1 -0
  3. package/README.md +310 -49
  4. package/SESSION_NOTES.md +154 -0
  5. package/bin/vibecode.js +235 -2
  6. package/package.json +5 -2
  7. package/src/agent/decomposition.js +476 -0
  8. package/src/agent/index.js +391 -0
  9. package/src/agent/memory.js +542 -0
  10. package/src/agent/orchestrator.js +917 -0
  11. package/src/agent/self-healing.js +516 -0
  12. package/src/commands/agent.js +349 -0
  13. package/src/commands/ask.js +230 -0
  14. package/src/commands/assist.js +413 -0
  15. package/src/commands/build.js +345 -4
  16. package/src/commands/debug.js +565 -0
  17. package/src/commands/docs.js +167 -0
  18. package/src/commands/git.js +1024 -0
  19. package/src/commands/go.js +635 -0
  20. package/src/commands/learn.js +294 -0
  21. package/src/commands/migrate.js +341 -0
  22. package/src/commands/plan.js +8 -2
  23. package/src/commands/refactor.js +205 -0
  24. package/src/commands/review.js +126 -1
  25. package/src/commands/security.js +229 -0
  26. package/src/commands/shell.js +486 -0
  27. package/src/commands/templates.js +397 -0
  28. package/src/commands/test.js +194 -0
  29. package/src/commands/undo.js +281 -0
  30. package/src/commands/watch.js +556 -0
  31. package/src/commands/wizard.js +322 -0
  32. package/src/config/constants.js +5 -1
  33. package/src/config/templates.js +146 -15
  34. package/src/core/backup.js +325 -0
  35. package/src/core/error-analyzer.js +237 -0
  36. package/src/core/fix-generator.js +195 -0
  37. package/src/core/iteration.js +226 -0
  38. package/src/core/learning.js +295 -0
  39. package/src/core/session.js +18 -2
  40. package/src/core/test-runner.js +281 -0
  41. package/src/debug/analyzer.js +329 -0
  42. package/src/debug/evidence.js +228 -0
  43. package/src/debug/fixer.js +348 -0
  44. package/src/debug/image-analyzer.js +304 -0
  45. package/src/debug/index.js +378 -0
  46. package/src/debug/verifier.js +346 -0
  47. package/src/index.js +102 -0
  48. package/src/providers/claude-code.js +12 -7
  49. package/src/templates/index.js +724 -0
  50. package/src/ui/__tests__/error-translator.test.js +390 -0
  51. package/src/ui/dashboard.js +364 -0
  52. package/src/ui/error-translator.js +775 -0
  53. package/src/utils/image.js +222 -0
@@ -0,0 +1,294 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // VIBECODE CLI - Learn Command
3
+ // Phase H5: View and manage AI learnings
4
+ // ═══════════════════════════════════════════════════════════════════════════════
5
+
6
+ import chalk from 'chalk';
7
+ import inquirer from 'inquirer';
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import { LearningEngine } from '../core/learning.js';
11
+
12
+ /**
13
+ * Learn Command - View and manage AI learnings
14
+ *
15
+ * Usage:
16
+ * vibecode learn - Interactive menu
17
+ * vibecode learn --stats - Show learning statistics
18
+ * vibecode learn --clear - Clear all learnings
19
+ * vibecode learn --export - Export learnings to file
20
+ */
21
+ export async function learnCommand(options = {}) {
22
+ const learning = new LearningEngine();
23
+
24
+ if (options.stats) {
25
+ await showStats(learning);
26
+ return;
27
+ }
28
+
29
+ if (options.clear) {
30
+ await clearLearnings(learning, options.force);
31
+ return;
32
+ }
33
+
34
+ if (options.export) {
35
+ await exportLearnings(learning);
36
+ return;
37
+ }
38
+
39
+ // Default: show interactive menu
40
+ await interactiveLearn(learning);
41
+ }
42
+
43
+ /**
44
+ * Show learning statistics
45
+ */
46
+ async function showStats(learning) {
47
+ const stats = await learning.getStats();
48
+
49
+ console.log(chalk.cyan(`
50
+ ╭────────────────────────────────────────────────────────────────────╮
51
+ │ 📊 LEARNING STATISTICS │
52
+ ╰────────────────────────────────────────────────────────────────────╯
53
+ `));
54
+
55
+ console.log(chalk.white(` 📁 Project Learnings`));
56
+ console.log(chalk.gray(` Tổng fixes: ${stats.local.total}`));
57
+ console.log(chalk.gray(` Thành công: ${stats.local.success} (${stats.local.rate}%)`));
58
+ console.log('');
59
+
60
+ console.log(chalk.white(` 🌍 Global Learnings`));
61
+ console.log(chalk.gray(` Tổng fixes: ${stats.global.total}`));
62
+ console.log(chalk.gray(` Thành công: ${stats.global.success} (${stats.global.rate}%)`));
63
+ console.log('');
64
+
65
+ if (Object.keys(stats.byCategory).length > 0) {
66
+ console.log(chalk.white(` 📂 Theo Error Category`));
67
+ for (const [cat, data] of Object.entries(stats.byCategory)) {
68
+ const rate = data.total > 0 ? (data.success / data.total * 100).toFixed(0) : 0;
69
+ const bar = renderMiniBar(data.success, data.total);
70
+ console.log(chalk.gray(` ${cat.padEnd(12)} ${bar} ${data.success}/${data.total} (${rate}%)`));
71
+ }
72
+ console.log('');
73
+ }
74
+
75
+ console.log(chalk.white(` ⚙️ Preferences đã lưu: ${stats.preferences}`));
76
+
77
+ if (stats.lastLearning) {
78
+ const lastDate = new Date(stats.lastLearning).toLocaleString('vi-VN');
79
+ console.log(chalk.gray(` 📅 Learning gần nhất: ${lastDate}`));
80
+ }
81
+
82
+ console.log('');
83
+ }
84
+
85
+ /**
86
+ * Render a mini progress bar
87
+ */
88
+ function renderMiniBar(value, total) {
89
+ const width = 10;
90
+ const filled = total > 0 ? Math.round(width * value / total) : 0;
91
+ const empty = width - filled;
92
+ return chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
93
+ }
94
+
95
+ /**
96
+ * Clear all local learnings
97
+ */
98
+ async function clearLearnings(learning, force) {
99
+ const stats = await learning.getStats();
100
+
101
+ if (stats.local.total === 0) {
102
+ console.log(chalk.yellow('\n📭 Không có learnings nào để xoá.\n'));
103
+ return;
104
+ }
105
+
106
+ if (!force) {
107
+ console.log(chalk.yellow(`\n⚠️ Sắp xoá ${stats.local.total} learnings của project này.\n`));
108
+
109
+ const { confirm } = await inquirer.prompt([
110
+ {
111
+ type: 'confirm',
112
+ name: 'confirm',
113
+ message: 'Xác nhận xoá tất cả learnings?',
114
+ default: false
115
+ }
116
+ ]);
117
+
118
+ if (!confirm) {
119
+ console.log(chalk.gray('\n👋 Đã huỷ.\n'));
120
+ return;
121
+ }
122
+ }
123
+
124
+ await learning.clearLocal();
125
+ console.log(chalk.green(`\n✅ Đã xoá ${stats.local.total} learnings.\n`));
126
+ }
127
+
128
+ /**
129
+ * Export learnings to file
130
+ */
131
+ async function exportLearnings(learning) {
132
+ const stats = await learning.getStats();
133
+ const fixes = await learning.loadJson(
134
+ path.join(learning.localPath, 'fixes.json'),
135
+ []
136
+ );
137
+ const prefs = await learning.loadJson(
138
+ path.join(learning.localPath, 'preferences.json'),
139
+ {}
140
+ );
141
+
142
+ if (fixes.length === 0 && Object.keys(prefs).length === 0) {
143
+ console.log(chalk.yellow('\n📭 Không có learnings nào để export.\n'));
144
+ return;
145
+ }
146
+
147
+ const exportData = {
148
+ exportedAt: new Date().toISOString(),
149
+ projectPath: learning.projectPath,
150
+ stats,
151
+ fixes: fixes.map(f => ({
152
+ id: f.id,
153
+ errorType: f.errorType,
154
+ errorCategory: f.errorCategory,
155
+ success: f.success,
156
+ userFeedback: f.userFeedback,
157
+ projectType: f.projectType,
158
+ timestamp: f.timestamp
159
+ })),
160
+ preferences: prefs
161
+ };
162
+
163
+ const exportPath = `vibecode-learnings-${Date.now()}.json`;
164
+ await fs.writeFile(exportPath, JSON.stringify(exportData, null, 2));
165
+
166
+ console.log(chalk.green(`\n✅ Đã export ${fixes.length} learnings → ${exportPath}\n`));
167
+ }
168
+
169
+ /**
170
+ * Interactive learning menu
171
+ */
172
+ async function interactiveLearn(learning) {
173
+ const stats = await learning.getStats();
174
+
175
+ const successBar = renderMiniBar(stats.local.success, stats.local.total);
176
+
177
+ console.log(chalk.cyan(`
178
+ ╭────────────────────────────────────────────────────────────────────╮
179
+ │ 🧠 VIBECODE LEARNING │
180
+ │ │
181
+ │ AI học từ feedback của bạn để cải thiện suggestions. │
182
+ │ │
183
+ │ Success rate: ${successBar} ${String(stats.local.rate + '%').padEnd(30)}│
184
+ │ Total learnings: ${String(stats.local.total).padEnd(44)}│
185
+ │ │
186
+ ╰────────────────────────────────────────────────────────────────────╯
187
+ `));
188
+
189
+ const { action } = await inquirer.prompt([
190
+ {
191
+ type: 'list',
192
+ name: 'action',
193
+ message: 'Bạn muốn làm gì?',
194
+ choices: [
195
+ { name: '📊 Xem thống kê chi tiết', value: 'stats' },
196
+ { name: '📤 Export learnings', value: 'export' },
197
+ { name: '🗑️ Xoá learnings', value: 'clear' },
198
+ new inquirer.Separator(),
199
+ { name: '👋 Thoát', value: 'exit' }
200
+ ]
201
+ }
202
+ ]);
203
+
204
+ switch (action) {
205
+ case 'stats':
206
+ await showStats(learning);
207
+ break;
208
+ case 'export':
209
+ await exportLearnings(learning);
210
+ break;
211
+ case 'clear':
212
+ await clearLearnings(learning, false);
213
+ break;
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Ask for feedback after a fix
219
+ * Called from debug/fix commands
220
+ */
221
+ export async function askFeedback(fixInfo) {
222
+ console.log('');
223
+ const { feedback } = await inquirer.prompt([
224
+ {
225
+ type: 'list',
226
+ name: 'feedback',
227
+ message: 'Fix này có đúng không?',
228
+ choices: [
229
+ { name: '✅ Đúng, hoạt động tốt', value: 'success' },
230
+ { name: '❌ Không đúng', value: 'failed' },
231
+ { name: '🔄 Đúng một phần', value: 'partial' },
232
+ { name: '⏭️ Bỏ qua', value: 'skip' }
233
+ ]
234
+ }
235
+ ]);
236
+
237
+ if (feedback === 'skip') {
238
+ return null;
239
+ }
240
+
241
+ const learning = new LearningEngine();
242
+ let userCorrection = null;
243
+
244
+ if (feedback === 'failed' || feedback === 'partial') {
245
+ const { correction } = await inquirer.prompt([
246
+ {
247
+ type: 'input',
248
+ name: 'correction',
249
+ message: 'Mô tả ngắn vấn đề hoặc cách fix đúng (Enter để bỏ qua):',
250
+ }
251
+ ]);
252
+ userCorrection = correction || null;
253
+ }
254
+
255
+ await learning.recordFix({
256
+ errorType: fixInfo.errorType,
257
+ errorMessage: fixInfo.errorMessage,
258
+ errorCategory: fixInfo.errorCategory,
259
+ fixApplied: fixInfo.fixApplied,
260
+ success: feedback === 'success',
261
+ userFeedback: feedback,
262
+ userCorrection
263
+ });
264
+
265
+ if (feedback === 'success') {
266
+ console.log(chalk.green(' ✅ Đã ghi nhận. Cảm ơn!\n'));
267
+ } else {
268
+ console.log(chalk.yellow(' 📝 Đã ghi nhận feedback.\n'));
269
+ }
270
+
271
+ return feedback;
272
+ }
273
+
274
+ /**
275
+ * Show learning-based suggestion (if available)
276
+ */
277
+ export async function showLearningSuggestion(errorType, errorCategory) {
278
+ const learning = new LearningEngine();
279
+ const suggestion = await learning.getSuggestion(errorType, errorCategory);
280
+
281
+ if (suggestion && suggestion.confidence > 0.6) {
282
+ const confidencePercent = (suggestion.confidence * 100).toFixed(0);
283
+ console.log(chalk.cyan(` 💡 Dựa trên ${suggestion.basedOn} fixes trước (độ tin cậy: ${confidencePercent}%)`));
284
+
285
+ if (suggestion.suggestion) {
286
+ const shortSuggestion = suggestion.suggestion.substring(0, 100);
287
+ console.log(chalk.gray(` Gợi ý: ${shortSuggestion}${suggestion.suggestion.length > 100 ? '...' : ''}`));
288
+ }
289
+ console.log('');
290
+ return suggestion;
291
+ }
292
+
293
+ return null;
294
+ }
@@ -0,0 +1,341 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // VIBECODE CLI - Migrate Command
3
+ // Phase K8: AI-Powered Code Migration
4
+ // ═══════════════════════════════════════════════════════════════════════════════
5
+
6
+ import { spawn } from 'child_process';
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+ import chalk from 'chalk';
10
+ import inquirer from 'inquirer';
11
+ import { BackupManager } from '../core/backup.js';
12
+
13
+ export async function migrateCommand(description, options = {}) {
14
+ const cwd = process.cwd();
15
+
16
+ // Interactive mode
17
+ if (!description || description.length === 0) {
18
+ return interactiveMigrate(cwd);
19
+ }
20
+
21
+ const migrationDesc = Array.isArray(description) ? description.join(' ') : description;
22
+ return performMigration(cwd, migrationDesc, options);
23
+ }
24
+
25
+ async function interactiveMigrate(cwd) {
26
+ console.log(chalk.cyan(`
27
+ ╭────────────────────────────────────────────────────────────────────╮
28
+ │ 🔄 CODE MIGRATION │
29
+ │ │
30
+ │ AI-powered code migration and transformation │
31
+ │ │
32
+ ╰────────────────────────────────────────────────────────────────────╯
33
+ `));
34
+
35
+ const { migrationType } = await inquirer.prompt([{
36
+ type: 'list',
37
+ name: 'migrationType',
38
+ message: 'What migration do you need?',
39
+ choices: [
40
+ { name: '📘 JavaScript → TypeScript', value: 'js-to-ts' },
41
+ { name: '⚛️ Class Components → Hooks', value: 'class-to-hooks' },
42
+ { name: '🔄 CommonJS → ESM', value: 'cjs-to-esm' },
43
+ { name: '📦 REST → GraphQL', value: 'rest-to-graphql' },
44
+ { name: '🎨 CSS → Tailwind', value: 'css-to-tailwind' },
45
+ { name: '🗄️ Mongoose → Prisma', value: 'mongoose-to-prisma' },
46
+ { name: '⚡ Express → Fastify', value: 'express-to-fastify' },
47
+ { name: '📱 Pages Router → App Router', value: 'pages-to-app' },
48
+ { name: '🧪 Jest → Vitest', value: 'jest-to-vitest' },
49
+ { name: '✏️ Custom migration', value: 'custom' },
50
+ { name: '👋 Exit', value: 'exit' }
51
+ ]
52
+ }]);
53
+
54
+ if (migrationType === 'exit') return;
55
+
56
+ let migrationDesc = migrationType;
57
+
58
+ if (migrationType === 'custom') {
59
+ const { desc } = await inquirer.prompt([{
60
+ type: 'input',
61
+ name: 'desc',
62
+ message: 'Describe your migration:'
63
+ }]);
64
+ migrationDesc = desc;
65
+ }
66
+
67
+ const { targetPath } = await inquirer.prompt([{
68
+ type: 'input',
69
+ name: 'targetPath',
70
+ message: 'Path to migrate (leave empty for entire project):',
71
+ default: ''
72
+ }]);
73
+
74
+ return performMigration(cwd, migrationDesc, { path: targetPath });
75
+ }
76
+
77
+ async function performMigration(cwd, migrationDesc, options) {
78
+ // Create backup
79
+ console.log(chalk.gray('\n Creating backup before migration...\n'));
80
+ const backup = new BackupManager(cwd);
81
+ await backup.createBackup(`migrate-${Date.now()}`);
82
+
83
+ const migrations = {
84
+ 'js-to-ts': `
85
+ # JavaScript to TypeScript Migration
86
+
87
+ Convert JavaScript files to TypeScript:
88
+
89
+ 1. **Setup**
90
+ - Create/update tsconfig.json with appropriate settings
91
+ - Install TypeScript and @types packages
92
+
93
+ 2. **File Conversion**
94
+ - Rename .js files to .ts/.tsx (for React components)
95
+ - Add type annotations to variables, parameters, return values
96
+ - Define interfaces/types for objects and props
97
+ - Fix any TypeScript errors
98
+
99
+ 3. **Best Practices**
100
+ - Use strict mode
101
+ - Avoid 'any' where possible
102
+ - Use enums for constants
103
+ - Add proper generics
104
+
105
+ 4. **Cleanup**
106
+ - Update imports
107
+ - Remove JSDoc type annotations (now in code)
108
+ `,
109
+ 'class-to-hooks': `
110
+ # React Class to Hooks Migration
111
+
112
+ Convert React class components to functional components with hooks:
113
+
114
+ 1. **Component Conversion**
115
+ - Convert class to function component
116
+ - Replace this.state with useState
117
+ - Replace lifecycle methods:
118
+ - componentDidMount → useEffect(..., [])
119
+ - componentDidUpdate → useEffect
120
+ - componentWillUnmount → useEffect cleanup
121
+
122
+ 2. **Methods & Bindings**
123
+ - Convert class methods to functions
124
+ - Remove .bind(this) calls
125
+ - Use useCallback for memoized callbacks
126
+
127
+ 3. **Refs & Context**
128
+ - Replace createRef with useRef
129
+ - Replace this.context with useContext
130
+
131
+ 4. **State Management**
132
+ - Use useReducer for complex state
133
+ - Lift state or use context where appropriate
134
+ `,
135
+ 'cjs-to-esm': `
136
+ # CommonJS to ES Modules Migration
137
+
138
+ Convert CommonJS to ESM:
139
+
140
+ 1. **Syntax Changes**
141
+ - Replace require() with import
142
+ - Replace module.exports with export
143
+ - Replace exports.x with export const x
144
+
145
+ 2. **Package.json**
146
+ - Add "type": "module"
147
+ - Update main/exports fields
148
+
149
+ 3. **File Extensions**
150
+ - Ensure .js extensions in imports (or configure bundler)
151
+
152
+ 4. **Dynamic Imports**
153
+ - Replace require() in conditionals with import()
154
+ - Handle __dirname, __filename with import.meta.url
155
+ `,
156
+ 'rest-to-graphql': `
157
+ # REST to GraphQL Migration
158
+
159
+ Convert REST API to GraphQL:
160
+
161
+ 1. **Schema Design**
162
+ - Create GraphQL types from REST response shapes
163
+ - Design queries for GET endpoints
164
+ - Design mutations for POST/PUT/DELETE
165
+
166
+ 2. **Server Setup**
167
+ - Set up Apollo Server or similar
168
+ - Create resolvers for each query/mutation
169
+ - Connect to existing data sources
170
+
171
+ 3. **Client Migration**
172
+ - Replace fetch/axios calls with GraphQL queries
173
+ - Set up Apollo Client or urql
174
+ - Use generated types if TypeScript
175
+ `,
176
+ 'css-to-tailwind': `
177
+ # CSS to Tailwind Migration
178
+
179
+ Convert CSS/SCSS to Tailwind classes:
180
+
181
+ 1. **Setup**
182
+ - Install and configure Tailwind CSS
183
+ - Set up tailwind.config.js
184
+
185
+ 2. **Conversion**
186
+ - Replace CSS properties with Tailwind utilities
187
+ - Convert custom values to Tailwind config
188
+ - Handle responsive designs with breakpoint prefixes
189
+
190
+ 3. **Components**
191
+ - Use @apply for repeated patterns
192
+ - Create component classes where needed
193
+ - Remove unused CSS
194
+
195
+ 4. **Cleanup**
196
+ - Remove old CSS files
197
+ - Update build process
198
+ `,
199
+ 'mongoose-to-prisma': `
200
+ # Mongoose to Prisma Migration
201
+
202
+ Convert Mongoose ODM to Prisma ORM:
203
+
204
+ 1. **Schema Migration**
205
+ - Create Prisma schema from Mongoose models
206
+ - Convert types (ObjectId → String with @id)
207
+ - Define relations explicitly
208
+
209
+ 2. **Query Migration**
210
+ - Replace Model.find() with prisma.model.findMany()
211
+ - Replace Model.findById() with prisma.model.findUnique()
212
+ - Update create/update/delete operations
213
+
214
+ 3. **Setup**
215
+ - Configure Prisma client
216
+ - Set up migrations
217
+ - Handle connection pooling
218
+ `,
219
+ 'express-to-fastify': `
220
+ # Express to Fastify Migration
221
+
222
+ Convert Express.js to Fastify:
223
+
224
+ 1. **App Setup**
225
+ - Replace express() with fastify()
226
+ - Update middleware to plugins
227
+ - Configure async handlers (native in Fastify)
228
+
229
+ 2. **Routes**
230
+ - Update route syntax
231
+ - Replace req/res patterns
232
+ - Use schema validation
233
+
234
+ 3. **Middleware**
235
+ - Convert Express middleware to Fastify plugins
236
+ - Update error handling
237
+ - Replace body-parser (built into Fastify)
238
+ `,
239
+ 'pages-to-app': `
240
+ # Next.js Pages to App Router Migration
241
+
242
+ Convert Pages Router to App Router:
243
+
244
+ 1. **Directory Structure**
245
+ - Move pages/ to app/
246
+ - Create layout.tsx files
247
+ - Convert _app.tsx to root layout
248
+
249
+ 2. **Data Fetching**
250
+ - Replace getServerSideProps with server components
251
+ - Replace getStaticProps with fetch + cache
252
+ - Use generateStaticParams for dynamic routes
253
+
254
+ 3. **Components**
255
+ - Mark client components with 'use client'
256
+ - Keep server components as default
257
+ - Update metadata handling
258
+
259
+ 4. **API Routes**
260
+ - Move to app/api/[route]/route.ts
261
+ - Update to new Route Handlers format
262
+ `,
263
+ 'jest-to-vitest': `
264
+ # Jest to Vitest Migration
265
+
266
+ Convert Jest tests to Vitest:
267
+
268
+ 1. **Configuration**
269
+ - Create vitest.config.ts
270
+ - Remove jest.config.js
271
+ - Update package.json scripts
272
+
273
+ 2. **Test Files**
274
+ - Update imports from 'vitest'
275
+ - Replace jest.fn() with vi.fn()
276
+ - Replace jest.mock() with vi.mock()
277
+ - Replace jest.spyOn() with vi.spyOn()
278
+
279
+ 3. **Assertions**
280
+ - Most expect() syntax is compatible
281
+ - Update any Jest-specific matchers
282
+ `
283
+ };
284
+
285
+ const migrationGuide = migrations[migrationDesc] || `
286
+ # Custom Migration: ${migrationDesc}
287
+
288
+ Perform this migration following best practices:
289
+ 1. Analyze current code structure
290
+ 2. Plan the migration steps
291
+ 3. Apply changes incrementally
292
+ 4. Verify each step works
293
+ 5. Run tests after migration
294
+ `;
295
+
296
+ const targetInfo = options.path ? `\n## Target Path: ${options.path}` : '\n## Target: Entire project';
297
+
298
+ const prompt = `
299
+ ${migrationGuide}
300
+ ${targetInfo}
301
+
302
+ ## Safety Requirements:
303
+ 1. Preserve all existing functionality
304
+ 2. Don't lose any data or configuration
305
+ 3. Make incremental changes when possible
306
+ 4. Add comments for complex changes
307
+ 5. Run tests if available
308
+
309
+ ## Instructions:
310
+ 1. Analyze the codebase
311
+ 2. Create a migration plan
312
+ 3. Execute the migration step by step
313
+ 4. Verify the changes work
314
+
315
+ Perform the migration now.
316
+ `;
317
+
318
+ const promptFile = path.join(cwd, '.vibecode', 'migrate-prompt.md');
319
+ await fs.mkdir(path.dirname(promptFile), { recursive: true });
320
+ await fs.writeFile(promptFile, prompt);
321
+
322
+ console.log(chalk.yellow(` Performing migration: ${migrationDesc}\n`));
323
+
324
+ await runClaudeCode(prompt, cwd);
325
+
326
+ console.log(chalk.green('\n✅ Migration complete!'));
327
+ console.log(chalk.gray(' • Run tests to verify'));
328
+ console.log(chalk.gray(' • Use `vibecode undo` to revert if needed\n'));
329
+ }
330
+
331
+ async function runClaudeCode(prompt, cwd) {
332
+ return new Promise((resolve) => {
333
+ const child = spawn('claude', ['-p', prompt, '--dangerously-skip-permissions'], {
334
+ cwd,
335
+ stdio: 'inherit'
336
+ });
337
+
338
+ child.on('close', resolve);
339
+ child.on('error', () => resolve());
340
+ });
341
+ }
@@ -45,7 +45,7 @@ export async function planCommand(options = {}) {
45
45
  const sessionPath = await getCurrentSessionPath();
46
46
  const specHash = await getSpecHash();
47
47
 
48
- // Read contract and blueprint
48
+ // Read contract, blueprint, and intake
49
49
  spinner.text = 'Reading contract...';
50
50
  const contractContent = await readSessionFile('contract.md');
51
51
 
@@ -54,6 +54,11 @@ export async function planCommand(options = {}) {
54
54
  blueprintContent = await readSessionFile('blueprint.md');
55
55
  }
56
56
 
57
+ let intakeContent = '';
58
+ if (await sessionFileExists('intake.md')) {
59
+ intakeContent = await readSessionFile('intake.md');
60
+ }
61
+
57
62
  // Generate plan
58
63
  spinner.text = 'Generating plan...';
59
64
  const planContent = getPlanTemplate(projectName, sessionId, specHash, contractContent);
@@ -66,7 +71,8 @@ export async function planCommand(options = {}) {
66
71
  sessionId,
67
72
  specHash,
68
73
  contractContent,
69
- blueprintContent
74
+ blueprintContent,
75
+ intakeContent
70
76
  );
71
77
  await writeSessionFile('coder_pack.md', coderPackContent);
72
78