vibecodingmachine-core 2026.1.3-2209 → 2026.1.23-1010
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/__tests__/provider-manager-fallback.test.js +43 -0
- package/__tests__/provider-manager-rate-limit.test.js +61 -0
- package/package.json +1 -1
- package/src/compliance/compliance-manager.js +5 -2
- package/src/database/migrations.js +135 -12
- package/src/database/user-database-client.js +63 -8
- package/src/database/user-schema.js +7 -0
- package/src/health-tracking/__tests__/ide-health-tracker.test.js +420 -0
- package/src/health-tracking/__tests__/interaction-recorder.test.js +392 -0
- package/src/health-tracking/errors.js +50 -0
- package/src/health-tracking/health-reporter.js +331 -0
- package/src/health-tracking/ide-health-tracker.js +446 -0
- package/src/health-tracking/interaction-recorder.js +161 -0
- package/src/health-tracking/json-storage.js +276 -0
- package/src/health-tracking/storage-interface.js +63 -0
- package/src/health-tracking/validators.js +277 -0
- package/src/ide-integration/applescript-manager.cjs +1062 -4
- package/src/ide-integration/applescript-manager.js +560 -11
- package/src/ide-integration/provider-manager.cjs +158 -28
- package/src/ide-integration/quota-detector.cjs +339 -16
- package/src/ide-integration/quota-detector.js +6 -1
- package/src/index.cjs +32 -1
- package/src/index.js +16 -0
- package/src/localization/translations/en.js +13 -1
- package/src/localization/translations/es.js +12 -0
- package/src/utils/admin-utils.js +33 -0
- package/src/utils/error-reporter.js +12 -4
- package/src/utils/requirement-helpers.js +34 -4
- package/src/utils/requirements-parser.js +3 -3
- package/tests/health-tracking/health-reporter.test.js +329 -0
- package/tests/health-tracking/ide-health-tracker.test.js +368 -0
- package/tests/health-tracking/interaction-recorder.test.js +309 -0
|
@@ -370,19 +370,43 @@ class AppleScriptManager {
|
|
|
370
370
|
|
|
371
371
|
// Handle macOS platform
|
|
372
372
|
try {
|
|
373
|
-
this.logger.log('Opening VS Code...');
|
|
373
|
+
this.logger.log('Opening VS Code with remote debugging enabled...');
|
|
374
374
|
|
|
375
|
-
|
|
375
|
+
// First, check if VS Code is already running
|
|
376
|
+
try {
|
|
377
|
+
const isRunning = execSync('pgrep -x "Code"', { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
378
|
+
if (isRunning) {
|
|
379
|
+
this.logger.log('VS Code is already running - closing it to enable remote debugging...');
|
|
380
|
+
execSync('pkill -x "Code"', { stdio: 'pipe' });
|
|
381
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
// VS Code not running, that's fine
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Launch VS Code with remote debugging enabled for quota detection
|
|
388
|
+
let command = 'open -a "Visual Studio Code" --args --remote-debugging-port=9222';
|
|
376
389
|
if (repoPath) {
|
|
377
|
-
command
|
|
390
|
+
command = `open -a "Visual Studio Code" "${repoPath}" --args --remote-debugging-port=9222`;
|
|
378
391
|
this.logger.log(`Opening VS Code with repository: ${repoPath}`);
|
|
379
392
|
}
|
|
380
393
|
|
|
381
394
|
execSync(command, { stdio: 'pipe' });
|
|
382
395
|
|
|
383
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
396
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
397
|
+
|
|
398
|
+
// Verify remote debugging port is accessible
|
|
399
|
+
try {
|
|
400
|
+
const CDP = require('chrome-remote-interface');
|
|
401
|
+
await CDP.List({ port: 9222 });
|
|
402
|
+
this.logger.log('✅ VS Code remote debugging port 9222 is accessible');
|
|
403
|
+
} catch (cdpError) {
|
|
404
|
+
this.logger.log(`⚠️ Warning: VS Code remote debugging port not accessible: ${cdpError.message}`);
|
|
405
|
+
this.logger.log(' Waiting additional 2 seconds for VS Code to fully start...');
|
|
406
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
407
|
+
}
|
|
384
408
|
|
|
385
|
-
this.logger.log('VS Code opened successfully');
|
|
409
|
+
this.logger.log('VS Code opened successfully with remote debugging');
|
|
386
410
|
return { success: true, message: `VS Code opened with repository: ${repoPath}`, method: 'applescript' };
|
|
387
411
|
} catch (error) {
|
|
388
412
|
this.logger.log('Error opening VS Code:', error.message);
|
|
@@ -390,6 +414,125 @@ class AppleScriptManager {
|
|
|
390
414
|
}
|
|
391
415
|
}
|
|
392
416
|
|
|
417
|
+
/**
|
|
418
|
+
* Open VS Code with a specific extension installed
|
|
419
|
+
* @param {string} extension - Extension key (e.g., 'github-copilot', 'amazon-q')
|
|
420
|
+
* @param {string} repoPath - Optional repository path to open
|
|
421
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
422
|
+
*/
|
|
423
|
+
async openVSCodeWithExtension(extension, repoPath = null) {
|
|
424
|
+
try {
|
|
425
|
+
this.logger.log(`Opening VS Code with ${extension} extension...`);
|
|
426
|
+
|
|
427
|
+
// Extension IDs mapping
|
|
428
|
+
const extensionIds = {
|
|
429
|
+
'github-copilot': 'GitHub.copilot',
|
|
430
|
+
'amazon-q': 'amazonwebservices.amazon-q-vscode',
|
|
431
|
+
'continue': 'Continue.continue'
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const extensionId = extensionIds[extension];
|
|
435
|
+
if (!extensionId) {
|
|
436
|
+
return { success: false, error: `Unknown extension: ${extension}`, method: 'applescript' };
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// First, check if the extension is installed
|
|
440
|
+
try {
|
|
441
|
+
const checkCmd = `code --list-extensions | grep -i "${extensionId}"`;
|
|
442
|
+
execSync(checkCmd, { stdio: 'pipe' });
|
|
443
|
+
this.logger.log(`Extension ${extension} is already installed`);
|
|
444
|
+
} catch (checkError) {
|
|
445
|
+
// Extension not found, try to install it
|
|
446
|
+
this.logger.log(`Extension ${extension} not found, installing...`);
|
|
447
|
+
try {
|
|
448
|
+
execSync(`code --install-extension ${extensionId} --force`, { stdio: 'pipe', timeout: 60000 });
|
|
449
|
+
this.logger.log(`Extension ${extension} installed successfully`);
|
|
450
|
+
} catch (installError) {
|
|
451
|
+
this.logger.log(`Failed to install extension ${extension}:`, installError.message);
|
|
452
|
+
return { success: false, error: `Failed to install extension: ${installError.message}`, method: 'applescript' };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// First, check if VS Code is already running
|
|
457
|
+
try {
|
|
458
|
+
const isRunning = execSync('pgrep -x "Code"', { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
459
|
+
if (isRunning) {
|
|
460
|
+
this.logger.log('VS Code is already running - closing it to enable remote debugging...');
|
|
461
|
+
execSync('pkill -x "Code"', { stdio: 'pipe' });
|
|
462
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
463
|
+
}
|
|
464
|
+
} catch (err) {
|
|
465
|
+
// VS Code not running, that's fine
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Open VS Code with the repository and remote debugging enabled
|
|
469
|
+
let command = 'open -a "Visual Studio Code" --args --remote-debugging-port=9222';
|
|
470
|
+
if (repoPath) {
|
|
471
|
+
command = `open -a "Visual Studio Code" "${repoPath}" --args --remote-debugging-port=9222`;
|
|
472
|
+
this.logger.log(`Opening VS Code with repository: ${repoPath}`);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
execSync(command, { stdio: 'pipe' });
|
|
476
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
477
|
+
|
|
478
|
+
// Verify remote debugging port is accessible
|
|
479
|
+
try {
|
|
480
|
+
const CDP = require('chrome-remote-interface');
|
|
481
|
+
await CDP.List({ port: 9222 });
|
|
482
|
+
this.logger.log('✅ VS Code remote debugging port 9222 is accessible');
|
|
483
|
+
} catch (cdpError) {
|
|
484
|
+
this.logger.log(`⚠️ Warning: VS Code remote debugging port not accessible: ${cdpError.message}`);
|
|
485
|
+
this.logger.log(' Waiting additional 2 seconds for VS Code to fully start...');
|
|
486
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
this.logger.log(`VS Code opened successfully with ${extension} extension and remote debugging`);
|
|
490
|
+
return { success: true, message: `VS Code opened with ${extension} extension`, method: 'applescript' };
|
|
491
|
+
} catch (error) {
|
|
492
|
+
this.logger.log(`Error opening VS Code with ${extension}:`, error.message);
|
|
493
|
+
return { success: false, error: error.message, method: 'applescript' };
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Open Replit Agent with optional repository path
|
|
499
|
+
* @param {string} repoPath - Optional repository path to open
|
|
500
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
501
|
+
*/
|
|
502
|
+
async openReplit(repoPath = null) {
|
|
503
|
+
try {
|
|
504
|
+
this.logger.log('Opening Replit...');
|
|
505
|
+
this.logger.log(`Platform detected: ${this.platform}`);
|
|
506
|
+
|
|
507
|
+
// Replit typically uses web browser, so we'll open the Replit website
|
|
508
|
+
// If Replit has a desktop app or CLI, this can be updated
|
|
509
|
+
const replitUrl = repoPath
|
|
510
|
+
? `https://replit.com/@replit/agent?path=${encodeURIComponent(repoPath)}`
|
|
511
|
+
: 'https://replit.com/@replit/agent';
|
|
512
|
+
|
|
513
|
+
let command;
|
|
514
|
+
if (this.platform === 'darwin') {
|
|
515
|
+
command = `open "${replitUrl}"`;
|
|
516
|
+
this.logger.log(`Using macOS command: ${command}`);
|
|
517
|
+
} else if (this.platform === 'win32') {
|
|
518
|
+
command = `start "" "${replitUrl}"`;
|
|
519
|
+
this.logger.log(`Using Windows command: ${command}`);
|
|
520
|
+
} else {
|
|
521
|
+
command = `xdg-open "${replitUrl}"`;
|
|
522
|
+
this.logger.log(`Using Linux command: ${command}`);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
execSync(command, { stdio: 'pipe' });
|
|
526
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
527
|
+
|
|
528
|
+
this.logger.log('Replit opened successfully');
|
|
529
|
+
return { success: true, message: 'Replit opened in browser', method: 'applescript' };
|
|
530
|
+
} catch (error) {
|
|
531
|
+
this.logger.log('Error opening Replit:', error.message);
|
|
532
|
+
return { success: false, error: error.message, method: 'applescript' };
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
393
536
|
|
|
394
537
|
/**
|
|
395
538
|
* Open Windsurf IDE with optional repository path
|
|
@@ -562,6 +705,85 @@ class AppleScriptManager {
|
|
|
562
705
|
}
|
|
563
706
|
}
|
|
564
707
|
|
|
708
|
+
/**
|
|
709
|
+
* Check Antigravity UI for Gemini quota limit popup text.
|
|
710
|
+
* This is best-effort: Antigravity may render the popup in a WebView that AppleScript can't read.
|
|
711
|
+
* @returns {Promise<{isRateLimited: boolean, message?: string, resumeAt?: string, note?: string}>}
|
|
712
|
+
*/
|
|
713
|
+
async checkAntigravityQuotaLimit() {
|
|
714
|
+
try {
|
|
715
|
+
const script = `
|
|
716
|
+
tell application "System Events"
|
|
717
|
+
if not (exists process "Antigravity") then
|
|
718
|
+
return "NOT_RUNNING"
|
|
719
|
+
end if
|
|
720
|
+
tell process "Antigravity"
|
|
721
|
+
set frontmost to true
|
|
722
|
+
delay 0.4
|
|
723
|
+
|
|
724
|
+
set allText to ""
|
|
725
|
+
try
|
|
726
|
+
set allText to allText & (value of static text of window 1 as string) & "\\n"
|
|
727
|
+
end try
|
|
728
|
+
|
|
729
|
+
try
|
|
730
|
+
set groupsList to groups of window 1
|
|
731
|
+
repeat with g in groupsList
|
|
732
|
+
try
|
|
733
|
+
set allText to allText & (value of static text of g as string) & "\\n"
|
|
734
|
+
end try
|
|
735
|
+
end repeat
|
|
736
|
+
end try
|
|
737
|
+
|
|
738
|
+
return allText
|
|
739
|
+
end tell
|
|
740
|
+
end tell
|
|
741
|
+
`;
|
|
742
|
+
|
|
743
|
+
const raw = execSync(`osascript -e '${script.replace(/'/g, "'\\\\''")}'`, {
|
|
744
|
+
encoding: 'utf8',
|
|
745
|
+
timeout: 8000
|
|
746
|
+
}).trim();
|
|
747
|
+
|
|
748
|
+
if (!raw || raw === 'NOT_RUNNING') {
|
|
749
|
+
return {
|
|
750
|
+
isRateLimited: false,
|
|
751
|
+
note: raw === 'NOT_RUNNING' ? 'Antigravity not running' : 'No readable UI text'
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const text = raw.replace(/\\s+/g, ' ').trim();
|
|
756
|
+
const lower = text.toLowerCase();
|
|
757
|
+
|
|
758
|
+
const hasGeminiQuota = lower.includes('model quota limit exceeded') ||
|
|
759
|
+
(lower.includes('quota limit') && lower.includes('you can resume')) ||
|
|
760
|
+
lower.includes('you have reached the quota limit') ||
|
|
761
|
+
lower.includes('spending cap reached') ||
|
|
762
|
+
lower.includes('usage cap reached') ||
|
|
763
|
+
lower.includes('rate limit reached');
|
|
764
|
+
|
|
765
|
+
if (!hasGeminiQuota) {
|
|
766
|
+
return { isRateLimited: false };
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const resumeAtMatch = text.match(/resume\s+(?:using\s+this\s+model\s+)?at\s+(\d{1,2}\/\d{1,2}\/\d{4})\s*,?\s*(\d{1,2}:\d{2}(?::\d{2})?)\s*(AM|PM)/i);
|
|
770
|
+
const resumeAt = resumeAtMatch
|
|
771
|
+
? `${resumeAtMatch[1]}, ${resumeAtMatch[2]} ${resumeAtMatch[3].toUpperCase()}`
|
|
772
|
+
: undefined;
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
isRateLimited: true,
|
|
776
|
+
message: text,
|
|
777
|
+
resumeAt
|
|
778
|
+
};
|
|
779
|
+
} catch (error) {
|
|
780
|
+
return {
|
|
781
|
+
isRateLimited: false,
|
|
782
|
+
note: `Failed to check Antigravity quota: ${error.message}`
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
565
787
|
/**
|
|
566
788
|
* Handle Antigravity quota limit by automatically switching models
|
|
567
789
|
* @returns {Promise<{success: boolean, model?: string, error?: string}>}
|
|
@@ -617,7 +839,7 @@ class AppleScriptManager {
|
|
|
617
839
|
|
|
618
840
|
-- Look for model dropdown/menu items
|
|
619
841
|
-- Try alternative models in order of preference
|
|
620
|
-
set modelNames to {"Gemini 3 Pro (Low)", "Claude Sonnet 4.5", "Claude Sonnet 4.5 (Thinking)", "GPT-OSS 120B (Medium)"}
|
|
842
|
+
set modelNames to {"Gemini 3 Flash", "Gemini 3 Pro (High)", "Gemini 3 Pro (Low)", "Claude Sonnet 4.5", "Claude Sonnet 4.5 (Thinking)", "Claude Opus 4.5 (Thinking)", "GPT-OSS 120B (Medium)"}
|
|
621
843
|
|
|
622
844
|
repeat with modelName in modelNames
|
|
623
845
|
try
|
|
@@ -626,7 +848,7 @@ class AppleScriptManager {
|
|
|
626
848
|
|
|
627
849
|
-- Try menu items
|
|
628
850
|
try
|
|
629
|
-
set modelItems to menu items of menu 1 of window 1 whose name
|
|
851
|
+
set modelItems to menu items of menu 1 of window 1 whose name contains modelName
|
|
630
852
|
end try
|
|
631
853
|
|
|
632
854
|
-- Try buttons if no menu items found
|
|
@@ -636,6 +858,22 @@ class AppleScriptManager {
|
|
|
636
858
|
end try
|
|
637
859
|
end if
|
|
638
860
|
|
|
861
|
+
-- Search in groups
|
|
862
|
+
if (count of modelItems) = 0 then
|
|
863
|
+
try
|
|
864
|
+
set allGroups to groups of window 1
|
|
865
|
+
repeat with grp in allGroups
|
|
866
|
+
try
|
|
867
|
+
set matchingItems to (every UI element of grp whose name contains modelName)
|
|
868
|
+
if (count of matchingItems) > 0 then
|
|
869
|
+
set modelItems to matchingItems
|
|
870
|
+
exit repeat
|
|
871
|
+
end if
|
|
872
|
+
end try
|
|
873
|
+
end repeat
|
|
874
|
+
end try
|
|
875
|
+
end if
|
|
876
|
+
|
|
639
877
|
if (count of modelItems) > 0 then
|
|
640
878
|
click item 1 of modelItems
|
|
641
879
|
delay 0.8
|
|
@@ -711,6 +949,14 @@ class AppleScriptManager {
|
|
|
711
949
|
return await this.openAntigravity(repoPath);
|
|
712
950
|
case 'vscode':
|
|
713
951
|
return await this.openVSCode(repoPath);
|
|
952
|
+
case 'github-copilot':
|
|
953
|
+
// Open VS Code with GitHub Copilot extension
|
|
954
|
+
return await this.openVSCodeWithExtension('github-copilot', repoPath);
|
|
955
|
+
case 'amazon-q':
|
|
956
|
+
// Open VS Code with Amazon Q extension
|
|
957
|
+
return await this.openVSCodeWithExtension('amazon-q', repoPath);
|
|
958
|
+
case 'replit':
|
|
959
|
+
return await this.openReplit(repoPath);
|
|
714
960
|
case 'kiro':
|
|
715
961
|
return await this.openKiro(repoPath);
|
|
716
962
|
case 'claude':
|
|
@@ -721,7 +967,7 @@ class AppleScriptManager {
|
|
|
721
967
|
default:
|
|
722
968
|
return {
|
|
723
969
|
success: false,
|
|
724
|
-
error: `Unknown IDE: ${ide}. Supported: cursor, windsurf, antigravity, vscode, claude, claude-code, gemini`
|
|
970
|
+
error: `Unknown IDE: ${ide}. Supported: cursor, windsurf, antigravity, vscode, github-copilot, amazon-q, replit, kiro, claude, claude-code, gemini`
|
|
725
971
|
};
|
|
726
972
|
}
|
|
727
973
|
}
|
|
@@ -833,7 +1079,23 @@ class AppleScriptManager {
|
|
|
833
1079
|
|
|
834
1080
|
-- Press Enter (increased delay for chat window to fully open)
|
|
835
1081
|
key code 36
|
|
836
|
-
delay
|
|
1082
|
+
delay 3.0
|
|
1083
|
+
|
|
1084
|
+
-- Additional step for Amazon Q: ensure it's properly focused
|
|
1085
|
+
${extension === 'amazon-q' ? `
|
|
1086
|
+
-- Wait for Amazon Q to fully load and then ensure focus
|
|
1087
|
+
delay 1.0
|
|
1088
|
+
-- Try to set focus to the Amazon Q chat input
|
|
1089
|
+
try
|
|
1090
|
+
-- Look for the Amazon Q chat input field and focus it
|
|
1091
|
+
keystroke tab
|
|
1092
|
+
delay 0.5
|
|
1093
|
+
keystroke tab
|
|
1094
|
+
delay 0.5
|
|
1095
|
+
on error
|
|
1096
|
+
-- If tab navigation fails, continue
|
|
1097
|
+
end try
|
|
1098
|
+
` : ''}
|
|
837
1099
|
|
|
838
1100
|
|
|
839
1101
|
-- Type the message (increased delay for input field to be ready)
|
|
@@ -1231,8 +1493,9 @@ class AppleScriptManager {
|
|
|
1231
1493
|
} else if (ide === 'cursor') {
|
|
1232
1494
|
// Cursor already has new chat logic in generateAIPanelFocusScript (Cmd+T)
|
|
1233
1495
|
appleScript = this.appleScriptUtils.generateAIPanelFocusScript(text, 'Cursor');
|
|
1234
|
-
} else if (ide === 'vscode') {
|
|
1496
|
+
} else if (ide === 'vscode' || ide === 'github-copilot' || ide === 'amazon-q') {
|
|
1235
1497
|
// Delegate to the dedicated VS Code method
|
|
1498
|
+
// github-copilot and amazon-q are VS Code extensions
|
|
1236
1499
|
return await this.sendTextToVSCode(text);
|
|
1237
1500
|
} else if (ide === 'antigravity') {
|
|
1238
1501
|
// AppleScript for Google Antigravity - Cmd+Shift+L opens Agent chat (non-toggle)
|
|
@@ -1311,7 +1574,7 @@ class AppleScriptManager {
|
|
|
1311
1574
|
return {
|
|
1312
1575
|
success: false,
|
|
1313
1576
|
error: `Unsupported IDE for AppleScript: ${ide}`,
|
|
1314
|
-
note: 'AppleScript is only supported for Cursor, Windsurf, Antigravity, VS Code,
|
|
1577
|
+
note: 'AppleScript is only supported for Cursor, Windsurf, Antigravity, VS Code, GitHub Copilot, Amazon Q, AWS Kiro, and Claude'
|
|
1315
1578
|
};
|
|
1316
1579
|
}
|
|
1317
1580
|
|
|
@@ -1353,6 +1616,28 @@ class AppleScriptManager {
|
|
|
1353
1616
|
} catch (error) {
|
|
1354
1617
|
this.logger.log('AppleScript interaction failed:', error.message);
|
|
1355
1618
|
|
|
1619
|
+
// Check for Accessibility permission error
|
|
1620
|
+
if (error.message.includes('not allowed to send keystrokes') ||
|
|
1621
|
+
error.message.includes('assistive devices') ||
|
|
1622
|
+
(error.message.includes('System Events') && error.message.includes('not allowed'))) {
|
|
1623
|
+
|
|
1624
|
+
this.logger.log('⚠️ Accessibility permissions missing. Opening System Settings...');
|
|
1625
|
+
try {
|
|
1626
|
+
// Open System Settings -> Privacy & Security -> Accessibility
|
|
1627
|
+
execSync('open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"');
|
|
1628
|
+
} catch (settingsErr) {
|
|
1629
|
+
this.logger.log('Failed to open System Settings:', settingsErr.message);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
return {
|
|
1633
|
+
success: false,
|
|
1634
|
+
error: 'Missing Accessibility Permissions',
|
|
1635
|
+
message: 'Please grant Accessibility permissions to Terminal/Node in System Settings',
|
|
1636
|
+
permissionError: true,
|
|
1637
|
+
note: 'macOS blocked keystroke automation. Opened settings for user.'
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1356
1641
|
// For Claude, don't fall back to simulated response - return actual failure
|
|
1357
1642
|
if (ide === 'claude' || ide === 'claude-code') {
|
|
1358
1643
|
return {
|
|
@@ -1363,6 +1648,16 @@ class AppleScriptManager {
|
|
|
1363
1648
|
};
|
|
1364
1649
|
}
|
|
1365
1650
|
|
|
1651
|
+
// For Antigravity, also return failure to trigger user notification in auto.js
|
|
1652
|
+
if (ide === 'antigravity' || ide === 'kiro') {
|
|
1653
|
+
return {
|
|
1654
|
+
success: false,
|
|
1655
|
+
method: 'applescript',
|
|
1656
|
+
error: `Failed to send text to ${ideName}: ${error.message}`,
|
|
1657
|
+
note: `${ideName} automation failed.`
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1366
1661
|
// For other IDEs, fall back to simulated response
|
|
1367
1662
|
return {
|
|
1368
1663
|
success: true,
|
|
@@ -2937,6 +3232,260 @@ end tell
|
|
|
2937
3232
|
};
|
|
2938
3233
|
}
|
|
2939
3234
|
}
|
|
3235
|
+
|
|
3236
|
+
/**
|
|
3237
|
+
* Check if an IDE is running and accessible
|
|
3238
|
+
* @param {string} ide - The IDE name
|
|
3239
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
3240
|
+
*/
|
|
3241
|
+
async getIDEStatus(ide) {
|
|
3242
|
+
if (!ide || typeof ide !== 'string') {
|
|
3243
|
+
return {
|
|
3244
|
+
success: false,
|
|
3245
|
+
error: 'Invalid IDE name provided',
|
|
3246
|
+
running: false
|
|
3247
|
+
};
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
try {
|
|
3251
|
+
this.logger.log(`🔍 Checking status of ${ide}...`);
|
|
3252
|
+
|
|
3253
|
+
switch (ide.toLowerCase()) {
|
|
3254
|
+
case 'cursor':
|
|
3255
|
+
return await this._checkCursorStatus();
|
|
3256
|
+
case 'vscode':
|
|
3257
|
+
return await this._checkVSCodeStatus();
|
|
3258
|
+
case 'windsurf':
|
|
3259
|
+
return await this._checkWindsurfStatus();
|
|
3260
|
+
case 'antigravity':
|
|
3261
|
+
return await this._checkAntigravityStatus();
|
|
3262
|
+
case 'cline':
|
|
3263
|
+
return await this._checkClineStatus();
|
|
3264
|
+
default:
|
|
3265
|
+
return {
|
|
3266
|
+
success: false,
|
|
3267
|
+
error: `Unsupported IDE: ${ide}`,
|
|
3268
|
+
running: false
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
} catch (error) {
|
|
3272
|
+
return {
|
|
3273
|
+
success: false,
|
|
3274
|
+
error: `Failed to check IDE status: ${error.message}`,
|
|
3275
|
+
running: false
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
/**
|
|
3281
|
+
* Check Cursor status
|
|
3282
|
+
* @private
|
|
3283
|
+
*/
|
|
3284
|
+
async _checkCursorStatus() {
|
|
3285
|
+
try {
|
|
3286
|
+
const script = `
|
|
3287
|
+
tell application "System Events"
|
|
3288
|
+
set isRunning to (exists process "Cursor")
|
|
3289
|
+
if isRunning then
|
|
3290
|
+
try
|
|
3291
|
+
tell application "Cursor" to activate
|
|
3292
|
+
delay 0.5
|
|
3293
|
+
return "running"
|
|
3294
|
+
on error
|
|
3295
|
+
return "error"
|
|
3296
|
+
end try
|
|
3297
|
+
else
|
|
3298
|
+
return "not_running"
|
|
3299
|
+
end if
|
|
3300
|
+
end tell
|
|
3301
|
+
`;
|
|
3302
|
+
|
|
3303
|
+
const result = this.appleScriptUtils.executeAppleScript(script);
|
|
3304
|
+
const running = result.includes('running');
|
|
3305
|
+
|
|
3306
|
+
return {
|
|
3307
|
+
success: true,
|
|
3308
|
+
running,
|
|
3309
|
+
status: running ? 'running' : 'not_running',
|
|
3310
|
+
message: running ? 'Cursor is running and accessible' : 'Cursor is not running'
|
|
3311
|
+
};
|
|
3312
|
+
} catch (error) {
|
|
3313
|
+
return {
|
|
3314
|
+
success: false,
|
|
3315
|
+
error: `Failed to check Cursor status: ${error.message}`,
|
|
3316
|
+
running: false
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
/**
|
|
3322
|
+
* Check VS Code status
|
|
3323
|
+
* @private
|
|
3324
|
+
*/
|
|
3325
|
+
async _checkVSCodeStatus() {
|
|
3326
|
+
try {
|
|
3327
|
+
const script = `
|
|
3328
|
+
tell application "System Events"
|
|
3329
|
+
set isRunning to (exists process "Code")
|
|
3330
|
+
if isRunning then
|
|
3331
|
+
try
|
|
3332
|
+
tell application "Visual Studio Code" to activate
|
|
3333
|
+
delay 0.5
|
|
3334
|
+
return "running"
|
|
3335
|
+
on error
|
|
3336
|
+
return "error"
|
|
3337
|
+
end try
|
|
3338
|
+
else
|
|
3339
|
+
return "not_running"
|
|
3340
|
+
end if
|
|
3341
|
+
end tell
|
|
3342
|
+
`;
|
|
3343
|
+
|
|
3344
|
+
const result = this.appleScriptUtils.executeAppleScript(script);
|
|
3345
|
+
const running = result.includes('running');
|
|
3346
|
+
|
|
3347
|
+
return {
|
|
3348
|
+
success: true,
|
|
3349
|
+
running,
|
|
3350
|
+
status: running ? 'running' : 'not_running',
|
|
3351
|
+
message: running ? 'VS Code is running and accessible' : 'VS Code is not running'
|
|
3352
|
+
};
|
|
3353
|
+
} catch (error) {
|
|
3354
|
+
return {
|
|
3355
|
+
success: false,
|
|
3356
|
+
error: `Failed to check VS Code status: ${error.message}`,
|
|
3357
|
+
running: false
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
/**
|
|
3363
|
+
* Check Windsurf status
|
|
3364
|
+
* @private
|
|
3365
|
+
*/
|
|
3366
|
+
async _checkWindsurfStatus() {
|
|
3367
|
+
try {
|
|
3368
|
+
const script = `
|
|
3369
|
+
tell application "System Events"
|
|
3370
|
+
set isRunning to (exists process "Windsurf")
|
|
3371
|
+
if isRunning then
|
|
3372
|
+
try
|
|
3373
|
+
tell application "Windsurf" to activate
|
|
3374
|
+
delay 0.5
|
|
3375
|
+
return "running"
|
|
3376
|
+
on error
|
|
3377
|
+
return "error"
|
|
3378
|
+
end try
|
|
3379
|
+
else
|
|
3380
|
+
return "not_running"
|
|
3381
|
+
end if
|
|
3382
|
+
end tell
|
|
3383
|
+
`;
|
|
3384
|
+
|
|
3385
|
+
const result = this.appleScriptUtils.executeAppleScript(script);
|
|
3386
|
+
const running = result.includes('running');
|
|
3387
|
+
|
|
3388
|
+
return {
|
|
3389
|
+
success: true,
|
|
3390
|
+
running,
|
|
3391
|
+
status: running ? 'running' : 'not_running',
|
|
3392
|
+
message: running ? 'Windsurf is running and accessible' : 'Windsurf is not running'
|
|
3393
|
+
};
|
|
3394
|
+
} catch (error) {
|
|
3395
|
+
return {
|
|
3396
|
+
success: false,
|
|
3397
|
+
error: `Failed to check Windsurf status: ${error.message}`,
|
|
3398
|
+
running: false
|
|
3399
|
+
};
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
/**
|
|
3404
|
+
* Check Antigravity status
|
|
3405
|
+
* @private
|
|
3406
|
+
*/
|
|
3407
|
+
async _checkAntigravityStatus() {
|
|
3408
|
+
try {
|
|
3409
|
+
// Antigravity runs in browser, check if Chrome/Edge is running with Antigravity tab
|
|
3410
|
+
const script = `
|
|
3411
|
+
tell application "System Events"
|
|
3412
|
+
set isChromeRunning to (exists process "Google Chrome")
|
|
3413
|
+
set isEdgeRunning to (exists process "Microsoft Edge")
|
|
3414
|
+
|
|
3415
|
+
if isChromeRunning then
|
|
3416
|
+
try
|
|
3417
|
+
tell application "Google Chrome" to activate
|
|
3418
|
+
delay 0.5
|
|
3419
|
+
return "running"
|
|
3420
|
+
on error
|
|
3421
|
+
return "error"
|
|
3422
|
+
end try
|
|
3423
|
+
else if isEdgeRunning then
|
|
3424
|
+
try
|
|
3425
|
+
tell application "Microsoft Edge" to activate
|
|
3426
|
+
delay 0.5
|
|
3427
|
+
return "running"
|
|
3428
|
+
on error
|
|
3429
|
+
return "error"
|
|
3430
|
+
end try
|
|
3431
|
+
else
|
|
3432
|
+
return "not_running"
|
|
3433
|
+
end if
|
|
3434
|
+
end tell
|
|
3435
|
+
`;
|
|
3436
|
+
|
|
3437
|
+
const result = this.appleScriptUtils.executeAppleScript(script);
|
|
3438
|
+
const running = result.includes('running');
|
|
3439
|
+
|
|
3440
|
+
return {
|
|
3441
|
+
success: true,
|
|
3442
|
+
running,
|
|
3443
|
+
status: running ? 'running' : 'not_running',
|
|
3444
|
+
message: running ? 'Browser is running (Antigravity accessible)' : 'Browser is not running'
|
|
3445
|
+
};
|
|
3446
|
+
} catch (error) {
|
|
3447
|
+
return {
|
|
3448
|
+
success: false,
|
|
3449
|
+
error: `Failed to check Antigravity status: ${error.message}`,
|
|
3450
|
+
running: false
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3455
|
+
/**
|
|
3456
|
+
* Check Cline status
|
|
3457
|
+
* @private
|
|
3458
|
+
*/
|
|
3459
|
+
async _checkClineStatus() {
|
|
3460
|
+
try {
|
|
3461
|
+
// Cline runs in VS Code as an extension
|
|
3462
|
+
const vscodeStatus = await this._checkVSCodeStatus();
|
|
3463
|
+
|
|
3464
|
+
if (!vscodeStatus.running) {
|
|
3465
|
+
return {
|
|
3466
|
+
success: true,
|
|
3467
|
+
running: false,
|
|
3468
|
+
status: 'not_running',
|
|
3469
|
+
message: 'Cline requires VS Code to be running'
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
// For now, assume Cline is available if VS Code is running
|
|
3474
|
+
// In a more sophisticated implementation, we could check if the extension is installed
|
|
3475
|
+
return {
|
|
3476
|
+
success: true,
|
|
3477
|
+
running: true,
|
|
3478
|
+
status: 'running',
|
|
3479
|
+
message: 'Cline is available (VS Code running)'
|
|
3480
|
+
};
|
|
3481
|
+
} catch (error) {
|
|
3482
|
+
return {
|
|
3483
|
+
success: false,
|
|
3484
|
+
error: `Failed to check Cline status: ${error.message}`,
|
|
3485
|
+
running: false
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
2940
3489
|
}
|
|
2941
3490
|
|
|
2942
3491
|
module.exports = AppleScriptManager;
|