vibecodingmachine-core 2025.12.25-25 → 2026.1.22-1441
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/ERROR_REPORTING_API.md +212 -0
- package/ERROR_REPORTING_USAGE.md +380 -0
- package/__tests__/provider-manager-fallback.test.js +43 -0
- package/__tests__/provider-manager-rate-limit.test.js +61 -0
- package/__tests__/utils/git-branch-manager.test.js +61 -0
- package/package.json +1 -1
- package/src/beta-request.js +160 -0
- package/src/compliance/compliance-manager.js +5 -2
- package/src/database/migrations.js +135 -12
- package/src/database/user-database-client.js +127 -8
- package/src/database/user-schema.js +28 -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 +1087 -9
- package/src/ide-integration/applescript-manager.js +565 -15
- package/src/ide-integration/applescript-utils.js +26 -18
- 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 +36 -1
- package/src/index.js +20 -0
- package/src/localization/translations/en.js +15 -1
- package/src/localization/translations/es.js +14 -0
- package/src/requirement-numbering.js +164 -0
- package/src/sync/aws-setup.js +4 -4
- package/src/utils/admin-utils.js +33 -0
- package/src/utils/error-reporter.js +117 -0
- package/src/utils/git-branch-manager.js +278 -0
- package/src/utils/requirement-helpers.js +44 -5
- package/src/utils/requirements-parser.js +28 -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,16 +949,25 @@ 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':
|
|
963
|
+
case 'claude-code':
|
|
717
964
|
return await this.openClaude(repoPath);
|
|
718
965
|
case 'gemini':
|
|
719
966
|
return await this.openGemini(repoPath);
|
|
720
967
|
default:
|
|
721
968
|
return {
|
|
722
969
|
success: false,
|
|
723
|
-
error: `Unknown IDE: ${ide}. Supported: cursor, windsurf, antigravity, vscode, claude, gemini`
|
|
970
|
+
error: `Unknown IDE: ${ide}. Supported: cursor, windsurf, antigravity, vscode, github-copilot, amazon-q, replit, kiro, claude, claude-code, gemini`
|
|
724
971
|
};
|
|
725
972
|
}
|
|
726
973
|
}
|
|
@@ -832,7 +1079,23 @@ class AppleScriptManager {
|
|
|
832
1079
|
|
|
833
1080
|
-- Press Enter (increased delay for chat window to fully open)
|
|
834
1081
|
key code 36
|
|
835
|
-
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
|
+
` : ''}
|
|
836
1099
|
|
|
837
1100
|
|
|
838
1101
|
-- Type the message (increased delay for input field to be ready)
|
|
@@ -879,7 +1142,7 @@ class AppleScriptManager {
|
|
|
879
1142
|
};
|
|
880
1143
|
}
|
|
881
1144
|
|
|
882
|
-
const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : ide === 'antigravity' ? 'Antigravity' : ide === 'claude' ? 'Claude' : ide === 'vscode' ? 'VS Code' : ide === 'kiro' ? 'AWS Kiro' : 'Unknown IDE';
|
|
1145
|
+
const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : ide === 'antigravity' ? 'Antigravity' : (ide === 'claude' || ide === 'claude-code') ? 'Claude' : ide === 'vscode' ? 'VS Code' : ide === 'kiro' ? 'AWS Kiro' : 'Unknown IDE';
|
|
883
1146
|
|
|
884
1147
|
this.logger.log(`🚀 [${ideName}] Starting text send on ${this.platform} platform`);
|
|
885
1148
|
this.logger.log(`🚀 [${ideName}] Text to send: "${text}"`);
|
|
@@ -1035,7 +1298,7 @@ class AppleScriptManager {
|
|
|
1035
1298
|
end tell
|
|
1036
1299
|
end tell
|
|
1037
1300
|
`;
|
|
1038
|
-
} else if (ide === 'claude') {
|
|
1301
|
+
} else if (ide === 'claude' || ide === 'claude-code') {
|
|
1039
1302
|
// Use a different approach for Claude - find existing Claude terminal and send text
|
|
1040
1303
|
const targetRepoPath = repoPath || '/Users/jesse/code/mediawink/vibecodingmachine';
|
|
1041
1304
|
this.logger.log(`🔍 [Claude] Using repo path for terminal detection: "${targetRepoPath}" (passed: "${repoPath}")`);
|
|
@@ -1230,8 +1493,9 @@ class AppleScriptManager {
|
|
|
1230
1493
|
} else if (ide === 'cursor') {
|
|
1231
1494
|
// Cursor already has new chat logic in generateAIPanelFocusScript (Cmd+T)
|
|
1232
1495
|
appleScript = this.appleScriptUtils.generateAIPanelFocusScript(text, 'Cursor');
|
|
1233
|
-
} else if (ide === 'vscode') {
|
|
1496
|
+
} else if (ide === 'vscode' || ide === 'github-copilot' || ide === 'amazon-q') {
|
|
1234
1497
|
// Delegate to the dedicated VS Code method
|
|
1498
|
+
// github-copilot and amazon-q are VS Code extensions
|
|
1235
1499
|
return await this.sendTextToVSCode(text);
|
|
1236
1500
|
} else if (ide === 'antigravity') {
|
|
1237
1501
|
// AppleScript for Google Antigravity - Cmd+Shift+L opens Agent chat (non-toggle)
|
|
@@ -1310,7 +1574,7 @@ class AppleScriptManager {
|
|
|
1310
1574
|
return {
|
|
1311
1575
|
success: false,
|
|
1312
1576
|
error: `Unsupported IDE for AppleScript: ${ide}`,
|
|
1313
|
-
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'
|
|
1314
1578
|
};
|
|
1315
1579
|
}
|
|
1316
1580
|
|
|
@@ -1352,8 +1616,30 @@ class AppleScriptManager {
|
|
|
1352
1616
|
} catch (error) {
|
|
1353
1617
|
this.logger.log('AppleScript interaction failed:', error.message);
|
|
1354
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
|
+
|
|
1355
1641
|
// For Claude, don't fall back to simulated response - return actual failure
|
|
1356
|
-
if (ide === 'claude') {
|
|
1642
|
+
if (ide === 'claude' || ide === 'claude-code') {
|
|
1357
1643
|
return {
|
|
1358
1644
|
success: false,
|
|
1359
1645
|
method: 'applescript',
|
|
@@ -1362,6 +1648,16 @@ class AppleScriptManager {
|
|
|
1362
1648
|
};
|
|
1363
1649
|
}
|
|
1364
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
|
+
|
|
1365
1661
|
// For other IDEs, fall back to simulated response
|
|
1366
1662
|
return {
|
|
1367
1663
|
success: true,
|
|
@@ -2544,7 +2840,7 @@ end tell
|
|
|
2544
2840
|
const ideName = ide.toLowerCase();
|
|
2545
2841
|
|
|
2546
2842
|
// Handle Claude CLI separately since it's a terminal application
|
|
2547
|
-
if (ideName === 'claude') {
|
|
2843
|
+
if (ideName === 'claude' || ideName === 'claude-code') {
|
|
2548
2844
|
return await this.closeClaudeCLI();
|
|
2549
2845
|
}
|
|
2550
2846
|
|
|
@@ -2936,6 +3232,260 @@ end tell
|
|
|
2936
3232
|
};
|
|
2937
3233
|
}
|
|
2938
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
|
+
}
|
|
2939
3489
|
}
|
|
2940
3490
|
|
|
2941
3491
|
module.exports = AppleScriptManager;
|