vibecodingmachine-cli 2026.3.14-1537 → 2026.6.17-1956

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 (162) hide show
  1. package/bin/auth/auth-compliance.js +7 -7
  2. package/bin/commands/agent-commands.js +15 -15
  3. package/bin/commands/auto-commands.js +3 -3
  4. package/bin/commands/command-aliases.js +13 -4
  5. package/bin/config/cli-config.js +15 -5
  6. package/bin/update/update-checker.js +5 -5
  7. package/bin/vibecodingmachine.js +2 -2
  8. package/package.json +2 -2
  9. package/src/commands/agents/add.js +5 -5
  10. package/src/commands/agents/check.js +19 -19
  11. package/src/commands/agents/list.js +24 -24
  12. package/src/commands/agents/remove.js +4 -4
  13. package/src/commands/agents-check.js +1 -1
  14. package/src/commands/analyze-file-sizes.js +43 -43
  15. package/src/commands/auto-direct/auto-provider-manager.js +19 -19
  16. package/src/commands/auto-direct/auto-start-phases.js +493 -0
  17. package/src/commands/auto-direct/auto-status-display.js +35 -35
  18. package/src/commands/auto-direct/auto-utils.js +50 -50
  19. package/src/commands/auto-direct/cline-installer.js +56 -0
  20. package/src/commands/auto-direct/code-processor.js +27 -27
  21. package/src/commands/auto-direct/file-scanner.js +19 -19
  22. package/src/commands/auto-direct/ide-completion-waiter.js +485 -0
  23. package/src/commands/auto-direct/ide-fallback-runner.js +226 -0
  24. package/src/commands/auto-direct/ide-provider-runner.js +103 -0
  25. package/src/commands/auto-direct/iteration-handlers.js +189 -0
  26. package/src/commands/auto-direct/iteration-runner.js +485 -0
  27. package/src/commands/auto-direct/provider-config.js +38 -7
  28. package/src/commands/auto-direct/provider-manager.js +132 -6
  29. package/src/commands/auto-direct/requirement-manager.js +169 -104
  30. package/src/commands/auto-direct/requirement-mover.js +350 -0
  31. package/src/commands/auto-direct/spec-handlers.js +155 -0
  32. package/src/commands/auto-direct/spec-ide-runner.js +318 -0
  33. package/src/commands/auto-direct/spec-processing.js +203 -0
  34. package/src/commands/auto-direct/status-display.js +9 -9
  35. package/src/commands/auto-direct/utils.js +83 -1
  36. package/src/commands/auto-direct-refactored.js +1 -413
  37. package/src/commands/auto-direct.js +127 -4119
  38. package/src/commands/auto-execution.js +21 -21
  39. package/src/commands/auto-status-helpers.js +0 -2
  40. package/src/commands/auto.js +22 -22
  41. package/src/commands/check-compliance.js +65 -65
  42. package/src/commands/computers.js +39 -39
  43. package/src/commands/continuous-scan.js +19 -19
  44. package/src/commands/ide.js +4 -4
  45. package/src/commands/locale.js +7 -7
  46. package/src/commands/refactor-file.js +59 -59
  47. package/src/commands/requirements/commands.js +17 -17
  48. package/src/commands/requirements/default-handlers.js +30 -30
  49. package/src/commands/requirements/disable.js +3 -3
  50. package/src/commands/requirements/enable.js +3 -3
  51. package/src/commands/requirements/utils.js +6 -6
  52. package/src/commands/requirements-refactored.js +3 -3
  53. package/src/commands/requirements-remote.js +38 -38
  54. package/src/commands/requirements.js +3 -3
  55. package/src/commands/settings.js +111 -0
  56. package/src/commands/specs/count.js +60 -0
  57. package/src/commands/specs/disable.js +3 -3
  58. package/src/commands/specs/enable.js +3 -3
  59. package/src/commands/status.js +10 -10
  60. package/src/commands/sync.js +25 -25
  61. package/src/commands/timeout.js +35 -35
  62. package/src/trui/TruiInterface.js +2 -2
  63. package/src/trui/agents/AgentInterface.js +4 -4
  64. package/src/trui/agents/handlers/CommandHandler.js +4 -4
  65. package/src/trui/agents/handlers/ContextManager.js +1 -1
  66. package/src/trui/agents/handlers/DisplayHandler.js +11 -11
  67. package/src/trui/agents/handlers/HelpHandler.js +1 -1
  68. package/src/utils/agent-selector.js +6 -6
  69. package/src/utils/antigravity-installer.js +4 -4
  70. package/src/utils/asset-cleanup.js +1 -1
  71. package/src/utils/auth.js +9 -12
  72. package/src/utils/clarification-actions.js +4 -4
  73. package/src/utils/cline-js-handler.js +5 -5
  74. package/src/utils/compliance-check.js +6 -6
  75. package/src/utils/config.js +12 -12
  76. package/src/utils/display-formatters-complete.js +2 -2
  77. package/src/utils/display-formatters-extracted.js +2 -2
  78. package/src/utils/display-formatters.js +2 -2
  79. package/src/utils/feedback-handler.js +2 -2
  80. package/src/utils/first-run.js +7 -7
  81. package/src/utils/ide-detection.js +1 -1
  82. package/src/utils/ide-handlers.js +6 -6
  83. package/src/utils/interactive/clarification-actions.js +3 -3
  84. package/src/utils/interactive/core-ui.js +7 -7
  85. package/src/utils/interactive/file-backup.js +6 -6
  86. package/src/utils/interactive/file-import-export.js +49 -49
  87. package/src/utils/interactive/file-operations.js +3 -3
  88. package/src/utils/interactive/file-validation.js +41 -41
  89. package/src/utils/interactive/interactive-prompts.js +41 -41
  90. package/src/utils/interactive/requirement-actions.js +5 -5
  91. package/src/utils/interactive/requirement-crud.js +4 -4
  92. package/src/utils/interactive/requirements-navigation.js +10 -10
  93. package/src/utils/interactive-broken.js +6 -6
  94. package/src/utils/interactive.js +37 -37
  95. package/src/utils/keyboard-handler.js +4 -4
  96. package/src/utils/prompt-helper.js +6 -6
  97. package/src/utils/provider-checker/agent-checker.js +1 -1
  98. package/src/utils/provider-checker/agent-runner.js +203 -314
  99. package/src/utils/provider-checker/agents-file-lock.js +134 -0
  100. package/src/utils/provider-checker/agents-manager.js +224 -36
  101. package/src/utils/provider-checker/cli-installer.js +28 -28
  102. package/src/utils/provider-checker/cli-utils.js +2 -2
  103. package/src/utils/provider-checker/cursor-approval-clicker.js +108 -0
  104. package/src/utils/provider-checker/format-utils.js +4 -4
  105. package/src/utils/provider-checker/ide-installer-helper.js +96 -0
  106. package/src/utils/provider-checker/ide-manager.js +19 -8
  107. package/src/utils/provider-checker/ide-quota-checker.js +120 -0
  108. package/src/utils/provider-checker/ide-utils.js +2 -2
  109. package/src/utils/provider-checker/node-detector.js +4 -4
  110. package/src/utils/provider-checker/node-utils.js +5 -5
  111. package/src/utils/provider-checker/opencode-checker.js +107 -73
  112. package/src/utils/provider-checker/process-utils.js +1 -1
  113. package/src/utils/provider-checker/provider-validator.js +11 -11
  114. package/src/utils/provider-checker/quota-checker.js +5 -5
  115. package/src/utils/provider-checker/quota-detector.js +5 -5
  116. package/src/utils/provider-checker/requirements-manager.js +6 -6
  117. package/src/utils/provider-checker/test-requirements.js +1 -1
  118. package/src/utils/provider-checker/vscode-approval-clicker.js +328 -0
  119. package/src/utils/provider-checker-new.js +6 -6
  120. package/src/utils/provider-checker.js +6 -6
  121. package/src/utils/provider-checkers/ide-manager.js +13 -13
  122. package/src/utils/provider-checkers/node-executable-finder.js +4 -4
  123. package/src/utils/provider-checkers/provider-checker-core.js +5 -5
  124. package/src/utils/provider-checkers/provider-checker-main.js +17 -17
  125. package/src/utils/provider-registry.js +5 -6
  126. package/src/utils/provider-utils.js +12 -12
  127. package/src/utils/quota-detectors.js +32 -32
  128. package/src/utils/requirement-action-handlers.js +12 -12
  129. package/src/utils/requirement-actions/requirement-operations.js +3 -3
  130. package/src/utils/requirement-actions.js +1 -1
  131. package/src/utils/requirement-file-operations.js +5 -5
  132. package/src/utils/requirement-helpers.js +1 -1
  133. package/src/utils/requirement-management.js +5 -5
  134. package/src/utils/requirement-navigation.js +2 -2
  135. package/src/utils/requirement-organization.js +3 -3
  136. package/src/utils/rui-trui-adapter.js +14 -14
  137. package/src/utils/simple-trui.js +3 -3
  138. package/src/utils/status-helpers-extracted.js +3 -3
  139. package/src/utils/trui-clarifications.js +11 -11
  140. package/src/utils/trui-debug.js +3 -2
  141. package/src/utils/trui-devin.js +217 -0
  142. package/src/utils/trui-feedback.js +7 -7
  143. package/src/utils/trui-kiro-integration.js +34 -34
  144. package/src/utils/trui-main-handlers.js +20 -21
  145. package/src/utils/trui-main-menu.js +19 -19
  146. package/src/utils/trui-nav-agents.js +59 -8
  147. package/src/utils/trui-nav-requirements.js +3 -3
  148. package/src/utils/trui-nav-settings.js +10 -10
  149. package/src/utils/trui-nav-specifications.js +1 -1
  150. package/src/utils/trui-navigation-backup.js +11 -11
  151. package/src/utils/trui-navigation.js +9 -9
  152. package/src/utils/trui-provider-health.js +25 -25
  153. package/src/utils/trui-provider-manager.js +28 -28
  154. package/src/utils/trui-quick-menu.js +2 -2
  155. package/src/utils/trui-req-actions-backup.js +21 -21
  156. package/src/utils/trui-req-actions.js +20 -20
  157. package/src/utils/trui-req-editor.js +10 -10
  158. package/src/utils/trui-req-file-ops.js +3 -3
  159. package/src/utils/trui-req-tree.js +7 -7
  160. package/src/utils/trui-windsurf.js +103 -103
  161. package/src/utils/user-tracking.js +15 -15
  162. package/src/utils/trui-req-tree-old.js +0 -719
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Requirement Moving Functions
3
+ * Extracted from requirement-manager.js for constitutional compliance
4
+ * Handles moving requirements between sections (TO VERIFY, Recycled, etc.)
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const chalk = require('chalk');
9
+ const { getRequirementsPath } = require('vibecodingmachine-core');
10
+ const { t } = require('vibecodingmachine-core');
11
+
12
+ /**
13
+ * Move requirement from TODO to TO VERIFY BY HUMAN section
14
+ * @param {string} repoPath - Repository path
15
+ * @param {string} requirementText - Requirement text to move
16
+ * @returns {Promise<boolean>} - Success status
17
+ */
18
+ async function moveRequirementToVerify(repoPath, requirementText) {
19
+ try {
20
+ const reqPath = await getRequirementsPath(repoPath);
21
+ if (!reqPath || !await fs.pathExists(reqPath)) {
22
+ return false;
23
+ }
24
+
25
+ const content = await fs.readFile(reqPath, 'utf8');
26
+ const lines = content.split('\n');
27
+
28
+ // Find the requirement by its title (in ### header format)
29
+ // Only look in TODO section
30
+ const normalizedRequirement = requirementText.trim();
31
+ const snippet = normalizedRequirement.substring(0, 80);
32
+ let requirementStartIndex = -1;
33
+ let requirementEndIndex = -1;
34
+ let inTodoSection = false;
35
+
36
+ for (let i = 0; i < lines.length; i++) {
37
+ const line = lines[i];
38
+ const trimmed = line.trim();
39
+
40
+ // Check if we're entering TODO section
41
+ if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
42
+ inTodoSection = true;
43
+ continue;
44
+ }
45
+
46
+ // Check if we're leaving TODO section
47
+ if (inTodoSection && trimmed.startsWith('##') && !trimmed.startsWith('###') && !trimmed.includes('Requirements not yet completed')) {
48
+ inTodoSection = false;
49
+ }
50
+
51
+ // Only look for requirements in TODO section
52
+ if (inTodoSection && trimmed.startsWith('###')) {
53
+ const title = trimmed.replace(/^###\s*/, '').trim();
54
+ if (title) {
55
+ // Try multiple matching strategies
56
+ const normalizedTitle = title.trim();
57
+
58
+ // Exact match
59
+ if (normalizedTitle === normalizedRequirement) {
60
+ requirementStartIndex = i;
61
+ }
62
+ // Check if either contains the other (for partial matches)
63
+ else if (normalizedTitle.includes(normalizedRequirement) || normalizedRequirement.includes(normalizedTitle)) {
64
+ requirementStartIndex = i;
65
+ }
66
+ // Check snippet matches
67
+ else if (normalizedTitle.includes(snippet) || snippet.includes(normalizedTitle.substring(0, 80))) {
68
+ requirementStartIndex = i;
69
+ }
70
+
71
+ if (requirementStartIndex !== -1) {
72
+ // Find the end of this requirement (next ### or ## header)
73
+ for (let j = i + 1; j < lines.length; j++) {
74
+ const nextLine = lines[j].trim();
75
+ if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
76
+ requirementEndIndex = j;
77
+ break;
78
+ }
79
+ }
80
+ if (requirementEndIndex === -1) {
81
+ requirementEndIndex = lines.length;
82
+ }
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ if (requirementStartIndex === -1) {
90
+ console.log(chalk.yellow(`⚠️ ${t('auto.direct.requirement.not.found.todo', { requirement: requirementText.substring(0, 60) + '...' })}`));
91
+ return false;
92
+ }
93
+
94
+ // Extract the entire requirement block
95
+ const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
96
+
97
+ // Remove the requirement from its current location
98
+ lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
99
+
100
+ // Check if there are any more requirements in TODO section after removal
101
+ let hasMoreTodoRequirements = false;
102
+ inTodoSection = false; // Reset the existing variable
103
+ for (let i = 0; i < lines.length; i++) {
104
+ const line = lines[i].trim();
105
+
106
+ // Check if we're entering TODO section
107
+ if (line.startsWith('##') && line.includes('Requirements not yet completed')) {
108
+ inTodoSection = true;
109
+ continue;
110
+ }
111
+
112
+ // Check if we're leaving TODO section
113
+ if (inTodoSection && line.startsWith('##') && !line.startsWith('###') && !line.includes('Requirements not yet completed')) {
114
+ break;
115
+ }
116
+
117
+ // Check if we found a requirement in TODO section
118
+ if (inTodoSection && line.startsWith('###')) {
119
+ const title = line.replace(/^###\s*/, '').trim();
120
+ if (title) {
121
+ hasMoreTodoRequirements = true;
122
+ break;
123
+ }
124
+ }
125
+ }
126
+
127
+ // If no more TODO requirements, log message
128
+ if (!hasMoreTodoRequirements) {
129
+ console.log(chalk.green(`🎉 ${t('auto.direct.requirement.no.more.todo')}`));
130
+ }
131
+
132
+ // Find or create TO VERIFY BY HUMAN section with conflict resolution
133
+ // IMPORTANT: Do NOT match VERIFIED sections - only match TO VERIFY sections
134
+ const verifySectionVariants = [
135
+ '## 🔍 TO VERIFY BY HUMAN',
136
+ '## 🔍 TO VERIFY',
137
+ '## TO VERIFY',
138
+ '## ✅ TO VERIFY',
139
+ '## ✅ Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG',
140
+ '## 📊 CROSS-COMPUTER REQUIREMENT ASSIGNMENT',
141
+ '## 🖥️ COMPUTER FOCUS AREA MANAGEMENT',
142
+ '## 🔍 spec-kit: TO VERIFY BY HUMAN'
143
+ ];
144
+
145
+ let verifyIndex = -1;
146
+ for (let i = 0; i < lines.length; i++) {
147
+ const line = lines[i];
148
+ const trimmed = line.trim();
149
+
150
+ // Check each variant more carefully
151
+ for (const variant of verifySectionVariants) {
152
+ const variantTrimmed = variant.trim();
153
+ // Exact match or line starts with variant
154
+ if (trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed)) {
155
+ // Double-check: make sure it's NOT a VERIFIED section (without TO VERIFY)
156
+ if (!trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i) &&
157
+ (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot') || trimmed.includes('CROSS-COMPUTER REQUIREMENT ASSIGNMENT') || trimmed.includes('COMPUTER FOCUS AREA MANAGEMENT') || trimmed.includes('spec-kit'))) {
158
+ verifyIndex = i;
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ if (verifyIndex !== -1) break;
164
+ }
165
+
166
+ if (verifyIndex === -1) {
167
+ // Create TO VERIFY section - place it BEFORE VERIFIED section if one exists, otherwise before CHANGELOG
168
+ const verifiedIndex = lines.findIndex(line => {
169
+ const trimmed = line.trim();
170
+ return trimmed === '## 📝 VERIFIED' || trimmed.startsWith('## 📝 VERIFIED') ||
171
+ (trimmed.startsWith('##') && trimmed.includes('VERIFIED') && !trimmed.includes('TO VERIFY'));
172
+ });
173
+ const changelogIndex = lines.findIndex(line => line.includes('## CHANGELOG'));
174
+ const manualFeedbackIndex = lines.findIndex(line => line.trim().startsWith('## ❓'));
175
+
176
+ // Prefer: before VERIFIED > before CHANGELOG > before manual feedback > at end
177
+ let insertionIndex = lines.length;
178
+ if (verifiedIndex > 0) {
179
+ insertionIndex = verifiedIndex;
180
+ } else if (changelogIndex > 0) {
181
+ insertionIndex = changelogIndex;
182
+ } else if (manualFeedbackIndex > 0) {
183
+ insertionIndex = manualFeedbackIndex;
184
+ }
185
+
186
+ const block = [];
187
+ if (insertionIndex > 0 && lines[insertionIndex - 1].trim() !== '') {
188
+ block.push('');
189
+ }
190
+ block.push('## 🔍 spec-kit: TO VERIFY BY HUMAN', '');
191
+ lines.splice(insertionIndex, 0, ...block);
192
+ verifyIndex = lines.findIndex(line => {
193
+ const trimmed = line.trim();
194
+ return trimmed === '## 🔍 spec-kit: TO VERIFY BY HUMAN' || trimmed.startsWith('## 🔍 spec-kit: TO VERIFY BY HUMAN');
195
+ });
196
+
197
+ // Safety check: verifyIndex should be valid
198
+ if (verifyIndex === -1) {
199
+ console.error(t('auto.direct.verify.section.create.failed'));
200
+ return false;
201
+ }
202
+ }
203
+
204
+ // Safety check: verify we're not inserting into a VERIFIED section
205
+ const verifyLine = lines[verifyIndex] || '';
206
+ if (verifyLine.includes('## 📝 VERIFIED') || (verifyLine.trim().startsWith('##') && verifyLine.includes('VERIFIED') && !verifyLine.includes('TO VERIFY'))) {
207
+ console.error('ERROR: Attempted to insert into VERIFIED section instead of TO VERIFY');
208
+ return false;
209
+ }
210
+
211
+ // Remove any existing duplicate of this requirement in TO VERIFY section
212
+ // Find the next section header after TO VERIFY
213
+ let nextSectionIndex = lines.length;
214
+ for (let i = verifyIndex + 1; i < lines.length; i++) {
215
+ const trimmed = lines[i].trim();
216
+ if (trimmed.startsWith('##') && !trimmed.startsWith('###')) {
217
+ nextSectionIndex = i;
218
+ break;
219
+ }
220
+ }
221
+
222
+ // Search for duplicate requirement in TO VERIFY section
223
+ const requirementTitle = requirementBlock[0].trim().replace(/^###\s*/, '').trim();
224
+ for (let i = verifyIndex + 1; i < nextSectionIndex; i++) {
225
+ const line = lines[i];
226
+ const trimmed = line.trim();
227
+
228
+ if (trimmed.startsWith('###')) {
229
+ const existingTitle = trimmed.replace(/^###\s*/, '').trim();
230
+
231
+ // Check if this is a duplicate (exact match or contains/contained by)
232
+ if (existingTitle === requirementTitle ||
233
+ existingTitle.includes(requirementTitle) ||
234
+ requirementTitle.includes(existingTitle)) {
235
+
236
+ // Find the end of this existing requirement
237
+ let existingEndIndex = nextSectionIndex;
238
+ for (let j = i + 1; j < nextSectionIndex; j++) {
239
+ const nextLine = lines[j].trim();
240
+ if (nextLine.startsWith('###') || nextLine.startsWith('##')) {
241
+ existingEndIndex = j;
242
+ break;
243
+ }
244
+ }
245
+
246
+ // Remove the duplicate
247
+ lines.splice(i, existingEndIndex - i);
248
+
249
+ // Adjust nextSectionIndex if needed
250
+ nextSectionIndex -= (existingEndIndex - i);
251
+ break;
252
+ }
253
+ }
254
+ }
255
+
256
+ // Insert requirement block at TOP of TO VERIFY section (right after section header)
257
+ let insertIndex = verifyIndex + 1;
258
+
259
+ // Ensure there's a blank line after the section header
260
+ if (lines[insertIndex]?.trim() !== '') {
261
+ lines.splice(insertIndex, 0, '');
262
+ insertIndex++;
263
+ }
264
+
265
+ // Insert the requirement block
266
+ lines.splice(insertIndex, 0, ...requirementBlock);
267
+
268
+ // Ensure there's a blank line after the requirement block
269
+ const afterIndex = insertIndex + requirementBlock.length;
270
+ if (afterIndex < lines.length && lines[afterIndex]?.trim() !== '') {
271
+ lines.splice(afterIndex, 0, '');
272
+ }
273
+
274
+ // Write the file
275
+ await fs.writeFile(reqPath, lines.join('\n'));
276
+ console.log(chalk.green(`✅ Moved requirement to TO VERIFY BY HUMAN: ${requirementText.substring(0, 80)}...`));
277
+ return true;
278
+ } catch (err) {
279
+ console.error(t('auto.direct.requirement.move.verify.error'), err.message);
280
+ console.error('⚠️ Requirement may have been lost. Please check the requirements file.');
281
+ return false;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Move requirement to recycled section
287
+ * @param {string} repoPath - Repository path
288
+ * @param {string} requirementText - Requirement text to recycle
289
+ * @returns {Promise<boolean>} - Success status
290
+ */
291
+ async function moveRequirementToRecycle(repoPath, requirementText) {
292
+ try {
293
+ const reqPath = await getRequirementsPath(repoPath);
294
+ if (!reqPath || !await fs.pathExists(reqPath)) {
295
+ return false;
296
+ }
297
+
298
+ let content = await fs.readFile(reqPath, 'utf8');
299
+
300
+ // Find and remove from any section
301
+ const lines = content.split('\n');
302
+ let requirementIndex = -1;
303
+
304
+ for (let i = 0; i < lines.length; i++) {
305
+ if (lines[i].includes(requirementText.substring(0, 50))) {
306
+ requirementIndex = i;
307
+ break;
308
+ }
309
+ }
310
+
311
+ if (requirementIndex === -1) {
312
+ console.log(chalk.yellow(`⚠️ ${t('auto.direct.requirement.not.found')}`));
313
+ return false;
314
+ }
315
+
316
+ // Remove from any section
317
+ const requirementLine = lines[requirementIndex];
318
+ lines.splice(requirementIndex, 1);
319
+
320
+ // Add to Recycled section (after "## ♻️ Recycled")
321
+ let recycledIndex = -1;
322
+ for (let i = 0; i < lines.length; i++) {
323
+ if (lines[i].includes('## ♻️ Recycled')) {
324
+ recycledIndex = i; // Move to the line of the header
325
+ break;
326
+ }
327
+ }
328
+
329
+ if (recycledIndex === -1) {
330
+ lines.push('## ♻️ Recycled');
331
+ recycledIndex = lines.length - 1;
332
+ }
333
+
334
+ // Add timestamp and insert at TOP of Recycled list
335
+ const timestamp = new Date().toISOString().split('T')[0];
336
+ lines.splice(recycledIndex + 1, 0, `- ${timestamp}: ${requirementLine.replace(/^- /, '')}`);
337
+
338
+ // Save
339
+ await fs.writeFile(reqPath, lines.join('\n'));
340
+ return true;
341
+ } catch (err) {
342
+ console.error(t('auto.direct.requirement.move.error'), err.message);
343
+ return false;
344
+ }
345
+ }
346
+
347
+ module.exports = {
348
+ moveRequirementToVerify,
349
+ moveRequirementToRecycle
350
+ };
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Specification Handlers Module
3
+ *
4
+ * This module provides functions for managing and processing specifications,
5
+ * including task counting, task retrieval, and requirement processing.
6
+ *
7
+ * Extracted from auto-direct.js to improve modularity and maintainability.
8
+ */
9
+
10
+ const fs = require('fs-extra');
11
+ const path = require('path');
12
+ const chalk = require('chalk');
13
+
14
+ /**
15
+ * Count checked and total checkboxes in a spec's tasks.md file.
16
+ * @param {string} specPath - Path to the spec directory
17
+ * @returns {{done: number, total: number}} - Checkbox counts
18
+ */
19
+ function countSpecCheckboxes(specPath) {
20
+ try {
21
+ const tasksFile = path.join(specPath, 'tasks.md');
22
+ if (!fs.existsSync(tasksFile)) return { done: 0, total: 0 };
23
+ const content = fs.readFileSync(tasksFile, 'utf8');
24
+ const totalMatches = content.match(/^- \[[ x]\]/gmi) || [];
25
+ const doneMatches = content.match(/^- \[x\]/gmi) || [];
26
+ return { done: doneMatches.length, total: totalMatches.length };
27
+ } catch (_) {
28
+ return { done: 0, total: 0 };
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Get the next unchecked task line from tasks.md.
34
+ * Returns { text, line } or null when all done.
35
+ */
36
+ function getNextSpecTask(specPath) {
37
+ try {
38
+ const tasksFile = path.join(specPath, 'tasks.md');
39
+ if (!fs.existsSync(tasksFile)) return null;
40
+ const content = fs.readFileSync(tasksFile, 'utf8');
41
+ for (const line of content.split('\n')) {
42
+ if (/^- \[ \]/.test(line)) {
43
+ return { text: line.replace(/^- \[ \]\s*/, '').trim(), line: line.trim() };
44
+ }
45
+ }
46
+ return null;
47
+ } catch (_) {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Load all enabled specs that have incomplete tasks (or no tasks.md yet).
54
+ */
55
+ async function loadEnabledIncompleteSpecs(repoPath) {
56
+ try {
57
+ const { getAllSpecifications } = require('vibecodingmachine-core');
58
+ const specs = await getAllSpecifications(repoPath, { skipDisabled: true });
59
+ return specs.filter(spec => {
60
+ if (!spec.hasTasks) return true; // No tasks.md = needs planning + implementation
61
+ const counts = countSpecCheckboxes(spec.path);
62
+ return counts.total === 0 || counts.done < counts.total;
63
+ });
64
+ } catch (err) {
65
+ console.log(chalk.yellow(`⚠️ Error loading specs: ${err.message}`));
66
+ return [];
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Process default requirement until completion
72
+ * @param {RequirementSequencer} sequencer - Requirement sequencer
73
+ * @param {DefaultRequirementManager} defaultManager - Default requirement manager
74
+ * @param {Object} providerConfig - Provider configuration
75
+ * @param {string} repoPath - Repository path
76
+ */
77
+ async function processDefaultRequirement(sequencer, defaultManager, providerConfig, repoPath) {
78
+ const { getRequirementsPath } = require('vibecodingmachine-core');
79
+ const requirementsPath = await getRequirementsPath(repoPath);
80
+ let iterationCount = 0;
81
+
82
+ // Import runIteration from parent module - will be injected when called
83
+ const { runIteration } = require('../auto-direct');
84
+
85
+ while (true) {
86
+ // Check if default requirement should stop
87
+ const shouldStop = await defaultManager.shouldStop();
88
+ if (shouldStop) {
89
+ const status = await defaultManager.getStatus();
90
+ console.log(chalk.bold.green(`\n✅ Default Requirement Complete`));
91
+ console.log(chalk.gray(`Status: ${status.completionReason || 'Completed'}\n`));
92
+ break;
93
+ }
94
+
95
+ // Check if regular requirements were added (should pause default)
96
+ const currentState = await sequencer.getCurrentState(requirementsPath);
97
+ if (currentState.hasRegularRequirements) {
98
+ console.log(chalk.bold.yellow('\n⏸️ Default Requirement Paused'));
99
+ console.log(chalk.gray('New regular requirements detected, pausing default requirement...\n'));
100
+ await defaultManager.pause();
101
+ break;
102
+ }
103
+
104
+ // Get current default requirement status
105
+ const defaultStatus = await defaultManager.getStatus();
106
+ iterationCount = defaultStatus.iterationCount + 1;
107
+
108
+ console.log(chalk.bold.cyan(`\n${'━'.repeat(80)}`));
109
+ console.log(chalk.bold.cyan(` ⭐ DEFAULT REQUIREMENT - Iteration ${iterationCount}/${defaultStatus.maxIterations}`));
110
+ console.log(chalk.bold.cyan(` ${defaultStatus.title}`));
111
+ console.log(chalk.bold.cyan(`${'━'.repeat(80)}\n`));
112
+
113
+ // Create a synthetic requirement object for the default requirement
114
+ const defaultRequirement = {
115
+ text: defaultStatus.description,
116
+ number: iterationCount,
117
+ isDefault: true
118
+ };
119
+
120
+ // Run iteration with default requirement
121
+ const result = await runIteration(defaultRequirement, providerConfig, repoPath);
122
+
123
+ if (result.success) {
124
+ // Increment iteration count
125
+ await defaultManager.incrementIteration();
126
+ console.log(chalk.bold.green(`✅ Default Requirement Iteration ${iterationCount}/${defaultStatus.maxIterations} COMPLETE`));
127
+
128
+ // Small delay between iterations
129
+ await new Promise(resolve => setTimeout(resolve, 3000));
130
+ } else {
131
+ // Record failure
132
+ await defaultManager.recordFailure();
133
+ console.log(chalk.bold.red(`❌ Default Requirement Iteration ${iterationCount}/${defaultStatus.maxIterations} FAILED`));
134
+ console.log(chalk.red(`Error: ${result.error}\n`));
135
+
136
+ // Check consecutive failures
137
+ const updatedStatus = await defaultManager.getStatus();
138
+ if (updatedStatus.consecutiveFailures >= 5) {
139
+ console.log(chalk.bold.yellow('\n⚠️ Maximum consecutive failures reached'));
140
+ await defaultManager.markDone('Stopped due to consecutive failures');
141
+ break;
142
+ }
143
+
144
+ // Delay longer after failure
145
+ await new Promise(resolve => setTimeout(resolve, 5000));
146
+ }
147
+ }
148
+ }
149
+
150
+ module.exports = {
151
+ countSpecCheckboxes,
152
+ getNextSpecTask,
153
+ loadEnabledIncompleteSpecs,
154
+ processDefaultRequirement
155
+ };