polydev-ai 1.9.38 → 1.9.40

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.
@@ -21,11 +21,60 @@ class TunnelClient {
21
21
  this.pollInterval = null;
22
22
  this._processing = new Set(); // track in-flight request IDs
23
23
  this._started = false;
24
+ this._consecutive401s = 0; // track auth failures for token reload
24
25
 
25
26
  // Configurable intervals
26
27
  this.HEARTBEAT_INTERVAL_MS = 30_000; // 30s
27
28
  this.POLL_INTERVAL_MS = 3_000; // 3s
28
29
  this.CLI_TIMEOUT_MS = 120_000; // 2 min per request
30
+
31
+ // Try to load freshest token from file on construction
32
+ // (env var may be stale if process was started long ago)
33
+ this._reloadTokenFromFile();
34
+ }
35
+
36
+ /**
37
+ * Reload token from ~/.polydev.env file.
38
+ * The env var POLYDEV_USER_TOKEN may be stale (set when the IDE started the process).
39
+ * The file is always updated by the latest login.
40
+ */
41
+ _reloadTokenFromFile() {
42
+ try {
43
+ const fs = require('fs');
44
+ const path = require('path');
45
+ const os = require('os');
46
+ const envFile = path.join(os.homedir(), '.polydev.env');
47
+
48
+ if (!fs.existsSync(envFile)) return false;
49
+
50
+ const content = fs.readFileSync(envFile, 'utf8');
51
+ const match = content.match(/POLYDEV_USER_TOKEN[=\s]["']?([^"'\n]+)["']?/);
52
+ if (match && match[1] && (match[1].startsWith('pd_') || match[1].startsWith('polydev_'))) {
53
+ if (match[1] !== this.authToken) {
54
+ console.error(`[Tunnel] Token reloaded from ${envFile} (was stale)`);
55
+ this.authToken = match[1];
56
+ this._consecutive401s = 0;
57
+ return true;
58
+ }
59
+ }
60
+ } catch {
61
+ // ignore file read errors
62
+ }
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Handle a 401 response — try reloading token from file
68
+ */
69
+ _handle401() {
70
+ this._consecutive401s++;
71
+ // Try reload every 5 consecutive 401s (every ~15s at 3s poll interval)
72
+ if (this._consecutive401s % 5 === 1) {
73
+ const reloaded = this._reloadTokenFromFile();
74
+ if (reloaded) {
75
+ console.error('[Tunnel] Token refreshed after 401 — retrying');
76
+ }
77
+ }
29
78
  }
30
79
 
31
80
  /**
@@ -36,6 +85,7 @@ class TunnelClient {
36
85
  this._started = true;
37
86
 
38
87
  console.error('[Tunnel] Starting CLI-as-API tunnel client');
88
+ console.error(`[Tunnel] Auth token prefix: ${this.authToken ? this.authToken.substring(0, 8) + '...' : 'NONE'}`);
39
89
 
40
90
  // Send initial heartbeat immediately
41
91
  try {
@@ -102,9 +152,14 @@ class TunnelClient {
102
152
  });
103
153
 
104
154
  if (!res.ok) {
155
+ if (res.status === 401) {
156
+ this._handle401();
157
+ return;
158
+ }
105
159
  const text = await res.text().catch(() => '');
106
160
  throw new Error(`Heartbeat failed (${res.status}): ${text}`);
107
161
  }
162
+ this._consecutive401s = 0; // reset on success
108
163
  }
109
164
 
110
165
  /**
@@ -120,11 +175,14 @@ class TunnelClient {
120
175
  });
121
176
 
122
177
  if (!res.ok) {
123
- // 401 is expected if token expired don't spam logs
124
- if (res.status === 401) return;
178
+ if (res.status === 401) {
179
+ this._handle401();
180
+ return;
181
+ }
125
182
  const text = await res.text().catch(() => '');
126
183
  throw new Error(`Poll failed (${res.status}): ${text}`);
127
184
  }
185
+ this._consecutive401s = 0; // reset on success
128
186
 
129
187
  const data = await res.json();
130
188
  const requests = data.requests || [];
@@ -2770,7 +2770,7 @@ To re-login: /polydev:login`
2770
2770
  const statusFile = path.join(polydevevDir, 'cli-status.json');
2771
2771
 
2772
2772
  // Ensure directory exists
2773
- if (!fs.existsSync(polydeveevDir)) {
2773
+ if (!fs.existsSync(polydevevDir)) {
2774
2774
  fs.mkdirSync(polydeveevDir, { recursive: true });
2775
2775
  }
2776
2776
 
@@ -2962,6 +2962,10 @@ To re-login: /polydev:login`
2962
2962
  return; // No auth, skip tunnel
2963
2963
  }
2964
2964
 
2965
+ // Reload token from file to get the freshest one
2966
+ // (env var may be stale if IDE started this process long ago)
2967
+ this.reloadTokenFromFiles();
2968
+
2965
2969
  try {
2966
2970
  this.tunnelClient = new TunnelClient(
2967
2971
  this.serverUrl, // https://www.polydev.ai/api/mcp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.38",
3
+ "version": "1.9.40",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },