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,328 @@
1
+ 'use strict';
2
+
3
+ const { execSync, spawn } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ /**
9
+ * Periodically clicks the Allow/Run approval button in VS Code-based IDEs
10
+ * (github-copilot, amazon-q, kiro) which display approval dialogs in WebViews
11
+ * that AppleScript accessibility cannot reach. Uses Python CGEvent for clicking.
12
+ *
13
+ * Returns a cleanup function that stops the interval.
14
+ */
15
+ function startVSCodeApprovalClicker(providerId, resolvedRef, testMessage) {
16
+ let vsCodeApprovalAttempt = 0;
17
+ let vsCodeApprovalInterval;
18
+
19
+ const clickVSCodeAllow = async () => {
20
+ if (resolvedRef.resolved) { clearInterval(vsCodeApprovalInterval); return; }
21
+ vsCodeApprovalAttempt++;
22
+ console.log(`[AGENT CHECK] ${providerId}: clicking Allow button (attempt ${vsCodeApprovalAttempt})`);
23
+
24
+ // Activate the right app
25
+ const activateScript = providerId === 'kiro'
26
+ ? `tell application "Kiro" to activate`
27
+ : `tell application "Visual Studio Code" to activate`;
28
+ try {
29
+ execSync(`osascript -e '${activateScript}'`, { timeout: 3000, stdio: 'pipe' });
30
+ } catch (_) {}
31
+
32
+ // Kiro: dismiss any "Restore Checkpoint" / confirmation modal that blocks the chat input.
33
+ // These are native buttons accessible via AppleScript accessibility.
34
+ if (providerId === 'kiro') {
35
+ const dismissScript = `
36
+ tell application "System Events"
37
+ tell process "Kiro"
38
+ set btnNames to {"Cancel", "No", "Dismiss", "Close"}
39
+ repeat with w from 1 to count of windows
40
+ try
41
+ repeat with btn in buttons of window w
42
+ try
43
+ if name of btn is in btnNames then
44
+ click btn
45
+ return "dismissed: " & (name of btn)
46
+ end if
47
+ end try
48
+ end repeat
49
+ end try
50
+ end repeat
51
+ end tell
52
+ end tell
53
+ `;
54
+ const dismissFile = path.join(os.tmpdir(), 'kiro_dismiss.scpt');
55
+ fs.writeFileSync(dismissFile, dismissScript);
56
+ try { execSync(`osascript "${dismissFile}"`, { timeout: 4000, stdio: 'pipe' }); } catch (_) {}
57
+ try { fs.unlinkSync(dismissFile); } catch (_) {}
58
+ }
59
+
60
+ // Get window bounds via Python Quartz
61
+ let winBounds = null;
62
+ try {
63
+ const appName = providerId === 'kiro' ? 'Kiro' : 'Code';
64
+ const pyScript = `import Quartz, sys
65
+ windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
66
+ for w in windows:
67
+ if w.get('kCGWindowOwnerName','') == '${appName}':
68
+ b = w.get('kCGWindowBounds',{})
69
+ x,y,w2,h = int(b.get('X',0)),int(b.get('Y',0)),int(b.get('Width',0)),int(b.get('Height',0))
70
+ if w2 > 100:
71
+ print(str(x)+','+str(y)+','+str(w2)+','+str(h))
72
+ sys.exit(0)
73
+ sys.exit(1)
74
+ `;
75
+ const pyFile = path.join(os.tmpdir(), `${providerId}_bounds.py`);
76
+ fs.writeFileSync(pyFile, pyScript);
77
+ const boundsOut = execSync(`python3 "${pyFile}"`, { encoding: 'utf8', timeout: 5000 }).trim();
78
+ try { fs.unlinkSync(pyFile); } catch (_) {}
79
+ if (boundsOut && boundsOut.includes(',')) {
80
+ const nums = boundsOut.match(/-?\d+/g);
81
+ if (nums && nums.length >= 4) {
82
+ const [x, y, w, h] = nums.map(Number);
83
+ if (w > 100) {
84
+ winBounds = { x, y, w, h };
85
+ console.log(`[AGENT CHECK] ${providerId}: window bounds = ${x},${y},${w},${h}`);
86
+ }
87
+ }
88
+ }
89
+ } catch (boundsErr) {
90
+ console.log(`[AGENT CHECK] ${providerId}: bounds error: ${boundsErr.message}`);
91
+ }
92
+
93
+ if (!winBounds) {
94
+ console.log(`[AGENT CHECK] ${providerId}: Could not get window bounds, using full-screen CGEvent coordinate sweep`);
95
+ const fullSweepPy = `
96
+ import Quartz, time
97
+
98
+ def click(x, y):
99
+ e1 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseDown, (x, y), Quartz.kCGMouseButtonLeft)
100
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e1)
101
+ time.sleep(0.04)
102
+ e2 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseUp, (x, y), Quartz.kCGMouseButtonLeft)
103
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e2)
104
+ time.sleep(0.07)
105
+
106
+ for x in [1400, 1500, 1600, 1700, 1200, 1300, 1100]:
107
+ for y in [400, 500, 600, 700, 300, 800]:
108
+ click(x, y)
109
+ `;
110
+ const sweepFile = path.join(os.tmpdir(), `${providerId}_fullsweep.py`);
111
+ fs.writeFileSync(sweepFile, fullSweepPy);
112
+ const sweepChild = spawn('python3', [sweepFile], { detached: true, stdio: 'ignore' });
113
+ sweepChild.on('exit', () => { try { fs.unlinkSync(sweepFile); } catch (_) {} });
114
+ sweepChild.unref();
115
+ return;
116
+ }
117
+
118
+ // Try OCR via screenshot
119
+ let ocrResult = '';
120
+ const screenshotPath = path.join(os.tmpdir(), `${providerId}_allow_${Date.now()}.png`);
121
+ let screenshotOk = false;
122
+ try {
123
+ execSync(`screencapture -x -R ${winBounds.x},${winBounds.y},${winBounds.w},${winBounds.h} "${screenshotPath}"`, { timeout: 5000, stdio: 'pipe' });
124
+ screenshotOk = true;
125
+ } catch (_) {
126
+ console.log(`[AGENT CHECK] ${providerId}: Screenshot failed, using coordinate sweep`);
127
+ }
128
+
129
+ if (screenshotOk) {
130
+ const swiftScript = `
131
+ import Vision
132
+ import AppKit
133
+ import Foundation
134
+ let screenshotPath = "${screenshotPath}"
135
+ let winX: CGFloat = ${winBounds.x}
136
+ let winY: CGFloat = ${winBounds.y}
137
+ let winW: CGFloat = ${winBounds.w}
138
+ let winH: CGFloat = ${winBounds.h}
139
+ guard let img = NSImage(contentsOfFile: screenshotPath),
140
+ let bitmap = img.representations.first as? NSBitmapImageRep,
141
+ let cgImg = bitmap.cgImage else {
142
+ print("ERROR:no-image")
143
+ exit(1)
144
+ }
145
+ let handler = VNImageRequestHandler(cgImage: cgImg, options: [:])
146
+ let request = VNRecognizeTextRequest()
147
+ request.recognitionLevel = .accurate
148
+ try! handler.perform([request])
149
+ for result in request.results ?? [] {
150
+ for candidate in result.topCandidates(1) {
151
+ let lower = candidate.string.lowercased().trimmingCharacters(in: .whitespaces)
152
+ if lower == "allow" || lower == "yes" || lower == "yes, allow" || lower == "yes, allow this time" || lower == "run" || lower == "approve" || lower == "accept" || lower == "apply" || lower == "apply changes" || lower.hasPrefix("run ") || lower == "insert" || lower == "insert code" || lower == "execute" || lower == "confirm" || lower == "proceed" || lower == "ok" || lower == "continue" || lower == "run tool" || lower == "allow all" {
153
+ let box = result.boundingBox
154
+ let centerX = winX + box.midX * winW
155
+ let centerY = winY + (1.0 - box.midY) * winH
156
+ print("FOUND:\\(candidate.string):\\(Int(centerX)):\\(Int(centerY))")
157
+ }
158
+ }
159
+ }
160
+ `;
161
+ const swiftFile = path.join(os.tmpdir(), `${providerId}_allow_ocr.swift`);
162
+ fs.writeFileSync(swiftFile, swiftScript);
163
+ try {
164
+ ocrResult = execSync(`swift "${swiftFile}" 2>/dev/null`, { encoding: 'utf8', timeout: 20000 }).trim();
165
+ } catch (_) {}
166
+ try { fs.unlinkSync(swiftFile); } catch (_) {}
167
+ try { fs.unlinkSync(screenshotPath); } catch (_) {}
168
+
169
+ if (ocrResult && ocrResult.includes('FOUND:')) {
170
+ const lines = ocrResult.split('\n').filter(l => l.startsWith('FOUND:'));
171
+ for (const line of lines) {
172
+ const parts = line.split(':');
173
+ if (parts.length >= 4) {
174
+ const clickX = parseInt(parts[2]);
175
+ const clickY = parseInt(parts[3]);
176
+ if (!isNaN(clickX) && !isNaN(clickY)) {
177
+ console.log(`[AGENT CHECK] ${providerId}: OCR found Allow button at (${clickX}, ${clickY}), clicking via CGEvent`);
178
+ const appToActivate = providerId === 'kiro' ? `tell application "Kiro" to activate` : `tell application "Visual Studio Code" to activate`;
179
+ const activateScriptOcr = `${appToActivate}\ndelay 0.8`;
180
+ const activateFile = path.join(os.tmpdir(), `${providerId}_activate.scpt`);
181
+ fs.writeFileSync(activateFile, activateScriptOcr);
182
+ try { execSync(`osascript "${activateFile}"`, { timeout: 3000, stdio: 'pipe' }); } catch (_) {}
183
+ try { fs.unlinkSync(activateFile); } catch (_) {}
184
+ const dropdownX = clickX + 30;
185
+ const pyScript = `
186
+ import Quartz
187
+ import time
188
+
189
+ def click(x, y):
190
+ e1 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseDown, (x, y), Quartz.kCGMouseButtonLeft)
191
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e1)
192
+ time.sleep(0.05)
193
+ e2 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseUp, (x, y), Quartz.kCGMouseButtonLeft)
194
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e2)
195
+ time.sleep(0.1)
196
+
197
+ # Click the dropdown arrow (▼) first, then Allow All
198
+ click(${dropdownX}, ${clickY})
199
+ time.sleep(0.5)
200
+ click(${dropdownX}, ${clickY})
201
+ time.sleep(0.3)
202
+ # Try allow button at various Y offsets (OCR can be off by up to 10px)
203
+ for dy in [8, 0, -8, 16, -16, 24, -24]:
204
+ click(${clickX}, ${clickY} + dy)
205
+ time.sleep(0.12)
206
+ `;
207
+ const pyFile = path.join(os.tmpdir(), `${providerId}_click.py`);
208
+ fs.writeFileSync(pyFile, pyScript);
209
+ try {
210
+ execSync(`python3 "${pyFile}"`, { timeout: 8000, stdio: 'pipe' });
211
+ } catch (_) {}
212
+ try { fs.unlinkSync(pyFile); } catch (_) {}
213
+ return;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ // For amazon-q: on even-numbered attempts, re-send the test message by clicking the
221
+ // chat input at the bottom of the right panel. The initial send via Cmd+Shift+I may
222
+ // have closed the panel (toggle behavior) causing the paste to land in the editor.
223
+ if (providerId === 'amazon-q' && vsCodeApprovalAttempt % 2 === 0 && testMessage) {
224
+ const inputX = Math.round(winBounds.x + winBounds.w * 0.83);
225
+ const inputY = Math.round(winBounds.y + winBounds.h - 62);
226
+ console.log(`[AGENT CHECK] amazon-q: re-sending via chat input at (${inputX}, ${inputY})`);
227
+ const msgFile = path.join(os.tmpdir(), `amazon_q_msg_${Date.now()}.txt`);
228
+ fs.writeFileSync(msgFile, testMessage, 'utf8');
229
+ const reSendPy = `
230
+ import Quartz, time, subprocess
231
+
232
+ def click(x, y):
233
+ p = (x, y)
234
+ e1 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseDown, p, Quartz.kCGMouseButtonLeft)
235
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e1)
236
+ time.sleep(0.05)
237
+ e2 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseUp, p, Quartz.kCGMouseButtonLeft)
238
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e2)
239
+ time.sleep(0.1)
240
+
241
+ # Click the Amazon Q chat input (bottom of right panel)
242
+ click(${inputX}, ${inputY})
243
+ time.sleep(0.4)
244
+
245
+ # Copy message to clipboard via pbcopy
246
+ with open('${msgFile}', 'r') as f:
247
+ msg = f.read()
248
+ subprocess.run(['pbcopy'], input=msg.encode(), check=True)
249
+ time.sleep(0.2)
250
+
251
+ # Select-all, delete old content, paste new message, Enter
252
+ subprocess.run(['osascript', '-e',
253
+ 'tell application "System Events" to tell process "Code" to keystroke "a" using command down'])
254
+ time.sleep(0.2)
255
+ subprocess.run(['osascript', '-e',
256
+ 'tell application "System Events" to tell process "Code" to key code 51'])
257
+ time.sleep(0.2)
258
+ subprocess.run(['osascript', '-e',
259
+ 'tell application "System Events" to tell process "Code" to key code 9 using {command down}'])
260
+ time.sleep(0.5)
261
+ subprocess.run(['osascript', '-e',
262
+ 'tell application "System Events" to tell process "Code" to key code 36'])
263
+ time.sleep(0.2)
264
+ import os
265
+ try: os.unlink('${msgFile}')
266
+ except: pass
267
+ `;
268
+ const reSendPyFile = path.join(os.tmpdir(), `amazon_q_resend_${Date.now()}.py`);
269
+ fs.writeFileSync(reSendPyFile, reSendPy);
270
+ try {
271
+ execSync(`python3 "${reSendPyFile}"`, { timeout: 12000, stdio: 'pipe' });
272
+ } catch (e) {
273
+ console.log(`[AGENT CHECK] amazon-q: re-send error: ${e.message}`);
274
+ }
275
+ try { fs.unlinkSync(reSendPyFile); } catch (_) {}
276
+ return;
277
+ }
278
+
279
+ // OCR didn't find the button — fall back to CGEvent coordinate sweep
280
+ console.log(`[AGENT CHECK] ${providerId}: OCR did not find Allow button, trying CGEvent coordinate sweep`);
281
+ const activateCmd2 = providerId === 'kiro' ? `tell application "Kiro" to activate` : `tell application "Visual Studio Code" to activate`;
282
+ const activateScpt = path.join(os.tmpdir(), `${providerId}_activate2.scpt`);
283
+ fs.writeFileSync(activateScpt, `${activateCmd2}\ndelay 0.5`);
284
+ try { execSync(`osascript "${activateScpt}"`, { timeout: 3000, stdio: 'pipe' }); } catch (_) {}
285
+ try { fs.unlinkSync(activateScpt); } catch (_) {}
286
+ const xPcts = [0.96, 0.80, 0.87, 0.75, 0.93, 0.65];
287
+ const yPcts = [0.61, 0.50, 0.58, 0.42, 0.65, 0.35, 0.72, 0.68];
288
+ const sweepCoords = [];
289
+ for (const xp of xPcts) {
290
+ for (const yp of yPcts) {
291
+ sweepCoords.push([Math.round(winBounds.x + winBounds.w * xp), Math.round(winBounds.y + winBounds.h * yp)]);
292
+ }
293
+ }
294
+ const fallbackPy = `
295
+ import Quartz
296
+ import time
297
+
298
+ def click(x, y):
299
+ e1 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseDown, (x, y), Quartz.kCGMouseButtonLeft)
300
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e1)
301
+ time.sleep(0.04)
302
+ e2 = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventLeftMouseUp, (x, y), Quartz.kCGMouseButtonLeft)
303
+ Quartz.CGEventPost(Quartz.kCGHIDEventTap, e2)
304
+ time.sleep(0.08)
305
+
306
+ coords = ${JSON.stringify(sweepCoords)}
307
+ for x, y in coords:
308
+ click(x, y)
309
+ `;
310
+ const fallbackPyFile = path.join(os.tmpdir(), `${providerId}_sweep.py`);
311
+ fs.writeFileSync(fallbackPyFile, fallbackPy);
312
+ const approveChild = spawn('python3', [fallbackPyFile], { detached: true, stdio: 'ignore' });
313
+ approveChild.on('exit', () => { try { fs.unlinkSync(fallbackPyFile); } catch (_) {} });
314
+ approveChild.unref();
315
+ };
316
+
317
+ // Start after 15s, then every 12s
318
+ setTimeout(() => {
319
+ if (!resolvedRef.resolved) {
320
+ clickVSCodeAllow();
321
+ vsCodeApprovalInterval = setInterval(clickVSCodeAllow, 12000);
322
+ }
323
+ }, 15000);
324
+
325
+ return () => clearInterval(vsCodeApprovalInterval);
326
+ }
327
+
328
+ module.exports = { startVSCodeApprovalClicker };
@@ -5,10 +5,10 @@ const { checkProvider, checkAllProviders, formatCheckedAt } = require('./provide
5
5
  const { DIRECT_TIMEOUT_MS, IDE_TIMEOUT_MS } = require('./provider-checkers/provider-checker-core');
6
6
 
7
7
  // Re-export the main API
8
- module.exports = {
9
- checkProvider,
10
- checkAllProviders,
11
- formatCheckedAt,
12
- DIRECT_TIMEOUT_MS,
13
- IDE_TIMEOUT_MS
8
+ module.exports = {
9
+ checkProvider,
10
+ checkAllProviders,
11
+ formatCheckedAt,
12
+ DIRECT_TIMEOUT_MS,
13
+ IDE_TIMEOUT_MS
14
14
  };
@@ -6,10 +6,10 @@ const { formatCheckedAt } = require('./provider-checker/time-formatter');
6
6
  const { DIRECT_TIMEOUT_MS, IDE_TIMEOUT_MS } = require('./provider-checker/agent-runner');
7
7
 
8
8
  // Re-export the main API
9
- module.exports = {
10
- checkProvider,
11
- checkAllProviders,
12
- formatCheckedAt,
13
- DIRECT_TIMEOUT_MS,
14
- IDE_TIMEOUT_MS
9
+ module.exports = {
10
+ checkProvider,
11
+ checkAllProviders,
12
+ formatCheckedAt,
13
+ DIRECT_TIMEOUT_MS,
14
+ IDE_TIMEOUT_MS
15
15
  };
@@ -19,15 +19,15 @@ const IDE_INFO = {
19
19
  linux: ['/usr/bin/cursor', '/usr/local/bin/cursor']
20
20
  }
21
21
  },
22
- 'windsurf': {
23
- app: 'Windsurf',
24
- binaryName: 'windsurf',
25
- processName: 'windsurf',
26
- bundleId: 'com.windsurf.Windsurf',
22
+ 'devin': {
23
+ app: 'Devin',
24
+ binaryName: 'devin',
25
+ processName: 'devin',
26
+ bundleId: 'ai.cognition.devin',
27
27
  paths: {
28
- darwin: ['/Applications/Windsurf.app'],
29
- win32: ['C:\\Program Files\\Windsurf\\Windsurf.exe', 'C:\\Program Files (x86)\\Windsurf\\Windsurf.exe'],
30
- linux: ['/usr/bin/windsurf', '/usr/local/bin/windsurf']
28
+ darwin: ['/Applications/Devin.app'],
29
+ win32: ['C:\\Program Files\\Devin\\Devin.exe', 'C:\\Program Files (x86)\\Devin\\Devin.exe'],
30
+ linux: ['/usr/bin/devin', '/usr/local/bin/devin']
31
31
  }
32
32
  },
33
33
  'vscode': {
@@ -70,10 +70,10 @@ function getIdeProcess(providerId) {
70
70
  if (!info) return null;
71
71
 
72
72
  try {
73
- const cmd = process.platform === 'win32'
73
+ const cmd = process.platform === 'win32'
74
74
  ? `tasklist /FI "IMAGENAME eq ${info.binaryName}.exe"`
75
75
  : `ps aux | grep -i "${info.processName}" | grep -v grep`;
76
-
76
+
77
77
  const result = execSync(cmd, { encoding: 'utf8' });
78
78
  return result.trim().length > 0 ? result.trim() : null;
79
79
  } catch {
@@ -97,19 +97,19 @@ async function launchIde(providerId) {
97
97
  try {
98
98
  if (platform === 'darwin') {
99
99
  // macOS: use open command
100
- spawn('open', ['-a', info.app], {
100
+ spawn('open', ['-a', info.app], {
101
101
  stdio: 'ignore',
102
102
  detached: true
103
103
  }).unref();
104
104
  } else if (platform === 'win32') {
105
105
  // Windows: spawn the executable
106
- spawn(idePath, [], {
106
+ spawn(idePath, [], {
107
107
  stdio: 'ignore',
108
108
  detached: true
109
109
  }).unref();
110
110
  } else {
111
111
  // Linux: spawn the binary
112
- spawn(info.binaryName, [], {
112
+ spawn(info.binaryName, [], {
113
113
  stdio: 'ignore',
114
114
  detached: true
115
115
  }).unref();
@@ -13,7 +13,7 @@ function getNodeExecutable() {
13
13
  if (process.env.NODE_BINARY_PATH) {
14
14
  return process.env.NODE_BINARY_PATH;
15
15
  }
16
-
16
+
17
17
  // Try to find node in PATH
18
18
  try {
19
19
  const nodeCmd = process.platform === 'win32' ? 'where node' : 'which node';
@@ -22,7 +22,7 @@ function getNodeExecutable() {
22
22
  return nodePath;
23
23
  }
24
24
  } catch (_) {}
25
-
25
+
26
26
  // Fallback: try common node installation paths
27
27
  const commonPaths = process.platform === 'win32'
28
28
  ? [
@@ -36,13 +36,13 @@ function getNodeExecutable() {
36
36
  '/usr/local/bin/node',
37
37
  '/opt/homebrew/bin/node'
38
38
  ];
39
-
39
+
40
40
  for (const nodePath of commonPaths) {
41
41
  if (nodePath && fs.existsSync(nodePath)) {
42
42
  return nodePath;
43
43
  }
44
44
  }
45
-
45
+
46
46
  // Last resort: use process.execPath (might be electron but worth trying)
47
47
  console.warn('[AGENT CHECK] Could not find node executable, falling back to process.execPath');
48
48
  return process.execPath;
@@ -69,13 +69,13 @@ async function checkProviderReachable(providerId, config, repoPath) {
69
69
  async function done(result) {
70
70
  if (resolved) return;
71
71
  resolved = true;
72
- try {
73
- if (watcher) watcher.close();
72
+ try {
73
+ if (watcher) watcher.close();
74
74
  } catch {}
75
75
  clearTimeout(timeout);
76
76
  clearInterval(cancelCheckInterval);
77
- try {
78
- if (child) child.kill();
77
+ try {
78
+ if (child) child.kill();
79
79
  } catch {}
80
80
  resolve(result);
81
81
  }
@@ -123,7 +123,7 @@ async function checkProviderReachable(providerId, config, repoPath) {
123
123
  try {
124
124
  const nodePath = getNodeExecutable();
125
125
  const args = [CLI_ENTRY_POINT, 'check-provider', providerId];
126
-
126
+
127
127
  child = spawn(nodePath, args, {
128
128
  stdio: 'ignore',
129
129
  env,
@@ -25,12 +25,12 @@ async function checkProvider(providerId, config, repoPath, onProgress, signal) {
25
25
  if (repoPath) {
26
26
  const { getRequirementsPath } = require('vibecodingmachine-core');
27
27
  let reqPath;
28
- try {
29
- reqPath = await getRequirementsPath(repoPath);
28
+ try {
29
+ reqPath = await getRequirementsPath(repoPath);
30
30
  } catch {
31
31
  reqPath = path.join(repoPath, '.vibecodingmachine', 'REQUIREMENTS.md');
32
32
  }
33
-
33
+
34
34
  if (fs.existsSync(reqPath)) {
35
35
  const content = fs.readFileSync(reqPath, 'utf8');
36
36
  if (!content.includes('AGENT_CHECK')) {
@@ -44,10 +44,10 @@ async function checkProvider(providerId, config, repoPath, onProgress, signal) {
44
44
  return result;
45
45
 
46
46
  } catch (error) {
47
- return {
48
- status: 'error',
47
+ return {
48
+ status: 'error',
49
49
  message: `Check failed: ${error.message}`,
50
- error: error.stack
50
+ error: error.stack
51
51
  };
52
52
  }
53
53
  }
@@ -61,7 +61,7 @@ async function checkAllProviders(config, repoPath, onProgress, signal) {
61
61
 
62
62
  for (const id of providerIds) {
63
63
  if (signal?.aborted) break;
64
-
64
+
65
65
  if (onProgress) onProgress(id, 'starting');
66
66
  results[id] = await checkProvider(id, config, repoPath, onProgress, signal);
67
67
  if (onProgress) onProgress(id, 'done', results[id]);
@@ -71,16 +71,16 @@ async function checkAllProviders(config, repoPath, onProgress, signal) {
71
71
  if (repoPath) {
72
72
  const { getRequirementsPath } = require('vibecodingmachine-core');
73
73
  let reqPath;
74
- try {
75
- reqPath = await getRequirementsPath(repoPath);
74
+ try {
75
+ reqPath = await getRequirementsPath(repoPath);
76
76
  } catch {
77
77
  reqPath = path.join(repoPath, '.vibecodingmachine', 'REQUIREMENTS.md');
78
78
  }
79
- try {
80
- removeTestRequirement(reqPath);
79
+ try {
80
+ removeTestRequirement(reqPath);
81
81
  } catch {}
82
- try {
83
- fs.unlinkSync(getResultFilePath(repoPath));
82
+ try {
83
+ fs.unlinkSync(getResultFilePath(repoPath));
84
84
  } catch {}
85
85
  }
86
86
 
@@ -100,8 +100,8 @@ function formatCheckedAt(checkedAt) {
100
100
  return `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()} at ${timePart}`;
101
101
  }
102
102
 
103
- module.exports = {
104
- checkProvider,
105
- checkAllProviders,
106
- formatCheckedAt
103
+ module.exports = {
104
+ checkProvider,
105
+ checkAllProviders,
106
+ formatCheckedAt
107
107
  };
@@ -41,15 +41,14 @@ const PROVIDER_DEFINITIONS = [
41
41
  estimatedSpeed: 35000
42
42
  },
43
43
  {
44
- id: 'windsurf',
45
- name: 'Windsurf IDE Agent',
44
+ id: 'devin',
45
+ name: 'Devin AI Agent',
46
46
  type: 'ide',
47
47
  category: 'ide',
48
- ide: 'windsurf',
48
+ ide: 'devin',
49
49
  defaultModel: 'default',
50
50
  subAgents: [
51
- { id: 'windsurf-default', name: 'Default', model: 'default' },
52
- { id: 'windsurf-swe-1-lite', name: 'SWE-1-lite', model: 'swe-1-lite' }
51
+ { id: 'devin-default', name: 'Default', model: 'default' }
53
52
  ],
54
53
  estimatedSpeed: 90000
55
54
  },
@@ -169,7 +168,7 @@ function getProviderDisplayName(id) {
169
168
  'ollama': 'provider.ollama.name',
170
169
  'lmstudio': 'provider.lmstudio.name',
171
170
  'cursor': 'ide.agent.cursor',
172
- 'windsurf': 'ide.agent.windsurf',
171
+ 'devin': 'ide.agent.devin',
173
172
  'vscode': 'ide.agent.vscode',
174
173
  'cline': 'ide.agent.cline',
175
174
  'claude-code': 'ide.agent.claude.code',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Provider Utils Module
3
- *
3
+ *
4
4
  * Contains utility functions for provider checking.
5
5
  */
6
6
 
@@ -19,7 +19,7 @@ function getNodeExecutable() {
19
19
  if (process.env.NODE_BINARY_PATH) {
20
20
  return process.env.NODE_BINARY_PATH;
21
21
  }
22
-
22
+
23
23
  // Try to find node in PATH
24
24
  try {
25
25
  const nodeCmd = process.platform === 'win32' ? 'where node' : 'which node';
@@ -28,7 +28,7 @@ function getNodeExecutable() {
28
28
  return nodePath;
29
29
  }
30
30
  } catch (_) {}
31
-
31
+
32
32
  // Fallback: try common node installation paths
33
33
  const commonPaths = process.platform === 'win32'
34
34
  ? [
@@ -42,13 +42,13 @@ function getNodeExecutable() {
42
42
  '/usr/local/bin/node',
43
43
  '/opt/homebrew/bin/node'
44
44
  ];
45
-
45
+
46
46
  for (const nodePath of commonPaths) {
47
47
  if (nodePath && fs.existsSync(nodePath)) {
48
48
  return nodePath;
49
49
  }
50
50
  }
51
-
51
+
52
52
  // Last resort: use process.execPath (might be electron but worth trying)
53
53
  console.warn('[AGENT CHECK] Could not find node executable, falling back to process.execPath');
54
54
  return process.execPath;
@@ -66,10 +66,10 @@ function getResultFilePath(repoPath) {
66
66
  */
67
67
  function removeTestRequirement(reqPath) {
68
68
  if (!fs.existsSync(reqPath)) return;
69
-
69
+
70
70
  const content = fs.readFileSync(reqPath, 'utf8');
71
71
  const lines = content.split('\n');
72
-
72
+
73
73
  // Find and remove the test requirement
74
74
  const startIdx = lines.findIndex(line => line.includes('### AGENT CHECK TEST'));
75
75
  if (startIdx !== -1) {
@@ -113,7 +113,7 @@ It will be automatically removed after the check completes.
113
113
  try {
114
114
  // Ensure directory exists
115
115
  fs.mkdirSync(path.dirname(reqPath), { recursive: true });
116
-
116
+
117
117
  // Read existing content
118
118
  let content = '';
119
119
  if (fs.existsSync(reqPath)) {
@@ -121,7 +121,7 @@ It will be automatically removed after the check completes.
121
121
  } else {
122
122
  content = '# Requirements\n\n';
123
123
  }
124
-
124
+
125
125
  // Add test requirement
126
126
  if (!content.includes('### AGENT CHECK TEST')) {
127
127
  content += '\n' + testReq;
@@ -140,10 +140,10 @@ function parseResultFile(resultFile) {
140
140
  if (!fs.existsSync(resultFile)) {
141
141
  return null;
142
142
  }
143
-
143
+
144
144
  const content = fs.readFileSync(resultFile, 'utf8');
145
145
  const lines = content.trim().split('\n');
146
-
146
+
147
147
  // Find the result line (should be the last non-empty line)
148
148
  for (let i = lines.length - 1; i >= 0; i--) {
149
149
  const line = lines[i].trim();
@@ -158,7 +158,7 @@ function parseResultFile(resultFile) {
158
158
  } catch (error) {
159
159
  console.warn('[AGENT CHECK] Error parsing result file:', error.message);
160
160
  }
161
-
161
+
162
162
  return null;
163
163
  }
164
164