ai-or-die 0.1.46 → 0.1.47

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.
@@ -3,7 +3,10 @@ REM Mock devtunnel CLI for E2E testing.
3
3
  REM Simulates the subcommands used by VSCodeTunnelManager's two-process model.
4
4
 
5
5
  REM --- user show: auth check (exit 0 = authenticated) ---
6
- if "%1"=="user" if "%2"=="show" exit /b 0
6
+ if "%1"=="user" if "%2"=="show" (
7
+ echo Logged in as mock-user using GitHub.
8
+ exit /b 0
9
+ )
7
10
 
8
11
  REM --- user login: authenticate (exit 0 = success) ---
9
12
  if "%1"=="user" if "%2"=="login" exit /b 0
@@ -4,6 +4,7 @@
4
4
 
5
5
  # --- user show: auth check (exit 0 = authenticated) ---
6
6
  if [ "$1" = "user" ] && [ "$2" = "show" ]; then
7
+ echo "Logged in as mock-user using GitHub."
7
8
  exit 0
8
9
  fi
9
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-or-die",
3
- "version": "0.1.46",
3
+ "version": "0.1.47",
4
4
  "description": "Universal AI coding terminal — Claude, Copilot, Gemini & more in your browser",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -21,7 +21,9 @@ class TunnelManager {
21
21
  this.stopping = false;
22
22
  this._restarting = false;
23
23
  this.retryCount = 0;
24
- this.tunnelId = `aiordie-${os.hostname().toLowerCase().replace(/[^a-z0-9-]/g, '')}`;
24
+ this._hostnameSlug = os.hostname().toLowerCase().replace(/[^a-z0-9-]/g, '');
25
+ this.tunnelId = `aiordie-${this._hostnameSlug}`;
26
+ this._authProvider = null;
25
27
 
26
28
  // Resilience tracking
27
29
  this._lastSpawnTime = null;
@@ -183,15 +185,20 @@ class TunnelManager {
183
185
 
184
186
  /**
185
187
  * Check if user is logged in. If not, attempt interactive login.
188
+ * Detects auth provider (GitHub vs Entra) and adjusts tunnel ID to avoid
189
+ * cross-provider name collisions.
186
190
  */
187
191
  async _checkLogin() {
188
- const isLoggedIn = await new Promise((resolve) => {
189
- execFile('devtunnel', ['user', 'show'], { timeout: 10000 }, (err) => {
190
- resolve(!err);
192
+ const result = await new Promise((resolve) => {
193
+ execFile('devtunnel', ['user', 'show'], { timeout: 10000 }, (err, stdout) => {
194
+ resolve({ ok: !err, stdout: (stdout || '').toString() });
191
195
  });
192
196
  });
193
197
 
194
- if (isLoggedIn) return true;
198
+ if (result.ok) {
199
+ this._applyAuthSuffix(result.stdout);
200
+ return true;
201
+ }
195
202
 
196
203
  console.log(' DevTunnel requires authentication. Launching login...\n');
197
204
 
@@ -206,6 +213,13 @@ class TunnelManager {
206
213
 
207
214
  if (loginOk) {
208
215
  console.log('\n Login successful. Connecting tunnel...');
216
+ // Re-check to detect which provider was used
217
+ const recheck = await new Promise((resolve) => {
218
+ execFile('devtunnel', ['user', 'show'], { timeout: 10000 }, (err, stdout) => {
219
+ resolve((stdout || '').toString());
220
+ });
221
+ });
222
+ this._applyAuthSuffix(recheck);
209
223
  return true;
210
224
  }
211
225
 
@@ -213,6 +227,19 @@ class TunnelManager {
213
227
  return false;
214
228
  }
215
229
 
230
+ /**
231
+ * Parse auth provider from `devtunnel user show` output and append
232
+ * a suffix to the tunnel ID when using GitHub auth. This prevents
233
+ * name collisions with tunnels created under a different provider.
234
+ */
235
+ _applyAuthSuffix(userShowOutput) {
236
+ const match = userShowOutput.match(/using\s+(GitHub)/i);
237
+ if (match) {
238
+ this._authProvider = 'github';
239
+ this.tunnelId = `aiordie-${this._hostnameSlug}-gh`;
240
+ }
241
+ }
242
+
216
243
  /**
217
244
  * Create the named tunnel and configure its port.
218
245
  * Steps: devtunnel create <id> → devtunnel port create <id> -p <port>
@@ -45,6 +45,7 @@ class VSCodeTunnelManager {
45
45
 
46
46
  this._healthInterval = null;
47
47
  this._reservedPorts = new Set();
48
+ this._authProvider = null;
48
49
 
49
50
  // Kick off async command discovery at construction time
50
51
  this._initPromise = Promise.all([
@@ -123,7 +124,7 @@ class VSCodeTunnelManager {
123
124
  connectionToken,
124
125
  localUrl: null,
125
126
  publicUrl: null,
126
- tunnelId: `aiordie-vscode-${sessionId.slice(0, 12).replace(/[^a-z0-9-]/gi, '')}`,
127
+ tunnelId: `aiordie-vscode-${sessionId.slice(0, 12).replace(/[^a-z0-9-]/gi, '')}${this._authProvider === 'github' ? '-gh' : ''}`,
127
128
  status: 'starting',
128
129
  sessionId,
129
130
  workingDir: workingDir || process.cwd(),
@@ -161,6 +162,13 @@ class VSCodeTunnelManager {
161
162
  return { success: false, error: 'Authentication failed or was cancelled' };
162
163
  }
163
164
  console.warn(`[VSCODE-TUNNEL] Session ${sessionId}: devtunnel login successful`);
165
+ // Re-check to detect auth provider after fresh login
166
+ await this._checkDevtunnelAuth();
167
+ }
168
+
169
+ // Update tunnel ID with auth-provider suffix after detection
170
+ if (this._authProvider === 'github') {
171
+ tunnel.tunnelId = `aiordie-vscode-${sessionId.slice(0, 12).replace(/[^a-z0-9-]/gi, '')}-gh`;
164
172
  }
165
173
 
166
174
  // Start health check interval (once)
@@ -241,7 +249,7 @@ class VSCodeTunnelManager {
241
249
 
242
250
  // Step 2: Clean up devtunnel (fire-and-forget)
243
251
  if (this._devtunnelCommand) {
244
- execFile(this._devtunnelCommand, ['delete', tunnel.tunnelId, '-y'], { timeout: 10000 }, () => {});
252
+ execFile(this._devtunnelCommand, ['delete', tunnel.tunnelId, '-f'], { timeout: 10000 }, () => {});
245
253
  }
246
254
 
247
255
  // Step 3: Kill server process
@@ -457,12 +465,22 @@ class VSCodeTunnelManager {
457
465
 
458
466
  /**
459
467
  * Check if user is authenticated with devtunnel (OS-level credential store).
468
+ * Also detects auth provider (GitHub vs Entra) for tunnel name suffixing.
460
469
  */
461
470
  async _checkDevtunnelAuth() {
462
471
  if (!this._devtunnelCommand) return false;
463
472
  return new Promise((resolve) => {
464
- execFile(this._devtunnelCommand, ['user', 'show'], { timeout: 10000 }, (err) => {
465
- resolve(!err);
473
+ execFile(this._devtunnelCommand, ['user', 'show'], { timeout: 10000 }, (err, stdout) => {
474
+ if (err) {
475
+ resolve(false);
476
+ } else {
477
+ const output = (stdout || '').toString();
478
+ const match = output.match(/using\s+(GitHub)/i);
479
+ if (match) {
480
+ this._authProvider = 'github';
481
+ }
482
+ resolve(true);
483
+ }
466
484
  });
467
485
  });
468
486
  }