polydev-ai 1.8.80 → 1.8.82

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/mcp/login.js CHANGED
@@ -444,49 +444,115 @@ function getSuccessHTML() {
444
444
  <html>
445
445
  <head>
446
446
  <meta charset="utf-8">
447
- <title>Polydev - Success</title>
447
+ <title>Polydev - Login Successful</title>
448
448
  <style>
449
449
  * { box-sizing: border-box; margin: 0; padding: 0; }
450
- body {
451
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
452
- display: flex; justify-content: center; align-items: center;
453
- height: 100vh; background: #f5f5f5;
450
+ body {
451
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
452
+ display: flex; justify-content: center; align-items: center;
453
+ min-height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
454
+ padding: 20px;
454
455
  }
455
- .container {
456
- text-align: center; padding: 48px; max-width: 400px;
457
- background: white; border-radius: 8px;
458
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
456
+ .container {
457
+ text-align: center; padding: 40px; max-width: 480px; width: 100%;
458
+ background: white; border-radius: 16px;
459
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
459
460
  }
460
- .logo { font-size: 24px; font-weight: 700; color: #111; margin-bottom: 24px; letter-spacing: -0.5px; }
461
- .check {
462
- width: 48px; height: 48px; border: 3px solid #111; border-radius: 50%;
463
- display: flex; align-items: center; justify-content: center;
464
- margin: 0 auto 24px; font-size: 24px;
461
+ .logo {
462
+ width: 80px; height: 80px; margin: 0 auto 20px;
463
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
464
+ border-radius: 20px; display: flex; align-items: center; justify-content: center;
465
+ box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
466
+ }
467
+ .logo svg { width: 48px; height: 48px; }
468
+ .brand { font-size: 28px; font-weight: 700; color: #111; margin-bottom: 8px; letter-spacing: -0.5px; }
469
+ .tagline { color: #666; font-size: 14px; margin-bottom: 24px; }
470
+ .success-badge {
471
+ display: inline-flex; align-items: center; gap: 8px;
472
+ background: #ecfdf5; color: #059669; padding: 12px 24px;
473
+ border-radius: 100px; font-weight: 600; font-size: 15px;
474
+ margin-bottom: 28px;
475
+ }
476
+ .success-badge svg { width: 20px; height: 20px; }
477
+ .section { text-align: left; margin-bottom: 20px; }
478
+ .section-title { font-size: 12px; font-weight: 600; color: #999; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; }
479
+ .api-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
480
+ .api-item {
481
+ padding: 12px; background: #f9fafb; border-radius: 8px;
482
+ font-size: 13px; color: #374151; text-align: center;
465
483
  }
466
- h1 { color: #111; font-size: 20px; font-weight: 600; margin-bottom: 12px; }
467
- p { color: #666; font-size: 14px; line-height: 1.6; margin-bottom: 8px; }
468
484
  .steps {
469
- background: #f9f9f9; border-radius: 6px; padding: 16px;
470
- margin: 20px 0; text-align: left;
485
+ background: #f9fafb; border-radius: 10px; padding: 16px;
486
+ margin-bottom: 20px; text-align: left;
471
487
  }
472
- .step { color: #444; font-size: 13px; margin-bottom: 8px; }
488
+ .step { color: #374151; font-size: 13px; margin-bottom: 10px; display: flex; gap: 10px; }
473
489
  .step:last-child { margin-bottom: 0; }
474
- code { background: #eee; padding: 2px 6px; border-radius: 3px; font-size: 12px; }
475
- .close { color: #999; font-size: 12px; margin-top: 20px; }
490
+ .step-num {
491
+ width: 20px; height: 20px; background: #667eea; color: white;
492
+ border-radius: 50%; font-size: 11px; font-weight: 600;
493
+ display: flex; align-items: center; justify-content: center; flex-shrink: 0;
494
+ }
495
+ code { background: #e5e7eb; padding: 2px 6px; border-radius: 4px; font-size: 12px; }
496
+ .divider { height: 1px; background: #e5e7eb; margin: 24px 0; }
497
+ .action-btn {
498
+ display: block; width: 100%; padding: 14px 20px;
499
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
500
+ color: white; border: none; border-radius: 10px;
501
+ font-size: 15px; font-weight: 600; cursor: pointer;
502
+ text-decoration: none; margin-bottom: 12px;
503
+ transition: transform 0.2s, box-shadow 0.2s;
504
+ }
505
+ .action-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); }
506
+ .secondary-btn {
507
+ display: block; width: 100%; padding: 12px 20px;
508
+ background: #f3f4f6; color: #374151; border: none; border-radius: 10px;
509
+ font-size: 14px; font-weight: 500; cursor: pointer; text-decoration: none;
510
+ }
511
+ .note { color: #9ca3af; font-size: 12px; margin-top: 20px; }
476
512
  </style>
477
513
  </head>
478
514
  <body>
479
515
  <div class="container">
480
- <div class="logo">Polydev</div>
481
- <div class="check">✓</div>
482
- <h1>Authentication Complete</h1>
483
- <p>Your token has been saved automatically.</p>
516
+ <div class="logo">
517
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
518
+ <path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
519
+ <path d="M2 17L12 22L22 17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
520
+ <path d="M2 12L12 17L22 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
521
+ </svg>
522
+ </div>
523
+ <div class="brand">Polydev</div>
524
+ <div class="tagline">Multi-Model AI Perspectives</div>
525
+
526
+ <div class="success-badge">
527
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
528
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
529
+ <polyline points="22 4 12 14.01 9 11.01"/>
530
+ </svg>
531
+ Login Successful
532
+ </div>
533
+
534
+ <div class="section">
535
+ <div class="section-title">API Models Available</div>
536
+ <div class="api-grid">
537
+ <div class="api-item">GPT-5.2</div>
538
+ <div class="api-item">Claude Opus</div>
539
+ <div class="api-item">Gemini 3</div>
540
+ <div class="api-item">Grok 4.1</div>
541
+ </div>
542
+ </div>
543
+
484
544
  <div class="steps">
485
- <div class="step">1. Restart terminal or run <code>source ~/.zshrc</code></div>
486
- <div class="step">2. Start your IDE (Claude Code, Cursor, etc.)</div>
487
- <div class="step">3. Use the <code>get_perspectives</code> tool</div>
545
+ <div class="step"><span class="step-num">1</span>Restart terminal or run <code>source ~/.zshrc</code></div>
546
+ <div class="step"><span class="step-num">2</span>Start your IDE (Claude Code, Cursor, etc.)</div>
547
+ <div class="step"><span class="step-num">3</span>Use <code>get_perspectives</code> tool</div>
488
548
  </div>
489
- <p class="close">You can close this window.</p>
549
+
550
+ <a href="https://www.polydev.ai/dashboard/models" target="_blank" class="action-btn">
551
+ Configure API Keys
552
+ </a>
553
+ <button onclick="window.close()" class="secondary-btn">Close Window</button>
554
+
555
+ <p class="note">Your token has been saved automatically</p>
490
556
  </div>
491
557
  </body>
492
558
  </html>`;
@@ -411,7 +411,7 @@ class StdioMCPWrapper {
411
411
  result: {
412
412
  content: [{
413
413
  type: 'text',
414
- text: `Already authenticated.\n\nYour token is configured. Use get_perspectives to query multiple AI models.\n\nTo re-login, run in terminal: npx polydev-ai login`
414
+ text: `Already authenticated.\n\nYour token is configured. Use get_perspectives to query multiple AI models.\n\nTo re-login, run in terminal: npx polydev-ai`
415
415
  }]
416
416
  }
417
417
  });
@@ -479,29 +479,11 @@ class StdioMCPWrapper {
479
479
 
480
480
  console.error(`[Polydev] Opening browser for authentication: ${authUrl}`);
481
481
 
482
- // Open browser - use exec with shell for better reliability in MCP stdio context
483
- const { exec } = require('child_process');
484
- const platform = process.platform;
485
-
486
- let openCommand;
487
- if (platform === 'darwin') {
488
- // Use osascript for more reliable browser opening on macOS
489
- openCommand = `osascript -e 'open location "${authUrl}"'`;
490
- } else if (platform === 'win32') {
491
- openCommand = `start "" "${authUrl}"`;
492
- } else {
493
- openCommand = `xdg-open "${authUrl}"`;
494
- }
495
-
496
- exec(openCommand, (error) => {
497
- if (error) {
498
- console.error('[Polydev] Browser open failed, trying fallback...');
499
- // Fallback to spawn
500
- const { spawn } = require('child_process');
501
- if (platform === 'darwin') {
502
- spawn('open', [authUrl], { detached: true, stdio: 'ignore' }).unref();
503
- }
504
- }
482
+ // Best-in-class browser opening using 'open' package (cross-platform)
483
+ // Falls back to platform-specific commands if package fails
484
+ this.openBrowser(authUrl).catch(() => {
485
+ console.error('[Polydev] All browser open methods failed');
486
+ console.error('[Polydev] Please open this URL manually:', authUrl);
505
487
  });
506
488
 
507
489
  // Timeout after 5 minutes
@@ -609,6 +591,64 @@ class StdioMCPWrapper {
609
591
  }
610
592
  }
611
593
 
594
+ /**
595
+ * Open URL in browser - best-in-class cross-platform implementation
596
+ * Uses 'open' npm package with fallbacks for reliability in MCP/stdio context
597
+ */
598
+ async openBrowser(url) {
599
+ // Try the 'open' package first (ESM, requires dynamic import)
600
+ try {
601
+ const open = await import('open');
602
+ await open.default(url);
603
+ console.error('[Polydev] Browser opened successfully');
604
+ return;
605
+ } catch (openError) {
606
+ console.error('[Polydev] open package failed:', openError.message);
607
+ }
608
+
609
+ // Fallback 1: Platform-specific commands with exec
610
+ const { exec } = require('child_process');
611
+ const platform = process.platform;
612
+
613
+ return new Promise((resolve, reject) => {
614
+ let command;
615
+ if (platform === 'darwin') {
616
+ // macOS: try osascript first (more reliable in headless contexts)
617
+ command = `osascript -e 'open location "${url}"'`;
618
+ } else if (platform === 'win32') {
619
+ command = `start "" "${url}"`;
620
+ } else {
621
+ command = `xdg-open "${url}"`;
622
+ }
623
+
624
+ exec(command, (error) => {
625
+ if (error) {
626
+ console.error('[Polydev] exec command failed:', error.message);
627
+
628
+ // Fallback 2: spawn with detached
629
+ const { spawn } = require('child_process');
630
+ try {
631
+ if (platform === 'darwin') {
632
+ spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
633
+ } else if (platform === 'win32') {
634
+ spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore', shell: true }).unref();
635
+ } else {
636
+ spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
637
+ }
638
+ console.error('[Polydev] Browser opened via spawn fallback');
639
+ resolve();
640
+ } catch (spawnError) {
641
+ console.error('[Polydev] spawn fallback failed:', spawnError.message);
642
+ reject(new Error('All browser open methods failed'));
643
+ }
644
+ } else {
645
+ console.error('[Polydev] Browser opened via exec');
646
+ resolve();
647
+ }
648
+ });
649
+ });
650
+ }
651
+
612
652
  /**
613
653
  * Save token to shell config files
614
654
  */
@@ -640,33 +680,136 @@ class StdioMCPWrapper {
640
680
  * Get login success HTML page
641
681
  */
642
682
  getLoginSuccessHTML() {
683
+ // Get CLI status for display
684
+ const cliStatus = this.cliManager ? this.cliManager.getCachedStatus() : {};
685
+ const detectedCLIs = Object.entries(cliStatus)
686
+ .filter(([_, status]) => status && status.available)
687
+ .map(([id, status]) => ({
688
+ name: id === 'claude_code' ? 'Claude Code' :
689
+ id === 'codex_cli' ? 'Codex CLI' :
690
+ id === 'gemini_cli' ? 'Gemini CLI' : id,
691
+ authenticated: status.authenticated
692
+ }));
693
+
694
+ const cliListHTML = detectedCLIs.length > 0
695
+ ? detectedCLIs.map(cli =>
696
+ `<div class="cli-item"><span class="cli-dot ${cli.authenticated ? 'green' : 'yellow'}"></span>${cli.name}</div>`
697
+ ).join('')
698
+ : '<div class="cli-item"><span class="cli-dot gray"></span>No local CLIs detected</div>';
699
+
643
700
  return `<!DOCTYPE html>
644
701
  <html>
645
702
  <head>
646
703
  <meta charset="utf-8">
647
- <title>Polydev - Success</title>
704
+ <title>Polydev - Login Successful</title>
648
705
  <style>
649
706
  * { box-sizing: border-box; margin: 0; padding: 0; }
650
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background: #f5f5f5; }
651
- .container { text-align: center; padding: 48px; max-width: 400px; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
652
- .logo { font-size: 24px; font-weight: 700; color: #111; margin-bottom: 24px; }
653
- .check { width: 48px; height: 48px; border: 3px solid #111; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 24px; font-size: 24px; }
654
- h1 { color: #111; font-size: 20px; font-weight: 600; margin-bottom: 12px; }
655
- p { color: #666; font-size: 14px; line-height: 1.6; }
656
- .important { background: #f0f0f0; padding: 16px; border-radius: 6px; margin: 20px 0; }
657
- .important strong { color: #111; }
707
+ body {
708
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
709
+ display: flex; justify-content: center; align-items: center;
710
+ min-height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
711
+ padding: 20px;
712
+ }
713
+ .container {
714
+ text-align: center; padding: 40px; max-width: 480px; width: 100%;
715
+ background: white; border-radius: 16px;
716
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
717
+ }
718
+ .logo {
719
+ width: 80px; height: 80px; margin: 0 auto 20px;
720
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
721
+ border-radius: 20px; display: flex; align-items: center; justify-content: center;
722
+ box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
723
+ }
724
+ .logo svg { width: 48px; height: 48px; }
725
+ .brand { font-size: 28px; font-weight: 700; color: #111; margin-bottom: 8px; letter-spacing: -0.5px; }
726
+ .tagline { color: #666; font-size: 14px; margin-bottom: 24px; }
727
+ .success-badge {
728
+ display: inline-flex; align-items: center; gap: 8px;
729
+ background: #ecfdf5; color: #059669; padding: 12px 24px;
730
+ border-radius: 100px; font-weight: 600; font-size: 15px;
731
+ margin-bottom: 28px;
732
+ }
733
+ .success-badge svg { width: 20px; height: 20px; }
734
+ .section {
735
+ text-align: left; margin-bottom: 20px;
736
+ }
737
+ .section-title { font-size: 12px; font-weight: 600; color: #999; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; }
738
+ .cli-item {
739
+ display: flex; align-items: center; gap: 10px;
740
+ padding: 10px 14px; background: #f9fafb; border-radius: 8px;
741
+ margin-bottom: 8px; font-size: 14px; color: #374151;
742
+ }
743
+ .cli-dot { width: 8px; height: 8px; border-radius: 50%; }
744
+ .cli-dot.green { background: #10b981; }
745
+ .cli-dot.yellow { background: #f59e0b; }
746
+ .cli-dot.gray { background: #9ca3af; }
747
+ .api-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
748
+ .api-item {
749
+ padding: 12px; background: #f9fafb; border-radius: 8px;
750
+ font-size: 13px; color: #374151; text-align: center;
751
+ }
752
+ .divider { height: 1px; background: #e5e7eb; margin: 24px 0; }
753
+ .action-btn {
754
+ display: block; width: 100%; padding: 14px 20px;
755
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
756
+ color: white; border: none; border-radius: 10px;
757
+ font-size: 15px; font-weight: 600; cursor: pointer;
758
+ text-decoration: none; margin-bottom: 12px;
759
+ transition: transform 0.2s, box-shadow 0.2s;
760
+ }
761
+ .action-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); }
762
+ .secondary-btn {
763
+ display: block; width: 100%; padding: 12px 20px;
764
+ background: #f3f4f6; color: #374151; border: none; border-radius: 10px;
765
+ font-size: 14px; font-weight: 500; cursor: pointer; text-decoration: none;
766
+ }
767
+ .note { color: #9ca3af; font-size: 12px; margin-top: 20px; }
658
768
  </style>
659
769
  </head>
660
770
  <body>
661
771
  <div class="container">
662
- <div class="logo">Polydev</div>
663
- <div class="check">✓</div>
664
- <h1>Login Successful</h1>
665
- <p>Your token has been saved.</p>
666
- <div class="important">
667
- <strong>Important:</strong> Restart your IDE to use the new token.
772
+ <div class="logo">
773
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
774
+ <path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
775
+ <path d="M2 17L12 22L22 17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
776
+ <path d="M2 12L12 17L22 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
777
+ </svg>
778
+ </div>
779
+ <div class="brand">Polydev</div>
780
+ <div class="tagline">Multi-Model AI Perspectives</div>
781
+
782
+ <div class="success-badge">
783
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
784
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
785
+ <polyline points="22 4 12 14.01 9 11.01"/>
786
+ </svg>
787
+ Login Successful
668
788
  </div>
669
- <p>You can close this window.</p>
789
+
790
+ <div class="section">
791
+ <div class="section-title">Local CLI Tools (Free)</div>
792
+ ${cliListHTML}
793
+ </div>
794
+
795
+ <div class="section">
796
+ <div class="section-title">API Models Available</div>
797
+ <div class="api-grid">
798
+ <div class="api-item">GPT-5.2</div>
799
+ <div class="api-item">Claude Opus</div>
800
+ <div class="api-item">Gemini 3</div>
801
+ <div class="api-item">Grok 4.1</div>
802
+ </div>
803
+ </div>
804
+
805
+ <div class="divider"></div>
806
+
807
+ <a href="https://www.polydev.ai/dashboard/models" target="_blank" class="action-btn">
808
+ Configure API Keys
809
+ </a>
810
+ <button onclick="window.close()" class="secondary-btn">Close Window</button>
811
+
812
+ <p class="note">Restart your IDE to use the new token</p>
670
813
  </div>
671
814
  </body>
672
815
  </html>`;
@@ -2112,28 +2255,11 @@ class StdioMCPWrapper {
2112
2255
  console.error(authUrl);
2113
2256
  console.error('');
2114
2257
 
2115
- // Open browser - use exec with shell for better reliability in stdio context
2116
- const { exec } = require('child_process');
2117
- const platform = process.platform;
2118
- let openCommand;
2119
- if (platform === 'darwin') {
2120
- // Use osascript for more reliable browser opening on macOS
2121
- openCommand = `osascript -e 'open location "${authUrl}"'`;
2122
- } else if (platform === 'win32') {
2123
- openCommand = `start "" "${authUrl}"`;
2124
- } else {
2125
- openCommand = `xdg-open "${authUrl}"`;
2126
- }
2127
-
2128
- exec(openCommand, (error) => {
2129
- if (error) {
2130
- console.error('[Polydev] Browser open failed, trying fallback...');
2131
- // Fallback to spawn
2132
- const { spawn } = require('child_process');
2133
- if (platform === 'darwin') {
2134
- spawn('open', [authUrl], { detached: true, stdio: 'ignore' }).unref();
2135
- }
2136
- }
2258
+ // Best-in-class browser opening using 'open' package (cross-platform)
2259
+ // Falls back to platform-specific commands if package fails
2260
+ this.openBrowser(authUrl).catch(() => {
2261
+ console.error('[Polydev] All browser open methods failed');
2262
+ console.error('[Polydev] Please open this URL manually:', authUrl);
2137
2263
  });
2138
2264
 
2139
2265
  // Don't block forever - resolve after timeout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.8.80",
3
+ "version": "1.8.82",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },
@@ -73,6 +73,7 @@
73
73
  "lucide-react": "^0.542.0",
74
74
  "marked": "^16.2.1",
75
75
  "next": "^15.5.7",
76
+ "open": "^11.0.0",
76
77
  "polydev-ai": "^1.8.42",
77
78
  "posthog-js": "^1.157.2",
78
79
  "prismjs": "^1.30.0",