@blue-soda/dsh-remote 0.5.5 → 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.
- package/README.md +2 -2
- package/cordis.patch.yml +30 -30
- package/dist/client.github.js +1 -1
- package/dist/client.js +1 -1
- package/dist/index.js +371 -80
- package/dist/index.js.map +4 -4
- package/dsh-plugin.json +41 -41
- package/package.json +165 -165
- package/dist/acp.d.ts +0 -75
- package/dist/acp.d.ts.map +0 -1
- package/dist/acp.js +0 -61
- package/dist/acp.js.map +0 -1
- package/dist/api-proxy-switch.d.ts +0 -33
- package/dist/api-proxy-switch.d.ts.map +0 -1
- package/dist/api-proxy-switch.js +0 -109
- package/dist/api-proxy-switch.js.map +0 -1
- package/dist/atomic-file.d.ts +0 -16
- package/dist/atomic-file.d.ts.map +0 -1
- package/dist/atomic-file.js +0 -81
- package/dist/atomic-file.js.map +0 -1
- package/dist/bin/doctor.d.ts +0 -3
- package/dist/bin/doctor.d.ts.map +0 -1
- package/dist/bin/doctor.js +0 -13
- package/dist/bin/doctor.js.map +0 -1
- package/dist/cli.d.ts +0 -32
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -289
- package/dist/cli.js.map +0 -1
- package/dist/client-runtime.d.ts +0 -375
- package/dist/client-runtime.d.ts.map +0 -1
- package/dist/client-runtime.js +0 -1768
- package/dist/client-runtime.js.map +0 -1
- package/dist/client-secure-transport.d.ts +0 -23
- package/dist/client-secure-transport.d.ts.map +0 -1
- package/dist/client-secure-transport.js +0 -144
- package/dist/client-secure-transport.js.map +0 -1
- package/dist/client-target-store.d.ts +0 -40
- package/dist/client-target-store.d.ts.map +0 -1
- package/dist/client-target-store.js +0 -79
- package/dist/client-target-store.js.map +0 -1
- package/dist/client.d.ts +0 -13
- package/dist/client.d.ts.map +0 -1
- package/dist/codex/app-server.d.ts +0 -71
- package/dist/codex/app-server.d.ts.map +0 -1
- package/dist/codex/app-server.js +0 -268
- package/dist/codex/app-server.js.map +0 -1
- package/dist/codex/codex-image-codec.d.ts +0 -7
- package/dist/codex/codex-image-codec.d.ts.map +0 -1
- package/dist/codex/codex-image-codec.js +0 -288
- package/dist/codex/codex-image-codec.js.map +0 -1
- package/dist/codex/domain.d.ts +0 -102
- package/dist/codex/domain.d.ts.map +0 -1
- package/dist/codex/domain.js +0 -1323
- package/dist/codex/domain.js.map +0 -1
- package/dist/codex/method-policy.d.ts +0 -338
- package/dist/codex/method-policy.d.ts.map +0 -1
- package/dist/codex/method-policy.js +0 -141
- package/dist/codex/method-policy.js.map +0 -1
- package/dist/codex/peer-bridge.d.ts +0 -57
- package/dist/codex/peer-bridge.d.ts.map +0 -1
- package/dist/codex/peer-bridge.js +0 -299
- package/dist/codex/peer-bridge.js.map +0 -1
- package/dist/codex/permissions.d.ts +0 -4
- package/dist/codex/permissions.d.ts.map +0 -1
- package/dist/codex/permissions.js +0 -21
- package/dist/codex/permissions.js.map +0 -1
- package/dist/codex/session-id.d.ts +0 -10
- package/dist/codex/session-id.d.ts.map +0 -1
- package/dist/codex/session-id.js +0 -15
- package/dist/codex/session-id.js.map +0 -1
- package/dist/codex/virtual-harness.d.ts +0 -209
- package/dist/codex/virtual-harness.d.ts.map +0 -1
- package/dist/codex/virtual-harness.js +0 -2650
- package/dist/codex/virtual-harness.js.map +0 -1
- package/dist/codex-workspace-bridge.d.ts +0 -108
- package/dist/codex-workspace-bridge.d.ts.map +0 -1
- package/dist/codex-workspace-bridge.js +0 -502
- package/dist/codex-workspace-bridge.js.map +0 -1
- package/dist/config.d.ts +0 -99
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -127
- package/dist/config.js.map +0 -1
- package/dist/connection-controller.d.ts +0 -44
- package/dist/connection-controller.d.ts.map +0 -1
- package/dist/connection-controller.js +0 -185
- package/dist/connection-controller.js.map +0 -1
- package/dist/control-route.d.ts +0 -34
- package/dist/control-route.d.ts.map +0 -1
- package/dist/control-route.js +0 -136
- package/dist/control-route.js.map +0 -1
- package/dist/control-runtime.d.ts +0 -138
- package/dist/control-runtime.d.ts.map +0 -1
- package/dist/control-runtime.js +0 -543
- package/dist/control-runtime.js.map +0 -1
- package/dist/control-stream.d.ts +0 -67
- package/dist/control-stream.d.ts.map +0 -1
- package/dist/control-stream.js +0 -179
- package/dist/control-stream.js.map +0 -1
- package/dist/defaults.d.ts +0 -9
- package/dist/defaults.d.ts.map +0 -1
- package/dist/defaults.js +0 -9
- package/dist/defaults.js.map +0 -1
- package/dist/file-viewer-bridge.d.ts +0 -30
- package/dist/file-viewer-bridge.d.ts.map +0 -1
- package/dist/file-viewer-bridge.js +0 -128
- package/dist/file-viewer-bridge.js.map +0 -1
- package/dist/file-viewer-contract.d.ts +0 -5
- package/dist/file-viewer-contract.d.ts.map +0 -1
- package/dist/file-viewer-contract.js +0 -4
- package/dist/file-viewer-contract.js.map +0 -1
- package/dist/harness-api-bridge.d.ts +0 -81
- package/dist/harness-api-bridge.d.ts.map +0 -1
- package/dist/harness-api-bridge.js +0 -862
- package/dist/harness-api-bridge.js.map +0 -1
- package/dist/harness-api-history.d.ts +0 -3
- package/dist/harness-api-history.d.ts.map +0 -1
- package/dist/harness-api-history.js +0 -59
- package/dist/harness-api-history.js.map +0 -1
- package/dist/harness-remote-bridge.d.ts +0 -60
- package/dist/harness-remote-bridge.d.ts.map +0 -1
- package/dist/harness-remote-bridge.js +0 -540
- package/dist/harness-remote-bridge.js.map +0 -1
- package/dist/harness-version.d.ts +0 -23
- package/dist/harness-version.d.ts.map +0 -1
- package/dist/harness-version.js +0 -95
- package/dist/harness-version.js.map +0 -1
- package/dist/identity-store.d.ts +0 -45
- package/dist/identity-store.d.ts.map +0 -1
- package/dist/identity-store.js +0 -186
- package/dist/identity-store.js.map +0 -1
- package/dist/ids.d.ts +0 -2
- package/dist/ids.d.ts.map +0 -1
- package/dist/ids.js +0 -17
- package/dist/ids.js.map +0 -1
- package/dist/index.d.ts +0 -78
- package/dist/index.d.ts.map +0 -1
- package/dist/logging.d.ts +0 -18
- package/dist/logging.d.ts.map +0 -1
- package/dist/logging.js +0 -30
- package/dist/logging.js.map +0 -1
- package/dist/loopback-host.d.ts +0 -20
- package/dist/loopback-host.d.ts.map +0 -1
- package/dist/loopback-host.js +0 -245
- package/dist/loopback-host.js.map +0 -1
- package/dist/loopback-preview.d.ts +0 -19
- package/dist/loopback-preview.d.ts.map +0 -1
- package/dist/loopback-preview.js +0 -232
- package/dist/loopback-preview.js.map +0 -1
- package/dist/native-rtc-helper.d.ts +0 -14
- package/dist/native-rtc-helper.d.ts.map +0 -1
- package/dist/native-rtc-helper.js +0 -575
- package/dist/native-rtc-helper.js.map +0 -1
- package/dist/remote-api-proxy.d.ts +0 -17
- package/dist/remote-api-proxy.d.ts.map +0 -1
- package/dist/remote-api-proxy.js +0 -451
- package/dist/remote-api-proxy.js.map +0 -1
- package/dist/remote-directory-browser.d.ts +0 -16
- package/dist/remote-directory-browser.d.ts.map +0 -1
- package/dist/remote-directory-browser.js +0 -48
- package/dist/remote-directory-browser.js.map +0 -1
- package/dist/remote-file-content-provider.d.ts +0 -48
- package/dist/remote-file-content-provider.d.ts.map +0 -1
- package/dist/remote-file-content-provider.js +0 -93
- package/dist/remote-file-content-provider.js.map +0 -1
- package/dist/remote-typert-gateway.d.ts +0 -20
- package/dist/remote-typert-gateway.d.ts.map +0 -1
- package/dist/remote-typert-gateway.js +0 -334
- package/dist/remote-typert-gateway.js.map +0 -1
- package/dist/rpc-binary-attachments.d.ts +0 -33
- package/dist/rpc-binary-attachments.d.ts.map +0 -1
- package/dist/rpc-binary-attachments.js +0 -142
- package/dist/rpc-binary-attachments.js.map +0 -1
- package/dist/rpc-router.d.ts +0 -31
- package/dist/rpc-router.d.ts.map +0 -1
- package/dist/rpc-router.js +0 -201
- package/dist/rpc-router.js.map +0 -1
- package/dist/safe-error.d.ts +0 -8
- package/dist/safe-error.d.ts.map +0 -1
- package/dist/safe-error.js +0 -20
- package/dist/safe-error.js.map +0 -1
- package/dist/server-api.d.ts +0 -109
- package/dist/server-api.d.ts.map +0 -1
- package/dist/server-api.js +0 -520
- package/dist/server-api.js.map +0 -1
- package/dist/server-connection.d.ts +0 -79
- package/dist/server-connection.d.ts.map +0 -1
- package/dist/server-connection.js +0 -1023
- package/dist/server-connection.js.map +0 -1
- package/dist/server-credentials.d.ts +0 -55
- package/dist/server-credentials.d.ts.map +0 -1
- package/dist/server-credentials.js +0 -108
- package/dist/server-credentials.js.map +0 -1
- package/dist/service.d.ts +0 -151
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -448
- package/dist/service.js.map +0 -1
- package/dist/session-format-compat.d.ts +0 -3
- package/dist/session-format-compat.d.ts.map +0 -1
- package/dist/session-format-compat.js +0 -183
- package/dist/session-format-compat.js.map +0 -1
- package/dist/status-stream.d.ts +0 -48
- package/dist/status-stream.d.ts.map +0 -1
- package/dist/status-stream.js +0 -133
- package/dist/status-stream.js.map +0 -1
- package/dist/terminal-policy.d.ts +0 -21
- package/dist/terminal-policy.d.ts.map +0 -1
- package/dist/terminal-policy.js +0 -68
- package/dist/terminal-policy.js.map +0 -1
- package/dist/tui-command.d.ts +0 -13
- package/dist/tui-command.d.ts.map +0 -1
- package/dist/tui-command.js +0 -392
- package/dist/tui-command.js.map +0 -1
- package/dist/typert-gateway-contract.d.ts +0 -59
- package/dist/typert-gateway-contract.d.ts.map +0 -1
- package/dist/typert-gateway-contract.js +0 -2
- package/dist/typert-gateway-contract.js.map +0 -1
- package/dist/typert-gateway-switch.d.ts +0 -85
- package/dist/typert-gateway-switch.d.ts.map +0 -1
- package/dist/typert-gateway-switch.js +0 -448
- package/dist/typert-gateway-switch.js.map +0 -1
- package/dist/types.d.ts +0 -20
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/version.d.ts +0 -12
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -12
- package/dist/version.js.map +0 -1
- package/dist/werift-rtc.d.ts +0 -121
- package/dist/werift-rtc.d.ts.map +0 -1
- package/dist/werift-rtc.js +0 -490
- 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.
|
|
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
|
-
|
|
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
|
|
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";
|
|
@@ -15512,7 +15559,7 @@ var CodexRemoteClient = class {
|
|
|
15512
15559
|
if (!isRecord(result) || !Array.isArray(result.data))
|
|
15513
15560
|
throw invalidResponse("thread list");
|
|
15514
15561
|
return {
|
|
15515
|
-
sessions: result.data.map(projectCodexThread).filter((value) => value !== void 0),
|
|
15562
|
+
sessions: uniqueCodexThreadRows(result.data).map(projectCodexThread).filter((value) => value !== void 0),
|
|
15516
15563
|
...typeof result.nextCursor === "string" ? { nextCursor: result.nextCursor } : {}
|
|
15517
15564
|
};
|
|
15518
15565
|
}
|
|
@@ -15666,6 +15713,33 @@ function projectCodexThread(value) {
|
|
|
15666
15713
|
...typeof value.isPinned === "boolean" ? { pinned: value.isPinned } : {}
|
|
15667
15714
|
};
|
|
15668
15715
|
}
|
|
15716
|
+
var THREAD_ID_KEY = /^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/u;
|
|
15717
|
+
var LEGACY_ROW_KEY = /^([A-Za-z0-9][A-Za-z0-9._-]{0,255})~[^~]{0,64}~[0-9]{1,9}$/u;
|
|
15718
|
+
function codexThreadIdFromKey(key) {
|
|
15719
|
+
if (THREAD_ID_KEY.test(key))
|
|
15720
|
+
return key;
|
|
15721
|
+
return LEGACY_ROW_KEY.exec(key)?.[1];
|
|
15722
|
+
}
|
|
15723
|
+
function rowFreshness(row) {
|
|
15724
|
+
for (const field of ["updatedAt", "createdAt"]) {
|
|
15725
|
+
const value = row[field];
|
|
15726
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
15727
|
+
return value;
|
|
15728
|
+
}
|
|
15729
|
+
return 0;
|
|
15730
|
+
}
|
|
15731
|
+
function uniqueCodexThreadRows(values) {
|
|
15732
|
+
const byThread = /* @__PURE__ */ new Map();
|
|
15733
|
+
for (const value of values) {
|
|
15734
|
+
if (!isRecord(value) || typeof value.id !== "string" || value.id.length === 0)
|
|
15735
|
+
continue;
|
|
15736
|
+
const threadId = codexThreadIdFromKey(value.id) ?? value.id;
|
|
15737
|
+
const current = byThread.get(threadId);
|
|
15738
|
+
if (current === void 0 || rowFreshness(value) > rowFreshness(current))
|
|
15739
|
+
byThread.set(threadId, value);
|
|
15740
|
+
}
|
|
15741
|
+
return [...byThread.values()];
|
|
15742
|
+
}
|
|
15669
15743
|
function deriveCodexCwdWorkspaces(values) {
|
|
15670
15744
|
const byPath = /* @__PURE__ */ new Map();
|
|
15671
15745
|
const usedIds = /* @__PURE__ */ new Set();
|
|
@@ -16866,7 +16940,7 @@ var RemoteHarnessApiProxy = class {
|
|
|
16866
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)) {
|
|
16867
16941
|
throw new Error("The remote Host returned an invalid Harness API transfer descriptor.");
|
|
16868
16942
|
}
|
|
16869
|
-
const
|
|
16943
|
+
const responseBytes2 = new Uint8Array(committed.totalBytes);
|
|
16870
16944
|
let offset = 0;
|
|
16871
16945
|
for (let index = 0; index < committed.totalChunks; index += 1) {
|
|
16872
16946
|
const result = await this.client.rpc(
|
|
@@ -16882,10 +16956,10 @@ var RemoteHarnessApiProxy = class {
|
|
|
16882
16956
|
if (chunk.byteLength !== expectedBytes) {
|
|
16883
16957
|
throw new Error("The remote Host returned an invalid Harness API transfer chunk.");
|
|
16884
16958
|
}
|
|
16885
|
-
|
|
16959
|
+
responseBytes2.set(chunk, offset);
|
|
16886
16960
|
offset += chunk.byteLength;
|
|
16887
16961
|
}
|
|
16888
|
-
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(
|
|
16962
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes2));
|
|
16889
16963
|
} finally {
|
|
16890
16964
|
if (opened) {
|
|
16891
16965
|
await this.client.rpc("harness.api.transfer.close", { transferId }).catch(() => void 0);
|
|
@@ -17360,7 +17434,7 @@ var RemoteTypertGateway2 = class {
|
|
|
17360
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)) {
|
|
17361
17435
|
throw new Error("The remote Host returned an invalid Harness Remote transfer descriptor.");
|
|
17362
17436
|
}
|
|
17363
|
-
const
|
|
17437
|
+
const responseBytes2 = new Uint8Array(committed.totalBytes);
|
|
17364
17438
|
let offset = 0;
|
|
17365
17439
|
for (let index = 0; index < committed.totalChunks; index += 1) {
|
|
17366
17440
|
const result = await this.client.rpc(
|
|
@@ -17376,10 +17450,10 @@ var RemoteTypertGateway2 = class {
|
|
|
17376
17450
|
if (chunk.byteLength !== expectedBytes) {
|
|
17377
17451
|
throw new Error("The remote Host returned an invalid Harness Remote transfer chunk.");
|
|
17378
17452
|
}
|
|
17379
|
-
|
|
17453
|
+
responseBytes2.set(chunk, offset);
|
|
17380
17454
|
offset += chunk.byteLength;
|
|
17381
17455
|
}
|
|
17382
|
-
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(
|
|
17456
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(responseBytes2));
|
|
17383
17457
|
} finally {
|
|
17384
17458
|
if (opened) await this.client.rpc("harness.remote.transfer.close", { transferId }).catch(() => void 0);
|
|
17385
17459
|
}
|
|
@@ -17540,6 +17614,17 @@ function record(value) {
|
|
|
17540
17614
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
17541
17615
|
}
|
|
17542
17616
|
|
|
17617
|
+
// src/codex/session-id.ts
|
|
17618
|
+
var SESSION_PREFIX = "codex:";
|
|
17619
|
+
function parseCodexSessionId(value) {
|
|
17620
|
+
if (typeof value !== "string" || !value.startsWith(SESSION_PREFIX)) return void 0;
|
|
17621
|
+
const threadId = codexThreadIdFromKey(value.slice(SESSION_PREFIX.length));
|
|
17622
|
+
return threadId === void 0 ? void 0 : { sessionId: value, threadId };
|
|
17623
|
+
}
|
|
17624
|
+
function resolveCodexThreadKey(key) {
|
|
17625
|
+
return codexThreadIdFromKey(key) ?? key;
|
|
17626
|
+
}
|
|
17627
|
+
|
|
17543
17628
|
// src/codex/method-policy.ts
|
|
17544
17629
|
var id2 = external_exports.string().min(1).max(256);
|
|
17545
17630
|
var cursor = external_exports.string().min(1).max(4096).nullable().optional();
|
|
@@ -19411,7 +19496,7 @@ async function loadCatalog(client, signal, pendingThreads) {
|
|
|
19411
19496
|
updatedAt: workspace.updatedAt
|
|
19412
19497
|
}));
|
|
19413
19498
|
}
|
|
19414
|
-
const projected = threads.map((thread) => {
|
|
19499
|
+
const projected = uniqueCodexThreadRows(threads).map((thread) => {
|
|
19415
19500
|
const session = projectCodexThread(thread);
|
|
19416
19501
|
return session === void 0 ? void 0 : { thread, session };
|
|
19417
19502
|
}).filter((value) => value !== void 0);
|
|
@@ -20121,10 +20206,9 @@ function sessionIdFromAddress(address) {
|
|
|
20121
20206
|
return requiredString(address.childSessionId, "childSessionId");
|
|
20122
20207
|
}
|
|
20123
20208
|
function nativeThreadId(sessionId) {
|
|
20124
|
-
|
|
20125
|
-
|
|
20126
|
-
|
|
20127
|
-
return sessionId.slice(CODEX_SESSION_PREFIX.length);
|
|
20209
|
+
const parsed = parseCodexSessionId(sessionId);
|
|
20210
|
+
if (parsed === void 0) throw new Error("The selected Session does not belong to CodeX.");
|
|
20211
|
+
return parsed.threadId;
|
|
20128
20212
|
}
|
|
20129
20213
|
function activeTurnId(value) {
|
|
20130
20214
|
if (!Array.isArray(value)) return void 0;
|
|
@@ -24679,8 +24763,9 @@ var CodexPeerBridge = class {
|
|
|
24679
24763
|
method: "thread/read",
|
|
24680
24764
|
params: { threadId: params.threadId, includeTurns: false }
|
|
24681
24765
|
});
|
|
24682
|
-
|
|
24683
|
-
|
|
24766
|
+
const threadId = resolveCodexThreadKey(params.threadId);
|
|
24767
|
+
this.streams.set(params.streamId, threadId);
|
|
24768
|
+
return { opened: true, streamId: params.streamId, threadId };
|
|
24684
24769
|
}
|
|
24685
24770
|
closeStream(input2) {
|
|
24686
24771
|
const params = streamCloseSchema.parse(input2);
|
|
@@ -24759,22 +24844,22 @@ var CodexPeerBridge = class {
|
|
|
24759
24844
|
});
|
|
24760
24845
|
throw error;
|
|
24761
24846
|
}
|
|
24762
|
-
const
|
|
24763
|
-
if (
|
|
24764
|
-
if (
|
|
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) {
|
|
24765
24850
|
throw new RpcError("RESPONSE_TOO_LARGE", "The Codex response exceeds the bounded transfer limit.");
|
|
24766
24851
|
}
|
|
24767
24852
|
if (this.outgoingTransfers.size >= MAX_ACTIVE_TRANSFERS) {
|
|
24768
24853
|
throw new RpcError("RATE_LIMITED", "Too many Codex response transfers are active.", void 0, true);
|
|
24769
24854
|
}
|
|
24770
|
-
const totalChunks = Math.ceil(
|
|
24855
|
+
const totalChunks = Math.ceil(responseBytes2.byteLength / CODEX_APP_TRANSFER_CHUNK_BYTES);
|
|
24771
24856
|
this.outgoingTransfers.set(params.transferId, {
|
|
24772
|
-
bytes:
|
|
24857
|
+
bytes: responseBytes2,
|
|
24773
24858
|
totalChunks,
|
|
24774
24859
|
nextIndex: 0,
|
|
24775
24860
|
touchedAt: Date.now()
|
|
24776
24861
|
});
|
|
24777
|
-
return { kind: "chunked", transferId: params.transferId, totalBytes:
|
|
24862
|
+
return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
|
|
24778
24863
|
}
|
|
24779
24864
|
readTransfer(input2) {
|
|
24780
24865
|
this.requireOpen();
|
|
@@ -25026,9 +25111,7 @@ var CodexRemoteDomain = class {
|
|
|
25026
25111
|
}));
|
|
25027
25112
|
}
|
|
25028
25113
|
if (isRecord12(call.params) && typeof call.params.threadId === "string") {
|
|
25029
|
-
|
|
25030
|
-
const separator = rowKey.indexOf("~");
|
|
25031
|
-
if (separator > 0) call.params.threadId = rowKey.slice(0, separator);
|
|
25114
|
+
call.params.threadId = resolveCodexThreadKey(call.params.threadId);
|
|
25032
25115
|
}
|
|
25033
25116
|
if (call.method === "thread/list") {
|
|
25034
25117
|
const result = sanitizeThreadList(await this.callUpstream(call.method, call.params));
|
|
@@ -25038,10 +25121,7 @@ var CodexRemoteDomain = class {
|
|
|
25038
25121
|
);
|
|
25039
25122
|
return {
|
|
25040
25123
|
...authorized,
|
|
25041
|
-
data: authorized.data
|
|
25042
|
-
...row,
|
|
25043
|
-
id: `${String(row.id)}~${String(row.createdAt ?? "")}~${index}`
|
|
25044
|
-
}))
|
|
25124
|
+
data: uniqueCodexThreadRows(authorized.data)
|
|
25045
25125
|
};
|
|
25046
25126
|
}
|
|
25047
25127
|
if (call.method === "thread/start") {
|
|
@@ -26546,12 +26626,14 @@ var PluginControlRuntime = class {
|
|
|
26546
26626
|
/** Consecutive reconciliations without a DSH session: DSH refreshes its grant, so one empty read is not a sign-out. */
|
|
26547
26627
|
/** Guards against re-entry through configure(), which reads the settings view back. */
|
|
26548
26628
|
reconcilingWithDeepSeek = false;
|
|
26629
|
+
/** The authorization exchange in flight; a settings poll must not start a second one. */
|
|
26630
|
+
deepseekAuthorization;
|
|
26549
26631
|
/**
|
|
26550
26632
|
* Keep this device's Server credentials in step with DSH's DeepSeek session - that session is the credential, and
|
|
26551
26633
|
* the Server verifies it before issuing this device its own tokens.
|
|
26552
26634
|
*
|
|
26553
26635
|
* Three cases: DSH signed in and this device not authorized -> authorize; DSH signed out and this device authorized
|
|
26554
|
-
* -> sign out; otherwise nothing. At most
|
|
26636
|
+
* -> sign out; otherwise nothing. At most one exchange at a time, from the settings poll the panel already makes.
|
|
26555
26637
|
*/
|
|
26556
26638
|
async reconcileWithDeepSeek() {
|
|
26557
26639
|
if (this.deepseekSession === void 0 || this.reconcilingWithDeepSeek) return;
|
|
@@ -26560,19 +26642,20 @@ var PluginControlRuntime = class {
|
|
|
26560
26642
|
const session = await this.deepseekSession.read();
|
|
26561
26643
|
if (this.client !== void 0) this.client.hasDeepSeekSession = session !== void 0;
|
|
26562
26644
|
const authorized = this.client === void 0 ? false : await this.client.hasServerAuthorization();
|
|
26563
|
-
console.error(`[dsh-remote] reconcile ${JSON.stringify({ hasSession: session !== void 0, authorized })}`);
|
|
26564
26645
|
if (session === void 0 && authorized) {
|
|
26565
26646
|
await this.logout({ releaseDeepSeek: false });
|
|
26566
26647
|
return;
|
|
26567
26648
|
}
|
|
26568
26649
|
if (session === void 0 || authorized) return;
|
|
26650
|
+
if (this.deepseekAuthorization !== void 0) return;
|
|
26569
26651
|
if (this.client !== void 0) this.client.authorizingWithDeepSeek = true;
|
|
26570
|
-
|
|
26652
|
+
this.deepseekAuthorization = (async () => {
|
|
26571
26653
|
try {
|
|
26572
26654
|
await this.configure({ provider: "deepseek", serverUrl: this.config.serverUrl });
|
|
26573
26655
|
} catch (error) {
|
|
26574
26656
|
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26575
26657
|
} finally {
|
|
26658
|
+
this.deepseekAuthorization = void 0;
|
|
26576
26659
|
if (this.client !== void 0) this.client.authorizingWithDeepSeek = false;
|
|
26577
26660
|
}
|
|
26578
26661
|
})();
|
|
@@ -26724,13 +26807,6 @@ function redact(value, key = "") {
|
|
|
26724
26807
|
return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [childKey, redact(child, childKey)]));
|
|
26725
26808
|
}
|
|
26726
26809
|
|
|
26727
|
-
// src/codex/session-id.ts
|
|
26728
|
-
function parseCodexSessionId(value) {
|
|
26729
|
-
if (typeof value !== "string") return void 0;
|
|
26730
|
-
const match = /^codex:([A-Za-z0-9][A-Za-z0-9._-]{0,255})$/.exec(value);
|
|
26731
|
-
return match === null ? void 0 : { sessionId: value, threadId: match[1] };
|
|
26732
|
-
}
|
|
26733
|
-
|
|
26734
26810
|
// src/terminal-policy.ts
|
|
26735
26811
|
var TERMINAL_CALLS = /* @__PURE__ */ new Set([
|
|
26736
26812
|
"terminal/environment",
|
|
@@ -26744,6 +26820,7 @@ var TERMINAL_CALLS = /* @__PURE__ */ new Set([
|
|
|
26744
26820
|
]);
|
|
26745
26821
|
var TERMINAL_STREAMS = /* @__PURE__ */ new Set(["terminal/follow", "terminal/retain"]);
|
|
26746
26822
|
var id3 = external_exports.string().regex(/^[A-Za-z0-9_:-]{1,256}$/);
|
|
26823
|
+
var sessionKey = external_exports.string().regex(/^[A-Za-z0-9_:~-]{1,512}$/);
|
|
26747
26824
|
var TerminalPolicy = class {
|
|
26748
26825
|
constructor(enabled, deviceId, owners) {
|
|
26749
26826
|
this.enabled = enabled;
|
|
@@ -26758,7 +26835,7 @@ var TerminalPolicy = class {
|
|
|
26758
26835
|
);
|
|
26759
26836
|
const args = external_exports.object({ args: external_exports.record(external_exports.unknown()) }).strict().parse(payload).args;
|
|
26760
26837
|
const rawSessionId = args.agentId ?? args.sessionId;
|
|
26761
|
-
const sessionId =
|
|
26838
|
+
const sessionId = sessionKey.parse(rawSessionId);
|
|
26762
26839
|
const codexSession = parseCodexSessionId(sessionId);
|
|
26763
26840
|
void codexSession;
|
|
26764
26841
|
if (endpoint === "terminal/environment" || endpoint === "terminal/shells" || endpoint === "terminal/list") return {};
|
|
@@ -27391,8 +27468,8 @@ async function callHistoryWithRetry(callWithTimeout, payload, rpcId2, pageSizes)
|
|
|
27391
27468
|
}
|
|
27392
27469
|
throw new RpcError("INTERNAL_ERROR", "Failed to load session history with a fallback page size.");
|
|
27393
27470
|
}
|
|
27394
|
-
function sessionHistoryFallbackPageSizes(
|
|
27395
|
-
const requested = normalizeSessionHistoryPageSize(
|
|
27471
|
+
function sessionHistoryFallbackPageSizes(requestedMaxMessages2) {
|
|
27472
|
+
const requested = normalizeSessionHistoryPageSize(requestedMaxMessages2);
|
|
27396
27473
|
const sizes = [];
|
|
27397
27474
|
if (requested === void 0) {
|
|
27398
27475
|
sizes.push(...SESSION_HISTORY_PAGE_SIZES);
|
|
@@ -27755,25 +27832,25 @@ var HarnessApiBridge = class {
|
|
|
27755
27832
|
}
|
|
27756
27833
|
const nativeRequest = callSchema2.parse(request);
|
|
27757
27834
|
const response = await this.call(nativeRequest);
|
|
27758
|
-
const
|
|
27759
|
-
if (
|
|
27835
|
+
const responseBytes2 = new TextEncoder().encode(JSON.stringify(response));
|
|
27836
|
+
if (responseBytes2.byteLength <= INLINE_TRANSFER_RESPONSE_BYTES2) {
|
|
27760
27837
|
return { kind: "inline", response };
|
|
27761
27838
|
}
|
|
27762
|
-
if (
|
|
27839
|
+
if (responseBytes2.byteLength > MAX_HARNESS_API_TRANSFER_BYTES) {
|
|
27763
27840
|
throw new RpcError("RESPONSE_TOO_LARGE", "The Harness API response exceeds the bounded transfer limit.");
|
|
27764
27841
|
}
|
|
27765
27842
|
this.pruneTransfers();
|
|
27766
27843
|
if (this.outgoingTransfers.size >= MAX_ACTIVE_API_TRANSFERS) {
|
|
27767
27844
|
throw new RpcError("RATE_LIMITED", "Too many Harness API response transfers are active.", void 0, true);
|
|
27768
27845
|
}
|
|
27769
|
-
const totalChunks = Math.ceil(
|
|
27846
|
+
const totalChunks = Math.ceil(responseBytes2.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
|
|
27770
27847
|
this.outgoingTransfers.set(params.transferId, {
|
|
27771
|
-
bytes:
|
|
27848
|
+
bytes: responseBytes2,
|
|
27772
27849
|
totalChunks,
|
|
27773
27850
|
nextIndex: 0,
|
|
27774
27851
|
touchedAt: Date.now()
|
|
27775
27852
|
});
|
|
27776
|
-
return { kind: "chunked", transferId: params.transferId, totalBytes:
|
|
27853
|
+
return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
|
|
27777
27854
|
}
|
|
27778
27855
|
readTransfer(input2) {
|
|
27779
27856
|
this.pruneTransfers();
|
|
@@ -28194,6 +28271,7 @@ function concatChunks2(chunks, totalBytes) {
|
|
|
28194
28271
|
}
|
|
28195
28272
|
|
|
28196
28273
|
// src/harness-remote-bridge.ts
|
|
28274
|
+
import { Buffer as Buffer4 } from "node:buffer";
|
|
28197
28275
|
var endpointSchema = external_exports.string().min(1).max(128).regex(/^(?:\$events(?:\/result)?|[A-Za-z0-9_$.-]+\/[A-Za-z0-9_$.-]+)$/);
|
|
28198
28276
|
var callSchema3 = external_exports.object({ endpoint: endpointSchema, payload: external_exports.unknown() }).strict();
|
|
28199
28277
|
var streamOpenSchema3 = external_exports.object({
|
|
@@ -28241,6 +28319,13 @@ var directoryListSchema2 = external_exports.object({
|
|
|
28241
28319
|
var MAX_ACTIVE_STREAMS2 = MAX_ALPHA_STREAMS_PER_CONNECTION;
|
|
28242
28320
|
var MAX_ACTIVE_TRANSFERS2 = MAX_ACTIVE_TRANSFERS_PER_DIRECTION;
|
|
28243
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;
|
|
28244
28329
|
var HARNESS_REMOTE_ALLOWLIST = [
|
|
28245
28330
|
"$events",
|
|
28246
28331
|
"$events/result",
|
|
@@ -28329,6 +28414,8 @@ var HarnessRemoteBridge = class {
|
|
|
28329
28414
|
streams = /* @__PURE__ */ new Map();
|
|
28330
28415
|
incomingTransfers = /* @__PURE__ */ new Map();
|
|
28331
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();
|
|
28332
28419
|
/**
|
|
28333
28420
|
* Answer one remote Gateway call.
|
|
28334
28421
|
*
|
|
@@ -28369,7 +28456,7 @@ var HarnessRemoteBridge = class {
|
|
|
28369
28456
|
const signal = AbortSignal.timeout(6e4);
|
|
28370
28457
|
try {
|
|
28371
28458
|
const nativePayload = normalizeWorkspaceRequestPayload(params.endpoint, params.payload, this.harnessVersion);
|
|
28372
|
-
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);
|
|
28373
28460
|
const result = params.endpoint === "directoryPicker/list" && needsDirectoryFallback(nativeResult) ? await this.directoryList(params.payload, signal) : nativeResult;
|
|
28374
28461
|
this.logger?.debug("harness remote call ok", {
|
|
28375
28462
|
endpoint: params.endpoint,
|
|
@@ -28390,7 +28477,10 @@ var HarnessRemoteBridge = class {
|
|
|
28390
28477
|
this.logger?.warn("harness remote call failed", {
|
|
28391
28478
|
endpoint: params.endpoint,
|
|
28392
28479
|
durationMs: Math.round(performance.now() - startedAt),
|
|
28393
|
-
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)
|
|
28394
28484
|
});
|
|
28395
28485
|
throw error;
|
|
28396
28486
|
}
|
|
@@ -28460,22 +28550,22 @@ var HarnessRemoteBridge = class {
|
|
|
28460
28550
|
throw new RpcError("INVALID_MESSAGE", "The Harness Remote transfer does not contain a valid request.");
|
|
28461
28551
|
}
|
|
28462
28552
|
const response = await this.call(callSchema3.parse(request));
|
|
28463
|
-
const
|
|
28464
|
-
if (
|
|
28465
|
-
if (
|
|
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) {
|
|
28466
28556
|
throw new RpcError("RESPONSE_TOO_LARGE", "The Harness Remote response exceeds the bounded transfer limit.");
|
|
28467
28557
|
}
|
|
28468
28558
|
if (this.outgoingTransfers.size >= MAX_ACTIVE_TRANSFERS2) {
|
|
28469
28559
|
throw new RpcError("RATE_LIMITED", "Too many Harness Remote response transfers are active.", void 0, true);
|
|
28470
28560
|
}
|
|
28471
|
-
const totalChunks = Math.ceil(
|
|
28561
|
+
const totalChunks = Math.ceil(responseBytes2.byteLength / HARNESS_API_TRANSFER_CHUNK_BYTES);
|
|
28472
28562
|
this.outgoingTransfers.set(params.transferId, {
|
|
28473
|
-
bytes:
|
|
28563
|
+
bytes: responseBytes2,
|
|
28474
28564
|
totalChunks,
|
|
28475
28565
|
nextIndex: 0,
|
|
28476
28566
|
touchedAt: Date.now()
|
|
28477
28567
|
});
|
|
28478
|
-
return { kind: "chunked", transferId: params.transferId, totalBytes:
|
|
28568
|
+
return { kind: "chunked", transferId: params.transferId, totalBytes: responseBytes2.byteLength, totalChunks };
|
|
28479
28569
|
}
|
|
28480
28570
|
readTransfer(input2) {
|
|
28481
28571
|
this.pruneTransfers();
|
|
@@ -28493,7 +28583,7 @@ var HarnessRemoteBridge = class {
|
|
|
28493
28583
|
return {
|
|
28494
28584
|
transferId: params.transferId,
|
|
28495
28585
|
index: params.index,
|
|
28496
|
-
data:
|
|
28586
|
+
data: Buffer4.from(transfer.bytes.subarray(start, end)).toString("base64")
|
|
28497
28587
|
};
|
|
28498
28588
|
}
|
|
28499
28589
|
closeTransfer(input2) {
|
|
@@ -28513,17 +28603,135 @@ var HarnessRemoteBridge = class {
|
|
|
28513
28603
|
}
|
|
28514
28604
|
const controller = new AbortController();
|
|
28515
28605
|
this.streams.set(params.streamId, { controller });
|
|
28516
|
-
let source;
|
|
28517
28606
|
try {
|
|
28518
|
-
|
|
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);
|
|
28519
28614
|
controller.signal.throwIfAborted();
|
|
28615
|
+
void this.pump(params.streamId, source, controller.signal);
|
|
28616
|
+
return { opened: true, streamId: params.streamId };
|
|
28520
28617
|
} catch (error) {
|
|
28521
28618
|
this.streams.delete(params.streamId);
|
|
28522
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
|
+
});
|
|
28523
28624
|
throw error;
|
|
28524
28625
|
}
|
|
28525
|
-
|
|
28526
|
-
|
|
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);
|
|
28527
28735
|
}
|
|
28528
28736
|
closeStream(input2) {
|
|
28529
28737
|
const params = streamCloseSchema3.parse(input2);
|
|
@@ -28539,6 +28747,7 @@ var HarnessRemoteBridge = class {
|
|
|
28539
28747
|
this.streams.clear();
|
|
28540
28748
|
this.incomingTransfers.clear();
|
|
28541
28749
|
this.outgoingTransfers.clear();
|
|
28750
|
+
this.historyPageSizes.clear();
|
|
28542
28751
|
for (const [, stream] of streams) stream.controller.abort(reason);
|
|
28543
28752
|
await this.codexWorkspace?.closeAll();
|
|
28544
28753
|
}
|
|
@@ -28550,17 +28759,28 @@ var HarnessRemoteBridge = class {
|
|
|
28550
28759
|
throw new RpcError("FEATURE_NOT_SUPPORTED", "This Harness version does not support Remote event transport.");
|
|
28551
28760
|
}
|
|
28552
28761
|
}
|
|
28553
|
-
async pump(streamId, source, signal) {
|
|
28762
|
+
async pump(streamId, source, signal, initialFrame) {
|
|
28554
28763
|
let reason = "completed";
|
|
28555
28764
|
let failure2;
|
|
28556
28765
|
try {
|
|
28766
|
+
if (initialFrame !== void 0 && !signal.aborted) await this.publish("harness.remote.frame", initialFrame);
|
|
28557
28767
|
for await (const value of source) {
|
|
28558
28768
|
if (signal.aborted) break;
|
|
28559
|
-
|
|
28769
|
+
const frame = {
|
|
28560
28770
|
streamId,
|
|
28561
28771
|
hasValue: true,
|
|
28562
28772
|
...value === void 0 ? {} : { value: collectRpcAttachments(value) }
|
|
28563
|
-
}
|
|
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);
|
|
28564
28784
|
}
|
|
28565
28785
|
if (signal.aborted) reason = "cancelled";
|
|
28566
28786
|
} catch (error) {
|
|
@@ -28581,6 +28801,77 @@ var HarnessRemoteBridge = class {
|
|
|
28581
28801
|
for (const [id4, transfer] of this.outgoingTransfers) if (transfer.touchedAt < cutoff) this.outgoingTransfers.delete(id4);
|
|
28582
28802
|
}
|
|
28583
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
|
+
} };
|
|
28584
28875
|
function normalizeWorkspaceChangesPayload(endpoint, payload, harnessVersion) {
|
|
28585
28876
|
if (endpoint !== "workspaceFiles/changes" || !requiresWorkspaceChangePath(harnessVersion)) return payload;
|
|
28586
28877
|
if (!isRecord14(payload) || !isRecord14(payload.args) || Object.hasOwn(payload.args, "path")) return payload;
|
|
@@ -28634,7 +28925,7 @@ async function dispatchCommandForHost(gateway, payload, signal, harnessVersion)
|
|
|
28634
28925
|
);
|
|
28635
28926
|
}
|
|
28636
28927
|
function decodeCanonicalBase643(value) {
|
|
28637
|
-
const bytes =
|
|
28928
|
+
const bytes = Buffer4.from(value, "base64");
|
|
28638
28929
|
if (bytes.toString("base64") !== value) throw new RpcError("INVALID_MESSAGE", "The Harness Remote transfer chunk is invalid.");
|
|
28639
28930
|
return bytes;
|
|
28640
28931
|
}
|