@nclamvn/vibecode-cli 2.2.0 → 3.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/bin/vibecode.js +101 -2
- package/package.json +3 -1
- package/src/commands/config.js +42 -4
- package/src/commands/deploy.js +728 -0
- package/src/commands/favorite.js +412 -0
- package/src/commands/feedback.js +473 -0
- package/src/commands/go.js +170 -4
- package/src/commands/history.js +249 -0
- package/src/commands/images.js +465 -0
- package/src/commands/preview.js +554 -0
- package/src/commands/voice.js +580 -0
- package/src/commands/watch.js +3 -20
- package/src/index.js +49 -2
- package/src/services/image-service.js +513 -0
- package/src/utils/history.js +357 -0
- package/src/utils/notifications.js +343 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - Favorite Command
|
|
3
|
+
// Manage favorite prompts for quick reuse
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import {
|
|
10
|
+
loadFavorites,
|
|
11
|
+
addFavorite,
|
|
12
|
+
removeFavorite,
|
|
13
|
+
getFavorite,
|
|
14
|
+
searchFavorites,
|
|
15
|
+
updateFavoriteUsage,
|
|
16
|
+
exportFavorites,
|
|
17
|
+
importFavorites,
|
|
18
|
+
clearFavorites,
|
|
19
|
+
getFavoritesStats
|
|
20
|
+
} from '../utils/history.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Favorite command entry point
|
|
24
|
+
*/
|
|
25
|
+
export async function favoriteCommand(action, args = [], options = {}) {
|
|
26
|
+
// Default action: list
|
|
27
|
+
if (!action || action === 'list') {
|
|
28
|
+
return listFavorites();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Add favorite
|
|
32
|
+
if (action === 'add') {
|
|
33
|
+
const prompt = Array.isArray(args) ? args.join(' ') : args;
|
|
34
|
+
if (!prompt) {
|
|
35
|
+
console.log(chalk.red('\n ❌ Please provide a prompt to save.\n'));
|
|
36
|
+
console.log(chalk.gray(' Usage: vibecode fav add "Your prompt here"\n'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
return addFavoriteCommand(prompt, options);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Remove favorite
|
|
43
|
+
if (action === 'remove' || action === 'rm' || action === 'delete') {
|
|
44
|
+
const identifier = Array.isArray(args) ? args[0] : args;
|
|
45
|
+
if (!identifier) {
|
|
46
|
+
console.log(chalk.red('\n ❌ Please specify which favorite to remove.\n'));
|
|
47
|
+
console.log(chalk.gray(' Usage: vibecode fav remove <number or name>\n'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
return removeFavoriteCommand(identifier);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Run favorite
|
|
54
|
+
if (action === 'run' || action === 'use') {
|
|
55
|
+
const identifier = Array.isArray(args) ? args[0] : args;
|
|
56
|
+
if (!identifier) {
|
|
57
|
+
return selectAndRunFavorite();
|
|
58
|
+
}
|
|
59
|
+
return runFavoriteCommand(identifier, options);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Search favorites
|
|
63
|
+
if (action === 'search' || action === 'find') {
|
|
64
|
+
const query = Array.isArray(args) ? args.join(' ') : args;
|
|
65
|
+
if (!query) {
|
|
66
|
+
console.log(chalk.red('\n ❌ Please provide a search query.\n'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
return searchFavoritesCommand(query);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Export
|
|
73
|
+
if (action === 'export') {
|
|
74
|
+
const data = await exportFavorites();
|
|
75
|
+
console.log(JSON.stringify(data, null, 2));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Import
|
|
80
|
+
if (action === 'import') {
|
|
81
|
+
return importFavoritesCommand(options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Clear
|
|
85
|
+
if (action === 'clear') {
|
|
86
|
+
return clearFavoritesCommand();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Stats
|
|
90
|
+
if (action === 'stats') {
|
|
91
|
+
return showFavoritesStats();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Unknown action - show help
|
|
95
|
+
showFavoriteHelp();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* List all favorites
|
|
100
|
+
*/
|
|
101
|
+
async function listFavorites() {
|
|
102
|
+
const favorites = await loadFavorites();
|
|
103
|
+
|
|
104
|
+
console.log(chalk.cyan(`
|
|
105
|
+
╭────────────────────────────────────────────────────────────────────╮
|
|
106
|
+
│ ⭐ FAVORITES │
|
|
107
|
+
╰────────────────────────────────────────────────────────────────────╯
|
|
108
|
+
`));
|
|
109
|
+
|
|
110
|
+
if (favorites.length === 0) {
|
|
111
|
+
console.log(chalk.gray(' No favorites yet.\n'));
|
|
112
|
+
console.log(chalk.gray(' Add one:\n'));
|
|
113
|
+
console.log(chalk.gray(' vibecode fav add "Your prompt here"\n'));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < favorites.length; i++) {
|
|
118
|
+
const fav = favorites[i];
|
|
119
|
+
const usage = fav.usageCount
|
|
120
|
+
? chalk.gray(` (used ${fav.usageCount}x)`)
|
|
121
|
+
: '';
|
|
122
|
+
|
|
123
|
+
const displayName = (fav.name || fav.description || 'Untitled').substring(0, 40);
|
|
124
|
+
|
|
125
|
+
console.log(
|
|
126
|
+
chalk.yellow(` ${(i + 1).toString().padStart(2)}. `) +
|
|
127
|
+
chalk.white(displayName) +
|
|
128
|
+
usage
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Show command preview
|
|
132
|
+
const cmdPreview = fav.command.length > 55
|
|
133
|
+
? fav.command.substring(0, 52) + '...'
|
|
134
|
+
: fav.command;
|
|
135
|
+
console.log(chalk.gray(` ${cmdPreview}`));
|
|
136
|
+
|
|
137
|
+
// Show tags if any
|
|
138
|
+
if (fav.tags && fav.tags.length > 0) {
|
|
139
|
+
console.log(chalk.gray(` Tags: ${fav.tags.join(', ')}`));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(chalk.gray(` Commands:`));
|
|
146
|
+
console.log(chalk.gray(` ${chalk.cyan('vibecode fav run <n>')} Run favorite`));
|
|
147
|
+
console.log(chalk.gray(` ${chalk.cyan('vibecode fav add "..."')} Add favorite`));
|
|
148
|
+
console.log(chalk.gray(` ${chalk.cyan('vibecode fav remove <n>')} Remove favorite\n`));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Add a new favorite
|
|
153
|
+
*/
|
|
154
|
+
async function addFavoriteCommand(prompt, options) {
|
|
155
|
+
// Build command
|
|
156
|
+
let command;
|
|
157
|
+
if (options.template) {
|
|
158
|
+
command = `vibecode go --template ${options.template}`;
|
|
159
|
+
} else {
|
|
160
|
+
command = `vibecode go "${prompt}"`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Add extra options if specified
|
|
164
|
+
if (options.preview) command += ' --preview';
|
|
165
|
+
if (options.deploy) command += ' --deploy';
|
|
166
|
+
if (options.notify) command += ' --notify';
|
|
167
|
+
|
|
168
|
+
const name = options.name || prompt.substring(0, 40);
|
|
169
|
+
const tags = options.tags ? options.tags.split(',').map(t => t.trim()) : [];
|
|
170
|
+
|
|
171
|
+
const result = await addFavorite(name, command, prompt, tags);
|
|
172
|
+
|
|
173
|
+
if (result.success) {
|
|
174
|
+
console.log(chalk.green(`\n ⭐ Added to favorites!\n`));
|
|
175
|
+
console.log(chalk.white(` Name: ${name}`));
|
|
176
|
+
console.log(chalk.gray(` Command: ${command}\n`));
|
|
177
|
+
} else {
|
|
178
|
+
console.log(chalk.yellow(`\n ⚠️ ${result.message}\n`));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Remove a favorite
|
|
184
|
+
*/
|
|
185
|
+
async function removeFavoriteCommand(identifier) {
|
|
186
|
+
const result = await removeFavorite(identifier);
|
|
187
|
+
|
|
188
|
+
if (result.success) {
|
|
189
|
+
console.log(chalk.green(`\n ✅ Removed: "${result.removed.name}"\n`));
|
|
190
|
+
} else {
|
|
191
|
+
console.log(chalk.red(`\n ❌ ${result.message}\n`));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Run a favorite by identifier
|
|
197
|
+
*/
|
|
198
|
+
async function runFavoriteCommand(identifier, options = {}) {
|
|
199
|
+
const favorite = await getFavorite(identifier);
|
|
200
|
+
|
|
201
|
+
if (!favorite) {
|
|
202
|
+
console.log(chalk.red(`\n ❌ Favorite "${identifier}" not found.\n`));
|
|
203
|
+
console.log(chalk.gray(' Run `vibecode fav` to see your favorites.\n'));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.log(chalk.cyan(`\n ⭐ Running: ${favorite.name}\n`));
|
|
208
|
+
console.log(chalk.gray(` ${favorite.command}\n`));
|
|
209
|
+
|
|
210
|
+
if (!options.yes) {
|
|
211
|
+
const { confirm } = await inquirer.prompt([{
|
|
212
|
+
type: 'confirm',
|
|
213
|
+
name: 'confirm',
|
|
214
|
+
message: 'Execute?',
|
|
215
|
+
default: true
|
|
216
|
+
}]);
|
|
217
|
+
|
|
218
|
+
if (!confirm) {
|
|
219
|
+
console.log(chalk.gray('\n Cancelled.\n'));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Update usage count
|
|
225
|
+
await updateFavoriteUsage(favorite.id);
|
|
226
|
+
|
|
227
|
+
console.log(chalk.cyan('\n Executing...\n'));
|
|
228
|
+
|
|
229
|
+
// Execute
|
|
230
|
+
const child = spawn('sh', ['-c', favorite.command], {
|
|
231
|
+
stdio: 'inherit',
|
|
232
|
+
cwd: process.cwd(),
|
|
233
|
+
shell: true
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
child.on('error', (error) => {
|
|
237
|
+
console.log(chalk.red(`\n ❌ Error: ${error.message}\n`));
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Interactive favorite selection
|
|
243
|
+
*/
|
|
244
|
+
async function selectAndRunFavorite() {
|
|
245
|
+
const favorites = await loadFavorites();
|
|
246
|
+
|
|
247
|
+
if (favorites.length === 0) {
|
|
248
|
+
console.log(chalk.yellow('\n No favorites yet.\n'));
|
|
249
|
+
console.log(chalk.gray(' Add one: vibecode fav add "Your prompt"\n'));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const { selected } = await inquirer.prompt([{
|
|
254
|
+
type: 'list',
|
|
255
|
+
name: 'selected',
|
|
256
|
+
message: 'Select favorite to run:',
|
|
257
|
+
choices: favorites.map((f, i) => {
|
|
258
|
+
const cmdPreview = f.command.length > 40
|
|
259
|
+
? f.command.substring(0, 37) + '...'
|
|
260
|
+
: f.command;
|
|
261
|
+
return {
|
|
262
|
+
name: `${f.name} - ${chalk.gray(cmdPreview)}`,
|
|
263
|
+
value: i + 1
|
|
264
|
+
};
|
|
265
|
+
})
|
|
266
|
+
}]);
|
|
267
|
+
|
|
268
|
+
await runFavoriteCommand(selected, { yes: true });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Search favorites
|
|
273
|
+
*/
|
|
274
|
+
async function searchFavoritesCommand(query) {
|
|
275
|
+
const results = await searchFavorites(query);
|
|
276
|
+
|
|
277
|
+
console.log(chalk.cyan(`\n 🔍 Favorites matching "${query}":\n`));
|
|
278
|
+
|
|
279
|
+
if (results.length === 0) {
|
|
280
|
+
console.log(chalk.gray(' No matches found.\n'));
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < results.length; i++) {
|
|
285
|
+
const fav = results[i];
|
|
286
|
+
console.log(chalk.yellow(` ${i + 1}. `) + chalk.white(fav.name));
|
|
287
|
+
|
|
288
|
+
const cmdPreview = fav.command.length > 55
|
|
289
|
+
? fav.command.substring(0, 52) + '...'
|
|
290
|
+
: fav.command;
|
|
291
|
+
console.log(chalk.gray(` ${cmdPreview}\n`));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
console.log(chalk.gray(` Run: vibecode fav run "<name>"\n`));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Import favorites from stdin
|
|
299
|
+
*/
|
|
300
|
+
async function importFavoritesCommand(options) {
|
|
301
|
+
// Check if data is being piped
|
|
302
|
+
if (process.stdin.isTTY) {
|
|
303
|
+
console.log(chalk.yellow('\n Paste JSON data and press Ctrl+D when done:\n'));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
let data = '';
|
|
307
|
+
process.stdin.setEncoding('utf8');
|
|
308
|
+
|
|
309
|
+
return new Promise((resolve) => {
|
|
310
|
+
process.stdin.on('readable', () => {
|
|
311
|
+
let chunk;
|
|
312
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
313
|
+
data += chunk;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
process.stdin.on('end', async () => {
|
|
318
|
+
try {
|
|
319
|
+
const parsed = JSON.parse(data);
|
|
320
|
+
|
|
321
|
+
if (!Array.isArray(parsed)) {
|
|
322
|
+
console.log(chalk.red('\n ❌ Invalid format: expected an array\n'));
|
|
323
|
+
resolve();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const result = await importFavorites(parsed, !options.replace);
|
|
328
|
+
console.log(chalk.green(`\n ✅ Imported ${result.imported} favorites`));
|
|
329
|
+
console.log(chalk.gray(` Total favorites: ${result.total}\n`));
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.log(chalk.red(`\n ❌ Invalid JSON: ${error.message}\n`));
|
|
332
|
+
}
|
|
333
|
+
resolve();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Clear all favorites
|
|
340
|
+
*/
|
|
341
|
+
async function clearFavoritesCommand() {
|
|
342
|
+
const favorites = await loadFavorites();
|
|
343
|
+
|
|
344
|
+
if (favorites.length === 0) {
|
|
345
|
+
console.log(chalk.gray('\n No favorites to clear.\n'));
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const { confirm } = await inquirer.prompt([{
|
|
350
|
+
type: 'confirm',
|
|
351
|
+
name: 'confirm',
|
|
352
|
+
message: `Clear all ${favorites.length} favorites?`,
|
|
353
|
+
default: false
|
|
354
|
+
}]);
|
|
355
|
+
|
|
356
|
+
if (confirm) {
|
|
357
|
+
await clearFavorites();
|
|
358
|
+
console.log(chalk.green('\n ✅ All favorites cleared\n'));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Show favorites statistics
|
|
364
|
+
*/
|
|
365
|
+
async function showFavoritesStats() {
|
|
366
|
+
const stats = await getFavoritesStats();
|
|
367
|
+
|
|
368
|
+
console.log(chalk.cyan(`
|
|
369
|
+
╭────────────────────────────────────────────────────────────────────╮
|
|
370
|
+
│ 📊 FAVORITES STATISTICS │
|
|
371
|
+
╰────────────────────────────────────────────────────────────────────╯
|
|
372
|
+
`));
|
|
373
|
+
|
|
374
|
+
console.log(chalk.white(` Total favorites: ${stats.total}`));
|
|
375
|
+
console.log(chalk.white(` Total usage: ${stats.totalUsage} runs`));
|
|
376
|
+
|
|
377
|
+
if (stats.mostUsed) {
|
|
378
|
+
console.log(chalk.white(` Most used: ${stats.mostUsed}`));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
console.log('');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Show help for favorite command
|
|
386
|
+
*/
|
|
387
|
+
function showFavoriteHelp() {
|
|
388
|
+
console.log(chalk.cyan(`
|
|
389
|
+
⭐ Favorites Commands:
|
|
390
|
+
|
|
391
|
+
${chalk.yellow('vibecode fav')} List all favorites
|
|
392
|
+
${chalk.yellow('vibecode fav list')} List all favorites
|
|
393
|
+
|
|
394
|
+
${chalk.yellow('vibecode fav add "prompt"')} Add a favorite
|
|
395
|
+
${chalk.yellow('vibecode fav add "prompt" -n X')} Add with custom name
|
|
396
|
+
${chalk.yellow('vibecode fav add "prompt" -t T')} Add with template
|
|
397
|
+
|
|
398
|
+
${chalk.yellow('vibecode fav run <n>')} Run favorite by number
|
|
399
|
+
${chalk.yellow('vibecode fav run "name"')} Run favorite by name
|
|
400
|
+
${chalk.yellow('vibecode fav run')} Interactive selection
|
|
401
|
+
|
|
402
|
+
${chalk.yellow('vibecode fav remove <n>')} Remove favorite
|
|
403
|
+
${chalk.yellow('vibecode fav search <query>')} Search favorites
|
|
404
|
+
|
|
405
|
+
${chalk.yellow('vibecode fav export')} Export to JSON
|
|
406
|
+
${chalk.yellow('vibecode fav import')} Import from JSON
|
|
407
|
+
${chalk.yellow('vibecode fav clear')} Clear all favorites
|
|
408
|
+
${chalk.yellow('vibecode fav stats')} Show statistics
|
|
409
|
+
`));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export default favoriteCommand;
|