@nclamvn/vibecode-cli 1.5.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 (77) hide show
  1. package/.vibecode/learning/fixes.json +1 -0
  2. package/.vibecode/learning/preferences.json +1 -0
  3. package/bin/vibecode.js +86 -3
  4. package/docs-site/README.md +41 -0
  5. package/docs-site/blog/2019-05-28-first-blog-post.md +12 -0
  6. package/docs-site/blog/2019-05-29-long-blog-post.md +44 -0
  7. package/docs-site/blog/2021-08-01-mdx-blog-post.mdx +24 -0
  8. package/docs-site/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  9. package/docs-site/blog/2021-08-26-welcome/index.md +29 -0
  10. package/docs-site/blog/authors.yml +25 -0
  11. package/docs-site/blog/tags.yml +19 -0
  12. package/docs-site/docs/commands/agent.md +162 -0
  13. package/docs-site/docs/commands/assist.md +71 -0
  14. package/docs-site/docs/commands/build.md +53 -0
  15. package/docs-site/docs/commands/config.md +30 -0
  16. package/docs-site/docs/commands/debug.md +173 -0
  17. package/docs-site/docs/commands/doctor.md +34 -0
  18. package/docs-site/docs/commands/go.md +128 -0
  19. package/docs-site/docs/commands/index.md +79 -0
  20. package/docs-site/docs/commands/init.md +42 -0
  21. package/docs-site/docs/commands/learn.md +82 -0
  22. package/docs-site/docs/commands/lock.md +33 -0
  23. package/docs-site/docs/commands/plan.md +29 -0
  24. package/docs-site/docs/commands/review.md +31 -0
  25. package/docs-site/docs/commands/snapshot.md +34 -0
  26. package/docs-site/docs/commands/start.md +32 -0
  27. package/docs-site/docs/commands/status.md +37 -0
  28. package/docs-site/docs/commands/undo.md +83 -0
  29. package/docs-site/docs/configuration.md +72 -0
  30. package/docs-site/docs/faq.md +83 -0
  31. package/docs-site/docs/getting-started.md +119 -0
  32. package/docs-site/docs/guides/agent-mode.md +94 -0
  33. package/docs-site/docs/guides/debug-mode.md +83 -0
  34. package/docs-site/docs/guides/magic-mode.md +107 -0
  35. package/docs-site/docs/installation.md +98 -0
  36. package/docs-site/docs/intro.md +67 -0
  37. package/docs-site/docusaurus.config.ts +141 -0
  38. package/docs-site/package-lock.json +18039 -0
  39. package/docs-site/package.json +48 -0
  40. package/docs-site/sidebars.ts +70 -0
  41. package/docs-site/src/components/HomepageFeatures/index.tsx +72 -0
  42. package/docs-site/src/components/HomepageFeatures/styles.module.css +16 -0
  43. package/docs-site/src/css/custom.css +30 -0
  44. package/docs-site/src/pages/index.module.css +23 -0
  45. package/docs-site/src/pages/index.tsx +44 -0
  46. package/docs-site/src/pages/markdown-page.md +7 -0
  47. package/docs-site/src/theme/Footer/index.tsx +127 -0
  48. package/docs-site/src/theme/Footer/styles.module.css +285 -0
  49. package/docs-site/static/.nojekyll +0 -0
  50. package/docs-site/static/img/docusaurus-social-card.jpg +0 -0
  51. package/docs-site/static/img/docusaurus.png +0 -0
  52. package/docs-site/static/img/favicon.ico +0 -0
  53. package/docs-site/static/img/logo.svg +1 -0
  54. package/docs-site/static/img/undraw_docusaurus_mountain.svg +171 -0
  55. package/docs-site/static/img/undraw_docusaurus_react.svg +170 -0
  56. package/docs-site/static/img/undraw_docusaurus_tree.svg +40 -0
  57. package/docs-site/tsconfig.json +8 -0
  58. package/package.json +5 -2
  59. package/src/agent/orchestrator.js +104 -35
  60. package/src/commands/build.js +13 -3
  61. package/src/commands/debug.js +109 -1
  62. package/src/commands/git.js +923 -0
  63. package/src/commands/go.js +9 -2
  64. package/src/commands/learn.js +294 -0
  65. package/src/commands/shell.js +486 -0
  66. package/src/commands/undo.js +281 -0
  67. package/src/commands/watch.js +556 -0
  68. package/src/commands/wizard.js +322 -0
  69. package/src/core/backup.js +325 -0
  70. package/src/core/learning.js +295 -0
  71. package/src/debug/image-analyzer.js +304 -0
  72. package/src/debug/index.js +30 -1
  73. package/src/index.js +50 -0
  74. package/src/ui/__tests__/error-translator.test.js +390 -0
  75. package/src/ui/dashboard.js +364 -0
  76. package/src/ui/error-translator.js +775 -0
  77. package/src/utils/image.js +222 -0
@@ -0,0 +1,281 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // VIBECODE CLI - Undo Command
3
+ // Phase H4: Revert last action with backup restore
4
+ // ═══════════════════════════════════════════════════════════════════════════════
5
+
6
+ import chalk from 'chalk';
7
+ import inquirer from 'inquirer';
8
+ import { BackupManager } from '../core/backup.js';
9
+
10
+ /**
11
+ * Undo Command - Revert to previous state
12
+ *
13
+ * Usage:
14
+ * vibecode undo - Interactive restore menu
15
+ * vibecode undo --list - List available backups
16
+ * vibecode undo --step 2 - Restore to 2 steps ago
17
+ * vibecode undo --clear - Clear all backups
18
+ */
19
+ export async function undoCommand(options = {}) {
20
+ const backup = new BackupManager();
21
+
22
+ // Clear all backups
23
+ if (options.clear) {
24
+ await clearBackups(backup, options);
25
+ return;
26
+ }
27
+
28
+ // List backups
29
+ if (options.list) {
30
+ await listBackups(backup);
31
+ return;
32
+ }
33
+
34
+ // Restore specific step
35
+ if (options.step) {
36
+ await restoreStep(backup, parseInt(options.step), options.force);
37
+ return;
38
+ }
39
+
40
+ // Interactive undo
41
+ await interactiveUndo(backup);
42
+ }
43
+
44
+ /**
45
+ * List all available backups
46
+ */
47
+ async function listBackups(backup) {
48
+ const backups = await backup.listBackups();
49
+
50
+ if (backups.length === 0) {
51
+ console.log(chalk.yellow('\n📭 Chưa có backup nào.\n'));
52
+ console.log(chalk.gray('Backup sẽ được tạo tự động khi chạy:'));
53
+ console.log(chalk.gray(' • vibecode build --auto'));
54
+ console.log(chalk.gray(' • vibecode agent'));
55
+ console.log(chalk.gray(' • vibecode go'));
56
+ console.log();
57
+ return;
58
+ }
59
+
60
+ console.log(chalk.cyan(`
61
+ ╭────────────────────────────────────────────────────────────────────╮
62
+ │ 📦 BACKUP HISTORY │
63
+ ╰────────────────────────────────────────────────────────────────────╯
64
+ `));
65
+
66
+ backups.forEach((b, index) => {
67
+ const date = new Date(b.timestamp);
68
+ const timeAgo = getTimeAgo(date);
69
+ const filesCount = b.files?.length || 0;
70
+
71
+ console.log(chalk.white(` ${(index + 1).toString().padStart(2)}. ${chalk.bold(b.action)}`));
72
+ console.log(chalk.gray(` ${timeAgo} · ${filesCount} files`));
73
+ console.log('');
74
+ });
75
+
76
+ console.log(chalk.gray(` Chạy ${chalk.cyan('vibecode undo')} để restore`));
77
+ console.log(chalk.gray(` Hoặc ${chalk.cyan('vibecode undo --step N')} để restore step cụ thể\n`));
78
+ }
79
+
80
+ /**
81
+ * Restore to specific step
82
+ */
83
+ async function restoreStep(backup, step, force = false) {
84
+ const backups = await backup.listBackups();
85
+
86
+ if (backups.length === 0) {
87
+ console.log(chalk.yellow('\n📭 Chưa có backup nào để restore.\n'));
88
+ return;
89
+ }
90
+
91
+ if (step < 1 || step > backups.length) {
92
+ console.log(chalk.red(`\n❌ Step ${step} không tồn tại.`));
93
+ console.log(chalk.gray(` Có ${backups.length} backups (1-${backups.length}).\n`));
94
+ return;
95
+ }
96
+
97
+ const targetBackup = backups[step - 1];
98
+
99
+ console.log(chalk.yellow(`\n⚠️ Sắp restore về: ${chalk.bold(targetBackup.action)}`));
100
+ console.log(chalk.gray(` Thời gian: ${new Date(targetBackup.timestamp).toLocaleString('vi-VN')}`));
101
+ console.log(chalk.gray(` Files: ${targetBackup.files?.length || 0}\n`));
102
+
103
+ if (!force) {
104
+ const { confirm } = await inquirer.prompt([
105
+ {
106
+ type: 'confirm',
107
+ name: 'confirm',
108
+ message: 'Xác nhận restore?',
109
+ default: false
110
+ }
111
+ ]);
112
+
113
+ if (!confirm) {
114
+ console.log(chalk.gray('\n👋 Đã huỷ.\n'));
115
+ return;
116
+ }
117
+ }
118
+
119
+ const result = await backup.restore(targetBackup.id);
120
+ showRestoreResult(result);
121
+ }
122
+
123
+ /**
124
+ * Interactive undo menu
125
+ */
126
+ async function interactiveUndo(backup) {
127
+ const backups = await backup.listBackups();
128
+
129
+ if (backups.length === 0) {
130
+ console.log(chalk.yellow('\n📭 Chưa có backup nào để undo.\n'));
131
+ console.log(chalk.gray('Backup sẽ được tạo tự động khi chạy các lệnh build.'));
132
+ console.log();
133
+ return;
134
+ }
135
+
136
+ console.log(chalk.cyan(`
137
+ ╭────────────────────────────────────────────────────────────────────╮
138
+ │ ⏪ VIBECODE UNDO │
139
+ │ │
140
+ │ Chọn backup để restore files về trạng thái trước đó. │
141
+ │ │
142
+ ╰────────────────────────────────────────────────────────────────────╯
143
+ `));
144
+
145
+ const choices = backups.map((b, index) => {
146
+ const timeAgo = getTimeAgo(new Date(b.timestamp));
147
+ const filesCount = b.files?.length || 0;
148
+ return {
149
+ name: `${b.action} (${timeAgo}, ${filesCount} files)`,
150
+ value: b.id,
151
+ short: b.action
152
+ };
153
+ });
154
+
155
+ choices.push(new inquirer.Separator());
156
+ choices.push({ name: '❌ Huỷ', value: 'cancel' });
157
+
158
+ const { backupId } = await inquirer.prompt([
159
+ {
160
+ type: 'list',
161
+ name: 'backupId',
162
+ message: 'Chọn backup để restore:',
163
+ choices,
164
+ pageSize: 10
165
+ }
166
+ ]);
167
+
168
+ if (backupId === 'cancel') {
169
+ console.log(chalk.gray('\n👋 Đã huỷ.\n'));
170
+ return;
171
+ }
172
+
173
+ const targetBackup = backups.find(b => b.id === backupId);
174
+
175
+ // Show files that will be restored
176
+ if (targetBackup.files && targetBackup.files.length > 0) {
177
+ console.log(chalk.gray('\n Files sẽ được restore:'));
178
+ const displayFiles = targetBackup.files.slice(0, 5);
179
+ for (const f of displayFiles) {
180
+ console.log(chalk.gray(` • ${f.path}`));
181
+ }
182
+ if (targetBackup.files.length > 5) {
183
+ console.log(chalk.gray(` ... và ${targetBackup.files.length - 5} files khác`));
184
+ }
185
+ console.log();
186
+ }
187
+
188
+ const { confirm } = await inquirer.prompt([
189
+ {
190
+ type: 'confirm',
191
+ name: 'confirm',
192
+ message: `Restore về "${targetBackup.action}"?`,
193
+ default: false
194
+ }
195
+ ]);
196
+
197
+ if (!confirm) {
198
+ console.log(chalk.gray('\n👋 Đã huỷ.\n'));
199
+ return;
200
+ }
201
+
202
+ const result = await backup.restore(backupId);
203
+ showRestoreResult(result);
204
+ }
205
+
206
+ /**
207
+ * Clear all backups
208
+ */
209
+ async function clearBackups(backup, options) {
210
+ const backups = await backup.listBackups();
211
+
212
+ if (backups.length === 0) {
213
+ console.log(chalk.yellow('\n📭 Không có backup nào để xoá.\n'));
214
+ return;
215
+ }
216
+
217
+ if (!options.force) {
218
+ console.log(chalk.yellow(`\n⚠️ Sắp xoá ${backups.length} backups.\n`));
219
+
220
+ const { confirm } = await inquirer.prompt([
221
+ {
222
+ type: 'confirm',
223
+ name: 'confirm',
224
+ message: 'Xác nhận xoá tất cả backups?',
225
+ default: false
226
+ }
227
+ ]);
228
+
229
+ if (!confirm) {
230
+ console.log(chalk.gray('\n👋 Đã huỷ.\n'));
231
+ return;
232
+ }
233
+ }
234
+
235
+ await backup.clearAllBackups();
236
+ console.log(chalk.green(`\n✅ Đã xoá ${backups.length} backups.\n`));
237
+ }
238
+
239
+ /**
240
+ * Show restore result
241
+ */
242
+ function showRestoreResult(result) {
243
+ if (result.success) {
244
+ console.log(chalk.green(`
245
+ ╭────────────────────────────────────────────────────────────────────╮
246
+ │ ✅ RESTORE THÀNH CÔNG │
247
+ │ │
248
+ │ Action: ${result.action.substring(0, 54).padEnd(54)}│
249
+ │ Files restored: ${String(result.filesRestored).padEnd(46)}│
250
+ │ │
251
+ ╰────────────────────────────────────────────────────────────────────╯
252
+ `));
253
+
254
+ // Show some restored files
255
+ if (result.files && result.files.length > 0) {
256
+ console.log(chalk.gray(' Files đã restore:'));
257
+ for (const f of result.files.slice(0, 5)) {
258
+ console.log(chalk.gray(` ✓ ${f}`));
259
+ }
260
+ if (result.files.length > 5) {
261
+ console.log(chalk.gray(` ... và ${result.files.length - 5} files khác`));
262
+ }
263
+ console.log();
264
+ }
265
+ } else {
266
+ console.log(chalk.red(`\n❌ Restore thất bại: ${result.error}\n`));
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Get human-readable time ago string
272
+ */
273
+ function getTimeAgo(date) {
274
+ const seconds = Math.floor((new Date() - date) / 1000);
275
+
276
+ if (seconds < 60) return 'vừa xong';
277
+ if (seconds < 3600) return `${Math.floor(seconds / 60)} phút trước`;
278
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)} giờ trước`;
279
+ if (seconds < 604800) return `${Math.floor(seconds / 86400)} ngày trước`;
280
+ return `${Math.floor(seconds / 604800)} tuần trước`;
281
+ }