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,305 @@
1
+ const { getRequirementsPath, getVibeCodingMachineDir } = require('vibecodingmachine-core');
2
+ const chalk = require('chalk');
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * Export requirements to different formats
8
+ */
9
+ async function exportRequirements(format = 'json') {
10
+ const reqPath = await getRequirementsPath();
11
+ const stats = await getRequirementsStats();
12
+
13
+ if (!stats) {
14
+ console.error(chalk.red('❌ Could not read requirements file'));
15
+ return;
16
+ }
17
+
18
+ const exportData = {
19
+ exportedAt: new Date().toISOString(),
20
+ stats,
21
+ requirements: {
22
+ todo: [],
23
+ verify: [],
24
+ clarification: [],
25
+ recycled: []
26
+ }
27
+ };
28
+
29
+ try {
30
+ const content = await fs.readFile(reqPath, 'utf8');
31
+ const lines = content.split('\n');
32
+
33
+ let currentSection = null;
34
+
35
+ for (const line of lines) {
36
+ const trimmed = line.trim();
37
+
38
+ if (trimmed.includes('Requirements not yet completed')) {
39
+ currentSection = 'todo';
40
+ } else if (trimmed.includes('Verified by AI screenshot')) {
41
+ currentSection = 'verify';
42
+ } else if (trimmed.includes('Needs clarification')) {
43
+ currentSection = 'clarification';
44
+ } else if (trimmed.includes('Recycled')) {
45
+ currentSection = 'recycled';
46
+ } else if (trimmed.startsWith('- ')) {
47
+ exportData.requirements[currentSection].push(trimmed.substring(2));
48
+ }
49
+ }
50
+
51
+ let fileName;
52
+ let exportContent;
53
+
54
+ switch (format.toLowerCase()) {
55
+ case 'json':
56
+ fileName = `requirements-export-${Date.now()}.json`;
57
+ exportContent = JSON.stringify(exportData, null, 2);
58
+ break;
59
+
60
+ case 'csv':
61
+ fileName = `requirements-export-${Date.now()}.csv`;
62
+ exportContent = convertToCSV(exportData);
63
+ break;
64
+
65
+ case 'txt':
66
+ fileName = `requirements-export-${Date.now()}.txt`;
67
+ exportContent = convertToText(exportData);
68
+ break;
69
+
70
+ default:
71
+ console.error(chalk.red('❌ Unsupported export format'));
72
+ return;
73
+ }
74
+
75
+ const exportPath = path.join(path.dirname(reqPath), fileName);
76
+ await fs.writeFile(exportPath, exportContent);
77
+
78
+ console.log(chalk.green(`✅ Requirements exported to: ${exportPath}`));
79
+
80
+ } catch (error) {
81
+ console.error(chalk.red('❌ Error exporting requirements:'), error.message);
82
+ }
83
+ }
84
+
85
+ function convertToCSV(data) {
86
+ const csvLines = ['Section,Requirement,ExportedAt'];
87
+
88
+ Object.entries(data.requirements).forEach(([section, requirements]) => {
89
+ requirements.forEach(req => {
90
+ csvLines.push(`"${section}","${req.replace(/"/g, '""')}","${data.exportedAt}"`);
91
+ });
92
+ });
93
+
94
+ return csvLines.join('\n');
95
+ }
96
+
97
+ function convertToText(data) {
98
+ let text = `Requirements Export\n`;
99
+ text += `Exported at: ${data.exportedAt}\n`;
100
+ text += `Total requirements: ${data.stats.totalRequirements}\n\n`;
101
+
102
+ Object.entries(data.requirements).forEach(([section, requirements]) => {
103
+ if (requirements.length > 0) {
104
+ text += `${section.toUpperCase()} (${requirements.length}):\n`;
105
+ requirements.forEach((req, index) => {
106
+ text += `${index + 1}. ${req}\n`;
107
+ });
108
+ text += '\n';
109
+ }
110
+ });
111
+
112
+ return text;
113
+ }
114
+
115
+ /**
116
+ * Import requirements from file
117
+ */
118
+ async function importRequirements(importPath) {
119
+ if (!await fs.pathExists(importPath)) {
120
+ console.error(chalk.red('❌ Import file not found'));
121
+ return;
122
+ }
123
+
124
+ try {
125
+ const ext = path.extname(importPath).toLowerCase();
126
+ let requirements = [];
127
+
128
+ switch (ext) {
129
+ case '.json':
130
+ const data = await fs.readJson(importPath);
131
+ requirements = Object.values(data.requirements).flat();
132
+ break;
133
+
134
+ case '.csv':
135
+ const csvContent = await fs.readFile(importPath, 'utf8');
136
+ const lines = csvContent.split('\n');
137
+ for (let i = 1; i < lines.length; i++) { // Skip header
138
+ const cols = lines[i].split(',');
139
+ if (cols.length >= 2) {
140
+ const requirement = cols[1].replace(/^"|"$/g, '').replace(/""/g, '"');
141
+ requirements.push(requirement);
142
+ }
143
+ }
144
+ break;
145
+
146
+ case '.txt':
147
+ const txtContent = await fs.readFile(importPath, 'utf8');
148
+ const txtLines = txtContent.split('\n');
149
+ for (const line of txtLines) {
150
+ const trimmed = line.trim();
151
+ if (trimmed && /^\d+\./.test(trimmed)) {
152
+ requirements.push(trimmed.replace(/^\d+\.\s*/, ''));
153
+ }
154
+ }
155
+ break;
156
+
157
+ default:
158
+ console.error(chalk.red('❌ Unsupported import format'));
159
+ return;
160
+ }
161
+
162
+ if (requirements.length === 0) {
163
+ console.log(chalk.yellow('⚠️ No requirements found in import file'));
164
+ return;
165
+ }
166
+
167
+ console.log(chalk.green(`✅ Found ${requirements.length} requirements to import`));
168
+
169
+ const reqPath = await getRequirementsPath();
170
+ const content = await fs.readFile(reqPath, 'utf8');
171
+ const lines = content.split('\n');
172
+
173
+ // Find TODO section
174
+ const todoIndex = lines.findIndex(line => line.includes('Requirements not yet completed'));
175
+ if (todoIndex === -1) {
176
+ console.error(chalk.red('❌ TODO section not found in requirements file'));
177
+ return;
178
+ }
179
+
180
+ // Insert requirements at the end of TODO section
181
+ let insertIndex = todoIndex + 1;
182
+ while (insertIndex < lines.length && !lines[insertIndex].startsWith('##') && lines[insertIndex].trim() !== '') {
183
+ insertIndex++;
184
+ }
185
+
186
+ // Add a blank line if needed
187
+ if (insertIndex < lines.length && lines[insertIndex].trim() !== '') {
188
+ lines.splice(insertIndex, 0, '');
189
+ insertIndex++;
190
+ }
191
+
192
+ // Add imported requirements
193
+ const importedRequirements = requirements.map(req => `- ${req}`);
194
+ lines.splice(insertIndex, 0, ...importedRequirements);
195
+
196
+ await fs.writeFile(reqPath, lines.join('\n'));
197
+ console.log(chalk.green(`✅ Imported ${requirements.length} requirements`));
198
+
199
+ } catch (error) {
200
+ console.error(chalk.red('❌ Error importing requirements:'), error.message);
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Get requirements stats (re-exported from validation module)
206
+ */
207
+ async function getRequirementsStats() {
208
+ const { getRequirementsStats: getStats } = require('./file-validation');
209
+ return await getStats();
210
+ }
211
+
212
+ /**
213
+ * Export requirements with custom filters
214
+ */
215
+ async function exportFilteredRequirements(filters = {}) {
216
+ const reqPath = await getRequirementsPath();
217
+ const stats = await getRequirementsStats();
218
+
219
+ if (!stats) {
220
+ console.error(chalk.red('❌ Could not read requirements file'));
221
+ return;
222
+ }
223
+
224
+ try {
225
+ const content = await fs.readFile(reqPath, 'utf8');
226
+ const lines = content.split('\n');
227
+
228
+ const filteredData = {
229
+ exportedAt: new Date().toISOString(),
230
+ filters,
231
+ requirements: {
232
+ todo: [],
233
+ verify: [],
234
+ clarification: [],
235
+ recycled: []
236
+ }
237
+ };
238
+
239
+ let currentSection = null;
240
+
241
+ for (const line of lines) {
242
+ const trimmed = line.trim();
243
+
244
+ if (trimmed.includes('Requirements not yet completed')) {
245
+ currentSection = 'todo';
246
+ } else if (trimmed.includes('Verified by AI screenshot')) {
247
+ currentSection = 'verify';
248
+ } else if (trimmed.includes('Needs clarification')) {
249
+ currentSection = 'clarification';
250
+ } else if (trimmed.includes('Recycled')) {
251
+ currentSection = 'recycled';
252
+ } else if (trimmed.startsWith('- ')) {
253
+ const requirement = trimmed.substring(2);
254
+
255
+ // Apply filters
256
+ let includeRequirement = true;
257
+
258
+ if (filters.section && filters.section !== currentSection) {
259
+ includeRequirement = false;
260
+ }
261
+
262
+ if (filters.keyword && !requirement.toLowerCase().includes(filters.keyword.toLowerCase())) {
263
+ includeRequirement = false;
264
+ }
265
+
266
+ if (filters.minLength && requirement.length < filters.minLength) {
267
+ includeRequirement = false;
268
+ }
269
+
270
+ if (filters.maxLength && requirement.length > filters.maxLength) {
271
+ includeRequirement = false;
272
+ }
273
+
274
+ if (includeRequirement) {
275
+ filteredData.requirements[currentSection].push(requirement);
276
+ }
277
+ }
278
+ }
279
+
280
+ // Count total filtered requirements
281
+ const totalFiltered = Object.values(filteredData.requirements).reduce((sum, reqs) => sum + reqs.length, 0);
282
+
283
+ console.log(chalk.green(`✅ Exported ${totalFiltered} filtered requirements`));
284
+
285
+ // Export as JSON by default for filtered exports
286
+ const fileName = `requirements-filtered-export-${Date.now()}.json`;
287
+ const exportPath = path.join(path.dirname(reqPath), fileName);
288
+ const exportContent = JSON.stringify(filteredData, null, 2);
289
+
290
+ await fs.writeFile(exportPath, exportContent);
291
+ console.log(chalk.green(`✅ Filtered export saved to: ${exportPath}`));
292
+
293
+ } catch (error) {
294
+ console.error(chalk.red('❌ Error exporting filtered requirements:'), error.message);
295
+ }
296
+ }
297
+
298
+ module.exports = {
299
+ exportRequirements,
300
+ importRequirements,
301
+ getRequirementsStats,
302
+ exportFilteredRequirements,
303
+ convertToCSV,
304
+ convertToText
305
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * File Operations - Orchestrates file I/O operations
3
+ *
4
+ * This module coordinates between backup, validation, and import/export operations.
5
+ * It serves as the main entry point for file-related operations.
6
+ */
7
+
8
+ const chalk = require('chalk');
9
+
10
+ // Import split modules
11
+ const {
12
+ createBackup,
13
+ restoreFromBackup,
14
+ listBackups,
15
+ cleanupOldBackups
16
+ } = require('./file-backup');
17
+
18
+ const {
19
+ validateRequirementsFile,
20
+ getRequirementsStats,
21
+ checkDuplicateRequirements,
22
+ checkOrphanedResponses
23
+ } = require('./file-validation');
24
+
25
+ const {
26
+ exportRequirements,
27
+ importRequirements,
28
+ exportFilteredRequirements
29
+ } = require('./file-import-export');
30
+
31
+ // Re-export all functions for backward compatibility
32
+ module.exports = {
33
+ // Backup operations
34
+ createBackup,
35
+ restoreFromBackup,
36
+ listBackups,
37
+ cleanupOldBackups,
38
+
39
+ // Validation operations
40
+ validateRequirementsFile,
41
+ getRequirementsStats,
42
+ checkDuplicateRequirements,
43
+ checkOrphanedResponses,
44
+
45
+ // Import/Export operations
46
+ exportRequirements,
47
+ importRequirements,
48
+ exportFilteredRequirements
49
+ };
@@ -0,0 +1,276 @@
1
+ const { getRequirementsPath } = require('vibecodingmachine-core');
2
+ const chalk = require('chalk');
3
+ const fs = require('fs-extra');
4
+
5
+ /**
6
+ * Validate requirements file format
7
+ */
8
+ async function validateRequirementsFile() {
9
+ const reqPath = await getRequirementsPath();
10
+
11
+ if (!await fs.pathExists(reqPath)) {
12
+ console.log(chalk.red('❌ Requirements file not found'));
13
+ return false;
14
+ }
15
+
16
+ try {
17
+ const content = await fs.readFile(reqPath, 'utf8');
18
+ const lines = content.split('\n');
19
+
20
+ const issues = [];
21
+ let hasTodoSection = false;
22
+ let hasVerifySection = false;
23
+ let hasStatusSection = false;
24
+
25
+ for (let i = 0; i < lines.length; i++) {
26
+ const line = lines[i].trim();
27
+
28
+ if (line.includes('Requirements not yet completed')) {
29
+ hasTodoSection = true;
30
+ }
31
+
32
+ if (line.includes('Verified by AI screenshot')) {
33
+ hasVerifySection = true;
34
+ }
35
+
36
+ if (line.includes('🚦 Current Status')) {
37
+ hasStatusSection = true;
38
+ }
39
+
40
+ // Check for malformed requirement lines
41
+ if (line && !line.startsWith('#') && !line.startsWith('-') && !line.startsWith('[') && !line.startsWith('```')) {
42
+ if (i > 0 && !lines[i-1].trim().startsWith('#')) {
43
+ issues.push(`Line ${i + 1}: Unexpected content - "${line.substring(0, 50)}..."`);
44
+ }
45
+ }
46
+ }
47
+
48
+ console.log(chalk.bold('\n🔍 Requirements File Validation\n'));
49
+
50
+ if (!hasTodoSection) {
51
+ issues.push('Missing TODO section');
52
+ }
53
+
54
+ if (!hasVerifySection) {
55
+ issues.push('Missing verification section');
56
+ }
57
+
58
+ if (!hasStatusSection) {
59
+ issues.push('Missing status section');
60
+ }
61
+
62
+ if (issues.length === 0) {
63
+ console.log(chalk.green('✅ Requirements file format is valid\n'));
64
+ return true;
65
+ } else {
66
+ console.log(chalk.yellow('⚠️ Issues found:\n'));
67
+ issues.forEach(issue => console.log(chalk.gray(` • ${issue}`)));
68
+ console.log();
69
+ return false;
70
+ }
71
+ } catch (error) {
72
+ console.error(chalk.red('❌ Error validating requirements file:'), error.message);
73
+ return false;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Get requirements file statistics
79
+ */
80
+ async function getRequirementsStats() {
81
+ const reqPath = await getRequirementsPath();
82
+
83
+ if (!await fs.pathExists(reqPath)) {
84
+ return null;
85
+ }
86
+
87
+ try {
88
+ const content = await fs.readFile(reqPath, 'utf8');
89
+ const lines = content.split('\n');
90
+
91
+ const stats = {
92
+ totalLines: lines.length,
93
+ todoCount: 0,
94
+ verifyCount: 0,
95
+ recycledCount: 0,
96
+ clarificationCount: 0,
97
+ totalRequirements: 0,
98
+ lastModified: (await fs.stat(reqPath)).mtime
99
+ };
100
+
101
+ let currentSection = null;
102
+
103
+ for (const line of lines) {
104
+ const trimmed = line.trim();
105
+
106
+ if (trimmed.includes('Requirements not yet completed')) {
107
+ currentSection = 'todo';
108
+ } else if (trimmed.includes('Verified by AI screenshot')) {
109
+ currentSection = 'verify';
110
+ } else if (trimmed.includes('Needs clarification')) {
111
+ currentSection = 'clarification';
112
+ } else if (trimmed.includes('Recycled')) {
113
+ currentSection = 'recycled';
114
+ } else if (trimmed.startsWith('- ')) {
115
+ stats.totalRequirements++;
116
+
117
+ switch (currentSection) {
118
+ case 'todo':
119
+ stats.todoCount++;
120
+ break;
121
+ case 'verify':
122
+ stats.verifyCount++;
123
+ break;
124
+ case 'clarification':
125
+ stats.clarificationCount++;
126
+ break;
127
+ case 'recycled':
128
+ stats.recycledCount++;
129
+ break;
130
+ }
131
+ }
132
+ }
133
+
134
+ return stats;
135
+ } catch (error) {
136
+ console.error(chalk.red('❌ Error getting requirements stats:'), error.message);
137
+ return null;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Check for duplicate requirements
143
+ */
144
+ async function checkDuplicateRequirements() {
145
+ const reqPath = await getRequirementsPath();
146
+
147
+ if (!await fs.pathExists(reqPath)) {
148
+ console.log(chalk.red('❌ Requirements file not found'));
149
+ return [];
150
+ }
151
+
152
+ try {
153
+ const content = await fs.readFile(reqPath, 'utf8');
154
+ const lines = content.split('\n');
155
+
156
+ const requirements = [];
157
+ const duplicates = [];
158
+
159
+ for (const line of lines) {
160
+ const trimmed = line.trim();
161
+ if (trimmed.startsWith('- ')) {
162
+ const requirement = trimmed.substring(2);
163
+ const normalized = requirement.toLowerCase().replace(/\s+/g, ' ').trim();
164
+
165
+ if (requirements[normalized]) {
166
+ duplicates.push({
167
+ requirement,
168
+ originalLine: requirements[normalized].line,
169
+ duplicateLine: lines.indexOf(line) + 1
170
+ });
171
+ } else {
172
+ requirements[normalized] = {
173
+ requirement,
174
+ line: lines.indexOf(line) + 1
175
+ };
176
+ }
177
+ }
178
+ }
179
+
180
+ if (duplicates.length > 0) {
181
+ console.log(chalk.bold('\n🔍 Duplicate Requirements Found\n'));
182
+ console.log(chalk.yellow(`Found ${duplicates.length} duplicate(s):\n`));
183
+
184
+ duplicates.forEach((dup, index) => {
185
+ console.log(chalk.cyan(`${index + 1}. "${dup.requirement}"`));
186
+ console.log(chalk.gray(` Original: Line ${dup.originalLine}`));
187
+ console.log(chalk.gray(` Duplicate: Line ${dup.duplicateLine}\n`));
188
+ });
189
+ } else {
190
+ console.log(chalk.green('\n✅ No duplicate requirements found\n'));
191
+ }
192
+
193
+ return duplicates;
194
+ } catch (error) {
195
+ console.error(chalk.red('❌ Error checking duplicates:'), error.message);
196
+ return [];
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Check for orphaned responses (responses without requirements)
202
+ */
203
+ async function checkOrphanedResponses() {
204
+ const reqPath = await getRequirementsPath();
205
+
206
+ if (!await fs.pathExists(reqPath)) {
207
+ console.log(chalk.red('❌ Requirements file not found'));
208
+ return [];
209
+ }
210
+
211
+ try {
212
+ const content = await fs.readFile(reqPath, 'utf8');
213
+ const lines = content.split('\n');
214
+
215
+ const orphanedResponses = [];
216
+ let inClarificationSection = false;
217
+ let lastRequirement = null;
218
+
219
+ for (let i = 0; i < lines.length; i++) {
220
+ const line = lines[i].trim();
221
+
222
+ if (line.includes('Needs clarification')) {
223
+ inClarificationSection = true;
224
+ continue;
225
+ }
226
+
227
+ if (line.startsWith('##') && !line.includes('Needs clarification')) {
228
+ inClarificationSection = false;
229
+ lastRequirement = null;
230
+ continue;
231
+ }
232
+
233
+ if (line.startsWith('- ')) {
234
+ lastRequirement = line;
235
+ continue;
236
+ }
237
+
238
+ if (line.startsWith(' - ')) {
239
+ const response = line.substring(4).trim();
240
+
241
+ if (!lastRequirement) {
242
+ orphanedResponses.push({
243
+ response,
244
+ line: i + 1,
245
+ type: 'no_requirement'
246
+ });
247
+ }
248
+ }
249
+ }
250
+
251
+ if (orphanedResponses.length > 0) {
252
+ console.log(chalk.bold('\n🔍 Orphaned Responses Found\n'));
253
+ console.log(chalk.yellow(`Found ${orphanedResponses.length} orphaned response(s):\n`));
254
+
255
+ orphanedResponses.forEach((orphan, index) => {
256
+ console.log(chalk.cyan(`${index + 1}. "${orphan.response}"`));
257
+ console.log(chalk.gray(` Line: ${orphan.line}`));
258
+ console.log(chalk.gray(` Type: ${orphan.type}\n`));
259
+ });
260
+ } else {
261
+ console.log(chalk.green('\n✅ No orphaned responses found\n'));
262
+ }
263
+
264
+ return orphanedResponses;
265
+ } catch (error) {
266
+ console.error(chalk.red('❌ Error checking orphaned responses:'), error.message);
267
+ return [];
268
+ }
269
+ }
270
+
271
+ module.exports = {
272
+ validateRequirementsFile,
273
+ getRequirementsStats,
274
+ checkDuplicateRequirements,
275
+ checkOrphanedResponses
276
+ };