@buda-ai/connector 0.1.28 → 0.1.30

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.
Files changed (2) hide show
  1. package/dist/cli.js +70 -26
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -523,7 +523,7 @@ import path2 from "path";
523
523
  // package.json
524
524
  var package_default = {
525
525
  name: "@buda-ai/connector",
526
- version: "0.1.28",
526
+ version: "0.1.30",
527
527
  private: false,
528
528
  type: "module",
529
529
  publishConfig: {
@@ -2790,6 +2790,25 @@ var stopLiveDaemon = async (config, status, configRoot = getConfigRoot(), comman
2790
2790
  await stopUnresponsiveDaemonProcess(status.pid);
2791
2791
  return true;
2792
2792
  };
2793
+ var matchesDaemonIdentity = (config, status) => status.connectorId === config.connectorId && normalizeServerOrigin(status.serverUrl) === normalizeServerOrigin(config.serverUrl) && Number.isSafeInteger(status.pid) && status.pid > 0 && typeof status.instanceId === "string" && status.instanceId.length > 0;
2794
+ var readMatchingPersistedDaemonStatus = async (config, configRoot = getConfigRoot()) => {
2795
+ const status = await readPersistedDaemonStatus(config, configRoot).catch(() => null);
2796
+ return status && matchesDaemonIdentity(config, status) ? status : null;
2797
+ };
2798
+ var stopDaemonForIdentity = async (config, configRoot = getConfigRoot()) => {
2799
+ const liveStatus = await readLiveStatus(config, configRoot);
2800
+ if (liveStatus) {
2801
+ await stopLiveDaemon(config, liveStatus, configRoot);
2802
+ return;
2803
+ }
2804
+ const persistedStatus = await readMatchingPersistedDaemonStatus(config, configRoot);
2805
+ if (!persistedStatus || !isProcessAlive2(persistedStatus.pid)) return;
2806
+ const currentStatus = await readMatchingPersistedDaemonStatus(config, configRoot);
2807
+ if (!currentStatus || currentStatus.pid !== persistedStatus.pid || currentStatus.instanceId !== persistedStatus.instanceId || !isProcessAlive2(currentStatus.pid)) {
2808
+ return;
2809
+ }
2810
+ await stopUnresponsiveDaemonProcess(currentStatus.pid);
2811
+ };
2793
2812
  var shouldRestartUnhealthyDaemonForEnrollment = (status, explicitEnrollment) => explicitEnrollment && status.idle && status.heartbeatHealthy === false;
2794
2813
  var readDaemonLockOwnerPid = async (config) => {
2795
2814
  const lockPath = `${getConnectorDaemonLockTarget(
@@ -2978,9 +2997,7 @@ async function stopLocalConnectorDaemon(connectorId, serverUrl, configRoot = get
2978
2997
  (candidate) => candidate.connectorId === connectorId && normalizeServerOrigin(candidate.serverUrl) === serverOrigin
2979
2998
  );
2980
2999
  if (!config) throw new Error(`Local Connector ${connectorId} was not found`);
2981
- const status = await readLiveStatus(config, configRoot);
2982
- if (!status) return;
2983
- await stopLiveDaemon(config, status, configRoot);
3000
+ await stopDaemonForIdentity(config, configRoot);
2984
3001
  }
2985
3002
  async function stopAllLocalConnectorDaemons(configRoot = getConfigRoot()) {
2986
3003
  const configs = await listDeviceConfigs(configRoot);
@@ -2991,10 +3008,7 @@ async function stopAllLocalConnectorDaemons(configRoot = getConfigRoot()) {
2991
3008
  ${config.connectorId}`, config);
2992
3009
  }
2993
3010
  const results = await Promise.allSettled(
2994
- [...identities.values()].map(async (config) => {
2995
- const status = await readLiveStatus(config, configRoot);
2996
- if (status) await stopLiveDaemon(config, status, configRoot);
2997
- })
3011
+ [...identities.values()].map((config) => stopDaemonForIdentity(config, configRoot))
2998
3012
  );
2999
3013
  const failures = results.filter((result) => result.status === "rejected");
3000
3014
  if (failures.length) {
@@ -4704,6 +4718,7 @@ var isAlreadyExists3 = (error) => error instanceof Error && "code" in error && e
4704
4718
  // src/relay.ts
4705
4719
  var RELAY_PING_INTERVAL_MS = 2e4;
4706
4720
  var RELAY_PONG_TIMEOUT_MS = 1e4;
4721
+ var RELAY_ACTIVE_REQUEST_PONG_TIMEOUT_LIMIT = 2;
4707
4722
  var RELAY_HANDSHAKE_TIMEOUT_MS = 1e4;
4708
4723
  var RELAY_RECONNECT_MAX_MS = 3e4;
4709
4724
  var RELAY_RECONNECT_JITTER = 0.2;
@@ -4809,6 +4824,7 @@ function startConnectorRelay(config, bunnyDaemon, relayProtocol, workspaceRegist
4809
4824
  socket = ws;
4810
4825
  const inflight = /* @__PURE__ */ new Map();
4811
4826
  currentInflight = inflight;
4827
+ let consecutivePongTimeouts = 0;
4812
4828
  let detached = false;
4813
4829
  const detach = () => {
4814
4830
  if (detached) return;
@@ -4821,6 +4837,7 @@ function startConnectorRelay(config, bunnyDaemon, relayProtocol, workspaceRegist
4821
4837
  void writeLog("info", `relay connected ${relayUrl}`);
4822
4838
  hadOpenConnection = true;
4823
4839
  reconnectDelayMs = RELAY_RECONNECT_INTERVAL_MS;
4840
+ consecutivePongTimeouts = 0;
4824
4841
  pingTimer = setInterval(() => {
4825
4842
  if (ws.readyState !== WebSocket2.OPEN) return;
4826
4843
  try {
@@ -4832,18 +4849,33 @@ function startConnectorRelay(config, bunnyDaemon, relayProtocol, workspaceRegist
4832
4849
  }
4833
4850
  if (pongTimer) clearTimeout(pongTimer);
4834
4851
  pongTimer = setTimeout(() => {
4852
+ pongTimer = null;
4853
+ consecutivePongTimeouts += 1;
4854
+ if (inflight.size > 0 && consecutivePongTimeouts < RELAY_ACTIVE_REQUEST_PONG_TIMEOUT_LIMIT) {
4855
+ void writeLog(
4856
+ "warn",
4857
+ `relay pong timeout deferred while ${inflight.size} request(s) are active`
4858
+ );
4859
+ return;
4860
+ }
4835
4861
  void writeLog("warn", "relay pong timeout, terminating");
4836
4862
  ws.terminate();
4837
4863
  }, RELAY_PONG_TIMEOUT_MS);
4838
4864
  }, RELAY_PING_INTERVAL_MS);
4839
4865
  });
4840
4866
  ws.on("pong", () => {
4867
+ consecutivePongTimeouts = 0;
4841
4868
  if (pongTimer) {
4842
4869
  clearTimeout(pongTimer);
4843
4870
  pongTimer = null;
4844
4871
  }
4845
4872
  });
4846
4873
  ws.on("message", (raw) => {
4874
+ consecutivePongTimeouts = 0;
4875
+ if (pongTimer) {
4876
+ clearTimeout(pongTimer);
4877
+ pongTimer = null;
4878
+ }
4847
4879
  void handleRelayMessage(
4848
4880
  ws,
4849
4881
  bunnyDaemon,
@@ -5019,7 +5051,7 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5019
5051
  });
5020
5052
  executionIdentity = message.executionIdentity;
5021
5053
  } catch (error) {
5022
- sendRelayError(socket, message.requestId, error);
5054
+ await sendRelayError(socket, message.requestId, error).catch(() => void 0);
5023
5055
  return;
5024
5056
  }
5025
5057
  }
@@ -5105,7 +5137,7 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5105
5137
  durationMs: Date.now() - codingRunStartedAt
5106
5138
  });
5107
5139
  }
5108
- sendRelayMessage(socket, {
5140
+ await sendRelayMessage(socket, {
5109
5141
  type: "start",
5110
5142
  requestId: message.requestId,
5111
5143
  status: response.status,
@@ -5125,7 +5157,7 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5125
5157
  while (true) {
5126
5158
  const { value, done } = await reader.read();
5127
5159
  if (done) break;
5128
- sendRelayMessage(socket, {
5160
+ await sendRelayMessage(socket, {
5129
5161
  type: "chunk",
5130
5162
  requestId: message.requestId,
5131
5163
  data: binaryResponse ? Buffer.from(value).toString("base64") : decoder?.decode(value, { stream: true }) ?? "",
@@ -5134,7 +5166,7 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5134
5166
  }
5135
5167
  const tail = decoder?.decode() ?? "";
5136
5168
  if (tail) {
5137
- sendRelayMessage(socket, {
5169
+ await sendRelayMessage(socket, {
5138
5170
  type: "chunk",
5139
5171
  requestId: message.requestId,
5140
5172
  data: tail
@@ -5145,7 +5177,7 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5145
5177
  reader.releaseLock();
5146
5178
  }
5147
5179
  }
5148
- sendRelayMessage(socket, {
5180
+ await sendRelayMessage(socket, {
5149
5181
  type: "end",
5150
5182
  requestId: message.requestId
5151
5183
  });
@@ -5157,14 +5189,16 @@ async function handleRelayMessage(socket, bunnyDaemon, raw, inflight, expectedCo
5157
5189
  });
5158
5190
  }
5159
5191
  } catch (error) {
5192
+ controller.abort();
5160
5193
  if (codingRunTrace && codingRunStartedAt !== void 0) {
5161
5194
  await writeLog("error", "relay request coding run error", {
5162
5195
  ...codingRunTrace,
5163
5196
  status: codingRunStatus,
5164
- durationMs: Date.now() - codingRunStartedAt
5197
+ durationMs: Date.now() - codingRunStartedAt,
5198
+ error: formatConnectorRelayError(error)
5165
5199
  });
5166
5200
  }
5167
- sendRelayError(socket, message.requestId, error);
5201
+ await sendRelayError(socket, message.requestId, error).catch(() => void 0);
5168
5202
  } finally {
5169
5203
  inflight.delete(message.requestId);
5170
5204
  }
@@ -5218,17 +5252,20 @@ var normalizeWorkspaceRequest = (request, mounts) => {
5218
5252
  if (!mount || relative === void 0) {
5219
5253
  throw new ConnectorRelayProtocolError("WORKSPACE_MISMATCH");
5220
5254
  }
5221
- const env = body.env && typeof body.env === "object" && !Array.isArray(body.env) ? body.env : {};
5255
+ const systemEnv = body.systemEnv && typeof body.systemEnv === "object" && !Array.isArray(body.systemEnv) ? body.systemEnv : {};
5256
+ const workspaceEnv = {
5257
+ BUDA_AGENT_ROOT: mounts.agent,
5258
+ BUDA_SPACE_ROOT: mounts.space,
5259
+ BUDA_SYSTEM_ROOT: mounts.system
5260
+ };
5222
5261
  return {
5223
5262
  ...request,
5224
5263
  body: {
5225
5264
  ...body,
5226
5265
  cwd: path12.join(mount, relative),
5227
- env: {
5228
- ...env,
5229
- BUDA_AGENT_ROOT: mounts.agent,
5230
- BUDA_SPACE_ROOT: mounts.space,
5231
- BUDA_SYSTEM_ROOT: mounts.system
5266
+ systemEnv: {
5267
+ ...systemEnv,
5268
+ ...workspaceEnv
5232
5269
  }
5233
5270
  }
5234
5271
  };
@@ -5260,17 +5297,24 @@ var normalizeConnectorFilesystemRequest = (request, mounts) => {
5260
5297
  }
5261
5298
  return request;
5262
5299
  };
5263
- function sendRelayError(socket, requestId, error) {
5264
- sendRelayMessage(socket, {
5300
+ async function sendRelayError(socket, requestId, error) {
5301
+ await sendRelayMessage(socket, {
5265
5302
  type: "error",
5266
5303
  requestId,
5267
5304
  error: error instanceof Error ? error.message : String(error),
5268
5305
  ...error instanceof ConnectorRelayProtocolError ? { code: error.code } : {}
5269
5306
  });
5270
5307
  }
5271
- function sendRelayMessage(socket, message) {
5272
- if (socket.readyState !== WebSocket2.OPEN) return;
5273
- socket.send(JSON.stringify(message));
5308
+ async function sendRelayMessage(socket, message) {
5309
+ if (socket.readyState !== WebSocket2.OPEN) {
5310
+ throw new Error(`Connector relay socket closed before ${message.type} could be sent.`);
5311
+ }
5312
+ await new Promise((resolve, reject) => {
5313
+ socket.send(JSON.stringify(message), (error) => {
5314
+ if (error) reject(error);
5315
+ else resolve();
5316
+ });
5317
+ });
5274
5318
  }
5275
5319
  function headersToRecord(headers) {
5276
5320
  const result = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buda-ai/connector",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "publishConfig": {