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.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/src/auth/access-denied.html +119 -119
  3. package/src/auth/shared-auth-storage.js +267 -267
  4. package/src/autonomous-mode/feature-implementer.cjs +70 -70
  5. package/src/autonomous-mode/feature-implementer.js +425 -425
  6. package/src/beta-request.js +160 -160
  7. package/src/chat-management/chat-manager.cjs +71 -71
  8. package/src/chat-management/chat-manager.js +342 -342
  9. package/src/compliance/compliance-prompt.js +183 -183
  10. package/src/ide-integration/aider-cli-manager.cjs +850 -850
  11. package/src/ide-integration/applescript-manager.cjs +3215 -3215
  12. package/src/ide-integration/applescript-utils.js +314 -314
  13. package/src/ide-integration/cdp-manager.cjs +221 -221
  14. package/src/ide-integration/claude-code-cli-manager.cjs +456 -456
  15. package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
  16. package/src/ide-integration/continue-cli-manager.js +431 -431
  17. package/src/ide-integration/provider-manager.cjs +595 -595
  18. package/src/ide-integration/quota-detector.cjs +399 -399
  19. package/src/ide-integration/windows-automation-manager.js +532 -4
  20. package/src/ide-integration/windows-ide-manager.js +12 -3
  21. package/src/index.cjs +142 -142
  22. package/src/llm/direct-llm-manager.cjs +1299 -1299
  23. package/src/localization/index.js +147 -147
  24. package/src/quota-management/index.js +108 -108
  25. package/src/requirement-numbering.js +164 -164
  26. package/src/sync/aws-setup.js +445 -445
  27. package/src/ui/ButtonComponents.js +247 -247
  28. package/src/ui/ChatInterface.js +499 -499
  29. package/src/ui/StateManager.js +259 -259
  30. package/src/utils/audit-logger.cjs +116 -116
  31. package/src/utils/config-helpers.cjs +94 -94
  32. package/src/utils/config-helpers.js +94 -94
  33. package/src/utils/env-helpers.js +54 -54
  34. package/src/utils/error-reporter.js +117 -117
  35. package/src/utils/gcloud-auth.cjs +394 -394
  36. package/src/utils/git-branch-manager.js +278 -278
  37. package/src/utils/logger.cjs +193 -193
  38. package/src/utils/logger.js +191 -191
  39. package/src/utils/repo-helpers.cjs +120 -120
  40. package/src/utils/repo-helpers.js +120 -120
  41. package/src/utils/update-checker.js +246 -246
  42. package/src/utils/version-checker.js +170 -170
@@ -1,399 +1,399 @@
1
- // @vibecodingmachine/core - Quota Detector (CommonJS)
2
- // Handles quota detection for different IDEs using CDP and AppleScript
3
-
4
- const CDP = require('chrome-remote-interface');
5
- const { AppleScriptManager } = require('./applescript-manager.cjs');
6
-
7
- /**
8
- * Quota Detector for IDE interactions
9
- * Detects quota warnings in different IDEs using CDP and AppleScript
10
- */
11
- 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
- 'monthly chat messages quota',
129
- 'upgrade to copilot pro',
130
- 'allowance to renew',
131
- 'reached your monthly',
132
- 'wait for your allowance',
133
- // Kiro-specific patterns
134
- "you're out of credits",
135
- 'upgrade to a higher plan',
136
- 'wait for next month',
137
- "next month's new set of credits",
138
- 'including steering documents'
139
- ];
140
-
141
- // Function to check if text contains quota warnings
142
- function containsQuotaWarning(text) {
143
- if (!text) return false;
144
- const lowerText = text.toLowerCase();
145
- return quotaPatterns.some(pattern => lowerText.includes(pattern));
146
- }
147
-
148
- // Method 1: Check all text content in the document
149
- const allText = document.body.innerText || document.body.textContent || '';
150
- if (containsQuotaWarning(allText)) {
151
- console.log('โŒ Quota warning detected in document text');
152
- return {
153
- hasQuotaWarning: true,
154
- method: 'document-text',
155
- matchedText: allText.substring(0, 200) + '...'
156
- };
157
- }
158
-
159
- // Method 2: Check specific elements that might contain quota warnings
160
- const quotaElements = [
161
- // VS Code specific selectors
162
- '.monaco-workbench .part.auxiliarybar',
163
- '.monaco-workbench .part.sidebar.right',
164
- '.monaco-workbench .chat-view',
165
- '.monaco-workbench .chat-input',
166
-
167
- // Cursor specific selectors
168
- '.aislash-editor-input',
169
- '.aislash-chat-container',
170
- '.aislash-panel',
171
-
172
- // Kiro specific selectors (AWS Kiro runs in VS Code)
173
- '[class*="kiro"]',
174
- '[data-testid*="kiro"]',
175
- '[aria-label*="kiro"]',
176
- '.webview',
177
- 'iframe',
178
-
179
- // Generic selectors
180
- '[data-testid*="chat"]',
181
- '[aria-label*="chat"]',
182
- '[class*="chat"]',
183
- '[class*="quota"]',
184
- '[class*="credits"]',
185
- '[class*="billing"]'
186
- ];
187
-
188
- for (const selector of quotaElements) {
189
- const elements = document.querySelectorAll(selector);
190
- for (const element of elements) {
191
- const elementText = element.innerText || element.textContent || '';
192
- if (containsQuotaWarning(elementText)) {
193
- console.log('โŒ Quota warning detected in element:', selector);
194
- return {
195
- hasQuotaWarning: true,
196
- method: 'element-specific',
197
- selector: selector,
198
- matchedText: elementText.substring(0, 200) + '...'
199
- };
200
- }
201
- }
202
- }
203
-
204
- // Method 3: Check for disabled input fields (common when quota is exceeded)
205
- const disabledInputs = document.querySelectorAll('input[disabled], textarea[disabled], [contenteditable="true"][aria-disabled="true"]');
206
- if (disabledInputs.length > 0) {
207
- console.log('โš ๏ธ Found disabled input fields, checking for quota context...');
208
-
209
- // Check if there are quota-related messages near disabled inputs
210
- for (const input of disabledInputs) {
211
- const parentText = input.parentElement?.innerText || '';
212
- if (containsQuotaWarning(parentText)) {
213
- console.log('โŒ Quota warning detected near disabled input');
214
- return {
215
- hasQuotaWarning: true,
216
- method: 'disabled-input-context',
217
- matchedText: parentText.substring(0, 200) + '...'
218
- };
219
- }
220
- }
221
- }
222
-
223
- // Method 4: Check for specific UI elements that indicate quota issues
224
- const quotaButtons = document.querySelectorAll('button, a, [role="button"]');
225
- for (const button of quotaButtons) {
226
- const buttonText = button.innerText || button.textContent || '';
227
- if (containsQuotaWarning(buttonText)) {
228
- console.log('โŒ Quota warning detected in button:', buttonText);
229
- return {
230
- hasQuotaWarning: true,
231
- method: 'button-text',
232
- matchedText: buttonText
233
- };
234
- }
235
- }
236
-
237
- // Method 5: Check for error messages or notifications
238
- const errorElements = document.querySelectorAll('[class*="error"], [class*="warning"], [class*="notification"], [role="alert"]');
239
- for (const error of errorElements) {
240
- const errorText = error.innerText || error.textContent || '';
241
- if (containsQuotaWarning(errorText)) {
242
- console.log('โŒ Quota warning detected in error element');
243
- return {
244
- hasQuotaWarning: true,
245
- method: 'error-element',
246
- matchedText: errorText.substring(0, 200) + '...'
247
- };
248
- }
249
- }
250
-
251
- // Method 6: Check inside iframes/webviews (important for Kiro and other webview-based extensions)
252
- try {
253
- const iframes = document.querySelectorAll('iframe, webview');
254
- console.log(\`๐Ÿ” Found \${iframes.length} iframe/webview elements to check\`);
255
-
256
- for (const frame of iframes) {
257
- try {
258
- // Try to access iframe content (will fail if cross-origin)
259
- const frameDoc = frame.contentDocument || frame.contentWindow?.document;
260
- if (frameDoc) {
261
- const frameText = frameDoc.body?.innerText || frameDoc.body?.textContent || '';
262
- if (containsQuotaWarning(frameText)) {
263
- console.log('โŒ Quota warning detected in iframe/webview');
264
- return {
265
- hasQuotaWarning: true,
266
- method: 'iframe-content',
267
- matchedText: frameText.substring(0, 200) + '...'
268
- };
269
- }
270
- }
271
- } catch (e) {
272
- // Cross-origin iframe - can't access, skip
273
- console.log('โš ๏ธ Cannot access iframe content (likely cross-origin)');
274
- }
275
- }
276
- } catch (e) {
277
- console.log('โš ๏ธ Error checking iframes:', e.message);
278
- }
279
-
280
- console.log('โœ… No quota warnings detected');
281
- return {
282
- hasQuotaWarning: false,
283
- method: 'cdp-comprehensive',
284
- note: 'No quota warnings found in ${ideName}'
285
- };
286
- })()
287
- `;
288
-
289
- const { result } = await this.timeout(10000, Runtime.evaluate({
290
- expression: detectionScript,
291
- returnByValue: true
292
- }));
293
-
294
- const detectionResult = result.value || result.unserializableValue;
295
-
296
- this.logger.log('๐Ÿ” CDP quota detection result:', detectionResult);
297
-
298
- if (detectionResult && detectionResult.hasQuotaWarning) {
299
- this.logger.log('โŒ Quota warning detected via CDP');
300
- return {
301
- hasQuotaWarning: true,
302
- method: detectionResult.method,
303
- matchedText: detectionResult.matchedText || 'Quota warning detected via CDP',
304
- note: detectionResult.matchedText || 'Quota warning detected via CDP',
305
- debug: detectionResult
306
- };
307
- }
308
-
309
- this.logger.log('โœ… No quota warnings detected via CDP');
310
- return {
311
- hasQuotaWarning: false,
312
- method: 'cdp-comprehensive',
313
- note: 'No quota warnings found in ' + ideName,
314
- debug: detectionResult
315
- };
316
-
317
- } catch (error) {
318
- this.logger.log(`โŒ CDP quota detection failed: ${error.message}`);
319
-
320
- // For Windsurf, fall back to AppleScript
321
- if (ide === 'windsurf') {
322
- this.logger.log('๐Ÿ” Falling back to AppleScript quota detection...');
323
- return await this.appleScriptManager.detectQuotaWarning(ide);
324
- }
325
-
326
- return {
327
- hasQuotaWarning: false,
328
- error: error.message,
329
- note: `CDP quota detection failed for ${ideName}`
330
- };
331
- }
332
- }
333
-
334
- /**
335
- * Get available IDEs without quota warnings
336
- * @param {Array<string>} ides - Array of IDE names to check
337
- * @returns {Promise<Array<string>>} Array of available IDE names
338
- */
339
- async getAvailableIdes(ides = ['vscode', 'cursor', 'windsurf']) {
340
- this.logger.log('๐Ÿ” Checking available IDEs without quota warnings...');
341
-
342
- const availableIdes = [];
343
-
344
- for (const ide of ides) {
345
- try {
346
- const quotaResult = await this.detectQuotaWarning(ide);
347
-
348
- if (!quotaResult.hasQuotaWarning) {
349
- availableIdes.push(ide);
350
- this.logger.log(`โœ… ${ide} is available (no quota warnings)`);
351
- } else {
352
- this.logger.log(`โŒ ${ide} has quota warnings: ${quotaResult.note || 'Unknown quota issue'}`);
353
- }
354
- } catch (error) {
355
- this.logger.log(`โš ๏ธ Error checking ${ide}: ${error.message}`);
356
- // If we can't check quota, assume the IDE is available
357
- availableIdes.push(ide);
358
- }
359
- }
360
-
361
- this.logger.log(`๐Ÿ“‹ Available IDEs: ${availableIdes.join(', ')}`);
362
- return availableIdes;
363
- }
364
-
365
- /**
366
- * Test quota detection with a test message
367
- * @param {string} ide - The IDE name to test
368
- * @returns {Promise<Object>} Test result
369
- */
370
- async testQuotaDetection(ide) {
371
- this.logger.log(`๐Ÿงช Testing quota detection for ${ide}...`);
372
-
373
- try {
374
- const quotaResult = await this.detectQuotaWarning(ide);
375
-
376
- this.logger.log(`๐Ÿงช Quota detection test result for ${ide}:`, quotaResult);
377
-
378
- return {
379
- ide,
380
- success: true,
381
- hasQuotaWarning: quotaResult.hasQuotaWarning,
382
- method: quotaResult.method,
383
- note: quotaResult.note,
384
- debug: quotaResult
385
- };
386
- } catch (error) {
387
- this.logger.log(`โŒ Quota detection test failed for ${ide}: ${error.message}`);
388
-
389
- return {
390
- ide,
391
- success: false,
392
- error: error.message,
393
- note: `Quota detection test failed for ${ide}`
394
- };
395
- }
396
- }
397
- }
398
-
399
- module.exports = { QuotaDetector };
1
+ // @vibecodingmachine/core - Quota Detector (CommonJS)
2
+ // Handles quota detection for different IDEs using CDP and AppleScript
3
+
4
+ const CDP = require('chrome-remote-interface');
5
+ const { AppleScriptManager } = require('./applescript-manager.cjs');
6
+
7
+ /**
8
+ * Quota Detector for IDE interactions
9
+ * Detects quota warnings in different IDEs using CDP and AppleScript
10
+ */
11
+ 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
+ 'monthly chat messages quota',
129
+ 'upgrade to copilot pro',
130
+ 'allowance to renew',
131
+ 'reached your monthly',
132
+ 'wait for your allowance',
133
+ // Kiro-specific patterns
134
+ "you're out of credits",
135
+ 'upgrade to a higher plan',
136
+ 'wait for next month',
137
+ "next month's new set of credits",
138
+ 'including steering documents'
139
+ ];
140
+
141
+ // Function to check if text contains quota warnings
142
+ function containsQuotaWarning(text) {
143
+ if (!text) return false;
144
+ const lowerText = text.toLowerCase();
145
+ return quotaPatterns.some(pattern => lowerText.includes(pattern));
146
+ }
147
+
148
+ // Method 1: Check all text content in the document
149
+ const allText = document.body.innerText || document.body.textContent || '';
150
+ if (containsQuotaWarning(allText)) {
151
+ console.log('โŒ Quota warning detected in document text');
152
+ return {
153
+ hasQuotaWarning: true,
154
+ method: 'document-text',
155
+ matchedText: allText.substring(0, 200) + '...'
156
+ };
157
+ }
158
+
159
+ // Method 2: Check specific elements that might contain quota warnings
160
+ const quotaElements = [
161
+ // VS Code specific selectors
162
+ '.monaco-workbench .part.auxiliarybar',
163
+ '.monaco-workbench .part.sidebar.right',
164
+ '.monaco-workbench .chat-view',
165
+ '.monaco-workbench .chat-input',
166
+
167
+ // Cursor specific selectors
168
+ '.aislash-editor-input',
169
+ '.aislash-chat-container',
170
+ '.aislash-panel',
171
+
172
+ // Kiro specific selectors (AWS Kiro runs in VS Code)
173
+ '[class*="kiro"]',
174
+ '[data-testid*="kiro"]',
175
+ '[aria-label*="kiro"]',
176
+ '.webview',
177
+ 'iframe',
178
+
179
+ // Generic selectors
180
+ '[data-testid*="chat"]',
181
+ '[aria-label*="chat"]',
182
+ '[class*="chat"]',
183
+ '[class*="quota"]',
184
+ '[class*="credits"]',
185
+ '[class*="billing"]'
186
+ ];
187
+
188
+ for (const selector of quotaElements) {
189
+ const elements = document.querySelectorAll(selector);
190
+ for (const element of elements) {
191
+ const elementText = element.innerText || element.textContent || '';
192
+ if (containsQuotaWarning(elementText)) {
193
+ console.log('โŒ Quota warning detected in element:', selector);
194
+ return {
195
+ hasQuotaWarning: true,
196
+ method: 'element-specific',
197
+ selector: selector,
198
+ matchedText: elementText.substring(0, 200) + '...'
199
+ };
200
+ }
201
+ }
202
+ }
203
+
204
+ // Method 3: Check for disabled input fields (common when quota is exceeded)
205
+ const disabledInputs = document.querySelectorAll('input[disabled], textarea[disabled], [contenteditable="true"][aria-disabled="true"]');
206
+ if (disabledInputs.length > 0) {
207
+ console.log('โš ๏ธ Found disabled input fields, checking for quota context...');
208
+
209
+ // Check if there are quota-related messages near disabled inputs
210
+ for (const input of disabledInputs) {
211
+ const parentText = input.parentElement?.innerText || '';
212
+ if (containsQuotaWarning(parentText)) {
213
+ console.log('โŒ Quota warning detected near disabled input');
214
+ return {
215
+ hasQuotaWarning: true,
216
+ method: 'disabled-input-context',
217
+ matchedText: parentText.substring(0, 200) + '...'
218
+ };
219
+ }
220
+ }
221
+ }
222
+
223
+ // Method 4: Check for specific UI elements that indicate quota issues
224
+ const quotaButtons = document.querySelectorAll('button, a, [role="button"]');
225
+ for (const button of quotaButtons) {
226
+ const buttonText = button.innerText || button.textContent || '';
227
+ if (containsQuotaWarning(buttonText)) {
228
+ console.log('โŒ Quota warning detected in button:', buttonText);
229
+ return {
230
+ hasQuotaWarning: true,
231
+ method: 'button-text',
232
+ matchedText: buttonText
233
+ };
234
+ }
235
+ }
236
+
237
+ // Method 5: Check for error messages or notifications
238
+ const errorElements = document.querySelectorAll('[class*="error"], [class*="warning"], [class*="notification"], [role="alert"]');
239
+ for (const error of errorElements) {
240
+ const errorText = error.innerText || error.textContent || '';
241
+ if (containsQuotaWarning(errorText)) {
242
+ console.log('โŒ Quota warning detected in error element');
243
+ return {
244
+ hasQuotaWarning: true,
245
+ method: 'error-element',
246
+ matchedText: errorText.substring(0, 200) + '...'
247
+ };
248
+ }
249
+ }
250
+
251
+ // Method 6: Check inside iframes/webviews (important for Kiro and other webview-based extensions)
252
+ try {
253
+ const iframes = document.querySelectorAll('iframe, webview');
254
+ console.log(\`๐Ÿ” Found \${iframes.length} iframe/webview elements to check\`);
255
+
256
+ for (const frame of iframes) {
257
+ try {
258
+ // Try to access iframe content (will fail if cross-origin)
259
+ const frameDoc = frame.contentDocument || frame.contentWindow?.document;
260
+ if (frameDoc) {
261
+ const frameText = frameDoc.body?.innerText || frameDoc.body?.textContent || '';
262
+ if (containsQuotaWarning(frameText)) {
263
+ console.log('โŒ Quota warning detected in iframe/webview');
264
+ return {
265
+ hasQuotaWarning: true,
266
+ method: 'iframe-content',
267
+ matchedText: frameText.substring(0, 200) + '...'
268
+ };
269
+ }
270
+ }
271
+ } catch (e) {
272
+ // Cross-origin iframe - can't access, skip
273
+ console.log('โš ๏ธ Cannot access iframe content (likely cross-origin)');
274
+ }
275
+ }
276
+ } catch (e) {
277
+ console.log('โš ๏ธ Error checking iframes:', e.message);
278
+ }
279
+
280
+ console.log('โœ… No quota warnings detected');
281
+ return {
282
+ hasQuotaWarning: false,
283
+ method: 'cdp-comprehensive',
284
+ note: 'No quota warnings found in ${ideName}'
285
+ };
286
+ })()
287
+ `;
288
+
289
+ const { result } = await this.timeout(10000, Runtime.evaluate({
290
+ expression: detectionScript,
291
+ returnByValue: true
292
+ }));
293
+
294
+ const detectionResult = result.value || result.unserializableValue;
295
+
296
+ this.logger.log('๐Ÿ” CDP quota detection result:', detectionResult);
297
+
298
+ if (detectionResult && detectionResult.hasQuotaWarning) {
299
+ this.logger.log('โŒ Quota warning detected via CDP');
300
+ return {
301
+ hasQuotaWarning: true,
302
+ method: detectionResult.method,
303
+ matchedText: detectionResult.matchedText || 'Quota warning detected via CDP',
304
+ note: detectionResult.matchedText || 'Quota warning detected via CDP',
305
+ debug: detectionResult
306
+ };
307
+ }
308
+
309
+ this.logger.log('โœ… No quota warnings detected via CDP');
310
+ return {
311
+ hasQuotaWarning: false,
312
+ method: 'cdp-comprehensive',
313
+ note: 'No quota warnings found in ' + ideName,
314
+ debug: detectionResult
315
+ };
316
+
317
+ } catch (error) {
318
+ this.logger.log(`โŒ CDP quota detection failed: ${error.message}`);
319
+
320
+ // For Windsurf, fall back to AppleScript
321
+ if (ide === 'windsurf') {
322
+ this.logger.log('๐Ÿ” Falling back to AppleScript quota detection...');
323
+ return await this.appleScriptManager.detectQuotaWarning(ide);
324
+ }
325
+
326
+ return {
327
+ hasQuotaWarning: false,
328
+ error: error.message,
329
+ note: `CDP quota detection failed for ${ideName}`
330
+ };
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Get available IDEs without quota warnings
336
+ * @param {Array<string>} ides - Array of IDE names to check
337
+ * @returns {Promise<Array<string>>} Array of available IDE names
338
+ */
339
+ async getAvailableIdes(ides = ['vscode', 'cursor', 'windsurf']) {
340
+ this.logger.log('๐Ÿ” Checking available IDEs without quota warnings...');
341
+
342
+ const availableIdes = [];
343
+
344
+ for (const ide of ides) {
345
+ try {
346
+ const quotaResult = await this.detectQuotaWarning(ide);
347
+
348
+ if (!quotaResult.hasQuotaWarning) {
349
+ availableIdes.push(ide);
350
+ this.logger.log(`โœ… ${ide} is available (no quota warnings)`);
351
+ } else {
352
+ this.logger.log(`โŒ ${ide} has quota warnings: ${quotaResult.note || 'Unknown quota issue'}`);
353
+ }
354
+ } catch (error) {
355
+ this.logger.log(`โš ๏ธ Error checking ${ide}: ${error.message}`);
356
+ // If we can't check quota, assume the IDE is available
357
+ availableIdes.push(ide);
358
+ }
359
+ }
360
+
361
+ this.logger.log(`๐Ÿ“‹ Available IDEs: ${availableIdes.join(', ')}`);
362
+ return availableIdes;
363
+ }
364
+
365
+ /**
366
+ * Test quota detection with a test message
367
+ * @param {string} ide - The IDE name to test
368
+ * @returns {Promise<Object>} Test result
369
+ */
370
+ async testQuotaDetection(ide) {
371
+ this.logger.log(`๐Ÿงช Testing quota detection for ${ide}...`);
372
+
373
+ try {
374
+ const quotaResult = await this.detectQuotaWarning(ide);
375
+
376
+ this.logger.log(`๐Ÿงช Quota detection test result for ${ide}:`, quotaResult);
377
+
378
+ return {
379
+ ide,
380
+ success: true,
381
+ hasQuotaWarning: quotaResult.hasQuotaWarning,
382
+ method: quotaResult.method,
383
+ note: quotaResult.note,
384
+ debug: quotaResult
385
+ };
386
+ } catch (error) {
387
+ this.logger.log(`โŒ Quota detection test failed for ${ide}: ${error.message}`);
388
+
389
+ return {
390
+ ide,
391
+ success: false,
392
+ error: error.message,
393
+ note: `Quota detection test failed for ${ide}`
394
+ };
395
+ }
396
+ }
397
+ }
398
+
399
+ module.exports = { QuotaDetector };