vibecodingmachine-cli 2026.3.14-1537 → 2026.6.17-1835

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,485 @@
1
+ /**
2
+ * Iteration Runner - Main Iteration Workflow
3
+ *
4
+ * Extracted from iteration-handlers.js for constitutional compliance (<555 lines per file)
5
+ * Contains the main runIteration function that orchestrates the PREPARE, ACT, CLEAN UP, VERIFY, DONE phases
6
+ */
7
+
8
+ const chalk = require('chalk');
9
+ const fs = require('fs-extra');
10
+ const path = require('path');
11
+ const vibecodingmachineCore = require('vibecodingmachine-core');
12
+ const { DirectLLMManager, t } = vibecodingmachineCore;
13
+
14
+ // Import modular functions
15
+ const { getLogTimestamp } = require('./utils');
16
+ const { moveRequirementToVerify } = require('./requirement-manager');
17
+ const { parseSearchReplaceBlocks, applyFileChange } = require('./code-processor');
18
+ const { findRelevantFiles, readFileSnippets } = require('./file-scanner');
19
+ const { printStatusCard } = require('./status-display');
20
+
21
+ // Import runIdeFallbackIteration from iteration-handlers (to avoid circular dependency)
22
+ let runIdeFallbackIteration = null;
23
+
24
+ // Shared variables set by parent module
25
+ let sharedProviderManager = null;
26
+ let sharedHealthTracker = null;
27
+
28
+ /**
29
+ * Initialize module with shared instances and function references
30
+ */
31
+ function initialize(deps) {
32
+ sharedProviderManager = deps.providerManager;
33
+ sharedHealthTracker = deps.healthTracker;
34
+ runIdeFallbackIteration = deps.runIdeFallbackIteration;
35
+ }
36
+
37
+ /**
38
+ * Run one iteration of autonomous mode with full workflow
39
+ * @param {Object} requirement - Requirement object
40
+ * @param {Object} providerConfig - Provider configuration
41
+ * @param {string} repoPath - Repository path
42
+ * @returns {Promise<{success: boolean, changes?: Array, error?: string}>}
43
+ */
44
+ async function runIteration(requirement, providerConfig, repoPath) {
45
+ const startTime = Date.now();
46
+ const providerManager = sharedProviderManager; // Use shared instance to persist rate limit state
47
+ const llm = new DirectLLMManager(sharedProviderManager); // Pass shared instance
48
+
49
+ if (providerConfig.type === 'ide') {
50
+ return runIdeFallbackIteration(requirement, providerConfig, repoPath, providerManager, llm, startTime);
51
+ }
52
+
53
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
54
+ // PREPARE PHASE - SEARCH AND READ ACTUAL FILES
55
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
56
+ printStatusCard(requirement.text, 'PREPARE', 'active');
57
+
58
+ console.log(chalk.bold.white('=� REQUIREMENT:'));
59
+ console.log(chalk.cyan(` ${requirement.text}\n`));
60
+ console.log(chalk.gray(t('auto.direct.summary.provider')), chalk.white(providerConfig.displayName));
61
+ console.log(chalk.gray(t('auto.repository')), chalk.white(repoPath));
62
+ console.log();
63
+
64
+ console.log(chalk.cyan(`= ${t('auto.direct.files.searching')}...\n`));
65
+ const relevantFiles = await findRelevantFiles(requirement.text, repoPath);
66
+
67
+ if (relevantFiles.length > 0) {
68
+ console.log(chalk.white(`${t('auto.direct.files.found', { count: relevantFiles.length })}:`));
69
+ relevantFiles.forEach((file, i) => {
70
+ console.log(chalk.gray(` ${i + 1}. ${file}`));
71
+ });
72
+ console.log();
73
+ }
74
+
75
+ console.log(chalk.cyan('=� Reading file context...\n'));
76
+ const fileSnippets = await readFileSnippets(relevantFiles, repoPath, requirement.text);
77
+
78
+ await new Promise(resolve => setTimeout(resolve, 500));
79
+
80
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
81
+ // ACT PHASE - GET STRUCTURED CHANGES FROM LLM
82
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
83
+ printStatusCard(requirement.text, 'ACT', 'active');
84
+
85
+ console.log(chalk.cyan(` ${getLogTimestamp()} - > Asking LLM for implementation...\n`));
86
+ console.log(chalk.gray(' '.repeat(80)));
87
+ console.log(chalk.yellow('=� LLM Response (streaming):'));
88
+ console.log(chalk.gray(' '.repeat(80)));
89
+
90
+ // Build context with actual file snippets (use relative paths)
91
+ let contextSection = '';
92
+ if (fileSnippets.length > 0) {
93
+ contextSection = '\n\nCURRENT CODE CONTEXT:\n';
94
+ fileSnippets.forEach(({ file, snippet, startLine }) => {
95
+ // Convert to relative path if absolute
96
+ let displayPath = file;
97
+ if (path.isAbsolute(file)) {
98
+ displayPath = path.relative(repoPath, file);
99
+ }
100
+ contextSection += `\n--- ${displayPath} (around line ${startLine}) ---\n${snippet}\n`;
101
+ });
102
+ }
103
+
104
+ // Check if requirement involves removing menu items or UI elements
105
+ const isRemovalRequirement = /remove|delete|eliminate/i.test(requirement.text) &&
106
+ (/menu|item|option|setting|button|ui|element/i.test(requirement.text));
107
+
108
+ let removalInstructions = '';
109
+ if (isRemovalRequirement) {
110
+ removalInstructions = `
111
+
112
+ � CRITICAL: THIS IS A REMOVAL REQUIREMENT �
113
+
114
+ When removing menu items, UI elements, or settings, you MUST:
115
+
116
+ 1. **FIND ALL OCCURRENCES**: Search the CURRENT CODE CONTEXT for:
117
+ - The exact text/identifier mentioned in the requirement
118
+ - Variations (e.g., "Restart CLI", "restart CLI", "restartCLI", "setting:restart-cli")
119
+ - Both display code (where it's shown) AND handler code (where it's processed)
120
+
121
+ 2. **REMOVE ALL CODE, NOT JUST TOGGLE**:
122
+ - DELETE the code that displays/creates the menu item (e.g., items.push() calls)
123
+ - DELETE the handler code that processes the action (e.g., case 'setting:restart-cli': blocks)
124
+ - DELETE any configuration/state code related to the item (e.g., const restartCLI = ...)
125
+ - DELETE any variable declarations or references to the item
126
+
127
+ 3. **MULTIPLE FILES MAY BE AFFECTED**:
128
+ - If you find references in multiple files, you MUST provide multiple FILE/SEARCH/REPLACE blocks
129
+ - Each file needs its own FILE/SEARCH/REPLACE block
130
+ - Remove ALL occurrences across ALL files shown in the context
131
+
132
+ 4. **VERIFICATION**:
133
+ - After removal, the code should compile/run without errors
134
+ - The removed item should not appear anywhere in the codebase
135
+ - All related handlers and configuration should be removed
136
+
137
+ EXAMPLE for removing "Restart CLI after each completed requirement":
138
+ - Remove: items.push({ type: 'setting', name: \`...Restart CLI...\`, value: 'setting:restart-cli' })
139
+ - Remove: case 'setting:restart-cli': { ... } handler block
140
+ - Remove: const restartCLI = ... variable declaration
141
+ - Remove: Any other references to restartCLI or 'setting:restart-cli'
142
+
143
+ `;
144
+ }
145
+
146
+ const prompt = `You are implementing a code change. Your task is to provide a SEARCH/REPLACE block that will modify the code.
147
+
148
+ REQUIREMENT TO IMPLEMENT:
149
+ ${requirement.text}
150
+ ${removalInstructions}
151
+ ${contextSection}
152
+
153
+ YOUR TASK:
154
+ 1. Read the CURRENT CODE CONTEXT carefully
155
+ 2. Find the EXACT location where changes are needed
156
+ 3. COPY AT LEAST 10 LINES EXACTLY as they appear (including indentation, spacing, comments)
157
+ 4. Show what the code should look like after your changes
158
+ ${isRemovalRequirement ? '5. **REMOVE ALL CODE** related to the item - do NOT comment it out, DELETE it completely' : ''}
159
+
160
+ OUTPUT FORMAT:
161
+
162
+ For modifying existing files:
163
+ FILE: <exact path from the "---" line - must be relative to repo root>
164
+ SEARCH: \`\`\`javascript
165
+ <COPY 10+ lines EXACTLY - preserve indentation, spacing, comments>
166
+ \`\`\`
167
+ REPLACE: \`\`\`javascript
168
+ <SAME lines but with necessary modifications>
169
+ \`\`\`
170
+
171
+ For creating new files:
172
+ CREATE: <relative path to new file>
173
+ CONTENT: \`\`\`javascript
174
+ <full content of new file>
175
+ \`\`\`
176
+
177
+ CRITICAL RULES - READ CAREFULLY:
178
+ 1. If the file does NOT exist, use CREATE: format to create it
179
+ 2. If the file DOES exist and you need to modify it, use FILE:/SEARCH:/REPLACE: format
180
+ 3. For FILE: blocks, SEARCH block must be COPIED CHARACTER-BY-CHARACTER from CURRENT CODE CONTEXT above
181
+ 4. Use the EXACT code as it appears NOW - do NOT use old/outdated code from memory
182
+ 5. Include ALL property values EXACTLY as shown (e.g., if context shows 'type: "info"', use 'type: "info"', NOT 'type: "setting"')
183
+ 6. Include indentation EXACTLY as shown (count the spaces!)
184
+ 7. For modifications, include AT LEAST 20-30 LINES of context:
185
+ - Start 10-15 lines BEFORE the code you need to change
186
+ - End 10-15 lines AFTER the code you need to change
187
+ - MORE context is BETTER than less - include extra lines if unsure
188
+ 8. Do NOT paraphrase or rewrite - COPY EXACTLY from CURRENT CODE CONTEXT
189
+ 9. FILE path must match exactly what's after "---" in CURRENT CODE CONTEXT (DO NOT include the "---" itself)
190
+ 10. All paths must be RELATIVE to repo root (e.g., "specs/005-beta-pricing/tasks.md" NOT "/Users/.../tasks.md")
191
+ 11. Output ONLY the FILE/SEARCH/REPLACE or CREATE/CONTENT blocks
192
+ 12. NO explanations, NO markdown outside the blocks, NO additional text
193
+ 13. If you cannot find the exact code to modify, output: ERROR: CANNOT LOCATE CODE IN CONTEXT
194
+ 14. IMPORTANT: Include ALL intermediate code between the before/after context - do NOT skip lines
195
+ 15. DOUBLE-CHECK: Compare your SEARCH block line-by-line with CURRENT CODE CONTEXT to ensure they match
196
+
197
+ EXAMPLE (notice EXACT copying of indentation and spacing):
198
+
199
+ FILE: packages/cli/src/utils/interactive.js
200
+ SEARCH: \`\`\`javascript
201
+ // Add warning if no TODO requirements
202
+ if (counts.todoCount === 0) {
203
+ requirementsText += \` \${chalk.red('� No requirements to work on')}\`;
204
+ }
205
+ } else {
206
+ requirementsText += \`\${chalk.yellow('0 TODO')}, \${chalk.cyan('0 TO VERIFY')}, \${chalk.green('0 VERIFIED')} \${chalk.red('� No requirements')}\`;
207
+ }
208
+ \`\`\`
209
+ REPLACE: \`\`\`javascript
210
+ // Add warning if no TODO requirements
211
+ if (counts.todoCount === 0) {
212
+ requirementsText += \` \${chalk.red('� No requirements')}\`;
213
+ }
214
+ } else {
215
+ requirementsText += \`\${chalk.yellow('0 TODO')}, \${chalk.cyan('0 TO VERIFY')}, \${chalk.green('0 VERIFIED')} \${chalk.red('� No requirements')}\`;
216
+ }
217
+ \`\`\`
218
+
219
+ CREATE EXAMPLE (for new files):
220
+
221
+ CREATE: packages/web/src/utils/paypal-config.js
222
+ CONTENT: \`\`\`javascript
223
+ /**
224
+ * PayPal Configuration Utility
225
+ */
226
+
227
+ export const getPayPalClientId = () => {
228
+ return import.meta.env.VITE_PAYPAL_CLIENT_ID;
229
+ };
230
+
231
+ export const getPayPalEnvironment = () => {
232
+ return import.meta.env.VITE_PAYPAL_ENVIRONMENT || 'sandbox';
233
+ };
234
+ \`\`\`
235
+
236
+ Now implement the requirement. Remember: For modifications, COPY THE SEARCH BLOCK EXACTLY! For new files, use CREATE: format.`;
237
+
238
+ let fullResponse = '';
239
+ let chunkCount = 0;
240
+ let totalChars = 0;
241
+
242
+ // Show spinner while waiting for first chunk
243
+ const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
244
+ let spinnerIndex = 0;
245
+ let spinnerInterval = null;
246
+ let receivedFirstChunk = false;
247
+
248
+ const startSpinner = () => {
249
+ process.stdout.write(chalk.cyan('� Waiting for response'));
250
+ spinnerInterval = setInterval(() => {
251
+ process.stdout.write(`\r${chalk.cyan('� Waiting for response')} ${chalk.yellow(spinnerFrames[spinnerIndex])}`);
252
+ spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
253
+ }, 100);
254
+ };
255
+
256
+ const stopSpinner = () => {
257
+ if (spinnerInterval) {
258
+ clearInterval(spinnerInterval);
259
+ spinnerInterval = null;
260
+ process.stdout.write('\r\x1b[K'); // Clear the line
261
+ }
262
+ };
263
+
264
+ startSpinner();
265
+
266
+ const result = await llm.call(providerConfig, prompt, {
267
+ temperature: 0.1,
268
+ maxTokens: 4096,
269
+ onChunk: (chunk) => {
270
+ chunkCount++;
271
+ totalChars += chunk.length;
272
+ // Show first chunk arrival to confirm streaming started
273
+ if (chunkCount === 1) {
274
+ stopSpinner();
275
+ receivedFirstChunk = true;
276
+ process.stdout.write(chalk.green(' Streaming started...\n'));
277
+ }
278
+ // Use white text for better visibility instead of gray
279
+ process.stdout.write(chalk.white(chunk));
280
+ fullResponse += chunk;
281
+ },
282
+ onComplete: () => {
283
+ stopSpinner();
284
+ if (chunkCount > 0) {
285
+ console.log(chalk.green(`\n Received ${totalChars} characters in ${chunkCount} chunks`));
286
+ } else {
287
+ console.log(chalk.yellow('\n� No streaming response received (using complete response)'));
288
+ }
289
+ console.log(chalk.gray(' '.repeat(80)));
290
+ console.log();
291
+ },
292
+ onError: (error) => {
293
+ stopSpinner();
294
+ console.error(chalk.red(`\n Error: ${error}`));
295
+ }
296
+ });
297
+
298
+ // Ensure spinner is stopped even if callbacks didn't fire
299
+ stopSpinner();
300
+
301
+ if (!result.success) {
302
+ const combinedError = [result.error, fullResponse].filter(Boolean).join('\n').trim() || 'Unknown error';
303
+ console.log(chalk.red(`\n LLM call failed: ${combinedError}`));
304
+ // CRITICAL: Mark provider as rate-limited for ANY error so acquireProviderConfig() will skip it
305
+ providerManager.markRateLimited(providerConfig.provider, providerConfig.model, combinedError);
306
+
307
+ // Track health metrics for failed direct providers
308
+ const providerType = providerConfig.provider;
309
+ const duration = Date.now() - startTime;
310
+ try {
311
+ // Detect quota/rate limit errors vs other failures
312
+ const quotaPattern = /(quota|rate.?limit|usage.?limit|spending.?cap|allowance|exceeded|overloaded)/i;
313
+ const isQuotaError = quotaPattern.test(combinedError);
314
+
315
+ if (isQuotaError) {
316
+ await sharedHealthTracker.recordQuota(providerType, combinedError, {
317
+ requirementId: requirement.id || requirement.text.substring(0, 50),
318
+ });
319
+ } else {
320
+ await sharedHealthTracker.recordFailure(providerType, combinedError, {
321
+ timeoutUsed: duration,
322
+ requirementId: requirement.id || requirement.text.substring(0, 50),
323
+ });
324
+ }
325
+ } catch (healthError) {
326
+ // Don't fail the iteration if health tracking fails
327
+ console.log(chalk.gray(`� Health tracking error: ${healthError.message}`));
328
+ }
329
+
330
+ return { success: false, error: combinedError };
331
+ }
332
+
333
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
334
+ // CLEAN UP PHASE - APPLY CHANGES TO ACTUAL FILES
335
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
336
+ printStatusCard(requirement.text, 'CLEAN UP', 'active');
337
+
338
+ console.log(chalk.cyan('>� Parsing and applying changes...\n'));
339
+
340
+ // Check if LLM said it cannot locate code
341
+ if (fullResponse.includes('ERROR: CANNOT LOCATE CODE') || fullResponse.includes('CANNOT LOCATE CODE')) {
342
+ console.log(chalk.red('\n LLM could not locate the code to modify'));
343
+ console.log(chalk.yellow('The code context provided may not contain the relevant section\n'));
344
+ return { success: false, error: 'LLM could not locate code in context', changes: [] };
345
+ }
346
+
347
+ const changes = parseSearchReplaceBlocks(fullResponse);
348
+
349
+ if (changes.length === 0) {
350
+ if (fullResponse.includes('NO CHANGES NEEDED')) {
351
+ console.log(chalk.yellow('� LLM determined no code changes needed\n'));
352
+ return { success: false, error: 'No changes needed', changes: [] };
353
+ } else {
354
+ console.log(chalk.yellow('� Could not parse any search/replace blocks from LLM response\n'));
355
+ console.log(chalk.gray('This might be a documentation-only requirement or LLM formatting issue\n'));
356
+ return { success: false, error: 'No search/replace blocks found', changes: [] };
357
+ }
358
+ } else {
359
+ console.log(chalk.white(`Applying ${changes.length} change(s):\n`));
360
+
361
+ let appliedCount = 0;
362
+ let failedCount = 0;
363
+
364
+ for (let i = 0; i < changes.length; i++) {
365
+ const change = changes[i];
366
+ console.log(chalk.cyan(` ${i + 1}. ${change.file}...`));
367
+
368
+ const applyResult = await applyFileChange(change, repoPath);
369
+
370
+ if (applyResult.success) {
371
+ const methodInfo = applyResult.method === 'fuzzy'
372
+ ? ` (fuzzy match at line ${applyResult.matchedAt})`
373
+ : '';
374
+ console.log(chalk.green(` Applied successfully${methodInfo}`));
375
+ appliedCount++;
376
+ } else {
377
+ console.log(chalk.red(` Failed: ${applyResult.error}`));
378
+ failedCount++;
379
+ }
380
+ }
381
+
382
+ console.log();
383
+ console.log(chalk.white(`Applied: ${chalk.green(appliedCount)}, Failed: ${chalk.red(failedCount)}`));
384
+ console.log();
385
+
386
+ // CRITICAL: Fail if no changes were applied successfully
387
+ if (appliedCount === 0 && failedCount > 0) {
388
+ console.log(chalk.bold.red('\nL ITERATION FAILED\n'));
389
+ console.log(chalk.red('No changes were successfully applied'));
390
+ console.log(chalk.yellow('Common causes:'));
391
+ console.log(chalk.gray(' - LLM provided incorrect search text'));
392
+ console.log(chalk.gray(' - Code has changed since context was provided'));
393
+ console.log(chalk.gray(' - File path is incorrect'));
394
+ console.log();
395
+ console.log(chalk.cyan('=� Tip: Check the search block matches the actual code in the file'));
396
+ console.log();
397
+ return { success: false, error: 'No changes applied', changes: [] };
398
+ }
399
+ }
400
+
401
+ await new Promise(resolve => setTimeout(resolve, 500));
402
+
403
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
404
+ // VERIFY PHASE - CONFIRM CHANGES WERE APPLIED
405
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
406
+ printStatusCard(requirement.text, 'VERIFY', 'active');
407
+
408
+ console.log(chalk.cyan(' Verifying changes...\n'));
409
+
410
+ if (changes.length > 0) {
411
+ console.log(chalk.white('Modified files:'));
412
+ for (const change of changes) {
413
+ const fullPath = path.join(repoPath, change.file);
414
+ if (await fs.pathExists(fullPath)) {
415
+ const content = await fs.readFile(fullPath, 'utf8');
416
+
417
+ // Handle both create and modify types
418
+ let hasChange = false;
419
+ if (change.type === 'create') {
420
+ hasChange = change.content && content.includes(change.content.trim());
421
+ } else {
422
+ hasChange = change.replace && content.includes(change.replace.trim());
423
+ }
424
+
425
+ if (hasChange) {
426
+ console.log(chalk.green(` ${change.file}`));
427
+ } else {
428
+ console.log(chalk.yellow(` � ${change.file} (change may not have applied)`));
429
+ }
430
+ }
431
+ }
432
+ console.log();
433
+ }
434
+
435
+ await new Promise(resolve => setTimeout(resolve, 500));
436
+
437
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
438
+ // DONE PHASE
439
+ // PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
440
+ printStatusCard(requirement.text, 'DONE', 'active');
441
+
442
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
443
+
444
+ console.log(chalk.bold.green(` ${t('auto.direct.requirement.completed')}\n`));
445
+ console.log(chalk.white(`${t('auto.direct.requirement.title')}`), chalk.cyan(requirement.text));
446
+ console.log(chalk.white(t('auto.direct.summary.files.modified')), chalk.cyan(changes.length));
447
+ console.log(chalk.white(t('auto.direct.summary.status')), chalk.green(t('auto.direct.summary.moving.to.verify')));
448
+ console.log(chalk.white(t('auto.direct.summary.time')), chalk.gray(`${elapsed}s`));
449
+ console.log();
450
+
451
+ // Move requirement to TO VERIFY section
452
+ const moved = await moveRequirementToVerify(repoPath, requirement.text);
453
+ if (moved) {
454
+ console.log(chalk.green(` ${t('auto.direct.status.verification.pending')}`));
455
+ } else {
456
+ console.log(chalk.yellow('� Could not automatically move requirement'));
457
+ }
458
+
459
+ // Record performance metric
460
+ const duration = Date.now() - startTime;
461
+ providerManager.recordPerformance(providerConfig.provider, providerConfig.model, duration);
462
+
463
+ // Track health metrics for direct providers (IDE providers tracked in runIdeFallbackIteration)
464
+ const providerType = providerConfig.provider;
465
+ try {
466
+ await sharedHealthTracker.recordSuccess(providerType, duration, {
467
+ requirementId: requirement.id || requirement.text.substring(0, 50),
468
+ continuationPromptsDetected: 0,
469
+ });
470
+ } catch (healthError) {
471
+ // Don't fail the iteration if health tracking fails
472
+ console.log(chalk.gray(`� Health tracking error: ${healthError.message}`));
473
+ }
474
+
475
+ console.log();
476
+ console.log(chalk.gray(' '.repeat(80)));
477
+ console.log();
478
+
479
+ return { success: true, changes };
480
+ }
481
+
482
+ module.exports = {
483
+ initialize,
484
+ runIteration
485
+ };
@@ -3,7 +3,7 @@
3
3
  * Extracted from auto-direct.js to reduce file size
4
4
  */
5
5
 
6
- const { getAutoConfig } = require('../../../utils/config');
6
+ const { getAutoConfig } = require('../../utils/config');
7
7
  const { getProviderPreferences, getProviderDefinition, saveProviderPreferences } = require('../../utils/provider-registry');
8
8
  const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
9
9
  const { checkAntigravityRateLimit, handleAntigravityRateLimit } = require('../../utils/antigravity-js-handler');
@@ -13,6 +13,22 @@ const { checkClineRateLimit, handleClineRateLimit } = require('../../utils/cline
13
13
  // CRITICAL: Shared ProviderManager instance to track rate limits across all function calls
14
14
  const sharedProviderManager = new ProviderManager();
15
15
 
16
+ /**
17
+ * Normalize config.providers to a {providerName: configObj} map.
18
+ * Handles both array format [{provider, model, ...}] and object format {name: {...}}.
19
+ */
20
+ function normalizeProvidersMap(rawProviders) {
21
+ if (!rawProviders) return {};
22
+ if (Array.isArray(rawProviders)) {
23
+ const map = {};
24
+ for (const entry of rawProviders) {
25
+ if (entry && entry.provider) map[entry.provider] = entry;
26
+ }
27
+ return map;
28
+ }
29
+ return rawProviders;
30
+ }
31
+
16
32
  /**
17
33
  * Get all available provider configurations
18
34
  */
@@ -23,8 +39,10 @@ async function getAllAvailableProviders() {
23
39
  const providers = [];
24
40
  const skipped = [];
25
41
 
42
+ const providersMap = normalizeProvidersMap(config.providers);
43
+
26
44
  // Check each provider in config
27
- for (const [providerName, providerConfig] of Object.entries(config.providers || {})) {
45
+ for (const [providerName, providerConfig] of Object.entries(providersMap)) {
28
46
  // Skip if provider is disabled in preferences
29
47
  if (prefs.disabled?.includes(providerName)) {
30
48
  skipped.push(providerName);
@@ -130,8 +148,21 @@ async function acquireProviderConfig(excludeProvider = null, excludeModel = null
130
148
  // If a specific provider is forced, bypass normal selection
131
149
  if (forcedProvider) {
132
150
  const { providers } = await getAllAvailableProviders();
133
- const provider = providers.find(p => p.name === forcedProvider);
134
-
151
+ let provider = providers.find(p => p.name === forcedProvider);
152
+
153
+ // Fall back to registry definition for credential-free providers (e.g. claude-code CLI)
154
+ if (!provider) {
155
+ const definition = getProviderDefinition(forcedProvider);
156
+ if (definition && !definition.credentials?.length) {
157
+ provider = {
158
+ name: forcedProvider,
159
+ displayName: definition.displayName || forcedProvider,
160
+ config: {},
161
+ definition
162
+ };
163
+ }
164
+ }
165
+
135
166
  if (!provider) {
136
167
  throw new Error(`Forced provider "${forcedProvider}" not available`);
137
168
  }
@@ -146,16 +177,16 @@ async function acquireProviderConfig(excludeProvider = null, excludeModel = null
146
177
  }
147
178
 
148
179
  const config = await getProviderConfig(excludeProvider);
149
-
180
+
150
181
  // Model selection logic
151
182
  let selectedModel = config.config.model;
152
-
183
+
153
184
  // Exclude specific model if requested
154
185
  if (excludeModel && selectedModel === excludeModel) {
155
186
  // Try alternative models
156
187
  const alternativeModels = config.definition.models || [];
157
188
  const availableModel = alternativeModels.find(m => m !== excludeModel && m !== selectedModel);
158
-
189
+
159
190
  if (availableModel) {
160
191
  selectedModel = availableModel;
161
192
  } else {