vibecodingmachine-core 2026.3.9-907 → 2026.3.10-1548
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.
- package/package.json +1 -1
- package/src/auth/access-denied.html +119 -119
- package/src/auth/shared-auth-storage.js +267 -267
- package/src/autonomous-mode/feature-implementer.cjs +70 -70
- package/src/autonomous-mode/feature-implementer.js +425 -425
- package/src/beta-request.js +160 -160
- package/src/chat-management/chat-manager.cjs +71 -71
- package/src/chat-management/chat-manager.js +342 -342
- package/src/compliance/compliance-prompt.js +183 -183
- package/src/ide-integration/aider-cli-manager.cjs +850 -850
- package/src/ide-integration/applescript-manager.cjs +3215 -3215
- package/src/ide-integration/applescript-utils.js +314 -314
- package/src/ide-integration/cdp-manager.cjs +221 -221
- package/src/ide-integration/claude-code-cli-manager.cjs +456 -456
- package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
- package/src/ide-integration/continue-cli-manager.js +431 -431
- package/src/ide-integration/provider-manager.cjs +595 -595
- package/src/ide-integration/quota-detector.cjs +399 -399
- package/src/ide-integration/windows-automation-manager.js +532 -4
- package/src/ide-integration/windows-ide-manager.js +12 -3
- package/src/index.cjs +142 -142
- package/src/llm/direct-llm-manager.cjs +1299 -1299
- package/src/localization/index.js +147 -147
- package/src/quota-management/index.js +108 -108
- package/src/requirement-numbering.js +164 -164
- package/src/sync/aws-setup.js +445 -445
- package/src/ui/ButtonComponents.js +247 -247
- package/src/ui/ChatInterface.js +499 -499
- package/src/ui/StateManager.js +259 -259
- package/src/utils/audit-logger.cjs +116 -116
- package/src/utils/config-helpers.cjs +94 -94
- package/src/utils/config-helpers.js +94 -94
- package/src/utils/env-helpers.js +54 -54
- package/src/utils/error-reporter.js +117 -117
- package/src/utils/gcloud-auth.cjs +394 -394
- package/src/utils/git-branch-manager.js +278 -278
- package/src/utils/logger.cjs +193 -193
- package/src/utils/logger.js +191 -191
- package/src/utils/repo-helpers.cjs +120 -120
- package/src/utils/repo-helpers.js +120 -120
- package/src/utils/update-checker.js +246 -246
- package/src/utils/version-checker.js +170 -170
|
@@ -1,456 +1,456 @@
|
|
|
1
|
-
// Claude Code CLI Manager - handles Claude Code CLI execution
|
|
2
|
-
const { execSync, spawn } = require('child_process');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
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
|
-
/spending cap reached/i,
|
|
25
|
-
/resets\s+[a-z]+\s+\d+\s+at\s+\d+[ap]m/i
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
// Helper function for timestamps
|
|
29
|
-
function getTimestamp() {
|
|
30
|
-
const now = new Date();
|
|
31
|
-
return now.toLocaleTimeString('en-US', {
|
|
32
|
-
hour: '2-digit',
|
|
33
|
-
minute: '2-digit',
|
|
34
|
-
hour12: false
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class ClaudeCodeCLIManager {
|
|
39
|
-
constructor() {
|
|
40
|
-
this.logger = console;
|
|
41
|
-
this.runningProcesses = [];
|
|
42
|
-
this.rateLimitInfo = null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Check if Claude Code CLI is installed
|
|
47
|
-
*/
|
|
48
|
-
isInstalled() {
|
|
49
|
-
try {
|
|
50
|
-
execSync('which claude', { stdio: 'pipe' });
|
|
51
|
-
return true;
|
|
52
|
-
} catch {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get Claude Code CLI version
|
|
59
|
-
*/
|
|
60
|
-
getVersion() {
|
|
61
|
-
try {
|
|
62
|
-
const version = execSync('claude --version', { encoding: 'utf8', stdio: 'pipe' });
|
|
63
|
-
return version.trim();
|
|
64
|
-
} catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Install Claude Code CLI
|
|
71
|
-
* @returns {Promise<{success: boolean, error?: string, suggestions?: string[]}>}
|
|
72
|
-
*/
|
|
73
|
-
async install() {
|
|
74
|
-
try {
|
|
75
|
-
console.log('\n📦 Installing Claude Code CLI...\n');
|
|
76
|
-
|
|
77
|
-
// Check if npm is available
|
|
78
|
-
try {
|
|
79
|
-
execSync('which npm', { stdio: 'pipe' });
|
|
80
|
-
} catch {
|
|
81
|
-
return {
|
|
82
|
-
success: false,
|
|
83
|
-
error: 'npm is not installed',
|
|
84
|
-
suggestions: [
|
|
85
|
-
'Install Node.js and npm first:',
|
|
86
|
-
' macOS: brew install node',
|
|
87
|
-
' Linux: sudo apt-get install nodejs npm',
|
|
88
|
-
' Windows: Download from https://nodejs.org/'
|
|
89
|
-
]
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Install Claude Code globally
|
|
94
|
-
console.log('Running: npm install -g @anthropic-ai/claude-code');
|
|
95
|
-
execSync('npm install -g @anthropic-ai/claude-code', {
|
|
96
|
-
stdio: 'inherit',
|
|
97
|
-
encoding: 'utf8'
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Verify installation
|
|
101
|
-
if (this.isInstalled()) {
|
|
102
|
-
const version = this.getVersion();
|
|
103
|
-
console.log(`\n✓ Claude Code CLI installed successfully: ${version}\n`);
|
|
104
|
-
return { success: true };
|
|
105
|
-
} else {
|
|
106
|
-
return {
|
|
107
|
-
success: false,
|
|
108
|
-
error: 'Installation completed but claude command not found',
|
|
109
|
-
suggestions: [
|
|
110
|
-
'Try running: npm install -g @anthropic-ai/claude-code',
|
|
111
|
-
'Make sure your npm global bin directory is in PATH'
|
|
112
|
-
]
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
} catch (error) {
|
|
116
|
-
return {
|
|
117
|
-
success: false,
|
|
118
|
-
error: error.message,
|
|
119
|
-
suggestions: [
|
|
120
|
-
'Try installing manually: npm install -g @anthropic-ai/claude-code',
|
|
121
|
-
'Check if you have permission to install global npm packages',
|
|
122
|
-
'You may need to use: sudo npm install -g @anthropic-ai/claude-code'
|
|
123
|
-
]
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Kill all running Claude Code processes
|
|
130
|
-
*/
|
|
131
|
-
killAllProcesses() {
|
|
132
|
-
for (const proc of this.runningProcesses) {
|
|
133
|
-
try {
|
|
134
|
-
if (!proc.killed) {
|
|
135
|
-
proc.kill('SIGTERM');
|
|
136
|
-
setTimeout(() => {
|
|
137
|
-
if (!proc.killed) {
|
|
138
|
-
proc.kill('SIGKILL');
|
|
139
|
-
}
|
|
140
|
-
}, 1000);
|
|
141
|
-
}
|
|
142
|
-
} catch (err) {
|
|
143
|
-
// Ignore errors
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
this.runningProcesses = [];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Get rate limit information if the last operation was rate limited
|
|
151
|
-
* @returns {{isRateLimited: boolean, resetTime?: Date, message?: string} | null}
|
|
152
|
-
*/
|
|
153
|
-
getRateLimitInfo() {
|
|
154
|
-
return this.rateLimitInfo || null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Send a prompt to Claude Code and wait for completion
|
|
159
|
-
* @param {string} text - The message/prompt to send
|
|
160
|
-
* @param {string} cwd - Path to the repository (working directory)
|
|
161
|
-
* @param {Object} options - Additional options
|
|
162
|
-
* @param {Function} options.onOutput - Optional callback for output
|
|
163
|
-
* @param {Function} options.onError - Optional callback for errors
|
|
164
|
-
* @param {number} options.timeoutMs - Timeout in milliseconds (default 300000 = 5 minutes)
|
|
165
|
-
* @returns {Promise<{success: boolean, output: string, error?: string}>}
|
|
166
|
-
*/
|
|
167
|
-
/**
|
|
168
|
-
* Check if the error indicates a rate limit
|
|
169
|
-
* @param {string} error - The error message
|
|
170
|
-
* @returns {{isRateLimited: boolean, resetTime?: Date, message?: string}}
|
|
171
|
-
*/
|
|
172
|
-
checkRateLimit(error) {
|
|
173
|
-
if (!error) return { isRateLimited: false };
|
|
174
|
-
|
|
175
|
-
const lowerError = error.toLowerCase();
|
|
176
|
-
|
|
177
|
-
// Check for rate limit patterns
|
|
178
|
-
const isRateLimited = RATE_LIMIT_PATTERNS.some(pattern =>
|
|
179
|
-
pattern.test(error)
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
if (!isRateLimited) {
|
|
183
|
-
return { isRateLimited: false };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Try to extract reset time if available
|
|
187
|
-
let resetTime;
|
|
188
|
-
// Match patterns like "resets Mar 9 at 6pm" or "resets at 6pm"
|
|
189
|
-
const resetMatch = error.match(/resets?\s+(?:([a-z]+\s+\d+)\s+at\s+)?(\d+)(?::(\d+))?\s*([ap]m)?\s*(\([^)]*\))?/i);
|
|
190
|
-
if (resetMatch) {
|
|
191
|
-
try {
|
|
192
|
-
const now = new Date();
|
|
193
|
-
const monthDay = resetMatch[1]; // "Mar 9" or undefined
|
|
194
|
-
let hours = parseInt(resetMatch[2]);
|
|
195
|
-
const minutes = resetMatch[3] ? parseInt(resetMatch[3]) : 0;
|
|
196
|
-
const period = resetMatch[4] ? resetMatch[4].toLowerCase() : null;
|
|
197
|
-
|
|
198
|
-
// Convert to 24-hour format if period is specified
|
|
199
|
-
if (period === 'pm' && hours < 12) hours += 12;
|
|
200
|
-
if (period === 'am' && hours === 12) hours = 0;
|
|
201
|
-
|
|
202
|
-
// Create reset date
|
|
203
|
-
const resetDate = new Date(now);
|
|
204
|
-
resetDate.setHours(hours, minutes, 0, 0);
|
|
205
|
-
|
|
206
|
-
// If month/day is specified, set it
|
|
207
|
-
if (monthDay) {
|
|
208
|
-
const monthDayMatch = monthDay.match(/([a-z]+)\s+(\d+)/i);
|
|
209
|
-
if (monthDayMatch) {
|
|
210
|
-
const monthStr = monthDayMatch[1];
|
|
211
|
-
const day = parseInt(monthDayMatch[2]);
|
|
212
|
-
const months = {
|
|
213
|
-
jan: 0, january: 0,
|
|
214
|
-
feb: 1, february: 1,
|
|
215
|
-
mar: 2, march: 2,
|
|
216
|
-
apr: 3, april: 3,
|
|
217
|
-
may: 4,
|
|
218
|
-
jun: 5, june: 5,
|
|
219
|
-
jul: 6, july: 6,
|
|
220
|
-
aug: 7, august: 7,
|
|
221
|
-
sep: 8, sept: 8, september: 8,
|
|
222
|
-
oct: 9, october: 9,
|
|
223
|
-
nov: 10, november: 10,
|
|
224
|
-
dec: 11, december: 11
|
|
225
|
-
};
|
|
226
|
-
const monthIndex = months[monthStr.toLowerCase().substring(0, 3)];
|
|
227
|
-
if (monthIndex !== undefined) {
|
|
228
|
-
resetDate.setMonth(monthIndex, day);
|
|
229
|
-
// If the date is in the past, assume it's next month
|
|
230
|
-
if (resetDate < now) {
|
|
231
|
-
resetDate.setMonth(resetDate.getMonth() + 1);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
// If no month/day specified and time is in the past, assume tomorrow
|
|
237
|
-
if (resetDate <= now) {
|
|
238
|
-
resetDate.setDate(resetDate.getDate() + 1);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
resetTime = resetDate;
|
|
243
|
-
} catch (e) {
|
|
244
|
-
console.error('Error parsing reset time:', e);
|
|
245
|
-
resetTime = null;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
isRateLimited: true,
|
|
251
|
-
resetTime,
|
|
252
|
-
message: `Rate limit reached${resetTime ? `, resets at ${resetTime.toLocaleString()}` : ''}`
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async sendText(text, cwd = process.cwd(), options = {}) {
|
|
257
|
-
if (!this.isInstalled()) {
|
|
258
|
-
return {
|
|
259
|
-
success: false,
|
|
260
|
-
error: 'Claude Code CLI is not installed. Run install() first.',
|
|
261
|
-
needsInstall: true
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
const { onOutput, onError, timeoutMs = 300000 } = options;
|
|
267
|
-
|
|
268
|
-
return new Promise((resolve) => {
|
|
269
|
-
const startTime = Date.now();
|
|
270
|
-
let stdout = '';
|
|
271
|
-
let stderr = '';
|
|
272
|
-
let completed = false;
|
|
273
|
-
let timeoutKilled = false;
|
|
274
|
-
let lastOutputTime = Date.now();
|
|
275
|
-
|
|
276
|
-
// Spawn Claude Code in the repository directory
|
|
277
|
-
const proc = spawn('claude', ['code'], {
|
|
278
|
-
cwd: cwd,
|
|
279
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
280
|
-
env: { ...process.env }
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
this.runningProcesses.push(proc);
|
|
284
|
-
|
|
285
|
-
// Status update interval - show progress every 10 seconds if no output
|
|
286
|
-
const statusInterval = setInterval(() => {
|
|
287
|
-
const timeSinceOutput = (Date.now() - lastOutputTime) / 1000;
|
|
288
|
-
if (timeSinceOutput > 10) {
|
|
289
|
-
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
|
290
|
-
const chalk = require('chalk');
|
|
291
|
-
const timestamp = getTimestamp();
|
|
292
|
-
console.log(chalk.yellow(`[${timestamp}] [CLAUDE] Still waiting... (${elapsed}s elapsed, ${timeSinceOutput.toFixed(0)}s since last output)`));
|
|
293
|
-
}
|
|
294
|
-
}, 10000);
|
|
295
|
-
|
|
296
|
-
// Hard timeout - kill process if it runs too long
|
|
297
|
-
const hardTimeout = setTimeout(() => {
|
|
298
|
-
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
|
299
|
-
const chalk = require('chalk');
|
|
300
|
-
const timestamp = getTimestamp();
|
|
301
|
-
console.log(chalk.red(`\n[${timestamp}] ⏰ TIMEOUT: Claude Code process exceeded ${timeoutMs/1000}s limit (ran for ${elapsed}s)`));
|
|
302
|
-
console.log(chalk.red(`[${timestamp}] Killing Claude Code process to prevent hanging...`));
|
|
303
|
-
timeoutKilled = true;
|
|
304
|
-
completed = true;
|
|
305
|
-
clearInterval(statusInterval);
|
|
306
|
-
proc.kill('SIGTERM');
|
|
307
|
-
setTimeout(() => proc.kill('SIGKILL'), 2000); // Force kill after 2s
|
|
308
|
-
}, timeoutMs);
|
|
309
|
-
|
|
310
|
-
// Handle stdout
|
|
311
|
-
proc.stdout.on('data', (chunk) => {
|
|
312
|
-
const chunkText = chunk.toString();
|
|
313
|
-
stdout += chunkText;
|
|
314
|
-
lastOutputTime = Date.now();
|
|
315
|
-
|
|
316
|
-
// Filter and show useful output
|
|
317
|
-
const lines = chunkText.split('\n');
|
|
318
|
-
for (const line of lines) {
|
|
319
|
-
const trimmed = line.trim();
|
|
320
|
-
if (!trimmed) continue;
|
|
321
|
-
|
|
322
|
-
// Call output callback if provided
|
|
323
|
-
if (onOutput) {
|
|
324
|
-
onOutput(line + '\n');
|
|
325
|
-
} else {
|
|
326
|
-
// Fallback: write directly to stdout
|
|
327
|
-
try {
|
|
328
|
-
const chalk = require('chalk');
|
|
329
|
-
process.stdout.write(chalk.gray(line + '\n'));
|
|
330
|
-
} catch {
|
|
331
|
-
process.stdout.write(line + '\n');
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// Handle stderr
|
|
338
|
-
proc.stderr.on('data', (chunk) => {
|
|
339
|
-
const chunkText = chunk.toString();
|
|
340
|
-
stderr += chunkText;
|
|
341
|
-
|
|
342
|
-
// Check for rate limits in stderr
|
|
343
|
-
const rateLimitInfo = this.checkRateLimit(chunkText);
|
|
344
|
-
if (rateLimitInfo.isRateLimited) {
|
|
345
|
-
this.rateLimitInfo = rateLimitInfo;
|
|
346
|
-
console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
|
|
347
|
-
|
|
348
|
-
// If we have a reset time, update the provider manager
|
|
349
|
-
if (rateLimitInfo.resetTime) {
|
|
350
|
-
try {
|
|
351
|
-
const ProviderManager = require('../ide-integration/provider-manager.cjs');
|
|
352
|
-
const providerManager = new ProviderManager();
|
|
353
|
-
providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
|
|
354
|
-
} catch (e) {
|
|
355
|
-
console.error('Failed to update rate limit status:', e);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Only show actual errors
|
|
361
|
-
if (chunkText.includes('Error:') || chunkText.includes('Failed:') || chunkText.includes('error')) {
|
|
362
|
-
if (onError) {
|
|
363
|
-
onError(chunkText.trim());
|
|
364
|
-
} else {
|
|
365
|
-
this.logger.error('[Claude Code Error]', chunkText.trim());
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
// Send the message and close stdin
|
|
371
|
-
proc.stdin.write(text + '\n');
|
|
372
|
-
proc.stdin.end();
|
|
373
|
-
|
|
374
|
-
// Handle process exit
|
|
375
|
-
proc.on('close', (code) => {
|
|
376
|
-
// Remove process from tracking array
|
|
377
|
-
const index = this.runningProcesses.indexOf(proc);
|
|
378
|
-
if (index > -1) {
|
|
379
|
-
this.runningProcesses.splice(index, 1);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
clearInterval(statusInterval);
|
|
383
|
-
clearTimeout(hardTimeout);
|
|
384
|
-
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
385
|
-
const chalk = require('chalk');
|
|
386
|
-
const timestamp = getTimestamp();
|
|
387
|
-
|
|
388
|
-
if (timeoutKilled) {
|
|
389
|
-
console.log(chalk.red(`[${timestamp}] [CLAUDE] Process killed due to timeout after ${elapsed}s`));
|
|
390
|
-
resolve({
|
|
391
|
-
success: false,
|
|
392
|
-
output: stdout,
|
|
393
|
-
error: 'Timeout: Process exceeded maximum execution time',
|
|
394
|
-
exitCode: -1,
|
|
395
|
-
timeout: true
|
|
396
|
-
});
|
|
397
|
-
} else if (code === 0) {
|
|
398
|
-
console.log(chalk.gray(`[${timestamp}] [CLAUDE] Process completed after ${elapsed}s with code: ${code}`));
|
|
399
|
-
resolve({
|
|
400
|
-
success: true,
|
|
401
|
-
output: stdout,
|
|
402
|
-
stderr: stderr,
|
|
403
|
-
exitCode: code
|
|
404
|
-
});
|
|
405
|
-
} else {
|
|
406
|
-
console.log(chalk.gray(`[${timestamp}] [CLAUDE] Process closed after ${elapsed}s with code: ${code}`));
|
|
407
|
-
resolve({
|
|
408
|
-
success: false,
|
|
409
|
-
output: stdout,
|
|
410
|
-
error: stderr || `Process exited with code ${code}`,
|
|
411
|
-
exitCode: code
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
proc.on('error', (error) => {
|
|
417
|
-
clearInterval(statusInterval);
|
|
418
|
-
clearTimeout(hardTimeout);
|
|
419
|
-
completed = true;
|
|
420
|
-
const timestamp = getTimestamp();
|
|
421
|
-
console.log(`\n[${timestamp}] ✗ Claude Code error: ${error.message}`);
|
|
422
|
-
resolve({
|
|
423
|
-
success: false,
|
|
424
|
-
error: error.message,
|
|
425
|
-
exitCode: -1
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
});
|
|
429
|
-
} catch (error) {
|
|
430
|
-
// Check if this is a rate limit error
|
|
431
|
-
const rateLimitInfo = this.checkRateLimit(error.message);
|
|
432
|
-
if (rateLimitInfo.isRateLimited) {
|
|
433
|
-
this.rateLimitInfo = rateLimitInfo;
|
|
434
|
-
console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
|
|
435
|
-
|
|
436
|
-
// Update provider manager with rate limit info
|
|
437
|
-
try {
|
|
438
|
-
const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
|
|
439
|
-
const providerManager = new ProviderManager();
|
|
440
|
-
providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
|
|
441
|
-
} catch (e) {
|
|
442
|
-
console.error('Failed to update rate limit status:', e);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return {
|
|
447
|
-
success: false,
|
|
448
|
-
error: error.message,
|
|
449
|
-
rateLimited: rateLimitInfo.isRateLimited,
|
|
450
|
-
rateLimitInfo: rateLimitInfo.isRateLimited ? rateLimitInfo : undefined
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
module.exports = ClaudeCodeCLIManager;
|
|
1
|
+
// Claude Code CLI Manager - handles Claude Code CLI execution
|
|
2
|
+
const { execSync, spawn } = require('child_process');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
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
|
+
/spending cap reached/i,
|
|
25
|
+
/resets\s+[a-z]+\s+\d+\s+at\s+\d+[ap]m/i
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Helper function for timestamps
|
|
29
|
+
function getTimestamp() {
|
|
30
|
+
const now = new Date();
|
|
31
|
+
return now.toLocaleTimeString('en-US', {
|
|
32
|
+
hour: '2-digit',
|
|
33
|
+
minute: '2-digit',
|
|
34
|
+
hour12: false
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class ClaudeCodeCLIManager {
|
|
39
|
+
constructor() {
|
|
40
|
+
this.logger = console;
|
|
41
|
+
this.runningProcesses = [];
|
|
42
|
+
this.rateLimitInfo = null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if Claude Code CLI is installed
|
|
47
|
+
*/
|
|
48
|
+
isInstalled() {
|
|
49
|
+
try {
|
|
50
|
+
execSync('which claude', { stdio: 'pipe' });
|
|
51
|
+
return true;
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get Claude Code CLI version
|
|
59
|
+
*/
|
|
60
|
+
getVersion() {
|
|
61
|
+
try {
|
|
62
|
+
const version = execSync('claude --version', { encoding: 'utf8', stdio: 'pipe' });
|
|
63
|
+
return version.trim();
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Install Claude Code CLI
|
|
71
|
+
* @returns {Promise<{success: boolean, error?: string, suggestions?: string[]}>}
|
|
72
|
+
*/
|
|
73
|
+
async install() {
|
|
74
|
+
try {
|
|
75
|
+
console.log('\n📦 Installing Claude Code CLI...\n');
|
|
76
|
+
|
|
77
|
+
// Check if npm is available
|
|
78
|
+
try {
|
|
79
|
+
execSync('which npm', { stdio: 'pipe' });
|
|
80
|
+
} catch {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: 'npm is not installed',
|
|
84
|
+
suggestions: [
|
|
85
|
+
'Install Node.js and npm first:',
|
|
86
|
+
' macOS: brew install node',
|
|
87
|
+
' Linux: sudo apt-get install nodejs npm',
|
|
88
|
+
' Windows: Download from https://nodejs.org/'
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Install Claude Code globally
|
|
94
|
+
console.log('Running: npm install -g @anthropic-ai/claude-code');
|
|
95
|
+
execSync('npm install -g @anthropic-ai/claude-code', {
|
|
96
|
+
stdio: 'inherit',
|
|
97
|
+
encoding: 'utf8'
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Verify installation
|
|
101
|
+
if (this.isInstalled()) {
|
|
102
|
+
const version = this.getVersion();
|
|
103
|
+
console.log(`\n✓ Claude Code CLI installed successfully: ${version}\n`);
|
|
104
|
+
return { success: true };
|
|
105
|
+
} else {
|
|
106
|
+
return {
|
|
107
|
+
success: false,
|
|
108
|
+
error: 'Installation completed but claude command not found',
|
|
109
|
+
suggestions: [
|
|
110
|
+
'Try running: npm install -g @anthropic-ai/claude-code',
|
|
111
|
+
'Make sure your npm global bin directory is in PATH'
|
|
112
|
+
]
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: error.message,
|
|
119
|
+
suggestions: [
|
|
120
|
+
'Try installing manually: npm install -g @anthropic-ai/claude-code',
|
|
121
|
+
'Check if you have permission to install global npm packages',
|
|
122
|
+
'You may need to use: sudo npm install -g @anthropic-ai/claude-code'
|
|
123
|
+
]
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Kill all running Claude Code processes
|
|
130
|
+
*/
|
|
131
|
+
killAllProcesses() {
|
|
132
|
+
for (const proc of this.runningProcesses) {
|
|
133
|
+
try {
|
|
134
|
+
if (!proc.killed) {
|
|
135
|
+
proc.kill('SIGTERM');
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
if (!proc.killed) {
|
|
138
|
+
proc.kill('SIGKILL');
|
|
139
|
+
}
|
|
140
|
+
}, 1000);
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
// Ignore errors
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
this.runningProcesses = [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get rate limit information if the last operation was rate limited
|
|
151
|
+
* @returns {{isRateLimited: boolean, resetTime?: Date, message?: string} | null}
|
|
152
|
+
*/
|
|
153
|
+
getRateLimitInfo() {
|
|
154
|
+
return this.rateLimitInfo || null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Send a prompt to Claude Code and wait for completion
|
|
159
|
+
* @param {string} text - The message/prompt to send
|
|
160
|
+
* @param {string} cwd - Path to the repository (working directory)
|
|
161
|
+
* @param {Object} options - Additional options
|
|
162
|
+
* @param {Function} options.onOutput - Optional callback for output
|
|
163
|
+
* @param {Function} options.onError - Optional callback for errors
|
|
164
|
+
* @param {number} options.timeoutMs - Timeout in milliseconds (default 300000 = 5 minutes)
|
|
165
|
+
* @returns {Promise<{success: boolean, output: string, error?: string}>}
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* Check if the error indicates a rate limit
|
|
169
|
+
* @param {string} error - The error message
|
|
170
|
+
* @returns {{isRateLimited: boolean, resetTime?: Date, message?: string}}
|
|
171
|
+
*/
|
|
172
|
+
checkRateLimit(error) {
|
|
173
|
+
if (!error) return { isRateLimited: false };
|
|
174
|
+
|
|
175
|
+
const lowerError = error.toLowerCase();
|
|
176
|
+
|
|
177
|
+
// Check for rate limit patterns
|
|
178
|
+
const isRateLimited = RATE_LIMIT_PATTERNS.some(pattern =>
|
|
179
|
+
pattern.test(error)
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (!isRateLimited) {
|
|
183
|
+
return { isRateLimited: false };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Try to extract reset time if available
|
|
187
|
+
let resetTime;
|
|
188
|
+
// Match patterns like "resets Mar 9 at 6pm" or "resets at 6pm"
|
|
189
|
+
const resetMatch = error.match(/resets?\s+(?:([a-z]+\s+\d+)\s+at\s+)?(\d+)(?::(\d+))?\s*([ap]m)?\s*(\([^)]*\))?/i);
|
|
190
|
+
if (resetMatch) {
|
|
191
|
+
try {
|
|
192
|
+
const now = new Date();
|
|
193
|
+
const monthDay = resetMatch[1]; // "Mar 9" or undefined
|
|
194
|
+
let hours = parseInt(resetMatch[2]);
|
|
195
|
+
const minutes = resetMatch[3] ? parseInt(resetMatch[3]) : 0;
|
|
196
|
+
const period = resetMatch[4] ? resetMatch[4].toLowerCase() : null;
|
|
197
|
+
|
|
198
|
+
// Convert to 24-hour format if period is specified
|
|
199
|
+
if (period === 'pm' && hours < 12) hours += 12;
|
|
200
|
+
if (period === 'am' && hours === 12) hours = 0;
|
|
201
|
+
|
|
202
|
+
// Create reset date
|
|
203
|
+
const resetDate = new Date(now);
|
|
204
|
+
resetDate.setHours(hours, minutes, 0, 0);
|
|
205
|
+
|
|
206
|
+
// If month/day is specified, set it
|
|
207
|
+
if (monthDay) {
|
|
208
|
+
const monthDayMatch = monthDay.match(/([a-z]+)\s+(\d+)/i);
|
|
209
|
+
if (monthDayMatch) {
|
|
210
|
+
const monthStr = monthDayMatch[1];
|
|
211
|
+
const day = parseInt(monthDayMatch[2]);
|
|
212
|
+
const months = {
|
|
213
|
+
jan: 0, january: 0,
|
|
214
|
+
feb: 1, february: 1,
|
|
215
|
+
mar: 2, march: 2,
|
|
216
|
+
apr: 3, april: 3,
|
|
217
|
+
may: 4,
|
|
218
|
+
jun: 5, june: 5,
|
|
219
|
+
jul: 6, july: 6,
|
|
220
|
+
aug: 7, august: 7,
|
|
221
|
+
sep: 8, sept: 8, september: 8,
|
|
222
|
+
oct: 9, october: 9,
|
|
223
|
+
nov: 10, november: 10,
|
|
224
|
+
dec: 11, december: 11
|
|
225
|
+
};
|
|
226
|
+
const monthIndex = months[monthStr.toLowerCase().substring(0, 3)];
|
|
227
|
+
if (monthIndex !== undefined) {
|
|
228
|
+
resetDate.setMonth(monthIndex, day);
|
|
229
|
+
// If the date is in the past, assume it's next month
|
|
230
|
+
if (resetDate < now) {
|
|
231
|
+
resetDate.setMonth(resetDate.getMonth() + 1);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
// If no month/day specified and time is in the past, assume tomorrow
|
|
237
|
+
if (resetDate <= now) {
|
|
238
|
+
resetDate.setDate(resetDate.getDate() + 1);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
resetTime = resetDate;
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.error('Error parsing reset time:', e);
|
|
245
|
+
resetTime = null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
isRateLimited: true,
|
|
251
|
+
resetTime,
|
|
252
|
+
message: `Rate limit reached${resetTime ? `, resets at ${resetTime.toLocaleString()}` : ''}`
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async sendText(text, cwd = process.cwd(), options = {}) {
|
|
257
|
+
if (!this.isInstalled()) {
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
error: 'Claude Code CLI is not installed. Run install() first.',
|
|
261
|
+
needsInstall: true
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const { onOutput, onError, timeoutMs = 300000 } = options;
|
|
267
|
+
|
|
268
|
+
return new Promise((resolve) => {
|
|
269
|
+
const startTime = Date.now();
|
|
270
|
+
let stdout = '';
|
|
271
|
+
let stderr = '';
|
|
272
|
+
let completed = false;
|
|
273
|
+
let timeoutKilled = false;
|
|
274
|
+
let lastOutputTime = Date.now();
|
|
275
|
+
|
|
276
|
+
// Spawn Claude Code in the repository directory
|
|
277
|
+
const proc = spawn('claude', ['code'], {
|
|
278
|
+
cwd: cwd,
|
|
279
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
280
|
+
env: { ...process.env }
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
this.runningProcesses.push(proc);
|
|
284
|
+
|
|
285
|
+
// Status update interval - show progress every 10 seconds if no output
|
|
286
|
+
const statusInterval = setInterval(() => {
|
|
287
|
+
const timeSinceOutput = (Date.now() - lastOutputTime) / 1000;
|
|
288
|
+
if (timeSinceOutput > 10) {
|
|
289
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
|
290
|
+
const chalk = require('chalk');
|
|
291
|
+
const timestamp = getTimestamp();
|
|
292
|
+
console.log(chalk.yellow(`[${timestamp}] [CLAUDE] Still waiting... (${elapsed}s elapsed, ${timeSinceOutput.toFixed(0)}s since last output)`));
|
|
293
|
+
}
|
|
294
|
+
}, 10000);
|
|
295
|
+
|
|
296
|
+
// Hard timeout - kill process if it runs too long
|
|
297
|
+
const hardTimeout = setTimeout(() => {
|
|
298
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
|
299
|
+
const chalk = require('chalk');
|
|
300
|
+
const timestamp = getTimestamp();
|
|
301
|
+
console.log(chalk.red(`\n[${timestamp}] ⏰ TIMEOUT: Claude Code process exceeded ${timeoutMs/1000}s limit (ran for ${elapsed}s)`));
|
|
302
|
+
console.log(chalk.red(`[${timestamp}] Killing Claude Code process to prevent hanging...`));
|
|
303
|
+
timeoutKilled = true;
|
|
304
|
+
completed = true;
|
|
305
|
+
clearInterval(statusInterval);
|
|
306
|
+
proc.kill('SIGTERM');
|
|
307
|
+
setTimeout(() => proc.kill('SIGKILL'), 2000); // Force kill after 2s
|
|
308
|
+
}, timeoutMs);
|
|
309
|
+
|
|
310
|
+
// Handle stdout
|
|
311
|
+
proc.stdout.on('data', (chunk) => {
|
|
312
|
+
const chunkText = chunk.toString();
|
|
313
|
+
stdout += chunkText;
|
|
314
|
+
lastOutputTime = Date.now();
|
|
315
|
+
|
|
316
|
+
// Filter and show useful output
|
|
317
|
+
const lines = chunkText.split('\n');
|
|
318
|
+
for (const line of lines) {
|
|
319
|
+
const trimmed = line.trim();
|
|
320
|
+
if (!trimmed) continue;
|
|
321
|
+
|
|
322
|
+
// Call output callback if provided
|
|
323
|
+
if (onOutput) {
|
|
324
|
+
onOutput(line + '\n');
|
|
325
|
+
} else {
|
|
326
|
+
// Fallback: write directly to stdout
|
|
327
|
+
try {
|
|
328
|
+
const chalk = require('chalk');
|
|
329
|
+
process.stdout.write(chalk.gray(line + '\n'));
|
|
330
|
+
} catch {
|
|
331
|
+
process.stdout.write(line + '\n');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Handle stderr
|
|
338
|
+
proc.stderr.on('data', (chunk) => {
|
|
339
|
+
const chunkText = chunk.toString();
|
|
340
|
+
stderr += chunkText;
|
|
341
|
+
|
|
342
|
+
// Check for rate limits in stderr
|
|
343
|
+
const rateLimitInfo = this.checkRateLimit(chunkText);
|
|
344
|
+
if (rateLimitInfo.isRateLimited) {
|
|
345
|
+
this.rateLimitInfo = rateLimitInfo;
|
|
346
|
+
console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
|
|
347
|
+
|
|
348
|
+
// If we have a reset time, update the provider manager
|
|
349
|
+
if (rateLimitInfo.resetTime) {
|
|
350
|
+
try {
|
|
351
|
+
const ProviderManager = require('../ide-integration/provider-manager.cjs');
|
|
352
|
+
const providerManager = new ProviderManager();
|
|
353
|
+
providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
|
|
354
|
+
} catch (e) {
|
|
355
|
+
console.error('Failed to update rate limit status:', e);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Only show actual errors
|
|
361
|
+
if (chunkText.includes('Error:') || chunkText.includes('Failed:') || chunkText.includes('error')) {
|
|
362
|
+
if (onError) {
|
|
363
|
+
onError(chunkText.trim());
|
|
364
|
+
} else {
|
|
365
|
+
this.logger.error('[Claude Code Error]', chunkText.trim());
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Send the message and close stdin
|
|
371
|
+
proc.stdin.write(text + '\n');
|
|
372
|
+
proc.stdin.end();
|
|
373
|
+
|
|
374
|
+
// Handle process exit
|
|
375
|
+
proc.on('close', (code) => {
|
|
376
|
+
// Remove process from tracking array
|
|
377
|
+
const index = this.runningProcesses.indexOf(proc);
|
|
378
|
+
if (index > -1) {
|
|
379
|
+
this.runningProcesses.splice(index, 1);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
clearInterval(statusInterval);
|
|
383
|
+
clearTimeout(hardTimeout);
|
|
384
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
385
|
+
const chalk = require('chalk');
|
|
386
|
+
const timestamp = getTimestamp();
|
|
387
|
+
|
|
388
|
+
if (timeoutKilled) {
|
|
389
|
+
console.log(chalk.red(`[${timestamp}] [CLAUDE] Process killed due to timeout after ${elapsed}s`));
|
|
390
|
+
resolve({
|
|
391
|
+
success: false,
|
|
392
|
+
output: stdout,
|
|
393
|
+
error: 'Timeout: Process exceeded maximum execution time',
|
|
394
|
+
exitCode: -1,
|
|
395
|
+
timeout: true
|
|
396
|
+
});
|
|
397
|
+
} else if (code === 0) {
|
|
398
|
+
console.log(chalk.gray(`[${timestamp}] [CLAUDE] Process completed after ${elapsed}s with code: ${code}`));
|
|
399
|
+
resolve({
|
|
400
|
+
success: true,
|
|
401
|
+
output: stdout,
|
|
402
|
+
stderr: stderr,
|
|
403
|
+
exitCode: code
|
|
404
|
+
});
|
|
405
|
+
} else {
|
|
406
|
+
console.log(chalk.gray(`[${timestamp}] [CLAUDE] Process closed after ${elapsed}s with code: ${code}`));
|
|
407
|
+
resolve({
|
|
408
|
+
success: false,
|
|
409
|
+
output: stdout,
|
|
410
|
+
error: stderr || `Process exited with code ${code}`,
|
|
411
|
+
exitCode: code
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
proc.on('error', (error) => {
|
|
417
|
+
clearInterval(statusInterval);
|
|
418
|
+
clearTimeout(hardTimeout);
|
|
419
|
+
completed = true;
|
|
420
|
+
const timestamp = getTimestamp();
|
|
421
|
+
console.log(`\n[${timestamp}] ✗ Claude Code error: ${error.message}`);
|
|
422
|
+
resolve({
|
|
423
|
+
success: false,
|
|
424
|
+
error: error.message,
|
|
425
|
+
exitCode: -1
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
} catch (error) {
|
|
430
|
+
// Check if this is a rate limit error
|
|
431
|
+
const rateLimitInfo = this.checkRateLimit(error.message);
|
|
432
|
+
if (rateLimitInfo.isRateLimited) {
|
|
433
|
+
this.rateLimitInfo = rateLimitInfo;
|
|
434
|
+
console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
|
|
435
|
+
|
|
436
|
+
// Update provider manager with rate limit info
|
|
437
|
+
try {
|
|
438
|
+
const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
|
|
439
|
+
const providerManager = new ProviderManager();
|
|
440
|
+
providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
|
|
441
|
+
} catch (e) {
|
|
442
|
+
console.error('Failed to update rate limit status:', e);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
success: false,
|
|
448
|
+
error: error.message,
|
|
449
|
+
rateLimited: rateLimitInfo.isRateLimited,
|
|
450
|
+
rateLimitInfo: rateLimitInfo.isRateLimited ? rateLimitInfo : undefined
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
module.exports = ClaudeCodeCLIManager;
|