@blue-soda/dsh-remote 0.5.3 → 0.5.5
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.github.js +63 -27
- package/dist/client.js +63 -27
- package/dist/index.js +149 -23
- package/dist/index.js.map +3 -3
- package/dsh-plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13480,7 +13480,12 @@ function resolveConfig(input2 = {}, env = process.env) {
|
|
|
13480
13480
|
enabled: parsed.reconnect !== false,
|
|
13481
13481
|
initialDelayMs,
|
|
13482
13482
|
maxDelayMs,
|
|
13483
|
-
jitter: reconnect.jitter ?? 0.2
|
|
13483
|
+
jitter: reconnect.jitter ?? 0.2,
|
|
13484
|
+
// A displaced connection is a standby: another instance holds this device identity, so it waits five
|
|
13485
|
+
// minutes - well outside the Server's 40-65 s reap window - and then tries again, taking over as soon
|
|
13486
|
+
// as that instance leaves. Giving up for good is how the device stayed offline after the winner left.
|
|
13487
|
+
// The fixture matrix needs a short interval to watch a standby take over, so an operator can override it.
|
|
13488
|
+
replacedRetryMs: reconnect.replacedRetryMs ?? (Number.isFinite(Number(env.DSH_REMOTE_RECONNECT_REPLACED_RETRY_MS)) ? Number(env.DSH_REMOTE_RECONNECT_REPLACED_RETRY_MS) : 3e5)
|
|
13484
13489
|
},
|
|
13485
13490
|
codex: {
|
|
13486
13491
|
// Off by default (2026-10-14). Carrying another agent's workspaces is a capability the user opts into, not
|
|
@@ -13516,7 +13521,7 @@ function normalizeServerUrl(value) {
|
|
|
13516
13521
|
}
|
|
13517
13522
|
|
|
13518
13523
|
// src/version.ts
|
|
13519
|
-
var PLUGIN_VERSION = "0.5.
|
|
13524
|
+
var PLUGIN_VERSION = "0.5.5";
|
|
13520
13525
|
|
|
13521
13526
|
// src/server-api.ts
|
|
13522
13527
|
var ENABLED_QR_PROVIDERS = ["github"];
|
|
@@ -14080,15 +14085,21 @@ var HostServerConnection = class {
|
|
|
14080
14085
|
}
|
|
14081
14086
|
async run() {
|
|
14082
14087
|
let delayMs = this.config.reconnect.initialDelayMs;
|
|
14088
|
+
let replacedRetryMs;
|
|
14089
|
+
let replacedAttempts = 0;
|
|
14083
14090
|
this.authRecoveryAttempted = false;
|
|
14084
14091
|
while (!this.stopped) {
|
|
14085
14092
|
try {
|
|
14086
14093
|
await this.connectOnce();
|
|
14087
14094
|
delayMs = this.config.reconnect.initialDelayMs;
|
|
14095
|
+
replacedRetryMs = void 0;
|
|
14096
|
+
replacedAttempts = 0;
|
|
14088
14097
|
} catch (error) {
|
|
14089
14098
|
const code = errorCode2(error);
|
|
14090
14099
|
if (code === "CREDENTIALS_REFRESHED") continue;
|
|
14091
14100
|
this.terminalError = code;
|
|
14101
|
+
replacedRetryMs = code === "CONNECTION_REPLACED" ? replacedAttempts === 0 ? Math.min(this.config.reconnect.replacedRetryMs, REPLACED_FIRST_RETRY_MS) : this.config.reconnect.replacedRetryMs : void 0;
|
|
14102
|
+
replacedAttempts = code === "CONNECTION_REPLACED" ? replacedAttempts + 1 : 0;
|
|
14092
14103
|
this.logger.warn("server control connection failed", {
|
|
14093
14104
|
code,
|
|
14094
14105
|
retryable: isRetryable(error),
|
|
@@ -14096,9 +14107,9 @@ var HostServerConnection = class {
|
|
|
14096
14107
|
...connectionFailureDetail(error)
|
|
14097
14108
|
});
|
|
14098
14109
|
if (TERMINAL_AUTH_ERRORS.has(code)) {
|
|
14099
|
-
this.logger.warn(code === "CONNECTION_REPLACED" ? "Another instance is using this Host identity.
|
|
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.");
|
|
14100
14111
|
}
|
|
14101
|
-
if (code === "DEVICE_REVOKED") {
|
|
14112
|
+
if (code === "DEVICE_REVOKED" || code === "AUTH_INVALID") {
|
|
14102
14113
|
try {
|
|
14103
14114
|
await this.api.clearAuthorization();
|
|
14104
14115
|
} catch (clearError) {
|
|
@@ -14114,7 +14125,7 @@ var HostServerConnection = class {
|
|
|
14114
14125
|
continue;
|
|
14115
14126
|
}
|
|
14116
14127
|
if (!this.config.reconnect.enabled) return;
|
|
14117
|
-
await this.waitBeforeRetry(delayMs);
|
|
14128
|
+
await (replacedRetryMs === void 0 ? this.waitBeforeRetry(delayMs) : this.waitBeforeRetry(replacedRetryMs, true));
|
|
14118
14129
|
if (this.reconnectRequested) {
|
|
14119
14130
|
this.reconnectRequested = false;
|
|
14120
14131
|
delayMs = this.config.reconnect.initialDelayMs;
|
|
@@ -14678,8 +14689,8 @@ var HostServerConnection = class {
|
|
|
14678
14689
|
tunnel.noise.destroy();
|
|
14679
14690
|
}
|
|
14680
14691
|
}
|
|
14681
|
-
waitBeforeRetry(baseDelay) {
|
|
14682
|
-
const spread = baseDelay * this.config.reconnect.jitter;
|
|
14692
|
+
waitBeforeRetry(baseDelay, exact = false) {
|
|
14693
|
+
const spread = exact ? 0 : baseDelay * this.config.reconnect.jitter;
|
|
14683
14694
|
const delay = Math.max(0, Math.round(baseDelay - spread + Math.random() * spread * 2));
|
|
14684
14695
|
return new Promise((resolve4) => {
|
|
14685
14696
|
const timer = setTimeout(() => {
|
|
@@ -14693,8 +14704,8 @@ var HostServerConnection = class {
|
|
|
14693
14704
|
});
|
|
14694
14705
|
}
|
|
14695
14706
|
};
|
|
14707
|
+
var REPLACED_FIRST_RETRY_MS = 65e3;
|
|
14696
14708
|
var TERMINAL_AUTH_ERRORS = /* @__PURE__ */ new Set([
|
|
14697
|
-
"CONNECTION_REPLACED",
|
|
14698
14709
|
"SERVER_CREDENTIALS_BUSY",
|
|
14699
14710
|
"ACCOUNT_AUTH_REQUIRED",
|
|
14700
14711
|
"AUTH_INVALID",
|
|
@@ -21909,10 +21920,16 @@ var ClientModeRuntime = class {
|
|
|
21909
21920
|
registerControl(connection, webServer) {
|
|
21910
21921
|
return registerControlRoute(connection, (endpoint, payload, signal) => this.handleControl(endpoint, payload, signal), webServer);
|
|
21911
21922
|
}
|
|
21923
|
+
/** True while the plugin is exchanging DSH's DeepSeek credential for this device's Server credentials. */
|
|
21924
|
+
authorizingWithDeepSeek = false;
|
|
21925
|
+
/** Whether DSH held a DeepSeek session at the last reconciliation. */
|
|
21926
|
+
hasDeepSeekSession = false;
|
|
21912
21927
|
status() {
|
|
21913
21928
|
const targetStatus = this.gatewaySwitch.supportsCarrier() ? this.gatewaySwitch.status() : this.proxySwitch?.status() ?? this.gatewaySwitch.status();
|
|
21914
21929
|
return {
|
|
21915
21930
|
available: this.config.serverUrl !== void 0,
|
|
21931
|
+
authorizing: this.authorizingWithDeepSeek,
|
|
21932
|
+
hasDeepSeekSession: this.hasDeepSeekSession,
|
|
21916
21933
|
identityReady: this.identity !== void 0,
|
|
21917
21934
|
deviceId: this.identity?.deviceId,
|
|
21918
21935
|
deviceName: this.identity?.name,
|
|
@@ -22075,11 +22092,33 @@ var ClientModeRuntime = class {
|
|
|
22075
22092
|
reloadCredentials() {
|
|
22076
22093
|
this.server.reloadCredentials();
|
|
22077
22094
|
}
|
|
22095
|
+
/** Whether this device holds Server credentials, i.e. the panel shows it as signed in. */
|
|
22096
|
+
async hasServerAuthorization() {
|
|
22097
|
+
if (this.server.hasStoredAuthorization === void 0) return false;
|
|
22098
|
+
return await this.server.hasStoredAuthorization().catch(() => false);
|
|
22099
|
+
}
|
|
22078
22100
|
async setHostAuthorization(enabled) {
|
|
22079
22101
|
if (this.host === void 0) throw new ClientModeError("METHOD_NOT_ALLOWED", "This plugin is not running as a Host.");
|
|
22080
|
-
|
|
22081
|
-
|
|
22082
|
-
|
|
22102
|
+
if (!enabled) {
|
|
22103
|
+
await this.host.setHostControl?.(false);
|
|
22104
|
+
await this.host.pauseHostConnection?.();
|
|
22105
|
+
return this.status();
|
|
22106
|
+
}
|
|
22107
|
+
let flagError;
|
|
22108
|
+
try {
|
|
22109
|
+
await this.host.setHostControl?.(true);
|
|
22110
|
+
} catch (error) {
|
|
22111
|
+
flagError = error;
|
|
22112
|
+
}
|
|
22113
|
+
await this.host.resumeHostConnection?.();
|
|
22114
|
+
try {
|
|
22115
|
+
await this.host.setHostControl?.(true);
|
|
22116
|
+
} catch (error) {
|
|
22117
|
+
this.logger.warn("could not tell the Server that this Host accepts control; retrying when it reconnects", {
|
|
22118
|
+
code: safeErrorCode(error),
|
|
22119
|
+
...flagError === void 0 ? {} : { firstCode: safeErrorCode(flagError) }
|
|
22120
|
+
});
|
|
22121
|
+
}
|
|
22083
22122
|
return this.status();
|
|
22084
22123
|
}
|
|
22085
22124
|
async setMode(mode, targetDeviceId, signal) {
|
|
@@ -22515,6 +22554,22 @@ var ClientModeRuntime = class {
|
|
|
22515
22554
|
return;
|
|
22516
22555
|
}
|
|
22517
22556
|
const transportLost = reason !== "codex-closed";
|
|
22557
|
+
if (String(reason) === "CONNECTION_REPLACED" && this.reconnecting === void 0) {
|
|
22558
|
+
const run = this.remoteReconnectRun;
|
|
22559
|
+
this.reconnecting = { targetDeviceId, ...targetName === void 0 ? {} : { targetName }, phase: "fast" };
|
|
22560
|
+
this.logger.info("the link was closed by this client's own connection replacement; retrying in place", {
|
|
22561
|
+
targetDeviceId: shortId2(targetDeviceId),
|
|
22562
|
+
kind
|
|
22563
|
+
});
|
|
22564
|
+
const rescued = await this.quickReconnectSession(targetDeviceId, target2, transportLost, run);
|
|
22565
|
+
if (run !== this.remoteReconnectRun) return;
|
|
22566
|
+
if (rescued) {
|
|
22567
|
+
this.finishRecovery(targetDeviceId, "replacement", kind);
|
|
22568
|
+
return;
|
|
22569
|
+
}
|
|
22570
|
+
void this.reconnectRemoteSession(targetDeviceId, target2);
|
|
22571
|
+
return;
|
|
22572
|
+
}
|
|
22518
22573
|
if (this.reconnecting === void 0) {
|
|
22519
22574
|
const run = this.remoteReconnectRun;
|
|
22520
22575
|
this.reconnecting = { targetDeviceId, ...targetName === void 0 ? {} : { targetName }, phase: "fast" };
|
|
@@ -23227,7 +23282,26 @@ var ClientModeRuntime = class {
|
|
|
23227
23282
|
throw error;
|
|
23228
23283
|
}
|
|
23229
23284
|
}
|
|
23285
|
+
/**
|
|
23286
|
+
* One attempt at a time per target: the panel's refresh and the automatic reconnect can ask at the same moment, and
|
|
23287
|
+
* two control connections in flight make the Server close the older one with 4003 (`CONNECTION_REPLACED`), which
|
|
23288
|
+
* also kills the link that was being built on it - what the user saw as being kicked out of the card.
|
|
23289
|
+
*/
|
|
23290
|
+
inFlightConnect;
|
|
23230
23291
|
async connect(targetDeviceId, signal, forceRelay = false) {
|
|
23292
|
+
const key = `${targetDeviceId}|${forceRelay ? "relay" : "auto"}`;
|
|
23293
|
+
const inFlight = this.inFlightConnect;
|
|
23294
|
+
if (inFlight?.key === key) {
|
|
23295
|
+
signal?.throwIfAborted();
|
|
23296
|
+
return await inFlight.promise;
|
|
23297
|
+
}
|
|
23298
|
+
const promise = this.connectNow(targetDeviceId, signal, forceRelay).finally(() => {
|
|
23299
|
+
if (this.inFlightConnect?.promise === promise) this.inFlightConnect = void 0;
|
|
23300
|
+
});
|
|
23301
|
+
this.inFlightConnect = { key, promise };
|
|
23302
|
+
return await promise;
|
|
23303
|
+
}
|
|
23304
|
+
async connectNow(targetDeviceId, signal, forceRelay = false) {
|
|
23231
23305
|
signal?.throwIfAborted();
|
|
23232
23306
|
const progressRunId = this.connectionProgressRun + 1;
|
|
23233
23307
|
this.connectionProgressRun = progressRunId;
|
|
@@ -24951,12 +25025,24 @@ var CodexRemoteDomain = class {
|
|
|
24951
25025
|
idempotencyKey: call.params.idempotencyKey
|
|
24952
25026
|
}));
|
|
24953
25027
|
}
|
|
25028
|
+
if (isRecord12(call.params) && typeof call.params.threadId === "string") {
|
|
25029
|
+
const rowKey = call.params.threadId;
|
|
25030
|
+
const separator = rowKey.indexOf("~");
|
|
25031
|
+
if (separator > 0) call.params.threadId = rowKey.slice(0, separator);
|
|
25032
|
+
}
|
|
24954
25033
|
if (call.method === "thread/list") {
|
|
24955
25034
|
const result = sanitizeThreadList(await this.callUpstream(call.method, call.params));
|
|
24956
|
-
|
|
25035
|
+
const authorized = filterThreadListByWorkspaceAuthority(
|
|
24957
25036
|
result,
|
|
24958
25037
|
await this.readWorkspaceAuthority(result.data)
|
|
24959
25038
|
);
|
|
25039
|
+
return {
|
|
25040
|
+
...authorized,
|
|
25041
|
+
data: authorized.data.map((row, index) => ({
|
|
25042
|
+
...row,
|
|
25043
|
+
id: `${String(row.id)}~${String(row.createdAt ?? "")}~${index}`
|
|
25044
|
+
}))
|
|
25045
|
+
};
|
|
24960
25046
|
}
|
|
24961
25047
|
if (call.method === "thread/start") {
|
|
24962
25048
|
const cwd = await this.requireCodexWorkspacePath(call.params.cwd);
|
|
@@ -26165,7 +26251,6 @@ var PluginControlRuntime = class {
|
|
|
26165
26251
|
*
|
|
26166
26252
|
* `undefined` means no sign-in is in flight, which is also the state after a completed authorization.
|
|
26167
26253
|
*/
|
|
26168
|
-
deepSeekSignIn;
|
|
26169
26254
|
register(connection, webServer) {
|
|
26170
26255
|
const statusStream = new ControlStatusStream(() => this.streamStatus());
|
|
26171
26256
|
return registerControlRoute(
|
|
@@ -26274,15 +26359,13 @@ var PluginControlRuntime = class {
|
|
|
26274
26359
|
throw new ClientModeError("METHOD_NOT_ALLOWED", "DeepSeek account sign-in is unavailable in this profile.");
|
|
26275
26360
|
}
|
|
26276
26361
|
const session = await this.deepseekSession.read();
|
|
26277
|
-
|
|
26278
|
-
if (!counted) {
|
|
26362
|
+
if (session === void 0) {
|
|
26279
26363
|
const started = await this.deepseekSession.startSignIn({
|
|
26280
26364
|
callbackOrigin: typeof value.callbackOrigin === "string" ? value.callbackOrigin : "",
|
|
26281
26365
|
loginSource: value.loginSource === "desktop" ? "desktop" : "web",
|
|
26282
26366
|
locale: typeof value.locale === "string" ? value.locale : "en",
|
|
26283
26367
|
timezoneOffsetSeconds: typeof value.timezoneOffsetSeconds === "number" ? value.timezoneOffsetSeconds : 0
|
|
26284
26368
|
});
|
|
26285
|
-
this.deepSeekSignIn = true;
|
|
26286
26369
|
return {
|
|
26287
26370
|
status: "deepseek-sign-in-required",
|
|
26288
26371
|
...started.authorizeUrl === void 0 ? {} : { authorizeUrl: started.authorizeUrl }
|
|
@@ -26295,7 +26378,6 @@ var PluginControlRuntime = class {
|
|
|
26295
26378
|
this.verifiedDeepSeekToken = session.token;
|
|
26296
26379
|
this.verifiedDeepSeekAuthorization = authorization;
|
|
26297
26380
|
}
|
|
26298
|
-
this.deepSeekSignIn = void 0;
|
|
26299
26381
|
} else {
|
|
26300
26382
|
if (typeof value.email !== "string" || typeof value.password !== "string") {
|
|
26301
26383
|
throw new ClientModeError("INVALID_MESSAGE", "Email and password are required for account authorization.");
|
|
@@ -26308,7 +26390,8 @@ var PluginControlRuntime = class {
|
|
|
26308
26390
|
if (this.host !== void 0 && !hostPaused) {
|
|
26309
26391
|
try {
|
|
26310
26392
|
this.host.reconnectHost?.();
|
|
26311
|
-
} catch {
|
|
26393
|
+
} catch (error) {
|
|
26394
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26312
26395
|
}
|
|
26313
26396
|
}
|
|
26314
26397
|
await this.settings.replace(editableConfig(next));
|
|
@@ -26408,14 +26491,13 @@ var PluginControlRuntime = class {
|
|
|
26408
26491
|
await this.settings.replace(editableConfig({ ...current, acp: { enabled: current.acp?.enabled ?? true, backends } }));
|
|
26409
26492
|
return this.settingsView();
|
|
26410
26493
|
}
|
|
26411
|
-
async logout() {
|
|
26494
|
+
async logout(options = {}) {
|
|
26412
26495
|
if (this.settings === void 0) {
|
|
26413
26496
|
throw new ClientModeError("SETTINGS_UNAVAILABLE", "DSH user settings are unavailable in this profile.");
|
|
26414
26497
|
}
|
|
26415
26498
|
const config = resolveConfig(this.settings.get());
|
|
26416
26499
|
this.verifiedDeepSeekToken = void 0;
|
|
26417
26500
|
this.verifiedDeepSeekAuthorization = void 0;
|
|
26418
|
-
this.deepSeekSignIn = void 0;
|
|
26419
26501
|
if (config.serverUrl !== void 0) {
|
|
26420
26502
|
await Promise.all([
|
|
26421
26503
|
this.client?.clearClientAuthorization(),
|
|
@@ -26424,11 +26506,13 @@ var PluginControlRuntime = class {
|
|
|
26424
26506
|
const directory = await ensureDeviceDirectory(this.identityDirectory, config.serverUrl);
|
|
26425
26507
|
await new ServerCredentialStore(directory).clear();
|
|
26426
26508
|
}
|
|
26509
|
+
if (this.client !== void 0) this.client.hasDeepSeekSession = false;
|
|
26427
26510
|
let deepseekSignedOut = false;
|
|
26428
26511
|
if (this.deepseekSession !== void 0) {
|
|
26429
26512
|
try {
|
|
26430
|
-
deepseekSignedOut = await this.deepseekSession.signOut();
|
|
26431
|
-
} catch {
|
|
26513
|
+
deepseekSignedOut = options.releaseDeepSeek === false ? false : await this.deepseekSession.signOut();
|
|
26514
|
+
} catch (error) {
|
|
26515
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26432
26516
|
deepseekSignedOut = false;
|
|
26433
26517
|
}
|
|
26434
26518
|
}
|
|
@@ -26459,7 +26543,49 @@ var PluginControlRuntime = class {
|
|
|
26459
26543
|
}
|
|
26460
26544
|
return this.client === void 0 ? this.hostOnlyStatus() : await this.client.status();
|
|
26461
26545
|
}
|
|
26546
|
+
/** Consecutive reconciliations without a DSH session: DSH refreshes its grant, so one empty read is not a sign-out. */
|
|
26547
|
+
/** Guards against re-entry through configure(), which reads the settings view back. */
|
|
26548
|
+
reconcilingWithDeepSeek = false;
|
|
26549
|
+
/**
|
|
26550
|
+
* Keep this device's Server credentials in step with DSH's DeepSeek session - that session is the credential, and
|
|
26551
|
+
* the Server verifies it before issuing this device its own tokens.
|
|
26552
|
+
*
|
|
26553
|
+
* 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 once per ten seconds, from the settings poll the panel already makes.
|
|
26555
|
+
*/
|
|
26556
|
+
async reconcileWithDeepSeek() {
|
|
26557
|
+
if (this.deepseekSession === void 0 || this.reconcilingWithDeepSeek) return;
|
|
26558
|
+
this.reconcilingWithDeepSeek = true;
|
|
26559
|
+
try {
|
|
26560
|
+
const session = await this.deepseekSession.read();
|
|
26561
|
+
if (this.client !== void 0) this.client.hasDeepSeekSession = session !== void 0;
|
|
26562
|
+
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
|
+
if (session === void 0 && authorized) {
|
|
26565
|
+
await this.logout({ releaseDeepSeek: false });
|
|
26566
|
+
return;
|
|
26567
|
+
}
|
|
26568
|
+
if (session === void 0 || authorized) return;
|
|
26569
|
+
if (this.client !== void 0) this.client.authorizingWithDeepSeek = true;
|
|
26570
|
+
void (async () => {
|
|
26571
|
+
try {
|
|
26572
|
+
await this.configure({ provider: "deepseek", serverUrl: this.config.serverUrl });
|
|
26573
|
+
} catch (error) {
|
|
26574
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26575
|
+
} finally {
|
|
26576
|
+
if (this.client !== void 0) this.client.authorizingWithDeepSeek = false;
|
|
26577
|
+
}
|
|
26578
|
+
})();
|
|
26579
|
+
} finally {
|
|
26580
|
+
this.reconcilingWithDeepSeek = false;
|
|
26581
|
+
}
|
|
26582
|
+
}
|
|
26583
|
+
/**
|
|
26584
|
+
* Keeps the reconciliation alive without the panel: DSH can be signed in or out while the card is closed, and the
|
|
26585
|
+
* plugin has to follow. Only local reads - the exchange itself is throttled to one per ten seconds.
|
|
26586
|
+
*/
|
|
26462
26587
|
async settingsView() {
|
|
26588
|
+
await this.reconcileWithDeepSeek();
|
|
26463
26589
|
const config = this.settings === void 0 ? editableConfig(this.config) : editableConfig(resolveConfig(this.settings.get()));
|
|
26464
26590
|
const associations = await this.associations(config);
|
|
26465
26591
|
const association = associations.host;
|
|
@@ -29994,7 +30120,7 @@ function remoteStatusLines(target2) {
|
|
|
29994
30120
|
`Authorization: ${status2.authorized ? status2.account === void 0 ? "logged in" : `logged in (${status2.account})` : "logged out"}`,
|
|
29995
30121
|
`Server connection: ${connection}`,
|
|
29996
30122
|
...status2.error === void 0 ? [] : [`Connection error: ${status2.error}`],
|
|
29997
|
-
...status2.error === "CONNECTION_REPLACED" ? ["Another instance is using this Host identity.
|
|
30123
|
+
...status2.error === "CONNECTION_REPLACED" ? ["Another instance is using this Host identity. Standing by: retrying every five minutes, and taking over as soon as it leaves."] : status2.error === "SERVER_CREDENTIALS_BUSY" ? ["Credential refresh is locked. Stop all instances before removing an orphaned server-credentials.json.refresh-lock and authorizing again."] : status2.accountRequired ? ["Authorize again with /remote login [github|zhihu]."] : [],
|
|
29998
30124
|
`Harness Remote API: ${capabilities.has("harness.api.v1") ? "available (ApiProxy)" : capabilities.has("harness.remote.v3") ? "available (Typert Remote Session V3)" : capabilities.has("harness.remote.v1") ? "available (Typert Remote)" : "unavailable"}`,
|
|
29999
30125
|
`Remote clients: ${diagnostics.activeConnections}`,
|
|
30000
30126
|
`Codex Remote: ${codex.enabled ? codex.state : "disabled"}`,
|