ds-harness-remote 0.4.8 → 0.4.9

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
@@ -16903,7 +16903,7 @@ function normalizeServerUrl(value) {
16903
16903
  }
16904
16904
 
16905
16905
  // src/version.ts
16906
- var PLUGIN_VERSION = "0.4.8";
16906
+ var PLUGIN_VERSION = "0.4.9";
16907
16907
 
16908
16908
  // src/server-api.ts
16909
16909
  var TERMINAL_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
@@ -18534,6 +18534,8 @@ var ClientModeRuntime = class {
18534
18534
  proxySwitch;
18535
18535
  gatewaySwitch;
18536
18536
  codexStreams = /* @__PURE__ */ new Map();
18537
+ connectionProgress;
18538
+ connectionProgressRun = 0;
18537
18539
  closed = false;
18538
18540
  async start() {
18539
18541
  if (this.closed) throw new Error("client remote-mode runtime is closed");
@@ -18562,7 +18564,15 @@ var ClientModeRuntime = class {
18562
18564
  ...targetStatus,
18563
18565
  connected: this.connected !== void 0,
18564
18566
  transport: this.connected?.client.getStats().mode ?? "Disconnected",
18567
+ connectedTargetDeviceId: this.connected?.target.deviceId,
18565
18568
  preferredTransports: this.config.forceRelay ? ["relay"] : ["lan", "p2p", "turn", "relay"],
18569
+ ...this.connectionProgress === void 0 ? {} : {
18570
+ connectionProgress: {
18571
+ targetDeviceId: this.connectionProgress.targetDeviceId,
18572
+ phase: this.connectionProgress.phase,
18573
+ ...this.connectionProgress.activeTransports === void 0 ? {} : { activeTransports: [...this.connectionProgress.activeTransports] }
18574
+ }
18575
+ },
18566
18576
  remoteFeatures: this.connected?.features ?? remoteHostFeatures(),
18567
18577
  ...this.pendingWorkspaceSelection === void 0 ? {} : { workspaceSelection: { ...this.pendingWorkspaceSelection } },
18568
18578
  backend: this.codexVirtual === void 0 ? "harness" : "codex",
@@ -18631,6 +18641,7 @@ var ClientModeRuntime = class {
18631
18641
  async clearClientAuthorization() {
18632
18642
  const previous = this.connected;
18633
18643
  this.connected = void 0;
18644
+ this.connectionProgress = void 0;
18634
18645
  this.pendingWorkspaceSelection = void 0;
18635
18646
  await this.closeCodexVirtual();
18636
18647
  this.proxySwitch?.selectLocal();
@@ -18658,6 +18669,7 @@ var ClientModeRuntime = class {
18658
18669
  this.gatewaySwitch.selectLocal();
18659
18670
  const previous2 = this.connected;
18660
18671
  this.connected = void 0;
18672
+ this.connectionProgress = void 0;
18661
18673
  this.pendingWorkspaceSelection = void 0;
18662
18674
  await this.closeCodexStreams(previous2?.client);
18663
18675
  await previous2?.client.close().catch(() => void 0);
@@ -18671,11 +18683,13 @@ var ClientModeRuntime = class {
18671
18683
  try {
18672
18684
  this.assertRemoteCompatible(next);
18673
18685
  } catch (error) {
18686
+ this.clearConnectionProgress(next.progressRunId);
18674
18687
  await next.client.close().catch(() => void 0);
18675
18688
  throw error;
18676
18689
  }
18677
18690
  const previous = this.connected;
18678
18691
  this.connected = next;
18692
+ this.clearConnectionProgress(next.progressRunId);
18679
18693
  this.pendingWorkspaceSelection = void 0;
18680
18694
  await this.closeCodexVirtual();
18681
18695
  this.selectRemoteTarget(next);
@@ -18818,6 +18832,7 @@ var ClientModeRuntime = class {
18818
18832
  await this.closeCodexStreams(this.connected?.client);
18819
18833
  await this.connected?.client.close().catch(() => void 0);
18820
18834
  this.connected = void 0;
18835
+ this.connectionProgress = void 0;
18821
18836
  this.proxySwitch?.restore();
18822
18837
  this.gatewaySwitch.restore();
18823
18838
  }
@@ -18999,57 +19014,62 @@ var ClientModeRuntime = class {
18999
19014
  }
19000
19015
  async connect(targetDeviceId, signal) {
19001
19016
  signal?.throwIfAborted();
19017
+ const progressRunId = this.connectionProgressRun + 1;
19018
+ this.connectionProgressRun = progressRunId;
19019
+ this.connectionProgress = { runId: progressRunId, targetDeviceId, phase: "checking-host" };
19002
19020
  const identity = this.requireIdentity();
19003
- const serverDevice = (await this.server.listDevices()).find((device) => device.deviceId === targetDeviceId);
19004
- if (serverDevice === void 0) {
19005
- throw new ClientModeError("MEMBERSHIP_REQUIRED", "The selected Host is not authorized for this account.");
19006
- }
19007
- const target = await this.authorizeHostPeer(serverDevice);
19008
- const presence = await this.server.presenceFor(targetDeviceId);
19009
- if (!presence.online) throw new ClientModeError("HOST_OFFLINE", "The selected Host is offline.", true);
19010
- const credentials = await this.server.authenticate(identity);
19011
- const rtcFactory = this.config.forceRelay ? void 0 : await this.rtcFactoryProvider({ routeTargets: [this.server.baseUrl] }).catch(() => void 0);
19012
- if (!this.config.forceRelay && rtcFactory === void 0) {
19013
- this.logger.warn("remote Harness WebRTC backend unavailable; using relay", {
19014
- targetDeviceId: shortId(target.deviceId)
19015
- });
19016
- }
19017
- let webRtcFallback = false;
19018
- const createTransport = (attempt) => new AdaptiveTransport(
19019
- websocketUrl(this.server.baseUrl),
19020
- {
19021
- role: "client",
19022
- deviceId: identity.deviceId,
19023
- accessToken: credentials.accessToken,
19024
- targetDeviceId,
19025
- forceRelay: this.config.forceRelay || attempt === "relay",
19026
- preferredTransports: preferredTransportsForAttempt(attempt),
19027
- negotiateTimeoutMs: attempt === "direct" ? DIRECT_WEBRTC_NEGOTIATE_TIMEOUT_MS : void 0,
19028
- ...rtcFactory === void 0 || attempt === "relay" ? {} : { rtcFactory },
19029
- fetchIceServers: async (connectionId) => iceServersForAttempt(attempt, await this.server.turnCredentials(connectionId)),
19030
- onWebRtcFallback: (error, diagnostics) => {
19031
- webRtcFallback = true;
19032
- this.logger.warn(attempt === "direct" ? "remote Harness direct WebRTC failed; trying TURN" : "remote Harness TURN WebRTC failed; using relay", {
19033
- targetDeviceId: shortId(target.deviceId),
19034
- attempt,
19035
- reason: diagnosticReason(error)
19036
- });
19037
- if (diagnostics !== void 0) {
19038
- this.logger.debug("remote Harness WebRTC fallback diagnostics", {
19021
+ let client;
19022
+ try {
19023
+ const serverDevice = (await this.server.listDevices()).find((device) => device.deviceId === targetDeviceId);
19024
+ if (serverDevice === void 0) {
19025
+ throw new ClientModeError("MEMBERSHIP_REQUIRED", "The selected Host is not authorized for this account.");
19026
+ }
19027
+ this.updateConnectionProgress(progressRunId, "authorizing-peer");
19028
+ const target = await this.authorizeHostPeer(serverDevice);
19029
+ const presence = await this.server.presenceFor(targetDeviceId);
19030
+ if (!presence.online) throw new ClientModeError("HOST_OFFLINE", "The selected Host is offline.", true);
19031
+ const credentials = await this.server.authenticate(identity);
19032
+ const rtcFactory = this.config.forceRelay ? void 0 : await this.rtcFactoryProvider({ routeTargets: [this.server.baseUrl] }).catch(() => void 0);
19033
+ if (!this.config.forceRelay && rtcFactory === void 0) {
19034
+ this.logger.warn("remote Harness WebRTC backend unavailable; using relay", {
19035
+ targetDeviceId: shortId(target.deviceId)
19036
+ });
19037
+ }
19038
+ let webRtcFallback = false;
19039
+ const createTransport = (attempt) => new AdaptiveTransport(
19040
+ websocketUrl(this.server.baseUrl),
19041
+ {
19042
+ role: "client",
19043
+ deviceId: identity.deviceId,
19044
+ accessToken: credentials.accessToken,
19045
+ targetDeviceId,
19046
+ forceRelay: this.config.forceRelay || attempt === "relay",
19047
+ preferredTransports: preferredTransportsForAttempt(attempt),
19048
+ negotiateTimeoutMs: attempt === "direct" ? DIRECT_WEBRTC_NEGOTIATE_TIMEOUT_MS : void 0,
19049
+ ...rtcFactory === void 0 || attempt === "relay" ? {} : { rtcFactory },
19050
+ fetchIceServers: async (connectionId) => iceServersForAttempt(attempt, await this.server.turnCredentials(connectionId)),
19051
+ onWebRtcFallback: (error, diagnostics) => {
19052
+ webRtcFallback = true;
19053
+ this.logger.warn(attempt === "direct" ? "remote Harness direct WebRTC failed; trying TURN" : "remote Harness TURN WebRTC failed; using relay", {
19039
19054
  targetDeviceId: shortId(target.deviceId),
19040
19055
  attempt,
19041
- ...webrtcDiagnosticsLogFields(diagnostics)
19056
+ reason: diagnosticReason(error)
19042
19057
  });
19058
+ if (diagnostics !== void 0) {
19059
+ this.logger.debug("remote Harness WebRTC fallback diagnostics", {
19060
+ targetDeviceId: shortId(target.deviceId),
19061
+ attempt,
19062
+ ...webrtcDiagnosticsLogFields(diagnostics)
19063
+ });
19064
+ }
19043
19065
  }
19044
19066
  }
19045
- }
19046
- );
19047
- const attempts = this.config.forceRelay || rtcFactory === void 0 ? ["relay"] : ["direct", "turn", "relay"];
19048
- let transport;
19049
- let client;
19050
- try {
19067
+ );
19068
+ const attempts = this.config.forceRelay || rtcFactory === void 0 ? ["relay"] : ["direct", "turn", "relay"];
19069
+ let transport;
19051
19070
  for (const attempt of attempts) {
19052
19071
  webRtcFallback = false;
19072
+ this.updateConnectionProgress(progressRunId, "probing", activeTransportsForAttempt(attempt));
19053
19073
  transport = createTransport(attempt);
19054
19074
  client = new RemoteClientCore(new ClientSecureTransport(transport, identity, target), 6e4);
19055
19075
  await client.connect();
@@ -19069,9 +19089,16 @@ var ClientModeRuntime = class {
19069
19089
  }
19070
19090
  const connectedClient = client;
19071
19091
  const connectedTransport = transport;
19092
+ const connectedPreference = transportPreferenceForMode(connectedClient.getStats().mode);
19093
+ this.updateConnectionProgress(
19094
+ progressRunId,
19095
+ "connected",
19096
+ connectedPreference === void 0 ? void 0 : [connectedPreference]
19097
+ );
19072
19098
  connectedClient.onClose(() => {
19073
19099
  if (this.connected?.client !== connectedClient) return;
19074
19100
  this.connected = void 0;
19101
+ this.connectionProgress = void 0;
19075
19102
  this.pendingWorkspaceSelection = void 0;
19076
19103
  void this.closeCodexVirtual();
19077
19104
  this.proxySwitch?.selectLocal();
@@ -19103,9 +19130,11 @@ var ClientModeRuntime = class {
19103
19130
  target,
19104
19131
  transport: connectedTransport,
19105
19132
  features,
19133
+ progressRunId,
19106
19134
  ...serverDevice.clientVersion === void 0 ? {} : { clientVersion: serverDevice.clientVersion }
19107
19135
  };
19108
19136
  } catch (error) {
19137
+ this.clearConnectionProgress(progressRunId);
19109
19138
  await client?.close().catch(() => void 0);
19110
19139
  throw error;
19111
19140
  }
@@ -19115,9 +19144,22 @@ var ClientModeRuntime = class {
19115
19144
  const next = await this.connect(targetDeviceId, signal);
19116
19145
  const previous = this.connected;
19117
19146
  this.connected = next;
19147
+ this.clearConnectionProgress(next.progressRunId);
19118
19148
  await previous?.client.close().catch(() => void 0);
19119
19149
  return next;
19120
19150
  }
19151
+ updateConnectionProgress(runId, phase, activeTransports) {
19152
+ if (this.connectionProgress?.runId !== runId) return;
19153
+ this.connectionProgress = {
19154
+ runId,
19155
+ targetDeviceId: this.connectionProgress.targetDeviceId,
19156
+ phase,
19157
+ ...activeTransports === void 0 ? {} : { activeTransports }
19158
+ };
19159
+ }
19160
+ clearConnectionProgress(runId) {
19161
+ if (this.connectionProgress?.runId === runId) this.connectionProgress = void 0;
19162
+ }
19121
19163
  async handleControl(endpoint, payload, signal) {
19122
19164
  try {
19123
19165
  if (endpoint === "status") return ok2(await this.detailedStatus());
@@ -19486,6 +19528,17 @@ function preferredTransportsForAttempt(attempt) {
19486
19528
  if (attempt === "turn") return ["turn", "relay"];
19487
19529
  return ["relay"];
19488
19530
  }
19531
+ function activeTransportsForAttempt(attempt) {
19532
+ if (attempt === "direct") return ["lan", "p2p"];
19533
+ return [attempt];
19534
+ }
19535
+ function transportPreferenceForMode(mode) {
19536
+ if (mode === "LAN") return "lan";
19537
+ if (mode === "P2P") return "p2p";
19538
+ if (mode === "TURN") return "turn";
19539
+ if (mode === "Relay") return "relay";
19540
+ return void 0;
19541
+ }
19489
19542
  function iceServersForAttempt(attempt, iceServers) {
19490
19543
  return attempt === "direct" ? stunOnlyIceServers(iceServers) : iceServers;
19491
19544
  }