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
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Requirement File Operations Module
3
+ *
4
+ * Contains file reading/writing operations for requirement management.
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const { getRequirementsPath } = require('vibecodingmachine-core');
9
+
10
+ /**
11
+ * Helper to edit clarification responses
12
+ */
13
+ async function editClarificationResponses(req, tree) {
14
+ const reqPath = await getRequirementsPath();
15
+
16
+ const content = await fs.readFile(reqPath, 'utf8');
17
+ const lines = content.split('\n');
18
+
19
+ // Find the clarification requirement
20
+ let startIdx = -1;
21
+ let endIdx = -1;
22
+
23
+ for (let i = 0; i < lines.length; i++) {
24
+ if (lines[i].includes(`### ${req.title}`)) {
25
+ startIdx = i;
26
+ // Find the end of this requirement
27
+ for (let j = i + 1; j < lines.length; j++) {
28
+ if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
29
+ endIdx = j;
30
+ break;
31
+ }
32
+ }
33
+ if (endIdx === -1) endIdx = lines.length;
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (startIdx === -1) return;
39
+
40
+ // Extract current responses
41
+ const reqLines = lines.slice(startIdx, endIdx);
42
+ const currentResponses = [];
43
+
44
+ for (const line of reqLines) {
45
+ if (line.startsWith('- **Response:**')) {
46
+ currentResponses.push(line.replace('- **Response:**', '').trim());
47
+ }
48
+ }
49
+
50
+ console.log('\n📝 Current Responses:');
51
+ currentResponses.forEach((response, index) => {
52
+ console.log(`${index + 1}. ${response}`);
53
+ });
54
+
55
+ // Add new responses
56
+ const inquirer = require('inquirer');
57
+ const { confirmAction } = require('./requirement-helpers');
58
+
59
+ let addMore = true;
60
+ while (addMore) {
61
+ const { newResponse } = await inquirer.prompt([
62
+ {
63
+ type: 'input',
64
+ name: 'newResponse',
65
+ message: 'Enter new response (or empty to finish):'
66
+ }
67
+ ]);
68
+
69
+ if (newResponse && newResponse.trim()) {
70
+ currentResponses.push(newResponse.trim());
71
+ console.log('✓ Response added');
72
+ } else {
73
+ addMore = false;
74
+ }
75
+ }
76
+
77
+ // Update the requirement with new responses
78
+ const newReqLines = [];
79
+ let inResponses = false;
80
+
81
+ for (const line of reqLines) {
82
+ if (line.startsWith('- **Response:**')) {
83
+ if (!inResponses) {
84
+ // Add all new responses
85
+ currentResponses.forEach(response => {
86
+ newReqLines.push(`- **Response:** ${response}`);
87
+ });
88
+ inResponses = true;
89
+ }
90
+ } else if (inResponses && line.startsWith('- **')) {
91
+ // Skip old response lines
92
+ continue;
93
+ } else {
94
+ newReqLines.push(line);
95
+ }
96
+ }
97
+
98
+ // Replace the requirement
99
+ lines.splice(startIdx, endIdx - startIdx, ...newReqLines);
100
+ await fs.writeFile(reqPath, lines.join('\n'));
101
+ console.log('\n✓ Responses updated!');
102
+ }
103
+
104
+ /**
105
+ * Helper to move clarification requirement back to TODO
106
+ */
107
+ async function moveClarificationToTodo(req, tree) {
108
+ const reqPath = await getRequirementsPath();
109
+
110
+ const content = await fs.readFile(reqPath, 'utf8');
111
+ const lines = content.split('\n');
112
+
113
+ // Find and remove the clarification requirement
114
+ let startIdx = -1;
115
+ let endIdx = -1;
116
+
117
+ for (let i = 0; i < lines.length; i++) {
118
+ if (lines[i].includes(`### ${req.title}`)) {
119
+ startIdx = i;
120
+ // Find the end of this requirement
121
+ for (let j = i + 1; j < lines.length; j++) {
122
+ if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
123
+ endIdx = j;
124
+ break;
125
+ }
126
+ }
127
+ if (endIdx === -1) endIdx = lines.length;
128
+ break;
129
+ }
130
+ }
131
+
132
+ if (startIdx === -1) return;
133
+
134
+ // Extract the requirement content
135
+ const reqContent = lines.slice(startIdx, endIdx);
136
+
137
+ // Remove from clarification section
138
+ lines.splice(startIdx, endIdx - startIdx);
139
+
140
+ // Find TODO section and add there
141
+ let todoIdx = -1;
142
+ for (let i = 0; i < lines.length; i++) {
143
+ if (lines[i].includes('⏳ Requirements not yet completed')) {
144
+ todoIdx = i;
145
+ break;
146
+ }
147
+ }
148
+
149
+ if (todoIdx !== -1) {
150
+ // Insert after the TODO header
151
+ let insertIdx = todoIdx + 1;
152
+ while (insertIdx < lines.length && lines[insertIdx].trim() === '') {
153
+ insertIdx++;
154
+ }
155
+
156
+ lines.splice(insertIdx, 0, ...reqContent);
157
+ }
158
+
159
+ await fs.writeFile(reqPath, lines.join('\n'));
160
+ console.log('\n✓ Moved to TODO!');
161
+ }
162
+
163
+ /**
164
+ * Helper to move clarification requirement to recycled (used to delete)
165
+ */
166
+ async function deleteClarification(req, tree) {
167
+ const reqPath = await getRequirementsPath();
168
+ const { confirmAction } = require('./requirement-helpers');
169
+
170
+ const confirmed = await confirmAction(`Delete "${req.title}"? This cannot be undone. (r/y/N)`);
171
+ if (!confirmed) {
172
+ console.log('Cancelled.');
173
+ return;
174
+ }
175
+
176
+ const content = await fs.readFile(reqPath, 'utf8');
177
+ const lines = content.split('\n');
178
+
179
+ // Find and remove the clarification requirement
180
+ let startIdx = -1;
181
+ let endIdx = -1;
182
+
183
+ for (let i = 0; i < lines.length; i++) {
184
+ if (lines[i].includes(`### ${req.title}`)) {
185
+ startIdx = i;
186
+ // Find the end of this requirement
187
+ for (let j = i + 1; j < lines.length; j++) {
188
+ if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
189
+ endIdx = j;
190
+ break;
191
+ }
192
+ }
193
+ if (endIdx === -1) endIdx = lines.length;
194
+ break;
195
+ }
196
+ }
197
+
198
+ if (startIdx !== -1) {
199
+ lines.splice(startIdx, endIdx - startIdx);
200
+ await fs.writeFile(reqPath, lines.join('\n'));
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Helper to save reordered requirements back to file
206
+ */
207
+ async function saveRequirementsOrder(reqPath, sectionTitle, requirements) {
208
+ const content = await fs.readFile(reqPath, 'utf8');
209
+ const lines = content.split('\n');
210
+
211
+ // Find the section
212
+ let sectionStart = -1;
213
+ let sectionEnd = -1;
214
+
215
+ for (let i = 0; i < lines.length; i++) {
216
+ if (lines[i].includes(sectionTitle)) {
217
+ sectionStart = i;
218
+ // Find the end of this section
219
+ for (let j = i + 1; j < lines.length; j++) {
220
+ if (lines[j].startsWith('##')) {
221
+ sectionEnd = j;
222
+ break;
223
+ }
224
+ }
225
+ if (sectionEnd === -1) sectionEnd = lines.length;
226
+ break;
227
+ }
228
+ }
229
+
230
+ if (sectionStart === -1) return;
231
+
232
+ // Build new section content
233
+ const newSection = [lines[sectionStart]]; // Keep the header
234
+ newSection.push(''); // Empty line after header
235
+
236
+ // Add requirements in new order
237
+ requirements.forEach(req => {
238
+ newSection.push(`### ${req.title}`);
239
+ if (req.details && req.details.length > 0) {
240
+ req.details.forEach(detail => {
241
+ newSection.push(detail);
242
+ });
243
+ }
244
+ newSection.push(''); // Empty line after requirement
245
+ });
246
+
247
+ // Replace the section
248
+ lines.splice(sectionStart, sectionEnd - sectionStart, ...newSection);
249
+
250
+ // Save
251
+ await fs.writeFile(reqPath, lines.join('\n'));
252
+ }
253
+
254
+ module.exports = {
255
+ editClarificationResponses,
256
+ moveClarificationToTodo,
257
+ deleteClarification,
258
+ saveRequirementsOrder
259
+ };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Requirement Helpers Module
3
+ *
4
+ * Contains helper functions for requirement management.
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const readline = require('readline');
9
+
10
+ /**
11
+ * Helper to show goodbye message
12
+ */
13
+ function showGoodbyeMessage() {
14
+ const hour = new Date().getHours();
15
+ const message = hour < 21
16
+ ? '\n👋 Goodbye! Thanks for using Vibe Coding Machine!\n'
17
+ : '\n👋 Goodbye! Go get some sleep!\n';
18
+ console.log(chalk.cyan(message));
19
+ }
20
+
21
+ /**
22
+ * Helper to get section title from section key
23
+ */
24
+ function getSectionTitle(sectionKey) {
25
+ if (sectionKey === 'todo') return '⏳ Requirements not yet completed';
26
+ if (sectionKey === 'verify') return '✅ Verified by AI screenshot';
27
+ if (sectionKey === 'recycled') return '♻️ Recycled';
28
+ return '';
29
+ }
30
+
31
+ /**
32
+ * Helper to get requirement list from tree by section key
33
+ */
34
+ function getRequirementList(tree, sectionKey) {
35
+ if (sectionKey === 'todo') return tree.todoReqs;
36
+ if (sectionKey === 'verify') return tree.verifyReqs;
37
+ if (sectionKey === 'clarification') return tree.clarificationReqs;
38
+ if (sectionKey === 'recycled') return tree.recycledReqs;
39
+ return [];
40
+ }
41
+
42
+ /**
43
+ * Helper to show confirmation prompt (r/y for yes, N for no, default N)
44
+ */
45
+ async function confirmAction(message) {
46
+ console.log();
47
+ process.stdout.write(chalk.yellow(`${message} `));
48
+
49
+ return new Promise((resolve) => {
50
+ readline.emitKeypressEvents(process.stdin);
51
+ if (process.stdin.isTTY) {
52
+ process.stdin.setRawMode(true);
53
+ }
54
+
55
+ process.stdin.resume();
56
+ process.stdin.on('keypress', (str, key) => {
57
+ process.stdin.setRawMode(false);
58
+ process.stdin.pause();
59
+ process.stdin.removeAllListeners('keypress');
60
+
61
+ if (key.name === 'return' || key.name === 'escape') {
62
+ resolve(false);
63
+ } else if ((key.name === 'r' || key.name === 'y') && !key.ctrl) {
64
+ resolve(true);
65
+ } else {
66
+ resolve(false);
67
+ }
68
+ });
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Helper to confirm and exit
74
+ */
75
+ async function confirmAndExit(message = 'Are you sure you want to exit? (r/y/N)') {
76
+ const confirmed = await confirmAction(message);
77
+ if (confirmed) {
78
+ showGoodbyeMessage();
79
+ process.exit(0);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Helper to format requirement title for display
85
+ */
86
+ function formatRequirementTitle(req, index = null) {
87
+ const prefix = index !== null ? `${index + 1}. ` : '';
88
+ const status = req.status ? `[${req.status}] ` : '';
89
+ return `${prefix}${status}${req.title}`;
90
+ }
91
+
92
+ /**
93
+ * Helper to validate requirement title
94
+ */
95
+ function validateRequirementTitle(title) {
96
+ if (!title || title.trim().length === 0) {
97
+ return 'Requirement title cannot be empty';
98
+ }
99
+ if (title.length > 200) {
100
+ return 'Requirement title must be less than 200 characters';
101
+ }
102
+ return null;
103
+ }
104
+
105
+ /**
106
+ * Helper to find requirement by title in any section
107
+ */
108
+ function findRequirementInTree(tree, title) {
109
+ for (const sectionKey of ['todo', 'verify', 'clarification', 'recycled']) {
110
+ const reqList = getRequirementList(tree, sectionKey);
111
+ const req = reqList.find(r => r.title === title);
112
+ if (req) {
113
+ return { req, sectionKey };
114
+ }
115
+ }
116
+ return null;
117
+ }
118
+
119
+ module.exports = {
120
+ showGoodbyeMessage,
121
+ getSectionTitle,
122
+ getRequirementList,
123
+ confirmAction,
124
+ confirmAndExit,
125
+ formatRequirementTitle,
126
+ validateRequirementTitle,
127
+ findRequirementInTree
128
+ };
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Requirement Management Module
3
+ *
4
+ * Handles basic requirement management actions like rename, delete, promote, demote.
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const inquirer = require('inquirer');
9
+ const fs = require('fs-extra');
10
+ const { getRequirementsPath } = require('vibecodingmachine-core');
11
+ const { getSectionTitle, getRequirementList, confirmAction } = require('./requirement-helpers');
12
+
13
+ /**
14
+ * Show requirement actions menu
15
+ */
16
+ async function showRequirementActions(req, sectionKey, tree) {
17
+ const reqList = getRequirementList(tree, sectionKey);
18
+ const sectionTitle = getSectionTitle(sectionKey);
19
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
20
+
21
+ if (reqIndex === -1) {
22
+ console.log(chalk.red('Requirement not found'));
23
+ return;
24
+ }
25
+
26
+ let actions = [
27
+ { label: '✏️ Rename/Edit', value: 'rename' },
28
+ { label: '👍 Thumbs Up (promote)', value: 'thumbs-up' },
29
+ { label: '👎 Thumbs Down (demote)', value: 'thumbs-down' },
30
+ { label: '🗑️ Delete', value: 'delete' },
31
+ { label: '↩️ Back', value: 'back' }
32
+ ];
33
+
34
+ // Add move actions based on current section
35
+ if (sectionKey === 'todo') {
36
+ actions.splice(-2, 0, { label: '↪️ Move to Clarification', value: 'move-to-clarification' });
37
+ } else if (sectionKey === 'clarification') {
38
+ actions.splice(-2, 0, { label: '↩️ Move back to TODO', value: 'move-to-todo' });
39
+ }
40
+
41
+ console.log(chalk.bold.cyan(`\n📋 ${sectionTitle}\n`));
42
+ console.log(chalk.bold(`${reqIndex + 1}. ${req.title}`));
43
+
44
+ if (req.details && req.details.length > 0) {
45
+ console.log(chalk.gray('Description:'));
46
+ req.details.forEach(detail => {
47
+ console.log(chalk.gray(` ${detail}`));
48
+ });
49
+ }
50
+ console.log();
51
+
52
+ try {
53
+ const { action } = await inquirer.prompt([{
54
+ type: 'list',
55
+ name: 'action',
56
+ message: 'What would you like to do?',
57
+ choices: actions
58
+ }]);
59
+
60
+ if (action !== 'back') {
61
+ await performRequirementAction(action, req, sectionKey, tree);
62
+ }
63
+ } catch (error) {
64
+ console.error(chalk.red('Error performing requirement action:'), error);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Perform action on requirement
70
+ */
71
+ async function performRequirementAction(action, req, sectionKey, tree) {
72
+ const reqList = getRequirementList(tree, sectionKey);
73
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
74
+
75
+ if (reqIndex === -1) {
76
+ console.log(chalk.red('Requirement not found'));
77
+ return;
78
+ }
79
+
80
+ switch (action) {
81
+ case 'rename':
82
+ await renameRequirement(req, sectionKey, tree);
83
+ break;
84
+ case 'thumbs-up':
85
+ await promoteRequirement(req, sectionKey, tree);
86
+ break;
87
+ case 'thumbs-down':
88
+ await demoteRequirement(req.title, sectionKey, tree);
89
+ break;
90
+ case 'delete':
91
+ await deleteRequirement(req, sectionKey, tree);
92
+ break;
93
+ case 'move-to-clarification':
94
+ await moveToClarification(req, sectionKey, tree);
95
+ break;
96
+ case 'move-to-todo':
97
+ await moveToTodo(req, sectionKey, tree);
98
+ break;
99
+ }
100
+
101
+ await new Promise(resolve => setTimeout(resolve, 1000));
102
+ }
103
+
104
+ /**
105
+ * Rename requirement (title and description)
106
+ */
107
+ async function renameRequirement(req, sectionKey, tree) {
108
+ const reqPath = await getRequirementsPath();
109
+
110
+ console.log(chalk.cyan('\n✏️ Rename/Edit Requirement\n'));
111
+ console.log(chalk.gray('Current title:'), chalk.white(req.title));
112
+ if (req.details && req.details.length > 0) {
113
+ console.log(chalk.gray('Current description:'));
114
+ req.details.forEach(line => console.log(chalk.white(' ' + line)));
115
+ }
116
+ console.log();
117
+
118
+ const answers = await inquirer.prompt([
119
+ {
120
+ type: 'input',
121
+ name: 'title',
122
+ message: 'New title (leave blank to keep current):',
123
+ default: ''
124
+ }
125
+ ]);
126
+
127
+ const newTitle = answers.title.trim() || req.title;
128
+
129
+ // Ask for description using multi-line input
130
+ console.log(chalk.gray('\nEnter new description (leave blank to keep current).'));
131
+ console.log(chalk.gray('Press Enter twice on empty line to finish:\n'));
132
+
133
+ const descriptionLines = [];
134
+ let emptyLineCount = 0;
135
+ let isFirstLine = true;
136
+ let newDescription = '';
137
+ let keptCurrent = false;
138
+
139
+ while (true) {
140
+ try {
141
+ const { line } = await inquirer.prompt([{
142
+ type: 'input',
143
+ name: 'line',
144
+ message: isFirstLine ? 'Description:' : ''
145
+ }]);
146
+
147
+ if (isFirstLine && line.trim() === '') {
148
+ // If first line is empty, keep current description
149
+ keptCurrent = true;
150
+ break;
151
+ }
152
+
153
+ isFirstLine = false;
154
+
155
+ if (line.trim() === '') {
156
+ emptyLineCount++;
157
+ if (emptyLineCount >= 2) break;
158
+ } else {
159
+ emptyLineCount = 0;
160
+ descriptionLines.push(line);
161
+ }
162
+ } catch (err) {
163
+ break;
164
+ }
165
+ }
166
+
167
+ if (!keptCurrent) {
168
+ newDescription = descriptionLines.join('\n');
169
+ }
170
+
171
+ // Read the requirements file
172
+ const content = await fs.readFile(reqPath, 'utf8');
173
+ const lines = content.split('\n');
174
+
175
+ // Find and update the requirement
176
+ let startIdx = -1;
177
+ let endIdx = -1;
178
+
179
+ for (let i = 0; i < lines.length; i++) {
180
+ if (lines[i].includes(`### ${req.title}`)) {
181
+ startIdx = i;
182
+ // Find the end of this requirement
183
+ for (let j = i + 1; j < lines.length; j++) {
184
+ if (lines[j].startsWith('###') || lines[j].startsWith('##')) {
185
+ endIdx = j;
186
+ break;
187
+ }
188
+ }
189
+ if (endIdx === -1) endIdx = lines.length;
190
+ break;
191
+ }
192
+ }
193
+
194
+ if (startIdx !== -1) {
195
+ // Build new requirement content
196
+ const newReqContent = [`### ${newTitle}`, ''];
197
+
198
+ if (newDescription && !keptCurrent) {
199
+ newReqContent.push(newDescription, '');
200
+ } else if (req.details && req.details.length > 0) {
201
+ req.details.forEach(detail => newReqContent.push(detail));
202
+ newReqContent.push('');
203
+ }
204
+
205
+ // Replace the requirement
206
+ lines.splice(startIdx, endIdx - startIdx, ...newReqContent);
207
+ await fs.writeFile(reqPath, lines.join('\n'));
208
+ console.log(chalk.green('\n✓ Requirement updated!'));
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Delete requirement
214
+ */
215
+ async function deleteRequirement(req, sectionKey, tree) {
216
+ const reqList = getRequirementList(tree, sectionKey);
217
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
218
+
219
+ if (reqIndex === -1) return;
220
+
221
+ const confirmed = await confirmAction(`Delete "${req.title}"? This cannot be undone. (r/y/N)`);
222
+ if (!confirmed) {
223
+ console.log(chalk.gray('Cancelled.'));
224
+ return;
225
+ }
226
+
227
+ const reqPath = await getRequirementsPath();
228
+ const content = await fs.readFile(reqPath, 'utf8');
229
+ const lines = content.split('\n');
230
+
231
+ // Find and remove the requirement
232
+ for (let i = 0; i < lines.length; i++) {
233
+ if (lines[i].includes(`### ${req.title}`)) {
234
+ // Find the end of this requirement
235
+ let endIdx = i + 1;
236
+ while (endIdx < lines.length && !lines[endIdx].startsWith('###') && !lines[endIdx].startsWith('##')) {
237
+ endIdx++;
238
+ }
239
+
240
+ lines.splice(i, endIdx - i);
241
+ break;
242
+ }
243
+ }
244
+
245
+ await fs.writeFile(reqPath, lines.join('\n'));
246
+ reqList.splice(reqIndex, 1);
247
+ console.log(chalk.green('\n✓ Requirement deleted!'));
248
+ }
249
+
250
+ /**
251
+ * Promote requirement (thumbs up)
252
+ */
253
+ async function promoteRequirement(req, sectionKey, tree) {
254
+ console.log(chalk.cyan(`\n👍 Promoting: ${req.title}`));
255
+
256
+ // Implementation would depend on specific promotion logic
257
+ // This is a placeholder for the actual promotion functionality
258
+ console.log(chalk.yellow('Promotion functionality not yet implemented'));
259
+ }
260
+
261
+ /**
262
+ * Demote requirement (thumbs down)
263
+ */
264
+ async function demoteRequirement(title, sectionKey, tree) {
265
+ console.log(chalk.cyan(`\n👎 Demoting: ${title}`));
266
+
267
+ // Implementation would depend on specific demotion logic
268
+ // This is a placeholder for the actual demotion functionality
269
+ console.log(chalk.yellow('Demotion functionality not yet implemented'));
270
+ }
271
+
272
+ module.exports = {
273
+ showRequirementActions,
274
+ performRequirementAction,
275
+ renameRequirement,
276
+ deleteRequirement,
277
+ promoteRequirement,
278
+ demoteRequirement
279
+ };