ds-harness-remote 0.5.13 → 0.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/settings.d.ts.map +1 -1
- package/dist/client/settings.js +30 -11
- package/dist/client/settings.js.map +1 -1
- package/dist/client/shell.d.ts.map +1 -1
- package/dist/client/shell.js +1 -0
- package/dist/client/shell.js.map +1 -1
- package/dist/client/types.d.ts +1 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/workspaces.d.ts.map +1 -1
- package/dist/client/workspaces.js +86 -20
- package/dist/client/workspaces.js.map +1 -1
- package/dist/client-connection.d.ts.map +1 -1
- package/dist/client-connection.js +14 -9
- package/dist/client-connection.js.map +1 -1
- package/dist/client-locale.d.ts +2 -1
- package/dist/client-locale.d.ts.map +1 -1
- package/dist/client-locale.js +4 -2
- package/dist/client-locale.js.map +1 -1
- package/dist/client-runtime.d.ts +3 -0
- package/dist/client-runtime.d.ts.map +1 -1
- package/dist/client-runtime.js +112 -65
- package/dist/client-runtime.js.map +1 -1
- package/dist/client.github.js +100 -45
- package/dist/client.js +100 -45
- package/dist/control-runtime.d.ts +12 -4
- package/dist/control-runtime.d.ts.map +1 -1
- package/dist/control-runtime.js +52 -8
- package/dist/control-runtime.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +262 -132
- package/dist/index.js.map +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dsh-plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14309,11 +14309,11 @@ var AdaptiveTransport = class extends BaseTransport {
|
|
|
14309
14309
|
};
|
|
14310
14310
|
socket.onerror = () => {
|
|
14311
14311
|
if (this.lifetime === lifetime)
|
|
14312
|
-
this.failConnection(new Error(`AdaptiveTransport failed to connect to ${this.url}`));
|
|
14312
|
+
this.failConnection(new Error(`AdaptiveTransport failed to connect to ${this.url}`), { reason: "control-error" });
|
|
14313
14313
|
};
|
|
14314
14314
|
socket.onclose = (event) => {
|
|
14315
14315
|
if (this.lifetime === lifetime)
|
|
14316
|
-
this.failConnection(adaptiveControlCloseError(event));
|
|
14316
|
+
this.failConnection(adaptiveControlCloseError(event), { reason: "control-closed", closeCode: event.code });
|
|
14317
14317
|
};
|
|
14318
14318
|
});
|
|
14319
14319
|
}
|
|
@@ -14483,7 +14483,7 @@ var AdaptiveTransport = class extends BaseTransport {
|
|
|
14483
14483
|
if (frame.type === "ping")
|
|
14484
14484
|
this.sendControl("pong", frame.payload);
|
|
14485
14485
|
} catch (error) {
|
|
14486
|
-
this.failConnection(error instanceof Error ? error : new Error("Invalid adaptive control frame"));
|
|
14486
|
+
this.failConnection(error instanceof Error ? error : new Error("Invalid adaptive control frame"), { reason: "invalid-control-frame" });
|
|
14487
14487
|
}
|
|
14488
14488
|
}
|
|
14489
14489
|
handleRelay(payload) {
|
|
@@ -14596,8 +14596,9 @@ var AdaptiveTransport = class extends BaseTransport {
|
|
|
14596
14596
|
this.emit(data2);
|
|
14597
14597
|
});
|
|
14598
14598
|
rtc.onClose(() => {
|
|
14599
|
-
if (this.rtc === rtc && this.dataMode === "webrtc")
|
|
14600
|
-
this.
|
|
14599
|
+
if (this.rtc === rtc && this.dataMode === "webrtc") {
|
|
14600
|
+
this.failConnection(new Error("Active WebRTC channel closed"), { reason: "webrtc-closed" });
|
|
14601
|
+
}
|
|
14601
14602
|
});
|
|
14602
14603
|
try {
|
|
14603
14604
|
await rtc.connect(signal);
|
|
@@ -14688,7 +14689,8 @@ var AdaptiveTransport = class extends BaseTransport {
|
|
|
14688
14689
|
this.readyResolve = void 0;
|
|
14689
14690
|
this.readyReject = void 0;
|
|
14690
14691
|
}
|
|
14691
|
-
failConnection(error) {
|
|
14692
|
+
failConnection(error, diagnostic) {
|
|
14693
|
+
const established = this.connectedAt !== void 0;
|
|
14692
14694
|
this.clearHandshake();
|
|
14693
14695
|
const reject = this.readyReject;
|
|
14694
14696
|
this.readyResolve = void 0;
|
|
@@ -14707,6 +14709,12 @@ var AdaptiveTransport = class extends BaseTransport {
|
|
|
14707
14709
|
reject?.(error);
|
|
14708
14710
|
void rtc?.close();
|
|
14709
14711
|
socket?.close();
|
|
14712
|
+
if (established && diagnostic !== void 0) {
|
|
14713
|
+
try {
|
|
14714
|
+
this.options.onDisconnect?.(diagnostic);
|
|
14715
|
+
} catch {
|
|
14716
|
+
}
|
|
14717
|
+
}
|
|
14710
14718
|
if (socket !== void 0)
|
|
14711
14719
|
this.emitClose();
|
|
14712
14720
|
}
|
|
@@ -22260,16 +22268,24 @@ var ClientConnection = class {
|
|
|
22260
22268
|
this.context.connectionProgress = { runId: progressRunId, targetDeviceId, phase: "checking-host" };
|
|
22261
22269
|
const identity2 = this.context.requireIdentity();
|
|
22262
22270
|
let client;
|
|
22271
|
+
const onAbort = () => {
|
|
22272
|
+
void client?.close().catch(() => void 0);
|
|
22273
|
+
};
|
|
22274
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
22263
22275
|
try {
|
|
22264
22276
|
const serverDevice = (await this.context.server.listDevices()).find((device) => device.deviceId === targetDeviceId);
|
|
22277
|
+
signal?.throwIfAborted();
|
|
22265
22278
|
if (serverDevice === void 0) {
|
|
22266
22279
|
throw new ClientModeError("MEMBERSHIP_REQUIRED", "The selected Host is not authorized for this account.");
|
|
22267
22280
|
}
|
|
22268
22281
|
this.updateConnectionProgress(progressRunId, "authorizing-peer");
|
|
22269
22282
|
const target2 = await this.authorizeHostPeer(serverDevice);
|
|
22283
|
+
signal?.throwIfAborted();
|
|
22270
22284
|
const presence = await this.context.server.presenceFor(targetDeviceId);
|
|
22285
|
+
signal?.throwIfAborted();
|
|
22271
22286
|
if (!presence.online) throw new ClientModeError("HOST_OFFLINE", "The selected Host is offline.", true);
|
|
22272
22287
|
const credentials = await this.context.server.authenticate(identity2);
|
|
22288
|
+
signal?.throwIfAborted();
|
|
22273
22289
|
const rtcFactory = this.context.config.forceRelay ? void 0 : await this.context.rtcFactoryProvider({ routeTargets: [this.context.server.baseUrl] }).catch(() => void 0);
|
|
22274
22290
|
if (!this.context.config.forceRelay && rtcFactory === void 0) {
|
|
22275
22291
|
this.context.logger.warn("remote Harness WebRTC backend unavailable; using relay", {
|
|
@@ -22315,16 +22331,8 @@ var ClientConnection = class {
|
|
|
22315
22331
|
transport = createTransport(attempt);
|
|
22316
22332
|
client = new RemoteClientCore(new ClientSecureTransport(transport, identity2, target2), 6e4);
|
|
22317
22333
|
const attemptClient = client;
|
|
22318
|
-
|
|
22319
|
-
|
|
22320
|
-
};
|
|
22321
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
22322
|
-
try {
|
|
22323
|
-
signal?.throwIfAborted();
|
|
22324
|
-
await attemptClient.connect();
|
|
22325
|
-
} finally {
|
|
22326
|
-
signal?.removeEventListener("abort", onAbort);
|
|
22327
|
-
}
|
|
22334
|
+
signal?.throwIfAborted();
|
|
22335
|
+
await attemptClient.connect();
|
|
22328
22336
|
signal?.throwIfAborted();
|
|
22329
22337
|
} finally {
|
|
22330
22338
|
stopProgressTimer();
|
|
@@ -22382,6 +22390,7 @@ var ClientConnection = class {
|
|
|
22382
22390
|
});
|
|
22383
22391
|
}
|
|
22384
22392
|
const features = await probeRemoteHostFeatures(connectedClient, serverDevice.clientVersion);
|
|
22393
|
+
signal?.throwIfAborted();
|
|
22385
22394
|
return {
|
|
22386
22395
|
client: connectedClient,
|
|
22387
22396
|
target: target2,
|
|
@@ -22395,6 +22404,8 @@ var ClientConnection = class {
|
|
|
22395
22404
|
this.clearConnectionProgress(progressRunId);
|
|
22396
22405
|
await client?.close().catch(() => void 0);
|
|
22397
22406
|
throw error;
|
|
22407
|
+
} finally {
|
|
22408
|
+
signal?.removeEventListener("abort", onAbort);
|
|
22398
22409
|
}
|
|
22399
22410
|
}
|
|
22400
22411
|
beginAttemptProgress(runId, attempt) {
|
|
@@ -27404,7 +27415,7 @@ function normalizeServerUrl(value) {
|
|
|
27404
27415
|
}
|
|
27405
27416
|
|
|
27406
27417
|
// src/version.ts
|
|
27407
|
-
var PLUGIN_VERSION = "0.5.
|
|
27418
|
+
var PLUGIN_VERSION = "0.5.14";
|
|
27408
27419
|
|
|
27409
27420
|
// src/server-api.ts
|
|
27410
27421
|
var TERMINAL_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
@@ -29530,8 +29541,16 @@ var ClientModeRuntime = class {
|
|
|
29530
29541
|
this.proxySwitch = apiProxy === void 0 ? void 0 : new ApiProxySwitch(apiProxy);
|
|
29531
29542
|
this.gatewaySwitch = new TypertGatewaySwitch(typertGateway);
|
|
29532
29543
|
}
|
|
29533
|
-
connect(targetDeviceId, signal) {
|
|
29534
|
-
|
|
29544
|
+
async connect(targetDeviceId, signal) {
|
|
29545
|
+
const lifetime = this.remoteLifetime.signal;
|
|
29546
|
+
const connectionSignal = signal === void 0 ? lifetime : AbortSignal.any([lifetime, signal]);
|
|
29547
|
+
connectionSignal.throwIfAborted();
|
|
29548
|
+
const remote = await this.connection.connect(targetDeviceId, connectionSignal);
|
|
29549
|
+
if (connectionSignal.aborted || this.closed) {
|
|
29550
|
+
await remote.client.close().catch(() => void 0);
|
|
29551
|
+
throw new ClientModeError("CANCELLED", "The Remote connection request was superseded or closed.");
|
|
29552
|
+
}
|
|
29553
|
+
return remote;
|
|
29535
29554
|
}
|
|
29536
29555
|
handleControl(endpoint, payload, signal) {
|
|
29537
29556
|
return this.control.handleControl(endpoint, payload, signal);
|
|
@@ -29555,6 +29574,7 @@ var ClientModeRuntime = class {
|
|
|
29555
29574
|
connectionProgress;
|
|
29556
29575
|
connectionProgressRun = 0;
|
|
29557
29576
|
closed = false;
|
|
29577
|
+
remoteLifetime = new AbortController();
|
|
29558
29578
|
async start() {
|
|
29559
29579
|
if (this.closed) throw new Error("client remote-mode runtime is closed");
|
|
29560
29580
|
this.identity = await this.identities.loadOrCreate(this.config.deviceName);
|
|
@@ -29698,21 +29718,13 @@ var ClientModeRuntime = class {
|
|
|
29698
29718
|
return result;
|
|
29699
29719
|
}
|
|
29700
29720
|
async clearClientAuthorization() {
|
|
29701
|
-
const
|
|
29702
|
-
this.connected = void 0;
|
|
29703
|
-
this.connectionProgress = void 0;
|
|
29704
|
-
this.pendingWorkspaceSelection = void 0;
|
|
29705
|
-
await this.closeCodexVirtual();
|
|
29721
|
+
const cleanup = this.leaveRemote();
|
|
29706
29722
|
this.codexOpenedSessions.clear();
|
|
29707
|
-
await this.
|
|
29708
|
-
this.proxySwitch?.selectLocal();
|
|
29709
|
-
await this.closePreview();
|
|
29710
|
-
this.gatewaySwitch.selectLocal();
|
|
29711
|
-
await this.codexStreamBridge.closeCodexStreams(previous?.client);
|
|
29712
|
-
await previous?.client.close().catch(() => void 0);
|
|
29713
|
-
await this.server.revokeCurrentDevice();
|
|
29723
|
+
const results = await Promise.allSettled([cleanup, this.server.revokeCurrentDevice()]);
|
|
29714
29724
|
this.identity = await this.identities.reset(this.config.deviceName);
|
|
29715
29725
|
this.server.bindIdentity(this.identity);
|
|
29726
|
+
const failure4 = results.find((result) => result.status === "rejected");
|
|
29727
|
+
if (failure4?.status === "rejected") throw failure4.reason;
|
|
29716
29728
|
}
|
|
29717
29729
|
async setHostAuthorization(enabled) {
|
|
29718
29730
|
if (this.host === void 0) throw new ClientModeError("METHOD_NOT_ALLOWED", "This plugin is not running as a Host.");
|
|
@@ -29726,23 +29738,14 @@ var ClientModeRuntime = class {
|
|
|
29726
29738
|
}
|
|
29727
29739
|
async setMode(mode2, targetDeviceId, signal) {
|
|
29728
29740
|
if (mode2 === "local") {
|
|
29729
|
-
await this.
|
|
29730
|
-
await this.closeCursorVirtual();
|
|
29731
|
-
this.proxySwitch?.selectLocal();
|
|
29732
|
-
await this.closePreview();
|
|
29733
|
-
this.gatewaySwitch.selectLocal();
|
|
29734
|
-
const previous2 = this.connected;
|
|
29735
|
-
this.connected = void 0;
|
|
29736
|
-
this.connectionProgress = void 0;
|
|
29737
|
-
this.pendingWorkspaceSelection = void 0;
|
|
29738
|
-
await this.codexStreamBridge.closeCodexStreams(previous2?.client);
|
|
29739
|
-
await previous2?.client.close().catch(() => void 0);
|
|
29741
|
+
await this.leaveRemote();
|
|
29740
29742
|
this.logger.info("Harness target switched", { mode: "local" });
|
|
29741
29743
|
return this.status();
|
|
29742
29744
|
}
|
|
29743
29745
|
if (targetDeviceId === void 0 || targetDeviceId.length === 0) {
|
|
29744
29746
|
throw new ClientModeError("INVALID_MESSAGE", "A targetDeviceId is required for remote mode.");
|
|
29745
29747
|
}
|
|
29748
|
+
const lifetime = this.remoteLifetime.signal;
|
|
29746
29749
|
const next = await this.connect(targetDeviceId, signal);
|
|
29747
29750
|
try {
|
|
29748
29751
|
this.assertRemoteCompatible(next);
|
|
@@ -29753,11 +29756,17 @@ var ClientModeRuntime = class {
|
|
|
29753
29756
|
}
|
|
29754
29757
|
const previous = this.connected;
|
|
29755
29758
|
await this.closePreview();
|
|
29759
|
+
if (lifetime.aborted || this.closed) {
|
|
29760
|
+
await next.client.close().catch(() => void 0);
|
|
29761
|
+
throw new ClientModeError("CANCELLED", "The Remote connection request was superseded or closed.");
|
|
29762
|
+
}
|
|
29756
29763
|
this.connected = next;
|
|
29757
29764
|
this.connection.clearConnectionProgress(next.progressRunId);
|
|
29758
29765
|
this.pendingWorkspaceSelection = void 0;
|
|
29759
29766
|
await this.closeCodexVirtual();
|
|
29767
|
+
this.assertRemoteCurrent(next, signal);
|
|
29760
29768
|
await this.closeCursorVirtual();
|
|
29769
|
+
this.assertRemoteCurrent(next, signal);
|
|
29761
29770
|
this.selectRemoteTarget(next);
|
|
29762
29771
|
await this.codexStreamBridge.closeCodexStreams(previous?.client);
|
|
29763
29772
|
await previous?.client.close().catch(() => void 0);
|
|
@@ -29815,8 +29824,11 @@ var ClientModeRuntime = class {
|
|
|
29815
29824
|
});
|
|
29816
29825
|
workspace = unwrapNativeResult(response);
|
|
29817
29826
|
}
|
|
29827
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29818
29828
|
await this.closeCodexVirtual();
|
|
29829
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29819
29830
|
await this.closeCursorVirtual();
|
|
29831
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29820
29832
|
this.selectRemoteTarget(remote, transport);
|
|
29821
29833
|
const workspaceId = workspaceRecordId(workspace.workspace);
|
|
29822
29834
|
this.pendingWorkspaceSelection = { targetDeviceId: remote.target.deviceId, workspaceId };
|
|
@@ -29898,6 +29910,7 @@ var ClientModeRuntime = class {
|
|
|
29898
29910
|
idempotencyKey: uuidV7()
|
|
29899
29911
|
}, signal));
|
|
29900
29912
|
const project = record2(result.project);
|
|
29913
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29901
29914
|
if (typeof project.id !== "string" || project.id.length === 0) {
|
|
29902
29915
|
throw new ClientModeError("INVALID_MESSAGE", "The Host returned an invalid CodeX project.");
|
|
29903
29916
|
}
|
|
@@ -29929,23 +29942,32 @@ var ClientModeRuntime = class {
|
|
|
29929
29942
|
}, backend, remote.features.acpModelLoadsSession ? ["agent.acp.antigravity.model-load.v1"] : [], new RemoteTypertGateway2(remote.client));
|
|
29930
29943
|
let workspace;
|
|
29931
29944
|
try {
|
|
29932
|
-
|
|
29933
|
-
|
|
29945
|
+
try {
|
|
29946
|
+
workspace = await virtual.selectWorkspace(workspaceId);
|
|
29947
|
+
} catch {
|
|
29948
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29949
|
+
throw new ClientModeError("WORKSPACE_NOT_FOUND", `The selected ${backend} workspace is no longer available.`);
|
|
29950
|
+
}
|
|
29951
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29952
|
+
await this.closeCodexVirtual();
|
|
29953
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29954
|
+
await this.closeCursorVirtual();
|
|
29955
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29956
|
+
const preferredSessionId = await virtual.preferredSessionId();
|
|
29957
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29958
|
+
this.cursorVirtual = virtual;
|
|
29959
|
+
this.acpVirtualBackend = backend;
|
|
29960
|
+
this.selectCursorTarget(virtual, remote);
|
|
29961
|
+
this.pendingWorkspaceSelection = {
|
|
29962
|
+
targetDeviceId: remote.target.deviceId,
|
|
29963
|
+
workspaceId: workspace.workspaceId,
|
|
29964
|
+
backend,
|
|
29965
|
+
...preferredSessionId === void 0 ? {} : { sessionId: preferredSessionId }
|
|
29966
|
+
};
|
|
29967
|
+
} catch (error) {
|
|
29934
29968
|
await virtual.close();
|
|
29935
|
-
throw
|
|
29969
|
+
throw error;
|
|
29936
29970
|
}
|
|
29937
|
-
await this.closeCodexVirtual();
|
|
29938
|
-
await this.closeCursorVirtual();
|
|
29939
|
-
this.cursorVirtual = virtual;
|
|
29940
|
-
this.acpVirtualBackend = backend;
|
|
29941
|
-
this.selectCursorTarget(virtual, remote);
|
|
29942
|
-
const preferredSessionId = await virtual.preferredSessionId();
|
|
29943
|
-
this.pendingWorkspaceSelection = {
|
|
29944
|
-
targetDeviceId: remote.target.deviceId,
|
|
29945
|
-
workspaceId: workspace.workspaceId,
|
|
29946
|
-
backend,
|
|
29947
|
-
...preferredSessionId === void 0 ? {} : { sessionId: preferredSessionId }
|
|
29948
|
-
};
|
|
29949
29971
|
this.logger.info(`${backend} virtual workspace opened`, { targetDeviceId: shortId(remote.target.deviceId) });
|
|
29950
29972
|
return { ...this.status(), workspace };
|
|
29951
29973
|
}
|
|
@@ -29962,19 +29984,27 @@ var ClientModeRuntime = class {
|
|
|
29962
29984
|
deviceId: remote.target.deviceId,
|
|
29963
29985
|
name: remote.target.name
|
|
29964
29986
|
}, backend, remote.features.acpModelLoadsSession ? ["agent.acp.antigravity.model-load.v1"] : [], new RemoteTypertGateway2(remote.client));
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
|
|
29971
|
-
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
29976
|
-
|
|
29977
|
-
|
|
29987
|
+
try {
|
|
29988
|
+
const workspace = await virtual.selectOrCreateWorkspace(trimmedPath);
|
|
29989
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29990
|
+
await this.closeCodexVirtual();
|
|
29991
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29992
|
+
await this.closeCursorVirtual();
|
|
29993
|
+
this.assertRemoteCurrent(remote, signal);
|
|
29994
|
+
this.cursorVirtual = virtual;
|
|
29995
|
+
this.acpVirtualBackend = backend;
|
|
29996
|
+
this.selectCursorTarget(virtual, remote);
|
|
29997
|
+
this.pendingWorkspaceSelection = {
|
|
29998
|
+
targetDeviceId: remote.target.deviceId,
|
|
29999
|
+
workspaceId: workspace.workspaceId,
|
|
30000
|
+
backend
|
|
30001
|
+
};
|
|
30002
|
+
this.logger.info(`${backend} virtual workspace created`, { targetDeviceId: shortId(remote.target.deviceId) });
|
|
30003
|
+
return { ...this.status(), workspace };
|
|
30004
|
+
} catch (error) {
|
|
30005
|
+
await virtual.close();
|
|
30006
|
+
throw error;
|
|
30007
|
+
}
|
|
29978
30008
|
}
|
|
29979
30009
|
consumeWorkspaceSelection(selection) {
|
|
29980
30010
|
const pending = this.pendingWorkspaceSelection;
|
|
@@ -29984,21 +30014,34 @@ var ClientModeRuntime = class {
|
|
|
29984
30014
|
return this.status();
|
|
29985
30015
|
}
|
|
29986
30016
|
async close() {
|
|
29987
|
-
await this.closePreview();
|
|
29988
30017
|
if (this.closed) return;
|
|
29989
30018
|
this.closed = true;
|
|
29990
|
-
this.
|
|
29991
|
-
|
|
29992
|
-
|
|
29993
|
-
|
|
29994
|
-
|
|
29995
|
-
|
|
29996
|
-
|
|
29997
|
-
|
|
30019
|
+
this.server.close?.();
|
|
30020
|
+
try {
|
|
30021
|
+
await this.leaveRemote();
|
|
30022
|
+
} finally {
|
|
30023
|
+
this.proxySwitch?.restore();
|
|
30024
|
+
this.gatewaySwitch.restore();
|
|
30025
|
+
}
|
|
30026
|
+
}
|
|
30027
|
+
async leaveRemote() {
|
|
30028
|
+
this.remoteLifetime.abort(new ClientModeError("CANCELLED", "The Remote connection was closed."));
|
|
30029
|
+
this.remoteLifetime = new AbortController();
|
|
30030
|
+
const previous = this.connected;
|
|
29998
30031
|
this.connected = void 0;
|
|
29999
30032
|
this.connectionProgress = void 0;
|
|
30000
|
-
this.
|
|
30001
|
-
this.
|
|
30033
|
+
this.pendingWorkspaceSelection = void 0;
|
|
30034
|
+
this.proxySwitch?.selectLocal();
|
|
30035
|
+
this.gatewaySwitch.selectLocal();
|
|
30036
|
+
const results = await Promise.allSettled([
|
|
30037
|
+
this.closeCodexVirtual(),
|
|
30038
|
+
this.closeCursorVirtual(),
|
|
30039
|
+
this.closePreview(),
|
|
30040
|
+
this.codexStreamBridge.closeCodexStreams(previous?.client),
|
|
30041
|
+
previous?.client.close()
|
|
30042
|
+
]);
|
|
30043
|
+
const failure4 = results.find((result) => result.status === "rejected");
|
|
30044
|
+
if (failure4?.status === "rejected") throw failure4.reason;
|
|
30002
30045
|
}
|
|
30003
30046
|
async callRemoteFileViewer(endpoint, payload, signal) {
|
|
30004
30047
|
const remote = this.connected;
|
|
@@ -30111,11 +30154,12 @@ var ClientModeRuntime = class {
|
|
|
30111
30154
|
);
|
|
30112
30155
|
}
|
|
30113
30156
|
async ensureConnected(targetDeviceId, signal, isCurrent) {
|
|
30157
|
+
const lifetime = this.remoteLifetime.signal;
|
|
30114
30158
|
if (this.connected?.target.deviceId === targetDeviceId) return this.connected;
|
|
30115
30159
|
const next = await this.connect(targetDeviceId, signal);
|
|
30116
30160
|
const assertCurrent = () => {
|
|
30117
30161
|
signal?.throwIfAborted();
|
|
30118
|
-
if (this.closed || isCurrent?.() === false) {
|
|
30162
|
+
if (this.closed || lifetime.aborted || isCurrent?.() === false) {
|
|
30119
30163
|
throw new ClientModeError("CANCELLED", "The Remote connection request was superseded or closed.");
|
|
30120
30164
|
}
|
|
30121
30165
|
};
|
|
@@ -30134,6 +30178,12 @@ var ClientModeRuntime = class {
|
|
|
30134
30178
|
await previous?.client.close().catch(() => void 0);
|
|
30135
30179
|
return next;
|
|
30136
30180
|
}
|
|
30181
|
+
assertRemoteCurrent(remote, signal) {
|
|
30182
|
+
signal?.throwIfAborted();
|
|
30183
|
+
if (this.closed || this.connected !== remote) {
|
|
30184
|
+
throw new ClientModeError("CANCELLED", "The Remote workspace request was superseded or closed.");
|
|
30185
|
+
}
|
|
30186
|
+
}
|
|
30137
30187
|
requireIdentity() {
|
|
30138
30188
|
if (this.identity === void 0) throw new ClientModeError("IDENTITY_INVALID", "The client identity is not ready.");
|
|
30139
30189
|
return this.identity;
|
|
@@ -37765,13 +37815,16 @@ function isRecord19(value) {
|
|
|
37765
37815
|
|
|
37766
37816
|
// src/control-runtime.ts
|
|
37767
37817
|
var PluginControlRuntime = class {
|
|
37768
|
-
constructor(config, identityDirectory, settings, client, host) {
|
|
37818
|
+
constructor(config, identityDirectory, settings, client, host, switchServer) {
|
|
37769
37819
|
this.config = config;
|
|
37770
37820
|
this.identityDirectory = identityDirectory;
|
|
37771
37821
|
this.settings = settings;
|
|
37772
37822
|
this.client = client;
|
|
37773
37823
|
this.host = host;
|
|
37824
|
+
this.switchServer = switchServer;
|
|
37774
37825
|
}
|
|
37826
|
+
logoutFlight;
|
|
37827
|
+
serverSwitchFlight;
|
|
37775
37828
|
register(connection, webServer) {
|
|
37776
37829
|
const statusStream = new ControlStatusStream(() => this.streamStatus());
|
|
37777
37830
|
return registerControlRoute(
|
|
@@ -37793,6 +37846,7 @@ var PluginControlRuntime = class {
|
|
|
37793
37846
|
}
|
|
37794
37847
|
async handle(endpoint, payload, signal) {
|
|
37795
37848
|
try {
|
|
37849
|
+
if (endpoint !== "settings.server.set") await this.serverSwitchFlight;
|
|
37796
37850
|
if (endpoint === "settings.development.set") return ok3(await this.setDevelopment(payload));
|
|
37797
37851
|
if (endpoint === "settings.get") return ok3(await this.settingsView());
|
|
37798
37852
|
if (endpoint === "settings.configure") return ok3(await this.configure(payload));
|
|
@@ -37886,6 +37940,19 @@ var PluginControlRuntime = class {
|
|
|
37886
37940
|
};
|
|
37887
37941
|
}
|
|
37888
37942
|
async setServer(payload) {
|
|
37943
|
+
if (this.serverSwitchFlight !== void 0) {
|
|
37944
|
+
throw new ClientModeError("SERVER_SWITCH_BUSY", "A Server switch is already in progress.");
|
|
37945
|
+
}
|
|
37946
|
+
const flight = this.applyServer(payload);
|
|
37947
|
+
this.serverSwitchFlight = flight;
|
|
37948
|
+
try {
|
|
37949
|
+
return await flight;
|
|
37950
|
+
} finally {
|
|
37951
|
+
if (this.serverSwitchFlight === flight) this.serverSwitchFlight = void 0;
|
|
37952
|
+
}
|
|
37953
|
+
}
|
|
37954
|
+
async applyServer(payload) {
|
|
37955
|
+
await this.logoutFlight;
|
|
37889
37956
|
if (this.settings === void 0) {
|
|
37890
37957
|
throw new ClientModeError("SETTINGS_UNAVAILABLE", "DSH user settings are unavailable in this profile.");
|
|
37891
37958
|
}
|
|
@@ -37896,6 +37963,15 @@ var PluginControlRuntime = class {
|
|
|
37896
37963
|
const current = editableConfig(resolveConfig(this.settings.get()));
|
|
37897
37964
|
const next = resolveConfig({ ...current, serverUrl: value.serverUrl });
|
|
37898
37965
|
await this.settings.replace(editableConfig(next));
|
|
37966
|
+
if (this.switchServer !== void 0) {
|
|
37967
|
+
if (next.serverUrl !== this.config.serverUrl) {
|
|
37968
|
+
const runtimes = await this.switchServer(next);
|
|
37969
|
+
this.client = runtimes.client;
|
|
37970
|
+
this.host = runtimes.host;
|
|
37971
|
+
}
|
|
37972
|
+
this.config = next;
|
|
37973
|
+
return { ...await this.settingsView(), applies: "live" };
|
|
37974
|
+
}
|
|
37899
37975
|
return this.settingsView();
|
|
37900
37976
|
}
|
|
37901
37977
|
async setRole(payload) {
|
|
@@ -38017,20 +38093,28 @@ var PluginControlRuntime = class {
|
|
|
38017
38093
|
const targetApi = targetRole === "host" ? new HostServerApi(serverUrl, new ServerCredentialStore(targetDirectory)) : new ClientServerApi(serverUrl, new ServerCredentialStore(targetDirectory));
|
|
38018
38094
|
await targetApi.authorizeOwnedRole(targetIdentity, sourceCredentials.accessToken, sourceCredentials.account);
|
|
38019
38095
|
}
|
|
38020
|
-
|
|
38021
|
-
if (this.
|
|
38022
|
-
|
|
38023
|
-
|
|
38024
|
-
|
|
38096
|
+
logout() {
|
|
38097
|
+
if (this.logoutFlight !== void 0) return this.logoutFlight;
|
|
38098
|
+
const task = this.clearAuthorization();
|
|
38099
|
+
this.logoutFlight = task;
|
|
38100
|
+
void task.finally(() => {
|
|
38101
|
+
if (this.logoutFlight === task) this.logoutFlight = void 0;
|
|
38102
|
+
}).catch(() => void 0);
|
|
38103
|
+
return task;
|
|
38104
|
+
}
|
|
38105
|
+
async clearAuthorization() {
|
|
38106
|
+
const config = this.settings === void 0 ? this.config : resolveConfig(this.settings.get());
|
|
38025
38107
|
if (config.serverUrl !== void 0) {
|
|
38026
|
-
await Promise.
|
|
38108
|
+
const runtimes = await Promise.allSettled([
|
|
38027
38109
|
this.client?.clearClientAuthorization(),
|
|
38028
38110
|
this.host?.clearHostAuthorization()
|
|
38029
38111
|
]);
|
|
38030
|
-
await Promise.
|
|
38112
|
+
const stores = await Promise.allSettled(["host", "client"].map(async (role) => {
|
|
38031
38113
|
const directory = serverStorageDirectory(this.identityDirectory, config.serverUrl, role);
|
|
38032
38114
|
await new ServerCredentialStore(directory).clear();
|
|
38033
38115
|
}));
|
|
38116
|
+
const failure4 = [...runtimes, ...stores].find((result) => result.status === "rejected");
|
|
38117
|
+
if (failure4?.status === "rejected") throw failure4.reason;
|
|
38034
38118
|
}
|
|
38035
38119
|
return this.settingsView();
|
|
38036
38120
|
}
|
|
@@ -42704,9 +42788,6 @@ async function activate(ctx, readConfig, entryId, tuiBinding) {
|
|
|
42704
42788
|
console.error(message);
|
|
42705
42789
|
}
|
|
42706
42790
|
}, config.logLevel);
|
|
42707
|
-
const hostIdentities = new IdentityStore({
|
|
42708
|
-
directory: config.serverUrl === void 0 ? defaultIdentityDirectory : serverStorageDirectory(defaultIdentityDirectory, config.serverUrl, "host")
|
|
42709
|
-
});
|
|
42710
42791
|
const apiProxy = ctx.get("apiProxy");
|
|
42711
42792
|
const nativeTypertGateway = ctx.get("typertGateway");
|
|
42712
42793
|
const hostGateway = new TypertGatewaySwitch(nativeTypertGateway);
|
|
@@ -42725,56 +42806,103 @@ async function activate(ctx, readConfig, entryId, tuiBinding) {
|
|
|
42725
42806
|
};
|
|
42726
42807
|
}
|
|
42727
42808
|
const subprocess = ctx.get("subprocess", false);
|
|
42728
|
-
const
|
|
42729
|
-
|
|
42730
|
-
|
|
42731
|
-
apiProxy,
|
|
42732
|
-
logger,
|
|
42733
|
-
localTypertGateway,
|
|
42734
|
-
() => ctx.get("fileViewerHost"),
|
|
42735
|
-
subprocess === void 0 ? void 0 : subprocessTerminalSpawner(subprocess),
|
|
42736
|
-
(peer) => createPluginRouteDispatcher(
|
|
42737
|
-
() => ctx.get("connection"),
|
|
42738
|
-
() => ctx.get("webServer")?.port,
|
|
42739
|
-
peer
|
|
42740
|
-
)
|
|
42741
|
-
);
|
|
42742
|
-
let clientRuntime;
|
|
42743
|
-
const hostControl = runtime;
|
|
42744
|
-
if (config.serverUrl !== void 0 && connection !== void 0) {
|
|
42745
|
-
const clientIdentities = new IdentityStore({
|
|
42746
|
-
directory: serverStorageDirectory(defaultIdentityDirectory, config.serverUrl, "client")
|
|
42809
|
+
const createRuntimes = (config2) => {
|
|
42810
|
+
const hostIdentities = new IdentityStore({
|
|
42811
|
+
directory: config2.serverUrl === void 0 ? defaultIdentityDirectory : serverStorageDirectory(defaultIdentityDirectory, config2.serverUrl, "host")
|
|
42747
42812
|
});
|
|
42748
|
-
|
|
42749
|
-
|
|
42750
|
-
|
|
42751
|
-
new ClientServerApi(config.serverUrl, new ServerCredentialStore(clientIdentities.directory)),
|
|
42813
|
+
const runtime2 = new HostPluginRuntime(
|
|
42814
|
+
config2,
|
|
42815
|
+
hostIdentities,
|
|
42752
42816
|
apiProxy,
|
|
42753
|
-
nativeTypertGateway,
|
|
42754
42817
|
logger,
|
|
42755
|
-
|
|
42818
|
+
localTypertGateway,
|
|
42819
|
+
() => ctx.get("fileViewerHost"),
|
|
42820
|
+
subprocess === void 0 ? void 0 : subprocessTerminalSpawner(subprocess),
|
|
42821
|
+
(peer) => createPluginRouteDispatcher(
|
|
42822
|
+
() => ctx.get("connection"),
|
|
42823
|
+
() => ctx.get("webServer")?.port,
|
|
42824
|
+
peer
|
|
42825
|
+
)
|
|
42756
42826
|
);
|
|
42757
|
-
|
|
42758
|
-
|
|
42827
|
+
let clientRuntime2;
|
|
42828
|
+
if (config2.serverUrl !== void 0 && connection !== void 0) {
|
|
42829
|
+
const clientIdentities = new IdentityStore({
|
|
42830
|
+
directory: serverStorageDirectory(defaultIdentityDirectory, config2.serverUrl, "client")
|
|
42831
|
+
});
|
|
42832
|
+
clientRuntime2 = new ClientModeRuntime(
|
|
42833
|
+
config2,
|
|
42834
|
+
clientIdentities,
|
|
42835
|
+
new ClientServerApi(config2.serverUrl, new ServerCredentialStore(clientIdentities.directory)),
|
|
42836
|
+
apiProxy,
|
|
42837
|
+
nativeTypertGateway,
|
|
42838
|
+
logger,
|
|
42839
|
+
runtime2
|
|
42840
|
+
);
|
|
42841
|
+
}
|
|
42842
|
+
return { runtime: runtime2, clientRuntime: clientRuntime2 };
|
|
42843
|
+
};
|
|
42844
|
+
let { runtime, clientRuntime } = createRuntimes(config);
|
|
42845
|
+
let closed = false;
|
|
42846
|
+
let clientServiceProvided = clientRuntime !== void 0;
|
|
42847
|
+
let startup;
|
|
42848
|
+
let replacement;
|
|
42849
|
+
const replaceServer = (next) => {
|
|
42850
|
+
const operation = async () => {
|
|
42851
|
+
await startup;
|
|
42852
|
+
if (closed) throw new Error("Remote plugin is closed");
|
|
42853
|
+
const shutdown = await Promise.allSettled([clientRuntime?.close(), runtime.close()]);
|
|
42854
|
+
const failure4 = shutdown.find((result) => result.status === "rejected");
|
|
42855
|
+
if (failure4?.status === "rejected") throw failure4.reason;
|
|
42856
|
+
if (closed) throw new Error("Remote plugin is closed");
|
|
42857
|
+
const fresh = createRuntimes(next);
|
|
42858
|
+
try {
|
|
42859
|
+
await fresh.runtime.start();
|
|
42860
|
+
await fresh.clientRuntime?.start();
|
|
42861
|
+
if (closed) throw new Error("Remote plugin is closed");
|
|
42862
|
+
} catch (error) {
|
|
42863
|
+
await Promise.allSettled([fresh.clientRuntime?.close(), fresh.runtime.close()]);
|
|
42864
|
+
throw error;
|
|
42865
|
+
}
|
|
42866
|
+
runtime = fresh.runtime;
|
|
42867
|
+
clientRuntime = fresh.clientRuntime;
|
|
42868
|
+
ctx.dshRemote = runtime;
|
|
42869
|
+
if (clientRuntime !== void 0) {
|
|
42870
|
+
if (clientServiceProvided) ctx.dshRemoteClient = clientRuntime;
|
|
42871
|
+
else {
|
|
42872
|
+
ctx.provide("dshRemoteClient", clientRuntime);
|
|
42873
|
+
clientServiceProvided = true;
|
|
42874
|
+
}
|
|
42875
|
+
}
|
|
42876
|
+
tuiTarget = { runtime, config: next };
|
|
42877
|
+
if (tuiBinding !== void 0) tuiBinding.target = tuiTarget;
|
|
42878
|
+
return { client: clientRuntime, host: runtime };
|
|
42879
|
+
};
|
|
42880
|
+
replacement = operation();
|
|
42881
|
+
return replacement;
|
|
42882
|
+
};
|
|
42883
|
+
const controlRuntime = connection === void 0 ? void 0 : new PluginControlRuntime(config, defaultIdentityDirectory, settingsBinding, clientRuntime, runtime, replaceServer);
|
|
42759
42884
|
ctx.provide("dshRemote", runtime);
|
|
42760
42885
|
if (clientRuntime !== void 0) ctx.provide("dshRemoteClient", clientRuntime);
|
|
42761
|
-
|
|
42886
|
+
let tuiTarget = { runtime, config };
|
|
42762
42887
|
if (tuiBinding !== void 0) tuiBinding.target = tuiTarget;
|
|
42763
42888
|
await disableLegacyLoaderEntries(ctx, logger);
|
|
42764
42889
|
await ctx.effect(async () => {
|
|
42765
42890
|
const disposeControl = controlRuntime?.register(connection, webServer);
|
|
42766
42891
|
try {
|
|
42767
|
-
|
|
42768
|
-
|
|
42769
|
-
|
|
42770
|
-
|
|
42771
|
-
|
|
42772
|
-
|
|
42773
|
-
|
|
42774
|
-
|
|
42775
|
-
|
|
42776
|
-
|
|
42777
|
-
|
|
42892
|
+
startup = (async () => {
|
|
42893
|
+
await runtime.start();
|
|
42894
|
+
if (clientRuntime !== void 0) {
|
|
42895
|
+
await clientRuntime.start();
|
|
42896
|
+
} else {
|
|
42897
|
+
logger.warn("client remote mode is unavailable", {
|
|
42898
|
+
serverConfigured: config.serverUrl !== void 0,
|
|
42899
|
+
apiProxyAvailable: apiProxy !== void 0,
|
|
42900
|
+
remoteGatewayAvailable: localTypertGateway.supportsCarrier,
|
|
42901
|
+
connectionAvailable: connection !== void 0
|
|
42902
|
+
});
|
|
42903
|
+
}
|
|
42904
|
+
})();
|
|
42905
|
+
await startup;
|
|
42778
42906
|
} catch (error) {
|
|
42779
42907
|
if (tuiBinding?.target === tuiTarget) tuiBinding.target = void 0;
|
|
42780
42908
|
await disposeControl?.();
|
|
@@ -42783,6 +42911,8 @@ async function activate(ctx, readConfig, entryId, tuiBinding) {
|
|
|
42783
42911
|
throw error;
|
|
42784
42912
|
}
|
|
42785
42913
|
return async () => {
|
|
42914
|
+
closed = true;
|
|
42915
|
+
await replacement?.catch(() => void 0);
|
|
42786
42916
|
if (tuiBinding?.target === tuiTarget) tuiBinding.target = void 0;
|
|
42787
42917
|
await disposeControl?.();
|
|
42788
42918
|
await clientRuntime?.close();
|