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,356 @@
1
+ const { t, getRequirementsPath, promoteTodoToVerify, promoteToVerified, demoteVerifyToTodo, demoteFromVerifiedToTodo } = require('vibecodingmachine-core');
2
+ const chalk = require('chalk');
3
+ const inquirer = require('inquirer');
4
+ const fs = require('fs-extra');
5
+
6
+ // Helper to get section title from section key
7
+ function getSectionTitle(sectionKey) {
8
+ if (sectionKey === 'todo') return '⏳ Requirements not yet completed';
9
+ if (sectionKey === 'verify') return '✅ Verified by AI screenshot';
10
+ if (sectionKey === 'recycled') return '♻️ Recycled';
11
+ if (sectionKey === 'clarification') return '❓ Needs clarification';
12
+ return '';
13
+ }
14
+
15
+ // Helper to get requirement list from tree by section key
16
+ function getRequirementList(tree, sectionKey) {
17
+ if (sectionKey === 'todo') return tree.todoReqs;
18
+ if (sectionKey === 'verify') return tree.verifyReqs;
19
+ if (sectionKey === 'clarification') return tree.clarificationReqs;
20
+ if (sectionKey === 'recycled') return tree.recycledReqs;
21
+ return [];
22
+ }
23
+
24
+ // Helper to rename requirement (title and description)
25
+ async function renameRequirement(req, sectionKey, tree) {
26
+ const { newTitle, newDescription } = await inquirer.prompt([
27
+ {
28
+ type: 'input',
29
+ name: 'newTitle',
30
+ message: 'Enter new title:',
31
+ default: req.title,
32
+ validate: input => input.trim().length > 0 || 'Title cannot be empty'
33
+ },
34
+ {
35
+ type: 'input',
36
+ name: 'newDescription',
37
+ message: 'Enter new description:',
38
+ default: req.content
39
+ }
40
+ ]);
41
+
42
+ const reqPath = await getRequirementsPath();
43
+ const content = await fs.readFile(reqPath, 'utf8');
44
+ const lines = content.split('\n');
45
+
46
+ // Find and replace the requirement
47
+ const reqIndex = lines.findIndex(line => line.includes(req.title));
48
+ if (reqIndex !== -1) {
49
+ lines[reqIndex] = `- ${newTitle}. ${newDescription}`;
50
+ await fs.writeFile(reqPath, lines.join('\n'));
51
+ console.log(chalk.green('✅ Requirement renamed'));
52
+ }
53
+ }
54
+
55
+ // Helper to move requirement to recycled section (used to delete)
56
+ async function deleteRequirement(req, sectionKey, tree) {
57
+ const reqList = getRequirementList(tree, sectionKey);
58
+ const sectionTitle = getSectionTitle(sectionKey);
59
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
60
+
61
+ if (reqIndex === -1) {
62
+ console.error(chalk.red('❌ Requirement not found'));
63
+ return;
64
+ }
65
+
66
+ const confirmed = await confirmAction('Delete this requirement? (r/y/N):');
67
+ if (!confirmed) return;
68
+
69
+ const reqPath = await getRequirementsPath();
70
+ const content = await fs.readFile(reqPath, 'utf8');
71
+ const lines = content.split('\n');
72
+
73
+ // Find the requirement line
74
+ const lineIndex = lines.findIndex(line => line.includes(req.title));
75
+ if (lineIndex !== -1) {
76
+ // Remove the requirement
77
+ const requirementLine = lines[lineIndex];
78
+ lines.splice(lineIndex, 1);
79
+
80
+ // Add to recycled section
81
+ await moveRequirementToRecycled(reqPath, req.title, sectionKey, [requirementLine]);
82
+
83
+ await fs.writeFile(reqPath, lines.join('\n'));
84
+ console.log(chalk.green('✅ Requirement deleted'));
85
+ }
86
+ }
87
+
88
+ // Helper to permanently delete requirement from file (used for recycled items)
89
+ async function permanentlyDeleteRequirement(req, sectionKey, tree) {
90
+ const reqList = getRequirementList(tree, sectionKey);
91
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
92
+
93
+ if (reqIndex === -1) {
94
+ console.error(chalk.red('❌ Requirement not found'));
95
+ return;
96
+ }
97
+
98
+ const confirmed = await confirmAction('Permanently delete this requirement? (r/y/N):');
99
+ if (!confirmed) return;
100
+
101
+ const reqPath = await getRequirementsPath();
102
+ const content = await fs.readFile(reqPath, 'utf8');
103
+ const lines = content.split('\n');
104
+
105
+ // Find and remove the requirement
106
+ const lineIndex = lines.findIndex(line => line.includes(req.title));
107
+ if (lineIndex !== -1) {
108
+ lines.splice(lineIndex, 1);
109
+ await fs.writeFile(reqPath, lines.join('\n'));
110
+ console.log(chalk.green('✅ Requirement permanently deleted'));
111
+ }
112
+ }
113
+
114
+ // Helper to move requirement to recycled section
115
+ async function moveRequirementToRecycled(reqPath, requirementTitle, fromSection, requirementLines = null) {
116
+ const content = await fs.readFile(reqPath, 'utf8');
117
+ const lines = content.split('\n');
118
+
119
+ // Find recycled section
120
+ const recycledIndex = lines.findIndex(line => line.includes('♻️ Recycled'));
121
+ if (recycledIndex === -1) {
122
+ // Create recycled section
123
+ lines.push('## ♻️ Recycled');
124
+ lines.push('');
125
+ lines.push(`- ${requirementTitle}`);
126
+ } else {
127
+ // Add to existing recycled section
128
+ let insertIndex = recycledIndex + 1;
129
+ while (insertIndex < lines.length && lines[insertIndex].trim() === '') {
130
+ insertIndex++;
131
+ }
132
+
133
+ if (requirementLines) {
134
+ lines.splice(insertIndex, 0, ...requirementLines);
135
+ } else {
136
+ lines.splice(insertIndex, 0, `- ${requirementTitle}`);
137
+ }
138
+ }
139
+
140
+ await fs.writeFile(reqPath, lines.join('\n'));
141
+ }
142
+
143
+ // Helper to move requirement down with 'j' key
144
+ async function moveRequirementDown(req, sectionKey, tree) {
145
+ const reqList = getRequirementList(tree, sectionKey);
146
+ const sectionTitle = getSectionTitle(sectionKey);
147
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
148
+
149
+ if (reqIndex === -1 || reqIndex === reqList.length - 1) {
150
+ return; // Can't move down if already at bottom
151
+ }
152
+
153
+ // Swap with next item
154
+ [reqList[reqIndex], reqList[reqIndex + 1]] = [reqList[reqIndex + 1], reqList[reqIndex]];
155
+
156
+ const reqPath = await getRequirementsPath();
157
+ await saveRequirementsOrder(reqPath, sectionTitle, reqList);
158
+ console.log(chalk.green('✅ Requirement moved down'));
159
+ }
160
+
161
+ // Helper to move requirement up with 'k' key
162
+ async function moveRequirementUp(req, sectionKey, tree) {
163
+ const reqList = getRequirementList(tree, sectionKey);
164
+ const sectionTitle = getSectionTitle(sectionKey);
165
+ const reqIndex = reqList.findIndex(r => r.title === req.title);
166
+
167
+ if (reqIndex <= 0) {
168
+ return; // Can't move up if already at top
169
+ }
170
+
171
+ // Swap with previous item
172
+ [reqList[reqIndex], reqList[reqIndex - 1]] = [reqList[reqIndex - 1], reqList[reqIndex]];
173
+
174
+ const reqPath = await getRequirementsPath();
175
+ await saveRequirementsOrder(reqPath, sectionTitle, reqList);
176
+ console.log(chalk.green('✅ Requirement moved up'));
177
+ }
178
+
179
+ // Helper to promote requirement to next list (TODO -> TO VERIFY -> VERIFIED)
180
+ async function promoteRequirement(req, sectionKey, tree, loadSection, loadVerified) {
181
+ const reqPath = await getRequirementsPath();
182
+
183
+ if (sectionKey === 'todo') {
184
+ await promoteTodoToVerify(reqPath, req.title);
185
+ console.log(chalk.green('✅ Requirement promoted to verification'));
186
+ } else if (sectionKey === 'verify') {
187
+ await promoteToVerified(reqPath, req.title);
188
+ console.log(chalk.green('✅ Requirement promoted to verified'));
189
+ }
190
+ }
191
+
192
+ // Helper to demote requirement to previous list (VERIFIED -> TODO, TO VERIFY -> TODO)
193
+ async function demoteRequirement(reqTitle, sectionKey, tree, loadSection, loadVerified) {
194
+ const reqPath = await getRequirementsPath();
195
+
196
+ if (sectionKey === 'verify') {
197
+ await demoteVerifyToTodo(reqPath, reqTitle);
198
+ console.log(chalk.green('✅ Requirement demoted to TODO'));
199
+ } else if (sectionKey === 'verified') {
200
+ await demoteFromVerifiedToTodo(reqPath, reqTitle);
201
+ console.log(chalk.green('✅ Requirement demoted to TODO'));
202
+ }
203
+ }
204
+
205
+ // Helper to restore requirement from recycled to TODO
206
+ async function restoreRequirement(req, sectionKey, tree) {
207
+ const reqPath = await getRequirementsPath();
208
+ const content = await fs.readFile(reqPath, 'utf8');
209
+ const lines = content.split('\n');
210
+
211
+ // Find requirement in recycled section
212
+ const reqIndex = lines.findIndex(line => line.includes(req.title));
213
+ if (reqIndex === -1) {
214
+ console.error(chalk.red('❌ Requirement not found'));
215
+ return;
216
+ }
217
+
218
+ // Remove from recycled
219
+ const requirementLine = lines[reqIndex];
220
+ lines.splice(reqIndex, 1);
221
+
222
+ // Add to TODO section
223
+ const todoIndex = lines.findIndex(line => line.includes('Requirements not yet completed'));
224
+ if (todoIndex !== -1) {
225
+ let insertIndex = todoIndex + 1;
226
+ while (insertIndex < lines.length && lines[insertIndex].trim() === '') {
227
+ insertIndex++;
228
+ }
229
+ lines.splice(insertIndex, 0, requirementLine);
230
+ }
231
+
232
+ await fs.writeFile(reqPath, lines.join('\n'));
233
+ console.log(chalk.green('✅ Requirement restored to TODO'));
234
+ }
235
+
236
+ // Helper to move requirement to clarification section
237
+ async function moveRequirementToClarification(req, sectionKey, tree) {
238
+ const reqPath = await getRequirementsPath();
239
+ const content = await fs.readFile(reqPath, 'utf8');
240
+ const lines = content.split('\n');
241
+
242
+ // Find requirement
243
+ const reqIndex = lines.findIndex(line => line.includes(req.title));
244
+ if (reqIndex === -1) {
245
+ console.error(chalk.red('❌ Requirement not found'));
246
+ return;
247
+ }
248
+
249
+ // Remove from current section
250
+ const requirementLine = lines[reqIndex];
251
+ lines.splice(reqIndex, 1);
252
+
253
+ // Add to clarification section
254
+ const clarificationIndex = lines.findIndex(line => line.includes('Needs clarification'));
255
+ if (clarificationIndex !== -1) {
256
+ let insertIndex = clarificationIndex + 1;
257
+ while (insertIndex < lines.length && lines[insertIndex].trim() === '') {
258
+ insertIndex++;
259
+ }
260
+ lines.splice(insertIndex, 0, requirementLine);
261
+ }
262
+
263
+ await fs.writeFile(reqPath, lines.join('\n'));
264
+ console.log(chalk.green('✅ Requirement moved to clarification'));
265
+ }
266
+
267
+ // Helper to save reordered requirements back to file
268
+ async function saveRequirementsOrder(reqPath, sectionTitle, requirements) {
269
+ const content = await fs.readFile(reqPath, 'utf8');
270
+ const lines = content.split('\n');
271
+
272
+ // Find section start
273
+ const sectionIndex = lines.findIndex(line => line.includes(sectionTitle));
274
+ if (sectionIndex === -1) {
275
+ console.error(chalk.red('❌ Section not found'));
276
+ return;
277
+ }
278
+
279
+ // Find section end (next section or end of file)
280
+ let sectionEnd = sectionIndex + 1;
281
+ while (sectionEnd < lines.length && !lines[sectionEnd].startsWith('##')) {
282
+ sectionEnd++;
283
+ }
284
+
285
+ // Build new section content
286
+ const newLines = lines.slice(0, sectionIndex + 1);
287
+ newLines.push(''); // Empty line after header
288
+
289
+ // Add requirements in new order
290
+ requirements.forEach(req => {
291
+ if (typeof req === 'string') {
292
+ newLines.push(req);
293
+ } else {
294
+ newLines.push(`- ${req.title}`);
295
+ }
296
+ });
297
+
298
+ // Add remaining lines
299
+ const remainingLines = lines.slice(sectionEnd);
300
+ newLines.push(...remainingLines);
301
+
302
+ await fs.writeFile(reqPath, newLines.join('\n'));
303
+ }
304
+
305
+ // Helper to show confirmation prompt (r/y for yes, N for no, default N)
306
+ async function confirmAction(message) {
307
+ console.log();
308
+ process.stdout.write(chalk.yellow(`${message} `));
309
+
310
+ return new Promise((resolve) => {
311
+ process.stdin.setRawMode(true);
312
+ process.stdin.resume();
313
+ process.stdin.setEncoding('utf8');
314
+
315
+ let data = '';
316
+ process.stdin.on('data', (key) => {
317
+ data += key;
318
+
319
+ // Accept 'r' or 'y' for yes, anything else for no
320
+ if (key.toLowerCase() === 'r' || key.toLowerCase() === 'y') {
321
+ process.stdout.write(key);
322
+ process.stdout.write('\n');
323
+ process.stdin.setRawMode(false);
324
+ process.stdin.pause();
325
+ resolve(true);
326
+ } else if (key === '\r' || key === '\n' || key === '\u0003') { // Enter, Esc, or Ctrl+C
327
+ process.stdout.write('N\n');
328
+ process.stdin.setRawMode(false);
329
+ process.stdin.pause();
330
+ resolve(false);
331
+ } else if (data.length > 1) { // Any other input
332
+ process.stdout.write('N\n');
333
+ process.stdin.setRawMode(false);
334
+ process.stdin.pause();
335
+ resolve(false);
336
+ }
337
+ });
338
+ });
339
+ }
340
+
341
+ module.exports = {
342
+ renameRequirement,
343
+ deleteRequirement,
344
+ permanentlyDeleteRequirement,
345
+ moveRequirementToRecycled,
346
+ moveRequirementDown,
347
+ moveRequirementUp,
348
+ promoteRequirement,
349
+ demoteRequirement,
350
+ restoreRequirement,
351
+ moveRequirementToClarification,
352
+ saveRequirementsOrder,
353
+ confirmAction,
354
+ getSectionTitle,
355
+ getRequirementList
356
+ };
@@ -0,0 +1,286 @@
1
+ const { t, getRequirementsPath } = require('vibecodingmachine-core');
2
+ const chalk = require('chalk');
3
+ const inquirer = require('inquirer');
4
+ const fs = require('fs-extra');
5
+
6
+ // Helper to get section title from section key
7
+ function getSectionTitle(sectionKey) {
8
+ if (sectionKey === 'todo') return '⏳ Requirements not yet completed';
9
+ if (sectionKey === 'verify') return '✅ Verified by AI screenshot';
10
+ if (sectionKey === 'recycled') return '♻️ Recycled';
11
+ if (sectionKey === 'clarification') return '❓ Needs clarification';
12
+ return '';
13
+ }
14
+
15
+ // Helper to get requirement list from tree by section key
16
+ function getRequirementList(tree, sectionKey) {
17
+ if (sectionKey === 'todo') return tree.todoReqs;
18
+ if (sectionKey === 'verify') return tree.verifyReqs;
19
+ if (sectionKey === 'clarification') return tree.clarificationReqs;
20
+ if (sectionKey === 'recycled') return tree.recycledReqs;
21
+ return [];
22
+ }
23
+
24
+ // Tree-style requirements navigator
25
+ async function showRequirementsTree() {
26
+ console.log(chalk.bold.cyan('\n📋 ' + t('requirements.navigator.title') + '\n'));
27
+ console.log(chalk.gray(t('requirements.navigator.basic.instructions') + '\n'));
28
+
29
+ try {
30
+ const reqPath = await getRequirementsPath();
31
+ const content = await fs.readFile(reqPath, 'utf8');
32
+
33
+ // Parse requirements into tree structure
34
+ const tree = parseRequirementsTree(content);
35
+
36
+ // Show summary
37
+ console.log(chalk.yellow(`📊 Summary:`));
38
+ console.log(chalk.gray(` • Todo: ${tree.todoReqs.length} items`));
39
+ console.log(chalk.gray(` • Needs clarification: ${tree.clarificationReqs.length} items`));
40
+ console.log(chalk.gray(` • Verified: ${tree.verifyReqs.length} items`));
41
+ console.log(chalk.gray(` • Recycled: ${tree.recycledReqs.length} items\n`));
42
+
43
+ // Interactive navigation
44
+ await navigateRequirements(tree);
45
+
46
+ } catch (error) {
47
+ console.error(chalk.red('❌ Error loading requirements:'), error.message);
48
+ }
49
+ }
50
+
51
+ function parseRequirementsTree(content) {
52
+ const lines = content.split('\n');
53
+ const tree = {
54
+ todoReqs: [],
55
+ verifyReqs: [],
56
+ clarificationReqs: [],
57
+ recycledReqs: []
58
+ };
59
+
60
+ let currentSection = null;
61
+
62
+ for (let i = 0; i < lines.length; i++) {
63
+ const line = lines[i].trim();
64
+
65
+ // Detect section headers
66
+ if (line.includes('Requirements not yet completed')) {
67
+ currentSection = 'todo';
68
+ } else if (line.includes('Verified by AI screenshot')) {
69
+ currentSection = 'verify';
70
+ } else if (line.includes('Needs clarification')) {
71
+ currentSection = 'clarification';
72
+ } else if (line.includes('Recycled')) {
73
+ currentSection = 'recycled';
74
+ } else if (line.startsWith('- ') && currentSection) {
75
+ // Parse requirement
76
+ const req = parseRequirement(line, i);
77
+ if (req) {
78
+ tree[`${currentSection}Reqs`].push(req);
79
+ }
80
+ }
81
+ }
82
+
83
+ return tree;
84
+ }
85
+
86
+ function parseRequirement(line, index) {
87
+ // Remove the "- " prefix
88
+ const content = line.substring(2);
89
+
90
+ // Extract title (first sentence or up to 100 chars)
91
+ const titleEnd = content.indexOf('.') !== -1 ? content.indexOf('.') + 1 : 100;
92
+ const title = content.substring(0, Math.min(titleEnd, 100)).trim();
93
+
94
+ return {
95
+ title,
96
+ content,
97
+ index,
98
+ originalLine: line
99
+ };
100
+ }
101
+
102
+ async function navigateRequirements(tree) {
103
+ const sections = [
104
+ { key: 'todo', name: '⏳ Todo', count: tree.todoReqs.length },
105
+ { key: 'clarification', name: '❓ Needs clarification', count: tree.clarificationReqs.length },
106
+ { key: 'verify', name: '✅ Verified', count: tree.verifyReqs.length },
107
+ { key: 'recycled', name: '♻️ Recycled', count: tree.recycledReqs.length }
108
+ ];
109
+
110
+ while (true) {
111
+ const { action } = await inquirer.prompt([
112
+ {
113
+ type: 'list',
114
+ name: 'action',
115
+ message: 'Navigate to section:',
116
+ choices: [
117
+ ...sections.filter(s => s.count > 0).map(s => ({
118
+ name: `${s.name} (${s.count} items)`,
119
+ value: s.key
120
+ })),
121
+ { name: '🔄 Refresh', value: 'refresh' },
122
+ { name: '📝 Add new requirement', value: 'add' },
123
+ { name: '🚪 Exit', value: 'exit' }
124
+ ]
125
+ }
126
+ ]);
127
+
128
+ if (action === 'exit') break;
129
+ if (action === 'refresh') {
130
+ // Reload requirements
131
+ const reqPath = await getRequirementsPath();
132
+ const content = await fs.readFile(reqPath, 'utf8');
133
+ Object.assign(tree, parseRequirementsTree(content));
134
+ continue;
135
+ }
136
+ if (action === 'add') {
137
+ await handleAddRequirement();
138
+ continue;
139
+ }
140
+
141
+ // Show section details
142
+ await showSectionDetails(action, tree);
143
+ }
144
+ }
145
+
146
+ async function showSectionDetails(sectionKey, tree) {
147
+ const reqList = getRequirementList(tree, sectionKey);
148
+ const sectionTitle = getSectionTitle(sectionKey);
149
+
150
+ if (reqList.length === 0) {
151
+ console.log(chalk.gray(`\nNo items in ${sectionTitle}\n`));
152
+ return;
153
+ }
154
+
155
+ console.log(chalk.bold(`\n${sectionTitle}\n`));
156
+
157
+ while (true) {
158
+ const { choice } = await inquirer.prompt([
159
+ {
160
+ type: 'list',
161
+ name: 'choice',
162
+ message: 'Select requirement:',
163
+ choices: [
164
+ ...reqList.map((req, index) => ({
165
+ name: `${index + 1}. ${req.title}`,
166
+ value: index
167
+ })),
168
+ { name: '⬅️ Back to sections', value: 'back' }
169
+ ]
170
+ }
171
+ ]);
172
+
173
+ if (choice === 'back') break;
174
+
175
+ const req = reqList[choice];
176
+ await showRequirementDetails(req, sectionKey, tree);
177
+
178
+ // Reload tree in case of changes
179
+ const reqPath = await getRequirementsPath();
180
+ const content = await fs.readFile(reqPath, 'utf8');
181
+ Object.assign(tree, parseRequirementsTree(content));
182
+ }
183
+ }
184
+
185
+ async function showRequirementDetails(req, sectionKey, tree) {
186
+ console.log(chalk.bold(`\n${req.title}\n`));
187
+ console.log(chalk.gray(req.content));
188
+ console.log();
189
+
190
+ const { action } = await inquirer.prompt([
191
+ {
192
+ type: 'list',
193
+ name: 'action',
194
+ message: 'What would you like to do?',
195
+ choices: getRequirementActions(sectionKey)
196
+ }
197
+ ]);
198
+
199
+ if (action !== 'back') {
200
+ await performRequirementAction(action, req, sectionKey, tree);
201
+ }
202
+ }
203
+
204
+ function getRequirementActions(sectionKey) {
205
+ const baseActions = [
206
+ { name: '⬅️ Back', value: 'back' }
207
+ ];
208
+
209
+ switch (sectionKey) {
210
+ case 'todo':
211
+ return [
212
+ { name: '✏️ Rename/Edit', value: 'rename' },
213
+ { name: '👍 Thumbs up (promote to Verified)', value: 'thumbs-up' },
214
+ { name: '❓ Needs clarification', value: 'needs-clarification' },
215
+ { name: '🗑️ Delete', value: 'delete' },
216
+ { name: '⬆️ Move up', value: 'move-up' },
217
+ { name: '⬇️ Move down', value: 'move-down' },
218
+ ...baseActions
219
+ ];
220
+ case 'clarification':
221
+ return [
222
+ { name: '✍️ Add/Edit Responses', value: 'edit-responses' },
223
+ { name: '↩️ Move back to TODO (after clarification)', value: 'move-to-todo' },
224
+ { name: '🗑️ Delete', value: 'delete' },
225
+ ...baseActions
226
+ ];
227
+ case 'verify':
228
+ return [
229
+ { name: '↩️ Move back to TODO', value: 'move-to-todo' },
230
+ { name: '🗑️ Delete', value: 'delete' },
231
+ ...baseActions
232
+ ];
233
+ case 'recycled':
234
+ return [
235
+ { name: '♻️ Restore to TODO', value: 'restore' },
236
+ { name: '🗑️ Permanently delete', value: 'permanent-delete' },
237
+ ...baseActions
238
+ ];
239
+ default:
240
+ return baseActions;
241
+ }
242
+ }
243
+
244
+ async function performRequirementAction(action, req, sectionKey, tree) {
245
+ const { performRequirementAction: actionHandler } = require('./requirement-actions');
246
+ await actionHandler(action, req, sectionKey, tree);
247
+ }
248
+
249
+ async function handleAddRequirement(type) {
250
+ const reqCommands = require('../commands/requirements');
251
+ const packages = ['all', 'cli', 'core', 'electron-app', 'web', 'mobile'];
252
+
253
+ const { package: pkg, requirement } = await inquirer.prompt([
254
+ {
255
+ type: 'list',
256
+ name: 'package',
257
+ message: 'Select package:',
258
+ choices: packages
259
+ },
260
+ {
261
+ type: 'input',
262
+ name: 'requirement',
263
+ message: 'Enter requirement:',
264
+ validate: input => input.trim().length > 0 || 'Requirement cannot be empty'
265
+ }
266
+ ]);
267
+
268
+ try {
269
+ await reqCommands.add(pkg, requirement);
270
+ console.log(chalk.green('✅ Requirement added successfully'));
271
+ } catch (error) {
272
+ console.error(chalk.red('❌ Error adding requirement:'), error.message);
273
+ }
274
+ }
275
+
276
+ module.exports = {
277
+ showRequirementsTree,
278
+ getSectionTitle,
279
+ getRequirementList,
280
+ parseRequirementsTree,
281
+ navigateRequirements,
282
+ showSectionDetails,
283
+ showRequirementDetails,
284
+ getRequirementActions,
285
+ handleAddRequirement
286
+ };