@nclamvn/vibecode-cli 1.2.0 → 1.5.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/README.md +310 -49
- package/bin/vibecode.js +65 -0
- package/package.json +1 -1
- package/src/agent/decomposition.js +476 -0
- package/src/agent/index.js +325 -0
- package/src/agent/memory.js +542 -0
- package/src/agent/orchestrator.js +644 -0
- package/src/agent/self-healing.js +516 -0
- package/src/commands/agent.js +255 -0
- package/src/commands/assist.js +413 -0
- package/src/commands/build.js +6 -5
- package/src/commands/debug.js +457 -0
- package/src/commands/go.js +380 -0
- package/src/commands/plan.js +8 -2
- package/src/config/templates.js +146 -15
- package/src/core/session.js +18 -2
- package/src/core/test-runner.js +38 -5
- package/src/debug/analyzer.js +329 -0
- package/src/debug/evidence.js +228 -0
- package/src/debug/fixer.js +348 -0
- package/src/debug/index.js +349 -0
- package/src/debug/verifier.js +346 -0
- package/src/index.js +31 -0
- package/src/providers/claude-code.js +12 -7
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE AGENT - Decomposition Engine
|
|
3
|
+
// Breaks projects into modules with dependency analysis
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Common module patterns for automatic detection
|
|
8
|
+
*/
|
|
9
|
+
const MODULE_PATTERNS = {
|
|
10
|
+
// Core Infrastructure
|
|
11
|
+
core: {
|
|
12
|
+
keywords: ['setup', 'config', 'init', 'base', 'foundation', 'core'],
|
|
13
|
+
priority: 0,
|
|
14
|
+
dependencies: []
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Authentication & Authorization
|
|
18
|
+
auth: {
|
|
19
|
+
keywords: ['auth', 'login', 'signup', 'register', 'password', 'oauth', 'jwt', 'session'],
|
|
20
|
+
priority: 1,
|
|
21
|
+
dependencies: ['core']
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Database & Data Layer
|
|
25
|
+
database: {
|
|
26
|
+
keywords: ['database', 'db', 'schema', 'model', 'entity', 'migration', 'orm'],
|
|
27
|
+
priority: 1,
|
|
28
|
+
dependencies: ['core']
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// API Layer
|
|
32
|
+
api: {
|
|
33
|
+
keywords: ['api', 'endpoint', 'route', 'rest', 'graphql', 'controller'],
|
|
34
|
+
priority: 2,
|
|
35
|
+
dependencies: ['core', 'database']
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// User Management
|
|
39
|
+
users: {
|
|
40
|
+
keywords: ['user', 'profile', 'account', 'member', 'admin'],
|
|
41
|
+
priority: 3,
|
|
42
|
+
dependencies: ['auth', 'database']
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// Dashboard & Admin
|
|
46
|
+
dashboard: {
|
|
47
|
+
keywords: ['dashboard', 'admin', 'panel', 'analytics', 'stats', 'metrics'],
|
|
48
|
+
priority: 4,
|
|
49
|
+
dependencies: ['auth', 'users']
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Billing & Payments
|
|
53
|
+
billing: {
|
|
54
|
+
keywords: ['billing', 'payment', 'stripe', 'subscription', 'pricing', 'checkout', 'invoice'],
|
|
55
|
+
priority: 4,
|
|
56
|
+
dependencies: ['auth', 'users']
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Notifications
|
|
60
|
+
notifications: {
|
|
61
|
+
keywords: ['notification', 'email', 'sms', 'push', 'alert', 'message'],
|
|
62
|
+
priority: 4,
|
|
63
|
+
dependencies: ['users']
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// UI Components
|
|
67
|
+
ui: {
|
|
68
|
+
keywords: ['component', 'button', 'form', 'modal', 'ui', 'layout', 'navigation', 'header', 'footer'],
|
|
69
|
+
priority: 2,
|
|
70
|
+
dependencies: ['core']
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Pages & Views
|
|
74
|
+
pages: {
|
|
75
|
+
keywords: ['page', 'view', 'screen', 'landing', 'home', 'about', 'contact'],
|
|
76
|
+
priority: 5,
|
|
77
|
+
dependencies: ['ui']
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// Testing
|
|
81
|
+
tests: {
|
|
82
|
+
keywords: ['test', 'spec', 'e2e', 'unit', 'integration'],
|
|
83
|
+
priority: 6,
|
|
84
|
+
dependencies: [] // Tests depend on what they test, handled dynamically
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Project type templates for smart decomposition
|
|
90
|
+
*/
|
|
91
|
+
const PROJECT_TEMPLATES = {
|
|
92
|
+
'landing': {
|
|
93
|
+
modules: ['core', 'ui', 'pages'],
|
|
94
|
+
description: 'Simple landing page'
|
|
95
|
+
},
|
|
96
|
+
'saas': {
|
|
97
|
+
modules: ['core', 'database', 'auth', 'users', 'dashboard', 'billing', 'ui', 'pages'],
|
|
98
|
+
description: 'Full SaaS application'
|
|
99
|
+
},
|
|
100
|
+
'api': {
|
|
101
|
+
modules: ['core', 'database', 'auth', 'api', 'tests'],
|
|
102
|
+
description: 'REST API backend'
|
|
103
|
+
},
|
|
104
|
+
'cli': {
|
|
105
|
+
modules: ['core', 'api', 'tests'],
|
|
106
|
+
description: 'Command-line tool'
|
|
107
|
+
},
|
|
108
|
+
'fullstack': {
|
|
109
|
+
modules: ['core', 'database', 'auth', 'api', 'users', 'ui', 'pages', 'tests'],
|
|
110
|
+
description: 'Full-stack web application'
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Decomposition Engine Class
|
|
116
|
+
* Analyzes project requirements and breaks them into buildable modules
|
|
117
|
+
*/
|
|
118
|
+
export class DecompositionEngine {
|
|
119
|
+
constructor() {
|
|
120
|
+
this.modules = [];
|
|
121
|
+
this.dependencyGraph = new Map();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Analyze description and decompose into modules
|
|
126
|
+
* @param {string} description - Project description
|
|
127
|
+
* @param {object} options - Decomposition options
|
|
128
|
+
* @returns {object} Decomposition result
|
|
129
|
+
*/
|
|
130
|
+
async decompose(description, options = {}) {
|
|
131
|
+
const lowerDesc = description.toLowerCase();
|
|
132
|
+
|
|
133
|
+
// Detect project type
|
|
134
|
+
const projectType = this.detectProjectType(lowerDesc);
|
|
135
|
+
|
|
136
|
+
// Get base modules from template
|
|
137
|
+
let detectedModules = projectType
|
|
138
|
+
? [...PROJECT_TEMPLATES[projectType].modules]
|
|
139
|
+
: ['core'];
|
|
140
|
+
|
|
141
|
+
// Detect additional modules from description
|
|
142
|
+
const additionalModules = this.detectModulesFromDescription(lowerDesc);
|
|
143
|
+
|
|
144
|
+
// Merge modules (avoid duplicates)
|
|
145
|
+
detectedModules = [...new Set([...detectedModules, ...additionalModules])];
|
|
146
|
+
|
|
147
|
+
// Build module objects with metadata
|
|
148
|
+
this.modules = this.buildModuleObjects(detectedModules, description);
|
|
149
|
+
|
|
150
|
+
// Build dependency graph
|
|
151
|
+
this.dependencyGraph = this.buildDependencyGraph(this.modules);
|
|
152
|
+
|
|
153
|
+
// Get build order using topological sort
|
|
154
|
+
const buildOrder = this.topologicalSort();
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
projectType: projectType || 'custom',
|
|
158
|
+
totalModules: this.modules.length,
|
|
159
|
+
modules: this.modules,
|
|
160
|
+
buildOrder,
|
|
161
|
+
dependencyGraph: this.serializeDependencyGraph(),
|
|
162
|
+
estimatedComplexity: this.estimateComplexity()
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Detect project type from description
|
|
168
|
+
*/
|
|
169
|
+
detectProjectType(description) {
|
|
170
|
+
const typeKeywords = {
|
|
171
|
+
landing: ['landing', 'landing page', 'one page', 'single page', 'portfolio'],
|
|
172
|
+
saas: ['saas', 'subscription', 'billing', 'multi-tenant', 'b2b', 'software as a service'],
|
|
173
|
+
api: ['api', 'rest api', 'graphql', 'backend', 'microservice'],
|
|
174
|
+
cli: ['cli', 'command line', 'terminal', 'shell'],
|
|
175
|
+
fullstack: ['fullstack', 'full stack', 'web app', 'web application']
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
for (const [type, keywords] of Object.entries(typeKeywords)) {
|
|
179
|
+
if (keywords.some(kw => description.includes(kw))) {
|
|
180
|
+
return type;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Default heuristics
|
|
185
|
+
if (description.includes('login') || description.includes('auth')) {
|
|
186
|
+
return 'fullstack';
|
|
187
|
+
}
|
|
188
|
+
if (description.includes('page') || description.includes('website')) {
|
|
189
|
+
return 'landing';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Detect modules from description keywords
|
|
197
|
+
*/
|
|
198
|
+
detectModulesFromDescription(description) {
|
|
199
|
+
const detected = [];
|
|
200
|
+
|
|
201
|
+
for (const [moduleName, config] of Object.entries(MODULE_PATTERNS)) {
|
|
202
|
+
const hasKeyword = config.keywords.some(kw => description.includes(kw));
|
|
203
|
+
if (hasKeyword) {
|
|
204
|
+
detected.push(moduleName);
|
|
205
|
+
// Also add dependencies
|
|
206
|
+
detected.push(...config.dependencies);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return [...new Set(detected)];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Build module objects with full metadata
|
|
215
|
+
*/
|
|
216
|
+
buildModuleObjects(moduleNames, description) {
|
|
217
|
+
return moduleNames.map(name => {
|
|
218
|
+
const pattern = MODULE_PATTERNS[name] || {
|
|
219
|
+
keywords: [name],
|
|
220
|
+
priority: 5,
|
|
221
|
+
dependencies: ['core']
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
id: name,
|
|
226
|
+
name: this.formatModuleName(name),
|
|
227
|
+
description: this.generateModuleDescription(name, description),
|
|
228
|
+
priority: pattern.priority,
|
|
229
|
+
dependencies: pattern.dependencies.filter(dep => moduleNames.includes(dep)),
|
|
230
|
+
status: 'pending',
|
|
231
|
+
estimatedSize: this.estimateModuleSize(name),
|
|
232
|
+
files: [],
|
|
233
|
+
buildAttempts: 0,
|
|
234
|
+
errors: []
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Format module name for display
|
|
241
|
+
*/
|
|
242
|
+
formatModuleName(name) {
|
|
243
|
+
return name.charAt(0).toUpperCase() + name.slice(1).replace(/-/g, ' ');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Generate module description based on context
|
|
248
|
+
*/
|
|
249
|
+
generateModuleDescription(moduleName, projectDescription) {
|
|
250
|
+
const descriptions = {
|
|
251
|
+
core: 'Project setup, configuration, and base infrastructure',
|
|
252
|
+
auth: 'Authentication system with login, signup, and session management',
|
|
253
|
+
database: 'Database schema, models, and data layer',
|
|
254
|
+
api: 'API endpoints and route handlers',
|
|
255
|
+
users: 'User management, profiles, and account settings',
|
|
256
|
+
dashboard: 'Admin dashboard and analytics views',
|
|
257
|
+
billing: 'Payment processing, subscriptions, and invoicing',
|
|
258
|
+
notifications: 'Email, push, and in-app notification system',
|
|
259
|
+
ui: 'Reusable UI components and design system',
|
|
260
|
+
pages: 'Application pages and views',
|
|
261
|
+
tests: 'Unit, integration, and end-to-end tests'
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
return descriptions[moduleName] || `${this.formatModuleName(moduleName)} module`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Estimate module size (small, medium, large)
|
|
269
|
+
*/
|
|
270
|
+
estimateModuleSize(moduleName) {
|
|
271
|
+
const largeMods = ['auth', 'billing', 'dashboard', 'api'];
|
|
272
|
+
const mediumMods = ['users', 'database', 'ui', 'pages'];
|
|
273
|
+
|
|
274
|
+
if (largeMods.includes(moduleName)) return 'large';
|
|
275
|
+
if (mediumMods.includes(moduleName)) return 'medium';
|
|
276
|
+
return 'small';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Build dependency graph as Map
|
|
281
|
+
*/
|
|
282
|
+
buildDependencyGraph(modules) {
|
|
283
|
+
const graph = new Map();
|
|
284
|
+
|
|
285
|
+
for (const mod of modules) {
|
|
286
|
+
graph.set(mod.id, {
|
|
287
|
+
module: mod,
|
|
288
|
+
dependsOn: mod.dependencies,
|
|
289
|
+
dependedBy: []
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Build reverse dependencies
|
|
294
|
+
for (const mod of modules) {
|
|
295
|
+
for (const dep of mod.dependencies) {
|
|
296
|
+
if (graph.has(dep)) {
|
|
297
|
+
graph.get(dep).dependedBy.push(mod.id);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return graph;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Topological sort for build order
|
|
307
|
+
* Uses Kahn's algorithm
|
|
308
|
+
*/
|
|
309
|
+
topologicalSort() {
|
|
310
|
+
const inDegree = new Map();
|
|
311
|
+
const queue = [];
|
|
312
|
+
const result = [];
|
|
313
|
+
|
|
314
|
+
// Initialize in-degrees
|
|
315
|
+
for (const mod of this.modules) {
|
|
316
|
+
inDegree.set(mod.id, mod.dependencies.length);
|
|
317
|
+
if (mod.dependencies.length === 0) {
|
|
318
|
+
queue.push(mod.id);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Process queue
|
|
323
|
+
while (queue.length > 0) {
|
|
324
|
+
const current = queue.shift();
|
|
325
|
+
result.push(current);
|
|
326
|
+
|
|
327
|
+
const node = this.dependencyGraph.get(current);
|
|
328
|
+
if (node) {
|
|
329
|
+
for (const dependent of node.dependedBy) {
|
|
330
|
+
const newDegree = inDegree.get(dependent) - 1;
|
|
331
|
+
inDegree.set(dependent, newDegree);
|
|
332
|
+
if (newDegree === 0) {
|
|
333
|
+
queue.push(dependent);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Check for cycles
|
|
340
|
+
if (result.length !== this.modules.length) {
|
|
341
|
+
console.warn('Circular dependency detected, falling back to priority order');
|
|
342
|
+
return this.modules
|
|
343
|
+
.sort((a, b) => a.priority - b.priority)
|
|
344
|
+
.map(m => m.id);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return result;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Serialize dependency graph for storage
|
|
352
|
+
*/
|
|
353
|
+
serializeDependencyGraph() {
|
|
354
|
+
const serialized = {};
|
|
355
|
+
for (const [key, value] of this.dependencyGraph) {
|
|
356
|
+
serialized[key] = {
|
|
357
|
+
dependsOn: value.dependsOn,
|
|
358
|
+
dependedBy: value.dependedBy
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
return serialized;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Estimate overall project complexity
|
|
366
|
+
*/
|
|
367
|
+
estimateComplexity() {
|
|
368
|
+
const sizeWeights = { small: 1, medium: 2, large: 3 };
|
|
369
|
+
const totalWeight = this.modules.reduce((sum, mod) => {
|
|
370
|
+
return sum + sizeWeights[mod.estimatedSize];
|
|
371
|
+
}, 0);
|
|
372
|
+
|
|
373
|
+
if (totalWeight <= 5) return 'simple';
|
|
374
|
+
if (totalWeight <= 10) return 'moderate';
|
|
375
|
+
if (totalWeight <= 15) return 'complex';
|
|
376
|
+
return 'enterprise';
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get module by ID
|
|
381
|
+
*/
|
|
382
|
+
getModule(moduleId) {
|
|
383
|
+
return this.modules.find(m => m.id === moduleId);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Update module status
|
|
388
|
+
*/
|
|
389
|
+
updateModuleStatus(moduleId, status, data = {}) {
|
|
390
|
+
const mod = this.getModule(moduleId);
|
|
391
|
+
if (mod) {
|
|
392
|
+
mod.status = status;
|
|
393
|
+
Object.assign(mod, data);
|
|
394
|
+
}
|
|
395
|
+
return mod;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Check if module can be built (dependencies satisfied)
|
|
400
|
+
*/
|
|
401
|
+
canBuildModule(moduleId) {
|
|
402
|
+
const mod = this.getModule(moduleId);
|
|
403
|
+
if (!mod) return false;
|
|
404
|
+
|
|
405
|
+
return mod.dependencies.every(depId => {
|
|
406
|
+
const dep = this.getModule(depId);
|
|
407
|
+
return dep && dep.status === 'completed';
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get next buildable modules
|
|
413
|
+
*/
|
|
414
|
+
getNextBuildableModules() {
|
|
415
|
+
return this.modules.filter(mod =>
|
|
416
|
+
mod.status === 'pending' && this.canBuildModule(mod.id)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Generate module prompt for Claude Code
|
|
422
|
+
*/
|
|
423
|
+
generateModulePrompt(moduleId, context = {}) {
|
|
424
|
+
const mod = this.getModule(moduleId);
|
|
425
|
+
if (!mod) return null;
|
|
426
|
+
|
|
427
|
+
const completedModules = this.modules
|
|
428
|
+
.filter(m => m.status === 'completed')
|
|
429
|
+
.map(m => `- ${m.name}: ${m.files.join(', ')}`)
|
|
430
|
+
.join('\n');
|
|
431
|
+
|
|
432
|
+
return `
|
|
433
|
+
# Module: ${mod.name}
|
|
434
|
+
|
|
435
|
+
## Description
|
|
436
|
+
${mod.description}
|
|
437
|
+
|
|
438
|
+
## Dependencies
|
|
439
|
+
${mod.dependencies.length > 0
|
|
440
|
+
? mod.dependencies.map(d => `- ${this.formatModuleName(d)}`).join('\n')
|
|
441
|
+
: 'No dependencies'}
|
|
442
|
+
|
|
443
|
+
## Already Built
|
|
444
|
+
${completedModules || 'None yet'}
|
|
445
|
+
|
|
446
|
+
## Context
|
|
447
|
+
${context.projectDescription || 'Build this module according to best practices.'}
|
|
448
|
+
|
|
449
|
+
## Requirements
|
|
450
|
+
- Follow existing code patterns from completed modules
|
|
451
|
+
- Ensure compatibility with dependencies
|
|
452
|
+
- Include necessary exports for dependent modules
|
|
453
|
+
- Add appropriate error handling
|
|
454
|
+
|
|
455
|
+
## Instructions
|
|
456
|
+
Build the ${mod.name} module. Create all necessary files and ensure they integrate with existing code.
|
|
457
|
+
`;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Create decomposition engine instance
|
|
463
|
+
*/
|
|
464
|
+
export function createDecompositionEngine() {
|
|
465
|
+
return new DecompositionEngine();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Quick decompose helper
|
|
470
|
+
*/
|
|
471
|
+
export async function decomposeProject(description, options = {}) {
|
|
472
|
+
const engine = new DecompositionEngine();
|
|
473
|
+
return engine.decompose(description, options);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export { MODULE_PATTERNS, PROJECT_TEMPLATES };
|