vibecodingmachine-core 1.0.2 โ 2025.11.2-7.1239
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/.babelrc +13 -13
- package/README.md +28 -28
- package/__tests__/applescript-manager-claude-fix.test.js +286 -286
- package/__tests__/requirement-2-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-3-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-4-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-6-auto-start-looping.test.js +73 -73
- package/__tests__/requirement-7-status-tracking.test.js +332 -332
- package/jest.config.js +18 -18
- package/jest.setup.js +12 -12
- package/package.json +48 -48
- package/src/auth/access-denied.html +119 -119
- package/src/auth/shared-auth-storage.js +230 -230
- package/src/autonomous-mode/feature-implementer.cjs +70 -70
- package/src/autonomous-mode/feature-implementer.js +425 -425
- package/src/chat-management/chat-manager.cjs +71 -71
- package/src/chat-management/chat-manager.js +342 -342
- package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -227
- package/src/ide-integration/aider-cli-manager.cjs +850 -850
- package/src/ide-integration/applescript-manager.cjs +1088 -1088
- package/src/ide-integration/applescript-manager.js +2802 -2802
- package/src/ide-integration/applescript-utils.js +306 -306
- package/src/ide-integration/cdp-manager.cjs +221 -221
- package/src/ide-integration/cdp-manager.js +321 -321
- package/src/ide-integration/claude-code-cli-manager.cjs +301 -301
- 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 +354 -354
- package/src/ide-integration/quota-detector.cjs +34 -34
- package/src/ide-integration/quota-detector.js +349 -349
- package/src/ide-integration/windows-automation-manager.js +262 -262
- package/src/index.cjs +47 -43
- package/src/index.js +17 -17
- package/src/llm/direct-llm-manager.cjs +609 -609
- 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/electron-update-checker.js +113 -85
- package/src/utils/gcloud-auth.cjs +394 -394
- 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/requirement-helpers.js +432 -432
- package/src/utils/update-checker.js +227 -167
- package/src/utils/version-checker.js +169 -0
|
@@ -1,349 +1,349 @@
|
|
|
1
|
-
// @vibecodingmachine/core - Quota Detector
|
|
2
|
-
// Handles quota detection for different IDEs using CDP and AppleScript
|
|
3
|
-
|
|
4
|
-
import CDP from 'chrome-remote-interface';
|
|
5
|
-
import { AppleScriptManager } from './applescript-manager.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Quota Detector for IDE interactions
|
|
9
|
-
* Detects quota warnings in different IDEs using CDP and AppleScript
|
|
10
|
-
*/
|
|
11
|
-
export class QuotaDetector {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.logger = console;
|
|
14
|
-
this.appleScriptManager = new AppleScriptManager();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Timeout utility function
|
|
19
|
-
* @param {number} ms - Timeout in milliseconds
|
|
20
|
-
* @param {Promise} promise - Promise to timeout
|
|
21
|
-
* @returns {Promise} Promise with timeout
|
|
22
|
-
*/
|
|
23
|
-
timeout(ms, promise) {
|
|
24
|
-
return Promise.race([
|
|
25
|
-
promise,
|
|
26
|
-
new Promise((_, reject) =>
|
|
27
|
-
setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms)
|
|
28
|
-
)
|
|
29
|
-
]);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Detect quota warnings in an IDE
|
|
34
|
-
* @param {string} ide - The IDE name ('vscode', 'cursor', 'windsurf')
|
|
35
|
-
* @returns {Promise<Object>} Quota detection result
|
|
36
|
-
*/
|
|
37
|
-
async detectQuotaWarning(ide = 'vscode') {
|
|
38
|
-
this.logger.log(`๐ Starting quota detection for ${ide}...`);
|
|
39
|
-
|
|
40
|
-
// Determine the port based on the IDE
|
|
41
|
-
const port = ide === 'windsurf' ? 9224 : ide === 'cursor' ? 9225 : 9222;
|
|
42
|
-
const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : 'VS Code';
|
|
43
|
-
|
|
44
|
-
this.logger.log(`๐ Checking ${ideName} on port ${port}...`);
|
|
45
|
-
|
|
46
|
-
// For Windsurf, use AppleScript detection since CDP is not supported
|
|
47
|
-
if (ide === 'windsurf') {
|
|
48
|
-
this.logger.log('๐ Windsurf detected - using AppleScript quota detection');
|
|
49
|
-
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// For VS Code and Cursor, use CDP detection
|
|
53
|
-
try {
|
|
54
|
-
this.logger.log(`๐ Attempting CDP connection to ${ideName} on port ${port}...`);
|
|
55
|
-
|
|
56
|
-
// Try to connect to CDP
|
|
57
|
-
const targets = await this.timeout(5000, CDP.List({ port }));
|
|
58
|
-
|
|
59
|
-
if (!targets || targets.length === 0) {
|
|
60
|
-
this.logger.log(`โ No CDP targets found on port ${port}`);
|
|
61
|
-
|
|
62
|
-
// For Windsurf, fall back to AppleScript
|
|
63
|
-
if (ide === 'windsurf') {
|
|
64
|
-
this.logger.log('๐ Falling back to enhanced AppleScript quota detection...');
|
|
65
|
-
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
hasQuotaWarning: false,
|
|
70
|
-
error: `Could not find ${ideName}. Make sure ${ideName} is running with --remote-debugging-port=${port}`,
|
|
71
|
-
note: 'CDP connection failed'
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
this.logger.log(`โ
Found ${targets.length} CDP targets`);
|
|
76
|
-
|
|
77
|
-
// For Cursor, prefer the workspace target over settings
|
|
78
|
-
let workbench;
|
|
79
|
-
if (ide === 'cursor') {
|
|
80
|
-
workbench = targets.find(t => t.title !== 'Cursor Settings' && t.type === 'page') ||
|
|
81
|
-
targets.find(t => t.url && t.url.includes('workbench')) ||
|
|
82
|
-
targets[0];
|
|
83
|
-
} else {
|
|
84
|
-
workbench = targets.find(t => t.url && t.url.includes('workbench')) || targets[0];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (!workbench) {
|
|
88
|
-
this.logger.log(`โ No suitable workbench target found`);
|
|
89
|
-
return {
|
|
90
|
-
hasQuotaWarning: false,
|
|
91
|
-
error: `No ${ideName} workbench target found.`,
|
|
92
|
-
note: 'No workbench target available'
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
this.logger.log(`โ
Selected workbench: ${workbench.title}`);
|
|
97
|
-
|
|
98
|
-
// Connect to CDP
|
|
99
|
-
const client = await this.timeout(10000, CDP({ port, target: workbench }));
|
|
100
|
-
const { Runtime, Page } = client;
|
|
101
|
-
|
|
102
|
-
await this.timeout(5000, Runtime.enable());
|
|
103
|
-
if (Page && Page.bringToFront) {
|
|
104
|
-
try {
|
|
105
|
-
await this.timeout(3000, Page.bringToFront());
|
|
106
|
-
} catch (error) {
|
|
107
|
-
this.logger.log(`โ ๏ธ Bring to front failed: ${error.message}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Execute JavaScript to detect quota warnings
|
|
112
|
-
const detectionScript = `
|
|
113
|
-
(() => {
|
|
114
|
-
console.log('๐ Starting quota detection in ${ideName}...');
|
|
115
|
-
|
|
116
|
-
// Common quota warning patterns
|
|
117
|
-
const quotaPatterns = [
|
|
118
|
-
'not enough credits',
|
|
119
|
-
'upgrade to a paid plan',
|
|
120
|
-
'switch to swe-1-lite',
|
|
121
|
-
'quota exceeded',
|
|
122
|
-
'credits exhausted',
|
|
123
|
-
'payment required',
|
|
124
|
-
'out of credits',
|
|
125
|
-
'insufficient credits',
|
|
126
|
-
'billing required',
|
|
127
|
-
'subscription needed'
|
|
128
|
-
];
|
|
129
|
-
|
|
130
|
-
// Function to check if text contains quota warnings
|
|
131
|
-
function containsQuotaWarning(text) {
|
|
132
|
-
if (!text) return false;
|
|
133
|
-
const lowerText = text.toLowerCase();
|
|
134
|
-
return quotaPatterns.some(pattern => lowerText.includes(pattern));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Method 1: Check all text content in the document
|
|
138
|
-
const allText = document.body.innerText || document.body.textContent || '';
|
|
139
|
-
if (containsQuotaWarning(allText)) {
|
|
140
|
-
console.log('โ Quota warning detected in document text');
|
|
141
|
-
return {
|
|
142
|
-
hasQuotaWarning: true,
|
|
143
|
-
method: 'document-text',
|
|
144
|
-
matchedText: allText.substring(0, 200) + '...'
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Method 2: Check specific elements that might contain quota warnings
|
|
149
|
-
const quotaElements = [
|
|
150
|
-
// VS Code specific selectors
|
|
151
|
-
'.monaco-workbench .part.auxiliarybar',
|
|
152
|
-
'.monaco-workbench .part.sidebar.right',
|
|
153
|
-
'.monaco-workbench .chat-view',
|
|
154
|
-
'.monaco-workbench .chat-input',
|
|
155
|
-
|
|
156
|
-
// Cursor specific selectors
|
|
157
|
-
'.aislash-editor-input',
|
|
158
|
-
'.aislash-chat-container',
|
|
159
|
-
'.aislash-panel',
|
|
160
|
-
|
|
161
|
-
// Generic selectors
|
|
162
|
-
'[data-testid*="chat"]',
|
|
163
|
-
'[aria-label*="chat"]',
|
|
164
|
-
'[class*="chat"]',
|
|
165
|
-
'[class*="quota"]',
|
|
166
|
-
'[class*="credits"]',
|
|
167
|
-
'[class*="billing"]'
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
for (const selector of quotaElements) {
|
|
171
|
-
const elements = document.querySelectorAll(selector);
|
|
172
|
-
for (const element of elements) {
|
|
173
|
-
const elementText = element.innerText || element.textContent || '';
|
|
174
|
-
if (containsQuotaWarning(elementText)) {
|
|
175
|
-
console.log('โ Quota warning detected in element:', selector);
|
|
176
|
-
return {
|
|
177
|
-
hasQuotaWarning: true,
|
|
178
|
-
method: 'element-specific',
|
|
179
|
-
selector: selector,
|
|
180
|
-
matchedText: elementText.substring(0, 200) + '...'
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Method 3: Check for disabled input fields (common when quota is exceeded)
|
|
187
|
-
const disabledInputs = document.querySelectorAll('input[disabled], textarea[disabled], [contenteditable="true"][aria-disabled="true"]');
|
|
188
|
-
if (disabledInputs.length > 0) {
|
|
189
|
-
console.log('โ ๏ธ Found disabled input fields, checking for quota context...');
|
|
190
|
-
|
|
191
|
-
// Check if there are quota-related messages near disabled inputs
|
|
192
|
-
for (const input of disabledInputs) {
|
|
193
|
-
const parentText = input.parentElement?.innerText || '';
|
|
194
|
-
if (containsQuotaWarning(parentText)) {
|
|
195
|
-
console.log('โ Quota warning detected near disabled input');
|
|
196
|
-
return {
|
|
197
|
-
hasQuotaWarning: true,
|
|
198
|
-
method: 'disabled-input-context',
|
|
199
|
-
matchedText: parentText.substring(0, 200) + '...'
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Method 4: Check for specific UI elements that indicate quota issues
|
|
206
|
-
const quotaButtons = document.querySelectorAll('button, a, [role="button"]');
|
|
207
|
-
for (const button of quotaButtons) {
|
|
208
|
-
const buttonText = button.innerText || button.textContent || '';
|
|
209
|
-
if (containsQuotaWarning(buttonText)) {
|
|
210
|
-
console.log('โ Quota warning detected in button:', buttonText);
|
|
211
|
-
return {
|
|
212
|
-
hasQuotaWarning: true,
|
|
213
|
-
method: 'button-text',
|
|
214
|
-
matchedText: buttonText
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Method 5: Check for error messages or notifications
|
|
220
|
-
const errorElements = document.querySelectorAll('[class*="error"], [class*="warning"], [class*="notification"], [role="alert"]');
|
|
221
|
-
for (const error of errorElements) {
|
|
222
|
-
const errorText = error.innerText || error.textContent || '';
|
|
223
|
-
if (containsQuotaWarning(errorText)) {
|
|
224
|
-
console.log('โ Quota warning detected in error element');
|
|
225
|
-
return {
|
|
226
|
-
hasQuotaWarning: true,
|
|
227
|
-
method: 'error-element',
|
|
228
|
-
matchedText: errorText.substring(0, 200) + '...'
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
console.log('โ
No quota warnings detected');
|
|
234
|
-
return {
|
|
235
|
-
hasQuotaWarning: false,
|
|
236
|
-
method: 'cdp-comprehensive',
|
|
237
|
-
note: 'No quota warnings found in ${ideName}'
|
|
238
|
-
};
|
|
239
|
-
})()
|
|
240
|
-
`;
|
|
241
|
-
|
|
242
|
-
const { result } = await this.timeout(10000, Runtime.evaluate({
|
|
243
|
-
expression: detectionScript,
|
|
244
|
-
returnByValue: true
|
|
245
|
-
}));
|
|
246
|
-
|
|
247
|
-
const detectionResult = result.value || result.unserializableValue;
|
|
248
|
-
|
|
249
|
-
this.logger.log('๐ CDP quota detection result:', detectionResult);
|
|
250
|
-
|
|
251
|
-
if (detectionResult && detectionResult.hasQuotaWarning) {
|
|
252
|
-
this.logger.log('โ Quota warning detected via CDP');
|
|
253
|
-
return {
|
|
254
|
-
hasQuotaWarning: true,
|
|
255
|
-
method: detectionResult.method,
|
|
256
|
-
note: detectionResult.matchedText || 'Quota warning detected via CDP',
|
|
257
|
-
debug: detectionResult
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
this.logger.log('โ
No quota warnings detected via CDP');
|
|
262
|
-
return {
|
|
263
|
-
hasQuotaWarning: false,
|
|
264
|
-
method: 'cdp-comprehensive',
|
|
265
|
-
note: 'No quota warnings found in ' + ideName,
|
|
266
|
-
debug: detectionResult
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
} catch (error) {
|
|
270
|
-
this.logger.log(`โ CDP quota detection failed: ${error.message}`);
|
|
271
|
-
|
|
272
|
-
// For Windsurf, fall back to AppleScript
|
|
273
|
-
if (ide === 'windsurf') {
|
|
274
|
-
this.logger.log('๐ Falling back to AppleScript quota detection...');
|
|
275
|
-
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return {
|
|
279
|
-
hasQuotaWarning: false,
|
|
280
|
-
error: error.message,
|
|
281
|
-
note: `CDP quota detection failed for ${ideName}`
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Get available IDEs without quota warnings
|
|
288
|
-
* @param {Array<string>} ides - Array of IDE names to check
|
|
289
|
-
* @returns {Promise<Array<string>>} Array of available IDE names
|
|
290
|
-
*/
|
|
291
|
-
async getAvailableIdes(ides = ['vscode', 'cursor', 'windsurf']) {
|
|
292
|
-
this.logger.log('๐ Checking available IDEs without quota warnings...');
|
|
293
|
-
|
|
294
|
-
const availableIdes = [];
|
|
295
|
-
|
|
296
|
-
for (const ide of ides) {
|
|
297
|
-
try {
|
|
298
|
-
const quotaResult = await this.detectQuotaWarning(ide);
|
|
299
|
-
|
|
300
|
-
if (!quotaResult.hasQuotaWarning) {
|
|
301
|
-
availableIdes.push(ide);
|
|
302
|
-
this.logger.log(`โ
${ide} is available (no quota warnings)`);
|
|
303
|
-
} else {
|
|
304
|
-
this.logger.log(`โ ${ide} has quota warnings: ${quotaResult.note || 'Unknown quota issue'}`);
|
|
305
|
-
}
|
|
306
|
-
} catch (error) {
|
|
307
|
-
this.logger.log(`โ ๏ธ Error checking ${ide}: ${error.message}`);
|
|
308
|
-
// If we can't check quota, assume the IDE is available
|
|
309
|
-
availableIdes.push(ide);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
this.logger.log(`๐ Available IDEs: ${availableIdes.join(', ')}`);
|
|
314
|
-
return availableIdes;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Test quota detection with a test message
|
|
319
|
-
* @param {string} ide - The IDE name to test
|
|
320
|
-
* @returns {Promise<Object>} Test result
|
|
321
|
-
*/
|
|
322
|
-
async testQuotaDetection(ide) {
|
|
323
|
-
this.logger.log(`๐งช Testing quota detection for ${ide}...`);
|
|
324
|
-
|
|
325
|
-
try {
|
|
326
|
-
const quotaResult = await this.detectQuotaWarning(ide);
|
|
327
|
-
|
|
328
|
-
this.logger.log(`๐งช Quota detection test result for ${ide}:`, quotaResult);
|
|
329
|
-
|
|
330
|
-
return {
|
|
331
|
-
ide,
|
|
332
|
-
success: true,
|
|
333
|
-
hasQuotaWarning: quotaResult.hasQuotaWarning,
|
|
334
|
-
method: quotaResult.method,
|
|
335
|
-
note: quotaResult.note,
|
|
336
|
-
debug: quotaResult
|
|
337
|
-
};
|
|
338
|
-
} catch (error) {
|
|
339
|
-
this.logger.log(`โ Quota detection test failed for ${ide}: ${error.message}`);
|
|
340
|
-
|
|
341
|
-
return {
|
|
342
|
-
ide,
|
|
343
|
-
success: false,
|
|
344
|
-
error: error.message,
|
|
345
|
-
note: `Quota detection test failed for ${ide}`
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
1
|
+
// @vibecodingmachine/core - Quota Detector
|
|
2
|
+
// Handles quota detection for different IDEs using CDP and AppleScript
|
|
3
|
+
|
|
4
|
+
import CDP from 'chrome-remote-interface';
|
|
5
|
+
import { AppleScriptManager } from './applescript-manager.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Quota Detector for IDE interactions
|
|
9
|
+
* Detects quota warnings in different IDEs using CDP and AppleScript
|
|
10
|
+
*/
|
|
11
|
+
export class QuotaDetector {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.logger = console;
|
|
14
|
+
this.appleScriptManager = new AppleScriptManager();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Timeout utility function
|
|
19
|
+
* @param {number} ms - Timeout in milliseconds
|
|
20
|
+
* @param {Promise} promise - Promise to timeout
|
|
21
|
+
* @returns {Promise} Promise with timeout
|
|
22
|
+
*/
|
|
23
|
+
timeout(ms, promise) {
|
|
24
|
+
return Promise.race([
|
|
25
|
+
promise,
|
|
26
|
+
new Promise((_, reject) =>
|
|
27
|
+
setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms)
|
|
28
|
+
)
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Detect quota warnings in an IDE
|
|
34
|
+
* @param {string} ide - The IDE name ('vscode', 'cursor', 'windsurf')
|
|
35
|
+
* @returns {Promise<Object>} Quota detection result
|
|
36
|
+
*/
|
|
37
|
+
async detectQuotaWarning(ide = 'vscode') {
|
|
38
|
+
this.logger.log(`๐ Starting quota detection for ${ide}...`);
|
|
39
|
+
|
|
40
|
+
// Determine the port based on the IDE
|
|
41
|
+
const port = ide === 'windsurf' ? 9224 : ide === 'cursor' ? 9225 : 9222;
|
|
42
|
+
const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : 'VS Code';
|
|
43
|
+
|
|
44
|
+
this.logger.log(`๐ Checking ${ideName} on port ${port}...`);
|
|
45
|
+
|
|
46
|
+
// For Windsurf, use AppleScript detection since CDP is not supported
|
|
47
|
+
if (ide === 'windsurf') {
|
|
48
|
+
this.logger.log('๐ Windsurf detected - using AppleScript quota detection');
|
|
49
|
+
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// For VS Code and Cursor, use CDP detection
|
|
53
|
+
try {
|
|
54
|
+
this.logger.log(`๐ Attempting CDP connection to ${ideName} on port ${port}...`);
|
|
55
|
+
|
|
56
|
+
// Try to connect to CDP
|
|
57
|
+
const targets = await this.timeout(5000, CDP.List({ port }));
|
|
58
|
+
|
|
59
|
+
if (!targets || targets.length === 0) {
|
|
60
|
+
this.logger.log(`โ No CDP targets found on port ${port}`);
|
|
61
|
+
|
|
62
|
+
// For Windsurf, fall back to AppleScript
|
|
63
|
+
if (ide === 'windsurf') {
|
|
64
|
+
this.logger.log('๐ Falling back to enhanced AppleScript quota detection...');
|
|
65
|
+
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
hasQuotaWarning: false,
|
|
70
|
+
error: `Could not find ${ideName}. Make sure ${ideName} is running with --remote-debugging-port=${port}`,
|
|
71
|
+
note: 'CDP connection failed'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.logger.log(`โ
Found ${targets.length} CDP targets`);
|
|
76
|
+
|
|
77
|
+
// For Cursor, prefer the workspace target over settings
|
|
78
|
+
let workbench;
|
|
79
|
+
if (ide === 'cursor') {
|
|
80
|
+
workbench = targets.find(t => t.title !== 'Cursor Settings' && t.type === 'page') ||
|
|
81
|
+
targets.find(t => t.url && t.url.includes('workbench')) ||
|
|
82
|
+
targets[0];
|
|
83
|
+
} else {
|
|
84
|
+
workbench = targets.find(t => t.url && t.url.includes('workbench')) || targets[0];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!workbench) {
|
|
88
|
+
this.logger.log(`โ No suitable workbench target found`);
|
|
89
|
+
return {
|
|
90
|
+
hasQuotaWarning: false,
|
|
91
|
+
error: `No ${ideName} workbench target found.`,
|
|
92
|
+
note: 'No workbench target available'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.logger.log(`โ
Selected workbench: ${workbench.title}`);
|
|
97
|
+
|
|
98
|
+
// Connect to CDP
|
|
99
|
+
const client = await this.timeout(10000, CDP({ port, target: workbench }));
|
|
100
|
+
const { Runtime, Page } = client;
|
|
101
|
+
|
|
102
|
+
await this.timeout(5000, Runtime.enable());
|
|
103
|
+
if (Page && Page.bringToFront) {
|
|
104
|
+
try {
|
|
105
|
+
await this.timeout(3000, Page.bringToFront());
|
|
106
|
+
} catch (error) {
|
|
107
|
+
this.logger.log(`โ ๏ธ Bring to front failed: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Execute JavaScript to detect quota warnings
|
|
112
|
+
const detectionScript = `
|
|
113
|
+
(() => {
|
|
114
|
+
console.log('๐ Starting quota detection in ${ideName}...');
|
|
115
|
+
|
|
116
|
+
// Common quota warning patterns
|
|
117
|
+
const quotaPatterns = [
|
|
118
|
+
'not enough credits',
|
|
119
|
+
'upgrade to a paid plan',
|
|
120
|
+
'switch to swe-1-lite',
|
|
121
|
+
'quota exceeded',
|
|
122
|
+
'credits exhausted',
|
|
123
|
+
'payment required',
|
|
124
|
+
'out of credits',
|
|
125
|
+
'insufficient credits',
|
|
126
|
+
'billing required',
|
|
127
|
+
'subscription needed'
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
// Function to check if text contains quota warnings
|
|
131
|
+
function containsQuotaWarning(text) {
|
|
132
|
+
if (!text) return false;
|
|
133
|
+
const lowerText = text.toLowerCase();
|
|
134
|
+
return quotaPatterns.some(pattern => lowerText.includes(pattern));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Method 1: Check all text content in the document
|
|
138
|
+
const allText = document.body.innerText || document.body.textContent || '';
|
|
139
|
+
if (containsQuotaWarning(allText)) {
|
|
140
|
+
console.log('โ Quota warning detected in document text');
|
|
141
|
+
return {
|
|
142
|
+
hasQuotaWarning: true,
|
|
143
|
+
method: 'document-text',
|
|
144
|
+
matchedText: allText.substring(0, 200) + '...'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Method 2: Check specific elements that might contain quota warnings
|
|
149
|
+
const quotaElements = [
|
|
150
|
+
// VS Code specific selectors
|
|
151
|
+
'.monaco-workbench .part.auxiliarybar',
|
|
152
|
+
'.monaco-workbench .part.sidebar.right',
|
|
153
|
+
'.monaco-workbench .chat-view',
|
|
154
|
+
'.monaco-workbench .chat-input',
|
|
155
|
+
|
|
156
|
+
// Cursor specific selectors
|
|
157
|
+
'.aislash-editor-input',
|
|
158
|
+
'.aislash-chat-container',
|
|
159
|
+
'.aislash-panel',
|
|
160
|
+
|
|
161
|
+
// Generic selectors
|
|
162
|
+
'[data-testid*="chat"]',
|
|
163
|
+
'[aria-label*="chat"]',
|
|
164
|
+
'[class*="chat"]',
|
|
165
|
+
'[class*="quota"]',
|
|
166
|
+
'[class*="credits"]',
|
|
167
|
+
'[class*="billing"]'
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
for (const selector of quotaElements) {
|
|
171
|
+
const elements = document.querySelectorAll(selector);
|
|
172
|
+
for (const element of elements) {
|
|
173
|
+
const elementText = element.innerText || element.textContent || '';
|
|
174
|
+
if (containsQuotaWarning(elementText)) {
|
|
175
|
+
console.log('โ Quota warning detected in element:', selector);
|
|
176
|
+
return {
|
|
177
|
+
hasQuotaWarning: true,
|
|
178
|
+
method: 'element-specific',
|
|
179
|
+
selector: selector,
|
|
180
|
+
matchedText: elementText.substring(0, 200) + '...'
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Method 3: Check for disabled input fields (common when quota is exceeded)
|
|
187
|
+
const disabledInputs = document.querySelectorAll('input[disabled], textarea[disabled], [contenteditable="true"][aria-disabled="true"]');
|
|
188
|
+
if (disabledInputs.length > 0) {
|
|
189
|
+
console.log('โ ๏ธ Found disabled input fields, checking for quota context...');
|
|
190
|
+
|
|
191
|
+
// Check if there are quota-related messages near disabled inputs
|
|
192
|
+
for (const input of disabledInputs) {
|
|
193
|
+
const parentText = input.parentElement?.innerText || '';
|
|
194
|
+
if (containsQuotaWarning(parentText)) {
|
|
195
|
+
console.log('โ Quota warning detected near disabled input');
|
|
196
|
+
return {
|
|
197
|
+
hasQuotaWarning: true,
|
|
198
|
+
method: 'disabled-input-context',
|
|
199
|
+
matchedText: parentText.substring(0, 200) + '...'
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Method 4: Check for specific UI elements that indicate quota issues
|
|
206
|
+
const quotaButtons = document.querySelectorAll('button, a, [role="button"]');
|
|
207
|
+
for (const button of quotaButtons) {
|
|
208
|
+
const buttonText = button.innerText || button.textContent || '';
|
|
209
|
+
if (containsQuotaWarning(buttonText)) {
|
|
210
|
+
console.log('โ Quota warning detected in button:', buttonText);
|
|
211
|
+
return {
|
|
212
|
+
hasQuotaWarning: true,
|
|
213
|
+
method: 'button-text',
|
|
214
|
+
matchedText: buttonText
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Method 5: Check for error messages or notifications
|
|
220
|
+
const errorElements = document.querySelectorAll('[class*="error"], [class*="warning"], [class*="notification"], [role="alert"]');
|
|
221
|
+
for (const error of errorElements) {
|
|
222
|
+
const errorText = error.innerText || error.textContent || '';
|
|
223
|
+
if (containsQuotaWarning(errorText)) {
|
|
224
|
+
console.log('โ Quota warning detected in error element');
|
|
225
|
+
return {
|
|
226
|
+
hasQuotaWarning: true,
|
|
227
|
+
method: 'error-element',
|
|
228
|
+
matchedText: errorText.substring(0, 200) + '...'
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log('โ
No quota warnings detected');
|
|
234
|
+
return {
|
|
235
|
+
hasQuotaWarning: false,
|
|
236
|
+
method: 'cdp-comprehensive',
|
|
237
|
+
note: 'No quota warnings found in ${ideName}'
|
|
238
|
+
};
|
|
239
|
+
})()
|
|
240
|
+
`;
|
|
241
|
+
|
|
242
|
+
const { result } = await this.timeout(10000, Runtime.evaluate({
|
|
243
|
+
expression: detectionScript,
|
|
244
|
+
returnByValue: true
|
|
245
|
+
}));
|
|
246
|
+
|
|
247
|
+
const detectionResult = result.value || result.unserializableValue;
|
|
248
|
+
|
|
249
|
+
this.logger.log('๐ CDP quota detection result:', detectionResult);
|
|
250
|
+
|
|
251
|
+
if (detectionResult && detectionResult.hasQuotaWarning) {
|
|
252
|
+
this.logger.log('โ Quota warning detected via CDP');
|
|
253
|
+
return {
|
|
254
|
+
hasQuotaWarning: true,
|
|
255
|
+
method: detectionResult.method,
|
|
256
|
+
note: detectionResult.matchedText || 'Quota warning detected via CDP',
|
|
257
|
+
debug: detectionResult
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
this.logger.log('โ
No quota warnings detected via CDP');
|
|
262
|
+
return {
|
|
263
|
+
hasQuotaWarning: false,
|
|
264
|
+
method: 'cdp-comprehensive',
|
|
265
|
+
note: 'No quota warnings found in ' + ideName,
|
|
266
|
+
debug: detectionResult
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
} catch (error) {
|
|
270
|
+
this.logger.log(`โ CDP quota detection failed: ${error.message}`);
|
|
271
|
+
|
|
272
|
+
// For Windsurf, fall back to AppleScript
|
|
273
|
+
if (ide === 'windsurf') {
|
|
274
|
+
this.logger.log('๐ Falling back to AppleScript quota detection...');
|
|
275
|
+
return await this.appleScriptManager.detectQuotaWarning(ide);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
hasQuotaWarning: false,
|
|
280
|
+
error: error.message,
|
|
281
|
+
note: `CDP quota detection failed for ${ideName}`
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get available IDEs without quota warnings
|
|
288
|
+
* @param {Array<string>} ides - Array of IDE names to check
|
|
289
|
+
* @returns {Promise<Array<string>>} Array of available IDE names
|
|
290
|
+
*/
|
|
291
|
+
async getAvailableIdes(ides = ['vscode', 'cursor', 'windsurf']) {
|
|
292
|
+
this.logger.log('๐ Checking available IDEs without quota warnings...');
|
|
293
|
+
|
|
294
|
+
const availableIdes = [];
|
|
295
|
+
|
|
296
|
+
for (const ide of ides) {
|
|
297
|
+
try {
|
|
298
|
+
const quotaResult = await this.detectQuotaWarning(ide);
|
|
299
|
+
|
|
300
|
+
if (!quotaResult.hasQuotaWarning) {
|
|
301
|
+
availableIdes.push(ide);
|
|
302
|
+
this.logger.log(`โ
${ide} is available (no quota warnings)`);
|
|
303
|
+
} else {
|
|
304
|
+
this.logger.log(`โ ${ide} has quota warnings: ${quotaResult.note || 'Unknown quota issue'}`);
|
|
305
|
+
}
|
|
306
|
+
} catch (error) {
|
|
307
|
+
this.logger.log(`โ ๏ธ Error checking ${ide}: ${error.message}`);
|
|
308
|
+
// If we can't check quota, assume the IDE is available
|
|
309
|
+
availableIdes.push(ide);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
this.logger.log(`๐ Available IDEs: ${availableIdes.join(', ')}`);
|
|
314
|
+
return availableIdes;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Test quota detection with a test message
|
|
319
|
+
* @param {string} ide - The IDE name to test
|
|
320
|
+
* @returns {Promise<Object>} Test result
|
|
321
|
+
*/
|
|
322
|
+
async testQuotaDetection(ide) {
|
|
323
|
+
this.logger.log(`๐งช Testing quota detection for ${ide}...`);
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const quotaResult = await this.detectQuotaWarning(ide);
|
|
327
|
+
|
|
328
|
+
this.logger.log(`๐งช Quota detection test result for ${ide}:`, quotaResult);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
ide,
|
|
332
|
+
success: true,
|
|
333
|
+
hasQuotaWarning: quotaResult.hasQuotaWarning,
|
|
334
|
+
method: quotaResult.method,
|
|
335
|
+
note: quotaResult.note,
|
|
336
|
+
debug: quotaResult
|
|
337
|
+
};
|
|
338
|
+
} catch (error) {
|
|
339
|
+
this.logger.log(`โ Quota detection test failed for ${ide}: ${error.message}`);
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
ide,
|
|
343
|
+
success: false,
|
|
344
|
+
error: error.message,
|
|
345
|
+
note: `Quota detection test failed for ${ide}`
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|