vibecodingmachine-core 2025.12.1-534 → 2025.12.22-2230

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.
@@ -72,7 +72,7 @@ class AppleScriptManager {
72
72
  } catch (rerr) {
73
73
  this.logger.log('⚠️ Deterministic: failed to read history before send:', rerr.message || rerr);
74
74
  historyOut = '';
75
- } finally { try { unlinkSync(tmpRead); } catch (e) {} }
75
+ } finally { try { unlinkSync(tmpRead); } catch (e) { } }
76
76
 
77
77
  this.logger.log('🔎 Deterministic: recent history snippet length:', historyOut.length);
78
78
 
@@ -128,7 +128,7 @@ class AppleScriptManager {
128
128
  const tempFile = join(tmpdir(), `claude_direct_${Date.now()}.scpt`);
129
129
  writeFileSync(tempFile, directSendScript, 'utf8');
130
130
  const out = execSync(`osascript "${tempFile}"`, { encoding: 'utf8', timeout: 30000, stdio: 'pipe' }).trim();
131
- try { unlinkSync(tempFile); } catch (e) {}
131
+ try { unlinkSync(tempFile); } catch (e) { }
132
132
 
133
133
  this.logger.log('🔁 Deterministic direct send output:', out);
134
134
  const verified = out.indexOf('|HIST:') !== -1 && out.split('|HIST:')[1].includes(text);
@@ -439,24 +439,24 @@ class AppleScriptManager {
439
439
  }
440
440
  }
441
441
 
442
- this.logger.log(`Executing command: ${command}`);
443
-
444
- // For Windsurf, we don't wait for the command to complete since it runs in background
445
- if (windsurfPath.includes('windsurf')) {
446
- // Use spawn to run in background
447
- const { spawn } = require('child_process');
448
- const windsurfProcess = spawn(windsurfPath, ['--reuse-window', repoPath], {
449
- stdio: 'pipe',
450
- detached: true
451
- });
452
-
453
- // Don't wait for completion, just give it a moment to start
454
- await new Promise(resolve => setTimeout(resolve, 1000));
455
- } else {
456
- execSync(command, { stdio: 'pipe' });
457
- // Wait a moment for Windsurf to start
458
- await new Promise(resolve => setTimeout(resolve, 2000));
459
- }
442
+ this.logger.log(`Executing command: ${command}`);
443
+
444
+ // For Windsurf, we don't wait for the command to complete since it runs in background
445
+ if (windsurfPath.includes('windsurf')) {
446
+ // Use spawn to run in background
447
+ const { spawn } = require('child_process');
448
+ const windsurfProcess = spawn(windsurfPath, ['--reuse-window', repoPath], {
449
+ stdio: 'pipe',
450
+ detached: true
451
+ });
452
+
453
+ // Don't wait for completion, just give it a moment to start
454
+ await new Promise(resolve => setTimeout(resolve, 1000));
455
+ } else {
456
+ execSync(command, { stdio: 'pipe' });
457
+ // Wait a moment for Windsurf to start
458
+ await new Promise(resolve => setTimeout(resolve, 2000));
459
+ }
460
460
 
461
461
  this.logger.log('Windsurf opened successfully');
462
462
  return {
@@ -516,6 +516,52 @@ class AppleScriptManager {
516
516
  }
517
517
  }
518
518
 
519
+ /**
520
+ * Open AWS Kiro IDE with optional repository path
521
+ * @param {string} repoPath - Optional repository path to open
522
+ * @returns {Promise<Object>} Result object with success status and details
523
+ */
524
+ async openKiro(repoPath = null) {
525
+ try {
526
+ this.logger.log('Opening AWS Kiro...');
527
+
528
+ let command = 'open -a "AWS Kiro"';
529
+ if (repoPath) {
530
+ command += ` "${repoPath}"`;
531
+ }
532
+
533
+ try {
534
+ this.logger.log(`Executing command: ${command}`);
535
+ execSync(command, { stdio: 'pipe' });
536
+ } catch (e) {
537
+ // Fallback to just "Kiro"
538
+ this.logger.log('Failed to open "AWS Kiro", trying "Kiro"...');
539
+ command = 'open -a "Kiro"';
540
+ if (repoPath) {
541
+ command += ` "${repoPath}"`;
542
+ }
543
+ execSync(command, { stdio: 'pipe' });
544
+ }
545
+
546
+ // Wait a moment for Kiro to start
547
+ await new Promise(resolve => setTimeout(resolve, 3000));
548
+
549
+ this.logger.log('AWS Kiro opened successfully');
550
+ return {
551
+ success: true,
552
+ message: repoPath ? `AWS Kiro opened with repository: ${repoPath}` : 'AWS Kiro opened successfully',
553
+ method: 'applescript'
554
+ };
555
+ } catch (error) {
556
+ this.logger.log('Error opening AWS Kiro:', error.message);
557
+ return {
558
+ success: false,
559
+ error: error.message,
560
+ method: 'applescript'
561
+ };
562
+ }
563
+ }
564
+
519
565
  /**
520
566
  * Handle Antigravity quota limit by automatically switching models
521
567
  * @returns {Promise<{success: boolean, model?: string, error?: string}>}
@@ -530,11 +576,43 @@ class AppleScriptManager {
530
576
  set frontmost to true
531
577
  delay 0.8
532
578
 
533
- -- Try to find and click "Select another model" button
579
+ -- Try to find model selection button with multiple possible texts
534
580
  try
535
- set modelButtons to buttons of window 1 whose name contains "Select another model"
536
- if (count of modelButtons) > 0 then
537
- click item 1 of modelButtons
581
+ set buttonTexts to {"Select another model", "Switch model", "Change model", "Select model", "Try another model", "Choose model"}
582
+ set foundButton to missing value
583
+
584
+ -- Search for button in window 1
585
+ repeat with buttonText in buttonTexts
586
+ try
587
+ set matchingButtons to buttons of window 1 whose name contains buttonText
588
+ if (count of matchingButtons) > 0 then
589
+ set foundButton to item 1 of matchingButtons
590
+ exit repeat
591
+ end if
592
+ end try
593
+ end repeat
594
+
595
+ -- Also search in groups within window 1
596
+ if foundButton is missing value then
597
+ repeat with buttonText in buttonTexts
598
+ try
599
+ set allGroups to groups of window 1
600
+ repeat with grp in allGroups
601
+ try
602
+ set matchingButtons to buttons of grp whose name contains buttonText
603
+ if (count of matchingButtons) > 0 then
604
+ set foundButton to item 1 of matchingButtons
605
+ exit repeat
606
+ end if
607
+ end try
608
+ end repeat
609
+ if foundButton is not missing value then exit repeat
610
+ end try
611
+ end repeat
612
+ end if
613
+
614
+ if foundButton is not missing value then
615
+ click foundButton
538
616
  delay 1.5
539
617
 
540
618
  -- Look for model dropdown/menu items
@@ -543,20 +621,38 @@ class AppleScriptManager {
543
621
 
544
622
  repeat with modelName in modelNames
545
623
  try
546
- -- Try to find and click this model option
547
- set modelItems to menu items of menu 1 of window 1 whose name is modelName
624
+ -- Try to find and click this model option in various locations
625
+ set modelItems to {}
626
+
627
+ -- Try menu items
628
+ try
629
+ set modelItems to menu items of menu 1 of window 1 whose name is modelName
630
+ end try
631
+
632
+ -- Try buttons if no menu items found
633
+ if (count of modelItems) = 0 then
634
+ try
635
+ set modelItems to buttons of window 1 whose name contains modelName
636
+ end try
637
+ end if
638
+
548
639
  if (count of modelItems) > 0 then
549
640
  click item 1 of modelItems
550
641
  delay 0.8
551
642
 
552
643
  -- Click "Accept all" or similar confirmation button
553
644
  try
554
- set acceptButtons to buttons of window 1 whose name contains "Accept"
555
- if (count of acceptButtons) > 0 then
556
- click item 1 of acceptButtons
557
- delay 0.5
558
- return "success:" & modelName
559
- end if
645
+ set acceptTexts to {"Accept", "OK", "Confirm", "Continue"}
646
+ repeat with acceptText in acceptTexts
647
+ try
648
+ set acceptButtons to buttons of window 1 whose name contains acceptText
649
+ if (count of acceptButtons) > 0 then
650
+ click item 1 of acceptButtons
651
+ delay 0.5
652
+ return "success:" & modelName
653
+ end if
654
+ end try
655
+ end repeat
560
656
  end try
561
657
 
562
658
  return "success:" & modelName
@@ -615,6 +711,8 @@ class AppleScriptManager {
615
711
  return await this.openAntigravity(repoPath);
616
712
  case 'vscode':
617
713
  return await this.openVSCode(repoPath);
714
+ case 'kiro':
715
+ return await this.openKiro(repoPath);
618
716
  case 'claude':
619
717
  return await this.openClaude(repoPath);
620
718
  case 'gemini':
@@ -781,7 +879,7 @@ class AppleScriptManager {
781
879
  };
782
880
  }
783
881
 
784
- const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : ide === 'antigravity' ? 'Antigravity' : ide === 'claude' ? 'Claude' : ide === 'vscode' ? 'VS Code' : 'Unknown IDE';
882
+ const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : ide === 'antigravity' ? 'Antigravity' : ide === 'claude' ? 'Claude' : ide === 'vscode' ? 'VS Code' : ide === 'kiro' ? 'AWS Kiro' : 'Unknown IDE';
785
883
 
786
884
  this.logger.log(`🚀 [${ideName}] Starting text send on ${this.platform} platform`);
787
885
  this.logger.log(`🚀 [${ideName}] Text to send: "${text}"`);
@@ -998,15 +1096,13 @@ class AppleScriptManager {
998
1096
  success: false,
999
1097
  method: 'applescript',
1000
1098
  error: `Invalid text parameter for Claude: received ${typeof text} instead of string`,
1001
- debug: { textType: typeof text, textValue: text }
1099
+ note: 'Text validation failed'
1002
1100
  };
1003
1101
  }
1004
1102
 
1005
- const escapedRepoPath = targetRepoPath.replace(/'/g, "'\\''");
1006
- const findAndSendScript = `
1103
+ const findAndSendToClaudeScript = `
1007
1104
  tell application "Terminal"
1008
1105
  activate
1009
-
1010
1106
  set claudeWindow to null
1011
1107
  set claudeTab to null
1012
1108
  set windowCount to count of windows
@@ -1070,58 +1166,58 @@ class AppleScriptManager {
1070
1166
  const tempFile = join(tmpdir(), `claude_script_${Date.now()}.scpt`);
1071
1167
  writeFileSync(tempFile, findAndSendScript, 'utf8');
1072
1168
 
1073
- let result;
1074
- try {
1075
- result = execSync(`osascript "${tempFile}"`, {
1076
- encoding: 'utf8',
1077
- timeout: 30000, // 30 seconds to allow for window searching and delays
1078
- stdio: 'pipe'
1079
- }).toString().trim();
1080
- } finally {
1081
- // Clean up temp file
1082
- try { unlinkSync(tempFile); } catch (cleanupError) { this.logger.log(`⚠️ [Claude] Failed to cleanup temp file: ${cleanupError.message}`); }
1083
- }
1169
+ let result;
1170
+ try {
1171
+ result = execSync(`osascript "${tempFile}"`, {
1172
+ encoding: 'utf8',
1173
+ timeout: 30000, // 30 seconds to allow for window searching and delays
1174
+ stdio: 'pipe'
1175
+ }).toString().trim();
1176
+ } finally {
1177
+ // Clean up temp file
1178
+ try { unlinkSync(tempFile); } catch (cleanupError) { this.logger.log(`⚠️ [Claude] Failed to cleanup temp file: ${cleanupError.message}`); }
1179
+ }
1180
+
1181
+ this.logger.log(`✅ [Claude] AppleScript execution output:`, result);
1084
1182
 
1085
- this.logger.log(`✅ [Claude] AppleScript execution output:`, result);
1086
-
1087
- // Verify that the sent text appears in the returned history snippet
1088
- try {
1089
- const sentVerified = result && result.indexOf('|HIST:') !== -1 && result.split('|HIST:')[1].includes(`${text}`);
1090
- if (sentVerified) {
1091
- this.logger.log('✅ [Claude] Verified sent text present in terminal history snippet');
1092
- return {
1093
- success: true,
1094
- method: 'applescript',
1095
- message: `Text sent and verified in Claude terminal: ${text}`,
1096
- note: result
1097
- };
1098
- }
1099
- this.logger.log('⚠️ [Claude] Sent text NOT found in terminal history snippet; will attempt deterministic retry');
1100
- } catch (verifyErr) {
1101
- this.logger.log('⚠️ [Claude] Verification parse error:', verifyErr.message || verifyErr);
1183
+ // Verify that the sent text appears in the returned history snippet
1184
+ try {
1185
+ const sentVerified = result && result.indexOf('|HIST:') !== -1 && result.split('|HIST:')[1].includes(`${text}`);
1186
+ if (sentVerified) {
1187
+ this.logger.log('✅ [Claude] Verified sent text present in terminal history snippet');
1188
+ return {
1189
+ success: true,
1190
+ method: 'applescript',
1191
+ message: `Text sent and verified in Claude terminal: ${text}`,
1192
+ note: result
1193
+ };
1102
1194
  }
1195
+ this.logger.log('⚠️ [Claude] Sent text NOT found in terminal history snippet; will attempt deterministic retry');
1196
+ } catch (verifyErr) {
1197
+ this.logger.log('⚠️ [Claude] Verification parse error:', verifyErr.message || verifyErr);
1198
+ }
1103
1199
 
1104
- // If verification failed, attempt a deterministic direct send to window 1 tab 1
1105
- try {
1106
- const det = await this.sendDeterministicToTerminalWindow1(text);
1107
- if (det && det.success) {
1108
- this.logger.log('✅ [Claude] Deterministic retry verified and succeeded');
1109
- return { success: true, method: 'applescript', message: `Text sent to newly opened Claude terminal: ${text}`, note: det.note };
1110
- }
1111
- this.logger.log('⚠️ [Claude] Deterministic retry did not verify:', det && det.note ? det.note : det && det.error ? det.error : det);
1112
- } catch (detErr) {
1113
- this.logger.log('❌ [Claude] Deterministic retry failed:', detErr.message || detErr);
1200
+ // If verification failed, attempt a deterministic direct send to window 1 tab 1
1201
+ try {
1202
+ const det = await this.sendDeterministicToTerminalWindow1(text);
1203
+ if (det && det.success) {
1204
+ this.logger.log('✅ [Claude] Deterministic retry verified and succeeded');
1205
+ return { success: true, method: 'applescript', message: `Text sent to newly opened Claude terminal: ${text}`, note: det.note };
1114
1206
  }
1207
+ this.logger.log('⚠️ [Claude] Deterministic retry did not verify:', det && det.note ? det.note : det && det.error ? det.error : det);
1208
+ } catch (detErr) {
1209
+ this.logger.log('❌ [Claude] Deterministic retry failed:', detErr.message || detErr);
1210
+ }
1115
1211
 
1116
- // CRITICAL FIX: If we reach here, text was sent but not verified
1117
- // Return success anyway since the AppleScript execution succeeded
1118
- this.logger.log('⚠️ [Claude] Text sent but verification inconclusive, returning success');
1119
- return {
1120
- success: true,
1121
- method: 'applescript',
1122
- message: `Text sent to Claude terminal (verification inconclusive): ${text}`,
1123
- note: 'Text sent successfully but verification did not confirm'
1124
- };
1212
+ // CRITICAL FIX: If we reach here, text was sent but not verified
1213
+ // Return success anyway since the AppleScript execution succeeded
1214
+ this.logger.log('⚠️ [Claude] Text sent but verification inconclusive, returning success');
1215
+ return {
1216
+ success: true,
1217
+ method: 'applescript',
1218
+ message: `Text sent to Claude terminal (verification inconclusive): ${text}`,
1219
+ note: 'Text sent successfully but verification did not confirm'
1220
+ };
1125
1221
  } catch (error) {
1126
1222
  this.logger.log('❌ [Claude] AppleScript failed:', error.message);
1127
1223
  return {
@@ -1168,11 +1264,53 @@ class AppleScriptManager {
1168
1264
  end tell
1169
1265
  end tell
1170
1266
  `;
1267
+ } else if (ide === 'kiro') {
1268
+ // AWS Kiro support
1269
+ this.logger.log('🚀 [AWS Kiro] Sending text via AppleScript accessibility (with fallback check)...');
1270
+
1271
+ appleScript = `
1272
+ tell application "System Events"
1273
+ set processName to "AWS Kiro"
1274
+ try
1275
+ if not (exists process "AWS Kiro") then
1276
+ set processName to "Kiro"
1277
+ end if
1278
+ on error
1279
+ set processName to "Kiro"
1280
+ end try
1281
+
1282
+ tell process processName
1283
+ set frontmost to true
1284
+ delay 1.0
1285
+
1286
+ -- Attempt to focus chat via standard AI IDE shortcuts
1287
+ -- Try Cmd+L (Cursor/Windsurf standard)
1288
+ try
1289
+ key code 37 using {command down}
1290
+ delay 0.5
1291
+ on error
1292
+ -- Ignore if fails
1293
+ end try
1294
+
1295
+ -- Use clipboard for more reliable text entry than keystrokes
1296
+ set the clipboard to "${text.replace(/"/g, '\\"')}"
1297
+ delay 0.3
1298
+
1299
+ -- Paste
1300
+ key code 9 using {command down}
1301
+ delay 0.5
1302
+
1303
+ -- Send Enter
1304
+ key code 36
1305
+ delay 0.5
1306
+ end tell
1307
+ end tell
1308
+ `;
1171
1309
  } else {
1172
1310
  return {
1173
1311
  success: false,
1174
1312
  error: `Unsupported IDE for AppleScript: ${ide}`,
1175
- note: 'AppleScript is only supported for Cursor, Windsurf, Antigravity, and VS Code'
1313
+ note: 'AppleScript is only supported for Cursor, Windsurf, Antigravity, VS Code, and AWS Kiro'
1176
1314
  };
1177
1315
  }
1178
1316
 
@@ -1820,14 +1958,14 @@ class AppleScriptManager {
1820
1958
 
1821
1959
  // Check if the result is just diagnostic information
1822
1960
  const isDiagnosticResult = result.includes('DEBUG:') ||
1823
- result.includes('diagnostic') ||
1824
- result.includes('No chat content found') ||
1825
- result.includes('Text areas found: 0') ||
1826
- result.includes('Static text found:') ||
1827
- result.includes('Window count:') ||
1828
- result.includes('Sample text:') ||
1829
- result.includes('Could not read') ||
1830
- result.includes('No readable text content detected');
1961
+ result.includes('diagnostic') ||
1962
+ result.includes('No chat content found') ||
1963
+ result.includes('Text areas found: 0') ||
1964
+ result.includes('Static text found:') ||
1965
+ result.includes('Window count:') ||
1966
+ result.includes('Sample text:') ||
1967
+ result.includes('Could not read') ||
1968
+ result.includes('No readable text content detected');
1831
1969
 
1832
1970
  this.logger.log(`🔍 Diagnostic detection check: isDiagnosticResult = ${isDiagnosticResult}`);
1833
1971
  this.logger.log(`🔍 Result contains 'DEBUG:': ${result.includes('DEBUG:')}`);
@@ -2701,9 +2839,9 @@ end tell
2701
2839
  try {
2702
2840
  // Check for VS Code extension environment variables
2703
2841
  return !!(process.env.VSCODE_PID ||
2704
- process.env.VSCODE_INJECTION ||
2705
- process.env.VSCODE_IPC_HOOK_CLI ||
2706
- (typeof require !== 'undefined' && require.main && require.main.filename.includes('vscode')));
2842
+ process.env.VSCODE_INJECTION ||
2843
+ process.env.VSCODE_IPC_HOOK_CLI ||
2844
+ (typeof require !== 'undefined' && require.main && require.main.filename.includes('vscode')));
2707
2845
  } catch (error) {
2708
2846
  this.logger.log('⚠️ Could not determine VS Code extension context:', error.message);
2709
2847
  return false;
@@ -3,6 +3,25 @@ const { execSync, spawn } = require('child_process');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
+ const chalk = require('chalk');
7
+
8
+ // Rate limit patterns for Claude Code
9
+ const RATE_LIMIT_PATTERNS = [
10
+ /quota limit/i,
11
+ /rate limit/i,
12
+ /too many requests/i,
13
+ /limit exceeded/i,
14
+ /quota: \d+\/\d+/i,
15
+ /you'?ve hit your limit/i,
16
+ /resets? (?:at )?\d+[a-z]{2} \(/i,
17
+ /rate limit reached/i,
18
+ /quota exceeded/i,
19
+ /usage limit reached/i,
20
+ /try again in \d+[mh]\d*[ms]?/i,
21
+ /please try again in/i,
22
+ /session limit reached/i,
23
+ /account limit reached/i
24
+ ];
6
25
 
7
26
  // Helper function for timestamps
8
27
  function getTimestamp() {
@@ -18,6 +37,7 @@ class ClaudeCodeCLIManager {
18
37
  constructor() {
19
38
  this.logger = console;
20
39
  this.runningProcesses = [];
40
+ this.rateLimitInfo = null;
21
41
  }
22
42
 
23
43
  /**
@@ -124,6 +144,14 @@ class ClaudeCodeCLIManager {
124
144
  this.runningProcesses = [];
125
145
  }
126
146
 
147
+ /**
148
+ * Get rate limit information if the last operation was rate limited
149
+ * @returns {{isRateLimited: boolean, resetTime?: Date, message?: string} | null}
150
+ */
151
+ getRateLimitInfo() {
152
+ return this.rateLimitInfo || null;
153
+ }
154
+
127
155
  /**
128
156
  * Send a prompt to Claude Code and wait for completion
129
157
  * @param {string} text - The message/prompt to send
@@ -134,6 +162,61 @@ class ClaudeCodeCLIManager {
134
162
  * @param {number} options.timeoutMs - Timeout in milliseconds (default 300000 = 5 minutes)
135
163
  * @returns {Promise<{success: boolean, output: string, error?: string}>}
136
164
  */
165
+ /**
166
+ * Check if the error indicates a rate limit
167
+ * @param {string} error - The error message
168
+ * @returns {{isRateLimited: boolean, resetTime?: Date, message?: string}}
169
+ */
170
+ checkRateLimit(error) {
171
+ if (!error) return { isRateLimited: false };
172
+
173
+ const lowerError = error.toLowerCase();
174
+
175
+ // Check for rate limit patterns
176
+ const isRateLimited = RATE_LIMIT_PATTERNS.some(pattern =>
177
+ pattern.test(error)
178
+ );
179
+
180
+ if (!isRateLimited) {
181
+ return { isRateLimited: false };
182
+ }
183
+
184
+ // Try to extract reset time if available
185
+ let resetTime;
186
+ // Match patterns like "resets 6am (America/Buenos_Aires)" or "resets at 6am (America/Buenos_Aires)"
187
+ const resetMatch = error.match(/resets? (?:at )?(\d+)(?::(\d+))?\s*([ap]m)?\s*(\([^)]+\))?/i);
188
+ if (resetMatch) {
189
+ try {
190
+ const now = new Date();
191
+ let hours = parseInt(resetMatch[1]);
192
+ const minutes = resetMatch[2] ? parseInt(resetMatch[2]) : 0;
193
+ const period = resetMatch[3] ? resetMatch[3].toLowerCase() : null;
194
+
195
+ // Convert to 24-hour format if period is specified
196
+ if (period === 'pm' && hours < 12) hours += 12;
197
+ if (period === 'am' && hours === 12) hours = 0;
198
+
199
+ // Create reset time
200
+ resetTime = new Date(now);
201
+ resetTime.setHours(hours, minutes, 0, 0);
202
+
203
+ // If reset time is in the past, assume it's for tomorrow
204
+ if (resetTime <= now) {
205
+ resetTime.setDate(resetTime.getDate() + 1);
206
+ }
207
+ } catch (e) {
208
+ console.error('Error parsing reset time:', e);
209
+ resetTime = null;
210
+ }
211
+ }
212
+
213
+ return {
214
+ isRateLimited: true,
215
+ resetTime,
216
+ message: `Rate limit reached${resetTime ? `, resets at ${resetTime.toLocaleString()}` : ''}`
217
+ };
218
+ }
219
+
137
220
  async sendText(text, cwd = process.cwd(), options = {}) {
138
221
  if (!this.isInstalled()) {
139
222
  return {
@@ -220,6 +303,24 @@ class ClaudeCodeCLIManager {
220
303
  const chunkText = chunk.toString();
221
304
  stderr += chunkText;
222
305
 
306
+ // Check for rate limits in stderr
307
+ const rateLimitInfo = this.checkRateLimit(chunkText);
308
+ if (rateLimitInfo.isRateLimited) {
309
+ this.rateLimitInfo = rateLimitInfo;
310
+ console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
311
+
312
+ // If we have a reset time, update the provider manager
313
+ if (rateLimitInfo.resetTime) {
314
+ try {
315
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
316
+ const providerManager = new ProviderManager();
317
+ providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
318
+ } catch (e) {
319
+ console.error('Failed to update rate limit status:', e);
320
+ }
321
+ }
322
+ }
323
+
223
324
  // Only show actual errors
224
325
  if (chunkText.includes('Error:') || chunkText.includes('Failed:') || chunkText.includes('error')) {
225
326
  if (onError) {
@@ -290,9 +391,27 @@ class ClaudeCodeCLIManager {
290
391
  });
291
392
  });
292
393
  } catch (error) {
394
+ // Check if this is a rate limit error
395
+ const rateLimitInfo = this.checkRateLimit(error.message);
396
+ if (rateLimitInfo.isRateLimited) {
397
+ this.rateLimitInfo = rateLimitInfo;
398
+ console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
399
+
400
+ // Update provider manager with rate limit info
401
+ try {
402
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
403
+ const providerManager = new ProviderManager();
404
+ providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
405
+ } catch (e) {
406
+ console.error('Failed to update rate limit status:', e);
407
+ }
408
+ }
409
+
293
410
  return {
294
411
  success: false,
295
- error: error.message
412
+ error: error.message,
413
+ rateLimited: rateLimitInfo.isRateLimited,
414
+ rateLimitInfo: rateLimitInfo.isRateLimited ? rateLimitInfo : undefined
296
415
  };
297
416
  }
298
417
  }