vibe-weaver 1.0.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 +229 -0
- package/bin/vibe-weaver.js +8 -0
- package/dist/bin/vibe-weaver.js +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2018 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
- package/src/agent/deploy.ts +171 -0
- package/src/agent/swarm.ts +167 -0
- package/src/agent/tasks.ts +205 -0
- package/src/auth/index.ts +273 -0
- package/src/config/index.ts +86 -0
- package/src/index.ts +797 -0
- package/src/lib/code-parser.ts +150 -0
- package/src/lib/vibe-api.ts +197 -0
- package/src/mcp/index.ts +273 -0
- package/src/tools/files.ts +279 -0
- package/src/tools/git.ts +498 -0
- package/src/tools/shell.ts +248 -0
- package/tsconfig.json +25 -0
- package/tsup.config.ts +34 -0
- package/vibe-weaver-1.0.0.tgz +0 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vibe-Weaver CLI - Main Entry Point
|
|
3
|
+
* A production-ready terminal agent that beats Claude Code
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { login, logout, whoami, loginGithub, isLoggedIn } from './auth/index.js';
|
|
9
|
+
import { generateCode, getCreditCost } from './lib/vibe-api.js';
|
|
10
|
+
import { writeCodeBlocks } from './lib/code-parser.js';
|
|
11
|
+
import { readFile, writeFile, listDir, grep } from './tools/files.js';
|
|
12
|
+
import { runShell, getInstallCommand, getBuildCommand } from './tools/shell.js';
|
|
13
|
+
import {
|
|
14
|
+
getStatus, getBranch, commit, commitAll, push, pull,
|
|
15
|
+
getDiff, isRepo, fullPRWorkflow
|
|
16
|
+
} from './tools/git.js';
|
|
17
|
+
import inquirer from 'inquirer';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
|
|
20
|
+
const program = new Command();
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.name('vibe-weaver')
|
|
24
|
+
.description('Vibe-Weaver CLI - Production-ready terminal agent that beats Claude Code')
|
|
25
|
+
.version('1.0.0');
|
|
26
|
+
|
|
27
|
+
// ============================================
|
|
28
|
+
// Auth Commands
|
|
29
|
+
// ============================================
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.command('login')
|
|
33
|
+
.description('Log in with your Vibe-Weaver API key')
|
|
34
|
+
.option('-k, --api-key <key>', 'API key (vw_...)')
|
|
35
|
+
.option('-o, --open', 'Open browser to create API key')
|
|
36
|
+
.option('-g, --github', 'Also configure GitHub token')
|
|
37
|
+
.action(async (options) => {
|
|
38
|
+
try {
|
|
39
|
+
await login({ apiKey: options.apiKey, openBrowser: options.open });
|
|
40
|
+
|
|
41
|
+
if (options.github) {
|
|
42
|
+
await loginGithub();
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(chalk.red('Login failed:'), error instanceof Error ? error.message : error);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command('logout')
|
|
52
|
+
.description('Log out and clear stored credentials')
|
|
53
|
+
.action(async () => {
|
|
54
|
+
try {
|
|
55
|
+
await logout();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red('Logout failed:'), error instanceof Error ? error.message : error);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
program
|
|
63
|
+
.command('whoami')
|
|
64
|
+
.description('Show current user info and credits')
|
|
65
|
+
.action(async () => {
|
|
66
|
+
try {
|
|
67
|
+
await whoami();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ============================================
|
|
75
|
+
// Generate Commands
|
|
76
|
+
// ============================================
|
|
77
|
+
|
|
78
|
+
program
|
|
79
|
+
.command('generate')
|
|
80
|
+
.description('Generate code using Vibe-Weaver AI')
|
|
81
|
+
.option('-g, --goal <text>', 'Goal/prompt for code generation')
|
|
82
|
+
.option('-p, --platform <type>', 'Platform: web, roblox, mobile, desktop, api', 'web')
|
|
83
|
+
.option('-l, --language <lang>', 'Language: typescript, javascript, python, lua, rust', 'typescript')
|
|
84
|
+
.option('-m, --mode <mode>', 'Model: fast, balanced, deep_reasoning, refactor', 'balanced')
|
|
85
|
+
.option('-o, --out <dir>', 'Output directory', '.')
|
|
86
|
+
.option('-y, --yes', 'Auto-approve file writes')
|
|
87
|
+
.option('-d, --dry-run', 'Show what would be generated without writing')
|
|
88
|
+
.action(async (options) => {
|
|
89
|
+
if (!options.goal) {
|
|
90
|
+
console.error(chalk.red('Error: --goal is required'));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const loggedIn = await isLoggedIn();
|
|
96
|
+
if (!loggedIn) {
|
|
97
|
+
console.error(chalk.red('Not logged in. Run "vibe-weaver login" first.'));
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(chalk.cyan('\n🎨 Vibe-Weaver Code Generation'));
|
|
102
|
+
console.log(chalk.gray(`Mode: ${options.mode} | Platform: ${options.platform} | Language: ${options.language}`));
|
|
103
|
+
console.log(chalk.gray(`Cost: ~${getCreditCost(options.mode)} credits\n`));
|
|
104
|
+
|
|
105
|
+
const result = await generateCode({
|
|
106
|
+
goal: options.goal,
|
|
107
|
+
platform: options.platform,
|
|
108
|
+
language: options.language,
|
|
109
|
+
modelId: options.mode
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
console.log(chalk.gray('Explanation:'));
|
|
113
|
+
console.log(result.explanation);
|
|
114
|
+
|
|
115
|
+
console.log(chalk.gray('\nQuality Score:'), `${result.quality.score}/100`);
|
|
116
|
+
|
|
117
|
+
if (result.parsed.blocks.length > 0) {
|
|
118
|
+
console.log(chalk.gray('\nGenerated Files:'));
|
|
119
|
+
for (const block of result.parsed.blocks) {
|
|
120
|
+
console.log(` - ${chalk.green(block.path)} (${block.language})`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!options.dryRun) {
|
|
124
|
+
const writeResult = await writeCodeBlocks(result.parsed.blocks, path.resolve(options.out));
|
|
125
|
+
|
|
126
|
+
console.log(chalk.gray('\nWritten:'));
|
|
127
|
+
for (const file of writeResult.success) {
|
|
128
|
+
console.log(` ✓ ${file}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (writeResult.failed.length > 0) {
|
|
132
|
+
console.log(chalk.red('\nFailed:'));
|
|
133
|
+
for (const file of writeResult.failed) {
|
|
134
|
+
console.log(` ✗ ${file.path}: ${file.error}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
console.log(chalk.yellow('\n[DRY-RUN] Files not written'));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log(chalk.green('\n✓ Generation complete'));
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// ============================================
|
|
150
|
+
// Agent Commands
|
|
151
|
+
// ============================================
|
|
152
|
+
|
|
153
|
+
program
|
|
154
|
+
.command('run')
|
|
155
|
+
.description('Run the interactive agent loop (REPL)')
|
|
156
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
157
|
+
.option('-y, --yes', 'Auto-approve all operations')
|
|
158
|
+
.option('-d, --dry-run', 'Preview changes without applying')
|
|
159
|
+
.action(async (options) => {
|
|
160
|
+
const loggedIn = await isLoggedIn();
|
|
161
|
+
if (!loggedIn) {
|
|
162
|
+
console.error(chalk.red('Not logged in. Run "vibe-weaver login" first.'));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
console.log(chalk.cyan('🎯 Vibe-Weaver Interactive Agent'));
|
|
167
|
+
console.log(chalk.gray('Type your goal or task. Press Ctrl+C to exit.\n'));
|
|
168
|
+
|
|
169
|
+
// Interactive REPL
|
|
170
|
+
const readline = await import('readline');
|
|
171
|
+
const rl = readline.createInterface({
|
|
172
|
+
input: process.stdin,
|
|
173
|
+
output: process.stdout
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const askQuestion = () => {
|
|
177
|
+
rl.question(chalk.green('\n> '), async (input) => {
|
|
178
|
+
if (!input.trim()) {
|
|
179
|
+
askQuestion();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
|
|
184
|
+
rl.close();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
console.log(chalk.gray('\nGenerating code...'));
|
|
190
|
+
const result = await generateCode({ goal: input });
|
|
191
|
+
|
|
192
|
+
if (result.parsed.blocks.length > 0) {
|
|
193
|
+
const writeResult = await writeCodeBlocks(result.parsed.blocks, options.cwd);
|
|
194
|
+
|
|
195
|
+
console.log(chalk.green('\n✓ Generated files:'));
|
|
196
|
+
for (const file of writeResult.success) {
|
|
197
|
+
console.log(` ✓ ${file}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (writeResult.failed.length > 0) {
|
|
201
|
+
console.log(chalk.red('\n✗ Failed:'));
|
|
202
|
+
for (const file of writeResult.failed) {
|
|
203
|
+
console.log(` ✗ ${file.path}: ${file.error}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
askQuestion();
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
askQuestion();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ============================================
|
|
219
|
+
// File Commands
|
|
220
|
+
// ============================================
|
|
221
|
+
|
|
222
|
+
program
|
|
223
|
+
.command('read')
|
|
224
|
+
.description('Read a file')
|
|
225
|
+
.argument('<file>', 'File path to read')
|
|
226
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
227
|
+
.action(async (file, options) => {
|
|
228
|
+
try {
|
|
229
|
+
const result = await readFile(file, options.cwd);
|
|
230
|
+
if (result.success && result.content) {
|
|
231
|
+
console.log(result.content);
|
|
232
|
+
} else {
|
|
233
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
program
|
|
243
|
+
.command('write')
|
|
244
|
+
.description('Write content to a file')
|
|
245
|
+
.argument('<file>', 'File path to write')
|
|
246
|
+
.argument('<content>', 'Content to write')
|
|
247
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
248
|
+
.option('-d, --dry-run', 'Preview without writing')
|
|
249
|
+
.action(async (file, content, options) => {
|
|
250
|
+
try {
|
|
251
|
+
const result = await writeFile(file, content, options.cwd, { dryRun: options.dryRun });
|
|
252
|
+
if (result.success) {
|
|
253
|
+
console.log(chalk.green(`✓ Written to ${file}`));
|
|
254
|
+
} else {
|
|
255
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
program
|
|
265
|
+
.command('ls')
|
|
266
|
+
.description('List files in a directory')
|
|
267
|
+
.argument('[dir]', 'Directory to list', '.')
|
|
268
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
269
|
+
.action(async (dir, options) => {
|
|
270
|
+
try {
|
|
271
|
+
const entries = await listDir(dir, options.cwd);
|
|
272
|
+
for (const entry of entries) {
|
|
273
|
+
const prefix = entry.isDirectory ? chalk.blue('📁') : chalk.gray('📄');
|
|
274
|
+
console.log(`${prefix} ${entry.path}`);
|
|
275
|
+
}
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
program
|
|
283
|
+
.command('grep')
|
|
284
|
+
.description('Search for a pattern in files')
|
|
285
|
+
.argument('<pattern>', 'Pattern to search for')
|
|
286
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
287
|
+
.option('-r, --recursive', 'Search recursively', true)
|
|
288
|
+
.action(async (pattern, options) => {
|
|
289
|
+
try {
|
|
290
|
+
const results = await grep(pattern, options.cwd, { recursive: options.recursive });
|
|
291
|
+
if (results.length === 0) {
|
|
292
|
+
console.log(chalk.yellow('No matches found'));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
for (const result of results) {
|
|
297
|
+
console.log(`${chalk.gray(`${result.file}:${result.line}`)} ${result.content}`);
|
|
298
|
+
}
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// ============================================
|
|
306
|
+
// Shell Commands
|
|
307
|
+
// ============================================
|
|
308
|
+
|
|
309
|
+
program
|
|
310
|
+
.command('exec')
|
|
311
|
+
.description('Execute a shell command')
|
|
312
|
+
.argument('<command>', 'Command to execute')
|
|
313
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
314
|
+
.option('-d, --dry-run', 'Preview without executing')
|
|
315
|
+
.action(async (command, options) => {
|
|
316
|
+
try {
|
|
317
|
+
if (options.dryRun) {
|
|
318
|
+
console.log(chalk.yellow(`[DRY-RUN] Would execute: ${command}`));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
console.log(chalk.gray(`$ ${command}`));
|
|
323
|
+
const result = await runShell(command, { cwd: options.cwd });
|
|
324
|
+
|
|
325
|
+
if (result.stdout) console.log(result.stdout);
|
|
326
|
+
if (result.stderr) console.error(chalk.red(result.stderr));
|
|
327
|
+
|
|
328
|
+
process.exit(result.exitCode);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// ============================================
|
|
336
|
+
// Git Commands
|
|
337
|
+
// ============================================
|
|
338
|
+
|
|
339
|
+
program
|
|
340
|
+
.command('status')
|
|
341
|
+
.description('Show git status')
|
|
342
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
343
|
+
.action(async (options) => {
|
|
344
|
+
try {
|
|
345
|
+
const status = await getStatus(options.cwd);
|
|
346
|
+
|
|
347
|
+
console.log(chalk.gray(`Branch: ${status.current || '(none)'}`));
|
|
348
|
+
if (status.tracking) {
|
|
349
|
+
console.log(chalk.gray(`Tracking: ${status.tracking}`));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (status.staged.length > 0) {
|
|
353
|
+
console.log(chalk.green('\nStaged:'));
|
|
354
|
+
for (const file of status.staged) {
|
|
355
|
+
console.log(` ${chalk.green('+')} ${file}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (status.modified.length > 0) {
|
|
360
|
+
console.log(chalk.yellow('\nModified:'));
|
|
361
|
+
for (const file of status.modified) {
|
|
362
|
+
console.log(` ${chalk.yellow('M')} ${file}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (status.untracked.length > 0) {
|
|
367
|
+
console.log(chalk.gray('\nUntracked:'));
|
|
368
|
+
for (const file of status.untracked) {
|
|
369
|
+
console.log(` ${chalk.gray('?')} ${file}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
program
|
|
379
|
+
.command('commit')
|
|
380
|
+
.description('Commit changes with a message')
|
|
381
|
+
.argument('<message>', 'Commit message')
|
|
382
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
383
|
+
.option('-a, --all', 'Stage all changes', false)
|
|
384
|
+
.action(async (message, options) => {
|
|
385
|
+
try {
|
|
386
|
+
if (options.all) {
|
|
387
|
+
const result = await commitAll(message, options.cwd);
|
|
388
|
+
if (result.success) {
|
|
389
|
+
console.log(chalk.green(`✓ Committed: ${result.message}`));
|
|
390
|
+
} else {
|
|
391
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
const result = await commit(message, options.cwd);
|
|
396
|
+
if (result.success) {
|
|
397
|
+
console.log(chalk.green(`✓ Committed: ${result.message}`));
|
|
398
|
+
} else {
|
|
399
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
program
|
|
410
|
+
.command('push')
|
|
411
|
+
.description('Push to remote')
|
|
412
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
413
|
+
.option('-f, --force', 'Force push', false)
|
|
414
|
+
.action(async (options) => {
|
|
415
|
+
try {
|
|
416
|
+
const result = await push({ force: options.force }, options.cwd);
|
|
417
|
+
if (result.success) {
|
|
418
|
+
console.log(chalk.green('✓ Pushed successfully'));
|
|
419
|
+
} else {
|
|
420
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
program
|
|
430
|
+
.command('pull')
|
|
431
|
+
.description('Pull from remote')
|
|
432
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
433
|
+
.action(async (options) => {
|
|
434
|
+
try {
|
|
435
|
+
const result = await pull({}, options.cwd);
|
|
436
|
+
if (result.success) {
|
|
437
|
+
console.log(chalk.green('✓ Pulled successfully'));
|
|
438
|
+
} else {
|
|
439
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
444
|
+
process.exit(1);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// ============================================
|
|
449
|
+
// PR Commands
|
|
450
|
+
// ============================================
|
|
451
|
+
|
|
452
|
+
program
|
|
453
|
+
.command('pr')
|
|
454
|
+
.description('Create a pull request with AI-generated summary')
|
|
455
|
+
.option('-t, --title <title>', 'PR title')
|
|
456
|
+
.option('-b, --body <body>', 'PR body')
|
|
457
|
+
.option('-o, --owner <owner>', 'Repository owner')
|
|
458
|
+
.option('-r, --repo <repo>', 'Repository name')
|
|
459
|
+
.option('-B, --base <branch>', 'Base branch', 'main')
|
|
460
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
461
|
+
.action(async (options) => {
|
|
462
|
+
try {
|
|
463
|
+
const isGitRepo = await isRepo(options.cwd);
|
|
464
|
+
if (!isGitRepo) {
|
|
465
|
+
console.error(chalk.red('Not a git repository'));
|
|
466
|
+
process.exit(1);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Get current branch
|
|
470
|
+
const currentBranch = await getBranch(options.cwd);
|
|
471
|
+
|
|
472
|
+
// If no title/body provided, generate with AI
|
|
473
|
+
let prTitle = options.title;
|
|
474
|
+
let prBody = options.body;
|
|
475
|
+
|
|
476
|
+
if (!prTitle || !prBody) {
|
|
477
|
+
console.log(chalk.gray('Generating PR description with AI...'));
|
|
478
|
+
const result = await generateCode({
|
|
479
|
+
goal: `Create a descriptive pull request title and body for the changes in branch ${currentBranch}. Focus on what changed and why.`,
|
|
480
|
+
modelId: 'balanced'
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// Parse the result
|
|
484
|
+
const lines = result.explanation.split('\n').filter(l => l.trim());
|
|
485
|
+
if (!prTitle) prTitle = lines[0] || `Update ${currentBranch}`;
|
|
486
|
+
if (!prBody) prBody = lines.slice(1).join('\n') || result.explanation;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Prompt for required options if not provided
|
|
490
|
+
if (!options.owner || !options.repo) {
|
|
491
|
+
const remote = await import('./tools/git.js').then(m => m.getRemote(options.cwd));
|
|
492
|
+
if (remote) {
|
|
493
|
+
// Parse owner/repo from remote URL
|
|
494
|
+
const match = remote.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
|
|
495
|
+
if (match) {
|
|
496
|
+
options.owner = options.owner || match[1];
|
|
497
|
+
options.repo = options.repo || match[2];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!options.owner || !options.repo) {
|
|
503
|
+
const answers = await inquirer.prompt([
|
|
504
|
+
{ type: 'input', name: 'owner', message: 'Repository owner:', when: !options.owner },
|
|
505
|
+
{ type: 'input', name: 'repo', message: 'Repository name:', when: !options.repo }
|
|
506
|
+
]);
|
|
507
|
+
options.owner = options.owner || answers.owner;
|
|
508
|
+
options.repo = options.repo || answers.repo;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Get diff for PR
|
|
512
|
+
const diff = await getDiff({ from: options.base, to: currentBranch }, options.cwd);
|
|
513
|
+
console.log(chalk.gray(`Diff: ${diff.length} characters`));
|
|
514
|
+
|
|
515
|
+
const result = await fullPRWorkflow({
|
|
516
|
+
owner: options.owner,
|
|
517
|
+
repo: options.repo,
|
|
518
|
+
branchName: currentBranch,
|
|
519
|
+
baseBranch: options.base,
|
|
520
|
+
files: [], // Would need to parse diff into files
|
|
521
|
+
commitMessage: prTitle,
|
|
522
|
+
prTitle,
|
|
523
|
+
prBody
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
if (result.success) {
|
|
527
|
+
console.log(chalk.green(`\n✓ PR created: ${result.prUrl}`));
|
|
528
|
+
} else {
|
|
529
|
+
console.error(chalk.red(`Error: ${result.error}`));
|
|
530
|
+
process.exit(1);
|
|
531
|
+
}
|
|
532
|
+
} catch (error) {
|
|
533
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
534
|
+
process.exit(1);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// ============================================
|
|
539
|
+
// Build Commands
|
|
540
|
+
// ============================================
|
|
541
|
+
|
|
542
|
+
program
|
|
543
|
+
.command('build')
|
|
544
|
+
.description('Run build command')
|
|
545
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
546
|
+
.option('-d, --dry-run', 'Preview without executing')
|
|
547
|
+
.action(async (options) => {
|
|
548
|
+
try {
|
|
549
|
+
const buildCmd = getBuildCommand(options.cwd);
|
|
550
|
+
|
|
551
|
+
if (options.dryRun) {
|
|
552
|
+
console.log(chalk.yellow(`[DRY-RUN] Would execute: ${buildCmd}`));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
console.log(chalk.gray(`$ ${buildCmd}`));
|
|
557
|
+
const result = await runShell(buildCmd, { cwd: options.cwd });
|
|
558
|
+
|
|
559
|
+
if (result.stdout) console.log(result.stdout);
|
|
560
|
+
if (result.stderr) console.error(chalk.red(result.stderr));
|
|
561
|
+
|
|
562
|
+
if (result.success) {
|
|
563
|
+
console.log(chalk.green('\n✓ Build successful'));
|
|
564
|
+
} else {
|
|
565
|
+
console.log(chalk.red(`\n✗ Build failed (exit code ${result.exitCode})`));
|
|
566
|
+
process.exit(result.exitCode);
|
|
567
|
+
}
|
|
568
|
+
} catch (error) {
|
|
569
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
program
|
|
575
|
+
.command('install')
|
|
576
|
+
.description('Run install command')
|
|
577
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
578
|
+
.option('-d, --dry-run', 'Preview without executing')
|
|
579
|
+
.action(async (options) => {
|
|
580
|
+
try {
|
|
581
|
+
const installCmd = getInstallCommand(options.cwd);
|
|
582
|
+
|
|
583
|
+
if (options.dryRun) {
|
|
584
|
+
console.log(chalk.yellow(`[DRY-RUN] Would execute: ${installCmd}`));
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
console.log(chalk.gray(`$ ${installCmd}`));
|
|
589
|
+
const result = await runShell(installCmd, { cwd: options.cwd, timeout: 300000 });
|
|
590
|
+
|
|
591
|
+
if (result.stdout) console.log(result.stdout);
|
|
592
|
+
if (result.stderr) console.error(chalk.red(result.stderr));
|
|
593
|
+
|
|
594
|
+
if (result.success) {
|
|
595
|
+
console.log(chalk.green('\n✓ Install successful'));
|
|
596
|
+
} else {
|
|
597
|
+
console.log(chalk.red(`\n✗ Install failed (exit code ${result.exitCode})`));
|
|
598
|
+
process.exit(result.exitCode);
|
|
599
|
+
}
|
|
600
|
+
} catch (error) {
|
|
601
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
// ============================================
|
|
607
|
+
// MCP Commands
|
|
608
|
+
// ============================================
|
|
609
|
+
|
|
610
|
+
program
|
|
611
|
+
.command('mcp')
|
|
612
|
+
.description('Manage MCP server connections')
|
|
613
|
+
.option('-l, --list', 'List available MCP servers')
|
|
614
|
+
.option('-c, --connect', 'Connect to all enabled MCP servers')
|
|
615
|
+
.option('-s, --status', 'Show MCP server status')
|
|
616
|
+
.action(async (options) => {
|
|
617
|
+
const { MCPManager, getDefaultMCPServers } = await import('./mcp/index.js');
|
|
618
|
+
|
|
619
|
+
if (options.list) {
|
|
620
|
+
const servers = getDefaultMCPServers();
|
|
621
|
+
console.log(chalk.cyan('\n📡 Available MCP Servers\n'));
|
|
622
|
+
for (const server of servers) {
|
|
623
|
+
const status = server.enabled ? chalk.green('enabled') : chalk.gray('disabled');
|
|
624
|
+
console.log(` ${server.name.padEnd(20)} ${status}`);
|
|
625
|
+
}
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (options.connect) {
|
|
630
|
+
const manager = new MCPManager();
|
|
631
|
+
console.log(chalk.cyan('\n🔌 Connecting to MCP servers...\n'));
|
|
632
|
+
const result = await manager.initializeAll();
|
|
633
|
+
console.log(chalk.green(`\n✓ Connected to ${result.success.length} servers`));
|
|
634
|
+
if (result.failed.length > 0) {
|
|
635
|
+
console.log(chalk.red(`✗ Failed to connect to ${result.failed.length} servers`));
|
|
636
|
+
}
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (options.status) {
|
|
641
|
+
const manager = new MCPManager();
|
|
642
|
+
await manager.initializeAll();
|
|
643
|
+
const status = manager.getStatus();
|
|
644
|
+
console.log(chalk.cyan('\n📡 MCP Server Status\n'));
|
|
645
|
+
for (const s of status) {
|
|
646
|
+
const icon = s.connected ? chalk.green('✓') : chalk.red('✗');
|
|
647
|
+
console.log(` ${icon} ${s.name}`);
|
|
648
|
+
}
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
console.log(chalk.gray('Use --list, --connect, or --status'));
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// ============================================
|
|
656
|
+
// Swarm Commands
|
|
657
|
+
// ============================================
|
|
658
|
+
|
|
659
|
+
program
|
|
660
|
+
.command('swarm')
|
|
661
|
+
.description('Run multiple agents in parallel for complex tasks')
|
|
662
|
+
.option('-g, --goal <text>', 'Goal for the swarm')
|
|
663
|
+
.option('-p, --parallel <num>', 'Max parallel agents', '3')
|
|
664
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
665
|
+
.action(async (options) => {
|
|
666
|
+
if (!options.goal) {
|
|
667
|
+
console.error(chalk.red('Error: --goal is required'));
|
|
668
|
+
process.exit(1);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const loggedIn = await isLoggedIn();
|
|
672
|
+
if (!loggedIn) {
|
|
673
|
+
console.error(chalk.red('Not logged in. Run "vibe-weaver login" first.'));
|
|
674
|
+
process.exit(1);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const { runSwarm } = await import('./agent/swarm.js');
|
|
678
|
+
await runSwarm(options.goal, {
|
|
679
|
+
maxParallel: parseInt(options.parallel),
|
|
680
|
+
baseDir: options.cwd
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// ============================================
|
|
685
|
+
// Task Commands
|
|
686
|
+
// ============================================
|
|
687
|
+
|
|
688
|
+
const taskCmd = program
|
|
689
|
+
.command('task')
|
|
690
|
+
.description('Manage background tasks');
|
|
691
|
+
|
|
692
|
+
taskCmd
|
|
693
|
+
.command('submit')
|
|
694
|
+
.description('Submit a background task')
|
|
695
|
+
.option('-g, --goal <text>', 'Task goal')
|
|
696
|
+
.option('-p, --platform <type>', 'Platform', 'web')
|
|
697
|
+
.option('-m, --mode <mode>', 'Model mode', 'balanced')
|
|
698
|
+
.action(async (options) => {
|
|
699
|
+
if (!options.goal) {
|
|
700
|
+
console.error(chalk.red('Error: --goal is required'));
|
|
701
|
+
process.exit(1);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const { submitTask } = await import('./agent/tasks.js');
|
|
705
|
+
await submitTask({
|
|
706
|
+
goal: options.goal,
|
|
707
|
+
platform: options.platform,
|
|
708
|
+
modelId: options.mode
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
taskCmd
|
|
713
|
+
.command('status')
|
|
714
|
+
.description('Check task status')
|
|
715
|
+
.argument('<id>', 'Task ID')
|
|
716
|
+
.action(async (taskId) => {
|
|
717
|
+
const { getTaskStatus, displayTaskStatus } = await import('./agent/tasks.js');
|
|
718
|
+
const status = await getTaskStatus(taskId);
|
|
719
|
+
displayTaskStatus(status);
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
taskCmd
|
|
723
|
+
.command('logs')
|
|
724
|
+
.description('Stream task logs')
|
|
725
|
+
.argument('<id>', 'Task ID')
|
|
726
|
+
.action(async (taskId) => {
|
|
727
|
+
const { streamTaskLogs } = await import('./agent/tasks.js');
|
|
728
|
+
console.log(chalk.gray(`Streaming logs for task ${taskId}...\n`));
|
|
729
|
+
|
|
730
|
+
for await (const log of streamTaskLogs(taskId)) {
|
|
731
|
+
process.stdout.write(log);
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
taskCmd
|
|
736
|
+
.command('wait')
|
|
737
|
+
.description('Wait for task to complete')
|
|
738
|
+
.argument('<id>', 'Task ID')
|
|
739
|
+
.option('-t, --timeout <seconds>', 'Timeout in seconds', '300')
|
|
740
|
+
.action(async (taskId, options) => {
|
|
741
|
+
const { waitForTask, displayTaskStatus } = await import('./agent/tasks.js');
|
|
742
|
+
|
|
743
|
+
try {
|
|
744
|
+
const status = await waitForTask(taskId, {
|
|
745
|
+
pollInterval: 5000,
|
|
746
|
+
onProgress: (s) => {
|
|
747
|
+
process.stdout.write(chalk.gray(`\rStatus: ${s.status}`));
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
console.log();
|
|
751
|
+
displayTaskStatus(status);
|
|
752
|
+
} catch (error) {
|
|
753
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
// ============================================
|
|
759
|
+
// Deploy Commands
|
|
760
|
+
// ============================================
|
|
761
|
+
|
|
762
|
+
program
|
|
763
|
+
.command('deploy')
|
|
764
|
+
.description('Deploy project and verify')
|
|
765
|
+
.option('-i, --project-id <id>', 'Project ID')
|
|
766
|
+
.option('-t, --platform <type>', 'Platform', 'web')
|
|
767
|
+
.option('-v, --verify', 'Verify deployment', true)
|
|
768
|
+
.option('--no-verify', 'Skip verification')
|
|
769
|
+
.option('-c, --cwd <dir>', 'Working directory', process.cwd())
|
|
770
|
+
.action(async (options) => {
|
|
771
|
+
const loggedIn = await isLoggedIn();
|
|
772
|
+
if (!loggedIn) {
|
|
773
|
+
console.error(chalk.red('Not logged in. Run "vibe-weaver login" first.'));
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const { deploy } = await import('./agent/deploy.js');
|
|
778
|
+
const result = await deploy({
|
|
779
|
+
projectId: options.projectId,
|
|
780
|
+
platform: options.platform,
|
|
781
|
+
verify: options.verify,
|
|
782
|
+
cwd: options.cwd
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
if (result.success) {
|
|
786
|
+
console.log(chalk.green(`\n✓ Deployed to ${result.url}`));
|
|
787
|
+
} else {
|
|
788
|
+
console.error(chalk.red(`\n✗ Deployment failed: ${result.error}`));
|
|
789
|
+
process.exit(1);
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// ============================================
|
|
794
|
+
// Main entry point
|
|
795
|
+
// ============================================
|
|
796
|
+
|
|
797
|
+
program.parse();
|