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.
- package/bin/auth/auth-compliance.js +126 -0
- package/bin/cli-program.js +104 -0
- package/bin/cli-setup.js +52 -0
- package/bin/commands/agent-commands.js +310 -0
- package/bin/commands/auto-commands.js +70 -0
- package/bin/commands/command-aliases.js +118 -0
- package/bin/commands/repo-commands.js +39 -0
- package/bin/commands/rui-commands.js +152 -0
- package/bin/config/cli-config.js +394 -0
- package/bin/init/environment-setup.js +84 -0
- package/bin/update/update-checker.js +126 -0
- package/bin/vibecodingmachine-new.js +50 -0
- package/bin/vibecodingmachine.js +29 -663
- package/package.json +8 -2
- package/src/commands/agents/add.js +277 -0
- package/src/commands/agents/check.js +380 -0
- package/src/commands/agents/list.js +471 -0
- package/src/commands/agents/remove.js +351 -0
- package/src/commands/analyze-file-sizes.js +428 -0
- package/src/commands/auto-direct/code-processor.js +282 -0
- package/src/commands/auto-direct/file-scanner.js +266 -0
- package/src/commands/auto-direct/provider-config.js +178 -0
- package/src/commands/auto-direct/provider-manager.js +219 -0
- package/src/commands/auto-direct/requirement-manager.js +172 -0
- package/src/commands/auto-direct/status-display.js +91 -0
- package/src/commands/auto-direct/utils.js +106 -0
- package/src/commands/auto-direct.js +875 -488
- package/src/commands/auto-execution.js +342 -0
- package/src/commands/auto-provider-management.js +102 -0
- package/src/commands/auto-requirement-management.js +161 -0
- package/src/commands/auto-status-helpers.js +141 -0
- package/src/commands/auto.js +105 -5155
- package/src/commands/check-compliance.js +536 -0
- package/src/commands/continuous-scan.js +119 -0
- package/src/commands/ide.js +16 -4
- package/src/commands/refactor-file.js +486 -0
- package/src/commands/requirements.js +301 -2
- package/src/commands/timeout.js +290 -0
- package/src/trui/TruiInterface.js +108 -0
- package/src/trui/agents/AgentInterface.js +580 -0
- package/src/utils/antigravity-installer.js +60 -6
- package/src/utils/clarification-actions.js +290 -0
- package/src/utils/config.js +123 -2
- package/src/utils/first-run.js +5 -5
- package/src/utils/ide-handlers.js +212 -0
- package/src/utils/interactive/clarification-actions.js +348 -0
- package/src/utils/interactive/core-ui.js +265 -0
- package/src/utils/interactive/file-backup.js +237 -0
- package/src/utils/interactive/file-import-export.js +305 -0
- package/src/utils/interactive/file-operations.js +49 -0
- package/src/utils/interactive/file-validation.js +276 -0
- package/src/utils/interactive/interactive-prompts.js +480 -0
- package/src/utils/interactive/requirement-actions.js +127 -0
- package/src/utils/interactive/requirement-crud.js +356 -0
- package/src/utils/interactive/requirements-navigation.js +286 -0
- package/src/utils/interactive.js +390 -3459
- package/src/utils/provider-checker/agent-checker.js +250 -0
- package/src/utils/provider-checker/agent-runner.js +450 -0
- package/src/utils/provider-checker/cli-installer.js +123 -0
- package/src/utils/provider-checker/cli-utils.js +15 -0
- package/src/utils/provider-checker/format-utils.js +32 -0
- package/src/utils/provider-checker/ide-manager.js +72 -0
- package/src/utils/provider-checker/ide-utils.js +71 -0
- package/src/utils/provider-checker/node-detector.js +56 -0
- package/src/utils/provider-checker/node-utils.js +61 -0
- package/src/utils/provider-checker/process-spawn.js +22 -0
- package/src/utils/provider-checker/process-utils.js +37 -0
- package/src/utils/provider-checker/provider-validator.js +160 -0
- package/src/utils/provider-checker/quota-checker.js +54 -0
- package/src/utils/provider-checker/quota-detector.js +44 -0
- package/src/utils/provider-checker/requirements-manager.js +94 -0
- package/src/utils/provider-checker/test-requirements.js +95 -0
- package/src/utils/provider-checker/time-formatter.js +18 -0
- package/src/utils/provider-checker-new.js +14 -0
- package/src/utils/provider-checker.js +12 -407
- package/src/utils/provider-checkers/ide-manager.js +128 -0
- package/src/utils/provider-checkers/node-executable-finder.js +51 -0
- package/src/utils/provider-checkers/provider-checker-core.js +172 -0
- package/src/utils/provider-checkers/provider-checker-main.js +107 -0
- package/src/utils/provider-manager.js +60 -4
- package/src/utils/provider-registry.js +26 -3
- package/src/utils/provider-utils.js +173 -0
- package/src/utils/quota-detectors.js +212 -0
- package/src/utils/requirement-action-handlers.js +288 -0
- package/src/utils/requirement-actions/clarification-actions.js +229 -0
- package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
- package/src/utils/requirement-actions/file-operations.js +92 -0
- package/src/utils/requirement-actions/helpers.js +40 -0
- package/src/utils/requirement-actions/requirement-operations.js +335 -0
- package/src/utils/requirement-actions.js +46 -856
- package/src/utils/requirement-file-operations.js +259 -0
- package/src/utils/requirement-helpers.js +128 -0
- package/src/utils/requirement-management.js +279 -0
- package/src/utils/requirement-navigation.js +146 -0
- package/src/utils/requirement-organization.js +271 -0
- package/src/utils/simple-trui.js +75 -1
- package/src/utils/trui-navigation.js +28 -2
- package/src/utils/trui-req-tree.js +196 -11
- package/src/utils/trui-specifications.js +31 -1
- package/src/utils/interactive-backup.js +0 -5664
- 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
|
-
*
|
|
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
|
-
|
|
495
|
-
|
|
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
|
-
|
|
11
|
+
// Import modular components
|
|
12
|
+
const {
|
|
13
|
+
showGoodbyeMessage,
|
|
14
|
+
getSectionTitle,
|
|
15
|
+
getRequirementList
|
|
16
|
+
} = require('./requirement-actions/helpers');
|
|
838
17
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
18
|
+
const {
|
|
19
|
+
confirmAction,
|
|
20
|
+
confirmAndExit
|
|
21
|
+
} = require('./requirement-actions/confirmation-prompts');
|
|
842
22
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
-
|
|
855
|
-
|
|
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
|
-
|
|
858
|
-
|
|
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
|
-
|
|
66
|
+
moveRequirementDown,
|
|
67
|
+
moveRequirementUp,
|
|
68
|
+
moveToClarification,
|
|
882
69
|
saveRequirementsOrder,
|
|
70
|
+
moveRequirementToRecycled,
|
|
71
|
+
permanentlyDeleteRequirement,
|
|
72
|
+
handleAddRequirement,
|
|
883
73
|
handleFeedbackSubmission
|
|
884
74
|
};
|