@hua-labs/tap 0.5.0 → 0.5.1

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/dist/index.mjs CHANGED
@@ -1388,13 +1388,14 @@ function startWindowsDetachedProcess(command, args, repoRoot, logPath, env = pro
1388
1388
  }
1389
1389
  return pid;
1390
1390
  }
1391
- function startWindowsCodexAppServer(command, url, repoRoot, logPath) {
1391
+ function startWindowsCodexAppServer(command, url, repoRoot, logPath, env = process.env) {
1392
1392
  const { command: exe, prefixArgs } = splitResolvedCommand(command);
1393
1393
  return startWindowsDetachedProcess(
1394
1394
  exe,
1395
1395
  [...prefixArgs, "app-server", "--listen", url],
1396
1396
  repoRoot,
1397
- logPath
1397
+ logPath,
1398
+ env
1398
1399
  );
1399
1400
  }
1400
1401
  function findListeningProcessId(url, platform) {
@@ -1514,14 +1515,14 @@ function startUnixDetachedProcess(command, args, repoRoot, logPath, env = proces
1514
1515
  }
1515
1516
  }
1516
1517
  }
1517
- function startUnixCodexAppServer(command, url, repoRoot, logPath, platform = DEFAULT_UNIX_PLATFORM) {
1518
+ function startUnixCodexAppServer(command, url, repoRoot, logPath, env = process.env, platform = DEFAULT_UNIX_PLATFORM) {
1518
1519
  const { command: exe, prefixArgs } = splitResolvedCommand(command);
1519
1520
  return startUnixDetachedProcess(
1520
1521
  exe,
1521
1522
  [...prefixArgs, "app-server", "--listen", url],
1522
1523
  repoRoot,
1523
1524
  logPath,
1524
- process.env,
1525
+ env,
1525
1526
  platform
1526
1527
  );
1527
1528
  }
@@ -2337,6 +2338,19 @@ var init_bridge_app_server_auth = __esm({
2337
2338
  // src/engine/bridge-app-server-lifecycle.ts
2338
2339
  import * as fs18 from "fs";
2339
2340
  import * as path17 from "path";
2341
+ function buildCodexAppServerEnv(options) {
2342
+ return {
2343
+ ...process.env,
2344
+ TAP_COMMS_DIR: options.commsDir,
2345
+ TAP_STATE_DIR: options.stateDir,
2346
+ TAP_RUNTIME_STATE_DIR: options.runtimeStateDir,
2347
+ TAP_REPO_ROOT: options.repoRoot,
2348
+ TAP_BRIDGE_INSTANCE_ID: options.instanceId,
2349
+ TAP_AGENT_ID: options.instanceId,
2350
+ TAP_AGENT_NAME: options.agentName,
2351
+ CODEX_TAP_AGENT_NAME: options.agentName
2352
+ };
2353
+ }
2340
2354
  function isAppServerUsedByOtherBridge(stateDir, excludeInstanceId, appServer) {
2341
2355
  const pidDir = path17.join(stateDir, "pids");
2342
2356
  if (!fs18.existsSync(pidDir)) return false;
@@ -2440,6 +2454,7 @@ Start the app-server manually:
2440
2454
  const logPath = appServerLogFilePath(options.stateDir, options.instanceId);
2441
2455
  fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
2442
2456
  rotateLog(logPath);
2457
+ const appServerEnv = buildCodexAppServerEnv(options);
2443
2458
  if (options.noAuth) {
2444
2459
  const manualCommand2 = formatCodexAppServerCommand("codex", effectiveUrl);
2445
2460
  let pid2;
@@ -2449,7 +2464,8 @@ Start the app-server manually:
2449
2464
  resolvedCommand,
2450
2465
  effectiveUrl,
2451
2466
  options.repoRoot,
2452
- logPath
2467
+ logPath,
2468
+ appServerEnv
2453
2469
  );
2454
2470
  } catch (err) {
2455
2471
  throw new Error(
@@ -2466,6 +2482,7 @@ Start it manually:
2466
2482
  effectiveUrl,
2467
2483
  options.repoRoot,
2468
2484
  logPath,
2485
+ appServerEnv,
2469
2486
  options.platform
2470
2487
  );
2471
2488
  } catch (err) {
@@ -2526,7 +2543,8 @@ Or start it manually:
2526
2543
  resolvedCommand,
2527
2544
  auth.upstreamUrl,
2528
2545
  options.repoRoot,
2529
- logPath
2546
+ logPath,
2547
+ appServerEnv
2530
2548
  );
2531
2549
  } catch (err) {
2532
2550
  if (auth.gatewayPid != null) {
@@ -2547,6 +2565,7 @@ Start it manually:
2547
2565
  auth.upstreamUrl,
2548
2566
  options.repoRoot,
2549
2567
  logPath,
2568
+ appServerEnv,
2550
2569
  options.platform
2551
2570
  );
2552
2571
  } catch (err) {
@@ -2777,9 +2796,12 @@ async function startBridge(options) {
2777
2796
  appServer = await ensureCodexAppServer({
2778
2797
  instanceId,
2779
2798
  stateDir,
2799
+ runtimeStateDir,
2800
+ commsDir,
2780
2801
  repoRoot,
2781
2802
  platform: options.platform,
2782
2803
  appServerUrl: effectiveAppServerUrl,
2804
+ agentName: resolvedAgent,
2783
2805
  existingAppServer: previousAppServer,
2784
2806
  noAuth: options.noAuth
2785
2807
  });
@@ -2800,7 +2822,9 @@ async function startBridge(options) {
2800
2822
  const bridgeEnv = {
2801
2823
  ...runtimeEnv,
2802
2824
  TAP_COMMS_DIR: commsDir,
2803
- TAP_STATE_DIR: runtimeStateDir,
2825
+ TAP_STATE_DIR: stateDir,
2826
+ TAP_RUNTIME_STATE_DIR: runtimeStateDir,
2827
+ TAP_REPO_ROOT: repoRoot,
2804
2828
  TAP_BRIDGE_RUNTIME: runtime,
2805
2829
  TAP_BRIDGE_INSTANCE_ID: instanceId,
2806
2830
  TAP_AGENT_ID: instanceId,
@@ -4354,8 +4378,24 @@ function resolveTuiConnectUrl(appServer) {
4354
4378
  function quoteCliArg(value) {
4355
4379
  return `"${value.replace(/"/g, '\\"')}"`;
4356
4380
  }
4357
- function formatCodexTuiAttachCommand(tuiConnectUrl, cwd) {
4358
- return `codex --enable tui_app_server --remote ${quoteCliArg(tuiConnectUrl)} --cd ${quoteCliArg(cwd)}`;
4381
+ function quoteShellEnvValue(value) {
4382
+ if (process.platform === "win32") {
4383
+ return `'${value.replace(/'/g, "''")}'`;
4384
+ }
4385
+ return `'${value.replace(/'/g, `'\\''`)}'`;
4386
+ }
4387
+ function formatCodexTuiAttachCommand(tuiConnectUrl, cwd, env = {}) {
4388
+ const base = `codex --enable tui_app_server --remote ${quoteCliArg(tuiConnectUrl)} --cd ${quoteCliArg(cwd)}`;
4389
+ const entries = Object.entries(env).filter(([, value]) => value.length > 0);
4390
+ if (entries.length === 0) {
4391
+ return base;
4392
+ }
4393
+ if (process.platform === "win32") {
4394
+ const envPrefix2 = entries.map(([key, value]) => `$env:${key} = ${quoteShellEnvValue(value)}`).join("; ");
4395
+ return `${envPrefix2}; ${base}`;
4396
+ }
4397
+ const envPrefix = entries.map(([key, value]) => `${key}=${quoteShellEnvValue(value)}`).join(" ");
4398
+ return `${envPrefix} ${base}`;
4359
4399
  }
4360
4400
  function resolveTuiAttachCwd(repoRoot, stateRepoRoot, runtimeThreadCwd, savedThreadCwd) {
4361
4401
  return runtimeThreadCwd ?? savedThreadCwd ?? stateRepoRoot ?? repoRoot;
@@ -5352,8 +5392,62 @@ var init_bridge_watch = __esm({
5352
5392
  }
5353
5393
  });
5354
5394
 
5355
- // src/commands/bridge-status.ts
5395
+ // src/engine/health-monitor.ts
5396
+ import * as fs26 from "fs";
5356
5397
  import * as path28 from "path";
5398
+ function getHeartbeatActivityMs2(record) {
5399
+ const timestamp = new Date(record.lastActivity ?? record.timestamp ?? 0).getTime();
5400
+ return Number.isFinite(timestamp) ? timestamp : null;
5401
+ }
5402
+ function isSameInstanceHeartbeat2(key, heartbeat, instanceId) {
5403
+ if (heartbeat.instanceId === instanceId) return true;
5404
+ if (heartbeat.connectHash === `instance:${instanceId}`) return true;
5405
+ return key === instanceId || key.replace(/_/g, "-") === instanceId || key.replace(/-/g, "_") === instanceId;
5406
+ }
5407
+ function loadLiveDispatchEvidence(commsDir, instanceId) {
5408
+ const heartbeatsPath = path28.join(commsDir, "heartbeats.json");
5409
+ if (!fs26.existsSync(heartbeatsPath)) return null;
5410
+ try {
5411
+ const store = JSON.parse(
5412
+ fs26.readFileSync(heartbeatsPath, "utf-8")
5413
+ );
5414
+ let best = null;
5415
+ let bestActivityMs = -1;
5416
+ for (const [key, heartbeat] of Object.entries(store)) {
5417
+ if (!isSameInstanceHeartbeat2(key, heartbeat, instanceId)) continue;
5418
+ if (heartbeat.source !== "bridge-dispatch") continue;
5419
+ if (heartbeat.bridgePid == null || !isProcessAlive(heartbeat.bridgePid)) {
5420
+ continue;
5421
+ }
5422
+ const activityMs = getHeartbeatActivityMs2(heartbeat);
5423
+ if (activityMs == null || Date.now() - activityMs > DISPATCH_EVIDENCE_FRESH_THRESHOLD_MS) {
5424
+ continue;
5425
+ }
5426
+ if (activityMs > bestActivityMs) {
5427
+ bestActivityMs = activityMs;
5428
+ best = {
5429
+ bridgePid: heartbeat.bridgePid,
5430
+ lastActivity: heartbeat.lastActivity ?? heartbeat.timestamp ?? new Date(activityMs).toISOString()
5431
+ };
5432
+ }
5433
+ }
5434
+ return best;
5435
+ } catch {
5436
+ return null;
5437
+ }
5438
+ }
5439
+ var DISPATCH_EVIDENCE_FRESH_THRESHOLD_MS, HEARTBEAT_FRESH_THRESHOLD_MS;
5440
+ var init_health_monitor = __esm({
5441
+ "src/engine/health-monitor.ts"() {
5442
+ "use strict";
5443
+ init_bridge_process_control();
5444
+ DISPATCH_EVIDENCE_FRESH_THRESHOLD_MS = 2 * 60 * 1e3;
5445
+ HEARTBEAT_FRESH_THRESHOLD_MS = 2 * 60 * 1e3;
5446
+ }
5447
+ });
5448
+
5449
+ // src/commands/bridge-status.ts
5450
+ import * as path29 from "path";
5357
5451
  function bridgeStatusAll() {
5358
5452
  const repoRoot = findRepoRoot();
5359
5453
  const state = loadState(repoRoot);
@@ -5402,23 +5496,26 @@ function bridgeStatusAll() {
5402
5496
  };
5403
5497
  continue;
5404
5498
  }
5405
- const status = getBridgeStatus(stateDir, instanceId);
5499
+ const rawStatus = getBridgeStatus(stateDir, instanceId);
5406
5500
  const bridgeState = loadBridgeState(stateDir, instanceId) ?? inst.bridge;
5407
- const runtimeHeartbeat = loadRuntimeBridgeHeartbeat(bridgeState);
5408
- const savedThread = loadRuntimeBridgeThreadState(bridgeState);
5409
- const lifecycle = deriveBridgeLifecycleState({
5410
- bridgeStatus: status,
5501
+ const liveDispatch = rawStatus === "running" ? null : loadLiveDispatchEvidence(state.commsDir, instanceId);
5502
+ const surfaceBridgeState = liveDispatch ? null : bridgeState;
5503
+ const runtimeHeartbeat = loadRuntimeBridgeHeartbeat(surfaceBridgeState);
5504
+ const savedThread = loadRuntimeBridgeThreadState(surfaceBridgeState);
5505
+ const status = liveDispatch ? "dispatch-live" : rawStatus;
5506
+ const lifecycle = liveDispatch ? deriveBridgeLifecycleState({ bridgeStatus: "stopped" }) : deriveBridgeLifecycleState({
5507
+ bridgeStatus: rawStatus,
5411
5508
  bridgeState,
5412
5509
  runtimeHeartbeat,
5413
5510
  savedThread,
5414
5511
  persistedLifecycle: inst.bridgeLifecycle ?? bridgeState?.lifecycle ?? null
5415
5512
  });
5416
- const session = status === "running" ? deriveCodexSessionState({
5513
+ const session = rawStatus === "running" || liveDispatch ? deriveCodexSessionState({
5417
5514
  runtimeHeartbeat,
5418
- runtimeStateDir: bridgeState?.runtimeStateDir ?? null
5515
+ runtimeStateDir: surfaceBridgeState?.runtimeStateDir ?? null
5419
5516
  }) : null;
5420
- const age = getHeartbeatAge(stateDir, instanceId);
5421
- if (lifecycle.status === "bridge-stale" && inst.bridge) {
5517
+ const age = liveDispatch ? null : getHeartbeatAge(stateDir, instanceId);
5518
+ if (rawStatus === "stale" && inst.bridge) {
5422
5519
  state.instances[instanceId] = {
5423
5520
  ...inst,
5424
5521
  bridge: null,
@@ -5430,22 +5527,22 @@ function bridgeStatusAll() {
5430
5527
  };
5431
5528
  stateChanged = true;
5432
5529
  }
5433
- const pid = bridgeState?.pid ?? null;
5434
- const heartbeat = getBridgeHeartbeatTimestamp(stateDir, instanceId);
5530
+ const pid = surfaceBridgeState?.pid ?? null;
5531
+ const heartbeat = liveDispatch ? null : getBridgeHeartbeatTimestamp(stateDir, instanceId);
5435
5532
  const pidStr = pid ? String(pid) : "-";
5436
5533
  const portStr = inst.port ? String(inst.port) : "-";
5437
5534
  const ageStr = age !== null ? formatAge(age) : "-";
5438
5535
  log(
5439
5536
  `${instanceId.padEnd(20)} ${inst.runtime.padEnd(8)} ${status.padEnd(10)} ${lifecycle.status.padEnd(20)} ${(session?.status ?? "-").padEnd(18)} ${pidStr.padEnd(8)} ${portStr.padEnd(6)} ${ageStr}`
5440
5537
  );
5441
- if (bridgeState?.appServer) {
5442
- log(` App server: ${formatAppServerState(bridgeState.appServer)}`);
5443
- if (bridgeState.appServer.logPath) {
5444
- log(` Server log: ${bridgeState.appServer.logPath}`);
5538
+ if (surfaceBridgeState?.appServer) {
5539
+ log(` App server: ${formatAppServerState(surfaceBridgeState.appServer)}`);
5540
+ if (surfaceBridgeState.appServer.logPath) {
5541
+ log(` Server log: ${surfaceBridgeState.appServer.logPath}`);
5445
5542
  }
5446
- if (bridgeState.appServer.auth) {
5543
+ if (surfaceBridgeState.appServer.auth) {
5447
5544
  log(
5448
- ` Protected: ${redactProtectedUrl(bridgeState.appServer.auth.protectedUrl)}`
5545
+ ` Protected: ${redactProtectedUrl(surfaceBridgeState.appServer.auth.protectedUrl)}`
5449
5546
  );
5450
5547
  }
5451
5548
  }
@@ -5463,6 +5560,11 @@ function bridgeStatusAll() {
5463
5560
  if (transition) {
5464
5561
  log(` Transition: ${transition}`);
5465
5562
  }
5563
+ if (liveDispatch) {
5564
+ log(
5565
+ ` Drift: fresh bridge-dispatch heartbeat from PID ${liveDispatch.bridgePid} without bridge pid state`
5566
+ );
5567
+ }
5466
5568
  const turnInfo = getTurnInfo(stateDir, instanceId);
5467
5569
  if (turnInfo?.activeTurnId) {
5468
5570
  const ageStr2 = turnInfo.ageSeconds != null ? formatAge(turnInfo.ageSeconds) : "?";
@@ -5488,7 +5590,7 @@ function bridgeStatusAll() {
5488
5590
  threadCwd: runtimeHeartbeat?.threadCwd ?? null,
5489
5591
  savedThreadId: savedThread?.threadId ?? null,
5490
5592
  savedThreadCwd: savedThread?.cwd ?? null,
5491
- appServer: bridgeState?.appServer ?? null
5593
+ appServer: surfaceBridgeState?.appServer ?? null
5492
5594
  };
5493
5595
  }
5494
5596
  if (instanceIds.length === 0) {
@@ -5585,14 +5687,17 @@ function bridgeStatusOne(identifier) {
5585
5687
  }
5586
5688
  const { config: resolvedCfg2 } = resolveConfig({}, repoRoot);
5587
5689
  const stateDir = resolvedCfg2.stateDir;
5588
- const status = getBridgeStatus(stateDir, instanceId);
5690
+ const rawStatus = getBridgeStatus(stateDir, instanceId);
5589
5691
  const bridgeState = loadBridgeState(stateDir, instanceId) ?? inst.bridge;
5590
- const runtimeHeartbeat = loadRuntimeBridgeHeartbeat(bridgeState);
5591
- const savedThread = loadRuntimeBridgeThreadState(bridgeState);
5592
- const age = getHeartbeatAge(stateDir, instanceId);
5593
- const heartbeat = getBridgeHeartbeatTimestamp(stateDir, instanceId);
5594
- const lifecycle = deriveBridgeLifecycleState({
5595
- bridgeStatus: status,
5692
+ const liveDispatch = rawStatus === "running" ? null : loadLiveDispatchEvidence(state.commsDir, instanceId);
5693
+ const surfaceBridgeState = liveDispatch ? null : bridgeState;
5694
+ const runtimeHeartbeat = loadRuntimeBridgeHeartbeat(surfaceBridgeState);
5695
+ const savedThread = loadRuntimeBridgeThreadState(surfaceBridgeState);
5696
+ const age = liveDispatch ? null : getHeartbeatAge(stateDir, instanceId);
5697
+ const heartbeat = liveDispatch ? null : getBridgeHeartbeatTimestamp(stateDir, instanceId);
5698
+ const status = liveDispatch ? "dispatch-live" : rawStatus;
5699
+ const lifecycle = liveDispatch ? deriveBridgeLifecycleState({ bridgeStatus: "stopped" }) : deriveBridgeLifecycleState({
5700
+ bridgeStatus: rawStatus,
5596
5701
  bridgeState,
5597
5702
  runtimeHeartbeat,
5598
5703
  savedThread,
@@ -5600,13 +5705,25 @@ function bridgeStatusOne(identifier) {
5600
5705
  });
5601
5706
  const session = deriveCodexSessionState({
5602
5707
  runtimeHeartbeat,
5603
- runtimeStateDir: bridgeState?.runtimeStateDir ?? null
5708
+ runtimeStateDir: surfaceBridgeState?.runtimeStateDir ?? null
5604
5709
  });
5605
5710
  log(`Status: ${status}`);
5606
5711
  log(`Lifecycle: ${lifecycle.summary}`);
5607
5712
  log(`Session: ${session.summary}`);
5608
- if (bridgeState) {
5609
- log(`PID: ${bridgeState.pid}`);
5713
+ if (rawStatus === "stale" && inst.bridge) {
5714
+ state.instances[instanceId] = {
5715
+ ...inst,
5716
+ bridge: null,
5717
+ bridgeLifecycle: transitionBridgeLifecycle(
5718
+ inst.bridgeLifecycle ?? inst.bridge?.lifecycle ?? null,
5719
+ "crashed",
5720
+ "bridge pid not alive"
5721
+ )
5722
+ };
5723
+ saveState(repoRoot, state);
5724
+ }
5725
+ if (surfaceBridgeState) {
5726
+ log(`PID: ${surfaceBridgeState.pid}`);
5610
5727
  log(
5611
5728
  `Heartbeat: ${heartbeat ?? "-"}${age !== null ? ` (${formatAge(age)})` : ""}`
5612
5729
  );
@@ -5621,35 +5738,35 @@ function bridgeStatusOne(identifier) {
5621
5738
  );
5622
5739
  }
5623
5740
  log(
5624
- `Log: ${path28.join(stateDir, "logs", `bridge-${instanceId}.log`)}`
5741
+ `Log: ${path29.join(stateDir, "logs", `bridge-${instanceId}.log`)}`
5625
5742
  );
5626
- if (bridgeState.appServer) {
5627
- log(`App server: ${bridgeState.appServer.url}`);
5628
- log(`Server PID: ${bridgeState.appServer.pid ?? "-"}`);
5743
+ if (surfaceBridgeState.appServer) {
5744
+ log(`App server: ${surfaceBridgeState.appServer.url}`);
5745
+ log(`Server PID: ${surfaceBridgeState.appServer.pid ?? "-"}`);
5629
5746
  log(
5630
- `Server mode: ${bridgeState.appServer.managed ? "managed" : "external"}`
5747
+ `Server mode: ${surfaceBridgeState.appServer.managed ? "managed" : "external"}`
5631
5748
  );
5632
5749
  log(
5633
- `Health: ${bridgeState.appServer.healthy ? "healthy" : "unhealthy"}`
5750
+ `Health: ${surfaceBridgeState.appServer.healthy ? "healthy" : "unhealthy"}`
5634
5751
  );
5635
- log(`Checked: ${bridgeState.appServer.lastCheckedAt}`);
5636
- if (bridgeState.appServer.logPath) {
5637
- log(`Server log: ${bridgeState.appServer.logPath}`);
5752
+ log(`Checked: ${surfaceBridgeState.appServer.lastCheckedAt}`);
5753
+ if (surfaceBridgeState.appServer.logPath) {
5754
+ log(`Server log: ${surfaceBridgeState.appServer.logPath}`);
5638
5755
  }
5639
- if (bridgeState.appServer.auth) {
5640
- log(`Auth: ${bridgeState.appServer.auth.mode}`);
5756
+ if (surfaceBridgeState.appServer.auth) {
5757
+ log(`Auth: ${surfaceBridgeState.appServer.auth.mode}`);
5641
5758
  log(
5642
- `Protected: ${redactProtectedUrl(bridgeState.appServer.auth.protectedUrl)}`
5759
+ `Protected: ${redactProtectedUrl(surfaceBridgeState.appServer.auth.protectedUrl)}`
5643
5760
  );
5644
- log(`Upstream: ${bridgeState.appServer.auth.upstreamUrl}`);
5645
- log(`TUI connect: ${bridgeState.appServer.auth.upstreamUrl}`);
5646
- log(`Gateway PID: ${bridgeState.appServer.auth.gatewayPid ?? "-"}`);
5647
- if (bridgeState.appServer.auth.gatewayLogPath) {
5648
- log(`Gateway log: ${bridgeState.appServer.auth.gatewayLogPath}`);
5761
+ log(`Upstream: ${surfaceBridgeState.appServer.auth.upstreamUrl}`);
5762
+ log(`TUI connect: ${surfaceBridgeState.appServer.auth.upstreamUrl}`);
5763
+ log(`Gateway PID: ${surfaceBridgeState.appServer.auth.gatewayPid ?? "-"}`);
5764
+ if (surfaceBridgeState.appServer.auth.gatewayLogPath) {
5765
+ log(`Gateway log: ${surfaceBridgeState.appServer.auth.gatewayLogPath}`);
5649
5766
  }
5650
- } else if (bridgeState.appServer.managed) {
5767
+ } else if (surfaceBridgeState.appServer.managed) {
5651
5768
  log(`Auth: none (--no-auth)`);
5652
- log(`TUI connect: ${bridgeState.appServer.url}`);
5769
+ log(`TUI connect: ${surfaceBridgeState.appServer.url}`);
5653
5770
  }
5654
5771
  }
5655
5772
  }
@@ -5657,6 +5774,11 @@ function bridgeStatusOne(identifier) {
5657
5774
  if (transition) {
5658
5775
  log(`Transition: ${transition}`);
5659
5776
  }
5777
+ if (liveDispatch) {
5778
+ log(
5779
+ `Drift: fresh bridge-dispatch heartbeat from PID ${liveDispatch.bridgePid} without bridge pid state`
5780
+ );
5781
+ }
5660
5782
  log("");
5661
5783
  return {
5662
5784
  ok: true,
@@ -5686,14 +5808,14 @@ function bridgeStatusOne(identifier) {
5686
5808
  lastDispatchAt: session.lastDispatchAt
5687
5809
  },
5688
5810
  bridgeMode: inst.bridgeMode,
5689
- pid: bridgeState?.pid ?? null,
5811
+ pid: surfaceBridgeState?.pid ?? null,
5690
5812
  port: inst.port,
5691
5813
  lastHeartbeat: heartbeat,
5692
5814
  threadId: runtimeHeartbeat?.threadId ?? null,
5693
5815
  threadCwd: runtimeHeartbeat?.threadCwd ?? null,
5694
5816
  savedThreadId: savedThread?.threadId ?? null,
5695
5817
  savedThreadCwd: savedThread?.cwd ?? null,
5696
- appServer: bridgeState?.appServer ?? null
5818
+ appServer: surfaceBridgeState?.appServer ?? null
5697
5819
  }
5698
5820
  };
5699
5821
  }
@@ -5702,6 +5824,7 @@ var init_bridge_status = __esm({
5702
5824
  "use strict";
5703
5825
  init_state();
5704
5826
  init_bridge();
5827
+ init_health_monitor();
5705
5828
  init_config();
5706
5829
  init_utils();
5707
5830
  init_bridge_helpers();
@@ -5796,7 +5919,23 @@ function bridgeTuiOne(identifier) {
5796
5919
  runtimeHeartbeat?.threadCwd,
5797
5920
  savedThread?.cwd
5798
5921
  );
5799
- const attachCommand = formatCodexTuiAttachCommand(tuiConnectUrl, attachCwd);
5922
+ const attachEnv = {
5923
+ TAP_BRIDGE_INSTANCE_ID: instanceId,
5924
+ TAP_AGENT_ID: instanceId,
5925
+ TAP_COMMS_DIR: resolvedConfig.commsDir,
5926
+ TAP_STATE_DIR: stateDir,
5927
+ TAP_RUNTIME_STATE_DIR: bridgeState?.runtimeStateDir ?? getBridgeRuntimeStateDir(repoRoot, instanceId),
5928
+ TAP_REPO_ROOT: repoRoot
5929
+ };
5930
+ if (typeof inst.agentName === "string" && inst.agentName.trim()) {
5931
+ attachEnv.TAP_AGENT_NAME = inst.agentName;
5932
+ attachEnv.CODEX_TAP_AGENT_NAME = inst.agentName;
5933
+ }
5934
+ const attachCommand = formatCodexTuiAttachCommand(
5935
+ tuiConnectUrl,
5936
+ attachCwd,
5937
+ attachEnv
5938
+ );
5800
5939
  const warnings = appServer.auth != null ? [
5801
5940
  "Use the upstream TUI URL, not the protected gateway URL. The protected URL is bridge-only."
5802
5941
  ] : [];
@@ -5821,6 +5960,7 @@ function bridgeTuiOne(identifier) {
5821
5960
  tuiConnectUrl,
5822
5961
  attachCwd,
5823
5962
  attachCommand,
5963
+ attachEnv,
5824
5964
  appServer
5825
5965
  }
5826
5966
  };
@@ -6856,8 +6996,8 @@ init_dashboard();
6856
6996
  init_utils();
6857
6997
  init_config();
6858
6998
  init_state();
6859
- import * as fs26 from "fs";
6860
- import * as path29 from "path";
6999
+ import * as fs27 from "fs";
7000
+ import * as path30 from "path";
6861
7001
  function getDashboardSnapshot(options) {
6862
7002
  const repoRoot = options?.repoRoot ?? findRepoRoot();
6863
7003
  return collectDashboardSnapshot(repoRoot, options?.commsDir);
@@ -6919,9 +7059,9 @@ function getHealthReport(options) {
6919
7059
  }
6920
7060
  }
6921
7061
  }
6922
- const tmpDir = path29.join(repoRoot, ".tmp");
6923
- if (fs26.existsSync(tmpDir)) {
6924
- for (const dir of fs26.readdirSync(tmpDir)) {
7062
+ const tmpDir = path30.join(repoRoot, ".tmp");
7063
+ if (fs27.existsSync(tmpDir)) {
7064
+ for (const dir of fs27.readdirSync(tmpDir)) {
6925
7065
  if (!dir.startsWith("codex-app-server-bridge")) continue;
6926
7066
  const suffix = dir.replace("codex-app-server-bridge-", "");
6927
7067
  if (activeMatchers.size > 0) {
@@ -6934,10 +7074,10 @@ function getHealthReport(options) {
6934
7074
  }
6935
7075
  if (!matched) continue;
6936
7076
  }
6937
- const hsPath = path29.join(tmpDir, dir, "headless-state.json");
6938
- if (!fs26.existsSync(hsPath)) continue;
7077
+ const hsPath = path30.join(tmpDir, dir, "headless-state.json");
7078
+ if (!fs27.existsSync(hsPath)) continue;
6939
7079
  try {
6940
- const hs = JSON.parse(fs26.readFileSync(hsPath, "utf-8"));
7080
+ const hs = JSON.parse(fs27.readFileSync(hsPath, "utf-8"));
6941
7081
  headlessStates.push({ instanceDir: dir, ...hs });
6942
7082
  } catch {
6943
7083
  }