@evident-ai/cli 3.2.1-dev.5d79124 → 3.2.1-dev.6350432

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
@@ -1052,6 +1052,7 @@ var MAX_FILE_SYNC_DIRECTORIES = 16;
1052
1052
 
1053
1053
  // ../../packages/types/src/logging/index.ts
1054
1054
  var CORRELATION_ID_HEADER = "x-evident-correlation-id";
1055
+ var FORWARD_FAILURE_REASON_HEADER = "X-Evident-Failure-Reason";
1055
1056
  function log(level, event, fields) {
1056
1057
  const method = level === "debug" ? "log" : level;
1057
1058
  try {
@@ -2645,6 +2646,17 @@ var StreamForwarder = class {
2645
2646
  };
2646
2647
 
2647
2648
  // src/lib/tunnel/connection.ts
2649
+ var FAILURE_REASON_HEADER_LC = FORWARD_FAILURE_REASON_HEADER.toLowerCase();
2650
+ var TunnelUpgradeRejectedError = class extends Error {
2651
+ constructor(message, reason) {
2652
+ super(message);
2653
+ this.reason = reason;
2654
+ }
2655
+ };
2656
+ function classifyUpgradeRejection(headers) {
2657
+ const value = headers[FAILURE_REASON_HEADER_LC];
2658
+ return value === "do_code_updated" ? "do_code_updated" : "unknown";
2659
+ }
2648
2660
  var MAX_RECONNECT_DELAY = 3e4;
2649
2661
  var BASE_RECONNECT_DELAY = 500;
2650
2662
  function getReconnectDelay(attempt) {
@@ -2689,6 +2701,7 @@ function connectTunnel(options) {
2689
2701
  onError,
2690
2702
  onResponse,
2691
2703
  onInfo,
2704
+ onWarning,
2692
2705
  onDrainPing
2693
2706
  } = options;
2694
2707
  const tunnelUrl = getTunnelUrlConfig();
@@ -2708,8 +2721,11 @@ function connectTunnel(options) {
2708
2721
  reject(new Error("Connection timeout"));
2709
2722
  }, 3e4);
2710
2723
  let upgradeRejection = null;
2724
+ let upgradeRejectionReason = null;
2711
2725
  ws.on("unexpected-response", (_req, res) => {
2712
2726
  clearTimeout(connectionTimeout);
2727
+ const reason = classifyUpgradeRejection(res.headers);
2728
+ upgradeRejectionReason = reason;
2713
2729
  const chunks = [];
2714
2730
  res.on("data", (chunk) => chunks.push(chunk));
2715
2731
  res.on("end", () => {
@@ -2723,8 +2739,14 @@ function connectTunnel(options) {
2723
2739
  }
2724
2740
  const statusLine = `HTTP ${res.statusCode}${res.statusMessage ? ` ${res.statusMessage}` : ""}`;
2725
2741
  upgradeRejection = detail ? `${statusLine}: ${detail}` : statusLine;
2726
- onError?.(`Tunnel refused by relay (${upgradeRejection})`);
2727
- reject(new Error(`Tunnel handshake rejected: ${upgradeRejection}`));
2742
+ if (reason === "do_code_updated") {
2743
+ onWarning?.("Relay redeployed \u2014 reconnecting");
2744
+ } else {
2745
+ onError?.(`Tunnel refused by relay (${upgradeRejection})`);
2746
+ }
2747
+ reject(
2748
+ new TunnelUpgradeRejectedError(`Tunnel handshake rejected: ${upgradeRejection}`, reason)
2749
+ );
2728
2750
  });
2729
2751
  });
2730
2752
  ws.on("open", () => {
@@ -2770,8 +2792,14 @@ function connectTunnel(options) {
2770
2792
  ws.on("error", (error2) => {
2771
2793
  clearTimeout(connectionTimeout);
2772
2794
  const detail = upgradeRejection ?? describeSocketError(error2, url);
2773
- onError?.(`Connection error: ${detail}`);
2774
- reject(upgradeRejection ? new Error(upgradeRejection) : new Error(detail));
2795
+ if (upgradeRejectionReason === "do_code_updated") {
2796
+ onWarning?.("Relay redeployed \u2014 reconnecting");
2797
+ } else {
2798
+ onError?.(`Connection error: ${detail}`);
2799
+ }
2800
+ reject(
2801
+ upgradeRejectionReason !== null ? new TunnelUpgradeRejectedError(detail, upgradeRejectionReason) : new Error(detail)
2802
+ );
2775
2803
  });
2776
2804
  ws.on("close", (code, reason) => {
2777
2805
  const reasonStr = reason.toString() || upgradeRejection || (code === 1006 ? "abnormal closure" : "No reason provided");
@@ -2847,7 +2875,8 @@ var RunnerConnection = class {
2847
2875
  onError: (error2) => events.onError?.(error2),
2848
2876
  onResponse: () => events.onResponse?.(),
2849
2877
  onDrainPing: () => events.onDrainPing?.(),
2850
- onInfo: (message) => events.onInfo?.(message)
2878
+ onInfo: (message) => events.onInfo?.(message),
2879
+ onWarning: (message) => events.onWarning?.(message)
2851
2880
  });
2852
2881
  return;
2853
2882
  } catch (error2) {
@@ -2858,7 +2887,12 @@ var RunnerConnection = class {
2858
2887
  }
2859
2888
  const delay = getReconnectDelay(this.reconnectAttempt);
2860
2889
  events.onReconnecting?.(this.reconnectAttempt);
2861
- events.onError?.(`Connection failed, retrying in ${Math.round(delay / 1e3)}s...`);
2890
+ const retryMessage = `Connection failed, retrying in ${Math.round(delay / 1e3)}s...`;
2891
+ if (error2 instanceof TunnelUpgradeRejectedError && error2.reason === "do_code_updated") {
2892
+ events.onWarning?.(retryMessage);
2893
+ } else {
2894
+ events.onError?.(retryMessage);
2895
+ }
2862
2896
  await this.sleep(delay);
2863
2897
  }
2864
2898
  }
@@ -7889,6 +7923,13 @@ async function run(options) {
7889
7923
  logActivity(state, { type: "error", error: error2 });
7890
7924
  if (state.interactive) displayStatus(state);
7891
7925
  },
7926
+ // `warn`, not `info`: `forwardRunnerActivity`'s FORWARDED_LEVELS floor is
7927
+ // {'warn','error'}, so an `info` entry would never leave the machine and
7928
+ // an operator couldn't correlate a reconnect storm with a relay deploy.
7929
+ onWarning: (message) => {
7930
+ logActivity(state, { type: "info", level: "warn", message });
7931
+ if (state.interactive) displayStatus(state);
7932
+ },
7892
7933
  // Web traffic is proxied transparently; note opencode is live and stamp
7893
7934
  // proxied activity so the idle loop treats interactive proxy use as work.
7894
7935
  // Fires per forwarded response head (incl. every SSE open) and excludes