@blue-soda/dsh-remote 0.5.6 → 0.5.7

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 (232) hide show
  1. package/README.md +2 -2
  2. package/cordis.patch.yml +30 -30
  3. package/dist/client.github.js +1 -1
  4. package/dist/client.js +1 -1
  5. package/dist/index.js +321 -57
  6. package/dist/index.js.map +3 -3
  7. package/dsh-plugin.json +41 -41
  8. package/package.json +165 -165
  9. package/dist/acp.d.ts +0 -75
  10. package/dist/acp.d.ts.map +0 -1
  11. package/dist/acp.js +0 -61
  12. package/dist/acp.js.map +0 -1
  13. package/dist/api-proxy-switch.d.ts +0 -33
  14. package/dist/api-proxy-switch.d.ts.map +0 -1
  15. package/dist/api-proxy-switch.js +0 -109
  16. package/dist/api-proxy-switch.js.map +0 -1
  17. package/dist/atomic-file.d.ts +0 -16
  18. package/dist/atomic-file.d.ts.map +0 -1
  19. package/dist/atomic-file.js +0 -81
  20. package/dist/atomic-file.js.map +0 -1
  21. package/dist/bin/doctor.d.ts +0 -3
  22. package/dist/bin/doctor.d.ts.map +0 -1
  23. package/dist/bin/doctor.js +0 -13
  24. package/dist/bin/doctor.js.map +0 -1
  25. package/dist/cli.d.ts +0 -32
  26. package/dist/cli.d.ts.map +0 -1
  27. package/dist/cli.js +0 -289
  28. package/dist/cli.js.map +0 -1
  29. package/dist/client-runtime.d.ts +0 -375
  30. package/dist/client-runtime.d.ts.map +0 -1
  31. package/dist/client-runtime.js +0 -1768
  32. package/dist/client-runtime.js.map +0 -1
  33. package/dist/client-secure-transport.d.ts +0 -23
  34. package/dist/client-secure-transport.d.ts.map +0 -1
  35. package/dist/client-secure-transport.js +0 -144
  36. package/dist/client-secure-transport.js.map +0 -1
  37. package/dist/client-target-store.d.ts +0 -40
  38. package/dist/client-target-store.d.ts.map +0 -1
  39. package/dist/client-target-store.js +0 -79
  40. package/dist/client-target-store.js.map +0 -1
  41. package/dist/client.d.ts +0 -13
  42. package/dist/client.d.ts.map +0 -1
  43. package/dist/codex/app-server.d.ts +0 -71
  44. package/dist/codex/app-server.d.ts.map +0 -1
  45. package/dist/codex/app-server.js +0 -268
  46. package/dist/codex/app-server.js.map +0 -1
  47. package/dist/codex/codex-image-codec.d.ts +0 -7
  48. package/dist/codex/codex-image-codec.d.ts.map +0 -1
  49. package/dist/codex/codex-image-codec.js +0 -288
  50. package/dist/codex/codex-image-codec.js.map +0 -1
  51. package/dist/codex/domain.d.ts +0 -102
  52. package/dist/codex/domain.d.ts.map +0 -1
  53. package/dist/codex/domain.js +0 -1323
  54. package/dist/codex/domain.js.map +0 -1
  55. package/dist/codex/method-policy.d.ts +0 -338
  56. package/dist/codex/method-policy.d.ts.map +0 -1
  57. package/dist/codex/method-policy.js +0 -141
  58. package/dist/codex/method-policy.js.map +0 -1
  59. package/dist/codex/peer-bridge.d.ts +0 -57
  60. package/dist/codex/peer-bridge.d.ts.map +0 -1
  61. package/dist/codex/peer-bridge.js +0 -299
  62. package/dist/codex/peer-bridge.js.map +0 -1
  63. package/dist/codex/permissions.d.ts +0 -4
  64. package/dist/codex/permissions.d.ts.map +0 -1
  65. package/dist/codex/permissions.js +0 -21
  66. package/dist/codex/permissions.js.map +0 -1
  67. package/dist/codex/session-id.d.ts +0 -10
  68. package/dist/codex/session-id.d.ts.map +0 -1
  69. package/dist/codex/session-id.js +0 -15
  70. package/dist/codex/session-id.js.map +0 -1
  71. package/dist/codex/virtual-harness.d.ts +0 -209
  72. package/dist/codex/virtual-harness.d.ts.map +0 -1
  73. package/dist/codex/virtual-harness.js +0 -2650
  74. package/dist/codex/virtual-harness.js.map +0 -1
  75. package/dist/codex-workspace-bridge.d.ts +0 -108
  76. package/dist/codex-workspace-bridge.d.ts.map +0 -1
  77. package/dist/codex-workspace-bridge.js +0 -502
  78. package/dist/codex-workspace-bridge.js.map +0 -1
  79. package/dist/config.d.ts +0 -99
  80. package/dist/config.d.ts.map +0 -1
  81. package/dist/config.js +0 -127
  82. package/dist/config.js.map +0 -1
  83. package/dist/connection-controller.d.ts +0 -44
  84. package/dist/connection-controller.d.ts.map +0 -1
  85. package/dist/connection-controller.js +0 -185
  86. package/dist/connection-controller.js.map +0 -1
  87. package/dist/control-route.d.ts +0 -34
  88. package/dist/control-route.d.ts.map +0 -1
  89. package/dist/control-route.js +0 -136
  90. package/dist/control-route.js.map +0 -1
  91. package/dist/control-runtime.d.ts +0 -138
  92. package/dist/control-runtime.d.ts.map +0 -1
  93. package/dist/control-runtime.js +0 -543
  94. package/dist/control-runtime.js.map +0 -1
  95. package/dist/control-stream.d.ts +0 -67
  96. package/dist/control-stream.d.ts.map +0 -1
  97. package/dist/control-stream.js +0 -179
  98. package/dist/control-stream.js.map +0 -1
  99. package/dist/defaults.d.ts +0 -9
  100. package/dist/defaults.d.ts.map +0 -1
  101. package/dist/defaults.js +0 -9
  102. package/dist/defaults.js.map +0 -1
  103. package/dist/file-viewer-bridge.d.ts +0 -30
  104. package/dist/file-viewer-bridge.d.ts.map +0 -1
  105. package/dist/file-viewer-bridge.js +0 -128
  106. package/dist/file-viewer-bridge.js.map +0 -1
  107. package/dist/file-viewer-contract.d.ts +0 -5
  108. package/dist/file-viewer-contract.d.ts.map +0 -1
  109. package/dist/file-viewer-contract.js +0 -4
  110. package/dist/file-viewer-contract.js.map +0 -1
  111. package/dist/harness-api-bridge.d.ts +0 -81
  112. package/dist/harness-api-bridge.d.ts.map +0 -1
  113. package/dist/harness-api-bridge.js +0 -862
  114. package/dist/harness-api-bridge.js.map +0 -1
  115. package/dist/harness-api-history.d.ts +0 -3
  116. package/dist/harness-api-history.d.ts.map +0 -1
  117. package/dist/harness-api-history.js +0 -59
  118. package/dist/harness-api-history.js.map +0 -1
  119. package/dist/harness-remote-bridge.d.ts +0 -60
  120. package/dist/harness-remote-bridge.d.ts.map +0 -1
  121. package/dist/harness-remote-bridge.js +0 -540
  122. package/dist/harness-remote-bridge.js.map +0 -1
  123. package/dist/harness-version.d.ts +0 -23
  124. package/dist/harness-version.d.ts.map +0 -1
  125. package/dist/harness-version.js +0 -95
  126. package/dist/harness-version.js.map +0 -1
  127. package/dist/identity-store.d.ts +0 -45
  128. package/dist/identity-store.d.ts.map +0 -1
  129. package/dist/identity-store.js +0 -186
  130. package/dist/identity-store.js.map +0 -1
  131. package/dist/ids.d.ts +0 -2
  132. package/dist/ids.d.ts.map +0 -1
  133. package/dist/ids.js +0 -17
  134. package/dist/ids.js.map +0 -1
  135. package/dist/index.d.ts +0 -78
  136. package/dist/index.d.ts.map +0 -1
  137. package/dist/logging.d.ts +0 -18
  138. package/dist/logging.d.ts.map +0 -1
  139. package/dist/logging.js +0 -30
  140. package/dist/logging.js.map +0 -1
  141. package/dist/loopback-host.d.ts +0 -20
  142. package/dist/loopback-host.d.ts.map +0 -1
  143. package/dist/loopback-host.js +0 -245
  144. package/dist/loopback-host.js.map +0 -1
  145. package/dist/loopback-preview.d.ts +0 -19
  146. package/dist/loopback-preview.d.ts.map +0 -1
  147. package/dist/loopback-preview.js +0 -232
  148. package/dist/loopback-preview.js.map +0 -1
  149. package/dist/native-rtc-helper.d.ts +0 -14
  150. package/dist/native-rtc-helper.d.ts.map +0 -1
  151. package/dist/native-rtc-helper.js +0 -575
  152. package/dist/native-rtc-helper.js.map +0 -1
  153. package/dist/remote-api-proxy.d.ts +0 -17
  154. package/dist/remote-api-proxy.d.ts.map +0 -1
  155. package/dist/remote-api-proxy.js +0 -451
  156. package/dist/remote-api-proxy.js.map +0 -1
  157. package/dist/remote-directory-browser.d.ts +0 -16
  158. package/dist/remote-directory-browser.d.ts.map +0 -1
  159. package/dist/remote-directory-browser.js +0 -48
  160. package/dist/remote-directory-browser.js.map +0 -1
  161. package/dist/remote-file-content-provider.d.ts +0 -48
  162. package/dist/remote-file-content-provider.d.ts.map +0 -1
  163. package/dist/remote-file-content-provider.js +0 -93
  164. package/dist/remote-file-content-provider.js.map +0 -1
  165. package/dist/remote-typert-gateway.d.ts +0 -20
  166. package/dist/remote-typert-gateway.d.ts.map +0 -1
  167. package/dist/remote-typert-gateway.js +0 -334
  168. package/dist/remote-typert-gateway.js.map +0 -1
  169. package/dist/rpc-binary-attachments.d.ts +0 -33
  170. package/dist/rpc-binary-attachments.d.ts.map +0 -1
  171. package/dist/rpc-binary-attachments.js +0 -142
  172. package/dist/rpc-binary-attachments.js.map +0 -1
  173. package/dist/rpc-router.d.ts +0 -31
  174. package/dist/rpc-router.d.ts.map +0 -1
  175. package/dist/rpc-router.js +0 -201
  176. package/dist/rpc-router.js.map +0 -1
  177. package/dist/safe-error.d.ts +0 -8
  178. package/dist/safe-error.d.ts.map +0 -1
  179. package/dist/safe-error.js +0 -20
  180. package/dist/safe-error.js.map +0 -1
  181. package/dist/server-api.d.ts +0 -109
  182. package/dist/server-api.d.ts.map +0 -1
  183. package/dist/server-api.js +0 -520
  184. package/dist/server-api.js.map +0 -1
  185. package/dist/server-connection.d.ts +0 -79
  186. package/dist/server-connection.d.ts.map +0 -1
  187. package/dist/server-connection.js +0 -1023
  188. package/dist/server-connection.js.map +0 -1
  189. package/dist/server-credentials.d.ts +0 -55
  190. package/dist/server-credentials.d.ts.map +0 -1
  191. package/dist/server-credentials.js +0 -108
  192. package/dist/server-credentials.js.map +0 -1
  193. package/dist/service.d.ts +0 -151
  194. package/dist/service.d.ts.map +0 -1
  195. package/dist/service.js +0 -448
  196. package/dist/service.js.map +0 -1
  197. package/dist/session-format-compat.d.ts +0 -3
  198. package/dist/session-format-compat.d.ts.map +0 -1
  199. package/dist/session-format-compat.js +0 -183
  200. package/dist/session-format-compat.js.map +0 -1
  201. package/dist/status-stream.d.ts +0 -48
  202. package/dist/status-stream.d.ts.map +0 -1
  203. package/dist/status-stream.js +0 -133
  204. package/dist/status-stream.js.map +0 -1
  205. package/dist/terminal-policy.d.ts +0 -21
  206. package/dist/terminal-policy.d.ts.map +0 -1
  207. package/dist/terminal-policy.js +0 -68
  208. package/dist/terminal-policy.js.map +0 -1
  209. package/dist/tui-command.d.ts +0 -13
  210. package/dist/tui-command.d.ts.map +0 -1
  211. package/dist/tui-command.js +0 -392
  212. package/dist/tui-command.js.map +0 -1
  213. package/dist/typert-gateway-contract.d.ts +0 -59
  214. package/dist/typert-gateway-contract.d.ts.map +0 -1
  215. package/dist/typert-gateway-contract.js +0 -2
  216. package/dist/typert-gateway-contract.js.map +0 -1
  217. package/dist/typert-gateway-switch.d.ts +0 -85
  218. package/dist/typert-gateway-switch.d.ts.map +0 -1
  219. package/dist/typert-gateway-switch.js +0 -448
  220. package/dist/typert-gateway-switch.js.map +0 -1
  221. package/dist/types.d.ts +0 -20
  222. package/dist/types.d.ts.map +0 -1
  223. package/dist/types.js +0 -2
  224. package/dist/types.js.map +0 -1
  225. package/dist/version.d.ts +0 -12
  226. package/dist/version.d.ts.map +0 -1
  227. package/dist/version.js +0 -12
  228. package/dist/version.js.map +0 -1
  229. package/dist/werift-rtc.d.ts +0 -121
  230. package/dist/werift-rtc.d.ts.map +0 -1
  231. package/dist/werift-rtc.js +0 -490
  232. package/dist/werift-rtc.js.map +0 -1
package/dist/index.js CHANGED
@@ -13521,7 +13521,7 @@ function normalizeServerUrl(value) {
13521
13521
  }
13522
13522
 
13523
13523
  // src/version.ts
13524
- var PLUGIN_VERSION = "0.5.6";
13524
+ var PLUGIN_VERSION = "0.5.7";
13525
13525
 
13526
13526
  // src/server-api.ts
13527
13527
  var ENABLED_QR_PROVIDERS = ["github"];
@@ -13998,6 +13998,7 @@ function requireRecord(value, name2) {
13998
13998
 
13999
13999
  // src/server-connection.ts
14000
14000
  var DEFAULT_WEBRTC_NEGOTIATE_TIMEOUT_MS = 12e3;
14001
+ var CLOSE_DRAIN_TIMEOUT_MS = 5e3;
14001
14002
  var HostServerConnection = class {
14002
14003
  constructor(config, identity, identities, api, connections, logger, createWebSocket = (url) => new WebSocket(url), rtcFactoryProvider, hostCapabilities = () => ["harness.api.v1"], harnessVersion) {
14003
14004
  this.config = config;
@@ -14041,7 +14042,7 @@ var HostServerConnection = class {
14041
14042
  }
14042
14043
  if (this.resumeQueued) return;
14043
14044
  this.resumeQueued = true;
14044
- void this.running.finally(() => {
14045
+ void this.running.catch(() => void 0).finally(() => {
14045
14046
  this.resumeQueued = false;
14046
14047
  if (!this.stopped) this.start();
14047
14048
  });
@@ -14077,7 +14078,7 @@ var HostServerConnection = class {
14077
14078
  this.reconnectRequested = true;
14078
14079
  this.retryWake?.();
14079
14080
  this.socket?.close(4e3, "manual reconnect");
14080
- void this.running.finally(() => {
14081
+ void this.running.catch(() => void 0).finally(() => {
14081
14082
  if (!this.reconnectRequested || this.stopped) return;
14082
14083
  this.reconnectRequested = false;
14083
14084
  this.start();
@@ -14107,7 +14108,7 @@ var HostServerConnection = class {
14107
14108
  ...connectionFailureDetail(error)
14108
14109
  });
14109
14110
  if (TERMINAL_AUTH_ERRORS.has(code)) {
14110
- this.logger.warn(code === "CONNECTION_REPLACED" ? "Another instance is using this Host identity. Standing by: retrying in five minutes, and taking over as soon as it leaves." : code === "SERVER_CREDENTIALS_BUSY" ? "Credential refresh is locked. Stop other instances; after a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again." : "Host authorization failed. Run /remote login or authorize this Host again in Remote settings.");
14111
+ this.logger.warn(code === "CONNECTION_REPLACED" ? "Another instance is using this Host identity. Standing by: retrying in five minutes, and taking over as soon as it leaves." : code === "SERVER_CREDENTIALS_BUSY" ? "Credential refresh is locked. Stop other instances; after a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again." : code === "CONTROL_DISABLED" ? 'This device is not accepting control. Turn on "Allow control of this device" to reconnect.' : "Host authorization failed. Run /remote login or authorize this Host again in Remote settings.");
14111
14112
  }
14112
14113
  if (code === "DEVICE_REVOKED" || code === "AUTH_INVALID") {
14113
14114
  try {
@@ -14166,9 +14167,25 @@ var HostServerConnection = class {
14166
14167
  });
14167
14168
  };
14168
14169
  socket.onmessage = (event) => {
14170
+ let frame;
14171
+ try {
14172
+ frame = decodeControl(event.data, this.controlFrameLimits);
14173
+ } catch (error) {
14174
+ this.controlFrameFailed(socket, error);
14175
+ return;
14176
+ }
14177
+ this.lastActiveAt = Date.now();
14178
+ if (acknowledged && (frame.type === "ping" || frame.type === "pong")) {
14179
+ if (frame.type === "pong") return;
14180
+ const nonce = objectValue(frame.payload, "nonce");
14181
+ if (typeof nonce !== "string") {
14182
+ this.controlFrameFailed(socket, new ControlConnectionError("INVALID_MESSAGE", "Control ping has no nonce."));
14183
+ return;
14184
+ }
14185
+ this.sendControl("pong", { nonce });
14186
+ return;
14187
+ }
14169
14188
  messageQueue = messageQueue.then(async () => {
14170
- const frame = decodeControl(event.data, this.controlFrameLimits);
14171
- this.lastActiveAt = Date.now();
14172
14189
  if (frame.type === "hello.ack") {
14173
14190
  const payload = requireHelloAck(frame.payload);
14174
14191
  this.authRecoveryAttempted = false;
@@ -14193,13 +14210,7 @@ var HostServerConnection = class {
14193
14210
  if (!acknowledged) throw new ControlConnectionError("INVALID_MESSAGE", "Server sent a frame before hello.ack.");
14194
14211
  await this.handleFrame(frame);
14195
14212
  }).catch((error) => {
14196
- const code = errorCode2(error);
14197
- this.terminalError = code;
14198
- this.logger.error("server control frame failed", {
14199
- code,
14200
- reason: diagnosticReason(error)
14201
- });
14202
- socket.close(4008, "invalid control frame");
14213
+ this.controlFrameFailed(socket, error);
14203
14214
  });
14204
14215
  };
14205
14216
  socket.onerror = (event) => {
@@ -14209,7 +14220,7 @@ var HostServerConnection = class {
14209
14220
  };
14210
14221
  socket.onclose = (event) => {
14211
14222
  const close = async () => {
14212
- await messageQueue.catch(() => void 0);
14223
+ await drainWithin(messageQueue, CLOSE_DRAIN_TIMEOUT_MS);
14213
14224
  if (this.stopped) {
14214
14225
  finish();
14215
14226
  return;
@@ -14237,13 +14248,23 @@ var HostServerConnection = class {
14237
14248
  finish(new ControlConnectionError("DEVICE_REVOKED", "The Server revoked this Host device."));
14238
14249
  return;
14239
14250
  }
14240
- if (acknowledged) this.terminalError = closeCode(event.code);
14241
- finish(acknowledged ? void 0 : new ControlConnectionError(closeCode(event.code), event.reason || "Server control connection closed."));
14251
+ if (acknowledged) this.terminalError = closeCode(event.code, event.reason);
14252
+ finish(acknowledged ? void 0 : new ControlConnectionError(closeCode(event.code, event.reason), event.reason || "Server control connection closed."));
14242
14253
  };
14243
14254
  void close();
14244
14255
  };
14245
14256
  });
14246
14257
  }
14258
+ /** Record a frame failure and close the socket, so the run retries from a clean state. */
14259
+ controlFrameFailed(socket, error) {
14260
+ const code = errorCode2(error);
14261
+ this.terminalError = code;
14262
+ this.logger.error("server control frame failed", {
14263
+ code,
14264
+ reason: diagnosticReason(error)
14265
+ });
14266
+ socket.close(4008, "invalid control frame");
14267
+ }
14247
14268
  async handleFrame(frame) {
14248
14269
  if (frame.type === "ping") {
14249
14270
  const nonce = objectValue(frame.payload, "nonce");
@@ -14705,10 +14726,25 @@ var HostServerConnection = class {
14705
14726
  }
14706
14727
  };
14707
14728
  var REPLACED_FIRST_RETRY_MS = 65e3;
14729
+ async function drainWithin(promise, ms) {
14730
+ let timer;
14731
+ try {
14732
+ await Promise.race([
14733
+ promise.catch(() => void 0),
14734
+ new Promise((resolve4) => {
14735
+ timer = setTimeout(resolve4, ms);
14736
+ timer.unref?.();
14737
+ })
14738
+ ]);
14739
+ } finally {
14740
+ if (timer !== void 0) clearTimeout(timer);
14741
+ }
14742
+ }
14708
14743
  var TERMINAL_AUTH_ERRORS = /* @__PURE__ */ new Set([
14709
14744
  "SERVER_CREDENTIALS_BUSY",
14710
14745
  "ACCOUNT_AUTH_REQUIRED",
14711
14746
  "AUTH_INVALID",
14747
+ "CONTROL_DISABLED",
14712
14748
  "DEVICE_OWNERSHIP_REQUIRED",
14713
14749
  "DEVICE_REVOKED",
14714
14750
  "TOKEN_EXPIRED"
@@ -14926,14 +14962,25 @@ function errorCode2(error) {
14926
14962
  function isRetryable(error) {
14927
14963
  return !TERMINAL_AUTH_ERRORS.has(errorCode2(error)) && (!(error instanceof ServerApiError) || error.retryable);
14928
14964
  }
14929
- function closeCode(code) {
14965
+ function closeCode(code, reason) {
14930
14966
  if (code === 4002) return "AUTH_INVALID";
14931
14967
  if (code === 4003) return "CONNECTION_REPLACED";
14932
14968
  if (code === 4004) return "DEVICE_REVOKED";
14933
14969
  if (code === 4007) return "RATE_LIMITED";
14934
14970
  if (code === 4011) return "UNSUPPORTED_VERSION";
14971
+ if (code === 4001 && reason !== void 0 && REJECTED_HELLO_CODES.has(reason)) return reason;
14935
14972
  return "CONNECTION_FAILED";
14936
14973
  }
14974
+ var REJECTED_HELLO_CODES = /* @__PURE__ */ new Set([
14975
+ "AUTH_REQUIRED",
14976
+ "AUTH_INVALID",
14977
+ "TOKEN_EXPIRED",
14978
+ "DEVICE_REVOKED",
14979
+ "CONTROL_DISABLED",
14980
+ "MEMBERSHIP_REQUIRED",
14981
+ "UNSUPPORTED_VERSION",
14982
+ "RATE_LIMITED"
14983
+ ]);
14937
14984
 
14938
14985
  // src/loopback-preview.ts
14939
14986
  import { randomBytes as randomBytes7, randomUUID } from "node:crypto";
@@ -16893,7 +16940,7 @@ var RemoteHarnessApiProxy = class {
16893
16940
  if (committed.transferId !== transferId || committed.totalBytes <= 0 || committed.totalBytes > MAX_HARNESS_API_TRANSFER_BYTES || committed.totalChunks !== Math.ceil(committed.totalBytes / HARNESS_API_TRANSFER_CHUNK_BYTES)) {
16894
16941
  throw new Error("The remote Host returned an invalid Harness API transfer descriptor.");
16895
16942
  }
16896
- const responseBytes = new Uint8Array(committed.totalBytes);
16943
+ const responseBytes2 = new Uint8Array(committed.totalBytes);
16897
16944
  let offset = 0;
16898
16945
  for (let index = 0; index < committed.totalChunks; index += 1) {
16899
16946
  const result = await this.client.rpc(
@@ -16909,10 +16956,10 @@ var RemoteHarnessApiProxy = class {
16909
16956
  if (chunk.byteLength !== expectedBytes) {
16910
16957
  throw new Error("The remote Host returned an invalid Harness API transfer chunk.");
16911
16958
  }
16912
- responseBytes.set(chunk, offset);
16959
+ responseBytes2.set(chunk, offset);
16913
16960
  offset += chunk.byteLength;
16914
16961
  }
16915
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes));
16962
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes2));
16916
16963
  } finally {
16917
16964
  if (opened) {
16918
16965
  await this.client.rpc("harness.api.transfer.close", { transferId }).catch(() => void 0);
@@ -17387,7 +17434,7 @@ var RemoteTypertGateway2 = class {
17387
17434
  if (committed.transferId !== transferId || committed.totalBytes <= 0 || committed.totalBytes > MAX_HARNESS_API_TRANSFER_BYTES || committed.totalChunks !== Math.ceil(committed.totalBytes / HARNESS_API_TRANSFER_CHUNK_BYTES)) {
17388
17435
  throw new Error("The remote Host returned an invalid Harness Remote transfer descriptor.");
17389
17436
  }
17390
- const responseBytes = new Uint8Array(committed.totalBytes);
17437
+ const responseBytes2 = new Uint8Array(committed.totalBytes);
17391
17438
  let offset = 0;
17392
17439
  for (let index = 0; index < committed.totalChunks; index += 1) {
17393
17440
  const result = await this.client.rpc(
@@ -17403,10 +17450,10 @@ var RemoteTypertGateway2 = class {
17403
17450
  if (chunk.byteLength !== expectedBytes) {
17404
17451
  throw new Error("The remote Host returned an invalid Harness Remote transfer chunk.");
17405
17452
  }
17406
- responseBytes.set(chunk, offset);
17453
+ responseBytes2.set(chunk, offset);
17407
17454
  offset += chunk.byteLength;
17408
17455
  }
17409
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes));
17456
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes2));
17410
17457
  } finally {
17411
17458
  if (opened) await this.client.rpc("harness.remote.transfer.close", { transferId }).catch(() => void 0);
17412
17459
  }
@@ -24797,22 +24844,22 @@ var CodexPeerBridge = class {
24797
24844
  });
24798
24845
  throw error;
24799
24846
  }
24800
- const responseBytes = new TextEncoder().encode(JSON.stringify(response));
24801
- if (responseBytes.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES) return { kind: "inline", response };
24802
- if (responseBytes.byteLength > MAX_CODEX_APP_TRANSFER_BYTES) {
24847
+ const responseBytes2 = new TextEncoder().encode(JSON.stringify(response));
24848
+ if (responseBytes2.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES) return { kind: "inline", response };
24849
+ if (responseBytes2.byteLength > MAX_CODEX_APP_TRANSFER_BYTES) {
24803
24850
  throw new RpcError("RESPONSE_TOO_LARGE", "The Codex response exceeds the bounded transfer limit.");
24804
24851
  }
24805
24852
  if (this.outgoingTransfers.size >= MAX_ACTIVE_TRANSFERS) {
24806
24853
  throw new RpcError("RATE_LIMITED", "Too many Codex response transfers are active.", void 0, true);
24807
24854
  }
24808
- const totalChunks = Math.ceil(responseBytes.byteLength / CODEX_APP_TRANSFER_CHUNK_BYTES);
24855
+ const totalChunks = Math.ceil(responseBytes2.byteLength / CODEX_APP_TRANSFER_CHUNK_BYTES);
24809
24856
  this.outgoingTransfers.set(params.transferId, {
24810
- bytes: responseBytes,
24857
+ bytes: responseBytes2,
24811
24858
  totalChunks,
24812
24859
  nextIndex: 0,
24813
24860
  touchedAt: Date.now()
24814
24861
  });
24815
- return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes.byteLength, totalChunks };
24862
+ return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
24816
24863
  }
24817
24864
  readTransfer(input2) {
24818
24865
  this.requireOpen();
@@ -26579,12 +26626,14 @@ var PluginControlRuntime = class {
26579
26626
  /** Consecutive reconciliations without a DSH session: DSH refreshes its grant, so one empty read is not a sign-out. */
26580
26627
  /** Guards against re-entry through configure(), which reads the settings view back. */
26581
26628
  reconcilingWithDeepSeek = false;
26629
+ /** The authorization exchange in flight; a settings poll must not start a second one. */
26630
+ deepseekAuthorization;
26582
26631
  /**
26583
26632
  * Keep this device's Server credentials in step with DSH's DeepSeek session - that session is the credential, and
26584
26633
  * the Server verifies it before issuing this device its own tokens.
26585
26634
  *
26586
26635
  * Three cases: DSH signed in and this device not authorized -> authorize; DSH signed out and this device authorized
26587
- * -> sign out; otherwise nothing. At most once per ten seconds, from the settings poll the panel already makes.
26636
+ * -> sign out; otherwise nothing. At most one exchange at a time, from the settings poll the panel already makes.
26588
26637
  */
26589
26638
  async reconcileWithDeepSeek() {
26590
26639
  if (this.deepseekSession === void 0 || this.reconcilingWithDeepSeek) return;
@@ -26593,19 +26642,20 @@ var PluginControlRuntime = class {
26593
26642
  const session = await this.deepseekSession.read();
26594
26643
  if (this.client !== void 0) this.client.hasDeepSeekSession = session !== void 0;
26595
26644
  const authorized = this.client === void 0 ? false : await this.client.hasServerAuthorization();
26596
- console.error(`[dsh-remote] reconcile ${JSON.stringify({ hasSession: session !== void 0, authorized })}`);
26597
26645
  if (session === void 0 && authorized) {
26598
26646
  await this.logout({ releaseDeepSeek: false });
26599
26647
  return;
26600
26648
  }
26601
26649
  if (session === void 0 || authorized) return;
26650
+ if (this.deepseekAuthorization !== void 0) return;
26602
26651
  if (this.client !== void 0) this.client.authorizingWithDeepSeek = true;
26603
- void (async () => {
26652
+ this.deepseekAuthorization = (async () => {
26604
26653
  try {
26605
26654
  await this.configure({ provider: "deepseek", serverUrl: this.config.serverUrl });
26606
26655
  } catch (error) {
26607
26656
  console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
26608
26657
  } finally {
26658
+ this.deepseekAuthorization = void 0;
26609
26659
  if (this.client !== void 0) this.client.authorizingWithDeepSeek = false;
26610
26660
  }
26611
26661
  })();
@@ -27418,8 +27468,8 @@ async function callHistoryWithRetry(callWithTimeout, payload, rpcId2, pageSizes)
27418
27468
  }
27419
27469
  throw new RpcError("INTERNAL_ERROR", "Failed to load session history with a fallback page size.");
27420
27470
  }
27421
- function sessionHistoryFallbackPageSizes(requestedMaxMessages) {
27422
- const requested = normalizeSessionHistoryPageSize(requestedMaxMessages);
27471
+ function sessionHistoryFallbackPageSizes(requestedMaxMessages2) {
27472
+ const requested = normalizeSessionHistoryPageSize(requestedMaxMessages2);
27423
27473
  const sizes = [];
27424
27474
  if (requested === void 0) {
27425
27475
  sizes.push(...SESSION_HISTORY_PAGE_SIZES);
@@ -27782,25 +27832,25 @@ var HarnessApiBridge = class {
27782
27832
  }
27783
27833
  const nativeRequest = callSchema2.parse(request);
27784
27834
  const response = await this.call(nativeRequest);
27785
- const responseBytes = new TextEncoder().encode(JSON.stringify(response));
27786
- if (responseBytes.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES2) {
27835
+ const responseBytes2 = new TextEncoder().encode(JSON.stringify(response));
27836
+ if (responseBytes2.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES2) {
27787
27837
  return { kind: "inline", response };
27788
27838
  }
27789
- if (responseBytes.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
27839
+ if (responseBytes2.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
27790
27840
  throw new RpcError("RESPONSE_TOO_LARGE", "The Harness API response exceeds the bounded transfer limit.");
27791
27841
  }
27792
27842
  this.pruneTransfers();
27793
27843
  if (this.outgoingTransfers.size >= MAX_ACTIVE_API_TRANSFERS) {
27794
27844
  throw new RpcError("RATE_LIMITED", "Too many Harness API response transfers are active.", void 0, true);
27795
27845
  }
27796
- const totalChunks = Math.ceil(responseBytes.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
27846
+ const totalChunks = Math.ceil(responseBytes2.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
27797
27847
  this.outgoingTransfers.set(params.transferId, {
27798
- bytes: responseBytes,
27848
+ bytes: responseBytes2,
27799
27849
  totalChunks,
27800
27850
  nextIndex: 0,
27801
27851
  touchedAt: Date.now()
27802
27852
  });
27803
- return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes.byteLength, totalChunks };
27853
+ return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
27804
27854
  }
27805
27855
  readTransfer(input2) {
27806
27856
  this.pruneTransfers();
@@ -28221,6 +28271,7 @@ function concatChunks2(chunks, totalBytes) {
28221
28271
  }
28222
28272
 
28223
28273
  // src/harness-remote-bridge.ts
28274
+ import { Buffer as Buffer4 } from "node:buffer";
28224
28275
  var endpointSchema = external_exports.string().min(1).max(128).regex(/^(?:\$events(?:\/result)?|[A-Za-z0-9_$.-]+\/[A-Za-z0-9_$.-]+)$/);
28225
28276
  var callSchema3 = external_exports.object({ endpoint: endpointSchema, payload: external_exports.unknown() }).strict();
28226
28277
  var streamOpenSchema3 = external_exports.object({
@@ -28268,6 +28319,13 @@ var directoryListSchema2 = external_exports.object({
28268
28319
  var MAX_ACTIVE_STREAMS2 = MAX_ALPHA_STREAMS_PER_CONNECTION;
28269
28320
  var MAX_ACTIVE_TRANSFERS2 = MAX_ACTIVE_TRANSFERS_PER_DIRECTION;
28270
28321
  var INLINE_TRANSFER_RESPONSE_BYTES3 = 2 * 1024 * 1024;
28322
+ var STREAM_FRAME_ENVELOPE_BYTES = 4 * 1024;
28323
+ var RESPONSE_ENVELOPE_BYTES = 8 * 1024;
28324
+ var HISTORY_PAGE_SIZES = [120, 80, 50, 30, 20, 12, 6, 3, 1];
28325
+ var MAX_HISTORY_PAGE_MESSAGES = 500;
28326
+ var REMOTE_HISTORY_CALL_ENDPOINTS = /* @__PURE__ */ new Set(["session/page", "session/history"]);
28327
+ var REMOTE_HISTORY_STREAM_ENDPOINTS = /* @__PURE__ */ new Set(["session/follow"]);
28328
+ var MAX_CACHED_HISTORY_PAGES = 64;
28271
28329
  var HARNESS_REMOTE_ALLOWLIST = [
28272
28330
  "$events",
28273
28331
  "$events/result",
@@ -28356,6 +28414,8 @@ var HarnessRemoteBridge = class {
28356
28414
  streams = /* @__PURE__ */ new Map();
28357
28415
  incomingTransfers = /* @__PURE__ */ new Map();
28358
28416
  outgoingTransfers = /* @__PURE__ */ new Map();
28417
+ /** Last page size that fit one secure message, per session, so probing is paid once. */
28418
+ historyPageSizes = /* @__PURE__ */ new Map();
28359
28419
  /**
28360
28420
  * Answer one remote Gateway call.
28361
28421
  *
@@ -28396,7 +28456,7 @@ var HarnessRemoteBridge = class {
28396
28456
  const signal = AbortSignal.timeout(6e4);
28397
28457
  try {
28398
28458
  const nativePayload = normalizeWorkspaceRequestPayload(params.endpoint, params.payload, this.harnessVersion);
28399
- const nativeResult = params.endpoint === "commands/execute" ? await dispatchCommandForHost(this.gateway, params.payload, signal, this.harnessVersion) : await this.gateway.dispatch(params.endpoint, nativePayload, signal);
28459
+ const nativeResult = REMOTE_HISTORY_CALL_ENDPOINTS.has(params.endpoint) ? await this.dispatchHistoryPage(params.endpoint, nativePayload, signal) : params.endpoint === "commands/execute" ? await dispatchCommandForHost(this.gateway, params.payload, signal, this.harnessVersion) : await this.gateway.dispatch(params.endpoint, nativePayload, signal);
28400
28460
  const result = params.endpoint === "directoryPicker/list" && needsDirectoryFallback(nativeResult) ? await this.directoryList(params.payload, signal) : nativeResult;
28401
28461
  this.logger?.debug("harness remote call ok", {
28402
28462
  endpoint: params.endpoint,
@@ -28417,7 +28477,10 @@ var HarnessRemoteBridge = class {
28417
28477
  this.logger?.warn("harness remote call failed", {
28418
28478
  endpoint: params.endpoint,
28419
28479
  durationMs: Math.round(performance.now() - startedAt),
28420
- code: this.gateway.failure(error).code
28480
+ code: this.gateway.failure(error).code,
28481
+ // The code alone is what the client sees; the message is the only thing that says WHY the
28482
+ // Host threw (a strict-schema rejection, an oversized page, a session the gateway lost).
28483
+ message: error instanceof Error ? error.message : String(error)
28421
28484
  });
28422
28485
  throw error;
28423
28486
  }
@@ -28487,22 +28550,22 @@ var HarnessRemoteBridge = class {
28487
28550
  throw new RpcError("INVALID_MESSAGE", "The Harness Remote transfer does not contain a valid request.");
28488
28551
  }
28489
28552
  const response = await this.call(callSchema3.parse(request));
28490
- const responseBytes = new TextEncoder().encode(JSON.stringify(response));
28491
- if (responseBytes.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES3) return { kind: "inline", response };
28492
- if (responseBytes.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
28553
+ const responseBytes2 = new TextEncoder().encode(JSON.stringify(response));
28554
+ if (responseBytes2.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES3) return { kind: "inline", response };
28555
+ if (responseBytes2.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
28493
28556
  throw new RpcError("RESPONSE_TOO_LARGE", "The Harness Remote response exceeds the bounded transfer limit.");
28494
28557
  }
28495
28558
  if (this.outgoingTransfers.size >= MAX_ACTIVE_TRANSFERS2) {
28496
28559
  throw new RpcError("RATE_LIMITED", "Too many Harness Remote response transfers are active.", void 0, true);
28497
28560
  }
28498
- const totalChunks = Math.ceil(responseBytes.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
28561
+ const totalChunks = Math.ceil(responseBytes2.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
28499
28562
  this.outgoingTransfers.set(params.transferId, {
28500
- bytes: responseBytes,
28563
+ bytes: responseBytes2,
28501
28564
  totalChunks,
28502
28565
  nextIndex: 0,
28503
28566
  touchedAt: Date.now()
28504
28567
  });
28505
- return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes.byteLength, totalChunks };
28568
+ return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
28506
28569
  }
28507
28570
  readTransfer(input2) {
28508
28571
  this.pruneTransfers();
@@ -28520,7 +28583,7 @@ var HarnessRemoteBridge = class {
28520
28583
  return {
28521
28584
  transferId: params.transferId,
28522
28585
  index: params.index,
28523
- data: Buffer.from(transfer.bytes.subarray(start, end)).toString("base64")
28586
+ data: Buffer4.from(transfer.bytes.subarray(start, end)).toString("base64")
28524
28587
  };
28525
28588
  }
28526
28589
  closeTransfer(input2) {
@@ -28540,17 +28603,135 @@ var HarnessRemoteBridge = class {
28540
28603
  }
28541
28604
  const controller = new AbortController();
28542
28605
  this.streams.set(params.streamId, { controller });
28543
- let source;
28544
28606
  try {
28545
- source = (this.codexWorkspace === void 0 ? void 0 : await this.codexWorkspace.open(params.endpoint, params.payload, controller.signal)) ?? await this.gateway.open(params.endpoint, normalizeWorkspaceChangesPayload(params.endpoint, params.payload, this.harnessVersion), controller.signal);
28607
+ const nativePayload = normalizeWorkspaceChangesPayload(params.endpoint, params.payload, this.harnessVersion);
28608
+ if (REMOTE_HISTORY_STREAM_ENDPOINTS.has(params.endpoint)) {
28609
+ const opened = await this.openHistoryStream(params, nativePayload, controller.signal);
28610
+ void this.pump(params.streamId, opened.source, controller.signal, opened.frame);
28611
+ return { opened: true, streamId: params.streamId };
28612
+ }
28613
+ const source = (this.codexWorkspace === void 0 ? void 0 : await this.codexWorkspace.open(params.endpoint, params.payload, controller.signal)) ?? await this.gateway.open(params.endpoint, nativePayload, controller.signal);
28546
28614
  controller.signal.throwIfAborted();
28615
+ void this.pump(params.streamId, source, controller.signal);
28616
+ return { opened: true, streamId: params.streamId };
28547
28617
  } catch (error) {
28548
28618
  this.streams.delete(params.streamId);
28549
28619
  controller.abort();
28620
+ this.logger?.warn("harness remote stream open failed", {
28621
+ endpoint: params.endpoint,
28622
+ message: error instanceof Error ? error.message : String(error)
28623
+ });
28550
28624
  throw error;
28551
28625
  }
28552
- void this.pump(params.streamId, source, controller.signal);
28553
- return { opened: true, streamId: params.streamId };
28626
+ }
28627
+ /**
28628
+ * Open a history stream with its opening page chosen by byte budget.
28629
+ *
28630
+ * `session/follow` yields one snapshot page and then live events. The snapshot cannot be
28631
+ * retried after the stream is handed to the client, so each attempt is pulled here, measured,
28632
+ * and closed again when it would not fit one secure message. The accepted iterator continues
28633
+ * after that first frame, which the pump publishes before the live tail.
28634
+ * @param params - the validated stream-open request.
28635
+ * @param payload - the request payload after endpoint normalization.
28636
+ * @param signal - the stream's cancellation signal.
28637
+ * @returns the remaining source and the measured first frame.
28638
+ */
28639
+ async openHistoryStream(params, payload, signal) {
28640
+ const { key, sizes } = this.historyPageSizesFor(payload);
28641
+ for (const size of sizes) {
28642
+ const source = await this.gateway.open(params.endpoint, withHistoryWindow(payload, size), signal);
28643
+ const iterator = source[Symbol.asyncIterator]();
28644
+ let first;
28645
+ try {
28646
+ first = await iterator.next();
28647
+ } catch (error) {
28648
+ await iterator.return?.();
28649
+ throw error;
28650
+ }
28651
+ if (first.done === true) {
28652
+ await iterator.return?.();
28653
+ return { source: EMPTY_ASYNC_ITERABLE };
28654
+ }
28655
+ const frame = {
28656
+ streamId: params.streamId,
28657
+ hasValue: true,
28658
+ ...first.value === void 0 ? {} : { value: collectRpcAttachments(first.value) }
28659
+ };
28660
+ const bytes = streamFrameBytes(frame);
28661
+ this.logger?.debug("history stream attempt", { endpoint: params.endpoint, size, bytes });
28662
+ if (bytes <= MAX_SECURE_MESSAGE_BYTES - STREAM_FRAME_ENVELOPE_BYTES) {
28663
+ this.rememberHistoryPageSize(key, size);
28664
+ return { source: remainingIterable(iterator), frame };
28665
+ }
28666
+ await iterator.return?.();
28667
+ }
28668
+ throw new RpcError(
28669
+ "RESPONSE_TOO_LARGE",
28670
+ "The Harness history page is too large for the secure Remote channel. Request a smaller page.",
28671
+ { maxBytes: MAX_SECURE_MESSAGE_BYTES },
28672
+ true
28673
+ );
28674
+ }
28675
+ /**
28676
+ * Answer one unary history page with the largest window that still fits.
28677
+ *
28678
+ * DSH's client asks for 500 messages; a session whose only Turn is long answers that with
28679
+ * its whole log, which the 4 MiB secure-message limit cannot carry. Each page is measured
28680
+ * after attachment tagging (the form the wire carries) and the request steps down through
28681
+ * {@link HISTORY_PAGE_SIZES} until it fits. Only a size overflow retries: a business failure
28682
+ * is returned immediately.
28683
+ * @param endpoint - the history endpoint being called.
28684
+ * @param payload - the request payload after endpoint normalization.
28685
+ * @param signal - the call's timeout signal.
28686
+ * @returns the page, or `RESPONSE_TOO_LARGE` when even one message cannot cross.
28687
+ */
28688
+ async dispatchHistoryPage(endpoint, payload, signal) {
28689
+ const { key, sizes } = this.historyPageSizesFor(payload);
28690
+ for (const size of sizes) {
28691
+ const startedAt = performance.now();
28692
+ const result = await this.gateway.dispatch(endpoint, withHistoryWindow(payload, size), signal);
28693
+ if (!result.ok) return result;
28694
+ const value = result.value;
28695
+ const wire = collectRpcAttachments(result);
28696
+ const bytes = responseBytes(wire);
28697
+ this.logger?.debug("history page attempt", {
28698
+ endpoint,
28699
+ size,
28700
+ durationMs: Math.round(performance.now() - startedAt),
28701
+ ok: result.ok,
28702
+ records: Array.isArray(value?.records) ? value.records.length : void 0,
28703
+ hasMore: value?.hasMore,
28704
+ bytes
28705
+ });
28706
+ if (bytes <= MAX_SECURE_MESSAGE_BYTES - RESPONSE_ENVELOPE_BYTES) {
28707
+ this.rememberHistoryPageSize(key, size);
28708
+ return wire;
28709
+ }
28710
+ }
28711
+ return {
28712
+ ok: false,
28713
+ error: {
28714
+ code: "RESPONSE_TOO_LARGE",
28715
+ message: "The Harness history page is too large for the secure Remote channel. Request a smaller page.",
28716
+ details: { maxBytes: MAX_SECURE_MESSAGE_BYTES }
28717
+ }
28718
+ };
28719
+ }
28720
+ /** The ladder for one history request, starting from what last fit for this session. */
28721
+ historyPageSizesFor(payload) {
28722
+ const key = historyPageKey(payload);
28723
+ const requested = requestedMaxMessages(payload) ?? HISTORY_PAGE_SIZES[0];
28724
+ const remembered = this.historyPageSizes.get(key);
28725
+ const start = Math.max(1, Math.min(requested, MAX_HISTORY_PAGE_MESSAGES, remembered ?? requested));
28726
+ this.logger?.debug("history window", { key: key.slice(0, 120), requested, remembered, start });
28727
+ return { key, sizes: historyPageSizes(start) };
28728
+ }
28729
+ rememberHistoryPageSize(key, size) {
28730
+ if (this.historyPageSizes.size >= MAX_CACHED_HISTORY_PAGES && !this.historyPageSizes.has(key)) {
28731
+ const oldest = this.historyPageSizes.keys().next().value;
28732
+ if (oldest !== void 0) this.historyPageSizes.delete(oldest);
28733
+ }
28734
+ this.historyPageSizes.set(key, size);
28554
28735
  }
28555
28736
  closeStream(input2) {
28556
28737
  const params = streamCloseSchema3.parse(input2);
@@ -28566,6 +28747,7 @@ var HarnessRemoteBridge = class {
28566
28747
  this.streams.clear();
28567
28748
  this.incomingTransfers.clear();
28568
28749
  this.outgoingTransfers.clear();
28750
+ this.historyPageSizes.clear();
28569
28751
  for (const [, stream] of streams) stream.controller.abort(reason);
28570
28752
  await this.codexWorkspace?.closeAll();
28571
28753
  }
@@ -28577,17 +28759,28 @@ var HarnessRemoteBridge = class {
28577
28759
  throw new RpcError("FEATURE_NOT_SUPPORTED", "This Harness version does not support Remote event transport.");
28578
28760
  }
28579
28761
  }
28580
- async pump(streamId, source, signal) {
28762
+ async pump(streamId, source, signal, initialFrame) {
28581
28763
  let reason = "completed";
28582
28764
  let failure2;
28583
28765
  try {
28766
+ if (initialFrame !== void 0 && !signal.aborted) await this.publish("harness.remote.frame", initialFrame);
28584
28767
  for await (const value of source) {
28585
28768
  if (signal.aborted) break;
28586
- await this.publish("harness.remote.frame", {
28769
+ const frame = {
28587
28770
  streamId,
28588
28771
  hasValue: true,
28589
28772
  ...value === void 0 ? {} : { value: collectRpcAttachments(value) }
28590
- });
28773
+ };
28774
+ if (streamFrameBytes(frame) > MAX_SECURE_MESSAGE_BYTES - STREAM_FRAME_ENVELOPE_BYTES) {
28775
+ failure2 = {
28776
+ code: "RESPONSE_TOO_LARGE",
28777
+ message: "The Harness stream frame is too large for the secure Remote channel.",
28778
+ details: { maxBytes: MAX_SECURE_MESSAGE_BYTES }
28779
+ };
28780
+ reason = "failed";
28781
+ break;
28782
+ }
28783
+ await this.publish("harness.remote.frame", frame);
28591
28784
  }
28592
28785
  if (signal.aborted) reason = "cancelled";
28593
28786
  } catch (error) {
@@ -28608,6 +28801,77 @@ var HarnessRemoteBridge = class {
28608
28801
  for (const [id4, transfer] of this.outgoingTransfers) if (transfer.touchedAt < cutoff) this.outgoingTransfers.delete(id4);
28609
28802
  }
28610
28803
  };
28804
+ function withHistoryWindow(payload, maxMessages) {
28805
+ if (!isRecord14(payload)) return payload;
28806
+ if (Array.isArray(payload.args)) {
28807
+ const [first, ...rest] = payload.args;
28808
+ return isRecord14(first) ? { ...payload, args: [windowedParams(first, maxMessages), ...rest] } : payload;
28809
+ }
28810
+ if (isRecord14(payload.args)) return { ...payload, args: windowedParams(payload.args, maxMessages) };
28811
+ return windowedParams(payload, maxMessages);
28812
+ }
28813
+ function windowedParams(params, maxMessages) {
28814
+ return isRecord14(params.request) ? { ...params, request: windowedRequest(params.request, maxMessages) } : windowedRequest(params, maxMessages);
28815
+ }
28816
+ function windowedRequest(request, maxMessages) {
28817
+ const turnWindow = isRecord14(request.turnWindow) ? request.turnWindow : void 0;
28818
+ const next = { ...request, maxMessages };
28819
+ if (turnWindow !== void 0) {
28820
+ next.turnWindow = typeof turnWindow.minMessages === "number" && Number.isFinite(turnWindow.minMessages) ? { ...turnWindow, minMessages: Math.min(turnWindow.minMessages, maxMessages) } : turnWindow;
28821
+ }
28822
+ return next;
28823
+ }
28824
+ function historyPageSizes(start) {
28825
+ const sizes = [start];
28826
+ for (const size of HISTORY_PAGE_SIZES) if (size < start) sizes.push(size);
28827
+ return sizes;
28828
+ }
28829
+ function historyRequestOf(payload) {
28830
+ let node = payload;
28831
+ for (let depth = 0; depth < 4; depth += 1) {
28832
+ if (!isRecord14(node)) return void 0;
28833
+ if (Array.isArray(node.args)) {
28834
+ node = node.args[0];
28835
+ continue;
28836
+ }
28837
+ if (isRecord14(node.args)) {
28838
+ node = node.args;
28839
+ continue;
28840
+ }
28841
+ if (isRecord14(node.request)) {
28842
+ node = node.request;
28843
+ continue;
28844
+ }
28845
+ return node;
28846
+ }
28847
+ return void 0;
28848
+ }
28849
+ function requestedMaxMessages(payload) {
28850
+ const value = historyRequestOf(payload)?.maxMessages;
28851
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
28852
+ }
28853
+ function historyPageKey(payload) {
28854
+ const request = historyRequestOf(payload);
28855
+ if (request === void 0) return "default";
28856
+ const address = request.address ?? request.request ?? request.threadId ?? request.sessionId;
28857
+ if (address === void 0) return "default";
28858
+ try {
28859
+ return JSON.stringify(address);
28860
+ } catch {
28861
+ return "default";
28862
+ }
28863
+ }
28864
+ function responseBytes(result) {
28865
+ return Buffer4.byteLength(JSON.stringify(result), "utf8");
28866
+ }
28867
+ function streamFrameBytes(frame) {
28868
+ return Buffer4.byteLength(JSON.stringify(frame), "utf8");
28869
+ }
28870
+ function remainingIterable(iterator) {
28871
+ return { [Symbol.asyncIterator]: () => iterator };
28872
+ }
28873
+ var EMPTY_ASYNC_ITERABLE = { async *[Symbol.asyncIterator]() {
28874
+ } };
28611
28875
  function normalizeWorkspaceChangesPayload(endpoint, payload, harnessVersion) {
28612
28876
  if (endpoint !== "workspaceFiles/changes" || !requiresWorkspaceChangePath(harnessVersion)) return payload;
28613
28877
  if (!isRecord14(payload) || !isRecord14(payload.args) || Object.hasOwn(payload.args, "path")) return payload;
@@ -28661,7 +28925,7 @@ async function dispatchCommandForHost(gateway, payload, signal, harnessVersion)
28661
28925
  );
28662
28926
  }
28663
28927
  function decodeCanonicalBase643(value) {
28664
- const bytes = Buffer.from(value, "base64");
28928
+ const bytes = Buffer4.from(value, "base64");
28665
28929
  if (bytes.toString("base64") !== value) throw new RpcError("INVALID_MESSAGE", "The Harness Remote transfer chunk is invalid.");
28666
28930
  return bytes;
28667
28931
  }