polydev-ai 1.9.27 → 1.9.29

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.
Files changed (2) hide show
  1. package/mcp/stdio-wrapper.js +75 -148
  2. package/package.json +1 -1
@@ -155,9 +155,6 @@ if (writableTmp) {
155
155
  * Strips: provider info, approval, sandbox, reasoning, session id, MCP errors, etc.
156
156
  *
157
157
  * Codex CLI output structure:
158
- * [metadata] → user → [echoed prompt] → thinking → [status] → codex → [RESPONSE] → tokens used → [count]
159
- *
160
- * Claude Code output structure:
161
158
  * [may include JSON or plain text response]
162
159
  */
163
160
  function cleanCliResponse(content) {
@@ -1046,9 +1043,28 @@ To authenticate, pass your token directly:
1046
1043
  };
1047
1044
  }
1048
1045
 
1049
- // Not sandboxed — auto-trigger browser login
1050
- console.error('[Polydev] No token found, auto-triggering login flow...');
1051
- return await this.triggerReAuth(id, 'Not authenticated. Opening browser for login...');
1046
+ // Not sandboxed — tell user to use login tool (don't auto-open browser)
1047
+ console.error('[Polydev] No token found, prompting user to login');
1048
+ return {
1049
+ jsonrpc: '2.0',
1050
+ id,
1051
+ result: {
1052
+ content: [{
1053
+ type: 'text',
1054
+ text: `POLYDEV STATUS
1055
+ ==============
1056
+
1057
+ Authentication: Not connected
1058
+
1059
+ To login:
1060
+ 1. Use the "login" tool (opens browser)
1061
+ 2. Or run: npx polydev-ai
1062
+
1063
+ Token will be saved automatically after login.`
1064
+ }],
1065
+ isError: true
1066
+ }
1067
+ };
1052
1068
  }
1053
1069
 
1054
1070
  try {
@@ -1138,9 +1154,26 @@ Configure: https://polydev.ai/dashboard/models`
1138
1154
  }
1139
1155
  };
1140
1156
  } else {
1141
- // Token invalid/expired - auto-trigger re-authentication
1142
- console.error('[Polydev] Auth status: token invalid/expired, auto-triggering re-auth...');
1143
- return await this.triggerReAuth(id, 'Token invalid or expired.');
1157
+ // Token invalid/expired - tell user to re-login (don't auto-open browser)
1158
+ console.error('[Polydev] Auth status: token invalid/expired');
1159
+ return {
1160
+ jsonrpc: '2.0',
1161
+ id,
1162
+ result: {
1163
+ content: [{
1164
+ type: 'text',
1165
+ text: `POLYDEV STATUS
1166
+ ==============
1167
+
1168
+ Authentication: Token invalid or expired
1169
+
1170
+ To re-authenticate:
1171
+ 1. Use the "login" tool (opens browser)
1172
+ 2. Or run: npx polydev-ai`
1173
+ }],
1174
+ isError: true
1175
+ }
1176
+ };
1144
1177
  }
1145
1178
  } catch (error) {
1146
1179
  // Categorize the error for clearer user messaging
@@ -1600,8 +1633,7 @@ To re-login: /polydev:login`
1600
1633
 
1601
1634
  /**
1602
1635
  * Start a periodic progress heartbeat to prevent client-side timeouts.
1603
- * Sends a progress notification every intervalMs to signal the server is still working.
1604
- * Compatible MCP clients will reset their timeout clock on each notification.
1636
+ * Sends a progress notification every intervalMs to keep the connection alive
1605
1637
  * @param {string|number} progressToken - Token from request's _meta.progressToken
1606
1638
  * @param {number} intervalMs - Heartbeat interval in milliseconds (default: 10s)
1607
1639
  * @returns {{ stop: Function, tick: Function }} Controller to stop heartbeat and manually tick progress
@@ -1687,11 +1719,24 @@ To re-login: /polydev:login`
1687
1719
  heartbeat.stop(); // Always clean up heartbeat
1688
1720
  console.error(`[Stdio Wrapper] get_perspectives error:`, error);
1689
1721
 
1690
- // Check if error is auth-related
1722
+ // Check if error is specifically an HTTP 401 unauthorized
1723
+ // IMPORTANT: Don't match generic 'token' or 'auth' strings — they appear in
1724
+ // unrelated errors like "Unexpected token" (JSON parse) or "authentication" (CLI output)
1691
1725
  const errMsg = (error.message || '').toLowerCase();
1692
- if (errMsg.includes('401') || errMsg.includes('unauthorized') || errMsg.includes('auth') || errMsg.includes('token')) {
1693
- console.error('[Polydev] Perspectives auth error, auto-triggering re-authentication...');
1694
- return await this.triggerReAuth(id, 'Authentication expired. Re-authenticating...');
1726
+ const isHttp401 = errMsg.includes('401') || errMsg.includes('unauthorized');
1727
+ if (isHttp401) {
1728
+ console.error('[Polydev] Perspectives auth error (401), suggesting re-login');
1729
+ return {
1730
+ jsonrpc: '2.0',
1731
+ id,
1732
+ result: {
1733
+ content: [{
1734
+ type: 'text',
1735
+ text: `Authentication error: ${error.message}\n\nPlease re-authenticate using the "login" tool or run: npx polydev-ai`
1736
+ }],
1737
+ isError: true
1738
+ }
1739
+ };
1695
1740
  }
1696
1741
 
1697
1742
  return {
@@ -2676,8 +2721,8 @@ To re-login: /polydev:login`
2676
2721
  const statusFile = path.join(polydevevDir, 'cli-status.json');
2677
2722
 
2678
2723
  // Ensure directory exists
2679
- if (!fs.existsSync(polydevevDir)) {
2680
- fs.mkdirSync(polydevevDir, { recursive: true });
2724
+ if (!fs.existsSync(polydeveevDir)) {
2725
+ fs.mkdirSync(polydeveevDir, { recursive: true });
2681
2726
  }
2682
2727
 
2683
2728
  // Save status with timestamp
@@ -3141,28 +3186,24 @@ To re-login: /polydev:login`
3141
3186
  }
3142
3187
 
3143
3188
  /**
3144
- * Run startup flow - auto-login if no token, verify if has token
3189
+ * Run startup flow - verify token if present, show instructions if not
3190
+ * NEVER auto-opens browser — only the explicit "login" tool should do that
3145
3191
  */
3146
3192
  async runStartupFlow() {
3193
+ // Last-chance token reload before deciding
3194
+ if (!this.userToken) {
3195
+ this.reloadTokenFromFiles();
3196
+ }
3197
+
3147
3198
  if (!this.userToken) {
3148
- // No token - auto-open browser for login (NON-BLOCKING)
3199
+ // No token found just log instructions, don't open browser
3149
3200
  console.error('─'.repeat(50));
3150
- console.error('Polydev - First Time Setup');
3201
+ console.error('Polydev - Authentication Required');
3151
3202
  console.error('─'.repeat(50));
3152
- console.error('Opening browser for authentication...\n');
3153
-
3154
- // Run auto-login in background (don't block MCP server startup)
3155
- this.autoLoginOnStartup().then(() => {
3156
- console.error('[Polydev] Login completed, running CLI detection...');
3157
- // After login, run CLI detection
3158
- return this.localForceCliDetection({});
3159
- }).then(() => {
3160
- this._cliDetectionComplete = true;
3161
- // Display CLI status after detection
3162
- return this.displayCliStatus();
3163
- }).catch((error) => {
3164
- console.error('[Polydev] Auto-login flow error:', error.message);
3165
- });
3203
+ console.error('No token found. To authenticate:');
3204
+ console.error(' 1. Use the "login" tool');
3205
+ console.error(' 2. Or run: npx polydev-ai');
3206
+ console.error('─'.repeat(50) + '\n');
3166
3207
  } else {
3167
3208
  // Has token - verify it (also non-blocking)
3168
3209
  this.verifyAndDisplayAuth().catch((error) => {
@@ -3171,117 +3212,6 @@ To re-login: /polydev:login`
3171
3212
  }
3172
3213
  }
3173
3214
 
3174
- /**
3175
- * Auto-login on startup (opens browser automatically)
3176
- */
3177
- async autoLoginOnStartup() {
3178
- const http = require('http');
3179
- const { spawn } = require('child_process');
3180
-
3181
- return new Promise((resolve) => {
3182
- const server = http.createServer((req, res) => {
3183
- const url = new URL(req.url, `http://localhost`);
3184
-
3185
- if (req.method === 'OPTIONS') {
3186
- res.writeHead(204, {
3187
- 'Access-Control-Allow-Origin': '*',
3188
- 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
3189
- 'Access-Control-Allow-Headers': 'Content-Type'
3190
- });
3191
- res.end();
3192
- return;
3193
- }
3194
-
3195
- if (url.pathname === '/callback') {
3196
- const token = url.searchParams.get('token');
3197
-
3198
- if (token && token.startsWith('pd_')) {
3199
- this.saveTokenToFiles(token);
3200
- this.userToken = token;
3201
- this.isAuthenticated = true;
3202
- this._freshLogin = true; // Flag for opening models page after CLI detection
3203
-
3204
- res.writeHead(200, {
3205
- 'Content-Type': 'text/html; charset=utf-8',
3206
- 'Access-Control-Allow-Origin': '*'
3207
- });
3208
- res.end(this.getLoginSuccessHTML());
3209
-
3210
- console.error('[Polydev] Login successful, token saved');
3211
-
3212
- // Wait 7 seconds before closing server (gives time for 5s auto-close countdown + buffer)
3213
- setTimeout(() => {
3214
- server.close();
3215
- resolve({
3216
- jsonrpc: '2.0',
3217
- id,
3218
- result: {
3219
- content: [{
3220
- type: 'text',
3221
- text: `LOGIN SUCCESSFUL
3222
- ================
3223
-
3224
- Token saved to:
3225
- ~/.polydev.env
3226
- ~/.zshrc
3227
-
3228
- IMPORTANT: Restart your IDE to activate.
3229
-
3230
- After restart, you can:
3231
- /polydev:ask Query multiple AI models
3232
- /polydev:auth Check status & credits
3233
-
3234
- Dashboard: https://polydev.ai/dashboard`
3235
- }]
3236
- }
3237
- });
3238
- }, 7000);
3239
- } else {
3240
- res.writeHead(400, { 'Content-Type': 'text/plain' });
3241
- res.end('Invalid or missing token');
3242
- }
3243
- } else {
3244
- res.writeHead(404);
3245
- res.end('Not found');
3246
- }
3247
- });
3248
-
3249
- server.listen(0, 'localhost', () => {
3250
- const port = server.address().port;
3251
- const callbackUrl = `http://localhost:${port}/callback`;
3252
- const authUrl = `https://polydev.ai/auth?callback=${encodeURIComponent(callbackUrl)}&redirect=ide-plugin&auto=true`;
3253
-
3254
- console.error('If browser does not open, visit:');
3255
- console.error(authUrl);
3256
- console.error('');
3257
-
3258
- // Best-in-class browser opening using 'open' package (cross-platform)
3259
- // Falls back to platform-specific commands if package fails
3260
- this.openBrowser(authUrl).catch(() => {
3261
- console.error('[Polydev] All browser open methods failed');
3262
- console.error('[Polydev] Please open this URL manually:', authUrl);
3263
- });
3264
-
3265
- // Don't block forever - resolve after timeout
3266
- setTimeout(() => {
3267
- if (!this.isAuthenticated) {
3268
- console.error('[!] Login timeout - use "login" tool to try again');
3269
- console.error('─'.repeat(50) + '\n');
3270
- }
3271
- server.close();
3272
- resolve(false);
3273
- }, 2 * 60 * 1000); // 2 minute timeout for startup
3274
- });
3275
-
3276
- server.on('error', (err) => {
3277
- console.error('[!] Could not start login server:', err.message);
3278
- console.error(' Use "login" tool or run: npx polydev-ai login');
3279
- console.error('─'.repeat(50) + '\n');
3280
- resolve(false);
3281
- });
3282
- });
3283
- }
3284
-
3285
3215
  /**
3286
3216
  * Verify token and display auth status
3287
3217
  */
@@ -3309,9 +3239,6 @@ Dashboard: https://polydev.ai/dashboard`
3309
3239
  console.error(`Credits: ${credits} | Tier: ${tier}`);
3310
3240
  console.error('─'.repeat(50) + '\n');
3311
3241
  } else {
3312
- // Don't clear isAuthenticated here — handleGetAuthStatus has its own
3313
- // verification and triggerReAuth logic. Clearing here causes a race condition
3314
- // where startup verification can invalidate auth before the user checks status.
3315
3242
  console.error('─'.repeat(50));
3316
3243
  console.error('Polydev - Token may be invalid');
3317
3244
  console.error('─'.repeat(50));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.27",
3
+ "version": "1.9.29",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },