@nclamvn/vibecode-cli 1.6.0 → 1.7.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 (63) hide show
  1. package/bin/vibecode.js +48 -1
  2. package/docs-site/README.md +41 -0
  3. package/docs-site/blog/2019-05-28-first-blog-post.md +12 -0
  4. package/docs-site/blog/2019-05-29-long-blog-post.md +44 -0
  5. package/docs-site/blog/2021-08-01-mdx-blog-post.mdx +24 -0
  6. package/docs-site/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  7. package/docs-site/blog/2021-08-26-welcome/index.md +29 -0
  8. package/docs-site/blog/authors.yml +25 -0
  9. package/docs-site/blog/tags.yml +19 -0
  10. package/docs-site/docs/commands/agent.md +162 -0
  11. package/docs-site/docs/commands/assist.md +71 -0
  12. package/docs-site/docs/commands/build.md +53 -0
  13. package/docs-site/docs/commands/config.md +30 -0
  14. package/docs-site/docs/commands/debug.md +173 -0
  15. package/docs-site/docs/commands/doctor.md +34 -0
  16. package/docs-site/docs/commands/go.md +128 -0
  17. package/docs-site/docs/commands/index.md +79 -0
  18. package/docs-site/docs/commands/init.md +42 -0
  19. package/docs-site/docs/commands/learn.md +82 -0
  20. package/docs-site/docs/commands/lock.md +33 -0
  21. package/docs-site/docs/commands/plan.md +29 -0
  22. package/docs-site/docs/commands/review.md +31 -0
  23. package/docs-site/docs/commands/snapshot.md +34 -0
  24. package/docs-site/docs/commands/start.md +32 -0
  25. package/docs-site/docs/commands/status.md +37 -0
  26. package/docs-site/docs/commands/undo.md +83 -0
  27. package/docs-site/docs/configuration.md +72 -0
  28. package/docs-site/docs/faq.md +83 -0
  29. package/docs-site/docs/getting-started.md +119 -0
  30. package/docs-site/docs/guides/agent-mode.md +94 -0
  31. package/docs-site/docs/guides/debug-mode.md +83 -0
  32. package/docs-site/docs/guides/magic-mode.md +107 -0
  33. package/docs-site/docs/installation.md +98 -0
  34. package/docs-site/docs/intro.md +67 -0
  35. package/docs-site/docusaurus.config.ts +141 -0
  36. package/docs-site/package-lock.json +18039 -0
  37. package/docs-site/package.json +48 -0
  38. package/docs-site/sidebars.ts +70 -0
  39. package/docs-site/src/components/HomepageFeatures/index.tsx +72 -0
  40. package/docs-site/src/components/HomepageFeatures/styles.module.css +16 -0
  41. package/docs-site/src/css/custom.css +30 -0
  42. package/docs-site/src/pages/index.module.css +23 -0
  43. package/docs-site/src/pages/index.tsx +44 -0
  44. package/docs-site/src/pages/markdown-page.md +7 -0
  45. package/docs-site/src/theme/Footer/index.tsx +127 -0
  46. package/docs-site/src/theme/Footer/styles.module.css +285 -0
  47. package/docs-site/static/.nojekyll +0 -0
  48. package/docs-site/static/img/docusaurus-social-card.jpg +0 -0
  49. package/docs-site/static/img/docusaurus.png +0 -0
  50. package/docs-site/static/img/favicon.ico +0 -0
  51. package/docs-site/static/img/logo.svg +1 -0
  52. package/docs-site/static/img/undraw_docusaurus_mountain.svg +171 -0
  53. package/docs-site/static/img/undraw_docusaurus_react.svg +170 -0
  54. package/docs-site/static/img/undraw_docusaurus_tree.svg +40 -0
  55. package/docs-site/tsconfig.json +8 -0
  56. package/package.json +2 -1
  57. package/src/commands/debug.js +109 -1
  58. package/src/commands/git.js +923 -0
  59. package/src/commands/shell.js +486 -0
  60. package/src/commands/watch.js +556 -0
  61. package/src/debug/image-analyzer.js +304 -0
  62. package/src/index.js +19 -0
  63. package/src/utils/image.js +222 -0
@@ -0,0 +1,486 @@
1
+ /**
2
+ * Shell Mode for Vibecode CLI
3
+ * Interactive command shell with vibecode context and AI assistance
4
+ */
5
+
6
+ import readline from 'readline';
7
+ import chalk from 'chalk';
8
+ import { exec, spawn } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import path from 'path';
11
+ import fs from 'fs/promises';
12
+
13
+ const execAsync = promisify(exec);
14
+
15
+ /**
16
+ * Main shell command handler
17
+ */
18
+ export async function shellCommand(options) {
19
+ const cwd = process.cwd();
20
+ const projectInfo = await getProjectInfo(cwd);
21
+ const history = [];
22
+ let historyIndex = -1;
23
+
24
+ // Render header
25
+ console.log(renderHeader(projectInfo));
26
+
27
+ // Setup readline with custom prompt
28
+ const rl = readline.createInterface({
29
+ input: process.stdin,
30
+ output: process.stdout,
31
+ prompt: chalk.green('vibe$ '),
32
+ historySize: 100,
33
+ terminal: true
34
+ });
35
+
36
+ // Custom completer
37
+ rl.on('line', async (line) => {
38
+ const input = line.trim();
39
+
40
+ if (!input) {
41
+ rl.prompt();
42
+ return;
43
+ }
44
+
45
+ // Add to history
46
+ history.push(input);
47
+ historyIndex = history.length;
48
+
49
+ try {
50
+ const shouldContinue = await processCommand(input, cwd, projectInfo, history, rl);
51
+ if (shouldContinue === false) {
52
+ return; // Exit was called
53
+ }
54
+ } catch (error) {
55
+ console.log(chalk.red(`\n Error: ${error.message}\n`));
56
+ }
57
+
58
+ rl.prompt();
59
+ });
60
+
61
+ rl.on('close', () => {
62
+ console.log(chalk.cyan('\n Shell closed.\n'));
63
+ process.exit(0);
64
+ });
65
+
66
+ // Handle SIGINT (Ctrl+C)
67
+ rl.on('SIGINT', () => {
68
+ console.log(chalk.gray('\n (Use "exit" to quit)\n'));
69
+ rl.prompt();
70
+ });
71
+
72
+ rl.prompt();
73
+ }
74
+
75
+ /**
76
+ * Get project information for context
77
+ */
78
+ async function getProjectInfo(cwd) {
79
+ const info = {
80
+ name: path.basename(cwd),
81
+ type: 'Unknown',
82
+ framework: null,
83
+ hasGit: false,
84
+ branch: null,
85
+ hasVibecode: false
86
+ };
87
+
88
+ try {
89
+ // Check package.json
90
+ const pkgPath = path.join(cwd, 'package.json');
91
+ const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8'));
92
+
93
+ info.name = pkg.name || info.name;
94
+
95
+ // Detect framework/type
96
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
97
+
98
+ if (deps.next) {
99
+ info.type = 'Next.js';
100
+ info.framework = 'next';
101
+ } else if (deps.react) {
102
+ info.type = 'React';
103
+ info.framework = 'react';
104
+ } else if (deps.vue) {
105
+ info.type = 'Vue';
106
+ info.framework = 'vue';
107
+ } else if (deps.express) {
108
+ info.type = 'Express';
109
+ info.framework = 'express';
110
+ } else if (deps.fastify) {
111
+ info.type = 'Fastify';
112
+ info.framework = 'fastify';
113
+ } else if (deps.typescript) {
114
+ info.type = 'TypeScript';
115
+ } else if (pkg.main || pkg.bin) {
116
+ info.type = 'Node.js';
117
+ }
118
+
119
+ // Add prisma indicator
120
+ if (deps['@prisma/client'] || deps.prisma) {
121
+ info.type += ' + Prisma';
122
+ }
123
+ } catch {
124
+ // No package.json
125
+ }
126
+
127
+ try {
128
+ // Check git
129
+ await execAsync('git rev-parse --git-dir', { cwd });
130
+ info.hasGit = true;
131
+
132
+ const { stdout } = await execAsync('git branch --show-current', { cwd });
133
+ info.branch = stdout.trim() || 'HEAD';
134
+ } catch {
135
+ // Not a git repo
136
+ }
137
+
138
+ try {
139
+ // Check vibecode
140
+ await fs.stat(path.join(cwd, '.vibecode'));
141
+ info.hasVibecode = true;
142
+ } catch {
143
+ // No vibecode
144
+ }
145
+
146
+ return info;
147
+ }
148
+
149
+ /**
150
+ * Render the shell header
151
+ */
152
+ function renderHeader(projectInfo) {
153
+ const gitInfo = projectInfo.hasGit
154
+ ? chalk.gray(` [${projectInfo.branch}]`)
155
+ : '';
156
+
157
+ const vibeInfo = projectInfo.hasVibecode
158
+ ? chalk.green(' [vibecode]')
159
+ : '';
160
+
161
+ return chalk.cyan(`
162
+ +----------------------------------------------------------------------+
163
+ | VIBECODE SHELL |
164
+ | |
165
+ | Project: ${chalk.white(projectInfo.name.padEnd(52))}|${gitInfo}${vibeInfo}
166
+ | Type: ${chalk.white(projectInfo.type.padEnd(55))}|
167
+ | |
168
+ | ${chalk.gray('Prefixes:')} |
169
+ | ${chalk.yellow('@')}${chalk.gray('<cmd>')} ${chalk.gray('Vibecode command (e.g., @status, @git)')} |
170
+ | ${chalk.yellow('?')}${chalk.gray('<query>')} ${chalk.gray('Ask AI (e.g., ?explain auth)')} |
171
+ | ${chalk.yellow('!')}${chalk.gray('<cmd>')} ${chalk.gray('Force raw execution')} |
172
+ | ${chalk.yellow('!!')} ${chalk.gray('Repeat last command')} |
173
+ | |
174
+ +----------------------------------------------------------------------+
175
+ `);
176
+ }
177
+
178
+ /**
179
+ * Process a command input
180
+ */
181
+ async function processCommand(input, cwd, projectInfo, history, rl) {
182
+ // Built-in commands
183
+ if (input === 'exit' || input === 'quit' || input === 'q') {
184
+ rl.close();
185
+ return false;
186
+ }
187
+
188
+ if (input === 'clear' || input === 'cls') {
189
+ console.clear();
190
+ console.log(renderHeader(projectInfo));
191
+ return true;
192
+ }
193
+
194
+ if (input === 'history' || input === 'hist') {
195
+ console.log(chalk.cyan('\n Command history:\n'));
196
+ const start = Math.max(0, history.length - 20);
197
+ history.slice(start, -1).forEach((cmd, i) => {
198
+ console.log(chalk.gray(` ${start + i + 1}. ${cmd}`));
199
+ });
200
+ console.log('');
201
+ return true;
202
+ }
203
+
204
+ if (input === 'help' || input === 'h') {
205
+ showHelp();
206
+ return true;
207
+ }
208
+
209
+ if (input === 'pwd') {
210
+ console.log(chalk.white(`\n ${cwd}\n`));
211
+ return true;
212
+ }
213
+
214
+ if (input === 'info') {
215
+ showProjectInfo(projectInfo, cwd);
216
+ return true;
217
+ }
218
+
219
+ // Repeat last command (!!)
220
+ if (input === '!!') {
221
+ if (history.length < 2) {
222
+ console.log(chalk.yellow('\n No previous command.\n'));
223
+ return true;
224
+ }
225
+ const lastCmd = history[history.length - 2];
226
+ console.log(chalk.gray(` Repeating: ${lastCmd}\n`));
227
+ return processCommand(lastCmd, cwd, projectInfo, history, rl);
228
+ }
229
+
230
+ // History expansion (!n)
231
+ const histMatch = input.match(/^!(\d+)$/);
232
+ if (histMatch) {
233
+ const index = parseInt(histMatch[1]) - 1;
234
+ if (index >= 0 && index < history.length - 1) {
235
+ const cmd = history[index];
236
+ console.log(chalk.gray(` Repeating: ${cmd}\n`));
237
+ return processCommand(cmd, cwd, projectInfo, history, rl);
238
+ }
239
+ console.log(chalk.yellow('\n Invalid history index.\n'));
240
+ return true;
241
+ }
242
+
243
+ // Vibecode commands (@)
244
+ if (input.startsWith('@')) {
245
+ await runVibecodeCommand(input.slice(1), cwd);
246
+ return true;
247
+ }
248
+
249
+ // AI queries (?)
250
+ if (input.startsWith('?')) {
251
+ await runAIQuery(input.slice(1), cwd, projectInfo);
252
+ return true;
253
+ }
254
+
255
+ // Force raw execution (!)
256
+ if (input.startsWith('!') && !input.startsWith('!!')) {
257
+ await runRawCommand(input.slice(1), cwd);
258
+ return true;
259
+ }
260
+
261
+ // cd command (special handling)
262
+ if (input.startsWith('cd ')) {
263
+ const dir = input.slice(3).trim();
264
+ try {
265
+ const newPath = path.resolve(cwd, dir);
266
+ await fs.stat(newPath);
267
+ process.chdir(newPath);
268
+ console.log(chalk.gray(`\n Changed to: ${newPath}\n`));
269
+ } catch {
270
+ console.log(chalk.red(`\n Directory not found: ${dir}\n`));
271
+ }
272
+ return true;
273
+ }
274
+
275
+ // Normal shell command
276
+ await runShellCommand(input, cwd);
277
+ return true;
278
+ }
279
+
280
+ /**
281
+ * Run a vibecode command
282
+ */
283
+ async function runVibecodeCommand(cmd, cwd) {
284
+ const parts = cmd.trim().split(/\s+/);
285
+ const command = parts[0];
286
+ const args = parts.slice(1);
287
+
288
+ if (!command) {
289
+ console.log(chalk.yellow('\n Usage: @<command> [args]\n'));
290
+ return;
291
+ }
292
+
293
+ console.log(chalk.cyan(`\n Running: vibecode ${cmd}\n`));
294
+
295
+ // Map aliases
296
+ const aliases = {
297
+ 's': 'status',
298
+ 'g': 'git',
299
+ 'd': 'debug',
300
+ 'b': 'build',
301
+ 'w': 'watch',
302
+ 'a': 'assist'
303
+ };
304
+
305
+ const vibeCmd = aliases[command] || command;
306
+
307
+ return new Promise((resolve) => {
308
+ const child = spawn('vibecode', [vibeCmd, ...args], {
309
+ cwd,
310
+ stdio: 'inherit',
311
+ shell: true
312
+ });
313
+
314
+ child.on('close', (code) => {
315
+ console.log('');
316
+ resolve();
317
+ });
318
+
319
+ child.on('error', (error) => {
320
+ console.log(chalk.red(`\n Error: ${error.message}\n`));
321
+ resolve();
322
+ });
323
+ });
324
+ }
325
+
326
+ /**
327
+ * Run an AI query using Claude
328
+ */
329
+ async function runAIQuery(query, cwd, projectInfo) {
330
+ if (!query.trim()) {
331
+ console.log(chalk.yellow('\n Usage: ?<your question>\n'));
332
+ return;
333
+ }
334
+
335
+ console.log(chalk.cyan(`\n AI Query: "${query}"\n`));
336
+
337
+ // Build context
338
+ const context = `Project: ${projectInfo.name} (${projectInfo.type})
339
+ Directory: ${cwd}
340
+ Question: ${query}
341
+
342
+ Please provide a helpful, concise answer.`;
343
+
344
+ return new Promise((resolve) => {
345
+ // Try using claude CLI directly
346
+ const child = spawn('claude', ['-p', context], {
347
+ cwd,
348
+ stdio: 'inherit',
349
+ shell: true
350
+ });
351
+
352
+ child.on('close', (code) => {
353
+ console.log('');
354
+ resolve();
355
+ });
356
+
357
+ child.on('error', () => {
358
+ // Fallback: suggest using vibecode assist
359
+ console.log(chalk.yellow(' Claude CLI not available.'));
360
+ console.log(chalk.gray(' Try: vibecode assist "' + query + '"\n'));
361
+ resolve();
362
+ });
363
+ });
364
+ }
365
+
366
+ /**
367
+ * Run a raw shell command (force mode)
368
+ */
369
+ async function runRawCommand(cmd, cwd) {
370
+ if (!cmd.trim()) {
371
+ console.log(chalk.yellow('\n Usage: !<command>\n'));
372
+ return;
373
+ }
374
+
375
+ return new Promise((resolve) => {
376
+ console.log('');
377
+
378
+ const child = spawn(cmd, [], {
379
+ cwd,
380
+ stdio: 'inherit',
381
+ shell: true
382
+ });
383
+
384
+ child.on('close', (code) => {
385
+ console.log('');
386
+ resolve();
387
+ });
388
+
389
+ child.on('error', (error) => {
390
+ console.log(chalk.red(`\n Error: ${error.message}\n`));
391
+ resolve();
392
+ });
393
+ });
394
+ }
395
+
396
+ /**
397
+ * Run a normal shell command
398
+ */
399
+ async function runShellCommand(cmd, cwd) {
400
+ return new Promise((resolve) => {
401
+ console.log('');
402
+
403
+ const child = spawn(cmd, [], {
404
+ cwd,
405
+ stdio: 'inherit',
406
+ shell: true
407
+ });
408
+
409
+ child.on('close', (code) => {
410
+ if (code !== 0 && code !== null) {
411
+ console.log(chalk.gray(` Exit code: ${code}`));
412
+ }
413
+ console.log('');
414
+ resolve();
415
+ });
416
+
417
+ child.on('error', (error) => {
418
+ // Command not found
419
+ const cmdName = cmd.split(' ')[0];
420
+ console.log(chalk.red(`\n Command not found: ${cmdName}`));
421
+ console.log(chalk.gray(` Did you mean: @${cmdName}?\n`));
422
+ resolve();
423
+ });
424
+ });
425
+ }
426
+
427
+ /**
428
+ * Show help message
429
+ */
430
+ function showHelp() {
431
+ console.log(chalk.white(`
432
+ VIBECODE SHELL HELP
433
+
434
+ ${chalk.cyan('Built-in Commands:')}
435
+ exit, quit, q Exit shell
436
+ clear, cls Clear screen
437
+ history, hist Show command history
438
+ help, h Show this help
439
+ pwd Print working directory
440
+ info Show project info
441
+ cd <dir> Change directory
442
+
443
+ ${chalk.cyan('Prefixes:')}
444
+ ${chalk.yellow('@')}<command> Run vibecode command
445
+ e.g., @status, @git status, @debug
446
+
447
+ ${chalk.yellow('?')}<query> Ask AI a question
448
+ e.g., ?explain this code, ?fix the error
449
+
450
+ ${chalk.yellow('!')}<command> Force raw shell execution
451
+ e.g., !npm run dev
452
+
453
+ ${chalk.yellow('!!')} Repeat last command
454
+ ${chalk.yellow('!')}<n> Repeat command #n from history
455
+
456
+ ${chalk.cyan('Examples:')}
457
+ vibe$ npm test Run npm test
458
+ vibe$ @git commit Git commit via vibecode
459
+ vibe$ @s Vibecode status (alias)
460
+ vibe$ ?what is useState Ask AI about useState
461
+ vibe$ !node server.js Run node directly
462
+ vibe$ !! Repeat last command
463
+
464
+ ${chalk.cyan('Aliases:')}
465
+ @s -> @status @g -> @git
466
+ @d -> @debug @b -> @build
467
+ @w -> @watch @a -> @assist
468
+ `));
469
+ }
470
+
471
+ /**
472
+ * Show project information
473
+ */
474
+ function showProjectInfo(projectInfo, cwd) {
475
+ console.log(chalk.cyan(`
476
+ PROJECT INFO
477
+
478
+ Name: ${chalk.white(projectInfo.name)}
479
+ Type: ${chalk.white(projectInfo.type)}
480
+ Directory: ${chalk.white(cwd)}
481
+ Git: ${projectInfo.hasGit ? chalk.green('Yes') + chalk.gray(` (${projectInfo.branch})`) : chalk.gray('No')}
482
+ Vibecode: ${projectInfo.hasVibecode ? chalk.green('Yes') : chalk.gray('No')}
483
+ `));
484
+ }
485
+
486
+ export default shellCommand;