@buildautomaton/cli 0.1.9 → 0.1.11

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
@@ -2236,7 +2236,7 @@ var require_websocket = __commonJS({
2236
2236
  "../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
2237
2237
  "use strict";
2238
2238
  var EventEmitter2 = __require("events");
2239
- var https3 = __require("https");
2239
+ var https2 = __require("https");
2240
2240
  var http = __require("http");
2241
2241
  var net = __require("net");
2242
2242
  var tls = __require("tls");
@@ -2771,7 +2771,7 @@ var require_websocket = __commonJS({
2771
2771
  }
2772
2772
  const defaultPort = isSecure ? 443 : 80;
2773
2773
  const key = randomBytes(16).toString("base64");
2774
- const request = isSecure ? https3.request : http.request;
2774
+ const request = isSecure ? https2.request : http.request;
2775
2775
  const protocolSet = /* @__PURE__ */ new Set();
2776
2776
  let perMessageDeflate;
2777
2777
  opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
@@ -22050,9 +22050,6 @@ var require_dist2 = __commonJS({
22050
22050
  }
22051
22051
  });
22052
22052
 
22053
- // src/bridge/connection/create-ws-bridge.ts
22054
- import https from "node:https";
22055
-
22056
22053
  // ../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
22057
22054
  var import_stream = __toESM(require_stream(), 1);
22058
22055
  var import_receiver = __toESM(require_receiver(), 1);
@@ -22073,26 +22070,77 @@ function applyCliOutboundNetworkPreferences() {
22073
22070
  }
22074
22071
  }
22075
22072
 
22073
+ // src/bridge/connection/cli-ws-client.ts
22074
+ import https from "node:https";
22075
+ var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
22076
+ function attachWebSocketClientPing(ws, intervalMs) {
22077
+ let timer = null;
22078
+ function clear() {
22079
+ if (timer != null) {
22080
+ clearInterval(timer);
22081
+ timer = null;
22082
+ }
22083
+ }
22084
+ clear();
22085
+ timer = setInterval(() => {
22086
+ if (ws.readyState === wrapper_default.OPEN) {
22087
+ try {
22088
+ ws.ping();
22089
+ } catch {
22090
+ }
22091
+ }
22092
+ }, intervalMs);
22093
+ return clear;
22094
+ }
22095
+ function buildCliWebSocketClientOptions(wsUrl) {
22096
+ const wsOptions = { perMessageDeflate: false, family: 4 };
22097
+ if (wsUrl.startsWith("wss://")) {
22098
+ wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
22099
+ }
22100
+ return wsOptions;
22101
+ }
22102
+ function logCliWebSocketError(log2, serviceLabel, err, detail) {
22103
+ const mid = detail ? ` ${detail}` : "";
22104
+ log2(`${serviceLabel} WebSocket error${mid}: ${err.message}`);
22105
+ }
22106
+ function safeCloseWebSocket(ws) {
22107
+ try {
22108
+ if (ws.readyState === wrapper_default.CLOSED) {
22109
+ ws.removeAllListeners();
22110
+ return;
22111
+ }
22112
+ ws.once("close", () => {
22113
+ ws.removeAllListeners();
22114
+ });
22115
+ ws.close();
22116
+ } catch {
22117
+ try {
22118
+ ws.removeAllListeners();
22119
+ } catch {
22120
+ }
22121
+ }
22122
+ }
22123
+ function safeSendWebSocketBinary(ws, data) {
22124
+ if (ws.readyState !== wrapper_default.OPEN) return false;
22125
+ try {
22126
+ ws.send(data, { binary: true });
22127
+ return true;
22128
+ } catch {
22129
+ return false;
22130
+ }
22131
+ }
22132
+
22076
22133
  // src/bridge/connection/create-ws-bridge.ts
22077
22134
  var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
22078
22135
  var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
22079
22136
  function createWsBridge(options) {
22080
22137
  const { url: url2, onMessage, onOpen, onClose, onError: onError2, onAuthInvalid, clientPingIntervalMs } = options;
22081
22138
  applyCliOutboundNetworkPreferences();
22082
- const wsOptions = {
22083
- perMessageDeflate: false,
22084
- family: 4
22085
- };
22086
- if (url2.startsWith("wss://")) {
22087
- wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
22088
- }
22089
- const ws = new wrapper_default(url2, wsOptions);
22090
- let clientPingTimer = null;
22091
- function clearClientPing() {
22092
- if (clientPingTimer != null) {
22093
- clearInterval(clientPingTimer);
22094
- clientPingTimer = null;
22095
- }
22139
+ const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
22140
+ let clearClientPing = null;
22141
+ function disposeClientPing() {
22142
+ clearClientPing?.();
22143
+ clearClientPing = null;
22096
22144
  }
22097
22145
  ws.on("unexpected-response", (request, response) => {
22098
22146
  const status = response?.statusCode ?? 0;
@@ -22103,16 +22151,9 @@ function createWsBridge(options) {
22103
22151
  }
22104
22152
  });
22105
22153
  ws.on("open", () => {
22106
- clearClientPing();
22154
+ disposeClientPing();
22107
22155
  if (clientPingIntervalMs != null && clientPingIntervalMs > 0) {
22108
- clientPingTimer = setInterval(() => {
22109
- if (ws.readyState === wrapper_default.OPEN) {
22110
- try {
22111
- ws.ping();
22112
- } catch {
22113
- }
22114
- }
22115
- }, clientPingIntervalMs);
22156
+ clearClientPing = attachWebSocketClientPing(ws, clientPingIntervalMs);
22116
22157
  }
22117
22158
  onOpen?.();
22118
22159
  });
@@ -22133,11 +22174,11 @@ function createWsBridge(options) {
22133
22174
  }
22134
22175
  });
22135
22176
  ws.on("close", (code, reason) => {
22136
- clearClientPing();
22177
+ disposeClientPing();
22137
22178
  onClose?.(code, reason.toString());
22138
22179
  });
22139
22180
  ws.on("error", (err) => {
22140
- clearClientPing();
22181
+ disposeClientPing();
22141
22182
  onError2?.(err);
22142
22183
  });
22143
22184
  return ws;
@@ -22823,12 +22864,64 @@ async function createSdkStdioAcpClient(options) {
22823
22864
  });
22824
22865
  }
22825
22866
 
22867
+ // src/net/transient-local-fetch-retry.ts
22868
+ var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
22869
+ function sleepMs(ms) {
22870
+ return new Promise((r) => setTimeout(r, ms));
22871
+ }
22872
+ function collectErrorText(err) {
22873
+ const parts = [];
22874
+ let e = err;
22875
+ for (let depth = 0; depth < 6 && e != null; depth += 1) {
22876
+ if (e instanceof Error) {
22877
+ parts.push(e.message);
22878
+ e = e.cause;
22879
+ } else {
22880
+ parts.push(String(e));
22881
+ break;
22882
+ }
22883
+ }
22884
+ return parts.join(" ").toLowerCase();
22885
+ }
22886
+ function isTransientLocalServiceError(err) {
22887
+ const text = collectErrorText(err);
22888
+ if (!text) return false;
22889
+ return text.includes("fetch failed") || text.includes("econnrefused") || text.includes("econnreset") || text.includes("epipe") || text.includes("etimedout") || text.includes("socket hang up") || text.includes("network connection lost") || text.includes("ecanceled") || text.includes("aborted") || text.includes("und_err_socket") || text.includes("other side closed") || text.includes("eai_again");
22890
+ }
22891
+ function isIdempotentHttpMethod(method) {
22892
+ const m = method.toUpperCase();
22893
+ return m === "GET" || m === "HEAD" || m === "OPTIONS";
22894
+ }
22895
+ async function fetchWithLocalTransientRetries(url2, init, options) {
22896
+ const method = (init?.method ?? "GET").toUpperCase();
22897
+ const allowRetry = isIdempotentHttpMethod(method);
22898
+ const delays = options?.delaysMs ?? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS;
22899
+ const maxAttempts = options?.maxAttempts ?? (allowRetry ? Math.max(1, delays.length + 1) : 1);
22900
+ let lastErr;
22901
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
22902
+ try {
22903
+ return await fetch(url2, init);
22904
+ } catch (e) {
22905
+ lastErr = e;
22906
+ const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
22907
+ if (!canRetry) throw e;
22908
+ const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
22909
+ await sleepMs(waitMs);
22910
+ }
22911
+ }
22912
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
22913
+ }
22914
+
22826
22915
  // src/firehose/proxy/local-proxy.ts
22827
22916
  var ALLOWED_HOSTS = ["localhost", "127.0.0.1", "::1"];
22828
22917
  function isAllowedHost(host) {
22829
22918
  const h = host.replace(/^\[|\]$/g, "");
22830
22919
  return ALLOWED_HOSTS.includes(host) || ALLOWED_HOSTS.includes(h);
22831
22920
  }
22921
+ function isIdempotentProxyMethod(method) {
22922
+ const m = method.toUpperCase();
22923
+ return m === "GET" || m === "HEAD" || m === "OPTIONS";
22924
+ }
22832
22925
  function checkUrlAndHost(request) {
22833
22926
  let url2;
22834
22927
  try {
@@ -22856,38 +22949,47 @@ async function proxyToLocal(request) {
22856
22949
  path: url2.pathname + url2.search,
22857
22950
  headers: request.headers
22858
22951
  };
22859
- return new Promise((resolve14) => {
22860
- const req = mod.request(opts, (res) => {
22861
- const chunks = [];
22862
- res.on("data", (c) => chunks.push(c));
22863
- res.on("end", () => {
22864
- const body = Buffer.concat(chunks).toString("utf8");
22865
- const headers = {};
22866
- for (const [k, v] of Object.entries(res.headers)) {
22867
- if (typeof v === "string") headers[k] = v;
22868
- else if (Array.isArray(v) && v[0]) headers[k] = v[0];
22869
- }
22952
+ const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
22953
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
22954
+ const once = await new Promise((resolve14) => {
22955
+ const req = mod.request(opts, (res) => {
22956
+ const chunks = [];
22957
+ res.on("data", (c) => chunks.push(c));
22958
+ res.on("end", () => {
22959
+ const body = Buffer.concat(chunks).toString("utf8");
22960
+ const headers = {};
22961
+ for (const [k, v] of Object.entries(res.headers)) {
22962
+ if (typeof v === "string") headers[k] = v;
22963
+ else if (Array.isArray(v) && v[0]) headers[k] = v[0];
22964
+ }
22965
+ resolve14({
22966
+ id: request.id,
22967
+ statusCode: res.statusCode ?? 0,
22968
+ headers,
22969
+ body
22970
+ });
22971
+ });
22972
+ });
22973
+ req.on("error", (err) => {
22870
22974
  resolve14({
22871
22975
  id: request.id,
22872
- statusCode: res.statusCode ?? 0,
22873
- headers,
22874
- body
22976
+ statusCode: 0,
22977
+ headers: {},
22978
+ body: "",
22979
+ error: err.message
22875
22980
  });
22876
22981
  });
22982
+ const method = request.method.toUpperCase();
22983
+ if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
22984
+ req.end();
22877
22985
  });
22878
- req.on("error", (err) => {
22879
- resolve14({
22880
- id: request.id,
22881
- statusCode: 0,
22882
- headers: {},
22883
- body: "",
22884
- error: err.message
22885
- });
22886
- });
22887
- const method = request.method.toUpperCase();
22888
- if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
22889
- req.end();
22890
- });
22986
+ const errMsg = once.error ?? "";
22987
+ const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
22988
+ if (!canRetry) return once;
22989
+ const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
22990
+ await sleepMs(waitMs);
22991
+ }
22992
+ throw new Error("Local proxy retry loop exited unexpectedly");
22891
22993
  }
22892
22994
  async function proxyToLocalStreaming(request, callbacks) {
22893
22995
  const checked = checkUrlAndHost(request);
@@ -22904,7 +23006,7 @@ async function proxyToLocalStreaming(request, callbacks) {
22904
23006
  if (request.body !== void 0 && request.body !== null && method !== "GET" && method !== "HEAD") {
22905
23007
  init.body = request.body;
22906
23008
  }
22907
- const res = await fetch(request.url, init);
23009
+ const res = await fetchWithLocalTransientRetries(request.url, init);
22908
23010
  const headers = {};
22909
23011
  res.headers.forEach((value, key) => {
22910
23012
  headers[key] = value;
@@ -23437,9 +23539,9 @@ function runPendingAuth(options) {
23437
23539
  keepaliveInterval = null;
23438
23540
  }
23439
23541
  if (ws) {
23440
- ws.removeAllListeners();
23441
- ws.close();
23542
+ const w = ws;
23442
23543
  ws = null;
23544
+ safeCloseWebSocket(w);
23443
23545
  }
23444
23546
  }
23445
23547
  function connect() {
@@ -23482,7 +23584,7 @@ function runPendingAuth(options) {
23482
23584
  connect();
23483
23585
  }, delay2);
23484
23586
  },
23485
- onError: (err) => logFn(`[Bridge service] WebSocket error while waiting for sign-in: ${err.message}`),
23587
+ onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
23486
23588
  onMessage: (data) => {
23487
23589
  const msg = data;
23488
23590
  if (msg.type === "auth_token" && typeof msg.token === "string") {
@@ -30037,14 +30139,50 @@ async function removeSessionWorktrees(paths, log2) {
30037
30139
  }
30038
30140
 
30039
30141
  // src/git/working-tree-status.ts
30040
- async function commitsAheadOfUpstream(repoDir) {
30041
- const g = simpleGit(repoDir);
30142
+ async function tryConfigGet(g, key) {
30143
+ try {
30144
+ const out = await g.raw(["config", "--get", key]);
30145
+ const v = String(out).trim();
30146
+ return v || null;
30147
+ } catch {
30148
+ return null;
30149
+ }
30150
+ }
30151
+ async function resolveRemoteTrackingRefForAhead(g) {
30042
30152
  try {
30043
30153
  await g.raw(["rev-parse", "--verify", "@{u}"]);
30154
+ return "@{u}";
30155
+ } catch {
30156
+ }
30157
+ const branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
30158
+ if (!branch || branch === "HEAD") return null;
30159
+ const remote = await tryConfigGet(g, `branch.${branch}.remote`) ?? "origin";
30160
+ const merge2 = await tryConfigGet(g, `branch.${branch}.merge`);
30161
+ if (merge2) {
30162
+ const upstreamBranch = merge2.replace(/^refs\/heads\//, "");
30163
+ const ref = `refs/remotes/${remote}/${upstreamBranch}`;
30164
+ try {
30165
+ await g.raw(["rev-parse", "--verify", ref]);
30166
+ return ref;
30167
+ } catch {
30168
+ }
30169
+ }
30170
+ const fallbackRef = `refs/remotes/${remote}/${branch}`;
30171
+ try {
30172
+ await g.raw(["rev-parse", "--verify", fallbackRef]);
30173
+ return fallbackRef;
30044
30174
  } catch {
30045
- return 0;
30175
+ return null;
30046
30176
  }
30047
- const out = await g.raw(["rev-list", "--count", "@{u}..HEAD"]);
30177
+ }
30178
+ async function commitsAheadOfRemoteTracking(repoDir) {
30179
+ const g = simpleGit(repoDir);
30180
+ const trackingRef = await resolveRemoteTrackingRefForAhead(g);
30181
+ if (!trackingRef) return 0;
30182
+ const localSha = (await g.raw(["rev-parse", "HEAD"])).trim();
30183
+ const remoteSha = (await g.raw(["rev-parse", trackingRef])).trim();
30184
+ if (localSha === remoteSha) return 0;
30185
+ const out = await g.raw(["rev-list", "--count", `${trackingRef}..HEAD`]);
30048
30186
  const n = parseInt(String(out).trim(), 10);
30049
30187
  return Number.isNaN(n) ? 0 : n;
30050
30188
  }
@@ -30052,7 +30190,7 @@ async function getRepoWorkingTreeStatus(repoDir) {
30052
30190
  const g = simpleGit(repoDir);
30053
30191
  const st = await g.status();
30054
30192
  const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
30055
- const ahead = await commitsAheadOfUpstream(repoDir);
30193
+ const ahead = await commitsAheadOfRemoteTracking(repoDir);
30056
30194
  return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
30057
30195
  }
30058
30196
  async function aggregateSessionPathsWorkingTreeStatus(paths) {
@@ -30068,7 +30206,7 @@ async function aggregateSessionPathsWorkingTreeStatus(paths) {
30068
30206
  async function pushAheadOfUpstreamForPaths(paths) {
30069
30207
  for (const p of paths) {
30070
30208
  const g = simpleGit(p);
30071
- const ahead = await commitsAheadOfUpstream(p);
30209
+ const ahead = await commitsAheadOfRemoteTracking(p);
30072
30210
  if (ahead <= 0) continue;
30073
30211
  await g.push();
30074
30212
  }
@@ -31343,13 +31481,13 @@ var DevServerManager = class {
31343
31481
  }
31344
31482
  };
31345
31483
 
31346
- // src/firehose/connect-firehose.ts
31347
- import https2 from "node:https";
31348
-
31349
31484
  // src/firehose/proxy/start-streaming-proxy.ts
31350
31485
  function startStreamingProxy(ws, log2, pr) {
31351
31486
  proxyToLocalStreaming(pr, {
31352
31487
  onStart: (statusCode, headers) => {
31488
+ if (ws.readyState !== wrapper_default.OPEN) {
31489
+ throw new Error("Preview stream interrupted (firehose connection closed)");
31490
+ }
31353
31491
  const forwardedHeaders = { ...headers };
31354
31492
  const ce = "content-encoding";
31355
31493
  const cl = "content-length";
@@ -31362,7 +31500,10 @@ function startStreamingProxy(ws, log2, pr) {
31362
31500
  },
31363
31501
  onChunk: (chunk) => {
31364
31502
  const idBuf = Buffer.from(pr.id, "utf8");
31365
- ws.send(Buffer.concat([idBuf, Buffer.from(chunk)]), { binary: true });
31503
+ const buf = Buffer.concat([idBuf, Buffer.from(chunk)]);
31504
+ if (!safeSendWebSocketBinary(ws, buf)) {
31505
+ throw new Error("Preview stream interrupted (firehose connection closed)");
31506
+ }
31366
31507
  },
31367
31508
  onEnd: () => sendWsMessage(ws, { type: "proxy_result_end", id: pr.id }),
31368
31509
  onError: (error40) => {
@@ -31480,22 +31621,15 @@ function tryConsumeBinaryProxyBody(raw, deps) {
31480
31621
  }
31481
31622
 
31482
31623
  // src/firehose/connect-firehose.ts
31483
- var FIREHOSE_CLIENT_PING_MS = 25e3;
31484
31624
  function connectFirehose(options) {
31485
31625
  const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
31486
31626
  const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
31487
31627
  applyCliOutboundNetworkPreferences();
31488
- const wsOptions = { perMessageDeflate: false, family: 4 };
31489
- if (wsUrl.startsWith("wss://")) {
31490
- wsOptions.agent = new https2.Agent({ rejectUnauthorized: false, family: 4 });
31491
- }
31492
- const ws = new wrapper_default(wsUrl, wsOptions);
31493
- let clientPingTimer = null;
31494
- function clearClientPing() {
31495
- if (clientPingTimer != null) {
31496
- clearInterval(clientPingTimer);
31497
- clientPingTimer = null;
31498
- }
31628
+ const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
31629
+ let clearClientPing = null;
31630
+ function disposeClientPing() {
31631
+ clearClientPing?.();
31632
+ clearClientPing = null;
31499
31633
  }
31500
31634
  const firehoseSend = (payload) => {
31501
31635
  sendWsMessage(ws, payload);
@@ -31509,15 +31643,8 @@ function connectFirehose(options) {
31509
31643
  startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
31510
31644
  };
31511
31645
  ws.on("open", () => {
31512
- clearClientPing();
31513
- clientPingTimer = setInterval(() => {
31514
- if (ws.readyState === wrapper_default.OPEN) {
31515
- try {
31516
- ws.ping();
31517
- } catch {
31518
- }
31519
- }
31520
- }, FIREHOSE_CLIENT_PING_MS);
31646
+ disposeClientPing();
31647
+ clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
31521
31648
  onOpen?.();
31522
31649
  devServerManager.attachFirehose(firehoseSend);
31523
31650
  sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
@@ -31533,24 +31660,23 @@ function connectFirehose(options) {
31533
31660
  }
31534
31661
  });
31535
31662
  ws.on("close", (code, reason) => {
31536
- clearClientPing();
31663
+ disposeClientPing();
31537
31664
  devServerManager.detachFirehose();
31538
31665
  const reasonStr = typeof reason === "string" ? reason : reason.toString();
31539
31666
  onClose?.(code, reasonStr);
31540
31667
  });
31541
31668
  ws.on("error", (err) => {
31542
- clearClientPing();
31543
- log2(`[Proxy and log service] WebSocket error: ${err.message}`);
31669
+ disposeClientPing();
31670
+ logCliWebSocketError(log2, "[Proxy and log service]", err);
31671
+ if (ws.readyState === wrapper_default.CONNECTING || ws.readyState === wrapper_default.OPEN) {
31672
+ safeCloseWebSocket(ws);
31673
+ }
31544
31674
  });
31545
31675
  return {
31546
31676
  close() {
31547
- clearClientPing();
31677
+ disposeClientPing();
31548
31678
  devServerManager.detachFirehose();
31549
- try {
31550
- ws.removeAllListeners();
31551
- ws.close();
31552
- } catch {
31553
- }
31679
+ safeCloseWebSocket(ws);
31554
31680
  },
31555
31681
  isConnected: () => ws.readyState === wrapper_default.OPEN
31556
31682
  };
@@ -32729,7 +32855,6 @@ async function refreshBridgeTokens(params) {
32729
32855
  }
32730
32856
 
32731
32857
  // src/bridge/connection/main-bridge-ws-lifecycle.ts
32732
- var BRIDGE_CLIENT_PING_MS = 25e3;
32733
32858
  function createMainBridgeWebSocketLifecycle(params) {
32734
32859
  const {
32735
32860
  state,
@@ -32787,6 +32912,11 @@ function createMainBridgeWebSocketLifecycle(params) {
32787
32912
  const prev = state.currentWs;
32788
32913
  if (prev) {
32789
32914
  prev.removeAllListeners();
32915
+ prev.once("error", () => {
32916
+ });
32917
+ prev.once("close", () => {
32918
+ prev.removeAllListeners();
32919
+ });
32790
32920
  try {
32791
32921
  prev.close();
32792
32922
  } catch {
@@ -32796,7 +32926,7 @@ function createMainBridgeWebSocketLifecycle(params) {
32796
32926
  const url2 = buildBridgeUrl(apiUrl, workspaceId, tokens.accessToken);
32797
32927
  state.currentWs = createWsBridge({
32798
32928
  url: url2,
32799
- clientPingIntervalMs: BRIDGE_CLIENT_PING_MS,
32929
+ clientPingIntervalMs: CLI_WEBSOCKET_CLIENT_PING_MS,
32800
32930
  onAuthInvalid: () => {
32801
32931
  if (authRefreshInFlight) return;
32802
32932
  void (async () => {
@@ -32832,7 +32962,7 @@ function createMainBridgeWebSocketLifecycle(params) {
32832
32962
  },
32833
32963
  onOpen: handleOpen,
32834
32964
  onClose: handleClose,
32835
- onError: (err) => logFn(`[Bridge service] WebSocket error: ${err.message}`),
32965
+ onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err),
32836
32966
  onMessage: (data) => handleBridgeMessage(data, messageDeps)
32837
32967
  });
32838
32968
  }