@buildautomaton/cli 0.1.78 → 0.1.80

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.js CHANGED
@@ -3691,7 +3691,7 @@ var require_tree_kill = __commonJS({
3691
3691
  "../../node_modules/.pnpm/tree-kill@1.2.2/node_modules/tree-kill/index.js"(exports, module) {
3692
3692
  "use strict";
3693
3693
  var childProcess2 = __require("child_process");
3694
- var spawn11 = childProcess2.spawn;
3694
+ var spawn12 = childProcess2.spawn;
3695
3695
  var exec = childProcess2.exec;
3696
3696
  module.exports = function(pid, signal, callback) {
3697
3697
  if (typeof signal === "function" && callback === void 0) {
@@ -3716,7 +3716,7 @@ var require_tree_kill = __commonJS({
3716
3716
  break;
3717
3717
  case "darwin":
3718
3718
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
3719
- return spawn11("pgrep", ["-P", parentPid]);
3719
+ return spawn12("pgrep", ["-P", parentPid]);
3720
3720
  }, function() {
3721
3721
  killAll(tree, signal, callback);
3722
3722
  });
@@ -3728,7 +3728,7 @@ var require_tree_kill = __commonJS({
3728
3728
  // break;
3729
3729
  default:
3730
3730
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
3731
- return spawn11("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
3731
+ return spawn12("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
3732
3732
  }, function() {
3733
3733
  killAll(tree, signal, callback);
3734
3734
  });
@@ -21909,31 +21909,31 @@ function handleWorkerOutMessage(message) {
21909
21909
  return;
21910
21910
  }
21911
21911
  if (message.type === "error") {
21912
- const pending2 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
21912
+ const pending3 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
21913
21913
  maybeLogCodeNavCacheWorkerError(message.message);
21914
- if (pending2 != null) {
21914
+ if (pending3 != null) {
21915
21915
  pendingRequests.delete(message.requestId);
21916
21916
  if (isCliImmediateShutdownRequested()) {
21917
- pending2.reject(new CliSqliteInterrupted());
21917
+ pending3.reject(new CliSqliteInterrupted());
21918
21918
  } else {
21919
- pending2.reject(new Error(message.message));
21919
+ pending3.reject(new Error(message.message));
21920
21920
  }
21921
21921
  }
21922
21922
  return;
21923
21923
  }
21924
21924
  if (!("requestId" in message)) return;
21925
- const pending = pendingRequests.get(message.requestId);
21926
- if (pending == null) return;
21925
+ const pending2 = pendingRequests.get(message.requestId);
21926
+ if (pending2 == null) return;
21927
21927
  pendingRequests.delete(message.requestId);
21928
- pending.resolve(message);
21928
+ pending2.resolve(message);
21929
21929
  }
21930
21930
  function resetWorkerReadyState() {
21931
21931
  workerReady = false;
21932
21932
  workerReadyWaiters = [];
21933
21933
  }
21934
21934
  function rejectAllPendingRequests(error40) {
21935
- for (const [, pending] of pendingRequests) {
21936
- pending.reject(error40);
21935
+ for (const [, pending2] of pendingRequests) {
21936
+ pending2.reject(error40);
21937
21937
  }
21938
21938
  pendingRequests.clear();
21939
21939
  }
@@ -22966,14 +22966,14 @@ function legacyCliDiskMigrationIsPending() {
22966
22966
  return false;
22967
22967
  }
22968
22968
  function importCliSqliteLegacyDiskData(db, log2) {
22969
- const pending = legacyCliDiskMigrationIsPending();
22970
- if (pending && log2) {
22969
+ const pending2 = legacyCliDiskMigrationIsPending();
22970
+ if (pending2 && log2) {
22971
22971
  log2("Migrating legacy on-disk CLI data to SQLite\u2026");
22972
22972
  }
22973
22973
  archiveLegacyFileIndexJsonFiles();
22974
22974
  importLegacyAgentSessionsFromDisk(db);
22975
22975
  importLegacyPromptQueuesFromDisk(db);
22976
- if (pending && log2) {
22976
+ if (pending2 && log2) {
22977
22977
  log2("Legacy on-disk CLI data migration finished.");
22978
22978
  }
22979
22979
  }
@@ -27169,6 +27169,16 @@ async function awaitSymbolIndexWorkerShutdown() {
27169
27169
  await terminateSymbolIndexWorker2();
27170
27170
  }
27171
27171
  }
27172
+ async function clearCliImmediateShutdown() {
27173
+ if (symbolIndexShutdownPromise != null) {
27174
+ try {
27175
+ await symbolIndexShutdownPromise;
27176
+ } catch {
27177
+ }
27178
+ }
27179
+ cliImmediateShutdownRequested = false;
27180
+ symbolIndexShutdownPromise = null;
27181
+ }
27172
27182
  function resetCliImmediateShutdownForTests() {
27173
27183
  cliImmediateShutdownRequested = false;
27174
27184
  symbolIndexShutdownPromise = null;
@@ -28122,6 +28132,29 @@ function safeSendWebSocketBinary(ws, data) {
28122
28132
  }
28123
28133
  }
28124
28134
 
28135
+ // src/connection/create-ws-bridge-options.ts
28136
+ var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
28137
+ var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
28138
+
28139
+ // src/connection/dispatch-ws-inbound-message.ts
28140
+ function dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket) {
28141
+ if (isActiveSocket && !isActiveSocket(ws)) return;
28142
+ try {
28143
+ let data;
28144
+ if (typeof raw === "string") {
28145
+ data = JSON.parse(raw);
28146
+ } else if (Buffer.isBuffer(raw) || raw instanceof ArrayBuffer) {
28147
+ const str = Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
28148
+ data = JSON.parse(str);
28149
+ } else {
28150
+ data = raw;
28151
+ }
28152
+ onMessage?.(data, ws);
28153
+ } catch {
28154
+ onMessage?.(raw, ws);
28155
+ }
28156
+ }
28157
+
28125
28158
  // src/connection/parse-compact-heartbeat-ack.ts
28126
28159
  function tryParseCompactHeartbeatAck(raw) {
28127
28160
  let str = null;
@@ -28149,8 +28182,6 @@ function tryParseCompactHeartbeatAck(raw) {
28149
28182
  }
28150
28183
 
28151
28184
  // src/connection/create-ws-bridge.ts
28152
- var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
28153
- var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
28154
28185
  function createWsBridge(options) {
28155
28186
  const {
28156
28187
  url: url2,
@@ -28161,15 +28192,16 @@ function createWsBridge(options) {
28161
28192
  onAuthInvalid,
28162
28193
  clientPingIntervalMs,
28163
28194
  onCompactHeartbeatAck,
28164
- isActiveSocket
28195
+ isActiveSocket,
28196
+ deferInboundMessages = true
28165
28197
  } = options;
28166
28198
  const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
28167
28199
  let clearClientPing = null;
28168
- function disposeClientPing() {
28200
+ const disposeClientPing = () => {
28169
28201
  clearClientPing?.();
28170
28202
  clearClientPing = null;
28171
- }
28172
- ws.on("unexpected-response", (request, response) => {
28203
+ };
28204
+ ws.on("unexpected-response", (_request, response) => {
28173
28205
  const status = response?.statusCode ?? 0;
28174
28206
  const headers = response?.headers ?? {};
28175
28207
  const errCode = (headers[BRIDGE_AUTH_ERROR_HEADER] ?? headers["X-Bridge-Auth-Error"] ?? "").toLowerCase();
@@ -28190,23 +28222,11 @@ function createWsBridge(options) {
28190
28222
  onCompactHeartbeatAck?.(ackSeq);
28191
28223
  return;
28192
28224
  }
28193
- setImmediate(() => {
28194
- if (isActiveSocket && !isActiveSocket(ws)) return;
28195
- try {
28196
- let data;
28197
- if (typeof raw === "string") {
28198
- data = JSON.parse(raw);
28199
- } else if (Buffer.isBuffer(raw) || raw instanceof ArrayBuffer) {
28200
- const str = Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
28201
- data = JSON.parse(str);
28202
- } else {
28203
- data = raw;
28204
- }
28205
- onMessage?.(data, ws);
28206
- } catch {
28207
- onMessage?.(raw, ws);
28208
- }
28209
- });
28225
+ if (deferInboundMessages) {
28226
+ setImmediate(() => dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket));
28227
+ return;
28228
+ }
28229
+ dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket);
28210
28230
  });
28211
28231
  ws.on("close", (code, reason) => {
28212
28232
  disposeClientPing();
@@ -28219,9 +28239,9 @@ function createWsBridge(options) {
28219
28239
  return ws;
28220
28240
  }
28221
28241
  function sendWsMessage(ws, payload) {
28222
- if (ws.readyState === wrapper_default.OPEN) {
28223
- ws.send(JSON.stringify(payload));
28224
- }
28242
+ if (ws.readyState !== wrapper_default.OPEN) return false;
28243
+ ws.send(JSON.stringify(payload));
28244
+ return true;
28225
28245
  }
28226
28246
 
28227
28247
  // src/files/cwd/index.ts
@@ -29352,6 +29372,31 @@ function getAgentModelFromAgentConfig(config2) {
29352
29372
  var HOUR_MS = 36e5;
29353
29373
  var DAY_MS = 24 * HOUR_MS;
29354
29374
 
29375
+ // ../types/src/hosts/skus.ts
29376
+ function defineHostSku(params) {
29377
+ return structuredClone(params);
29378
+ }
29379
+ var FLY_LEGACY_HOST_SKU = defineHostSku({
29380
+ id: "fly-shared-1x512-1gb",
29381
+ provider: "fly",
29382
+ compute: { cpus: 1, cpuKind: "shared" },
29383
+ memory: { memoryMb: 512 },
29384
+ storage: { storageGb: 1 },
29385
+ monthlyPriceCents: 750
29386
+ });
29387
+ var FLY_DEFAULT_HOST_SKU = defineHostSku({
29388
+ id: "fly-shared-1x1024-1gb",
29389
+ provider: "fly",
29390
+ compute: { cpus: 1, cpuKind: "shared" },
29391
+ memory: { memoryMb: 1024 },
29392
+ storage: { storageGb: 1 },
29393
+ monthlyPriceCents: 1e3
29394
+ });
29395
+ var HOST_SKUS_BY_ID = {
29396
+ [FLY_LEGACY_HOST_SKU.id]: FLY_LEGACY_HOST_SKU,
29397
+ [FLY_DEFAULT_HOST_SKU.id]: FLY_DEFAULT_HOST_SKU
29398
+ };
29399
+
29355
29400
  // ../types/src/bridges/agents/types.ts
29356
29401
  var INSTALLABLE_BRIDGE_AGENTS = [
29357
29402
  { value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
@@ -29465,11 +29510,11 @@ function createSdkStdioExtNotificationHandler(options) {
29465
29510
 
29466
29511
  // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
29467
29512
  function awaitSdkStdioPermissionRequestHandshake(params) {
29468
- const { requestId, paramsRecord, pending, onRequest } = params;
29513
+ const { requestId, paramsRecord, pending: pending2, onRequest } = params;
29469
29514
  return new Promise((resolve35) => {
29470
- pending.set(requestId, { resolve: resolve35, params: paramsRecord });
29515
+ pending2.set(requestId, { resolve: resolve35, params: paramsRecord });
29471
29516
  if (onRequest == null) {
29472
- pending.delete(requestId);
29517
+ pending2.delete(requestId);
29473
29518
  resolve35({ outcome: { outcome: "denied" } });
29474
29519
  return;
29475
29520
  }
@@ -29485,9 +29530,9 @@ function awaitSdkStdioPermissionRequestHandshake(params) {
29485
29530
  }
29486
29531
 
29487
29532
  // src/agents/acp/clients/sdk/sdk-stdio-permission-pending.ts
29488
- function resolvePendingSdkStdioPermissionCancellations(pending) {
29489
- for (const [id, entry] of [...pending.entries()]) {
29490
- pending.delete(id);
29533
+ function resolvePendingSdkStdioPermissionCancellations(pending2) {
29534
+ for (const [id, entry] of [...pending2.entries()]) {
29535
+ pending2.delete(id);
29491
29536
  entry.resolve({ outcome: { outcome: "cancelled" } });
29492
29537
  }
29493
29538
  }
@@ -30612,14 +30657,8 @@ function installBridgeProcessResilience() {
30612
30657
  });
30613
30658
  }
30614
30659
 
30615
- // src/cli-version.ts
30616
- var CLI_VERSION = "0.1.78".length > 0 ? "0.1.78" : "0.0.0-dev";
30617
-
30618
- // src/connection/heartbeat/constants.ts
30619
- var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
30620
- var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
30621
- var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
30622
- var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
30660
+ // src/auth/pending/run-pending-auth.ts
30661
+ init_log();
30623
30662
 
30624
30663
  // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
30625
30664
  import process7 from "node:process";
@@ -31174,8 +31213,16 @@ async function openBrowser(connectionId, initialWorkspaceId, preferredBridgeName
31174
31213
  }
31175
31214
  }
31176
31215
 
31177
- // src/auth/run-pending-auth.ts
31178
- init_log();
31216
+ // src/auth/pending/constants.ts
31217
+ var PENDING_KEEPALIVE_MS = 25e3;
31218
+ var BROWSER_OPEN_FALLBACK_MS = 4e3;
31219
+
31220
+ // src/auth/pending/build-pending-bridge-url.ts
31221
+ function buildPendingBridgeUrl(apiUrl, connectionId) {
31222
+ const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
31223
+ const params = new URLSearchParams({ connectionId });
31224
+ return `${base}/ws/bridge/pending?${params.toString()}`;
31225
+ }
31179
31226
 
31180
31227
  // src/connection/reconnect/constants.ts
31181
31228
  var RECONNECT_QUIET_MS = 2e3;
@@ -31506,6 +31553,12 @@ function scheduleMainBridgeReconnect(state, connect, log2, closeMeta) {
31506
31553
  });
31507
31554
  }
31508
31555
 
31556
+ // src/connection/heartbeat/constants.ts
31557
+ var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
31558
+ var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
31559
+ var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
31560
+ var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
31561
+
31509
31562
  // src/connection/reconnect/duplicate-bridge-connection-detect.ts
31510
31563
  var BRIDGE_SUPERSEDED_CLOSE_REASON_SNIPPET = "superseded";
31511
31564
  var DUPLICATE_BRIDGE_SHORT_SESSION_MS = 25e3;
@@ -31590,145 +31643,180 @@ function clearFirehoseReconnectQuietOnOpen(ctx, log2) {
31590
31643
  });
31591
31644
  }
31592
31645
 
31593
- // src/auth/run-pending-auth.ts
31594
- var PENDING_KEEPALIVE_MS = 25e3;
31595
- var BROWSER_OPEN_FALLBACK_MS = 4e3;
31596
- function buildPendingBridgeUrl(apiUrl, connectionId) {
31597
- const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
31598
- const params = new URLSearchParams({ connectionId });
31599
- return `${base}/ws/bridge/pending?${params.toString()}`;
31600
- }
31601
- function runPendingAuth(options) {
31602
- const { apiUrl, initialWorkspaceId, preferredBridgeName, onAuth } = options;
31603
- const logFn = options.log ?? log;
31604
- let ws = null;
31605
- let reconnectTimeout = null;
31606
- let keepaliveInterval = null;
31607
- let browserFallback = null;
31608
- const connectionId = crypto.randomUUID();
31609
- let hasOpenedBrowser = false;
31610
- let resolved = false;
31611
- let resolveAuth;
31612
- const authPromise = new Promise((resolve35) => {
31613
- resolveAuth = resolve35;
31614
- });
31615
- let reconnectAttempt = 0;
31616
- const signInQuiet = createEmptyReconnectQuietSlot();
31617
- function clearQuietOnOpen() {
31618
- clearReconnectQuietOnSuccessfulConnection(
31619
- signInQuiet,
31620
- logFn,
31621
- "[Bridge service] Sign-in connection restored."
31622
- );
31623
- reconnectAttempt = 0;
31624
- }
31625
- function beginDeferredPendingCloseLog(code, reason) {
31646
+ // src/auth/pending/pending-auth-on-close.ts
31647
+ function createPendingAuthOnClose(params) {
31648
+ const { session, log: log2, connect } = params;
31649
+ return (code, reason) => {
31650
+ if (session.keepaliveInterval) {
31651
+ clearInterval(session.keepaliveInterval);
31652
+ session.keepaliveInterval = null;
31653
+ }
31654
+ if (session.resolved) return;
31626
31655
  beginDeferredDisconnectForReconnect({
31627
- isClosedByUser: () => resolved,
31628
- quiet: signInQuiet,
31656
+ isClosedByUser: () => session.resolved,
31657
+ quiet: session.signInQuiet,
31629
31658
  code,
31630
31659
  reason,
31631
31660
  willReconnect: true,
31632
- log: logFn,
31661
+ log: log2,
31633
31662
  serviceLabel: "[Bridge service]",
31634
31663
  shutdownDetail: "Not reconnecting (shutting down).",
31635
31664
  reconnectingDetail: "Waiting for browser sign-in; reconnecting\u2026",
31636
- shouldAbortQuietWindow: () => ws != null && ws.readyState === wrapper_default.OPEN
31665
+ shouldAbortQuietWindow: () => session.ws != null && session.ws.readyState === wrapper_default.OPEN
31637
31666
  });
31638
- }
31639
- function cleanup() {
31640
- clearReconnectQuietTimer(signInQuiet);
31641
- if (reconnectTimeout) {
31642
- clearTimeout(reconnectTimeout);
31643
- reconnectTimeout = null;
31644
- }
31645
- if (browserFallback) {
31646
- clearTimeout(browserFallback);
31647
- browserFallback = null;
31648
- }
31649
- if (keepaliveInterval) {
31650
- clearInterval(keepaliveInterval);
31651
- keepaliveInterval = null;
31652
- }
31653
- if (ws) {
31654
- const w = ws;
31655
- ws = null;
31656
- safeCloseWebSocket(w);
31667
+ const delay4 = pendingAuthReconnectDelayMs(session.reconnectAttempt);
31668
+ session.reconnectAttempt += 1;
31669
+ if (session.signInQuiet.verboseLogs) {
31670
+ const delayLabel = formatReconnectDelayForLog(delay4);
31671
+ log2(
31672
+ `[Bridge service] Next sign-in connection attempt in ${delayLabel} (attempt ${session.reconnectAttempt}).`
31673
+ );
31657
31674
  }
31675
+ session.reconnectTimeout = setTimeout(() => {
31676
+ session.reconnectTimeout = null;
31677
+ connect();
31678
+ }, delay4);
31679
+ };
31680
+ }
31681
+
31682
+ // src/auth/pending/pending-auth-session.ts
31683
+ function createPendingAuthSession() {
31684
+ let resolveAuth;
31685
+ const authPromise = new Promise((resolve35) => {
31686
+ resolveAuth = resolve35;
31687
+ });
31688
+ return {
31689
+ ws: null,
31690
+ reconnectTimeout: null,
31691
+ keepaliveInterval: null,
31692
+ browserFallback: null,
31693
+ connectionId: crypto.randomUUID(),
31694
+ hasOpenedBrowser: false,
31695
+ resolved: false,
31696
+ resolveAuth,
31697
+ reconnectAttempt: 0,
31698
+ signInQuiet: createEmptyReconnectQuietSlot(),
31699
+ authPromise
31700
+ };
31701
+ }
31702
+ function cleanupPendingAuthSession(session) {
31703
+ clearReconnectQuietTimer(session.signInQuiet);
31704
+ if (session.reconnectTimeout) {
31705
+ clearTimeout(session.reconnectTimeout);
31706
+ session.reconnectTimeout = null;
31658
31707
  }
31659
- function connect() {
31660
- const url2 = buildPendingBridgeUrl(apiUrl, connectionId);
31661
- let pendingHbSeq = -1;
31662
- ws = createWsBridge({
31663
- url: url2,
31664
- onOpen: () => {
31665
- clearQuietOnOpen();
31666
- pendingHbSeq = -1;
31667
- sendWsMessage(ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
31668
- keepaliveInterval = setInterval(() => {
31669
- if (resolved || !ws || ws.readyState !== 1) return;
31670
- pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
31671
- const hb = { t: "h", s: pendingHbSeq };
31672
- sendWsMessage(ws, hb);
31673
- }, PENDING_KEEPALIVE_MS);
31674
- if (browserFallback) {
31675
- clearTimeout(browserFallback);
31676
- browserFallback = null;
31677
- }
31678
- if (!hasOpenedBrowser) {
31679
- hasOpenedBrowser = true;
31680
- void openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
31681
- }
31682
- },
31683
- onClose: (code, reason) => {
31684
- if (keepaliveInterval) {
31685
- clearInterval(keepaliveInterval);
31686
- keepaliveInterval = null;
31687
- }
31688
- if (resolved) return;
31689
- beginDeferredPendingCloseLog(code, reason);
31690
- const delay4 = pendingAuthReconnectDelayMs(reconnectAttempt);
31691
- reconnectAttempt += 1;
31692
- if (signInQuiet.verboseLogs) {
31693
- const delayLabel = formatReconnectDelayForLog(delay4);
31694
- logFn(
31695
- `[Bridge service] Next sign-in connection attempt in ${delayLabel} (attempt ${reconnectAttempt}).`
31696
- );
31697
- }
31698
- reconnectTimeout = setTimeout(() => {
31699
- reconnectTimeout = null;
31700
- connect();
31701
- }, delay4);
31702
- },
31703
- onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
31704
- onMessage: (data) => {
31705
- const msg = data;
31706
- if (msg.type === "auth_token" && typeof msg.token === "string") {
31707
- resolved = true;
31708
- const workspaceId = typeof msg.workspaceId === "string" ? msg.workspaceId : "";
31709
- cleanup();
31710
- const refreshToken = typeof msg.refreshToken === "string" ? msg.refreshToken : void 0;
31711
- const result = { workspaceId, token: msg.token, refreshToken };
31712
- resolveAuth(result);
31713
- onAuth(result);
31714
- }
31715
- }
31716
- });
31708
+ if (session.browserFallback) {
31709
+ clearTimeout(session.browserFallback);
31710
+ session.browserFallback = null;
31711
+ }
31712
+ if (session.keepaliveInterval) {
31713
+ clearInterval(session.keepaliveInterval);
31714
+ session.keepaliveInterval = null;
31715
+ }
31716
+ if (session.ws) {
31717
+ const w = session.ws;
31718
+ session.ws = null;
31719
+ safeCloseWebSocket(w);
31717
31720
  }
31718
- browserFallback = setTimeout(() => {
31719
- browserFallback = null;
31720
- if (!hasOpenedBrowser) {
31721
- hasOpenedBrowser = true;
31722
- void openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
31721
+ }
31722
+
31723
+ // src/auth/pending/pending-auth-on-message.ts
31724
+ function createPendingAuthOnMessage(params) {
31725
+ const { session, onAuth } = params;
31726
+ return (data) => {
31727
+ const msg = data;
31728
+ if (msg.type !== "auth_token" || typeof msg.token !== "string") return;
31729
+ session.resolved = true;
31730
+ const workspaceId = typeof msg.workspaceId === "string" ? msg.workspaceId : "";
31731
+ const refreshToken = typeof msg.refreshToken === "string" ? msg.refreshToken : void 0;
31732
+ const result = { workspaceId, token: msg.token, refreshToken };
31733
+ session.resolveAuth(result);
31734
+ onAuth(result);
31735
+ cleanupPendingAuthSession(session);
31736
+ };
31737
+ }
31738
+
31739
+ // src/cli-version.ts
31740
+ var CLI_VERSION = "0.1.80".length > 0 ? "0.1.80" : "0.0.0-dev";
31741
+
31742
+ // src/auth/pending/pending-auth-on-open.ts
31743
+ function createPendingAuthOnOpen(params) {
31744
+ const { session, apiUrl, initialWorkspaceId, preferredBridgeName, log: log2 } = params;
31745
+ let pendingHbSeq = -1;
31746
+ return () => {
31747
+ clearReconnectQuietOnSuccessfulConnection(
31748
+ session.signInQuiet,
31749
+ log2,
31750
+ "[Bridge service] Sign-in connection restored."
31751
+ );
31752
+ session.reconnectAttempt = 0;
31753
+ pendingHbSeq = -1;
31754
+ sendWsMessage(session.ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
31755
+ session.keepaliveInterval = setInterval(() => {
31756
+ if (session.resolved || !session.ws || session.ws.readyState !== 1) return;
31757
+ pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
31758
+ const hb = { t: "h", s: pendingHbSeq };
31759
+ sendWsMessage(session.ws, hb);
31760
+ }, PENDING_KEEPALIVE_MS);
31761
+ if (session.browserFallback) {
31762
+ clearTimeout(session.browserFallback);
31763
+ session.browserFallback = null;
31764
+ }
31765
+ if (!session.hasOpenedBrowser) {
31766
+ session.hasOpenedBrowser = true;
31767
+ void openBrowser(session.connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, log2);
31768
+ }
31769
+ };
31770
+ }
31771
+
31772
+ // src/auth/pending/connect-pending-auth.ts
31773
+ function connectPendingAuth(params) {
31774
+ const { session, apiUrl, initialWorkspaceId, preferredBridgeName, onAuth, log: log2 } = params;
31775
+ const connect = () => {
31776
+ session.ws = createWsBridge({
31777
+ url: buildPendingBridgeUrl(apiUrl, session.connectionId),
31778
+ deferInboundMessages: false,
31779
+ onOpen: createPendingAuthOnOpen({
31780
+ session,
31781
+ apiUrl,
31782
+ initialWorkspaceId,
31783
+ preferredBridgeName,
31784
+ log: log2
31785
+ }),
31786
+ onClose: createPendingAuthOnClose({ session, log: log2, connect }),
31787
+ onError: (err) => logCliWebSocketError(log2, "[Bridge service]", err, "while waiting for sign-in"),
31788
+ onMessage: createPendingAuthOnMessage({ session, onAuth })
31789
+ });
31790
+ };
31791
+ connect();
31792
+ }
31793
+
31794
+ // src/auth/pending/run-pending-auth.ts
31795
+ function runPendingAuth(options) {
31796
+ const { apiUrl, initialWorkspaceId, preferredBridgeName, onAuth } = options;
31797
+ const logFn = options.log ?? log;
31798
+ const session = createPendingAuthSession();
31799
+ session.browserFallback = setTimeout(() => {
31800
+ session.browserFallback = null;
31801
+ if (!session.hasOpenedBrowser) {
31802
+ session.hasOpenedBrowser = true;
31803
+ void openBrowser(session.connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
31723
31804
  }
31724
31805
  }, BROWSER_OPEN_FALLBACK_MS);
31725
- connect();
31806
+ connectPendingAuth({
31807
+ session,
31808
+ apiUrl,
31809
+ initialWorkspaceId,
31810
+ preferredBridgeName,
31811
+ onAuth,
31812
+ log: logFn
31813
+ });
31726
31814
  return {
31727
31815
  close: () => {
31728
- if (!resolved) resolveAuth(null);
31729
- cleanup();
31816
+ if (!session.resolved) session.resolveAuth(null);
31817
+ cleanupPendingAuthSession(session);
31730
31818
  },
31731
- authPromise
31819
+ authPromise: session.authPromise
31732
31820
  };
31733
31821
  }
31734
31822
 
@@ -33220,8 +33308,8 @@ function createCursorAcpSessionContext(options) {
33220
33308
 
33221
33309
  // src/agents/acp/clients/cursor/cancel-pending-cursor-permission-requests.ts
33222
33310
  function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
33223
- for (const [reqId, pending] of [...pendingRequests2.entries()]) {
33224
- if (pending.method === "session/request_permission") {
33311
+ for (const [reqId, pending2] of [...pendingRequests2.entries()]) {
33312
+ if (pending2.method === "session/request_permission") {
33225
33313
  respond(reqId, { outcome: { outcome: "cancelled" } });
33226
33314
  pendingRequests2.delete(reqId);
33227
33315
  }
@@ -33413,8 +33501,8 @@ function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
33413
33501
 
33414
33502
  // src/agents/acp/clients/cursor/cursor-incoming-resolve-request.ts
33415
33503
  function resolveCursorIncomingRequest(pendingRequests2, respond, requestId, result) {
33416
- const pending = pendingRequests2.get(requestId);
33417
- const payload = pending?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending.params) : result;
33504
+ const pending2 = pendingRequests2.get(requestId);
33505
+ const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
33418
33506
  respond(requestId, payload);
33419
33507
  pendingRequests2.delete(requestId);
33420
33508
  }
@@ -33552,25 +33640,25 @@ function createCursorJsonRpcInboundRespond(stdin) {
33552
33640
 
33553
33641
  // src/agents/acp/clients/cursor/cursor-json-rpc-outbound.ts
33554
33642
  function createCursorJsonRpcOutboundPending() {
33555
- const pending = /* @__PURE__ */ new Map();
33643
+ const pending2 = /* @__PURE__ */ new Map();
33556
33644
  let nextId = 1;
33557
33645
  function allocateId() {
33558
33646
  return nextId++;
33559
33647
  }
33560
33648
  function register(id, waiter) {
33561
- pending.set(id, waiter);
33649
+ pending2.set(id, waiter);
33562
33650
  }
33563
33651
  function settleResponse(id, msg) {
33564
- const waiter = pending.get(id);
33652
+ const waiter = pending2.get(id);
33565
33653
  if (!waiter) return false;
33566
- pending.delete(id);
33654
+ pending2.delete(id);
33567
33655
  if (msg.error) waiter.reject(msg.error);
33568
33656
  else waiter.resolve(msg.result);
33569
33657
  return true;
33570
33658
  }
33571
33659
  function rejectOnWriteError(id, err) {
33572
- const waiter = pending.get(id);
33573
- pending.delete(id);
33660
+ const waiter = pending2.get(id);
33661
+ pending2.delete(id);
33574
33662
  waiter?.reject(err);
33575
33663
  }
33576
33664
  return { allocateId, register, settleResponse, rejectOnWriteError };
@@ -38458,11 +38546,11 @@ function tryConsumeBinaryProxyBody(raw, deps) {
38458
38546
  if (!PROXY_ID_RE.test(id)) return false;
38459
38547
  const body = raw.slice(PROXY_ID_BYTES);
38460
38548
  const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
38461
- const pending = deps.pendingProxyBody.get(id);
38462
- if (pending) {
38549
+ const pending2 = deps.pendingProxyBody.get(id);
38550
+ if (pending2) {
38463
38551
  deps.pendingProxyBody.delete(id);
38464
38552
  deps.startStreamingProxy({
38465
- ...pending.pr,
38553
+ ...pending2.pr,
38466
38554
  body: bodyBytes.length > 0 ? bodyBytes : void 0
38467
38555
  });
38468
38556
  return true;
@@ -38855,9 +38943,9 @@ function processHeartbeatAck(params) {
38855
38943
  if (awaitingSeq === null) return { awaitingSeq, missed: 0 };
38856
38944
  if (!Number.isFinite(seq)) return { awaitingSeq, missed: 0 };
38857
38945
  const ack = Math.trunc(seq);
38858
- const pending = awaitingSeq;
38859
- if (ack < pending) return { awaitingSeq, missed: 0 };
38860
- if (ack === pending) {
38946
+ const pending2 = awaitingSeq;
38947
+ if (ack < pending2) return { awaitingSeq, missed: 0 };
38948
+ if (ack === pending2) {
38861
38949
  recordRtt(Date.now() - sentAtMs);
38862
38950
  }
38863
38951
  return { awaitingSeq: null, missed: 0 };
@@ -49226,18 +49314,62 @@ async function applyPromptQueueStateFromServer(msg, deps) {
49226
49314
  }
49227
49315
  }
49228
49316
 
49317
+ // src/agents/acp/from-bridge/pending-prompt-results.ts
49318
+ var pending = [];
49319
+ function enqueuePendingPromptResult(message) {
49320
+ const runId = typeof message.runId === "string" ? message.runId : "";
49321
+ if (runId) {
49322
+ const idx = pending.findIndex((m) => m.runId === runId);
49323
+ if (idx >= 0) pending.splice(idx, 1);
49324
+ }
49325
+ pending.push(message);
49326
+ }
49327
+ function flushPendingPromptResults(getWs, encrypt) {
49328
+ if (pending.length === 0) return;
49329
+ const ws = getWs();
49330
+ if (!ws || ws.readyState !== wrapper_default.OPEN) return;
49331
+ const still = [];
49332
+ for (const message of pending) {
49333
+ const wire = encrypt ? encrypt(message) : message;
49334
+ if (!sendWsMessage(ws, wire)) still.push(message);
49335
+ }
49336
+ pending.length = 0;
49337
+ pending.push(...still);
49338
+ }
49339
+
49340
+ // src/agents/acp/from-bridge/send-session-update-wire.ts
49341
+ function sendSessionUpdateWire(getWs, payload, opts) {
49342
+ const s = getWs();
49343
+ if (!s || s.readyState !== wrapper_default.OPEN) {
49344
+ opts.log("[Bridge service] Session update not sent: not connected to the bridge.");
49345
+ return;
49346
+ }
49347
+ const p = payload;
49348
+ const wire = p.type === "session_update" && opts.e2ee ? opts.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && opts.e2ee ? opts.e2ee.encryptFields(payload, [
49349
+ "path",
49350
+ "oldText",
49351
+ "newText",
49352
+ "patchContent",
49353
+ "isDirectory",
49354
+ "directoryRemoved"
49355
+ ]) : payload;
49356
+ sendWsMessage(s, wire);
49357
+ }
49358
+
49229
49359
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
49230
49360
  function createBridgePromptSenders(deps, getWs) {
49231
49361
  const sendBridgeMessage = (message, encryptedFields = []) => {
49232
49362
  const s = getWs();
49233
- if (!s) return false;
49363
+ if (!s || s.readyState !== wrapper_default.OPEN) return false;
49234
49364
  const wire = deps.e2ee && encryptedFields.length > 0 ? deps.e2ee.encryptFields(message, encryptedFields) : message;
49235
- sendWsMessage(s, wire);
49236
- return true;
49365
+ return sendWsMessage(s, wire);
49237
49366
  };
49238
49367
  const sendResult = (result) => {
49239
- const encryptedFields = result.type === "prompt_result" ? ["output", "error"] : [];
49240
- sendBridgeMessage(result, encryptedFields);
49368
+ const sent = sendBridgeMessage(result, result.type === "prompt_result" ? ["output", "error"] : []);
49369
+ if (!sent && result.type === "prompt_result") {
49370
+ enqueuePendingPromptResult(result);
49371
+ deps.log("[Bridge service] prompt_result deferred until bridge reconnect.");
49372
+ }
49241
49373
  if (result.type === "prompt_result") {
49242
49374
  const pr = result;
49243
49375
  const cancelled = pr.stopReason === "cancelled";
@@ -49250,24 +49382,11 @@ function createBridgePromptSenders(deps, getWs) {
49250
49382
  });
49251
49383
  }
49252
49384
  };
49253
- const sendSessionUpdate = (payload) => {
49254
- const s = getWs();
49255
- if (!s) {
49256
- deps.log("[Bridge service] Session update not sent: not connected to the bridge.");
49257
- return;
49258
- }
49259
- const p = payload;
49260
- const wire = p.type === "session_update" && deps.e2ee ? deps.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && deps.e2ee ? deps.e2ee.encryptFields(payload, [
49261
- "path",
49262
- "oldText",
49263
- "newText",
49264
- "patchContent",
49265
- "isDirectory",
49266
- "directoryRemoved"
49267
- ]) : payload;
49268
- sendWsMessage(s, wire);
49385
+ return {
49386
+ sendBridgeMessage,
49387
+ sendResult,
49388
+ sendSessionUpdate: (payload) => sendSessionUpdateWire(getWs, payload, { e2ee: deps.e2ee, log: deps.log })
49269
49389
  };
49270
- return { sendBridgeMessage, sendResult, sendSessionUpdate };
49271
49390
  }
49272
49391
 
49273
49392
  // src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
@@ -49977,25 +50096,59 @@ var handleInstallSkillsMessage = (msg, deps) => {
49977
50096
  })();
49978
50097
  };
49979
50098
 
49980
- // src/agents/install/commands/run-npm-global-install.ts
49981
- import { execFile as execFile9 } from "node:child_process";
49982
- import { promisify as promisify10 } from "node:util";
49983
-
49984
- // src/agents/install/format-command-output.ts
49985
- function formatCommandOutput(stdout, stderr) {
49986
- const parts = [String(stdout ?? "").trimEnd(), String(stderr ?? "").trimEnd()].filter(Boolean);
49987
- return parts.join("\n");
50099
+ // src/agents/install/run-streaming-command.ts
50100
+ import { spawn as spawn11 } from "node:child_process";
50101
+ import * as readline3 from "node:readline";
50102
+ function runStreamingCommand(command, args, options) {
50103
+ return new Promise((resolve35, reject) => {
50104
+ const child = spawn11(command, args, {
50105
+ env: options.env,
50106
+ stdio: ["ignore", "pipe", "pipe"]
50107
+ });
50108
+ let settled = false;
50109
+ const timer = options.timeoutMs != null ? setTimeout(() => {
50110
+ child.kill("SIGKILL");
50111
+ if (!settled) {
50112
+ settled = true;
50113
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
50114
+ }
50115
+ }, options.timeoutMs) : null;
50116
+ const onLine = (line) => {
50117
+ if (line.length > 0) options.onLine?.(line);
50118
+ };
50119
+ if (child.stdout) {
50120
+ readline3.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
50121
+ }
50122
+ if (child.stderr) {
50123
+ readline3.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
50124
+ }
50125
+ child.on("error", (err) => {
50126
+ if (timer) clearTimeout(timer);
50127
+ if (!settled) {
50128
+ settled = true;
50129
+ reject(err);
50130
+ }
50131
+ });
50132
+ child.on("close", (code, signal) => {
50133
+ if (timer) clearTimeout(timer);
50134
+ if (!settled) {
50135
+ settled = true;
50136
+ resolve35({ code, signal });
50137
+ }
50138
+ });
50139
+ });
49988
50140
  }
49989
50141
 
49990
50142
  // src/agents/install/commands/run-npm-global-install.ts
49991
- var execFileAsync8 = promisify10(execFile9);
49992
- async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
49993
- const { stdout, stderr } = await execFileAsync8("npm", ["install", "-g", packageName], {
49994
- timeout: timeoutMs,
50143
+ async function runNpmGlobalInstall(packageName, env, options) {
50144
+ const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
49995
50145
  env: bridgeAgentPathEnv(env),
49996
- maxBuffer: 10 * 1024 * 1024
50146
+ timeoutMs: options?.timeoutMs ?? 3e5,
50147
+ onLine: options?.onLine
49997
50148
  });
49998
- return formatCommandOutput(stdout, stderr);
50149
+ if (result.code !== 0) {
50150
+ throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
50151
+ }
49999
50152
  }
50000
50153
 
50001
50154
  // src/agents/install/commands/claude-code.ts
@@ -50003,11 +50156,12 @@ var claudeCodeInstallCommand = {
50003
50156
  agentType: "claude-code",
50004
50157
  detectCommand: "claude",
50005
50158
  async install(ctx) {
50006
- const logOutput = await runNpmGlobalInstall("@anthropic-ai/claude-code", {
50007
- ...ctx.env,
50008
- ANTHROPIC_API_KEY: ctx.authToken
50009
- });
50010
- ctx.onProgress?.("Installing Anthropic Claude Code", logOutput || void 0);
50159
+ ctx.onProgress?.("Installing Anthropic Claude Code");
50160
+ await runNpmGlobalInstall(
50161
+ "@anthropic-ai/claude-code",
50162
+ { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
50163
+ { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
50164
+ );
50011
50165
  }
50012
50166
  };
50013
50167
 
@@ -50016,34 +50170,34 @@ var codexAcpInstallCommand = {
50016
50170
  agentType: "codex-acp",
50017
50171
  detectCommand: "codex",
50018
50172
  async install(ctx) {
50019
- const logOutput = await runNpmGlobalInstall("@openai/codex", {
50020
- ...ctx.env,
50021
- OPENAI_API_KEY: ctx.authToken
50022
- });
50023
- ctx.onProgress?.("Installing Codex", logOutput || void 0);
50173
+ ctx.onProgress?.("Installing Codex");
50174
+ await runNpmGlobalInstall(
50175
+ "@openai/codex",
50176
+ { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
50177
+ { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
50178
+ );
50024
50179
  }
50025
50180
  };
50026
50181
 
50027
50182
  // src/agents/install/commands/cursor-cli.ts
50028
- import { execFile as execFile10 } from "node:child_process";
50029
- import { promisify as promisify11 } from "node:util";
50030
- var execFileAsync9 = promisify11(execFile10);
50031
50183
  var cursorCliInstallCommand = {
50032
50184
  agentType: "cursor-cli",
50033
50185
  detectCommand: "agent",
50034
50186
  alternateDetectCommands: ["cursor-agent"],
50035
50187
  async install(ctx) {
50036
- const { stdout, stderr } = await execFileAsync9(
50188
+ ctx.onProgress?.("Installing Cursor CLI");
50189
+ const result = await runStreamingCommand(
50037
50190
  "bash",
50038
50191
  ["-lc", "curl -fsSL https://cursor.com/install | bash"],
50039
50192
  {
50040
- timeout: 3e5,
50193
+ timeoutMs: 3e5,
50041
50194
  env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
50042
- maxBuffer: 10 * 1024 * 1024
50195
+ onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
50043
50196
  }
50044
50197
  );
50045
- const logOutput = formatCommandOutput(stdout, stderr);
50046
- ctx.onProgress?.("Installing Cursor CLI", logOutput || void 0);
50198
+ if (result.code !== 0) {
50199
+ throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
50200
+ }
50047
50201
  }
50048
50202
  };
50049
50203
 
@@ -50052,11 +50206,12 @@ var opencodeInstallCommand = {
50052
50206
  agentType: "opencode",
50053
50207
  detectCommand: "opencode",
50054
50208
  async install(ctx) {
50055
- const logOutput = await runNpmGlobalInstall("opencode-ai", {
50056
- ...ctx.env,
50057
- OPENCODE_API_KEY: ctx.authToken
50058
- });
50059
- ctx.onProgress?.("Installing OpenCode", logOutput || void 0);
50209
+ ctx.onProgress?.("Installing OpenCode");
50210
+ await runNpmGlobalInstall(
50211
+ "opencode-ai",
50212
+ { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
50213
+ { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
50214
+ );
50060
50215
  }
50061
50216
  };
50062
50217
 
@@ -50117,25 +50272,47 @@ var handleInstallAgentMessage = (msg, deps) => {
50117
50272
  if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
50118
50273
  void (async () => {
50119
50274
  const socket = deps.getWs();
50120
- const report = (step, message, logOutput) => {
50121
- if (socket) {
50122
- sendWsMessage(socket, {
50123
- type: "install_agent_progress",
50124
- processId,
50125
- agentId,
50126
- tokenId,
50127
- agentType,
50128
- step,
50129
- message,
50130
- ...logOutput ? { logOutput } : {}
50131
- });
50275
+ let pendingLines = [];
50276
+ let flushTimer = null;
50277
+ const sendProgress = (message, logOutput) => {
50278
+ if (!socket) return;
50279
+ sendWsMessage(socket, {
50280
+ type: "install_agent_progress",
50281
+ processId,
50282
+ agentId,
50283
+ tokenId,
50284
+ agentType,
50285
+ step: "agent_install_package",
50286
+ message,
50287
+ ...logOutput ? { logOutput } : {}
50288
+ });
50289
+ };
50290
+ const flushLines = (message) => {
50291
+ if (flushTimer) {
50292
+ clearTimeout(flushTimer);
50293
+ flushTimer = null;
50132
50294
  }
50295
+ if (pendingLines.length === 0) return;
50296
+ const logOutput = pendingLines.join("\n");
50297
+ pendingLines = [];
50298
+ sendProgress(message, logOutput);
50133
50299
  };
50134
50300
  const result = await installLocalAgentOnBridge({
50135
50301
  agentType,
50136
50302
  authToken,
50137
- onProgress: (message, logOutput) => report("agent_install_package", message, logOutput)
50303
+ onProgress: (message, logOutput) => {
50304
+ if (logOutput == null) {
50305
+ flushLines(message);
50306
+ sendProgress(message);
50307
+ return;
50308
+ }
50309
+ pendingLines.push(logOutput);
50310
+ if (!flushTimer) {
50311
+ flushTimer = setTimeout(() => flushLines(message), 100);
50312
+ }
50313
+ }
50138
50314
  });
50315
+ flushLines("Installing agent packages on the bridge machine.");
50139
50316
  if (socket) {
50140
50317
  sendWsMessage(socket, {
50141
50318
  type: "install_agent_result",
@@ -50147,9 +50324,7 @@ var handleInstallAgentMessage = (msg, deps) => {
50147
50324
  error: result.error
50148
50325
  });
50149
50326
  }
50150
- if (result.success) {
50151
- await deps.reportAutoDetectedAgents?.();
50152
- }
50327
+ if (result.success) await deps.reportAutoDetectedAgents?.();
50153
50328
  if (!result.success) {
50154
50329
  deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
50155
50330
  }
@@ -50734,6 +50909,10 @@ function createMainBridgeOpenHandler(params) {
50734
50909
  if (socket) {
50735
50910
  sendBridgeIdentify(socket, { identifyReportedPaths, e2ee });
50736
50911
  reportGitRepos(getWs, logFn);
50912
+ flushPendingPromptResults(
50913
+ getWs,
50914
+ (message) => e2ee ? e2ee.encryptFields(message, ["output", "error"]) : message
50915
+ );
50737
50916
  try {
50738
50917
  onBridgeSocketOpen?.();
50739
50918
  } catch {
@@ -50878,7 +51057,7 @@ async function createBridgeConnection(options) {
50878
51057
  }
50879
51058
 
50880
51059
  // src/e2e-certificates/key-command.ts
50881
- import * as readline3 from "node:readline";
51060
+ import * as readline4 from "node:readline";
50882
51061
  function installE2eCertificateKeyCommand({
50883
51062
  log: log2,
50884
51063
  onOpenCertificate,
@@ -50889,7 +51068,7 @@ function installE2eCertificateKeyCommand({
50889
51068
  return () => {
50890
51069
  };
50891
51070
  }
50892
- readline3.emitKeypressEvents(process.stdin);
51071
+ readline4.emitKeypressEvents(process.stdin);
50893
51072
  process.stdin.setRawMode(true);
50894
51073
  process.stdin.resume();
50895
51074
  const onKeypress = (str, key) => {
@@ -50930,32 +51109,42 @@ async function openE2eCertificateImportUrl({
50930
51109
  }
50931
51110
  }
50932
51111
 
50933
- // src/run-bridge-connected.ts
51112
+ // src/run-bridge-e2ee-key-command.ts
51113
+ function installConnectedBridgeE2eeKeyCommand(params) {
51114
+ let openingCertificate = false;
51115
+ return installE2eCertificateKeyCommand({
51116
+ log: params.log,
51117
+ onInterrupt: params.onInterrupt,
51118
+ onOpenCertificate: () => {
51119
+ if (openingCertificate) return;
51120
+ openingCertificate = true;
51121
+ void openE2eCertificateImportUrl({
51122
+ apiUrl: params.apiUrl,
51123
+ workspaceId: params.workspaceId,
51124
+ certificate: params.e2eCertificate,
51125
+ log: params.log
51126
+ }).finally(() => {
51127
+ openingCertificate = false;
51128
+ });
51129
+ }
51130
+ });
51131
+ }
51132
+
51133
+ // src/run-bridge-connected-signals.ts
51134
+ init_log();
50934
51135
  init_cli_process_interrupt();
50935
- init_cli_database();
50936
- async function runConnectedBridge(options, restartWithoutAuth) {
50937
- const {
50938
- apiUrl,
50939
- workspaceId,
50940
- authToken,
50941
- refreshToken,
50942
- justAuthenticated,
50943
- worktreesRootPath,
50944
- e2eCertificate
50945
- } = options;
50946
- const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
50947
- let cleanupKeyCommand;
50948
- let bridgeClose = null;
51136
+ function installConnectedBridgeSignals(params) {
50949
51137
  let shutdownStarted = false;
50950
51138
  const onSignal = (kind) => {
50951
51139
  requestCliImmediateShutdown();
50952
51140
  abortActiveGitChildProcesses();
50953
- cleanupKeyCommand?.();
51141
+ params.cleanupKeyCommand();
50954
51142
  if (shutdownStarted) return;
50955
51143
  shutdownStarted = true;
50956
51144
  logImmediate(
50957
51145
  kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
50958
51146
  );
51147
+ const bridgeClose = params.getBridgeClose();
50959
51148
  if (bridgeClose) {
50960
51149
  void bridgeClose().finally(() => process.exit(0));
50961
51150
  return;
@@ -50966,9 +51155,56 @@ async function runConnectedBridge(options, restartWithoutAuth) {
50966
51155
  const onSigTerm = () => onSignal("stop");
50967
51156
  process.on("SIGINT", onSigInt);
50968
51157
  process.on("SIGTERM", onSigTerm);
50969
- let handle;
51158
+ return {
51159
+ onSigInt,
51160
+ remove: () => {
51161
+ process.off("SIGINT", onSigInt);
51162
+ process.off("SIGTERM", onSigTerm);
51163
+ }
51164
+ };
51165
+ }
51166
+
51167
+ // src/run-bridge-on-auth-invalid.ts
51168
+ init_cli_process_interrupt();
51169
+ async function closeBridgeForReauth(params) {
51170
+ params.log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
51171
+ clearConfigForApi(params.apiUrl);
51172
+ await params.close();
51173
+ params.removeSignalHandlers();
51174
+ await clearCliImmediateShutdown();
51175
+ params.endConnectedSession();
51176
+ }
51177
+
51178
+ // src/run-bridge-connected.ts
51179
+ init_cli_database();
51180
+ async function runConnectedBridge(options, restartWithoutAuth) {
51181
+ const {
51182
+ apiUrl,
51183
+ workspaceId,
51184
+ authToken,
51185
+ refreshToken,
51186
+ justAuthenticated,
51187
+ worktreesRootPath,
51188
+ e2eCertificate
51189
+ } = options;
51190
+ const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
51191
+ let cleanupKeyCommand;
51192
+ let bridgeClose = null;
51193
+ let endConnectedSession;
51194
+ const sessionDone = new Promise((resolve35) => {
51195
+ endConnectedSession = resolve35;
51196
+ });
51197
+ let resolveHandleReady;
51198
+ const handleReady = new Promise((resolve35) => {
51199
+ resolveHandleReady = resolve35;
51200
+ });
51201
+ const handleRef = { current: null };
51202
+ const signals = installConnectedBridgeSignals({
51203
+ getBridgeClose: () => bridgeClose,
51204
+ cleanupKeyCommand: () => cleanupKeyCommand?.()
51205
+ });
50970
51206
  try {
50971
- handle = await createBridgeConnection({
51207
+ const handle = await createBridgeConnection({
50972
51208
  apiUrl,
50973
51209
  workspaceId,
50974
51210
  authToken,
@@ -50987,41 +51223,40 @@ async function runConnectedBridge(options, restartWithoutAuth) {
50987
51223
  },
50988
51224
  onAuthInvalid: () => {
50989
51225
  cleanupKeyCommand?.();
50990
- log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
50991
- clearConfigForApi(apiUrl);
50992
- void handle.close().then(() => {
50993
- void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
50994
- });
51226
+ void (async () => {
51227
+ await handleReady;
51228
+ await closeBridgeForReauth({
51229
+ apiUrl,
51230
+ log,
51231
+ close: async () => {
51232
+ if (handleRef.current) await handleRef.current.close();
51233
+ },
51234
+ removeSignalHandlers: signals.remove,
51235
+ endConnectedSession
51236
+ });
51237
+ })();
50995
51238
  }
50996
51239
  });
50997
- } catch (e) {
50998
- process.off("SIGINT", onSigInt);
50999
- process.off("SIGTERM", onSigTerm);
51000
- if (e instanceof CliSqliteInterrupted) {
51001
- process.exit(0);
51240
+ handleRef.current = handle;
51241
+ bridgeClose = () => handle.close();
51242
+ if (e2eCertificate) {
51243
+ cleanupKeyCommand = installConnectedBridgeE2eeKeyCommand({
51244
+ apiUrl,
51245
+ workspaceId,
51246
+ e2eCertificate,
51247
+ log,
51248
+ onInterrupt: signals.onSigInt
51249
+ });
51002
51250
  }
51251
+ } catch (e) {
51252
+ signals.remove();
51253
+ if (e instanceof CliSqliteInterrupted) process.exit(0);
51003
51254
  throw e;
51255
+ } finally {
51256
+ resolveHandleReady();
51004
51257
  }
51005
- bridgeClose = () => handle.close();
51006
- if (e2eCertificate) {
51007
- let openingCertificate = false;
51008
- cleanupKeyCommand = installE2eCertificateKeyCommand({
51009
- log,
51010
- onInterrupt: onSigInt,
51011
- onOpenCertificate: () => {
51012
- if (openingCertificate) return;
51013
- openingCertificate = true;
51014
- void openE2eCertificateImportUrl({
51015
- apiUrl,
51016
- workspaceId,
51017
- certificate: e2eCertificate,
51018
- log
51019
- }).finally(() => {
51020
- openingCertificate = false;
51021
- });
51022
- }
51023
- });
51024
- }
51258
+ await sessionDone;
51259
+ await restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
51025
51260
  }
51026
51261
 
51027
51262
  // src/run-bridge.ts
@@ -51065,12 +51300,16 @@ async function runBridge(options) {
51065
51300
  process.off("SIGINT", onSigInt);
51066
51301
  process.off("SIGTERM", onSigTerm);
51067
51302
  handle.close();
51068
- if (!auth) return;
51303
+ if (!auth) {
51304
+ log("Sign-in ended before a token was received.");
51305
+ return;
51306
+ }
51069
51307
  writeConfigForApi(apiUrl, {
51070
51308
  workspaceId: auth.workspaceId,
51071
51309
  token: auth.token,
51072
51310
  refreshToken: auth.refreshToken
51073
51311
  });
51312
+ log("Link established. Connecting with the new token\u2026");
51074
51313
  await runBridge({
51075
51314
  apiUrl,
51076
51315
  workspaceId: auth.workspaceId,