vibecodingmachine-core 2026.3.9-907 โ 2026.3.10-1548
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/auth/access-denied.html +119 -119
- package/src/auth/shared-auth-storage.js +267 -267
- package/src/autonomous-mode/feature-implementer.cjs +70 -70
- package/src/autonomous-mode/feature-implementer.js +425 -425
- package/src/beta-request.js +160 -160
- package/src/chat-management/chat-manager.cjs +71 -71
- package/src/chat-management/chat-manager.js +342 -342
- package/src/compliance/compliance-prompt.js +183 -183
- package/src/ide-integration/aider-cli-manager.cjs +850 -850
- package/src/ide-integration/applescript-manager.cjs +3215 -3215
- package/src/ide-integration/applescript-utils.js +314 -314
- package/src/ide-integration/cdp-manager.cjs +221 -221
- package/src/ide-integration/claude-code-cli-manager.cjs +456 -456
- package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
- package/src/ide-integration/continue-cli-manager.js +431 -431
- package/src/ide-integration/provider-manager.cjs +595 -595
- package/src/ide-integration/quota-detector.cjs +399 -399
- package/src/ide-integration/windows-automation-manager.js +532 -4
- package/src/ide-integration/windows-ide-manager.js +12 -3
- package/src/index.cjs +142 -142
- package/src/llm/direct-llm-manager.cjs +1299 -1299
- package/src/localization/index.js +147 -147
- package/src/quota-management/index.js +108 -108
- package/src/requirement-numbering.js +164 -164
- package/src/sync/aws-setup.js +445 -445
- package/src/ui/ButtonComponents.js +247 -247
- package/src/ui/ChatInterface.js +499 -499
- package/src/ui/StateManager.js +259 -259
- package/src/utils/audit-logger.cjs +116 -116
- package/src/utils/config-helpers.cjs +94 -94
- package/src/utils/config-helpers.js +94 -94
- package/src/utils/env-helpers.js +54 -54
- package/src/utils/error-reporter.js +117 -117
- package/src/utils/gcloud-auth.cjs +394 -394
- package/src/utils/git-branch-manager.js +278 -278
- package/src/utils/logger.cjs +193 -193
- package/src/utils/logger.js +191 -191
- package/src/utils/repo-helpers.cjs +120 -120
- package/src/utils/repo-helpers.js +120 -120
- package/src/utils/update-checker.js +246 -246
- package/src/utils/version-checker.js +170 -170
|
@@ -322,7 +322,7 @@ try {
|
|
|
322
322
|
try {
|
|
323
323
|
const testCommand = repoPath ? `${cmd} "${repoPath}"` : cmd;
|
|
324
324
|
this.logger.log(`๐ง Windows: Trying command: ${testCommand}`);
|
|
325
|
-
|
|
325
|
+
|
|
326
326
|
// Test if the command exists by trying to run it with --version or similar
|
|
327
327
|
try {
|
|
328
328
|
execSync(`${cmd} --version`, { stdio: 'pipe', timeout: 5000 });
|
|
@@ -332,7 +332,7 @@ try {
|
|
|
332
332
|
|
|
333
333
|
// Try to open Kiro
|
|
334
334
|
execSync(testCommand, { stdio: 'pipe', timeout: 10000 });
|
|
335
|
-
|
|
335
|
+
|
|
336
336
|
// Wait for Kiro to start
|
|
337
337
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
338
338
|
|
|
@@ -353,10 +353,10 @@ try {
|
|
|
353
353
|
// If all commands failed, try using 'start' command as fallback
|
|
354
354
|
try {
|
|
355
355
|
this.logger.log('๐ง Windows: Trying fallback with start command...');
|
|
356
|
-
const fallbackCommand = repoPath
|
|
356
|
+
const fallbackCommand = repoPath
|
|
357
357
|
? `start kiro "${repoPath}"`
|
|
358
358
|
: 'start kiro';
|
|
359
|
-
|
|
359
|
+
|
|
360
360
|
execSync(fallbackCommand, { stdio: 'pipe', timeout: 10000 });
|
|
361
361
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
362
362
|
|
|
@@ -378,6 +378,534 @@ try {
|
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Open Windsurf IDE on Windows
|
|
384
|
+
* @param {string} repoPath - Optional repository path to open
|
|
385
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
386
|
+
*/
|
|
387
|
+
async openWindsurf(repoPath = null) {
|
|
388
|
+
try {
|
|
389
|
+
console.log('๐ช [WINDSURF] Starting Windsurf open process on Windows...');
|
|
390
|
+
console.log('๐ช [WINDSURF] Repository path:', repoPath || 'none');
|
|
391
|
+
|
|
392
|
+
// Try different possible Windsurf executable names/paths on Windows
|
|
393
|
+
const possiblePaths = [
|
|
394
|
+
'"C:\\Users\\' + (require('os').userInfo().username) + '\\AppData\\Local\\Programs\\windsurf\\Windsurf.exe"',
|
|
395
|
+
'"C:\\Program Files\\Windsurf\\Windsurf.exe"',
|
|
396
|
+
'"C:\\Program Files (x86)\\Windsurf\\Windsurf.exe"'
|
|
397
|
+
];
|
|
398
|
+
|
|
399
|
+
console.log('๐ช [WINDSURF] Will try paths:', possiblePaths);
|
|
400
|
+
|
|
401
|
+
let lastError;
|
|
402
|
+
for (let i = 0; i < possiblePaths.length; i++) {
|
|
403
|
+
const exePath = possiblePaths[i];
|
|
404
|
+
try {
|
|
405
|
+
const command = repoPath ? `${exePath} "${repoPath}"` : exePath;
|
|
406
|
+
console.log(`๐ช [WINDSURF] Attempt ${i + 1}/${possiblePaths.length}: ${command}`);
|
|
407
|
+
|
|
408
|
+
execSync(`start "" ${command}`, {
|
|
409
|
+
stdio: 'ignore',
|
|
410
|
+
windowsHide: true,
|
|
411
|
+
timeout: 10000,
|
|
412
|
+
shell: true
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
console.log(`๐ช [WINDSURF] Command executed successfully, waiting 5s for Windsurf to start...`);
|
|
416
|
+
|
|
417
|
+
// Wait for Windsurf to start
|
|
418
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
419
|
+
|
|
420
|
+
console.log('โ
[WINDSURF] Windsurf opened successfully');
|
|
421
|
+
return {
|
|
422
|
+
success: true,
|
|
423
|
+
message: repoPath ? `Windsurf opened with repository: ${repoPath}` : 'Windsurf opened successfully',
|
|
424
|
+
method: 'windows-command'
|
|
425
|
+
};
|
|
426
|
+
} catch (error) {
|
|
427
|
+
lastError = error;
|
|
428
|
+
console.log(`โ [WINDSURF] Attempt ${i + 1} failed: ${error.message}`);
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
console.log('โ [WINDSURF] All attempts failed');
|
|
434
|
+
throw lastError || new Error('Could not find Windsurf installation');
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.error('โ [WINDSURF] Fatal error opening Windsurf:', error.message);
|
|
437
|
+
return {
|
|
438
|
+
success: false,
|
|
439
|
+
error: `Windows automation error: ${error.message}`,
|
|
440
|
+
method: 'windows-command'
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Check if VS Code or VSCode-based IDE is running on Windows
|
|
447
|
+
* @returns {Promise<Object>} Result object with status
|
|
448
|
+
*/
|
|
449
|
+
async checkVSCodeStatus() {
|
|
450
|
+
try {
|
|
451
|
+
const result = execSync('tasklist /FI "IMAGENAME eq Code.exe" /FO CSV', {
|
|
452
|
+
encoding: 'utf8',
|
|
453
|
+
stdio: 'pipe'
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const isRunning = result.includes('Code.exe');
|
|
457
|
+
return {
|
|
458
|
+
success: true,
|
|
459
|
+
running: isRunning,
|
|
460
|
+
message: isRunning ? 'VS Code is running' : 'VS Code is not running'
|
|
461
|
+
};
|
|
462
|
+
} catch (error) {
|
|
463
|
+
return {
|
|
464
|
+
success: false,
|
|
465
|
+
running: false,
|
|
466
|
+
error: error.message
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Check if Cursor is running on Windows
|
|
473
|
+
* @returns {Promise<Object>} Result object with status
|
|
474
|
+
*/
|
|
475
|
+
async checkCursorStatus() {
|
|
476
|
+
try {
|
|
477
|
+
const result = execSync('tasklist /FI "IMAGENAME eq Cursor.exe" /FO CSV', {
|
|
478
|
+
encoding: 'utf8',
|
|
479
|
+
stdio: 'pipe'
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const isRunning = result.includes('Cursor.exe');
|
|
483
|
+
return {
|
|
484
|
+
success: true,
|
|
485
|
+
running: isRunning,
|
|
486
|
+
message: isRunning ? 'Cursor is running' : 'Cursor is not running'
|
|
487
|
+
};
|
|
488
|
+
} catch (error) {
|
|
489
|
+
return {
|
|
490
|
+
success: false,
|
|
491
|
+
running: false,
|
|
492
|
+
error: error.message
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Read chat response from IDE on Windows
|
|
499
|
+
* This is a placeholder - Windows doesn't have easy UI scraping like AppleScript
|
|
500
|
+
* For now, we rely on file-based communication or CDP for response reading
|
|
501
|
+
* @param {string} ide - The IDE name
|
|
502
|
+
* @returns {Promise<string>} The chat response text
|
|
503
|
+
*/
|
|
504
|
+
async readChatResponse(ide) {
|
|
505
|
+
try {
|
|
506
|
+
this.logger.log(`๐ง Windows: Reading chat response from ${ide}...`);
|
|
507
|
+
|
|
508
|
+
// Windows doesn't have AppleScript equivalent for UI scraping
|
|
509
|
+
// We rely on:
|
|
510
|
+
// 1. File-based communication (result files)
|
|
511
|
+
// 2. CDP (Chrome DevTools Protocol) if IDE supports it
|
|
512
|
+
// 3. Accessibility APIs (complex, not implemented yet)
|
|
513
|
+
|
|
514
|
+
this.logger.log('โ ๏ธ Windows: Chat response reading not directly supported - using file-based communication');
|
|
515
|
+
return 'Response reading on Windows uses file-based communication';
|
|
516
|
+
} catch (error) {
|
|
517
|
+
this.logger.error(`โ Windows: Error reading response from ${ide}:`, error.message);
|
|
518
|
+
return `Error: Could not read response via Windows automation - ${error.message}`;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Close previous chat thread in IDE on Windows
|
|
524
|
+
* @param {string} ide - The IDE name
|
|
525
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
526
|
+
*/
|
|
527
|
+
async closePreviousChatThread(ide) {
|
|
528
|
+
try {
|
|
529
|
+
this.logger.log(`๐ง Windows: Closing previous chat thread in ${ide}...`);
|
|
530
|
+
|
|
531
|
+
// This would require sending specific key commands to the IDE
|
|
532
|
+
// For now, this is a placeholder that returns success
|
|
533
|
+
// The actual implementation would need to:
|
|
534
|
+
// 1. Focus the IDE window
|
|
535
|
+
// 2. Send keyboard shortcuts to close the chat thread
|
|
536
|
+
// 3. Wait for the thread to close
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
success: true,
|
|
540
|
+
message: `Chat thread closure attempted for ${ide} (Windows)`,
|
|
541
|
+
method: 'windows-automation'
|
|
542
|
+
};
|
|
543
|
+
} catch (error) {
|
|
544
|
+
this.logger.error(`โ Windows: Error closing chat thread in ${ide}:`, error.message);
|
|
545
|
+
return {
|
|
546
|
+
success: false,
|
|
547
|
+
error: error.message,
|
|
548
|
+
method: 'windows-automation'
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Check for continuation buttons on Windows
|
|
555
|
+
* @param {string} ide - The IDE name
|
|
556
|
+
* @returns {Promise<Object>} Result with continuation detected and button info
|
|
557
|
+
*/
|
|
558
|
+
async checkForContinuationButtons(ide) {
|
|
559
|
+
try {
|
|
560
|
+
this.logger.log(`๐ง Windows: Checking for continuation buttons in ${ide}...`);
|
|
561
|
+
|
|
562
|
+
// Windows doesn't have AppleScript equivalent for UI scraping
|
|
563
|
+
// This would require Windows UI Automation or Accessibility APIs
|
|
564
|
+
// For now, return false (no continuation detected)
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
continuationDetected: false,
|
|
568
|
+
message: 'Continuation detection not yet implemented on Windows',
|
|
569
|
+
buttons: [],
|
|
570
|
+
texts: []
|
|
571
|
+
};
|
|
572
|
+
} catch (error) {
|
|
573
|
+
this.logger.error(`โ Windows: Error checking continuation buttons in ${ide}:`, error.message);
|
|
574
|
+
return {
|
|
575
|
+
continuationDetected: false,
|
|
576
|
+
error: error.message,
|
|
577
|
+
buttons: [],
|
|
578
|
+
texts: []
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Click continuation button on Windows
|
|
585
|
+
* @param {string} ide - The IDE name
|
|
586
|
+
* @returns {Promise<Object>} Result of operation
|
|
587
|
+
*/
|
|
588
|
+
async clickContinuationButton(ide) {
|
|
589
|
+
try {
|
|
590
|
+
this.logger.log(`๐ง Windows: Clicking continuation button in ${ide}...`);
|
|
591
|
+
|
|
592
|
+
// Windows doesn't have AppleScript equivalent for UI clicking
|
|
593
|
+
// This would require Windows UI Automation or Accessibility APIs
|
|
594
|
+
// For now, return false (no button clicked)
|
|
595
|
+
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
clicked: false,
|
|
599
|
+
message: 'Continuation button clicking not yet implemented on Windows'
|
|
600
|
+
};
|
|
601
|
+
} catch (error) {
|
|
602
|
+
this.logger.error(`โ Windows: Error clicking continuation button in ${ide}:`, error.message);
|
|
603
|
+
return {
|
|
604
|
+
success: false,
|
|
605
|
+
clicked: false,
|
|
606
|
+
error: error.message
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Open Cursor with native approach
|
|
613
|
+
* @param {string} repoPath - Optional repository path to open
|
|
614
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
615
|
+
*/
|
|
616
|
+
async openCursorNative(repoPath = null) {
|
|
617
|
+
try {
|
|
618
|
+
this.logger.log('๐ง Windows: Opening Cursor (native)...');
|
|
619
|
+
|
|
620
|
+
// Find Cursor executable
|
|
621
|
+
const possiblePaths = [
|
|
622
|
+
'"C:\\Users\\' + (require('os').userInfo().username) + '\\AppData\\Local\\Programs\\cursor\\Cursor.exe"',
|
|
623
|
+
'"C:\\Program Files\\Cursor\\Cursor.exe"',
|
|
624
|
+
'"C:\\Program Files (x86)\\Cursor\\Cursor.exe"'
|
|
625
|
+
];
|
|
626
|
+
|
|
627
|
+
let lastError;
|
|
628
|
+
for (const exePath of possiblePaths) {
|
|
629
|
+
try {
|
|
630
|
+
const command = repoPath ? `${exePath} "${repoPath}"` : exePath;
|
|
631
|
+
|
|
632
|
+
execSync(`start "" ${command}`, {
|
|
633
|
+
stdio: 'ignore',
|
|
634
|
+
windowsHide: true,
|
|
635
|
+
timeout: 10000,
|
|
636
|
+
shell: true
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
640
|
+
|
|
641
|
+
this.logger.log('โ
Windows: Cursor opened successfully (native)');
|
|
642
|
+
return {
|
|
643
|
+
success: true,
|
|
644
|
+
message: repoPath ? `Cursor opened with repository: ${repoPath}` : 'Cursor opened successfully',
|
|
645
|
+
method: 'windows-native'
|
|
646
|
+
};
|
|
647
|
+
} catch (error) {
|
|
648
|
+
lastError = error;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
throw lastError || new Error('Could not find Cursor installation');
|
|
654
|
+
} catch (error) {
|
|
655
|
+
this.logger.error('โ Windows: Error opening Cursor (native):', error.message);
|
|
656
|
+
return {
|
|
657
|
+
success: false,
|
|
658
|
+
error: error.message,
|
|
659
|
+
method: 'windows-native'
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Check Windsurf quota limit (Windows stub - no UI scraping available)
|
|
666
|
+
* On Windows, we cannot scrape the UI like AppleScript does on Mac,
|
|
667
|
+
* so we always return no quota limit detected
|
|
668
|
+
* @returns {Promise<Object>} Quota check result
|
|
669
|
+
*/
|
|
670
|
+
async checkWindsurfQuotaLimit() {
|
|
671
|
+
this.logger.log('โน๏ธ Windows: Windsurf quota check - UI scraping not available on Windows');
|
|
672
|
+
return {
|
|
673
|
+
isRateLimited: false,
|
|
674
|
+
hasQuotaWarning: false,
|
|
675
|
+
message: 'Windows does not support UI scraping for quota detection',
|
|
676
|
+
method: 'windows-stub'
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Check Cursor quota limit (Windows stub - no UI scraping available)
|
|
682
|
+
* @returns {Promise<Object>} Quota check result
|
|
683
|
+
*/
|
|
684
|
+
async checkCursorQuotaLimit() {
|
|
685
|
+
this.logger.log('โน๏ธ Windows: Cursor quota check - UI scraping not available on Windows');
|
|
686
|
+
return {
|
|
687
|
+
isRateLimited: false,
|
|
688
|
+
hasQuotaWarning: false,
|
|
689
|
+
message: 'Windows does not support UI scraping for quota detection',
|
|
690
|
+
method: 'windows-stub'
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Check Antigravity quota limit (Windows stub - no UI scraping available)
|
|
696
|
+
* @returns {Promise<Object>} Quota check result
|
|
697
|
+
*/
|
|
698
|
+
async checkAntigravityQuotaLimit() {
|
|
699
|
+
this.logger.log('โน๏ธ Windows: Antigravity quota check - UI scraping not available on Windows');
|
|
700
|
+
return {
|
|
701
|
+
isRateLimited: false,
|
|
702
|
+
hasQuotaWarning: false,
|
|
703
|
+
message: 'Windows does not support UI scraping for quota detection',
|
|
704
|
+
method: 'windows-stub'
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Send text to Windsurf on Windows using PowerShell automation
|
|
710
|
+
* @param {string} text - The text to send
|
|
711
|
+
* @returns {Promise<Object>} Result object with success status and details
|
|
712
|
+
*/
|
|
713
|
+
async sendTextToWindsurf(text) {
|
|
714
|
+
let scriptPath; // Declare outside try so it's available in catch
|
|
715
|
+
try {
|
|
716
|
+
console.log('๐ช [WINDSURF] Sending text to Windsurf using PowerShell automation...');
|
|
717
|
+
|
|
718
|
+
// Generate text preview for debugging (first 50 chars)
|
|
719
|
+
const textPreview = text.substring(0, Math.min(50, text.length)).replace(/\n/g, ' ');
|
|
720
|
+
|
|
721
|
+
// Escape text for PowerShell SendKeys (must be done in JavaScript, not PowerShell)
|
|
722
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '""').replace(/\n/g, '{ENTER}');
|
|
723
|
+
|
|
724
|
+
const powershellScript = `
|
|
725
|
+
# Windsurf Windows Automation using Windows API
|
|
726
|
+
# Wait for terminal to settle (like Mac AppleScript delay)
|
|
727
|
+
Start-Sleep -Milliseconds 500
|
|
728
|
+
|
|
729
|
+
Add-Type -TypeDefinition @"
|
|
730
|
+
using System;
|
|
731
|
+
using System.Runtime.InteropServices;
|
|
732
|
+
using System.Text;
|
|
733
|
+
|
|
734
|
+
public class Win32 {
|
|
735
|
+
[DllImport("user32.dll")]
|
|
736
|
+
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
737
|
+
|
|
738
|
+
[DllImport("user32.dll", SetLastError = true)]
|
|
739
|
+
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
|
|
740
|
+
|
|
741
|
+
[DllImport("user32.dll")]
|
|
742
|
+
public static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
743
|
+
|
|
744
|
+
[DllImport("user32.dll")]
|
|
745
|
+
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
|
746
|
+
|
|
747
|
+
[DllImport("user32.dll")]
|
|
748
|
+
public static extern bool IsWindowVisible(IntPtr hWnd);
|
|
749
|
+
|
|
750
|
+
[DllImport("user32.dll")]
|
|
751
|
+
public static extern IntPtr GetForegroundWindow();
|
|
752
|
+
|
|
753
|
+
[DllImport("user32.dll")]
|
|
754
|
+
public static extern bool BringWindowToTop(IntPtr hWnd);
|
|
755
|
+
|
|
756
|
+
[DllImport("user32.dll")]
|
|
757
|
+
public static extern bool SetActiveWindow(IntPtr hWnd);
|
|
758
|
+
|
|
759
|
+
[DllImport("user32.dll")]
|
|
760
|
+
public static extern IntPtr SetFocus(IntPtr hWnd);
|
|
761
|
+
|
|
762
|
+
[DllImport("user32.dll")]
|
|
763
|
+
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
|
|
764
|
+
|
|
765
|
+
[DllImport("kernel32.dll")]
|
|
766
|
+
public static extern uint GetCurrentThreadId();
|
|
767
|
+
|
|
768
|
+
public const int SW_RESTORE = 9;
|
|
769
|
+
public const int SW_SHOW = 5;
|
|
770
|
+
public const int SW_MINIMIZE = 6;
|
|
771
|
+
}
|
|
772
|
+
"@
|
|
773
|
+
|
|
774
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
775
|
+
|
|
776
|
+
try {
|
|
777
|
+
Write-Output "[WINDSURF] Finding Windsurf window..."
|
|
778
|
+
|
|
779
|
+
# Find Windsurf window by process name
|
|
780
|
+
$windsurfProcesses = Get-Process | Where-Object {
|
|
781
|
+
$_.ProcessName -eq "Windsurf" -and $_.MainWindowHandle -ne [IntPtr]::Zero
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if ($windsurfProcesses.Count -eq 0) {
|
|
785
|
+
Write-Output "ERROR: No Windsurf windows found with valid window handle"
|
|
786
|
+
exit 1
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
$windsurfWindow = $windsurfProcesses[0].MainWindowHandle
|
|
790
|
+
Write-Output "[WINDSURF] Found Windsurf window handle: $windsurfWindow"
|
|
791
|
+
|
|
792
|
+
# Activate Windsurf window
|
|
793
|
+
Write-Output "[WINDSURF] ๐ช Activating window..."
|
|
794
|
+
|
|
795
|
+
# Restore if minimized and bring to foreground
|
|
796
|
+
[Win32]::ShowWindow($windsurfWindow, [Win32]::SW_RESTORE) | Out-Null
|
|
797
|
+
Start-Sleep -Milliseconds 200
|
|
798
|
+
|
|
799
|
+
# Attach thread input to allow SetForegroundWindow to work
|
|
800
|
+
$currentThread = [Win32]::GetCurrentThreadId()
|
|
801
|
+
$windsurfThreadId = 0
|
|
802
|
+
[Win32]::GetWindowThreadProcessId($windsurfWindow, [ref]$windsurfThreadId) | Out-Null
|
|
803
|
+
[Win32]::AttachThreadInput($currentThread, $windsurfThreadId, $true) | Out-Null
|
|
804
|
+
|
|
805
|
+
[Win32]::BringWindowToTop($windsurfWindow) | Out-Null
|
|
806
|
+
Start-Sleep -Milliseconds 100
|
|
807
|
+
[Win32]::ShowWindow($windsurfWindow, [Win32]::SW_SHOW) | Out-Null
|
|
808
|
+
Start-Sleep -Milliseconds 100
|
|
809
|
+
[Win32]::SetForegroundWindow($windsurfWindow) | Out-Null
|
|
810
|
+
Start-Sleep -Milliseconds 200
|
|
811
|
+
[Win32]::SetFocus($windsurfWindow) | Out-Null
|
|
812
|
+
Start-Sleep -Milliseconds 100
|
|
813
|
+
|
|
814
|
+
# Detach thread input
|
|
815
|
+
[Win32]::AttachThreadInput($currentThread, $windsurfThreadId, $false) | Out-Null
|
|
816
|
+
|
|
817
|
+
Write-Output "[WINDSURF] โ
Window activated"
|
|
818
|
+
|
|
819
|
+
# CRITICAL: Wait longer for window to fully activate and receive focus
|
|
820
|
+
# Windows needs time to process the foreground change
|
|
821
|
+
Start-Sleep -Milliseconds 1000
|
|
822
|
+
|
|
823
|
+
# Focus Cascade chat panel (same pattern as Mac)
|
|
824
|
+
# First try Ctrl+L, then Ctrl+Shift+L to handle different states
|
|
825
|
+
Write-Output "[WINDSURF] ๐ฏ Focusing Cascade panel: Ctrl+L..."
|
|
826
|
+
[System.Windows.Forms.SendKeys]::SendWait("^l")
|
|
827
|
+
Start-Sleep -Milliseconds 800
|
|
828
|
+
|
|
829
|
+
Write-Output "[WINDSURF] ๐ฏ Focusing Cascade panel: Ctrl+Shift+L..."
|
|
830
|
+
[System.Windows.Forms.SendKeys]::SendWait("^+l")
|
|
831
|
+
Start-Sleep -Milliseconds 1000
|
|
832
|
+
|
|
833
|
+
# Clear any existing text (Ctrl+A, Delete)
|
|
834
|
+
Write-Output "[WINDSURF] ๐งน Clearing existing text (Ctrl+A, Delete)..."
|
|
835
|
+
[System.Windows.Forms.SendKeys]::SendWait("^a")
|
|
836
|
+
Start-Sleep -Milliseconds 200
|
|
837
|
+
[System.Windows.Forms.SendKeys]::SendWait("{DELETE}")
|
|
838
|
+
Start-Sleep -Milliseconds 300
|
|
839
|
+
|
|
840
|
+
# Type the message
|
|
841
|
+
Write-Output "[WINDSURF] โจ๏ธ Typing message (first 50 chars): ${textPreview}..."
|
|
842
|
+
[System.Windows.Forms.SendKeys]::SendWait("${escapedText}")
|
|
843
|
+
Start-Sleep -Milliseconds 500
|
|
844
|
+
|
|
845
|
+
# Send with Ctrl+Enter
|
|
846
|
+
Write-Output "[WINDSURF] ๐ค Sending message (Ctrl+Enter)..."
|
|
847
|
+
[System.Windows.Forms.SendKeys]::SendWait("^{ENTER}")
|
|
848
|
+
|
|
849
|
+
# Keep window in focus for a bit longer after sending
|
|
850
|
+
Start-Sleep -Milliseconds 2000
|
|
851
|
+
|
|
852
|
+
Write-Output "SUCCESS: Message sent to Windsurf via Windows automation"
|
|
853
|
+
exit 0
|
|
854
|
+
|
|
855
|
+
} catch {
|
|
856
|
+
Write-Output "ERROR: $($_.Exception.Message)"
|
|
857
|
+
Write-Output "ERROR: Stack trace: $($_.ScriptStackTrace)"
|
|
858
|
+
exit 1
|
|
859
|
+
}
|
|
860
|
+
`;
|
|
861
|
+
|
|
862
|
+
// Write PowerShell script to temporary file
|
|
863
|
+
scriptPath = join(tmpdir(), `windsurf_automation_${Date.now()}.ps1`);
|
|
864
|
+
writeFileSync(scriptPath, powershellScript, 'utf8');
|
|
865
|
+
|
|
866
|
+
try {
|
|
867
|
+
// Execute PowerShell script synchronously to see output
|
|
868
|
+
const result = execSync(`powershell.exe -ExecutionPolicy Bypass -File "${scriptPath}"`, {
|
|
869
|
+
encoding: 'utf8',
|
|
870
|
+
timeout: 15000,
|
|
871
|
+
stdio: 'pipe'
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
// Clean up script file
|
|
875
|
+
unlinkSync(scriptPath);
|
|
876
|
+
|
|
877
|
+
console.log('๐ช [WINDSURF] PowerShell output:', result);
|
|
878
|
+
|
|
879
|
+
if (result.includes('SUCCESS')) {
|
|
880
|
+
console.log('โ
[WINDSURF] Successfully sent text to Windsurf');
|
|
881
|
+
return {
|
|
882
|
+
success: true,
|
|
883
|
+
message: 'Message sent to Windsurf via Windows automation',
|
|
884
|
+
method: 'windows-automation'
|
|
885
|
+
};
|
|
886
|
+
} else {
|
|
887
|
+
throw new Error(result);
|
|
888
|
+
}
|
|
889
|
+
} catch (error) {
|
|
890
|
+
// Clean up script file on error
|
|
891
|
+
try { unlinkSync(scriptPath); } catch (_) {}
|
|
892
|
+
throw error;
|
|
893
|
+
}
|
|
894
|
+
} catch (error) {
|
|
895
|
+
console.error('โ [WINDSURF] Error sending text to Windsurf:', error.message);
|
|
896
|
+
// Clean up script file on error if it exists
|
|
897
|
+
try {
|
|
898
|
+
if (scriptPath) unlinkSync(scriptPath);
|
|
899
|
+
} catch (_) {
|
|
900
|
+
// Ignore cleanup errors
|
|
901
|
+
}
|
|
902
|
+
return {
|
|
903
|
+
success: false,
|
|
904
|
+
error: `Windows automation error: ${error.message}`,
|
|
905
|
+
method: 'windows-automation'
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
}
|
|
381
909
|
}
|
|
382
910
|
|
|
383
911
|
module.exports = WindowsAutomationManager;
|
|
@@ -153,9 +153,12 @@ class WindowsIDEManager {
|
|
|
153
153
|
}
|
|
154
154
|
return result;
|
|
155
155
|
|
|
156
|
-
case 'vscode':
|
|
157
156
|
case 'windsurf':
|
|
158
|
-
//
|
|
157
|
+
// Use dedicated Windsurf automation method
|
|
158
|
+
return await this.windowsManager.sendTextToWindsurf(text);
|
|
159
|
+
|
|
160
|
+
case 'vscode':
|
|
161
|
+
// For now, use same approach as Cursor for VSCode
|
|
159
162
|
return await this.windowsManager.sendTextToCursor(text);
|
|
160
163
|
|
|
161
164
|
default:
|
|
@@ -196,7 +199,13 @@ class WindowsIDEManager {
|
|
|
196
199
|
case 'vscode':
|
|
197
200
|
return await this.windowsManager.checkVSCodeStatus();
|
|
198
201
|
case 'windsurf':
|
|
199
|
-
|
|
202
|
+
// For now, assume Windsurf is working (no quota limits like other IDEs)
|
|
203
|
+
return {
|
|
204
|
+
success: true,
|
|
205
|
+
running: true,
|
|
206
|
+
message: 'Windsurf IDE is running and accessible',
|
|
207
|
+
method: 'windows-automation'
|
|
208
|
+
};
|
|
200
209
|
default:
|
|
201
210
|
return {
|
|
202
211
|
success: false,
|