polydev-ai 1.9.19 → 1.9.20
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/manifest.json +4 -0
- package/mcp/stdio-wrapper.js +137 -20
- package/package.json +1 -1
package/mcp/manifest.json
CHANGED
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
"minimum": 30,
|
|
99
99
|
"maximum": 600,
|
|
100
100
|
"default": 300
|
|
101
|
+
},
|
|
102
|
+
"user_token": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"description": "Polydev user token (pd_xxx). Use this in sandboxed environments (Cowork, containers) where browser login is unavailable. Get your token from https://polydev.ai/dashboard"
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
},
|
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -300,6 +300,9 @@ class StdioMCPWrapper {
|
|
|
300
300
|
// Pending session file for surviving restarts
|
|
301
301
|
this.PENDING_SESSION_FILE = path.join(os.homedir(), '.polydev-pending-session');
|
|
302
302
|
|
|
303
|
+
// Sandbox detection (Cowork, containers with limited disk/no browser)
|
|
304
|
+
this._isSandboxed = null; // lazy-detected
|
|
305
|
+
|
|
303
306
|
// MCP client info (set during initialize handshake)
|
|
304
307
|
// Used to detect which IDE is running us and exclude its CLI to avoid recursive calls
|
|
305
308
|
this.clientInfo = null;
|
|
@@ -491,7 +494,18 @@ Token will be saved automatically after login.`
|
|
|
491
494
|
*/
|
|
492
495
|
async handleLoginTool(params, id) {
|
|
493
496
|
const crypto = require('crypto');
|
|
494
|
-
|
|
497
|
+
|
|
498
|
+
// Accept user_token from params (essential for sandboxed environments like Cowork)
|
|
499
|
+
const inlineToken = params?.arguments?.user_token;
|
|
500
|
+
if (inlineToken && (inlineToken.startsWith('pd_') || inlineToken.startsWith('polydev_'))) {
|
|
501
|
+
console.error('[Polydev] Login via inline user_token');
|
|
502
|
+
this.userToken = inlineToken;
|
|
503
|
+
this.isAuthenticated = true;
|
|
504
|
+
process.env.POLYDEV_USER_TOKEN = inlineToken;
|
|
505
|
+
this.saveTokenToFiles(inlineToken);
|
|
506
|
+
return await this.fetchAuthStatusResponse(id);
|
|
507
|
+
}
|
|
508
|
+
|
|
495
509
|
// Check if already authenticated - verify with server first
|
|
496
510
|
if (this.isAuthenticated && this.userToken) {
|
|
497
511
|
console.error('[Polydev] Token exists locally, verifying with server...');
|
|
@@ -525,9 +539,38 @@ To re-login: npx polydev-ai`
|
|
|
525
539
|
this.userToken = null;
|
|
526
540
|
}
|
|
527
541
|
|
|
542
|
+
// In sandboxed environments, don't try browser login — show token-paste instructions
|
|
543
|
+
if (this.isSandboxed()) {
|
|
544
|
+
console.error('[Polydev] Sandbox detected — browser login unavailable');
|
|
545
|
+
return {
|
|
546
|
+
jsonrpc: '2.0',
|
|
547
|
+
id,
|
|
548
|
+
result: {
|
|
549
|
+
content: [{
|
|
550
|
+
type: 'text',
|
|
551
|
+
text: `LOGIN - Sandboxed Environment
|
|
552
|
+
==============================
|
|
553
|
+
|
|
554
|
+
Browser login is not available in this environment (Cowork/container).
|
|
555
|
+
|
|
556
|
+
To authenticate, use one of these methods:
|
|
557
|
+
|
|
558
|
+
**Method 1: Pass token directly**
|
|
559
|
+
1. Get your token from https://polydev.ai/dashboard
|
|
560
|
+
2. Call login with user_token:
|
|
561
|
+
|
|
562
|
+
mcp__plugin_polydev_mcp__login({ user_token: "pd_your_token_here" })
|
|
563
|
+
|
|
564
|
+
**Method 2: Set environment variable**
|
|
565
|
+
Set POLYDEV_USER_TOKEN=pd_your_token before starting the MCP server.`
|
|
566
|
+
}]
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
528
571
|
// Generate unique session ID for polling-based auth
|
|
529
572
|
const sessionId = crypto.randomBytes(32).toString('hex');
|
|
530
|
-
|
|
573
|
+
|
|
531
574
|
try {
|
|
532
575
|
// Create session on server (with retry for transient network issues)
|
|
533
576
|
let createResponse;
|
|
@@ -936,13 +979,52 @@ Still waiting for login. Use /polydev:auth to check status after signing in.`
|
|
|
936
979
|
* Handle get_auth_status tool - comprehensive status display
|
|
937
980
|
*/
|
|
938
981
|
async handleGetAuthStatus(params, id) {
|
|
982
|
+
// Accept user_token from params (essential for sandboxed environments like Cowork)
|
|
983
|
+
const inlineToken = params?.arguments?.user_token;
|
|
984
|
+
if (inlineToken && (inlineToken.startsWith('pd_') || inlineToken.startsWith('polydev_'))) {
|
|
985
|
+
console.error('[Polydev] Using inline user_token from params');
|
|
986
|
+
this.userToken = inlineToken;
|
|
987
|
+
this.isAuthenticated = true;
|
|
988
|
+
process.env.POLYDEV_USER_TOKEN = inlineToken;
|
|
989
|
+
this.saveTokenToFiles(inlineToken); // safe — handles sandbox gracefully
|
|
990
|
+
}
|
|
991
|
+
|
|
939
992
|
// Try to hot-reload token if not authenticated
|
|
940
993
|
if (!this.isAuthenticated || !this.userToken) {
|
|
941
994
|
this.reloadTokenFromFiles();
|
|
942
995
|
}
|
|
943
|
-
|
|
996
|
+
|
|
944
997
|
if (!this.isAuthenticated || !this.userToken) {
|
|
945
|
-
// No token found
|
|
998
|
+
// No token found — check if we're in a sandbox (Cowork, containers)
|
|
999
|
+
if (this.isSandboxed()) {
|
|
1000
|
+
console.error('[Polydev] No token and sandboxed — showing token-paste instructions');
|
|
1001
|
+
return {
|
|
1002
|
+
jsonrpc: '2.0',
|
|
1003
|
+
id,
|
|
1004
|
+
result: {
|
|
1005
|
+
content: [{
|
|
1006
|
+
type: 'text',
|
|
1007
|
+
text: `POLYDEV STATUS
|
|
1008
|
+
==============
|
|
1009
|
+
|
|
1010
|
+
Authentication: Not connected (sandboxed environment detected)
|
|
1011
|
+
|
|
1012
|
+
Browser login is not available in this environment.
|
|
1013
|
+
|
|
1014
|
+
To authenticate, pass your token directly:
|
|
1015
|
+
1. Get your token from https://polydev.ai/dashboard
|
|
1016
|
+
2. Call get_auth_status with user_token parameter:
|
|
1017
|
+
|
|
1018
|
+
mcp__plugin_polydev_mcp__get_auth_status({ user_token: "pd_your_token_here" })
|
|
1019
|
+
|
|
1020
|
+
3. Or set the environment variable before starting:
|
|
1021
|
+
POLYDEV_USER_TOKEN=pd_your_token_here`
|
|
1022
|
+
}]
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// Not sandboxed — auto-trigger browser login
|
|
946
1028
|
console.error('[Polydev] No token found, auto-triggering login flow...');
|
|
947
1029
|
return await this.triggerReAuth(id, 'Not authenticated. Opening browser for login...');
|
|
948
1030
|
}
|
|
@@ -1071,6 +1153,29 @@ To re-login: /polydev:login`
|
|
|
1071
1153
|
}
|
|
1072
1154
|
}
|
|
1073
1155
|
|
|
1156
|
+
/**
|
|
1157
|
+
* Detect if running in a sandboxed environment (Cowork, containers, etc.)
|
|
1158
|
+
* where filesystem is read-only/limited and browser is unavailable.
|
|
1159
|
+
* Result is cached after first check.
|
|
1160
|
+
*/
|
|
1161
|
+
isSandboxed() {
|
|
1162
|
+
if (this._isSandboxed !== null) return this._isSandboxed;
|
|
1163
|
+
|
|
1164
|
+
try {
|
|
1165
|
+
// Try writing a test file to home directory
|
|
1166
|
+
const testFile = path.join(os.homedir(), '.polydev-sandbox-test');
|
|
1167
|
+
fs.writeFileSync(testFile, 'test');
|
|
1168
|
+
fs.unlinkSync(testFile);
|
|
1169
|
+
this._isSandboxed = false;
|
|
1170
|
+
} catch (e) {
|
|
1171
|
+
// ENOSPC, EROFS, EACCES all indicate sandbox-like constraints
|
|
1172
|
+
console.error(`[Polydev] Sandbox detected: ${e.code || e.message}`);
|
|
1173
|
+
this._isSandboxed = true;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
return this._isSandboxed;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1074
1179
|
/**
|
|
1075
1180
|
* Open URL in browser - best-in-class cross-platform implementation
|
|
1076
1181
|
* Uses 'open' npm package with fallbacks for reliability in MCP/stdio context
|
|
@@ -1133,27 +1238,39 @@ To re-login: /polydev:login`
|
|
|
1133
1238
|
* Save token to shell config files
|
|
1134
1239
|
*/
|
|
1135
1240
|
saveTokenToFiles(token) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1241
|
+
if (this.isSandboxed()) {
|
|
1242
|
+
// In sandbox, just set in-memory — can't write files
|
|
1243
|
+
console.error('[Polydev] Sandbox: skipping file writes, token set in-memory only');
|
|
1244
|
+
process.env.POLYDEV_USER_TOKEN = token;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1140
1247
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1248
|
+
try {
|
|
1249
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
1250
|
+
const rcFile = shell.includes('zsh') ? path.join(os.homedir(), '.zshrc') :
|
|
1251
|
+
shell.includes('bash') ? path.join(os.homedir(), '.bashrc') :
|
|
1252
|
+
path.join(os.homedir(), '.profile');
|
|
1143
1253
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
!line.trim().startsWith('POLYDEV_USER_TOKEN')
|
|
1147
|
-
);
|
|
1254
|
+
let content = '';
|
|
1255
|
+
try { content = fs.readFileSync(rcFile, 'utf8'); } catch (e) {}
|
|
1148
1256
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1257
|
+
const lines = content.split('\n').filter(line =>
|
|
1258
|
+
!line.trim().startsWith('export POLYDEV_USER_TOKEN') &&
|
|
1259
|
+
!line.trim().startsWith('POLYDEV_USER_TOKEN')
|
|
1260
|
+
);
|
|
1151
1261
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
fs.writeFileSync(envFile, `POLYDEV_USER_TOKEN="${token}"\n`);
|
|
1262
|
+
lines.push(`export POLYDEV_USER_TOKEN="${token}"`);
|
|
1263
|
+
fs.writeFileSync(rcFile, lines.join('\n').replace(/\n+$/, '') + '\n');
|
|
1155
1264
|
|
|
1156
|
-
|
|
1265
|
+
// Also save to .polydev.env
|
|
1266
|
+
const envFile = path.join(os.homedir(), '.polydev.env');
|
|
1267
|
+
fs.writeFileSync(envFile, `POLYDEV_USER_TOKEN="${token}"\n`);
|
|
1268
|
+
|
|
1269
|
+
console.error(`[Polydev] Token saved to ${rcFile} and ${envFile}`);
|
|
1270
|
+
} catch (e) {
|
|
1271
|
+
console.error(`[Polydev] Could not write token to files (${e.code || e.message}), set in-memory only`);
|
|
1272
|
+
process.env.POLYDEV_USER_TOKEN = token;
|
|
1273
|
+
}
|
|
1157
1274
|
}
|
|
1158
1275
|
|
|
1159
1276
|
/**
|