ds-harness-remote 0.3.20 → 0.3.22
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/dist/client-runtime.d.ts +4 -2
- package/dist/client-runtime.d.ts.map +1 -1
- package/dist/client-runtime.js +46 -5
- package/dist/client-runtime.js.map +1 -1
- package/dist/client.github.js +80 -35
- package/dist/client.js +80 -35
- package/dist/client.js.map +1 -1
- package/dist/harness-version.d.ts +9 -0
- package/dist/harness-version.d.ts.map +1 -0
- package/dist/harness-version.js +42 -0
- package/dist/harness-version.js.map +1 -0
- package/dist/index.js +180 -55
- package/dist/index.js.map +4 -4
- package/dist/remote-api-proxy.d.ts +1 -1
- package/dist/remote-api-proxy.d.ts.map +1 -1
- package/dist/remote-api-proxy.js +3 -1
- package/dist/remote-api-proxy.js.map +1 -1
- package/dist/server-api.d.ts +2 -1
- package/dist/server-api.d.ts.map +1 -1
- package/dist/server-api.js +5 -4
- package/dist/server-api.js.map +1 -1
- package/dist/server-connection.d.ts +2 -1
- package/dist/server-connection.d.ts.map +1 -1
- package/dist/server-connection.js +4 -1
- package/dist/server-connection.js.map +1 -1
- package/dist/service.d.ts +4 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +33 -2
- package/dist/service.js.map +1 -1
- package/dist/version.d.ts +3 -3
- package/dist/version.js +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
3
|
+
const LEGACY_PLACEHOLDER_VERSION = '0.0.1';
|
|
4
|
+
export function normalizeHarnessVersion(value) {
|
|
5
|
+
if (typeof value !== 'string')
|
|
6
|
+
return undefined;
|
|
7
|
+
const version = value.trim();
|
|
8
|
+
if (version.length === 0 || version.length > 64 || /[\u0000-\u001f]/u.test(version))
|
|
9
|
+
return undefined;
|
|
10
|
+
return version;
|
|
11
|
+
}
|
|
12
|
+
export function selectHarnessVersion(reportedVersion, distributionVersion) {
|
|
13
|
+
if (reportedVersion !== undefined && reportedVersion !== LEGACY_PLACEHOLDER_VERSION)
|
|
14
|
+
return reportedVersion;
|
|
15
|
+
return distributionVersion;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Compatibility fallback for Harness builds whose host.describe still returns
|
|
19
|
+
* the historical 0.0.1 placeholder. The running CLI entrypoint sits below the
|
|
20
|
+
* @deepseek-ai/dsh package root, so walk only its ancestor chain.
|
|
21
|
+
*/
|
|
22
|
+
export async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
|
|
23
|
+
if (entrypoint === undefined || !isAbsolute(entrypoint))
|
|
24
|
+
return undefined;
|
|
25
|
+
let directory = dirname(entrypoint);
|
|
26
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
27
|
+
try {
|
|
28
|
+
const manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8'));
|
|
29
|
+
if (manifest.name === '@deepseek-ai/dsh')
|
|
30
|
+
return normalizeHarnessVersion(manifest.version);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Most ancestors do not contain a package manifest.
|
|
34
|
+
}
|
|
35
|
+
const parent = dirname(directory);
|
|
36
|
+
if (parent === directory)
|
|
37
|
+
break;
|
|
38
|
+
directory = parent;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=harness-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-version.js","sourceRoot":"","sources":["../src/harness-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErD,MAAM,0BAA0B,GAAG,OAAO,CAAA;AAE1C,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IACrG,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,eAAmC,EACnC,mBAAuC;IAEvC,IAAI,eAAe,KAAK,SAAS,IAAI,eAAe,KAAK,0BAA0B;QAAE,OAAO,eAAe,CAAA;IAC3G,OAAO,mBAAmB,CAAA;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,aAAiC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhD,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAA;IACzE,IAAI,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACnC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAA;YAC/G,IAAI,QAAQ,CAAC,IAAI,KAAK,kBAAkB;gBAAE,OAAO,uBAAuB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC5F,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;QACjC,IAAI,MAAM,KAAK,SAAS;YAAE,MAAK;QAC/B,SAAS,GAAG,MAAM,CAAA;IACpB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4111,7 +4111,8 @@ var helloPayloadSchema = external_exports.object({
|
|
|
4111
4111
|
accessToken: external_exports.string().min(1),
|
|
4112
4112
|
protocols: external_exports.array(external_exports.number().int()).min(1),
|
|
4113
4113
|
capabilities: external_exports.array(external_exports.string()),
|
|
4114
|
-
clientVersion: external_exports.string().optional()
|
|
4114
|
+
clientVersion: external_exports.string().optional(),
|
|
4115
|
+
harnessVersion: external_exports.string().optional()
|
|
4115
4116
|
});
|
|
4116
4117
|
var helloAckPayloadSchema = external_exports.object({
|
|
4117
4118
|
protocol: external_exports.literal(PROTOCOL_VERSION),
|
|
@@ -4359,6 +4360,14 @@ function cryptoRandomId() {
|
|
|
4359
4360
|
}
|
|
4360
4361
|
|
|
4361
4362
|
// ../client-core/dist/index.js
|
|
4363
|
+
var RemoteClientError = class extends Error {
|
|
4364
|
+
code;
|
|
4365
|
+
constructor(code, message, options) {
|
|
4366
|
+
super(message, options);
|
|
4367
|
+
this.code = code;
|
|
4368
|
+
this.name = "RemoteClientError";
|
|
4369
|
+
}
|
|
4370
|
+
};
|
|
4362
4371
|
var RemoteClientCore = class {
|
|
4363
4372
|
transport;
|
|
4364
4373
|
timeoutMs;
|
|
@@ -4367,6 +4376,7 @@ var RemoteClientCore = class {
|
|
|
4367
4376
|
unsubscribeTransport;
|
|
4368
4377
|
unsubscribeClose;
|
|
4369
4378
|
closeHandlers = /* @__PURE__ */ new Set();
|
|
4379
|
+
closeNotified = false;
|
|
4370
4380
|
constructor(transport, timeoutMs = 3e4) {
|
|
4371
4381
|
this.transport = transport;
|
|
4372
4382
|
this.timeoutMs = timeoutMs;
|
|
@@ -4374,6 +4384,7 @@ var RemoteClientCore = class {
|
|
|
4374
4384
|
async connect() {
|
|
4375
4385
|
if (this.unsubscribeTransport !== void 0)
|
|
4376
4386
|
return;
|
|
4387
|
+
this.closeNotified = false;
|
|
4377
4388
|
this.unsubscribeTransport = this.transport.onMessage((data) => this.handleMessage(data));
|
|
4378
4389
|
this.unsubscribeClose = this.transport.onClose?.(() => this.handleTransportClose());
|
|
4379
4390
|
try {
|
|
@@ -4387,23 +4398,24 @@ var RemoteClientCore = class {
|
|
|
4387
4398
|
}
|
|
4388
4399
|
}
|
|
4389
4400
|
async rpc(method, params, signal) {
|
|
4390
|
-
signal?.
|
|
4401
|
+
if (signal?.aborted)
|
|
4402
|
+
throw rpcAbortedError(method, signal.reason);
|
|
4391
4403
|
const request = createRpcRequest(method, params);
|
|
4392
4404
|
const result = new Promise((resolve2, reject) => {
|
|
4393
4405
|
const timer = setTimeout(() => {
|
|
4394
|
-
|
|
4395
|
-
pending2?.removeAbort?.();
|
|
4396
|
-
this.pending.delete(request.id);
|
|
4397
|
-
reject(new Error(`RPC ${method} timed out`));
|
|
4406
|
+
this.rejectPending(request.id, new RemoteClientError("RPC_TIMEOUT", `RPC ${method} timed out after ${this.timeoutMs}ms`));
|
|
4398
4407
|
}, this.timeoutMs);
|
|
4399
|
-
const pending = {
|
|
4408
|
+
const pending = {
|
|
4409
|
+
method,
|
|
4410
|
+
resolve: resolve2,
|
|
4411
|
+
reject,
|
|
4412
|
+
timer
|
|
4413
|
+
};
|
|
4400
4414
|
if (signal !== void 0) {
|
|
4401
4415
|
const onAbort = () => {
|
|
4402
4416
|
if (this.pending.get(request.id) !== pending)
|
|
4403
4417
|
return;
|
|
4404
|
-
|
|
4405
|
-
this.pending.delete(request.id);
|
|
4406
|
-
reject(signal.reason instanceof Error ? signal.reason : new Error("RPC was cancelled"));
|
|
4418
|
+
this.rejectPending(request.id, rpcAbortedError(method, signal.reason));
|
|
4407
4419
|
};
|
|
4408
4420
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
4409
4421
|
pending.removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
@@ -4411,15 +4423,12 @@ var RemoteClientCore = class {
|
|
|
4411
4423
|
this.pending.set(request.id, pending);
|
|
4412
4424
|
});
|
|
4413
4425
|
try {
|
|
4414
|
-
|
|
4426
|
+
const send = this.transport.send(encodeMessage(request));
|
|
4427
|
+
void send.catch((error) => {
|
|
4428
|
+
this.rejectPending(request.id, transportSendError(error));
|
|
4429
|
+
});
|
|
4415
4430
|
} catch (error) {
|
|
4416
|
-
|
|
4417
|
-
if (pending !== void 0) {
|
|
4418
|
-
clearTimeout(pending.timer);
|
|
4419
|
-
pending.removeAbort?.();
|
|
4420
|
-
}
|
|
4421
|
-
this.pending.delete(request.id);
|
|
4422
|
-
throw error;
|
|
4431
|
+
this.rejectPending(request.id, transportSendError(error));
|
|
4423
4432
|
}
|
|
4424
4433
|
return result;
|
|
4425
4434
|
}
|
|
@@ -4439,23 +4448,13 @@ var RemoteClientCore = class {
|
|
|
4439
4448
|
this.unsubscribeTransport = void 0;
|
|
4440
4449
|
this.unsubscribeClose?.();
|
|
4441
4450
|
this.unsubscribeClose = void 0;
|
|
4451
|
+
this.rejectAllPending((pending) => new RemoteClientError("CLIENT_CLOSED", `RPC ${pending.method} terminated because the remote client closed`));
|
|
4452
|
+
this.notifyClose();
|
|
4442
4453
|
await this.transport.close();
|
|
4443
|
-
for (const pending of this.pending.values()) {
|
|
4444
|
-
clearTimeout(pending.timer);
|
|
4445
|
-
pending.removeAbort?.();
|
|
4446
|
-
pending.reject(new Error("remote client closed"));
|
|
4447
|
-
}
|
|
4448
|
-
this.pending.clear();
|
|
4449
4454
|
}
|
|
4450
4455
|
handleTransportClose() {
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
pending.removeAbort?.();
|
|
4454
|
-
pending.reject(new Error("remote transport closed"));
|
|
4455
|
-
}
|
|
4456
|
-
this.pending.clear();
|
|
4457
|
-
for (const handler of this.closeHandlers)
|
|
4458
|
-
handler();
|
|
4456
|
+
this.rejectAllPending((pending) => new RemoteClientError("TRANSPORT_CLOSED", `RPC ${pending.method} terminated because the remote transport closed`));
|
|
4457
|
+
this.notifyClose();
|
|
4459
4458
|
}
|
|
4460
4459
|
handleMessage(data) {
|
|
4461
4460
|
const message = decodeMessage(data);
|
|
@@ -4470,24 +4469,54 @@ var RemoteClientCore = class {
|
|
|
4470
4469
|
}
|
|
4471
4470
|
}
|
|
4472
4471
|
handleResponse(message) {
|
|
4473
|
-
const pending = this.
|
|
4472
|
+
const pending = this.takePending(message.payload.requestId);
|
|
4474
4473
|
if (pending === void 0)
|
|
4475
4474
|
return;
|
|
4476
|
-
this.pending.delete(message.payload.requestId);
|
|
4477
|
-
clearTimeout(pending.timer);
|
|
4478
|
-
pending.removeAbort?.();
|
|
4479
4475
|
pending.resolve(message.payload.result);
|
|
4480
4476
|
}
|
|
4481
4477
|
handleError(message) {
|
|
4482
|
-
const pending = this.
|
|
4478
|
+
const pending = this.takePending(message.payload.requestId);
|
|
4483
4479
|
if (pending === void 0)
|
|
4484
4480
|
return;
|
|
4485
|
-
|
|
4481
|
+
pending.reject(Object.assign(new Error(message.payload.message), { code: message.payload.code }));
|
|
4482
|
+
}
|
|
4483
|
+
takePending(requestId) {
|
|
4484
|
+
const pending = this.pending.get(requestId);
|
|
4485
|
+
if (pending === void 0)
|
|
4486
|
+
return void 0;
|
|
4487
|
+
this.pending.delete(requestId);
|
|
4486
4488
|
clearTimeout(pending.timer);
|
|
4487
4489
|
pending.removeAbort?.();
|
|
4488
|
-
pending
|
|
4490
|
+
return pending;
|
|
4491
|
+
}
|
|
4492
|
+
rejectPending(requestId, error) {
|
|
4493
|
+
const pending = this.takePending(requestId);
|
|
4494
|
+
if (pending === void 0)
|
|
4495
|
+
return false;
|
|
4496
|
+
pending.reject(error);
|
|
4497
|
+
return true;
|
|
4498
|
+
}
|
|
4499
|
+
rejectAllPending(createError) {
|
|
4500
|
+
for (const requestId of [...this.pending.keys()]) {
|
|
4501
|
+
const pending = this.takePending(requestId);
|
|
4502
|
+
if (pending !== void 0)
|
|
4503
|
+
pending.reject(createError(pending));
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
notifyClose() {
|
|
4507
|
+
if (this.closeNotified)
|
|
4508
|
+
return;
|
|
4509
|
+
this.closeNotified = true;
|
|
4510
|
+
for (const handler of this.closeHandlers)
|
|
4511
|
+
handler();
|
|
4489
4512
|
}
|
|
4490
4513
|
};
|
|
4514
|
+
function rpcAbortedError(method, reason) {
|
|
4515
|
+
return new RemoteClientError("RPC_ABORTED", `RPC ${method} was aborted`, reason === void 0 ? void 0 : { cause: reason });
|
|
4516
|
+
}
|
|
4517
|
+
function transportSendError(error) {
|
|
4518
|
+
return error instanceof Error ? error : new Error("remote transport send failed", { cause: error });
|
|
4519
|
+
}
|
|
4491
4520
|
|
|
4492
4521
|
// ../webrtc/dist/transport.js
|
|
4493
4522
|
var BaseTransport = class {
|
|
@@ -12966,7 +12995,7 @@ function normalizeLegacyResponse(method, response) {
|
|
|
12966
12995
|
};
|
|
12967
12996
|
}
|
|
12968
12997
|
function isRemoteDisconnect(error) {
|
|
12969
|
-
return error instanceof
|
|
12998
|
+
return error instanceof RemoteClientError && (error.code === "TRANSPORT_CLOSED" || error.code === "CLIENT_CLOSED");
|
|
12970
12999
|
}
|
|
12971
13000
|
var AsyncFrameQueue = class {
|
|
12972
13001
|
values = [];
|
|
@@ -13092,7 +13121,7 @@ function normalizeServerUrl(value) {
|
|
|
13092
13121
|
}
|
|
13093
13122
|
|
|
13094
13123
|
// src/version.ts
|
|
13095
|
-
var PLUGIN_VERSION = "0.3.
|
|
13124
|
+
var PLUGIN_VERSION = "0.3.22";
|
|
13096
13125
|
|
|
13097
13126
|
// src/server-api.ts
|
|
13098
13127
|
var HostServerApi = class {
|
|
@@ -13155,12 +13184,12 @@ var HostServerApi = class {
|
|
|
13155
13184
|
isAdmin: login.isAdmin
|
|
13156
13185
|
};
|
|
13157
13186
|
}
|
|
13158
|
-
async startOAuthQrLogin() {
|
|
13159
|
-
const value = requireRecord(await this.publicRequest(
|
|
13187
|
+
async startOAuthQrLogin(provider = "zhihu") {
|
|
13188
|
+
const value = requireRecord(await this.publicRequest(`/api/v1/auth/oauth/qr/start?provider=${provider}`, {
|
|
13160
13189
|
method: "POST",
|
|
13161
13190
|
body: "{}"
|
|
13162
13191
|
}), "QR login");
|
|
13163
|
-
if (typeof value.qrId !== "string" || value.qrId.length < 20 || typeof value.scanUrl !== "string" || !value.scanUrl.startsWith(`${this.baseUrl}/`) || !Number.isSafeInteger(value.expiresIn)) {
|
|
13192
|
+
if (typeof value.qrId !== "string" || value.qrId.length < 20 || typeof value.scanUrl !== "string" || !value.scanUrl.startsWith(`${this.baseUrl}/`) || !Number.isSafeInteger(value.expiresIn) || provider === "github" && value.provider !== "github" || value.provider !== void 0 && value.provider !== provider) {
|
|
13164
13193
|
throw new ServerApiError("INVALID_MESSAGE", "The Server returned an invalid QR login session.", false);
|
|
13165
13194
|
}
|
|
13166
13195
|
return { qrId: value.qrId, scanUrl: value.scanUrl, expiresIn: value.expiresIn };
|
|
@@ -13315,8 +13344,7 @@ var HostServerApi = class {
|
|
|
13315
13344
|
role: this.role,
|
|
13316
13345
|
platform: platform(),
|
|
13317
13346
|
identityKey: identity.publicKey,
|
|
13318
|
-
clientVersion: PLUGIN_VERSION
|
|
13319
|
-
...this.role === "host" ? { harnessVersion: "0.1.0-rc.6" } : {}
|
|
13347
|
+
clientVersion: PLUGIN_VERSION
|
|
13320
13348
|
};
|
|
13321
13349
|
}
|
|
13322
13350
|
saveTokens(identity, tokens, authorization) {
|
|
@@ -13735,6 +13763,7 @@ var ClientModeRuntime = class {
|
|
|
13735
13763
|
}
|
|
13736
13764
|
identity;
|
|
13737
13765
|
connected;
|
|
13766
|
+
pendingWorkspaceSelection;
|
|
13738
13767
|
proxySwitch;
|
|
13739
13768
|
gatewaySwitch;
|
|
13740
13769
|
closed = false;
|
|
@@ -13764,6 +13793,7 @@ var ClientModeRuntime = class {
|
|
|
13764
13793
|
connected: this.connected !== void 0,
|
|
13765
13794
|
transport: this.connected?.client.getStats().mode ?? "Disconnected",
|
|
13766
13795
|
remoteFeatures: this.connected?.features ?? remoteHostFeatures(),
|
|
13796
|
+
...this.pendingWorkspaceSelection === void 0 ? {} : { workspaceSelection: { ...this.pendingWorkspaceSelection } },
|
|
13767
13797
|
hostAuthorizationAvailable: this.host !== void 0,
|
|
13768
13798
|
...this.host === void 0 ? {} : { host: this.host.hostStatus() }
|
|
13769
13799
|
};
|
|
@@ -13813,8 +13843,8 @@ var ClientModeRuntime = class {
|
|
|
13813
13843
|
this.logger.info("Client account authorized");
|
|
13814
13844
|
return authorization;
|
|
13815
13845
|
}
|
|
13816
|
-
async startClientOAuthQrLogin() {
|
|
13817
|
-
return this.server.startOAuthQrLogin();
|
|
13846
|
+
async startClientOAuthQrLogin(provider) {
|
|
13847
|
+
return this.server.startOAuthQrLogin(provider);
|
|
13818
13848
|
}
|
|
13819
13849
|
async pollClientOAuthQrLogin(qrId) {
|
|
13820
13850
|
try {
|
|
@@ -13832,6 +13862,7 @@ var ClientModeRuntime = class {
|
|
|
13832
13862
|
async clearClientAuthorization() {
|
|
13833
13863
|
const previous = this.connected;
|
|
13834
13864
|
this.connected = void 0;
|
|
13865
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13835
13866
|
this.proxySwitch.selectLocal();
|
|
13836
13867
|
this.gatewaySwitch.selectLocal();
|
|
13837
13868
|
await previous?.client.close().catch(() => void 0);
|
|
@@ -13855,6 +13886,7 @@ var ClientModeRuntime = class {
|
|
|
13855
13886
|
this.gatewaySwitch.selectLocal();
|
|
13856
13887
|
const previous2 = this.connected;
|
|
13857
13888
|
this.connected = void 0;
|
|
13889
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13858
13890
|
await previous2?.client.close().catch(() => void 0);
|
|
13859
13891
|
this.logger.info("Harness target switched", { mode: "local" });
|
|
13860
13892
|
return this.status();
|
|
@@ -13865,6 +13897,7 @@ var ClientModeRuntime = class {
|
|
|
13865
13897
|
const next = await this.connect(targetDeviceId, signal);
|
|
13866
13898
|
const previous = this.connected;
|
|
13867
13899
|
this.connected = next;
|
|
13900
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13868
13901
|
const remoteApi = new RemoteHarnessApiProxy(next.client).api;
|
|
13869
13902
|
this.proxySwitch.selectRemote(remoteApi, { deviceId: next.target.deviceId, name: next.target.name });
|
|
13870
13903
|
this.selectRemoteCommands(next);
|
|
@@ -13902,14 +13935,24 @@ var ClientModeRuntime = class {
|
|
|
13902
13935
|
const workspace = unwrapNativeResult(response);
|
|
13903
13936
|
this.proxySwitch.selectRemote(api, { deviceId: remote.target.deviceId, name: remote.target.name });
|
|
13904
13937
|
this.selectRemoteCommands(remote);
|
|
13938
|
+
const workspaceId = workspaceRecordId(workspace.workspace);
|
|
13939
|
+
this.pendingWorkspaceSelection = { targetDeviceId: remote.target.deviceId, workspaceId };
|
|
13905
13940
|
this.logger.info("Remote workspace opened", { targetDeviceId: shortId(remote.target.deviceId) });
|
|
13906
13941
|
return { ...this.status(), workspace };
|
|
13907
13942
|
}
|
|
13943
|
+
consumeWorkspaceSelection(selection) {
|
|
13944
|
+
const pending = this.pendingWorkspaceSelection;
|
|
13945
|
+
if (pending?.targetDeviceId === selection.targetDeviceId && pending.workspaceId === selection.workspaceId) {
|
|
13946
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13947
|
+
}
|
|
13948
|
+
return this.status();
|
|
13949
|
+
}
|
|
13908
13950
|
async close() {
|
|
13909
13951
|
if (this.closed) return;
|
|
13910
13952
|
this.closed = true;
|
|
13911
13953
|
this.proxySwitch.selectLocal();
|
|
13912
13954
|
this.gatewaySwitch.selectLocal();
|
|
13955
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13913
13956
|
await this.connected?.client.close().catch(() => void 0);
|
|
13914
13957
|
this.connected = void 0;
|
|
13915
13958
|
this.proxySwitch.restore();
|
|
@@ -13982,6 +14025,7 @@ var ClientModeRuntime = class {
|
|
|
13982
14025
|
client.onClose(() => {
|
|
13983
14026
|
if (this.connected?.client !== client) return;
|
|
13984
14027
|
this.connected = void 0;
|
|
14028
|
+
this.pendingWorkspaceSelection = void 0;
|
|
13985
14029
|
this.proxySwitch.selectLocal();
|
|
13986
14030
|
this.gatewaySwitch.selectLocal();
|
|
13987
14031
|
void client.close().catch(() => void 0);
|
|
@@ -14018,7 +14062,14 @@ var ClientModeRuntime = class {
|
|
|
14018
14062
|
}
|
|
14019
14063
|
return ok(await this.authorizeClientWithAccount(value.email, value.password));
|
|
14020
14064
|
}
|
|
14021
|
-
if (endpoint === "client.account.qr.start")
|
|
14065
|
+
if (endpoint === "client.account.qr.start") {
|
|
14066
|
+
const value = record(payload);
|
|
14067
|
+
const provider = value.provider ?? "zhihu";
|
|
14068
|
+
if (provider !== "zhihu" && provider !== "github") {
|
|
14069
|
+
throw new ClientModeError("INVALID_MESSAGE", "A supported OAuth provider is required.");
|
|
14070
|
+
}
|
|
14071
|
+
return ok(await this.startClientOAuthQrLogin(provider));
|
|
14072
|
+
}
|
|
14022
14073
|
if (endpoint === "client.account.qr.poll") {
|
|
14023
14074
|
const value = record(payload);
|
|
14024
14075
|
if (typeof value.qrId !== "string" || value.qrId.length < 20) {
|
|
@@ -14047,6 +14098,16 @@ var ClientModeRuntime = class {
|
|
|
14047
14098
|
}
|
|
14048
14099
|
return ok(await this.openRemoteWorkspace(value.targetDeviceId, value.path, signal));
|
|
14049
14100
|
}
|
|
14101
|
+
if (endpoint === "workspace.selection.consume") {
|
|
14102
|
+
const value = record(payload);
|
|
14103
|
+
if (typeof value.targetDeviceId !== "string" || typeof value.workspaceId !== "string") {
|
|
14104
|
+
throw new ClientModeError("INVALID_MESSAGE", "A Host and Workspace are required.");
|
|
14105
|
+
}
|
|
14106
|
+
return ok(this.consumeWorkspaceSelection({
|
|
14107
|
+
targetDeviceId: value.targetDeviceId,
|
|
14108
|
+
workspaceId: value.workspaceId
|
|
14109
|
+
}));
|
|
14110
|
+
}
|
|
14050
14111
|
if (endpoint === "fileviewer.stat" || endpoint === "fileviewer.readRange" || endpoint === "fileviewer.list") {
|
|
14051
14112
|
const method = endpoint === "fileviewer.stat" ? "stat" : endpoint === "fileviewer.readRange" ? "readRange" : "list";
|
|
14052
14113
|
return ok(await this.callRemoteFileViewer(method, payload, signal));
|
|
@@ -14157,6 +14218,12 @@ function unwrapNativeResult(response) {
|
|
|
14157
14218
|
}
|
|
14158
14219
|
return result.value;
|
|
14159
14220
|
}
|
|
14221
|
+
function workspaceRecordId(value) {
|
|
14222
|
+
if (typeof value !== "object" || value === null || !("workspaceId" in value) || typeof value.workspaceId !== "string" || value.workspaceId.length === 0) {
|
|
14223
|
+
throw new ClientModeError("INVALID_MESSAGE", "The remote Host returned an invalid Workspace.");
|
|
14224
|
+
}
|
|
14225
|
+
return value.workspaceId;
|
|
14226
|
+
}
|
|
14160
14227
|
function fail(error) {
|
|
14161
14228
|
const source = error instanceof Error ? error : void 0;
|
|
14162
14229
|
const remoteCode = source !== void 0 && "code" in source && typeof source.code === "string" ? source.code : source instanceof ClientModeError ? source.code : void 0;
|
|
@@ -14704,6 +14771,10 @@ function redact(value, key = "") {
|
|
|
14704
14771
|
return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [childKey, redact(child, childKey)]));
|
|
14705
14772
|
}
|
|
14706
14773
|
|
|
14774
|
+
// src/service.ts
|
|
14775
|
+
import { randomUUID } from "node:crypto";
|
|
14776
|
+
import { RpcId } from "@deepseek-ai/dsh-host-apiproxy/api";
|
|
14777
|
+
|
|
14707
14778
|
// src/connection-controller.ts
|
|
14708
14779
|
var ConnectionController = class {
|
|
14709
14780
|
constructor(identities, createRouter, logger) {
|
|
@@ -14872,6 +14943,36 @@ function shortId2(value) {
|
|
|
14872
14943
|
return value.length <= 12 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
|
|
14873
14944
|
}
|
|
14874
14945
|
|
|
14946
|
+
// src/harness-version.ts
|
|
14947
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
14948
|
+
import { dirname as dirname3, isAbsolute, join as join3 } from "node:path";
|
|
14949
|
+
var LEGACY_PLACEHOLDER_VERSION = "0.0.1";
|
|
14950
|
+
function normalizeHarnessVersion(value) {
|
|
14951
|
+
if (typeof value !== "string") return void 0;
|
|
14952
|
+
const version = value.trim();
|
|
14953
|
+
if (version.length === 0 || version.length > 64 || /[\u0000-\u001f]/u.test(version)) return void 0;
|
|
14954
|
+
return version;
|
|
14955
|
+
}
|
|
14956
|
+
function selectHarnessVersion(reportedVersion, distributionVersion) {
|
|
14957
|
+
if (reportedVersion !== void 0 && reportedVersion !== LEGACY_PLACEHOLDER_VERSION) return reportedVersion;
|
|
14958
|
+
return distributionVersion;
|
|
14959
|
+
}
|
|
14960
|
+
async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
|
|
14961
|
+
if (entrypoint === void 0 || !isAbsolute(entrypoint)) return void 0;
|
|
14962
|
+
let directory = dirname3(entrypoint);
|
|
14963
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
14964
|
+
try {
|
|
14965
|
+
const manifest = JSON.parse(await readFile3(join3(directory, "package.json"), "utf8"));
|
|
14966
|
+
if (manifest.name === "@deepseek-ai/dsh") return normalizeHarnessVersion(manifest.version);
|
|
14967
|
+
} catch {
|
|
14968
|
+
}
|
|
14969
|
+
const parent = dirname3(directory);
|
|
14970
|
+
if (parent === directory) break;
|
|
14971
|
+
directory = parent;
|
|
14972
|
+
}
|
|
14973
|
+
return void 0;
|
|
14974
|
+
}
|
|
14975
|
+
|
|
14875
14976
|
// src/rpc-router.ts
|
|
14876
14977
|
var wireRequestSchema = external_exports.object({ method: external_exports.string().min(1), params: external_exports.unknown() }).strict();
|
|
14877
14978
|
var apiMethods = /* @__PURE__ */ new Set([
|
|
@@ -15091,7 +15192,7 @@ function isOversizedListing(value) {
|
|
|
15091
15192
|
// src/server-connection.ts
|
|
15092
15193
|
var DEFAULT_WEBRTC_NEGOTIATE_TIMEOUT_MS = 8e3;
|
|
15093
15194
|
var HostServerConnection = class {
|
|
15094
|
-
constructor(config, identity, identities, api, connections, logger, createWebSocket = (url) => new WebSocket(url), rtcFactoryProvider, hostCapabilities = () => ["harness.api.v1"]) {
|
|
15195
|
+
constructor(config, identity, identities, api, connections, logger, createWebSocket = (url) => new WebSocket(url), rtcFactoryProvider, hostCapabilities = () => ["harness.api.v1"], harnessVersion) {
|
|
15095
15196
|
this.config = config;
|
|
15096
15197
|
this.identity = identity;
|
|
15097
15198
|
this.identities = identities;
|
|
@@ -15101,6 +15202,7 @@ var HostServerConnection = class {
|
|
|
15101
15202
|
this.createWebSocket = createWebSocket;
|
|
15102
15203
|
this.rtcFactoryProvider = rtcFactoryProvider;
|
|
15103
15204
|
this.hostCapabilities = hostCapabilities;
|
|
15205
|
+
this.harnessVersion = harnessVersion;
|
|
15104
15206
|
}
|
|
15105
15207
|
socket;
|
|
15106
15208
|
running;
|
|
@@ -15224,6 +15326,7 @@ var HostServerConnection = class {
|
|
|
15224
15326
|
accessToken: credentials.accessToken,
|
|
15225
15327
|
protocols: [PROTOCOL_VERSION],
|
|
15226
15328
|
clientVersion: PLUGIN_VERSION,
|
|
15329
|
+
...this.harnessVersion === void 0 ? {} : { harnessVersion: this.harnessVersion },
|
|
15227
15330
|
capabilities: this.rtcFactoryProvider === void 0 || this.config.forceRelay ? ["transport.relay", ...this.hostCapabilities()] : ["transport.p2p", "transport.turn", "transport.relay", ...this.hostCapabilities()]
|
|
15228
15331
|
});
|
|
15229
15332
|
};
|
|
@@ -15776,13 +15879,13 @@ function closeCode(code) {
|
|
|
15776
15879
|
// src/remote-directory-browser.ts
|
|
15777
15880
|
import { readdir, stat as stat3 } from "node:fs/promises";
|
|
15778
15881
|
import { homedir as homedir2, platform as platform2 } from "node:os";
|
|
15779
|
-
import { basename, dirname as
|
|
15882
|
+
import { basename, dirname as dirname4, isAbsolute as isAbsolute2, parse, resolve } from "node:path";
|
|
15780
15883
|
var MAX_ENTRIES = 500;
|
|
15781
15884
|
async function listRemoteDirectory(path, signal) {
|
|
15782
15885
|
signal?.throwIfAborted();
|
|
15783
15886
|
const home = resolve(homedir2());
|
|
15784
15887
|
const target = path === void 0 || path.trim() === "" ? home : resolve(path);
|
|
15785
|
-
if (!
|
|
15888
|
+
if (!isAbsolute2(target)) throw new Error("The remote directory path must be absolute.");
|
|
15786
15889
|
const rows = await readdir(target, { withFileTypes: true });
|
|
15787
15890
|
const directories = [];
|
|
15788
15891
|
for (const row of rows) {
|
|
@@ -15809,7 +15912,7 @@ function crumbs(path) {
|
|
|
15809
15912
|
let current = path;
|
|
15810
15913
|
while (current !== root) {
|
|
15811
15914
|
segments.unshift(basename(current));
|
|
15812
|
-
current =
|
|
15915
|
+
current = dirname4(current);
|
|
15813
15916
|
}
|
|
15814
15917
|
for (const segment of segments) {
|
|
15815
15918
|
current = resolve(current, segment);
|
|
@@ -16173,11 +16276,12 @@ var HostPluginRuntime = class {
|
|
|
16173
16276
|
constructor(config, identities, apiProxy, logger, typertGateway, fileViewerHost) {
|
|
16174
16277
|
this.config = config;
|
|
16175
16278
|
this.identities = identities;
|
|
16279
|
+
this.apiProxy = apiProxy;
|
|
16176
16280
|
this.logger = logger;
|
|
16177
16281
|
this.fileViewerHost = fileViewerHost;
|
|
16178
16282
|
this.connections = new ConnectionController(this.identities, (_context, send) => {
|
|
16179
16283
|
const harnessApi = new HarnessApiBridge(
|
|
16180
|
-
apiProxy,
|
|
16284
|
+
this.apiProxy,
|
|
16181
16285
|
(event, data) => send(createEvent(event, data)),
|
|
16182
16286
|
void 0,
|
|
16183
16287
|
this.logger,
|
|
@@ -16197,6 +16301,7 @@ var HostPluginRuntime = class {
|
|
|
16197
16301
|
identity;
|
|
16198
16302
|
serverApi;
|
|
16199
16303
|
serverConnection;
|
|
16304
|
+
harnessVersion;
|
|
16200
16305
|
closed = false;
|
|
16201
16306
|
async start() {
|
|
16202
16307
|
if (this.closed) throw new Error("remote runtime is closed");
|
|
@@ -16207,6 +16312,7 @@ var HostPluginRuntime = class {
|
|
|
16207
16312
|
server: this.config.serverUrl ?? "not configured"
|
|
16208
16313
|
});
|
|
16209
16314
|
if (this.serverApi !== void 0) {
|
|
16315
|
+
this.harnessVersion = await this.readHarnessVersion();
|
|
16210
16316
|
this.serverApi.bindIdentity(this.identity);
|
|
16211
16317
|
this.serverConnection = this.createServerConnection(this.identity);
|
|
16212
16318
|
this.serverConnection.start();
|
|
@@ -16325,9 +16431,28 @@ var HostPluginRuntime = class {
|
|
|
16325
16431
|
this.logger,
|
|
16326
16432
|
void 0,
|
|
16327
16433
|
this.config.forceRelay ? void 0 : loadWeriftFactory,
|
|
16328
|
-
() => this.fileViewerHost?.() === void 0 ? ["harness.api.v1"] : ["harness.api.v1", "fileviewer.read.v1"]
|
|
16434
|
+
() => this.fileViewerHost?.() === void 0 ? ["harness.api.v1"] : ["harness.api.v1", "fileviewer.read.v1"],
|
|
16435
|
+
this.harnessVersion
|
|
16329
16436
|
);
|
|
16330
16437
|
}
|
|
16438
|
+
async readHarnessVersion() {
|
|
16439
|
+
let reportedVersion;
|
|
16440
|
+
let errorCode2;
|
|
16441
|
+
try {
|
|
16442
|
+
const response = await this.apiProxy.host.describe({ rpcId: RpcId(randomUUID()), payload: {} });
|
|
16443
|
+
if (!response.result.ok) {
|
|
16444
|
+
errorCode2 = response.result.error.code;
|
|
16445
|
+
} else {
|
|
16446
|
+
reportedVersion = normalizeHarnessVersion(response.result.value.version);
|
|
16447
|
+
}
|
|
16448
|
+
} catch {
|
|
16449
|
+
}
|
|
16450
|
+
const distributionVersion = reportedVersion === void 0 || reportedVersion === "0.0.1" ? await readHarnessDistributionVersion() : void 0;
|
|
16451
|
+
const version = selectHarnessVersion(reportedVersion, distributionVersion);
|
|
16452
|
+
if (version !== void 0) return version;
|
|
16453
|
+
this.logger.warn("Harness version is unavailable", errorCode2 === void 0 ? void 0 : { code: errorCode2 });
|
|
16454
|
+
return void 0;
|
|
16455
|
+
}
|
|
16331
16456
|
};
|
|
16332
16457
|
function shortId5(value) {
|
|
16333
16458
|
return value.length <= 12 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
|