@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/cli.js CHANGED
@@ -7262,31 +7262,31 @@ function handleWorkerOutMessage(message) {
7262
7262
  return;
7263
7263
  }
7264
7264
  if (message.type === "error") {
7265
- const pending2 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
7265
+ const pending3 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
7266
7266
  maybeLogCodeNavCacheWorkerError(message.message);
7267
- if (pending2 != null) {
7267
+ if (pending3 != null) {
7268
7268
  pendingRequests.delete(message.requestId);
7269
7269
  if (isCliImmediateShutdownRequested()) {
7270
- pending2.reject(new CliSqliteInterrupted());
7270
+ pending3.reject(new CliSqliteInterrupted());
7271
7271
  } else {
7272
- pending2.reject(new Error(message.message));
7272
+ pending3.reject(new Error(message.message));
7273
7273
  }
7274
7274
  }
7275
7275
  return;
7276
7276
  }
7277
7277
  if (!("requestId" in message)) return;
7278
- const pending = pendingRequests.get(message.requestId);
7279
- if (pending == null) return;
7278
+ const pending2 = pendingRequests.get(message.requestId);
7279
+ if (pending2 == null) return;
7280
7280
  pendingRequests.delete(message.requestId);
7281
- pending.resolve(message);
7281
+ pending2.resolve(message);
7282
7282
  }
7283
7283
  function resetWorkerReadyState() {
7284
7284
  workerReady = false;
7285
7285
  workerReadyWaiters = [];
7286
7286
  }
7287
7287
  function rejectAllPendingRequests(error40) {
7288
- for (const [, pending] of pendingRequests) {
7289
- pending.reject(error40);
7288
+ for (const [, pending2] of pendingRequests) {
7289
+ pending2.reject(error40);
7290
7290
  }
7291
7291
  pendingRequests.clear();
7292
7292
  }
@@ -8319,14 +8319,14 @@ function legacyCliDiskMigrationIsPending() {
8319
8319
  return false;
8320
8320
  }
8321
8321
  function importCliSqliteLegacyDiskData(db, log2) {
8322
- const pending = legacyCliDiskMigrationIsPending();
8323
- if (pending && log2) {
8322
+ const pending2 = legacyCliDiskMigrationIsPending();
8323
+ if (pending2 && log2) {
8324
8324
  log2("Migrating legacy on-disk CLI data to SQLite\u2026");
8325
8325
  }
8326
8326
  archiveLegacyFileIndexJsonFiles();
8327
8327
  importLegacyAgentSessionsFromDisk(db);
8328
8328
  importLegacyPromptQueuesFromDisk(db);
8329
- if (pending && log2) {
8329
+ if (pending2 && log2) {
8330
8330
  log2("Legacy on-disk CLI data migration finished.");
8331
8331
  }
8332
8332
  }
@@ -12522,6 +12522,16 @@ async function awaitSymbolIndexWorkerShutdown() {
12522
12522
  await terminateSymbolIndexWorker2();
12523
12523
  }
12524
12524
  }
12525
+ async function clearCliImmediateShutdown() {
12526
+ if (symbolIndexShutdownPromise != null) {
12527
+ try {
12528
+ await symbolIndexShutdownPromise;
12529
+ } catch {
12530
+ }
12531
+ }
12532
+ cliImmediateShutdownRequested = false;
12533
+ symbolIndexShutdownPromise = null;
12534
+ }
12525
12535
  function resetCliImmediateShutdownForTests() {
12526
12536
  cliImmediateShutdownRequested = false;
12527
12537
  symbolIndexShutdownPromise = null;
@@ -16657,7 +16667,7 @@ var require_tree_kill = __commonJS({
16657
16667
  "../../node_modules/.pnpm/tree-kill@1.2.2/node_modules/tree-kill/index.js"(exports, module) {
16658
16668
  "use strict";
16659
16669
  var childProcess2 = __require("child_process");
16660
- var spawn11 = childProcess2.spawn;
16670
+ var spawn12 = childProcess2.spawn;
16661
16671
  var exec = childProcess2.exec;
16662
16672
  module.exports = function(pid, signal, callback) {
16663
16673
  if (typeof signal === "function" && callback === void 0) {
@@ -16682,7 +16692,7 @@ var require_tree_kill = __commonJS({
16682
16692
  break;
16683
16693
  case "darwin":
16684
16694
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
16685
- return spawn11("pgrep", ["-P", parentPid]);
16695
+ return spawn12("pgrep", ["-P", parentPid]);
16686
16696
  }, function() {
16687
16697
  killAll(tree, signal, callback);
16688
16698
  });
@@ -16694,7 +16704,7 @@ var require_tree_kill = __commonJS({
16694
16704
  // break;
16695
16705
  default:
16696
16706
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
16697
- return spawn11("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
16707
+ return spawn12("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
16698
16708
  }, function() {
16699
16709
  killAll(tree, signal, callback);
16700
16710
  });
@@ -31071,7 +31081,7 @@ var {
31071
31081
  } = import_index.default;
31072
31082
 
31073
31083
  // src/cli-version.ts
31074
- var CLI_VERSION = "0.1.78".length > 0 ? "0.1.78" : "0.0.0-dev";
31084
+ var CLI_VERSION = "0.1.80".length > 0 ? "0.1.80" : "0.0.0-dev";
31075
31085
 
31076
31086
  // src/cli/defaults.ts
31077
31087
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -31533,181 +31543,8 @@ function installBridgeProcessResilience() {
31533
31543
  });
31534
31544
  }
31535
31545
 
31536
- // ../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
31537
- var import_stream = __toESM(require_stream(), 1);
31538
- var import_receiver = __toESM(require_receiver(), 1);
31539
- var import_sender = __toESM(require_sender(), 1);
31540
- var import_websocket = __toESM(require_websocket(), 1);
31541
- var import_websocket_server = __toESM(require_websocket_server(), 1);
31542
- var wrapper_default = import_websocket.default;
31543
-
31544
- // src/connection/cli-ws-client.ts
31545
- import https from "node:https";
31546
- var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
31547
- function attachWebSocketClientPing(ws, intervalMs) {
31548
- let timer = null;
31549
- function clear() {
31550
- if (timer != null) {
31551
- clearInterval(timer);
31552
- timer = null;
31553
- }
31554
- }
31555
- clear();
31556
- timer = setInterval(() => {
31557
- if (ws.readyState === wrapper_default.OPEN) {
31558
- try {
31559
- ws.ping();
31560
- } catch {
31561
- }
31562
- }
31563
- }, intervalMs);
31564
- return clear;
31565
- }
31566
- function buildCliWebSocketClientOptions(wsUrl) {
31567
- const wsOptions = { perMessageDeflate: false };
31568
- if (wsUrl.startsWith("wss://")) {
31569
- wsOptions.agent = new https.Agent({ rejectUnauthorized: false });
31570
- }
31571
- return wsOptions;
31572
- }
31573
- function logCliWebSocketError(log2, serviceLabel, err, detail) {
31574
- const mid = detail ? ` ${detail}` : "";
31575
- log2(`${serviceLabel} WebSocket error${mid}: ${err.message}`);
31576
- }
31577
- function safeCloseWebSocket(ws) {
31578
- try {
31579
- if (ws.readyState === wrapper_default.CLOSED) {
31580
- ws.removeAllListeners();
31581
- return;
31582
- }
31583
- ws.once("close", () => {
31584
- ws.removeAllListeners();
31585
- });
31586
- ws.close();
31587
- } catch {
31588
- try {
31589
- ws.removeAllListeners();
31590
- } catch {
31591
- }
31592
- }
31593
- }
31594
- function safeSendWebSocketBinary(ws, data) {
31595
- if (ws.readyState !== wrapper_default.OPEN) return false;
31596
- try {
31597
- ws.send(data, { binary: true });
31598
- return true;
31599
- } catch {
31600
- return false;
31601
- }
31602
- }
31603
-
31604
- // src/connection/parse-compact-heartbeat-ack.ts
31605
- function tryParseCompactHeartbeatAck(raw) {
31606
- let str = null;
31607
- if (typeof raw === "string") {
31608
- str = raw;
31609
- } else if (Buffer.isBuffer(raw)) {
31610
- str = raw.toString("utf8");
31611
- } else if (raw instanceof ArrayBuffer) {
31612
- str = Buffer.from(raw).toString("utf8");
31613
- } else {
31614
- return null;
31615
- }
31616
- if (str.length > 64 || !str.includes('"ha"')) return null;
31617
- try {
31618
- const parsed = JSON.parse(str);
31619
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
31620
- const o = parsed;
31621
- if (o.t !== "ha") return null;
31622
- const s = o.s;
31623
- if (typeof s !== "number" || !Number.isFinite(s)) return null;
31624
- return Math.trunc(s);
31625
- } catch {
31626
- return null;
31627
- }
31628
- }
31629
-
31630
- // src/connection/create-ws-bridge.ts
31631
- var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
31632
- var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
31633
- function createWsBridge(options) {
31634
- const {
31635
- url: url2,
31636
- onMessage,
31637
- onOpen,
31638
- onClose,
31639
- onError: onError2,
31640
- onAuthInvalid,
31641
- clientPingIntervalMs,
31642
- onCompactHeartbeatAck,
31643
- isActiveSocket
31644
- } = options;
31645
- const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
31646
- let clearClientPing = null;
31647
- function disposeClientPing() {
31648
- clearClientPing?.();
31649
- clearClientPing = null;
31650
- }
31651
- ws.on("unexpected-response", (request, response) => {
31652
- const status = response?.statusCode ?? 0;
31653
- const headers = response?.headers ?? {};
31654
- const errCode = (headers[BRIDGE_AUTH_ERROR_HEADER] ?? headers["X-Bridge-Auth-Error"] ?? "").toLowerCase();
31655
- if (status === 401 && errCode === BRIDGE_AUTH_ERROR_TOKEN_INVALID) {
31656
- void Promise.resolve(onAuthInvalid?.());
31657
- }
31658
- });
31659
- ws.on("open", () => {
31660
- disposeClientPing();
31661
- if (clientPingIntervalMs != null && clientPingIntervalMs > 0) {
31662
- clearClientPing = attachWebSocketClientPing(ws, clientPingIntervalMs);
31663
- }
31664
- onOpen?.();
31665
- });
31666
- ws.on("message", (raw) => {
31667
- const ackSeq = tryParseCompactHeartbeatAck(raw);
31668
- if (ackSeq != null) {
31669
- onCompactHeartbeatAck?.(ackSeq);
31670
- return;
31671
- }
31672
- setImmediate(() => {
31673
- if (isActiveSocket && !isActiveSocket(ws)) return;
31674
- try {
31675
- let data;
31676
- if (typeof raw === "string") {
31677
- data = JSON.parse(raw);
31678
- } else if (Buffer.isBuffer(raw) || raw instanceof ArrayBuffer) {
31679
- const str = Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
31680
- data = JSON.parse(str);
31681
- } else {
31682
- data = raw;
31683
- }
31684
- onMessage?.(data, ws);
31685
- } catch {
31686
- onMessage?.(raw, ws);
31687
- }
31688
- });
31689
- });
31690
- ws.on("close", (code, reason) => {
31691
- disposeClientPing();
31692
- onClose?.(code, reason.toString());
31693
- });
31694
- ws.on("error", (err) => {
31695
- disposeClientPing();
31696
- onError2?.(err);
31697
- });
31698
- return ws;
31699
- }
31700
- function sendWsMessage(ws, payload) {
31701
- if (ws.readyState === wrapper_default.OPEN) {
31702
- ws.send(JSON.stringify(payload));
31703
- }
31704
- }
31705
-
31706
- // src/connection/heartbeat/constants.ts
31707
- var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
31708
- var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
31709
- var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
31710
- var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
31546
+ // src/auth/pending/run-pending-auth.ts
31547
+ init_log();
31711
31548
 
31712
31549
  // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
31713
31550
  import process7 from "node:process";
@@ -32262,8 +32099,196 @@ async function openBrowser(connectionId, initialWorkspaceId, preferredBridgeName
32262
32099
  }
32263
32100
  }
32264
32101
 
32265
- // src/auth/run-pending-auth.ts
32266
- init_log();
32102
+ // src/auth/pending/constants.ts
32103
+ var PENDING_KEEPALIVE_MS = 25e3;
32104
+ var BROWSER_OPEN_FALLBACK_MS = 4e3;
32105
+
32106
+ // ../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
32107
+ var import_stream = __toESM(require_stream(), 1);
32108
+ var import_receiver = __toESM(require_receiver(), 1);
32109
+ var import_sender = __toESM(require_sender(), 1);
32110
+ var import_websocket = __toESM(require_websocket(), 1);
32111
+ var import_websocket_server = __toESM(require_websocket_server(), 1);
32112
+ var wrapper_default = import_websocket.default;
32113
+
32114
+ // src/connection/cli-ws-client.ts
32115
+ import https from "node:https";
32116
+ var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
32117
+ function attachWebSocketClientPing(ws, intervalMs) {
32118
+ let timer = null;
32119
+ function clear() {
32120
+ if (timer != null) {
32121
+ clearInterval(timer);
32122
+ timer = null;
32123
+ }
32124
+ }
32125
+ clear();
32126
+ timer = setInterval(() => {
32127
+ if (ws.readyState === wrapper_default.OPEN) {
32128
+ try {
32129
+ ws.ping();
32130
+ } catch {
32131
+ }
32132
+ }
32133
+ }, intervalMs);
32134
+ return clear;
32135
+ }
32136
+ function buildCliWebSocketClientOptions(wsUrl) {
32137
+ const wsOptions = { perMessageDeflate: false };
32138
+ if (wsUrl.startsWith("wss://")) {
32139
+ wsOptions.agent = new https.Agent({ rejectUnauthorized: false });
32140
+ }
32141
+ return wsOptions;
32142
+ }
32143
+ function logCliWebSocketError(log2, serviceLabel, err, detail) {
32144
+ const mid = detail ? ` ${detail}` : "";
32145
+ log2(`${serviceLabel} WebSocket error${mid}: ${err.message}`);
32146
+ }
32147
+ function safeCloseWebSocket(ws) {
32148
+ try {
32149
+ if (ws.readyState === wrapper_default.CLOSED) {
32150
+ ws.removeAllListeners();
32151
+ return;
32152
+ }
32153
+ ws.once("close", () => {
32154
+ ws.removeAllListeners();
32155
+ });
32156
+ ws.close();
32157
+ } catch {
32158
+ try {
32159
+ ws.removeAllListeners();
32160
+ } catch {
32161
+ }
32162
+ }
32163
+ }
32164
+ function safeSendWebSocketBinary(ws, data) {
32165
+ if (ws.readyState !== wrapper_default.OPEN) return false;
32166
+ try {
32167
+ ws.send(data, { binary: true });
32168
+ return true;
32169
+ } catch {
32170
+ return false;
32171
+ }
32172
+ }
32173
+
32174
+ // src/connection/create-ws-bridge-options.ts
32175
+ var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
32176
+ var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
32177
+
32178
+ // src/connection/dispatch-ws-inbound-message.ts
32179
+ function dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket) {
32180
+ if (isActiveSocket && !isActiveSocket(ws)) return;
32181
+ try {
32182
+ let data;
32183
+ if (typeof raw === "string") {
32184
+ data = JSON.parse(raw);
32185
+ } else if (Buffer.isBuffer(raw) || raw instanceof ArrayBuffer) {
32186
+ const str = Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
32187
+ data = JSON.parse(str);
32188
+ } else {
32189
+ data = raw;
32190
+ }
32191
+ onMessage?.(data, ws);
32192
+ } catch {
32193
+ onMessage?.(raw, ws);
32194
+ }
32195
+ }
32196
+
32197
+ // src/connection/parse-compact-heartbeat-ack.ts
32198
+ function tryParseCompactHeartbeatAck(raw) {
32199
+ let str = null;
32200
+ if (typeof raw === "string") {
32201
+ str = raw;
32202
+ } else if (Buffer.isBuffer(raw)) {
32203
+ str = raw.toString("utf8");
32204
+ } else if (raw instanceof ArrayBuffer) {
32205
+ str = Buffer.from(raw).toString("utf8");
32206
+ } else {
32207
+ return null;
32208
+ }
32209
+ if (str.length > 64 || !str.includes('"ha"')) return null;
32210
+ try {
32211
+ const parsed = JSON.parse(str);
32212
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
32213
+ const o = parsed;
32214
+ if (o.t !== "ha") return null;
32215
+ const s = o.s;
32216
+ if (typeof s !== "number" || !Number.isFinite(s)) return null;
32217
+ return Math.trunc(s);
32218
+ } catch {
32219
+ return null;
32220
+ }
32221
+ }
32222
+
32223
+ // src/connection/create-ws-bridge.ts
32224
+ function createWsBridge(options) {
32225
+ const {
32226
+ url: url2,
32227
+ onMessage,
32228
+ onOpen,
32229
+ onClose,
32230
+ onError: onError2,
32231
+ onAuthInvalid,
32232
+ clientPingIntervalMs,
32233
+ onCompactHeartbeatAck,
32234
+ isActiveSocket,
32235
+ deferInboundMessages = true
32236
+ } = options;
32237
+ const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
32238
+ let clearClientPing = null;
32239
+ const disposeClientPing = () => {
32240
+ clearClientPing?.();
32241
+ clearClientPing = null;
32242
+ };
32243
+ ws.on("unexpected-response", (_request, response) => {
32244
+ const status = response?.statusCode ?? 0;
32245
+ const headers = response?.headers ?? {};
32246
+ const errCode = (headers[BRIDGE_AUTH_ERROR_HEADER] ?? headers["X-Bridge-Auth-Error"] ?? "").toLowerCase();
32247
+ if (status === 401 && errCode === BRIDGE_AUTH_ERROR_TOKEN_INVALID) {
32248
+ void Promise.resolve(onAuthInvalid?.());
32249
+ }
32250
+ });
32251
+ ws.on("open", () => {
32252
+ disposeClientPing();
32253
+ if (clientPingIntervalMs != null && clientPingIntervalMs > 0) {
32254
+ clearClientPing = attachWebSocketClientPing(ws, clientPingIntervalMs);
32255
+ }
32256
+ onOpen?.();
32257
+ });
32258
+ ws.on("message", (raw) => {
32259
+ const ackSeq = tryParseCompactHeartbeatAck(raw);
32260
+ if (ackSeq != null) {
32261
+ onCompactHeartbeatAck?.(ackSeq);
32262
+ return;
32263
+ }
32264
+ if (deferInboundMessages) {
32265
+ setImmediate(() => dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket));
32266
+ return;
32267
+ }
32268
+ dispatchWsInboundMessage(raw, ws, onMessage, isActiveSocket);
32269
+ });
32270
+ ws.on("close", (code, reason) => {
32271
+ disposeClientPing();
32272
+ onClose?.(code, reason.toString());
32273
+ });
32274
+ ws.on("error", (err) => {
32275
+ disposeClientPing();
32276
+ onError2?.(err);
32277
+ });
32278
+ return ws;
32279
+ }
32280
+ function sendWsMessage(ws, payload) {
32281
+ if (ws.readyState !== wrapper_default.OPEN) return false;
32282
+ ws.send(JSON.stringify(payload));
32283
+ return true;
32284
+ }
32285
+
32286
+ // src/auth/pending/build-pending-bridge-url.ts
32287
+ function buildPendingBridgeUrl(apiUrl, connectionId) {
32288
+ const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
32289
+ const params = new URLSearchParams({ connectionId });
32290
+ return `${base}/ws/bridge/pending?${params.toString()}`;
32291
+ }
32267
32292
 
32268
32293
  // src/connection/reconnect/constants.ts
32269
32294
  var RECONNECT_QUIET_MS = 2e3;
@@ -32594,6 +32619,12 @@ function scheduleMainBridgeReconnect(state, connect, log2, closeMeta) {
32594
32619
  });
32595
32620
  }
32596
32621
 
32622
+ // src/connection/heartbeat/constants.ts
32623
+ var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
32624
+ var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
32625
+ var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
32626
+ var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
32627
+
32597
32628
  // src/connection/reconnect/duplicate-bridge-connection-detect.ts
32598
32629
  var BRIDGE_SUPERSEDED_CLOSE_REASON_SNIPPET = "superseded";
32599
32630
  var DUPLICATE_BRIDGE_SHORT_SESSION_MS = 25e3;
@@ -32678,145 +32709,177 @@ function clearFirehoseReconnectQuietOnOpen(ctx, log2) {
32678
32709
  });
32679
32710
  }
32680
32711
 
32681
- // src/auth/run-pending-auth.ts
32682
- var PENDING_KEEPALIVE_MS = 25e3;
32683
- var BROWSER_OPEN_FALLBACK_MS = 4e3;
32684
- function buildPendingBridgeUrl(apiUrl, connectionId) {
32685
- const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
32686
- const params = new URLSearchParams({ connectionId });
32687
- return `${base}/ws/bridge/pending?${params.toString()}`;
32688
- }
32689
- function runPendingAuth(options) {
32690
- const { apiUrl, initialWorkspaceId, preferredBridgeName, onAuth } = options;
32691
- const logFn = options.log ?? log;
32692
- let ws = null;
32693
- let reconnectTimeout = null;
32694
- let keepaliveInterval = null;
32695
- let browserFallback = null;
32696
- const connectionId = crypto.randomUUID();
32697
- let hasOpenedBrowser = false;
32698
- let resolved = false;
32699
- let resolveAuth;
32700
- const authPromise = new Promise((resolve37) => {
32701
- resolveAuth = resolve37;
32702
- });
32703
- let reconnectAttempt = 0;
32704
- const signInQuiet = createEmptyReconnectQuietSlot();
32705
- function clearQuietOnOpen() {
32706
- clearReconnectQuietOnSuccessfulConnection(
32707
- signInQuiet,
32708
- logFn,
32709
- "[Bridge service] Sign-in connection restored."
32710
- );
32711
- reconnectAttempt = 0;
32712
- }
32713
- function beginDeferredPendingCloseLog(code, reason) {
32712
+ // src/auth/pending/pending-auth-on-close.ts
32713
+ function createPendingAuthOnClose(params) {
32714
+ const { session, log: log2, connect } = params;
32715
+ return (code, reason) => {
32716
+ if (session.keepaliveInterval) {
32717
+ clearInterval(session.keepaliveInterval);
32718
+ session.keepaliveInterval = null;
32719
+ }
32720
+ if (session.resolved) return;
32714
32721
  beginDeferredDisconnectForReconnect({
32715
- isClosedByUser: () => resolved,
32716
- quiet: signInQuiet,
32722
+ isClosedByUser: () => session.resolved,
32723
+ quiet: session.signInQuiet,
32717
32724
  code,
32718
32725
  reason,
32719
32726
  willReconnect: true,
32720
- log: logFn,
32727
+ log: log2,
32721
32728
  serviceLabel: "[Bridge service]",
32722
32729
  shutdownDetail: "Not reconnecting (shutting down).",
32723
32730
  reconnectingDetail: "Waiting for browser sign-in; reconnecting\u2026",
32724
- shouldAbortQuietWindow: () => ws != null && ws.readyState === wrapper_default.OPEN
32731
+ shouldAbortQuietWindow: () => session.ws != null && session.ws.readyState === wrapper_default.OPEN
32725
32732
  });
32726
- }
32727
- function cleanup() {
32728
- clearReconnectQuietTimer(signInQuiet);
32729
- if (reconnectTimeout) {
32730
- clearTimeout(reconnectTimeout);
32731
- reconnectTimeout = null;
32732
- }
32733
- if (browserFallback) {
32734
- clearTimeout(browserFallback);
32735
- browserFallback = null;
32736
- }
32737
- if (keepaliveInterval) {
32738
- clearInterval(keepaliveInterval);
32739
- keepaliveInterval = null;
32740
- }
32741
- if (ws) {
32742
- const w = ws;
32743
- ws = null;
32744
- safeCloseWebSocket(w);
32733
+ const delay4 = pendingAuthReconnectDelayMs(session.reconnectAttempt);
32734
+ session.reconnectAttempt += 1;
32735
+ if (session.signInQuiet.verboseLogs) {
32736
+ const delayLabel = formatReconnectDelayForLog(delay4);
32737
+ log2(
32738
+ `[Bridge service] Next sign-in connection attempt in ${delayLabel} (attempt ${session.reconnectAttempt}).`
32739
+ );
32745
32740
  }
32741
+ session.reconnectTimeout = setTimeout(() => {
32742
+ session.reconnectTimeout = null;
32743
+ connect();
32744
+ }, delay4);
32745
+ };
32746
+ }
32747
+
32748
+ // src/auth/pending/pending-auth-session.ts
32749
+ function createPendingAuthSession() {
32750
+ let resolveAuth;
32751
+ const authPromise = new Promise((resolve37) => {
32752
+ resolveAuth = resolve37;
32753
+ });
32754
+ return {
32755
+ ws: null,
32756
+ reconnectTimeout: null,
32757
+ keepaliveInterval: null,
32758
+ browserFallback: null,
32759
+ connectionId: crypto.randomUUID(),
32760
+ hasOpenedBrowser: false,
32761
+ resolved: false,
32762
+ resolveAuth,
32763
+ reconnectAttempt: 0,
32764
+ signInQuiet: createEmptyReconnectQuietSlot(),
32765
+ authPromise
32766
+ };
32767
+ }
32768
+ function cleanupPendingAuthSession(session) {
32769
+ clearReconnectQuietTimer(session.signInQuiet);
32770
+ if (session.reconnectTimeout) {
32771
+ clearTimeout(session.reconnectTimeout);
32772
+ session.reconnectTimeout = null;
32746
32773
  }
32747
- function connect() {
32748
- const url2 = buildPendingBridgeUrl(apiUrl, connectionId);
32749
- let pendingHbSeq = -1;
32750
- ws = createWsBridge({
32751
- url: url2,
32752
- onOpen: () => {
32753
- clearQuietOnOpen();
32754
- pendingHbSeq = -1;
32755
- sendWsMessage(ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
32756
- keepaliveInterval = setInterval(() => {
32757
- if (resolved || !ws || ws.readyState !== 1) return;
32758
- pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
32759
- const hb = { t: "h", s: pendingHbSeq };
32760
- sendWsMessage(ws, hb);
32761
- }, PENDING_KEEPALIVE_MS);
32762
- if (browserFallback) {
32763
- clearTimeout(browserFallback);
32764
- browserFallback = null;
32765
- }
32766
- if (!hasOpenedBrowser) {
32767
- hasOpenedBrowser = true;
32768
- void openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
32769
- }
32770
- },
32771
- onClose: (code, reason) => {
32772
- if (keepaliveInterval) {
32773
- clearInterval(keepaliveInterval);
32774
- keepaliveInterval = null;
32775
- }
32776
- if (resolved) return;
32777
- beginDeferredPendingCloseLog(code, reason);
32778
- const delay4 = pendingAuthReconnectDelayMs(reconnectAttempt);
32779
- reconnectAttempt += 1;
32780
- if (signInQuiet.verboseLogs) {
32781
- const delayLabel = formatReconnectDelayForLog(delay4);
32782
- logFn(
32783
- `[Bridge service] Next sign-in connection attempt in ${delayLabel} (attempt ${reconnectAttempt}).`
32784
- );
32785
- }
32786
- reconnectTimeout = setTimeout(() => {
32787
- reconnectTimeout = null;
32788
- connect();
32789
- }, delay4);
32790
- },
32791
- onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
32792
- onMessage: (data) => {
32793
- const msg = data;
32794
- if (msg.type === "auth_token" && typeof msg.token === "string") {
32795
- resolved = true;
32796
- const workspaceId = typeof msg.workspaceId === "string" ? msg.workspaceId : "";
32797
- cleanup();
32798
- const refreshToken = typeof msg.refreshToken === "string" ? msg.refreshToken : void 0;
32799
- const result = { workspaceId, token: msg.token, refreshToken };
32800
- resolveAuth(result);
32801
- onAuth(result);
32802
- }
32803
- }
32804
- });
32774
+ if (session.browserFallback) {
32775
+ clearTimeout(session.browserFallback);
32776
+ session.browserFallback = null;
32805
32777
  }
32806
- browserFallback = setTimeout(() => {
32807
- browserFallback = null;
32808
- if (!hasOpenedBrowser) {
32809
- hasOpenedBrowser = true;
32810
- void openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
32778
+ if (session.keepaliveInterval) {
32779
+ clearInterval(session.keepaliveInterval);
32780
+ session.keepaliveInterval = null;
32781
+ }
32782
+ if (session.ws) {
32783
+ const w = session.ws;
32784
+ session.ws = null;
32785
+ safeCloseWebSocket(w);
32786
+ }
32787
+ }
32788
+
32789
+ // src/auth/pending/pending-auth-on-message.ts
32790
+ function createPendingAuthOnMessage(params) {
32791
+ const { session, onAuth } = params;
32792
+ return (data) => {
32793
+ const msg = data;
32794
+ if (msg.type !== "auth_token" || typeof msg.token !== "string") return;
32795
+ session.resolved = true;
32796
+ const workspaceId = typeof msg.workspaceId === "string" ? msg.workspaceId : "";
32797
+ const refreshToken = typeof msg.refreshToken === "string" ? msg.refreshToken : void 0;
32798
+ const result = { workspaceId, token: msg.token, refreshToken };
32799
+ session.resolveAuth(result);
32800
+ onAuth(result);
32801
+ cleanupPendingAuthSession(session);
32802
+ };
32803
+ }
32804
+
32805
+ // src/auth/pending/pending-auth-on-open.ts
32806
+ function createPendingAuthOnOpen(params) {
32807
+ const { session, apiUrl, initialWorkspaceId, preferredBridgeName, log: log2 } = params;
32808
+ let pendingHbSeq = -1;
32809
+ return () => {
32810
+ clearReconnectQuietOnSuccessfulConnection(
32811
+ session.signInQuiet,
32812
+ log2,
32813
+ "[Bridge service] Sign-in connection restored."
32814
+ );
32815
+ session.reconnectAttempt = 0;
32816
+ pendingHbSeq = -1;
32817
+ sendWsMessage(session.ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
32818
+ session.keepaliveInterval = setInterval(() => {
32819
+ if (session.resolved || !session.ws || session.ws.readyState !== 1) return;
32820
+ pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
32821
+ const hb = { t: "h", s: pendingHbSeq };
32822
+ sendWsMessage(session.ws, hb);
32823
+ }, PENDING_KEEPALIVE_MS);
32824
+ if (session.browserFallback) {
32825
+ clearTimeout(session.browserFallback);
32826
+ session.browserFallback = null;
32827
+ }
32828
+ if (!session.hasOpenedBrowser) {
32829
+ session.hasOpenedBrowser = true;
32830
+ void openBrowser(session.connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, log2);
32831
+ }
32832
+ };
32833
+ }
32834
+
32835
+ // src/auth/pending/connect-pending-auth.ts
32836
+ function connectPendingAuth(params) {
32837
+ const { session, apiUrl, initialWorkspaceId, preferredBridgeName, onAuth, log: log2 } = params;
32838
+ const connect = () => {
32839
+ session.ws = createWsBridge({
32840
+ url: buildPendingBridgeUrl(apiUrl, session.connectionId),
32841
+ deferInboundMessages: false,
32842
+ onOpen: createPendingAuthOnOpen({
32843
+ session,
32844
+ apiUrl,
32845
+ initialWorkspaceId,
32846
+ preferredBridgeName,
32847
+ log: log2
32848
+ }),
32849
+ onClose: createPendingAuthOnClose({ session, log: log2, connect }),
32850
+ onError: (err) => logCliWebSocketError(log2, "[Bridge service]", err, "while waiting for sign-in"),
32851
+ onMessage: createPendingAuthOnMessage({ session, onAuth })
32852
+ });
32853
+ };
32854
+ connect();
32855
+ }
32856
+
32857
+ // src/auth/pending/run-pending-auth.ts
32858
+ function runPendingAuth(options) {
32859
+ const { apiUrl, initialWorkspaceId, preferredBridgeName, onAuth } = options;
32860
+ const logFn = options.log ?? log;
32861
+ const session = createPendingAuthSession();
32862
+ session.browserFallback = setTimeout(() => {
32863
+ session.browserFallback = null;
32864
+ if (!session.hasOpenedBrowser) {
32865
+ session.hasOpenedBrowser = true;
32866
+ void openBrowser(session.connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
32811
32867
  }
32812
32868
  }, BROWSER_OPEN_FALLBACK_MS);
32813
- connect();
32869
+ connectPendingAuth({
32870
+ session,
32871
+ apiUrl,
32872
+ initialWorkspaceId,
32873
+ preferredBridgeName,
32874
+ onAuth,
32875
+ log: logFn
32876
+ });
32814
32877
  return {
32815
32878
  close: () => {
32816
- if (!resolved) resolveAuth(null);
32817
- cleanup();
32879
+ if (!session.resolved) session.resolveAuth(null);
32880
+ cleanupPendingAuthSession(session);
32818
32881
  },
32819
- authPromise
32882
+ authPromise: session.authPromise
32820
32883
  };
32821
32884
  }
32822
32885
 
@@ -34953,6 +35016,31 @@ function getAgentModelFromAgentConfig(config2) {
34953
35016
  var HOUR_MS = 36e5;
34954
35017
  var DAY_MS = 24 * HOUR_MS;
34955
35018
 
35019
+ // ../types/src/hosts/skus.ts
35020
+ function defineHostSku(params) {
35021
+ return structuredClone(params);
35022
+ }
35023
+ var FLY_LEGACY_HOST_SKU = defineHostSku({
35024
+ id: "fly-shared-1x512-1gb",
35025
+ provider: "fly",
35026
+ compute: { cpus: 1, cpuKind: "shared" },
35027
+ memory: { memoryMb: 512 },
35028
+ storage: { storageGb: 1 },
35029
+ monthlyPriceCents: 750
35030
+ });
35031
+ var FLY_DEFAULT_HOST_SKU = defineHostSku({
35032
+ id: "fly-shared-1x1024-1gb",
35033
+ provider: "fly",
35034
+ compute: { cpus: 1, cpuKind: "shared" },
35035
+ memory: { memoryMb: 1024 },
35036
+ storage: { storageGb: 1 },
35037
+ monthlyPriceCents: 1e3
35038
+ });
35039
+ var HOST_SKUS_BY_ID = {
35040
+ [FLY_LEGACY_HOST_SKU.id]: FLY_LEGACY_HOST_SKU,
35041
+ [FLY_DEFAULT_HOST_SKU.id]: FLY_DEFAULT_HOST_SKU
35042
+ };
35043
+
34956
35044
  // ../types/src/bridges/agents/types.ts
34957
35045
  var INSTALLABLE_BRIDGE_AGENTS = [
34958
35046
  { value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
@@ -35453,11 +35541,11 @@ function createSdkStdioExtNotificationHandler(options) {
35453
35541
 
35454
35542
  // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
35455
35543
  function awaitSdkStdioPermissionRequestHandshake(params) {
35456
- const { requestId, paramsRecord, pending, onRequest } = params;
35544
+ const { requestId, paramsRecord, pending: pending2, onRequest } = params;
35457
35545
  return new Promise((resolve37) => {
35458
- pending.set(requestId, { resolve: resolve37, params: paramsRecord });
35546
+ pending2.set(requestId, { resolve: resolve37, params: paramsRecord });
35459
35547
  if (onRequest == null) {
35460
- pending.delete(requestId);
35548
+ pending2.delete(requestId);
35461
35549
  resolve37({ outcome: { outcome: "denied" } });
35462
35550
  return;
35463
35551
  }
@@ -35473,9 +35561,9 @@ function awaitSdkStdioPermissionRequestHandshake(params) {
35473
35561
  }
35474
35562
 
35475
35563
  // src/agents/acp/clients/sdk/sdk-stdio-permission-pending.ts
35476
- function resolvePendingSdkStdioPermissionCancellations(pending) {
35477
- for (const [id, entry] of [...pending.entries()]) {
35478
- pending.delete(id);
35564
+ function resolvePendingSdkStdioPermissionCancellations(pending2) {
35565
+ for (const [id, entry] of [...pending2.entries()]) {
35566
+ pending2.delete(id);
35479
35567
  entry.resolve({ outcome: { outcome: "cancelled" } });
35480
35568
  }
35481
35569
  }
@@ -36201,8 +36289,8 @@ function createCursorAcpSessionContext(options) {
36201
36289
 
36202
36290
  // src/agents/acp/clients/cursor/cancel-pending-cursor-permission-requests.ts
36203
36291
  function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
36204
- for (const [reqId, pending] of [...pendingRequests2.entries()]) {
36205
- if (pending.method === "session/request_permission") {
36292
+ for (const [reqId, pending2] of [...pendingRequests2.entries()]) {
36293
+ if (pending2.method === "session/request_permission") {
36206
36294
  respond(reqId, { outcome: { outcome: "cancelled" } });
36207
36295
  pendingRequests2.delete(reqId);
36208
36296
  }
@@ -36394,8 +36482,8 @@ function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
36394
36482
 
36395
36483
  // src/agents/acp/clients/cursor/cursor-incoming-resolve-request.ts
36396
36484
  function resolveCursorIncomingRequest(pendingRequests2, respond, requestId, result) {
36397
- const pending = pendingRequests2.get(requestId);
36398
- const payload = pending?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending.params) : result;
36485
+ const pending2 = pendingRequests2.get(requestId);
36486
+ const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
36399
36487
  respond(requestId, payload);
36400
36488
  pendingRequests2.delete(requestId);
36401
36489
  }
@@ -36533,25 +36621,25 @@ function createCursorJsonRpcInboundRespond(stdin) {
36533
36621
 
36534
36622
  // src/agents/acp/clients/cursor/cursor-json-rpc-outbound.ts
36535
36623
  function createCursorJsonRpcOutboundPending() {
36536
- const pending = /* @__PURE__ */ new Map();
36624
+ const pending2 = /* @__PURE__ */ new Map();
36537
36625
  let nextId = 1;
36538
36626
  function allocateId() {
36539
36627
  return nextId++;
36540
36628
  }
36541
36629
  function register(id, waiter) {
36542
- pending.set(id, waiter);
36630
+ pending2.set(id, waiter);
36543
36631
  }
36544
36632
  function settleResponse(id, msg) {
36545
- const waiter = pending.get(id);
36633
+ const waiter = pending2.get(id);
36546
36634
  if (!waiter) return false;
36547
- pending.delete(id);
36635
+ pending2.delete(id);
36548
36636
  if (msg.error) waiter.reject(msg.error);
36549
36637
  else waiter.resolve(msg.result);
36550
36638
  return true;
36551
36639
  }
36552
36640
  function rejectOnWriteError(id, err) {
36553
- const waiter = pending.get(id);
36554
- pending.delete(id);
36641
+ const waiter = pending2.get(id);
36642
+ pending2.delete(id);
36555
36643
  waiter?.reject(err);
36556
36644
  }
36557
36645
  return { allocateId, register, settleResponse, rejectOnWriteError };
@@ -41504,11 +41592,11 @@ function tryConsumeBinaryProxyBody(raw, deps) {
41504
41592
  if (!PROXY_ID_RE.test(id)) return false;
41505
41593
  const body = raw.slice(PROXY_ID_BYTES);
41506
41594
  const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
41507
- const pending = deps.pendingProxyBody.get(id);
41508
- if (pending) {
41595
+ const pending2 = deps.pendingProxyBody.get(id);
41596
+ if (pending2) {
41509
41597
  deps.pendingProxyBody.delete(id);
41510
41598
  deps.startStreamingProxy({
41511
- ...pending.pr,
41599
+ ...pending2.pr,
41512
41600
  body: bodyBytes.length > 0 ? bodyBytes : void 0
41513
41601
  });
41514
41602
  return true;
@@ -41901,9 +41989,9 @@ function processHeartbeatAck(params) {
41901
41989
  if (awaitingSeq === null) return { awaitingSeq, missed: 0 };
41902
41990
  if (!Number.isFinite(seq)) return { awaitingSeq, missed: 0 };
41903
41991
  const ack = Math.trunc(seq);
41904
- const pending = awaitingSeq;
41905
- if (ack < pending) return { awaitingSeq, missed: 0 };
41906
- if (ack === pending) {
41992
+ const pending2 = awaitingSeq;
41993
+ if (ack < pending2) return { awaitingSeq, missed: 0 };
41994
+ if (ack === pending2) {
41907
41995
  recordRtt(Date.now() - sentAtMs);
41908
41996
  }
41909
41997
  return { awaitingSeq: null, missed: 0 };
@@ -52272,18 +52360,62 @@ async function applyPromptQueueStateFromServer(msg, deps) {
52272
52360
  }
52273
52361
  }
52274
52362
 
52363
+ // src/agents/acp/from-bridge/pending-prompt-results.ts
52364
+ var pending = [];
52365
+ function enqueuePendingPromptResult(message) {
52366
+ const runId = typeof message.runId === "string" ? message.runId : "";
52367
+ if (runId) {
52368
+ const idx = pending.findIndex((m) => m.runId === runId);
52369
+ if (idx >= 0) pending.splice(idx, 1);
52370
+ }
52371
+ pending.push(message);
52372
+ }
52373
+ function flushPendingPromptResults(getWs, encrypt) {
52374
+ if (pending.length === 0) return;
52375
+ const ws = getWs();
52376
+ if (!ws || ws.readyState !== wrapper_default.OPEN) return;
52377
+ const still = [];
52378
+ for (const message of pending) {
52379
+ const wire = encrypt ? encrypt(message) : message;
52380
+ if (!sendWsMessage(ws, wire)) still.push(message);
52381
+ }
52382
+ pending.length = 0;
52383
+ pending.push(...still);
52384
+ }
52385
+
52386
+ // src/agents/acp/from-bridge/send-session-update-wire.ts
52387
+ function sendSessionUpdateWire(getWs, payload, opts) {
52388
+ const s = getWs();
52389
+ if (!s || s.readyState !== wrapper_default.OPEN) {
52390
+ opts.log("[Bridge service] Session update not sent: not connected to the bridge.");
52391
+ return;
52392
+ }
52393
+ const p = payload;
52394
+ const wire = p.type === "session_update" && opts.e2ee ? opts.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && opts.e2ee ? opts.e2ee.encryptFields(payload, [
52395
+ "path",
52396
+ "oldText",
52397
+ "newText",
52398
+ "patchContent",
52399
+ "isDirectory",
52400
+ "directoryRemoved"
52401
+ ]) : payload;
52402
+ sendWsMessage(s, wire);
52403
+ }
52404
+
52275
52405
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
52276
52406
  function createBridgePromptSenders(deps, getWs) {
52277
52407
  const sendBridgeMessage = (message, encryptedFields = []) => {
52278
52408
  const s = getWs();
52279
- if (!s) return false;
52409
+ if (!s || s.readyState !== wrapper_default.OPEN) return false;
52280
52410
  const wire = deps.e2ee && encryptedFields.length > 0 ? deps.e2ee.encryptFields(message, encryptedFields) : message;
52281
- sendWsMessage(s, wire);
52282
- return true;
52411
+ return sendWsMessage(s, wire);
52283
52412
  };
52284
52413
  const sendResult = (result) => {
52285
- const encryptedFields = result.type === "prompt_result" ? ["output", "error"] : [];
52286
- sendBridgeMessage(result, encryptedFields);
52414
+ const sent = sendBridgeMessage(result, result.type === "prompt_result" ? ["output", "error"] : []);
52415
+ if (!sent && result.type === "prompt_result") {
52416
+ enqueuePendingPromptResult(result);
52417
+ deps.log("[Bridge service] prompt_result deferred until bridge reconnect.");
52418
+ }
52287
52419
  if (result.type === "prompt_result") {
52288
52420
  const pr = result;
52289
52421
  const cancelled = pr.stopReason === "cancelled";
@@ -52296,24 +52428,11 @@ function createBridgePromptSenders(deps, getWs) {
52296
52428
  });
52297
52429
  }
52298
52430
  };
52299
- const sendSessionUpdate = (payload) => {
52300
- const s = getWs();
52301
- if (!s) {
52302
- deps.log("[Bridge service] Session update not sent: not connected to the bridge.");
52303
- return;
52304
- }
52305
- const p = payload;
52306
- const wire = p.type === "session_update" && deps.e2ee ? deps.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && deps.e2ee ? deps.e2ee.encryptFields(payload, [
52307
- "path",
52308
- "oldText",
52309
- "newText",
52310
- "patchContent",
52311
- "isDirectory",
52312
- "directoryRemoved"
52313
- ]) : payload;
52314
- sendWsMessage(s, wire);
52431
+ return {
52432
+ sendBridgeMessage,
52433
+ sendResult,
52434
+ sendSessionUpdate: (payload) => sendSessionUpdateWire(getWs, payload, { e2ee: deps.e2ee, log: deps.log })
52315
52435
  };
52316
- return { sendBridgeMessage, sendResult, sendSessionUpdate };
52317
52436
  }
52318
52437
 
52319
52438
  // src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
@@ -53197,25 +53316,59 @@ var handleInstallSkillsMessage = (msg, deps) => {
53197
53316
  })();
53198
53317
  };
53199
53318
 
53200
- // src/agents/install/commands/run-npm-global-install.ts
53201
- import { execFile as execFile9 } from "node:child_process";
53202
- import { promisify as promisify10 } from "node:util";
53203
-
53204
- // src/agents/install/format-command-output.ts
53205
- function formatCommandOutput(stdout, stderr) {
53206
- const parts = [String(stdout ?? "").trimEnd(), String(stderr ?? "").trimEnd()].filter(Boolean);
53207
- return parts.join("\n");
53319
+ // src/agents/install/run-streaming-command.ts
53320
+ import { spawn as spawn11 } from "node:child_process";
53321
+ import * as readline3 from "node:readline";
53322
+ function runStreamingCommand(command, args, options) {
53323
+ return new Promise((resolve37, reject) => {
53324
+ const child = spawn11(command, args, {
53325
+ env: options.env,
53326
+ stdio: ["ignore", "pipe", "pipe"]
53327
+ });
53328
+ let settled = false;
53329
+ const timer = options.timeoutMs != null ? setTimeout(() => {
53330
+ child.kill("SIGKILL");
53331
+ if (!settled) {
53332
+ settled = true;
53333
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
53334
+ }
53335
+ }, options.timeoutMs) : null;
53336
+ const onLine = (line) => {
53337
+ if (line.length > 0) options.onLine?.(line);
53338
+ };
53339
+ if (child.stdout) {
53340
+ readline3.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
53341
+ }
53342
+ if (child.stderr) {
53343
+ readline3.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
53344
+ }
53345
+ child.on("error", (err) => {
53346
+ if (timer) clearTimeout(timer);
53347
+ if (!settled) {
53348
+ settled = true;
53349
+ reject(err);
53350
+ }
53351
+ });
53352
+ child.on("close", (code, signal) => {
53353
+ if (timer) clearTimeout(timer);
53354
+ if (!settled) {
53355
+ settled = true;
53356
+ resolve37({ code, signal });
53357
+ }
53358
+ });
53359
+ });
53208
53360
  }
53209
53361
 
53210
53362
  // src/agents/install/commands/run-npm-global-install.ts
53211
- var execFileAsync8 = promisify10(execFile9);
53212
- async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
53213
- const { stdout, stderr } = await execFileAsync8("npm", ["install", "-g", packageName], {
53214
- timeout: timeoutMs,
53363
+ async function runNpmGlobalInstall(packageName, env, options) {
53364
+ const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
53215
53365
  env: bridgeAgentPathEnv(env),
53216
- maxBuffer: 10 * 1024 * 1024
53366
+ timeoutMs: options?.timeoutMs ?? 3e5,
53367
+ onLine: options?.onLine
53217
53368
  });
53218
- return formatCommandOutput(stdout, stderr);
53369
+ if (result.code !== 0) {
53370
+ throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
53371
+ }
53219
53372
  }
53220
53373
 
53221
53374
  // src/agents/install/commands/claude-code.ts
@@ -53223,11 +53376,12 @@ var claudeCodeInstallCommand = {
53223
53376
  agentType: "claude-code",
53224
53377
  detectCommand: "claude",
53225
53378
  async install(ctx) {
53226
- const logOutput = await runNpmGlobalInstall("@anthropic-ai/claude-code", {
53227
- ...ctx.env,
53228
- ANTHROPIC_API_KEY: ctx.authToken
53229
- });
53230
- ctx.onProgress?.("Installing Anthropic Claude Code", logOutput || void 0);
53379
+ ctx.onProgress?.("Installing Anthropic Claude Code");
53380
+ await runNpmGlobalInstall(
53381
+ "@anthropic-ai/claude-code",
53382
+ { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
53383
+ { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
53384
+ );
53231
53385
  }
53232
53386
  };
53233
53387
 
@@ -53236,34 +53390,34 @@ var codexAcpInstallCommand = {
53236
53390
  agentType: "codex-acp",
53237
53391
  detectCommand: "codex",
53238
53392
  async install(ctx) {
53239
- const logOutput = await runNpmGlobalInstall("@openai/codex", {
53240
- ...ctx.env,
53241
- OPENAI_API_KEY: ctx.authToken
53242
- });
53243
- ctx.onProgress?.("Installing Codex", logOutput || void 0);
53393
+ ctx.onProgress?.("Installing Codex");
53394
+ await runNpmGlobalInstall(
53395
+ "@openai/codex",
53396
+ { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
53397
+ { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
53398
+ );
53244
53399
  }
53245
53400
  };
53246
53401
 
53247
53402
  // src/agents/install/commands/cursor-cli.ts
53248
- import { execFile as execFile10 } from "node:child_process";
53249
- import { promisify as promisify11 } from "node:util";
53250
- var execFileAsync9 = promisify11(execFile10);
53251
53403
  var cursorCliInstallCommand = {
53252
53404
  agentType: "cursor-cli",
53253
53405
  detectCommand: "agent",
53254
53406
  alternateDetectCommands: ["cursor-agent"],
53255
53407
  async install(ctx) {
53256
- const { stdout, stderr } = await execFileAsync9(
53408
+ ctx.onProgress?.("Installing Cursor CLI");
53409
+ const result = await runStreamingCommand(
53257
53410
  "bash",
53258
53411
  ["-lc", "curl -fsSL https://cursor.com/install | bash"],
53259
53412
  {
53260
- timeout: 3e5,
53413
+ timeoutMs: 3e5,
53261
53414
  env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
53262
- maxBuffer: 10 * 1024 * 1024
53415
+ onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
53263
53416
  }
53264
53417
  );
53265
- const logOutput = formatCommandOutput(stdout, stderr);
53266
- ctx.onProgress?.("Installing Cursor CLI", logOutput || void 0);
53418
+ if (result.code !== 0) {
53419
+ throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
53420
+ }
53267
53421
  }
53268
53422
  };
53269
53423
 
@@ -53272,11 +53426,12 @@ var opencodeInstallCommand = {
53272
53426
  agentType: "opencode",
53273
53427
  detectCommand: "opencode",
53274
53428
  async install(ctx) {
53275
- const logOutput = await runNpmGlobalInstall("opencode-ai", {
53276
- ...ctx.env,
53277
- OPENCODE_API_KEY: ctx.authToken
53278
- });
53279
- ctx.onProgress?.("Installing OpenCode", logOutput || void 0);
53429
+ ctx.onProgress?.("Installing OpenCode");
53430
+ await runNpmGlobalInstall(
53431
+ "opencode-ai",
53432
+ { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
53433
+ { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
53434
+ );
53280
53435
  }
53281
53436
  };
53282
53437
 
@@ -53337,25 +53492,47 @@ var handleInstallAgentMessage = (msg, deps) => {
53337
53492
  if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
53338
53493
  void (async () => {
53339
53494
  const socket = deps.getWs();
53340
- const report = (step, message, logOutput) => {
53341
- if (socket) {
53342
- sendWsMessage(socket, {
53343
- type: "install_agent_progress",
53344
- processId,
53345
- agentId,
53346
- tokenId,
53347
- agentType,
53348
- step,
53349
- message,
53350
- ...logOutput ? { logOutput } : {}
53351
- });
53495
+ let pendingLines = [];
53496
+ let flushTimer = null;
53497
+ const sendProgress = (message, logOutput) => {
53498
+ if (!socket) return;
53499
+ sendWsMessage(socket, {
53500
+ type: "install_agent_progress",
53501
+ processId,
53502
+ agentId,
53503
+ tokenId,
53504
+ agentType,
53505
+ step: "agent_install_package",
53506
+ message,
53507
+ ...logOutput ? { logOutput } : {}
53508
+ });
53509
+ };
53510
+ const flushLines = (message) => {
53511
+ if (flushTimer) {
53512
+ clearTimeout(flushTimer);
53513
+ flushTimer = null;
53352
53514
  }
53515
+ if (pendingLines.length === 0) return;
53516
+ const logOutput = pendingLines.join("\n");
53517
+ pendingLines = [];
53518
+ sendProgress(message, logOutput);
53353
53519
  };
53354
53520
  const result = await installLocalAgentOnBridge({
53355
53521
  agentType,
53356
53522
  authToken,
53357
- onProgress: (message, logOutput) => report("agent_install_package", message, logOutput)
53523
+ onProgress: (message, logOutput) => {
53524
+ if (logOutput == null) {
53525
+ flushLines(message);
53526
+ sendProgress(message);
53527
+ return;
53528
+ }
53529
+ pendingLines.push(logOutput);
53530
+ if (!flushTimer) {
53531
+ flushTimer = setTimeout(() => flushLines(message), 100);
53532
+ }
53533
+ }
53358
53534
  });
53535
+ flushLines("Installing agent packages on the bridge machine.");
53359
53536
  if (socket) {
53360
53537
  sendWsMessage(socket, {
53361
53538
  type: "install_agent_result",
@@ -53367,9 +53544,7 @@ var handleInstallAgentMessage = (msg, deps) => {
53367
53544
  error: result.error
53368
53545
  });
53369
53546
  }
53370
- if (result.success) {
53371
- await deps.reportAutoDetectedAgents?.();
53372
- }
53547
+ if (result.success) await deps.reportAutoDetectedAgents?.();
53373
53548
  if (!result.success) {
53374
53549
  deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
53375
53550
  }
@@ -53954,6 +54129,10 @@ function createMainBridgeOpenHandler(params) {
53954
54129
  if (socket) {
53955
54130
  sendBridgeIdentify(socket, { identifyReportedPaths, e2ee });
53956
54131
  reportGitRepos(getWs, logFn);
54132
+ flushPendingPromptResults(
54133
+ getWs,
54134
+ (message) => e2ee ? e2ee.encryptFields(message, ["output", "error"]) : message
54135
+ );
53957
54136
  try {
53958
54137
  onBridgeSocketOpen?.();
53959
54138
  } catch {
@@ -54098,7 +54277,7 @@ async function createBridgeConnection(options) {
54098
54277
  }
54099
54278
 
54100
54279
  // src/e2e-certificates/key-command.ts
54101
- import * as readline3 from "node:readline";
54280
+ import * as readline4 from "node:readline";
54102
54281
  function installE2eCertificateKeyCommand({
54103
54282
  log: log2,
54104
54283
  onOpenCertificate,
@@ -54109,7 +54288,7 @@ function installE2eCertificateKeyCommand({
54109
54288
  return () => {
54110
54289
  };
54111
54290
  }
54112
- readline3.emitKeypressEvents(process.stdin);
54291
+ readline4.emitKeypressEvents(process.stdin);
54113
54292
  process.stdin.setRawMode(true);
54114
54293
  process.stdin.resume();
54115
54294
  const onKeypress = (str, key) => {
@@ -54150,32 +54329,42 @@ async function openE2eCertificateImportUrl({
54150
54329
  }
54151
54330
  }
54152
54331
 
54153
- // src/run-bridge-connected.ts
54332
+ // src/run-bridge-e2ee-key-command.ts
54333
+ function installConnectedBridgeE2eeKeyCommand(params) {
54334
+ let openingCertificate = false;
54335
+ return installE2eCertificateKeyCommand({
54336
+ log: params.log,
54337
+ onInterrupt: params.onInterrupt,
54338
+ onOpenCertificate: () => {
54339
+ if (openingCertificate) return;
54340
+ openingCertificate = true;
54341
+ void openE2eCertificateImportUrl({
54342
+ apiUrl: params.apiUrl,
54343
+ workspaceId: params.workspaceId,
54344
+ certificate: params.e2eCertificate,
54345
+ log: params.log
54346
+ }).finally(() => {
54347
+ openingCertificate = false;
54348
+ });
54349
+ }
54350
+ });
54351
+ }
54352
+
54353
+ // src/run-bridge-connected-signals.ts
54354
+ init_log();
54154
54355
  init_cli_process_interrupt();
54155
- init_cli_database();
54156
- async function runConnectedBridge(options, restartWithoutAuth) {
54157
- const {
54158
- apiUrl,
54159
- workspaceId,
54160
- authToken,
54161
- refreshToken,
54162
- justAuthenticated,
54163
- worktreesRootPath,
54164
- e2eCertificate
54165
- } = options;
54166
- const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
54167
- let cleanupKeyCommand;
54168
- let bridgeClose = null;
54356
+ function installConnectedBridgeSignals(params) {
54169
54357
  let shutdownStarted = false;
54170
54358
  const onSignal = (kind) => {
54171
54359
  requestCliImmediateShutdown();
54172
54360
  abortActiveGitChildProcesses();
54173
- cleanupKeyCommand?.();
54361
+ params.cleanupKeyCommand();
54174
54362
  if (shutdownStarted) return;
54175
54363
  shutdownStarted = true;
54176
54364
  logImmediate(
54177
54365
  kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
54178
54366
  );
54367
+ const bridgeClose = params.getBridgeClose();
54179
54368
  if (bridgeClose) {
54180
54369
  void bridgeClose().finally(() => process.exit(0));
54181
54370
  return;
@@ -54186,9 +54375,56 @@ async function runConnectedBridge(options, restartWithoutAuth) {
54186
54375
  const onSigTerm = () => onSignal("stop");
54187
54376
  process.on("SIGINT", onSigInt);
54188
54377
  process.on("SIGTERM", onSigTerm);
54189
- let handle;
54378
+ return {
54379
+ onSigInt,
54380
+ remove: () => {
54381
+ process.off("SIGINT", onSigInt);
54382
+ process.off("SIGTERM", onSigTerm);
54383
+ }
54384
+ };
54385
+ }
54386
+
54387
+ // src/run-bridge-on-auth-invalid.ts
54388
+ init_cli_process_interrupt();
54389
+ async function closeBridgeForReauth(params) {
54390
+ params.log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
54391
+ clearConfigForApi(params.apiUrl);
54392
+ await params.close();
54393
+ params.removeSignalHandlers();
54394
+ await clearCliImmediateShutdown();
54395
+ params.endConnectedSession();
54396
+ }
54397
+
54398
+ // src/run-bridge-connected.ts
54399
+ init_cli_database();
54400
+ async function runConnectedBridge(options, restartWithoutAuth) {
54401
+ const {
54402
+ apiUrl,
54403
+ workspaceId,
54404
+ authToken,
54405
+ refreshToken,
54406
+ justAuthenticated,
54407
+ worktreesRootPath,
54408
+ e2eCertificate
54409
+ } = options;
54410
+ const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
54411
+ let cleanupKeyCommand;
54412
+ let bridgeClose = null;
54413
+ let endConnectedSession;
54414
+ const sessionDone = new Promise((resolve37) => {
54415
+ endConnectedSession = resolve37;
54416
+ });
54417
+ let resolveHandleReady;
54418
+ const handleReady = new Promise((resolve37) => {
54419
+ resolveHandleReady = resolve37;
54420
+ });
54421
+ const handleRef = { current: null };
54422
+ const signals = installConnectedBridgeSignals({
54423
+ getBridgeClose: () => bridgeClose,
54424
+ cleanupKeyCommand: () => cleanupKeyCommand?.()
54425
+ });
54190
54426
  try {
54191
- handle = await createBridgeConnection({
54427
+ const handle = await createBridgeConnection({
54192
54428
  apiUrl,
54193
54429
  workspaceId,
54194
54430
  authToken,
@@ -54207,41 +54443,40 @@ async function runConnectedBridge(options, restartWithoutAuth) {
54207
54443
  },
54208
54444
  onAuthInvalid: () => {
54209
54445
  cleanupKeyCommand?.();
54210
- log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
54211
- clearConfigForApi(apiUrl);
54212
- void handle.close().then(() => {
54213
- void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
54214
- });
54446
+ void (async () => {
54447
+ await handleReady;
54448
+ await closeBridgeForReauth({
54449
+ apiUrl,
54450
+ log,
54451
+ close: async () => {
54452
+ if (handleRef.current) await handleRef.current.close();
54453
+ },
54454
+ removeSignalHandlers: signals.remove,
54455
+ endConnectedSession
54456
+ });
54457
+ })();
54215
54458
  }
54216
54459
  });
54217
- } catch (e) {
54218
- process.off("SIGINT", onSigInt);
54219
- process.off("SIGTERM", onSigTerm);
54220
- if (e instanceof CliSqliteInterrupted) {
54221
- process.exit(0);
54460
+ handleRef.current = handle;
54461
+ bridgeClose = () => handle.close();
54462
+ if (e2eCertificate) {
54463
+ cleanupKeyCommand = installConnectedBridgeE2eeKeyCommand({
54464
+ apiUrl,
54465
+ workspaceId,
54466
+ e2eCertificate,
54467
+ log,
54468
+ onInterrupt: signals.onSigInt
54469
+ });
54222
54470
  }
54471
+ } catch (e) {
54472
+ signals.remove();
54473
+ if (e instanceof CliSqliteInterrupted) process.exit(0);
54223
54474
  throw e;
54475
+ } finally {
54476
+ resolveHandleReady();
54224
54477
  }
54225
- bridgeClose = () => handle.close();
54226
- if (e2eCertificate) {
54227
- let openingCertificate = false;
54228
- cleanupKeyCommand = installE2eCertificateKeyCommand({
54229
- log,
54230
- onInterrupt: onSigInt,
54231
- onOpenCertificate: () => {
54232
- if (openingCertificate) return;
54233
- openingCertificate = true;
54234
- void openE2eCertificateImportUrl({
54235
- apiUrl,
54236
- workspaceId,
54237
- certificate: e2eCertificate,
54238
- log
54239
- }).finally(() => {
54240
- openingCertificate = false;
54241
- });
54242
- }
54243
- });
54244
- }
54478
+ await sessionDone;
54479
+ await restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
54245
54480
  }
54246
54481
 
54247
54482
  // src/run-bridge.ts
@@ -54285,12 +54520,16 @@ async function runBridge(options) {
54285
54520
  process.off("SIGINT", onSigInt);
54286
54521
  process.off("SIGTERM", onSigTerm);
54287
54522
  handle.close();
54288
- if (!auth) return;
54523
+ if (!auth) {
54524
+ log("Sign-in ended before a token was received.");
54525
+ return;
54526
+ }
54289
54527
  writeConfigForApi(apiUrl, {
54290
54528
  workspaceId: auth.workspaceId,
54291
54529
  token: auth.token,
54292
54530
  refreshToken: auth.refreshToken
54293
54531
  });
54532
+ log("Link established. Connecting with the new token\u2026");
54294
54533
  await runBridge({
54295
54534
  apiUrl,
54296
54535
  workspaceId: auth.workspaceId,