polydev-ai 1.8.91 → 1.8.93
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/stdio-wrapper.js +127 -94
- package/package.json +1 -1
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -407,9 +407,10 @@ class StdioMCPWrapper {
|
|
|
407
407
|
|
|
408
408
|
/**
|
|
409
409
|
* Handle login tool - opens browser for authentication
|
|
410
|
+
* Uses polling-based flow that survives MCP reconnections
|
|
410
411
|
*/
|
|
411
412
|
async handleLoginTool(params, id) {
|
|
412
|
-
const
|
|
413
|
+
const crypto = require('crypto');
|
|
413
414
|
|
|
414
415
|
// Check if already authenticated
|
|
415
416
|
if (this.isAuthenticated && this.userToken) {
|
|
@@ -436,96 +437,56 @@ To re-login: npx polydev-ai`
|
|
|
436
437
|
};
|
|
437
438
|
}
|
|
438
439
|
|
|
439
|
-
//
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
448
|
-
'Access-Control-Allow-Headers': 'Content-Type'
|
|
449
|
-
});
|
|
450
|
-
res.end();
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (url.pathname === '/callback') {
|
|
455
|
-
const token = url.searchParams.get('token');
|
|
456
|
-
|
|
457
|
-
if (token && token.startsWith('pd_')) {
|
|
458
|
-
// Save token
|
|
459
|
-
this.saveTokenToFiles(token);
|
|
460
|
-
this.userToken = token;
|
|
461
|
-
this.isAuthenticated = true;
|
|
462
|
-
this._freshLogin = true;
|
|
463
|
-
|
|
464
|
-
res.writeHead(200, {
|
|
465
|
-
'Content-Type': 'text/html; charset=utf-8',
|
|
466
|
-
'Access-Control-Allow-Origin': '*'
|
|
467
|
-
});
|
|
468
|
-
res.end(this.getLoginSuccessHTML());
|
|
469
|
-
|
|
470
|
-
console.error('[Polydev] Login successful, token saved');
|
|
471
|
-
console.error('[Polydev] ✓ You can now use Polydev tools!');
|
|
472
|
-
|
|
473
|
-
// Wait 7 seconds before closing server
|
|
474
|
-
setTimeout(() => {
|
|
475
|
-
server.close();
|
|
476
|
-
resolve(true);
|
|
477
|
-
}, 7000);
|
|
478
|
-
} else {
|
|
479
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
480
|
-
res.end('Invalid or missing token');
|
|
481
|
-
}
|
|
482
|
-
} else {
|
|
483
|
-
res.writeHead(404);
|
|
484
|
-
res.end('Not found');
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
server.listen(0, 'localhost', () => {
|
|
489
|
-
const port = server.address().port;
|
|
490
|
-
const callbackUrl = `http://localhost:${port}/callback`;
|
|
491
|
-
const authUrl = `https://polydev.ai/auth?callback=${encodeURIComponent(callbackUrl)}&redirect=ide-plugin&auto=true`;
|
|
492
|
-
|
|
493
|
-
console.error(`[Polydev] Opening browser for authentication...`);
|
|
494
|
-
console.error(`[Polydev] Auth URL: ${authUrl}`);
|
|
495
|
-
|
|
496
|
-
this.openBrowser(authUrl).catch(() => {
|
|
497
|
-
console.error('[Polydev] Could not open browser automatically');
|
|
498
|
-
console.error('[Polydev] Please open this URL manually:', authUrl);
|
|
499
|
-
});
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
// Timeout after 5 minutes
|
|
503
|
-
setTimeout(() => {
|
|
504
|
-
server.close();
|
|
505
|
-
resolve(false);
|
|
506
|
-
}, 5 * 60 * 1000);
|
|
507
|
-
|
|
508
|
-
server.on('error', (err) => {
|
|
509
|
-
console.error('[Polydev] Login server error:', err.message);
|
|
510
|
-
resolve(false);
|
|
440
|
+
// Generate unique session ID for polling-based auth
|
|
441
|
+
const sessionId = crypto.randomBytes(32).toString('hex');
|
|
442
|
+
|
|
443
|
+
try {
|
|
444
|
+
// Create session on server
|
|
445
|
+
const createResponse = await fetch(`https://www.polydev.ai/api/auth/cli-session/${sessionId}`, {
|
|
446
|
+
method: 'POST',
|
|
447
|
+
headers: { 'Content-Type': 'application/json' }
|
|
511
448
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
449
|
+
|
|
450
|
+
if (!createResponse.ok) {
|
|
451
|
+
const error = await createResponse.text();
|
|
452
|
+
console.error('[Polydev] Failed to create login session:', error);
|
|
453
|
+
return {
|
|
454
|
+
jsonrpc: '2.0',
|
|
455
|
+
id,
|
|
456
|
+
result: {
|
|
457
|
+
content: [{
|
|
458
|
+
type: 'text',
|
|
459
|
+
text: `Login session creation failed. Please try again or run: npx polydev-ai`
|
|
460
|
+
}],
|
|
461
|
+
isError: true
|
|
462
|
+
}
|
|
463
|
+
};
|
|
518
464
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
465
|
+
|
|
466
|
+
// Open browser with session_id (no localhost callback needed)
|
|
467
|
+
const authUrl = `https://polydev.ai/auth?session_id=${sessionId}&redirect=ide-plugin&auto=true`;
|
|
468
|
+
|
|
469
|
+
console.error(`[Polydev] Opening browser for authentication...`);
|
|
470
|
+
console.error(`[Polydev] Session ID: ${sessionId.slice(0, 8)}...`);
|
|
471
|
+
console.error(`[Polydev] Auth URL: ${authUrl}`);
|
|
472
|
+
|
|
473
|
+
this.openBrowser(authUrl).catch(() => {
|
|
474
|
+
console.error('[Polydev] Could not open browser automatically');
|
|
475
|
+
console.error('[Polydev] Please open this URL manually:', authUrl);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Start polling in background (survives reconnections because
|
|
479
|
+
// if this process dies, the new one can resume polling with same session)
|
|
480
|
+
this.startLoginPolling(sessionId);
|
|
481
|
+
|
|
482
|
+
// Return immediately
|
|
483
|
+
return {
|
|
484
|
+
jsonrpc: '2.0',
|
|
485
|
+
id,
|
|
486
|
+
result: {
|
|
487
|
+
content: [{
|
|
488
|
+
type: 'text',
|
|
489
|
+
text: `╭─────────────────────────────────────────╮
|
|
529
490
|
│ BROWSER OPENED FOR LOGIN 🌐 │
|
|
530
491
|
╰─────────────────────────────────────────╯
|
|
531
492
|
|
|
@@ -533,14 +494,86 @@ To re-login: npx polydev-ai`
|
|
|
533
494
|
|
|
534
495
|
After login:
|
|
535
496
|
• Token will be saved automatically
|
|
536
|
-
• You
|
|
537
|
-
•
|
|
497
|
+
• You can safely reconnect MCP or restart IDE
|
|
498
|
+
• Use /polydev:auth to check status
|
|
499
|
+
|
|
500
|
+
⏳ Polling for authentication completion...
|
|
501
|
+
(Session expires in 10 minutes)`
|
|
502
|
+
}]
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
} catch (error) {
|
|
507
|
+
console.error('[Polydev] Login error:', error);
|
|
508
|
+
return {
|
|
509
|
+
jsonrpc: '2.0',
|
|
510
|
+
id,
|
|
511
|
+
result: {
|
|
512
|
+
content: [{
|
|
513
|
+
type: 'text',
|
|
514
|
+
text: `Login failed: ${error.message}\n\nPlease try: npx polydev-ai`
|
|
515
|
+
}],
|
|
516
|
+
isError: true
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
538
521
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
522
|
+
/**
|
|
523
|
+
* Poll for login session completion
|
|
524
|
+
*/
|
|
525
|
+
async startLoginPolling(sessionId) {
|
|
526
|
+
const pollInterval = 2000; // 2 seconds
|
|
527
|
+
const maxPolls = 300; // 10 minutes max
|
|
528
|
+
let polls = 0;
|
|
529
|
+
|
|
530
|
+
const poll = async () => {
|
|
531
|
+
polls++;
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
const response = await fetch(`https://www.polydev.ai/api/auth/cli-session/${sessionId}`);
|
|
535
|
+
const data = await response.json();
|
|
536
|
+
|
|
537
|
+
if (data.status === 'completed' && data.token) {
|
|
538
|
+
// Success! Save the token
|
|
539
|
+
this.saveTokenToFiles(data.token);
|
|
540
|
+
this.userToken = data.token;
|
|
541
|
+
this.isAuthenticated = true;
|
|
542
|
+
this._freshLogin = true;
|
|
543
|
+
|
|
544
|
+
console.error('[Polydev] ✓ Login successful! Token saved.');
|
|
545
|
+
console.error('[Polydev] You can now use Polydev tools.');
|
|
546
|
+
return; // Stop polling
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (data.status === 'expired' || response.status === 410) {
|
|
550
|
+
console.error('[Polydev] Login session expired. Please try again.');
|
|
551
|
+
return; // Stop polling
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (data.status === 'not_found' || response.status === 404) {
|
|
555
|
+
console.error('[Polydev] Login session not found.');
|
|
556
|
+
return; // Stop polling
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Still pending, continue polling
|
|
560
|
+
if (polls < maxPolls) {
|
|
561
|
+
setTimeout(poll, pollInterval);
|
|
562
|
+
} else {
|
|
563
|
+
console.error('[Polydev] Login polling timed out.');
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error('[Polydev] Poll error:', error.message);
|
|
568
|
+
// Continue polling on network errors
|
|
569
|
+
if (polls < maxPolls) {
|
|
570
|
+
setTimeout(poll, pollInterval);
|
|
571
|
+
}
|
|
542
572
|
}
|
|
543
573
|
};
|
|
574
|
+
|
|
575
|
+
// Start polling
|
|
576
|
+
setTimeout(poll, pollInterval);
|
|
544
577
|
}
|
|
545
578
|
|
|
546
579
|
/**
|