vibecodingmachine-cli 2026.2.20-438 → 2026.2.26-1739

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 (101) hide show
  1. package/bin/auth/auth-compliance.js +126 -0
  2. package/bin/cli-program.js +104 -0
  3. package/bin/cli-setup.js +52 -0
  4. package/bin/commands/agent-commands.js +310 -0
  5. package/bin/commands/auto-commands.js +70 -0
  6. package/bin/commands/command-aliases.js +118 -0
  7. package/bin/commands/repo-commands.js +39 -0
  8. package/bin/commands/rui-commands.js +152 -0
  9. package/bin/config/cli-config.js +394 -0
  10. package/bin/init/environment-setup.js +84 -0
  11. package/bin/update/update-checker.js +126 -0
  12. package/bin/vibecodingmachine-new.js +50 -0
  13. package/bin/vibecodingmachine.js +29 -663
  14. package/package.json +8 -2
  15. package/src/commands/agents/add.js +277 -0
  16. package/src/commands/agents/check.js +380 -0
  17. package/src/commands/agents/list.js +471 -0
  18. package/src/commands/agents/remove.js +351 -0
  19. package/src/commands/analyze-file-sizes.js +428 -0
  20. package/src/commands/auto-direct/code-processor.js +282 -0
  21. package/src/commands/auto-direct/file-scanner.js +266 -0
  22. package/src/commands/auto-direct/provider-config.js +178 -0
  23. package/src/commands/auto-direct/provider-manager.js +219 -0
  24. package/src/commands/auto-direct/requirement-manager.js +172 -0
  25. package/src/commands/auto-direct/status-display.js +91 -0
  26. package/src/commands/auto-direct/utils.js +106 -0
  27. package/src/commands/auto-direct.js +875 -488
  28. package/src/commands/auto-execution.js +342 -0
  29. package/src/commands/auto-provider-management.js +102 -0
  30. package/src/commands/auto-requirement-management.js +161 -0
  31. package/src/commands/auto-status-helpers.js +141 -0
  32. package/src/commands/auto.js +105 -5155
  33. package/src/commands/check-compliance.js +536 -0
  34. package/src/commands/continuous-scan.js +119 -0
  35. package/src/commands/ide.js +16 -4
  36. package/src/commands/refactor-file.js +486 -0
  37. package/src/commands/requirements.js +301 -2
  38. package/src/commands/timeout.js +290 -0
  39. package/src/trui/TruiInterface.js +108 -0
  40. package/src/trui/agents/AgentInterface.js +580 -0
  41. package/src/utils/antigravity-installer.js +60 -6
  42. package/src/utils/clarification-actions.js +290 -0
  43. package/src/utils/config.js +123 -2
  44. package/src/utils/first-run.js +5 -5
  45. package/src/utils/ide-handlers.js +212 -0
  46. package/src/utils/interactive/clarification-actions.js +348 -0
  47. package/src/utils/interactive/core-ui.js +265 -0
  48. package/src/utils/interactive/file-backup.js +237 -0
  49. package/src/utils/interactive/file-import-export.js +305 -0
  50. package/src/utils/interactive/file-operations.js +49 -0
  51. package/src/utils/interactive/file-validation.js +276 -0
  52. package/src/utils/interactive/interactive-prompts.js +480 -0
  53. package/src/utils/interactive/requirement-actions.js +127 -0
  54. package/src/utils/interactive/requirement-crud.js +356 -0
  55. package/src/utils/interactive/requirements-navigation.js +286 -0
  56. package/src/utils/interactive.js +390 -3459
  57. package/src/utils/provider-checker/agent-checker.js +250 -0
  58. package/src/utils/provider-checker/agent-runner.js +450 -0
  59. package/src/utils/provider-checker/cli-installer.js +123 -0
  60. package/src/utils/provider-checker/cli-utils.js +15 -0
  61. package/src/utils/provider-checker/format-utils.js +32 -0
  62. package/src/utils/provider-checker/ide-manager.js +72 -0
  63. package/src/utils/provider-checker/ide-utils.js +71 -0
  64. package/src/utils/provider-checker/node-detector.js +56 -0
  65. package/src/utils/provider-checker/node-utils.js +61 -0
  66. package/src/utils/provider-checker/process-spawn.js +22 -0
  67. package/src/utils/provider-checker/process-utils.js +37 -0
  68. package/src/utils/provider-checker/provider-validator.js +160 -0
  69. package/src/utils/provider-checker/quota-checker.js +54 -0
  70. package/src/utils/provider-checker/quota-detector.js +44 -0
  71. package/src/utils/provider-checker/requirements-manager.js +94 -0
  72. package/src/utils/provider-checker/test-requirements.js +95 -0
  73. package/src/utils/provider-checker/time-formatter.js +18 -0
  74. package/src/utils/provider-checker-new.js +14 -0
  75. package/src/utils/provider-checker.js +12 -407
  76. package/src/utils/provider-checkers/ide-manager.js +128 -0
  77. package/src/utils/provider-checkers/node-executable-finder.js +51 -0
  78. package/src/utils/provider-checkers/provider-checker-core.js +172 -0
  79. package/src/utils/provider-checkers/provider-checker-main.js +107 -0
  80. package/src/utils/provider-manager.js +60 -4
  81. package/src/utils/provider-registry.js +26 -3
  82. package/src/utils/provider-utils.js +173 -0
  83. package/src/utils/quota-detectors.js +212 -0
  84. package/src/utils/requirement-action-handlers.js +288 -0
  85. package/src/utils/requirement-actions/clarification-actions.js +229 -0
  86. package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
  87. package/src/utils/requirement-actions/file-operations.js +92 -0
  88. package/src/utils/requirement-actions/helpers.js +40 -0
  89. package/src/utils/requirement-actions/requirement-operations.js +335 -0
  90. package/src/utils/requirement-actions.js +46 -856
  91. package/src/utils/requirement-file-operations.js +259 -0
  92. package/src/utils/requirement-helpers.js +128 -0
  93. package/src/utils/requirement-management.js +279 -0
  94. package/src/utils/requirement-navigation.js +146 -0
  95. package/src/utils/requirement-organization.js +271 -0
  96. package/src/utils/simple-trui.js +75 -1
  97. package/src/utils/trui-navigation.js +28 -2
  98. package/src/utils/trui-req-tree.js +196 -11
  99. package/src/utils/trui-specifications.js +31 -1
  100. package/src/utils/interactive-backup.js +0 -5664
  101. package/src/utils/trui-provider-manager.js +0 -182
@@ -1,863 +1,52 @@
1
- const chalk = require('chalk');
2
- const inquirer = require('inquirer');
3
- const fs = require('fs-extra');
4
- const readline = require('readline');
5
- const { t, getRequirementsPath } = require('vibecodingmachine-core');
6
- const { handleFeedbackSubmission } = require('./feedback-handler');
7
-
8
- /**
9
- * Helper to show goodbye message
10
- */
11
- function showGoodbyeMessage() {
12
- const hour = new Date().getHours();
13
- const message = hour < 21
14
- ? '\n👋 ' + t('interactive.goodbye') + '\n'
15
- : '\n👋 Goodbye! Go get some sleep!\n';
16
- console.log(chalk.cyan(message));
17
- }
18
-
19
- /**
20
- * Helper to get section title from section key
21
- */
22
- function getSectionTitle(sectionKey) {
23
- if (sectionKey === 'todo') return '⏳ Requirements not yet completed';
24
- if (sectionKey === 'verify') return '✅ Verified by AI screenshot';
25
- if (sectionKey === 'recycled') return '♻️ Recycled';
26
- return '';
27
- }
28
-
29
- /**
30
- * Helper to get requirement list from tree by section key
31
- */
32
- function getRequirementList(tree, sectionKey) {
33
- if (sectionKey === 'todo') return tree.todoReqs;
34
- if (sectionKey === 'verify') return tree.verifyReqs;
35
- if (sectionKey === 'clarification') return tree.clarificationReqs;
36
- if (sectionKey === 'recycled') return tree.recycledReqs;
37
- return [];
38
- }
39
-
40
- /**
41
- * Helper to show confirmation prompt (r/y for yes, N for no, default N)
42
- */
43
- async function confirmAction(message) {
44
- console.log();
45
- process.stdout.write(chalk.yellow(`${message} `));
46
-
47
- return new Promise((resolve) => {
48
- readline.emitKeypressEvents(process.stdin);
49
- if (process.stdin.isTTY) {
50
- process.stdin.setRawMode(true);
51
- }
52
-
53
- const handler = (str, key) => {
54
- process.stdin.removeListener('keypress', handler);
55
- if (process.stdin.isTTY) {
56
- process.stdin.setRawMode(false);
57
- }
58
-
59
- if (key.ctrl && key.name === 'c') {
60
- process.exit(0);
61
- }
62
-
63
- const confirmed = key.name === 'r' || key.name === 'y';
64
- console.log(confirmed ? chalk.green('Yes') : chalk.gray('No'));
65
- resolve(confirmed);
66
- };
67
-
68
- process.stdin.on('keypress', handler);
69
- process.stdin.resume();
70
- });
71
- }
72
-
73
- /**
74
- * Helper to confirm exit and exit if confirmed (default N)
75
- */
76
- async function confirmAndExit() {
77
- console.log(chalk.gray('\n[DEBUG] confirmAndExit called'));
78
- console.log();
79
- process.stdout.write(chalk.yellow(`${t('interactive.confirm.exit')} `));
80
-
81
- const confirmed = await new Promise((resolve) => {
82
- readline.emitKeypressEvents(process.stdin);
83
- if (process.stdin.isTTY) {
84
- process.stdin.setRawMode(true);
85
- }
86
-
87
- const handler = (str, key) => {
88
- process.stdin.removeListener('keypress', handler);
89
- if (process.stdin.isTTY) {
90
- process.stdin.setRawMode(false);
91
- }
92
-
93
- if (key.ctrl && key.name === 'c') {
94
- process.exit(0);
95
- }
96
-
97
- const confirmed = key.name === 'r' || key.name === 'y';
98
- console.log(confirmed ? chalk.green('Yes') : chalk.gray('No'));
99
- resolve(confirmed);
100
- };
101
-
102
- process.stdin.on('keypress', handler);
103
- process.stdin.resume();
104
- });
105
-
106
- if (confirmed) {
107
- showGoodbyeMessage();
108
- process.exit(0);
109
- }
110
- }
111
-
112
- /**
113
- * Helper to edit clarification responses
114
- */
115
- async function editClarificationResponses(req, tree) {
116
- const reqPath = await getRequirementsPath();
117
-
118
- const content = await fs.readFile(reqPath, 'utf8');
119
- const lines = content.split('\n');
120
-
121
- // Find the requirement in the file
122
- let startIdx = -1;
123
- let endIdx = -1;
124
-
125
- for (let i = 0; i < lines.length; i++) {
126
- if (lines[i].includes(`### ${req.title}`)) {
127
- startIdx = i;
128
- // Find the end of this requirement (next ### or ##)
129
- for (let j = i + 1; j < lines.length; j++) {
130
- if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
131
- endIdx = j;
132
- break;
133
- }
134
- }
135
- if (endIdx === -1) endIdx = lines.length;
136
- break;
137
- }
138
- }
139
-
140
- if (startIdx === -1) {
141
- console.log(chalk.red('Requirement not found in file'));
142
- return;
143
- }
144
-
145
- console.log(chalk.bold.cyan(`\n✍️ Editing responses for: ${req.title}\n`));
146
-
147
- // Edit each question
148
- const updatedQuestions = [];
149
- for (const question of req.questions) {
150
- console.log(chalk.gray(`Q: ${question.question.replace(/^\d+\.\s*/, '')}`));
151
-
152
- const { response } = await inquirer.prompt([{
153
- type: 'input',
154
- name: 'response',
155
- message: 'Response:',
156
- default: question.response || ''
157
- }]);
158
-
159
- updatedQuestions.push({
160
- question: question.question,
161
- response: response.trim()
162
- });
163
- }
164
-
165
- // Update the file
166
- let newLines = [...lines];
167
- let lineIdx = startIdx + 1;
168
-
169
- // Skip existing lines until we find questions section
170
- while (lineIdx < endIdx && !lines[lineIdx].includes('**Clarifying questions:**')) {
171
- lineIdx++;
172
- }
173
-
174
- if (lineIdx < endIdx && lines[lineIdx].includes('**Clarifying questions:**')) {
175
- lineIdx++; // Skip the questions header
176
- }
177
-
178
- // Remove old question responses
179
- while (lineIdx < endIdx && (lines[lineIdx].match(/^\d+\./) || lines[lineIdx].trim() === '')) {
180
- newLines.splice(lineIdx, 1);
181
- endIdx--;
182
- }
183
-
184
- // Add updated questions
185
- for (const q of updatedQuestions) {
186
- if (q.response && q.response.trim()) {
187
- newLines.splice(lineIdx, 0, q.question);
188
- newLines.splice(lineIdx + 1, 0, q.response);
189
- lineIdx += 2;
190
- endIdx += 2;
191
- }
192
- }
193
-
194
- await fs.writeFile(reqPath, newLines.join('\n'));
195
- console.log(chalk.green('\n✓ Responses saved!'));
196
- await new Promise(resolve => setTimeout(resolve, 1000));
197
- }
198
-
199
- /**
200
- * Helper to move clarification requirement back to TODO
201
- */
202
- async function moveClarificationToTodo(req, tree) {
203
- const reqPath = await getRequirementsPath();
204
-
205
- const content = await fs.readFile(reqPath, 'utf8');
206
- const lines = content.split('\n');
207
-
208
- // Find and remove the clarification requirement
209
- let startIdx = -1;
210
- let endIdx = -1;
211
-
212
- for (let i = 0; i < lines.length; i++) {
213
- if (lines[i].includes(`### ${req.title}`)) {
214
- startIdx = i;
215
- // Find the end of this requirement
216
- for (let j = i + 1; j < lines.length; j++) {
217
- if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
218
- endIdx = j;
219
- break;
220
- }
221
- }
222
- if (endIdx === -1) endIdx = lines.length;
223
- break;
224
- }
225
- }
226
-
227
- if (startIdx === -1) return;
228
-
229
- // Extract the requirement content
230
- const reqContent = lines.slice(startIdx, endIdx);
231
-
232
- // Remove from clarification section
233
- lines.splice(startIdx, endIdx - startIdx);
234
-
235
- // Find TODO section and add there
236
- let todoIdx = -1;
237
- for (let i = 0; i < lines.length; i++) {
238
- if (lines[i].includes('⏳ Requirements not yet completed')) {
239
- todoIdx = i;
240
- break;
241
- }
242
- }
243
-
244
- if (todoIdx !== -1) {
245
- // Insert after the TODO header
246
- let insertIdx = todoIdx + 1;
247
- while (insertIdx < lines.length && lines[insertIdx].trim() === '') {
248
- insertIdx++;
249
- }
250
-
251
- lines.splice(insertIdx, 0, ...reqContent);
252
- }
253
-
254
- await fs.writeFile(reqPath, lines.join('\n'));
255
- console.log(chalk.green('\n✓ Moved to TODO!'));
256
- await new Promise(resolve => setTimeout(resolve, 1000));
257
- }
258
-
259
- /**
260
- * Helper to move clarification requirement to recycled (used to delete)
261
- */
262
- async function deleteClarification(req, tree) {
263
- const reqPath = await getRequirementsPath();
264
-
265
- const confirmed = await confirmAction(`Delete "${req.title}"? This cannot be undone. (r/y/N)`);
266
- if (!confirmed) {
267
- console.log(chalk.gray('Cancelled.'));
268
- return;
269
- }
270
-
271
- const content = await fs.readFile(reqPath, 'utf8');
272
- const lines = content.split('\n');
273
-
274
- // Find and remove the clarification requirement
275
- let startIdx = -1;
276
- let endIdx = -1;
277
-
278
- for (let i = 0; i < lines.length; i++) {
279
- if (lines[i].includes(`### ${req.title}`)) {
280
- startIdx = i;
281
- // Find the end of this requirement
282
- for (let j = i + 1; j < lines.length; j++) {
283
- if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
284
- endIdx = j;
285
- break;
286
- }
287
- }
288
- if (endIdx === -1) endIdx = lines.length;
289
- break;
290
- }
291
- }
292
-
293
- if (startIdx !== -1) {
294
- lines.splice(startIdx, endIdx - startIdx);
295
- await fs.writeFile(reqPath, lines.join('\n'));
296
- }
297
- }
298
-
299
- /**
300
- * Helper to show actions for a requirement
301
- */
302
- async function showClarificationActions(req, tree, loadClarification) {
303
- const actions = [
304
- { label: '✍️ Add/Edit Responses', value: 'edit-responses' },
305
- { label: '↩️ Move back to TODO (after clarification)', value: 'move-to-todo' },
306
- { label: '🗑️ Delete', value: 'delete' },
307
- { label: '↩️ Back', value: 'back' }
308
- ];
309
-
310
- console.log(chalk.bold.cyan(`\n❓ ${req.title}\n`));
311
-
312
- // Show questions and responses
313
- if (req.questions && req.questions.length > 0) {
314
- console.log(chalk.gray('Questions:'));
315
- req.questions.forEach((q, idx) => {
316
- console.log(chalk.gray(` ${idx + 1}. ${q.question.replace(/^\d+\.\s*/, '')}`));
317
- if (q.response) {
318
- console.log(chalk.green(` → ${q.response}`));
319
- } else {
320
- console.log(chalk.yellow(' → (no response)'));
321
- }
322
- });
323
- console.log();
324
- }
325
-
326
- if (req.details && req.details.length > 0) {
327
- console.log(chalk.gray('Details:'));
328
- req.details.forEach(detail => {
329
- console.log(chalk.gray(` ${detail}`));
330
- });
331
- console.log();
332
- }
333
-
334
- try {
335
- const { action } = await inquirer.prompt([{
336
- type: 'list',
337
- name: 'action',
338
- message: 'What would you like to do?',
339
- choices: actions
340
- }]);
341
-
342
- switch (action) {
343
- case 'edit-responses':
344
- await editClarificationResponses(req, tree);
345
- break;
346
- case 'move-to-todo':
347
- await moveClarificationToTodo(req, tree);
348
- break;
349
- case 'delete':
350
- await deleteClarification(req, tree);
351
- break;
352
- case 'back':
353
- return;
354
- }
355
- } catch (error) {
356
- // User cancelled
357
- return;
358
- }
359
- }
360
-
361
- /**
362
- * Show requirement actions menu
363
- */
364
- async function showRequirementActions(req, sectionKey, tree) {
365
- const actions = [
366
- { label: '✏️ Rename/Edit', value: 'rename' },
367
- { label: '👍 Thumbs up (promote to Verified)', value: 'thumbs-up' },
368
- { label: '👎 Thumbs down (demote to TODO)', value: 'thumbs-down' },
369
- { label: '🗑️ Delete', value: 'delete' },
370
- { label: '↩️ Back', value: 'back' }
371
- ];
372
-
373
- console.log(chalk.bold.cyan(`\n${req.title}\n`));
374
-
375
- if (req.details && req.details.length > 0) {
376
- console.log(chalk.gray('Details:'));
377
- req.details.forEach(detail => {
378
- console.log(chalk.gray(` ${detail}`));
379
- });
380
- console.log();
381
- }
382
-
383
- try {
384
- const { action } = await inquirer.prompt([{
385
- type: 'list',
386
- name: 'action',
387
- message: 'What would you like to do?',
388
- choices: actions
389
- }]);
390
-
391
- if (action === 'back') return;
392
-
393
- await performRequirementAction(action, req, sectionKey, tree);
394
- } catch (error) {
395
- // User cancelled
396
- return;
397
- }
398
- }
399
-
400
- /**
401
- * Helper to perform action on requirement
402
- */
403
- async function performRequirementAction(action, req, sectionKey, tree) {
404
- const reqList = getRequirementList(tree, sectionKey);
405
- const sectionTitle = getSectionTitle(sectionKey);
406
- const reqIndex = reqList.findIndex(r => r.title === req.title);
407
-
408
- if (reqIndex === -1) {
409
- console.log(chalk.red('Requirement not found'));
410
- return;
411
- }
412
-
413
- switch (action) {
414
- case 'rename':
415
- await renameRequirement(req, sectionKey, tree);
416
- break;
417
- case 'thumbs-up':
418
- await promoteRequirement(req, sectionKey, tree);
419
- break;
420
- case 'thumbs-down':
421
- await demoteRequirement(req.title, sectionKey, tree);
422
- break;
423
- case 'delete':
424
- await deleteRequirement(req, sectionKey, tree);
425
- break;
426
- }
427
-
428
- await new Promise(resolve => setTimeout(resolve, 1000));
429
- }
430
-
431
1
  /**
432
- * Helper to rename requirement (title and description)
2
+ * Requirement Actions - Main Module
3
+ *
4
+ * Main orchestrator for requirement action functionality.
5
+ * This file imports and coordinates the modular action components.
433
6
  */
434
- async function renameRequirement(req, sectionKey, tree) {
435
- const reqPath = await getRequirementsPath();
436
-
437
- console.log(chalk.cyan('\n✏️ Rename/Edit Requirement\n'));
438
- console.log(chalk.gray('Current title:'), chalk.white(req.title));
439
- if (req.details.length > 0) {
440
- console.log(chalk.gray('Current description:'));
441
- req.details.forEach(line => console.log(chalk.white(' ' + line)));
442
- }
443
- console.log();
444
-
445
- const answers = await inquirer.prompt([
446
- {
447
- type: 'input',
448
- name: 'title',
449
- message: 'New title (leave blank to keep current):',
450
- default: ''
451
- }
452
- ]);
453
-
454
- const newTitle = answers.title.trim() || req.title;
455
-
456
- // Ask for description using multi-line input
457
- console.log(chalk.gray('\nEnter new description (leave blank to keep current).'));
458
- console.log(chalk.gray('Press Enter twice on empty line to finish:\n'));
459
-
460
- const descriptionLines = [];
461
- let emptyLineCount = 0;
462
- let isFirstLine = true;
463
- let newDescription = '';
464
- let keptCurrent = false;
465
-
466
- while (true) {
467
- try {
468
- const { line } = await inquirer.prompt([{
469
- type: 'input',
470
- name: 'line',
471
- message: isFirstLine ? 'Description:' : ''
472
- }]);
473
-
474
- if (isFirstLine && line.trim() === '') {
475
- // If first line is empty, keep current description
476
- keptCurrent = true;
477
- break;
478
- }
479
-
480
- isFirstLine = false;
481
-
482
- if (line.trim() === '') {
483
- emptyLineCount++;
484
- if (emptyLineCount >= 2) break;
485
- } else {
486
- emptyLineCount = 0;
487
- descriptionLines.push(line);
488
- }
489
- } catch (err) {
490
- break;
491
- }
492
- }
493
7
 
494
- if (!keptCurrent) {
495
- newDescription = descriptionLines.join('\n');
496
- }
497
-
498
- // Read the requirements file
499
- const content = await fs.readFile(reqPath, 'utf8');
500
- const lines = content.split('\n');
501
-
502
- // Find the requirement block
503
- let requirementStartIndex = -1;
504
- let requirementEndIndex = -1;
505
-
506
- for (let i = 0; i < lines.length; i++) {
507
- const line = lines[i].trim();
508
- if (line.startsWith('###')) {
509
- const title = line.replace(/^###\s*/, '').trim();
510
- if (title === req.title) {
511
- requirementStartIndex = i;
512
- // Find the end of this requirement (next ### or ## header)
513
- for (let j = i + 1; j < lines.length; j++) {
514
- const nextLine = lines[j].trim();
515
- if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
516
- requirementEndIndex = j;
517
- break;
518
- }
519
- }
520
- if (requirementEndIndex === -1) {
521
- requirementEndIndex = lines.length;
522
- }
523
- break;
524
- }
525
- }
526
- }
527
-
528
- if (requirementStartIndex === -1) {
529
- console.log(chalk.yellow('⚠️ Could not find requirement to rename'));
530
- return;
531
- }
532
-
533
- // Build new requirement block
534
- const newBlock = [`### ${newTitle}`];
535
-
536
- // If new description provided, use it; otherwise keep existing details
537
- if (newDescription) {
538
- newDescription.split('\n').forEach(line => {
539
- if (line.trim()) {
540
- newBlock.push(line);
541
- }
542
- });
543
- } else {
544
- // Keep existing details (skip the ### header line)
545
- for (let i = requirementStartIndex + 1; i < requirementEndIndex; i++) {
546
- const line = lines[i];
547
- // Skip empty lines at the start and PACKAGE lines if we want to preserve them
548
- if (line.trim()) {
549
- newBlock.push(line);
550
- }
551
- }
552
- }
553
-
554
- newBlock.push(''); // Blank line after requirement
555
-
556
- // Replace the old block with the new one
557
- lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex, ...newBlock);
558
-
559
- // Save
560
- await fs.writeFile(reqPath, lines.join('\n'));
561
- console.log(chalk.green('\n✓ Requirement renamed/updated\n'));
562
-
563
- // Update the tree data
564
- const reqList = getRequirementList(tree, sectionKey);
565
- const reqIndex = reqList.findIndex(r => r.title === req.title);
566
- if (reqIndex !== -1) {
567
- reqList[reqIndex].title = newTitle;
568
- if (newDescription) {
569
- reqList[reqIndex].details = newDescription.split('\n').filter(line => line.trim());
570
- }
571
- }
572
- }
573
-
574
- /**
575
- * Helper to move requirement to recycled section (used to delete)
576
- */
577
- async function deleteRequirement(req, sectionKey, tree) {
578
- const reqList = getRequirementList(tree, sectionKey);
579
- const sectionTitle = getSectionTitle(sectionKey);
580
- const reqIndex = reqList.findIndex(r => r.title === req.title);
581
-
582
- if (reqIndex === -1) return;
583
-
584
- const confirmed = await confirmAction(`Move "${req.title}" to recycled? (r/y/N)`);
585
- if (!confirmed) {
586
- console.log(chalk.gray('Cancelled.'));
587
- return;
588
- }
589
-
590
- const reqPath = await getRequirementsPath();
591
- await moveRequirementToRecycled(reqPath, req.title, sectionTitle);
592
- reqList.splice(reqIndex, 1);
593
- }
594
-
595
- /**
596
- * Helper to permanently delete requirement from file (used for recycled items)
597
- */
598
- async function permanentlyDeleteRequirement(req, sectionKey, tree) {
599
- const reqList = getRequirementList(tree, sectionKey);
600
- const reqIndex = reqList.findIndex(r => r.title === req.title);
601
-
602
- if (reqIndex === -1) return;
603
-
604
- const confirmed = await confirmAction(`Permanently delete "${req.title}"? This cannot be undone. (r/y/N)`);
605
- if (!confirmed) {
606
- console.log(chalk.gray('Cancelled.'));
607
- return;
608
- }
609
-
610
- const reqPath = await getRequirementsPath();
611
- const content = await fs.readFile(reqPath, 'utf8');
612
- const lines = content.split('\n');
613
-
614
- // Find and remove the requirement
615
- for (let i = 0; i < lines.length; i++) {
616
- if (lines[i].includes(`### ${req.title}`)) {
617
- // Find the end of this requirement
618
- let endIdx = i + 1;
619
- while (endIdx < lines.length && !lines[endIdx].startsWith('###') && !lines[endIdx].startsWith('##')) {
620
- endIdx++;
621
- }
622
-
623
- lines.splice(i, endIdx - i);
624
- break;
625
- }
626
- }
627
-
628
- await fs.writeFile(reqPath, lines.join('\n'));
629
- reqList.splice(reqIndex, 1);
630
- }
631
-
632
- /**
633
- * Helper to move requirement to recycled section
634
- */
635
- async function moveRequirementToRecycled(reqPath, requirementTitle, fromSection) {
636
- const content = await fs.readFile(reqPath, 'utf8');
637
- const lines = content.split('\n');
638
-
639
- // Find the requirement to move
640
- let startIdx = -1;
641
- let endIdx = -1;
642
-
643
- for (let i = 0; i < lines.length; i++) {
644
- if (lines[i].includes(`### ${requirementTitle}`)) {
645
- startIdx = i;
646
- // Find the end of this requirement
647
- for (let j = i + 1; j < lines.length; j++) {
648
- if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
649
- endIdx = j;
650
- break;
651
- }
652
- }
653
- if (endIdx === -1) endIdx = lines.length;
654
- break;
655
- }
656
- }
657
-
658
- if (startIdx === -1) return;
659
-
660
- // Extract the requirement content
661
- const reqContent = lines.slice(startIdx, endIdx);
662
-
663
- // Remove from original location
664
- lines.splice(startIdx, endIdx - startIdx);
665
-
666
- // Find recycled section
667
- let recycledIdx = -1;
668
- for (let i = 0; i < lines.length; i++) {
669
- if (lines[i].includes('♻️ Recycled')) {
670
- recycledIdx = i;
671
- break;
672
- }
673
- }
674
-
675
- if (recycledIdx === -1) {
676
- // Create recycled section if it doesn't exist
677
- lines.push('## ♻️ Recycled');
678
- lines.push('');
679
- lines.push(...reqContent);
680
- } else {
681
- // Add to existing recycled section
682
- let insertIdx = recycledIdx + 1;
683
- while (insertIdx < lines.length && lines[insertIdx].trim() === '') {
684
- insertIdx++;
685
- }
686
- lines.splice(insertIdx, 0, ...reqContent);
687
- }
688
-
689
- // Save
690
- await fs.writeFile(reqPath, lines.join('\n'));
691
- }
692
-
693
- /**
694
- * Helper to move requirement down with 'j' key
695
- */
696
- async function moveRequirementDown(req, sectionKey, tree) {
697
- const reqList = getRequirementList(tree, sectionKey);
698
- const sectionTitle = getSectionTitle(sectionKey);
699
- const reqIndex = reqList.findIndex(r => r.title === req.title);
700
-
701
- if (reqIndex === -1 || reqIndex === reqList.length - 1) return;
702
-
703
- const reqPath = await getRequirementsPath();
704
-
705
- // Swap in the array
706
- [reqList[reqIndex], reqList[reqIndex + 1]] = [reqList[reqIndex + 1], reqList[reqIndex]];
707
- await saveRequirementsOrder(reqPath, sectionTitle, reqList);
708
- }
709
-
710
- /**
711
- * Helper to move requirement up with 'k' key
712
- */
713
- async function moveRequirementUp(req, sectionKey, tree) {
714
- const reqList = getRequirementList(tree, sectionKey);
715
- const sectionTitle = getSectionTitle(sectionKey);
716
- const reqIndex = reqList.findIndex(r => r.title === req.title);
717
-
718
- if (reqIndex === -1 || reqIndex === 0) return;
719
-
720
- const reqPath = await getRequirementsPath();
721
-
722
- // Swap in the array
723
- [reqList[reqIndex], reqList[reqIndex - 1]] = [reqList[reqIndex - 1], reqList[reqIndex]];
724
- await saveRequirementsOrder(reqPath, sectionTitle, reqList);
725
- }
726
-
727
- /**
728
- * Helper to promote requirement to next list (TODO -> TO VERIFY -> VERIFIED)
729
- */
730
- async function promoteRequirement(req, sectionKey, tree, loadSection, loadVerified) {
731
- const { promoteTodoToVerify, promoteToVerified } = require('vibecodingmachine-core');
732
- const reqPath = await getRequirementsPath();
733
-
734
- try {
735
- if (sectionKey === 'todo') {
736
- await promoteTodoToVerify(req.title);
737
- // Reload sections
738
- tree.todoReqs = await loadSection('todo', '⏳ Requirements not yet completed');
739
- tree.verifyReqs = await loadSection('verify', '✅ Verified by AI screenshot');
740
- } else if (sectionKey === 'verify') {
741
- await promoteToVerified(req.title);
742
- // Reload sections
743
- tree.verifyReqs = await loadSection('verify', '✅ Verified by AI screenshot');
744
- tree.verifiedReqs = await loadVerified();
745
- }
746
- } catch (error) {
747
- console.log(chalk.red('Error promoting requirement:'), error.message);
748
- }
749
- }
750
-
751
- /**
752
- * Helper to demote requirement to previous list (VERIFIED -> TODO, TO VERIFY -> TODO)
753
- */
754
- async function demoteRequirement(reqTitle, sectionKey, tree, loadSection, loadVerified) {
755
- const { demoteVerifyToTodo, demoteFromVerifiedToTodo } = require('vibecodingmachine-core');
756
- const reqPath = await getRequirementsPath();
757
-
758
- try {
759
- if (sectionKey === 'verify') {
760
- await demoteVerifyToTodo(reqTitle);
761
- // Reload sections
762
- tree.todoReqs = await loadSection('todo', '⏳ Requirements not yet completed');
763
- tree.verifyReqs = await loadSection('verify', '✅ Verified by AI screenshot');
764
- } else if (sectionKey === 'verified') {
765
- await demoteFromVerifiedToTodo(reqTitle);
766
- // Reload sections
767
- tree.verifyReqs = await loadSection('verify', '✅ Verified by AI screenshot');
768
- tree.verifiedReqs = await loadVerified();
769
- tree.todoReqs = await loadSection('todo', '⏳ Requirements not yet completed');
770
- }
771
- } catch (error) {
772
- console.log(chalk.red('Error demoting requirement:'), error.message);
773
- }
774
- }
775
-
776
- /**
777
- * Helper to handle adding requirements
778
- */
779
- async function handleAddRequirement(type) {
780
- const reqCommands = require('../commands/requirements');
781
- const packages = ['all', 'cli', 'core', 'electron-app', 'web', 'mobile'];
782
-
783
- if (type === 'add-one') {
784
- const { pkg } = await inquirer.prompt([{
785
- type: 'list',
786
- name: 'pkg',
787
- message: 'Which package?',
788
- choices: packages
789
- }]);
790
-
791
- await reqCommands.add({ package: pkg, interactive: true });
792
- } else if (type === 'add-many') {
793
- const { selectedPackages } = await inquirer.prompt([{
794
- type: 'checkbox',
795
- name: 'selectedPackages',
796
- message: 'Which packages?',
797
- choices: packages
798
- }]);
799
-
800
- if (selectedPackages.length === 0) {
801
- console.log(chalk.yellow('No packages selected.'));
802
- return;
803
- }
804
-
805
- for (const pkg of selectedPackages) {
806
- await reqCommands.add({ package: pkg, interactive: true });
807
- }
808
- }
809
- }
810
-
811
- /**
812
- * Helper to save reordered requirements back to file
813
- */
814
- async function saveRequirementsOrder(reqPath, sectionTitle, requirements) {
815
- const content = await fs.readFile(reqPath, 'utf8');
816
- const lines = content.split('\n');
817
-
818
- // Find the section
819
- let sectionStart = -1;
820
- let sectionEnd = -1;
821
-
822
- for (let i = 0; i < lines.length; i++) {
823
- if (lines[i].includes(sectionTitle)) {
824
- sectionStart = i;
825
- // Find the end of this section
826
- for (let j = i + 1; j < lines.length; j++) {
827
- if (lines[j].startsWith('##')) {
828
- sectionEnd = j;
829
- break;
830
- }
831
- }
832
- if (sectionEnd === -1) sectionEnd = lines.length;
833
- break;
834
- }
835
- }
8
+ const chalk = require('chalk');
9
+ const { handleFeedbackSubmission } = require('./feedback-handler');
836
10
 
837
- if (sectionStart === -1) return;
11
+ // Import modular components
12
+ const {
13
+ showGoodbyeMessage,
14
+ getSectionTitle,
15
+ getRequirementList
16
+ } = require('./requirement-actions/helpers');
838
17
 
839
- // Build new section content
840
- const newSection = [lines[sectionStart]]; // Keep the header
841
- newSection.push(''); // Empty line after header
18
+ const {
19
+ confirmAction,
20
+ confirmAndExit
21
+ } = require('./requirement-actions/confirmation-prompts');
842
22
 
843
- // Add requirements in new order
844
- requirements.forEach(req => {
845
- newSection.push(`### ${req.title}`);
846
- if (req.details && req.details.length > 0) {
847
- req.details.forEach(detail => {
848
- newSection.push(detail);
849
- });
850
- }
851
- newSection.push(''); // Empty line after requirement
852
- });
23
+ const {
24
+ editClarificationResponses,
25
+ moveClarificationToTodo,
26
+ deleteClarification,
27
+ showClarificationActions
28
+ } = require('./requirement-actions/clarification-actions');
853
29
 
854
- // Replace the section
855
- lines.splice(sectionStart, sectionEnd - sectionStart, ...newSection);
30
+ const {
31
+ showRequirementActions,
32
+ performRequirementAction,
33
+ renameRequirement,
34
+ deleteRequirement,
35
+ promoteRequirement,
36
+ demoteRequirement,
37
+ moveRequirementDown,
38
+ moveRequirementUp,
39
+ moveToClarification,
40
+ saveRequirementsOrder,
41
+ permanentlyDeleteRequirement
42
+ } = require('./requirement-actions/requirement-operations');
856
43
 
857
- // Save
858
- await fs.writeFile(reqPath, lines.join('\n'));
859
- }
44
+ const {
45
+ moveRequirementToRecycled,
46
+ handleAddRequirement
47
+ } = require('./requirement-actions/file-operations');
860
48
 
49
+ // Re-export all functions for backward compatibility
861
50
  module.exports = {
862
51
  showGoodbyeMessage,
863
52
  getSectionTitle,
@@ -872,13 +61,14 @@ module.exports = {
872
61
  performRequirementAction,
873
62
  renameRequirement,
874
63
  deleteRequirement,
875
- permanentlyDeleteRequirement,
876
- moveRequirementToRecycled,
877
- moveRequirementDown,
878
- moveRequirementUp,
879
64
  promoteRequirement,
880
65
  demoteRequirement,
881
- handleAddRequirement,
66
+ moveRequirementDown,
67
+ moveRequirementUp,
68
+ moveToClarification,
882
69
  saveRequirementsOrder,
70
+ moveRequirementToRecycled,
71
+ permanentlyDeleteRequirement,
72
+ handleAddRequirement,
883
73
  handleFeedbackSubmission
884
74
  };