dsh-remote-local-plugin 0.8.0 → 0.8.2
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 +12 -0
- package/assets/dsh-remote-agent-0.2.1.tgz +0 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +66 -0
- package/lib/client.js.map +2 -2
- package/lib/index.js +125 -15
- package/lib/types/config.d.ts +6 -0
- package/package.json +1 -1
- package/lib/types/rpc/contract.d.ts +0 -114
- package/lib/types/rpc/handler.d.ts +0 -12
- package/node_modules/dsh-remote-terminal-controller/lib/client.js.map +0 -7
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* dsh-remote-local-plugin@0.8.
|
|
1
|
+
/* dsh-remote-local-plugin@0.8.2 — bundled host entry */
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
@@ -23,6 +23,8 @@ var Config = z.object({
|
|
|
23
23
|
remoteDshVersion: z.string().default("0.2.1-rc.2"),
|
|
24
24
|
remotePnpmVersion: z.string().default("11.21.0"),
|
|
25
25
|
remoteNodeVersion: z.string().default("22.19.0"),
|
|
26
|
+
remoteInstallProxy: z.string().default(""),
|
|
27
|
+
remoteInstallNoProxy: z.string().default("127.0.0.1,localhost"),
|
|
26
28
|
autoInstallNode: z.boolean().default(true),
|
|
27
29
|
remoteStart: z.string().default("systemd"),
|
|
28
30
|
provisionTimeoutMs: z.number().min(6e4).max(18e5).default(6e5),
|
|
@@ -80,6 +82,8 @@ function resolveConfig(config = {}, env = process.env) {
|
|
|
80
82
|
remoteDshVersion: config.remoteDshVersion ?? "0.2.1-rc.2",
|
|
81
83
|
remotePnpmVersion: config.remotePnpmVersion ?? "11.21.0",
|
|
82
84
|
remoteNodeVersion: config.remoteNodeVersion ?? "22.19.0",
|
|
85
|
+
remoteInstallProxy: config.remoteInstallProxy ?? "",
|
|
86
|
+
remoteInstallNoProxy: config.remoteInstallNoProxy ?? "127.0.0.1,localhost",
|
|
83
87
|
autoInstallNode: config.autoInstallNode ?? true,
|
|
84
88
|
remoteStart,
|
|
85
89
|
provisionTimeoutMs: config.provisionTimeoutMs ?? 6e5,
|
|
@@ -2793,11 +2797,32 @@ AUTO_INSTALL_NODE=${options.autoInstallNode ? "1" : "0"}
|
|
|
2793
2797
|
AGENT_TARBALL=${shellLiteral(options.agentTarball)}
|
|
2794
2798
|
MODEL_BASE_URL=${options.modelBaseUrl === void 0 ? "''" : shellLiteral(options.modelBaseUrl)}
|
|
2795
2799
|
MODEL_API_KEY=${options.modelApiKey === void 0 ? "''" : shellLiteral(options.modelApiKey)}
|
|
2800
|
+
PROXY_URL=${options.proxyUrl === void 0 ? "''" : shellLiteral(options.proxyUrl)}
|
|
2801
|
+
PROXY_NO_PROXY=${options.noProxy === void 0 ? "''" : shellLiteral(options.noProxy)}
|
|
2796
2802
|
STATE_FILE="$DSH_HOME/remote-agent/agent.json"
|
|
2797
2803
|
WAIT_FOR_STATE=${options.start === "none" ? 0 : 1}
|
|
2798
2804
|
|
|
2799
2805
|
export DSH_HOME
|
|
2800
2806
|
mkdir -p "$INSTALL_DIR" "$DSH_HOME/remote-agent"
|
|
2807
|
+
echo "dsh-remote: preparing remote install"
|
|
2808
|
+
if [ -z "$PROXY_URL" ]; then
|
|
2809
|
+
# Reuse a proxy already configured in the remote login environment.
|
|
2810
|
+
PROXY_URL="$(bash -lc 'printf "%s" "\${HTTPS_PROXY:-\${HTTP_PROXY:-}}"' 2>/dev/null | tail -n 1 || true)"
|
|
2811
|
+
fi
|
|
2812
|
+
if [ -z "$PROXY_URL" ]; then
|
|
2813
|
+
# Some clusters configure the proxy in .bashrc, which login shells skip.
|
|
2814
|
+
PROXY_URL="$(bash -ic 'printf "%s" "\${HTTPS_PROXY:-\${HTTP_PROXY:-}}"' 2>/dev/null | tail -n 1 || true)"
|
|
2815
|
+
fi
|
|
2816
|
+
if [ -n "$PROXY_URL" ]; then
|
|
2817
|
+
export HTTP_PROXY="$PROXY_URL" http_proxy="$PROXY_URL"
|
|
2818
|
+
export HTTPS_PROXY="$PROXY_URL" https_proxy="$PROXY_URL"
|
|
2819
|
+
export ALL_PROXY="$PROXY_URL" all_proxy="$PROXY_URL"
|
|
2820
|
+
export npm_config_proxy="$PROXY_URL" npm_config_https_proxy="$PROXY_URL"
|
|
2821
|
+
if [ -n "$PROXY_NO_PROXY" ]; then
|
|
2822
|
+
export NO_PROXY="$PROXY_NO_PROXY" no_proxy="$PROXY_NO_PROXY"
|
|
2823
|
+
fi
|
|
2824
|
+
echo "dsh-remote: install proxy configured"
|
|
2825
|
+
fi
|
|
2801
2826
|
|
|
2802
2827
|
${nodePathPrelude()}
|
|
2803
2828
|
|
|
@@ -2819,6 +2844,7 @@ if ! command -v npm >/dev/null 2>&1; then
|
|
|
2819
2844
|
echo "dsh-remote: npm is required; install a Node.js distribution that includes npm" >&2
|
|
2820
2845
|
exit 23
|
|
2821
2846
|
fi
|
|
2847
|
+
echo "dsh-remote: node ready"
|
|
2822
2848
|
|
|
2823
2849
|
export PATH="$INSTALL_DIR/node_modules/.bin:$PATH"
|
|
2824
2850
|
if ! command -v pnpm >/dev/null 2>&1; then
|
|
@@ -2839,9 +2865,11 @@ fi
|
|
|
2839
2865
|
echo "dsh-remote: adding plugin to profile $PROFILE"
|
|
2840
2866
|
"$DSH_BIN" plugin --profile "$PROFILE" add "$AGENT_TARBALL"
|
|
2841
2867
|
|
|
2868
|
+
echo "dsh-remote: starting dsh web"
|
|
2842
2869
|
${startBlock}
|
|
2843
2870
|
|
|
2844
2871
|
if [ "$WAIT_FOR_STATE" -eq 1 ]; then
|
|
2872
|
+
echo "dsh-remote: waiting for agent state"
|
|
2845
2873
|
i=0
|
|
2846
2874
|
while [ "$i" -lt 60 ]; do
|
|
2847
2875
|
if [ -s "$STATE_FILE" ]; then break; fi
|
|
@@ -2853,6 +2881,7 @@ fi
|
|
|
2853
2881
|
echo "dsh-remote: installed"
|
|
2854
2882
|
echo "dsh-remote: state file $STATE_FILE"
|
|
2855
2883
|
if [ "$WAIT_FOR_STATE" -eq 1 ] && [ -s "$STATE_FILE" ]; then
|
|
2884
|
+
echo "dsh-remote: agent ready"
|
|
2856
2885
|
PORT_VALUE=$(sed -n 's/.*"port": *\\([0-9][0-9]*\\).*/\\1/p' "$STATE_FILE" | head -1)
|
|
2857
2886
|
echo "dsh-remote: remote agent port \${PORT_VALUE:-unknown}"
|
|
2858
2887
|
else
|
|
@@ -2875,6 +2904,7 @@ cat > "$UNIT_DIR/dsh-remote-agent.service" <<DSH_REMOTE_UNIT
|
|
|
2875
2904
|
${unit}DSH_REMOTE_UNIT
|
|
2876
2905
|
chmod 600 "$UNIT_DIR/dsh-remote-agent.service"
|
|
2877
2906
|
|
|
2907
|
+
echo "dsh-remote: restarting systemd user unit"
|
|
2878
2908
|
if command -v systemctl >/dev/null 2>&1 && systemctl --user daemon-reload >/dev/null 2>&1; then
|
|
2879
2909
|
if systemctl --user enable dsh-remote-agent.service >/dev/null 2>&1 && systemctl --user restart dsh-remote-agent.service; then
|
|
2880
2910
|
echo "dsh-remote: restarted systemd user unit dsh-remote-agent.service"
|
|
@@ -2892,6 +2922,7 @@ function renderNohup(options) {
|
|
|
2892
2922
|
return `if [ -f "$DSH_HOME/remote-agent/web.pid" ]; then
|
|
2893
2923
|
kill "$(cat "$DSH_HOME/remote-agent/web.pid")" 2>/dev/null || true
|
|
2894
2924
|
fi
|
|
2925
|
+
echo "dsh-remote: starting dsh web under nohup"
|
|
2895
2926
|
${modelEnv}nohup "$DSH_BIN" web --host 127.0.0.1 --port "$PORT" --no-open > "$DSH_HOME/remote-agent/web.log" 2>&1 &
|
|
2896
2927
|
echo $! > "$DSH_HOME/remote-agent/web.pid"
|
|
2897
2928
|
echo "dsh-remote: started dsh web under nohup (pid $(cat "$DSH_HOME/remote-agent/web.pid"))"`;
|
|
@@ -2987,7 +3018,7 @@ function runRemoteScript(target, script, options) {
|
|
|
2987
3018
|
reject(new Error(`remote bootstrap timed out after ${options.timeoutMs}ms`));
|
|
2988
3019
|
}, options.timeoutMs);
|
|
2989
3020
|
timer.unref?.();
|
|
2990
|
-
const append = (target2, chunk) => {
|
|
3021
|
+
const append = (target2, stream, chunk) => {
|
|
2991
3022
|
bytes += chunk.length;
|
|
2992
3023
|
if (bytes > 4 * 1024 * 1024) {
|
|
2993
3024
|
child.kill("SIGKILL");
|
|
@@ -2995,9 +3026,13 @@ function runRemoteScript(target, script, options) {
|
|
|
2995
3026
|
}
|
|
2996
3027
|
target2.push(chunk);
|
|
2997
3028
|
if (options.verbose) process.stderr.write(chunk);
|
|
3029
|
+
try {
|
|
3030
|
+
options.onOutput?.(stream, chunk.toString("utf8"));
|
|
3031
|
+
} catch {
|
|
3032
|
+
}
|
|
2998
3033
|
};
|
|
2999
|
-
child.stdout.on("data", (chunk) => append(stdout, chunk));
|
|
3000
|
-
child.stderr.on("data", (chunk) => append(stderr, chunk));
|
|
3034
|
+
child.stdout.on("data", (chunk) => append(stdout, "stdout", chunk));
|
|
3035
|
+
child.stderr.on("data", (chunk) => append(stderr, "stderr", chunk));
|
|
3001
3036
|
child.stdin.on("error", (error) => {
|
|
3002
3037
|
if (settled) return;
|
|
3003
3038
|
settled = true;
|
|
@@ -3019,8 +3054,13 @@ function runRemoteScript(target, script, options) {
|
|
|
3019
3054
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
3020
3055
|
code: code ?? (signal === null ? 1 : 137)
|
|
3021
3056
|
};
|
|
3022
|
-
if (result.code === 0)
|
|
3023
|
-
|
|
3057
|
+
if (result.code === 0) {
|
|
3058
|
+
resolve4(result);
|
|
3059
|
+
return;
|
|
3060
|
+
}
|
|
3061
|
+
const tail = result.stderr.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line !== "").slice(-2).join(" | ").slice(0, 500);
|
|
3062
|
+
const message = `remote bootstrap exited with ${String(result.code)}${tail === "" ? "" : `: ${tail}`}`;
|
|
3063
|
+
reject(Object.assign(new Error(message), { result }));
|
|
3024
3064
|
});
|
|
3025
3065
|
child.stdin.end(script);
|
|
3026
3066
|
});
|
|
@@ -3031,7 +3071,9 @@ async function provisionRemoteAgent(options) {
|
|
|
3031
3071
|
await access(options.agentTarballPath);
|
|
3032
3072
|
const remoteTarball = `/tmp/dsh-remote-agent-${Date.now()}-${process.pid}.tgz`;
|
|
3033
3073
|
const timeoutMs = Math.max(options.timeoutMs ?? 6e5, 6e5);
|
|
3074
|
+
options.onProgress?.("dsh-remote: uploading agent package");
|
|
3034
3075
|
await uploadFile2(options.agentTarballPath, remoteTarball, target, options);
|
|
3076
|
+
options.onProgress?.("dsh-remote: agent package uploaded");
|
|
3035
3077
|
const script = renderBootstrapScript({
|
|
3036
3078
|
profile: options.profile,
|
|
3037
3079
|
port: 0,
|
|
@@ -3044,13 +3086,38 @@ async function provisionRemoteAgent(options) {
|
|
|
3044
3086
|
start: options.start,
|
|
3045
3087
|
agentTarball: remoteTarball,
|
|
3046
3088
|
...options.modelBaseUrl === void 0 ? {} : { modelBaseUrl: options.modelBaseUrl },
|
|
3047
|
-
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey }
|
|
3089
|
+
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey },
|
|
3090
|
+
...options.proxyUrl === void 0 ? {} : { proxyUrl: options.proxyUrl },
|
|
3091
|
+
...options.noProxy === void 0 ? {} : { noProxy: options.noProxy }
|
|
3048
3092
|
});
|
|
3093
|
+
let stdoutBuffer = "";
|
|
3094
|
+
let stderrBuffer = "";
|
|
3095
|
+
const emitLines = (stream, chunk) => {
|
|
3096
|
+
const key2 = stream === "stdout" ? "stdout" : "stderr";
|
|
3097
|
+
let buffer = key2 === "stdout" ? stdoutBuffer : stderrBuffer;
|
|
3098
|
+
buffer += chunk;
|
|
3099
|
+
let newline = buffer.indexOf("\n");
|
|
3100
|
+
while (newline >= 0) {
|
|
3101
|
+
const line = buffer.slice(0, newline).trim();
|
|
3102
|
+
buffer = buffer.slice(newline + 1);
|
|
3103
|
+
if (line !== "") {
|
|
3104
|
+
try {
|
|
3105
|
+
options.onProgress?.(line);
|
|
3106
|
+
} catch {
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
newline = buffer.indexOf("\n");
|
|
3110
|
+
}
|
|
3111
|
+
if (buffer.length > 8192) buffer = buffer.slice(-8192);
|
|
3112
|
+
if (key2 === "stdout") stdoutBuffer = buffer;
|
|
3113
|
+
else stderrBuffer = buffer;
|
|
3114
|
+
};
|
|
3049
3115
|
const result = await runRemoteScript(target, script, {
|
|
3050
3116
|
binary: options.sshBinary,
|
|
3051
3117
|
strictHostKeyChecking: options.strictHostKeyChecking,
|
|
3052
3118
|
timeoutMs,
|
|
3053
|
-
verbose: options.verbose ?? false
|
|
3119
|
+
verbose: options.verbose ?? false,
|
|
3120
|
+
onOutput: emitLines
|
|
3054
3121
|
});
|
|
3055
3122
|
return { stdout: result.stdout, stderr: result.stderr, remoteTarball };
|
|
3056
3123
|
}
|
|
@@ -3181,7 +3248,9 @@ var RemoteProvisioner = class {
|
|
|
3181
3248
|
*/
|
|
3182
3249
|
async ensureInstalled(target, options = {}) {
|
|
3183
3250
|
const tarball = findAgentTarball();
|
|
3184
|
-
options.onProgress?.("\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5
|
|
3251
|
+
options.onProgress?.("\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026");
|
|
3252
|
+
const proxyUrl = this.#config.remoteInstallProxy.trim() || void 0;
|
|
3253
|
+
if (proxyUrl !== void 0) options.onProgress?.("\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026");
|
|
3185
3254
|
try {
|
|
3186
3255
|
await provisionRemoteAgent({
|
|
3187
3256
|
target: target.canonical,
|
|
@@ -3199,7 +3268,15 @@ var RemoteProvisioner = class {
|
|
|
3199
3268
|
timeoutMs: this.#config.provisionTimeoutMs,
|
|
3200
3269
|
...options.modelBaseUrl === void 0 ? {} : { modelBaseUrl: options.modelBaseUrl },
|
|
3201
3270
|
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey },
|
|
3202
|
-
verbose: false
|
|
3271
|
+
verbose: false,
|
|
3272
|
+
...proxyUrl === void 0 ? {} : {
|
|
3273
|
+
proxyUrl,
|
|
3274
|
+
noProxy: this.#config.remoteInstallNoProxy
|
|
3275
|
+
},
|
|
3276
|
+
onProgress: (line) => {
|
|
3277
|
+
const message = progressForLine(line);
|
|
3278
|
+
if (message !== void 0) options.onProgress?.(message);
|
|
3279
|
+
}
|
|
3203
3280
|
});
|
|
3204
3281
|
} catch (error) {
|
|
3205
3282
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -3209,12 +3286,13 @@ var RemoteProvisioner = class {
|
|
|
3209
3286
|
cause: error
|
|
3210
3287
|
});
|
|
3211
3288
|
}
|
|
3212
|
-
options.onProgress?.("\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u7B49\u5F85 DSH web \u542F\u52A8\u2026");
|
|
3289
|
+
options.onProgress?.("\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u6B63\u5728\u7B49\u5F85 DSH web \u542F\u52A8\u2026");
|
|
3213
3290
|
await this.#waitForAgent(target, options.onProgress, options.signal);
|
|
3214
3291
|
}
|
|
3215
3292
|
async #waitForAgent(target, onProgress, signal) {
|
|
3216
3293
|
const deadline = Date.now() + 12e4;
|
|
3217
3294
|
let lastError;
|
|
3295
|
+
onProgress?.("\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u2026");
|
|
3218
3296
|
while (Date.now() < deadline) {
|
|
3219
3297
|
if (signal?.aborted === true) throw new LocalError("internal", "\u8FDC\u7AEF\u5B89\u88C5\u5DF2\u53D6\u6D88");
|
|
3220
3298
|
try {
|
|
@@ -3224,10 +3302,13 @@ var RemoteProvisioner = class {
|
|
|
3224
3302
|
strictHostKeyChecking: this.#config.strictHostKeyChecking,
|
|
3225
3303
|
remoteStateFile: this.#config.remoteStateFile
|
|
3226
3304
|
});
|
|
3227
|
-
if (isAgentLive(discovered.state))
|
|
3305
|
+
if (isAgentLive(discovered.state)) {
|
|
3306
|
+
onProgress?.("\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026");
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3228
3309
|
} catch (error) {
|
|
3229
3310
|
lastError = error;
|
|
3230
|
-
onProgress?.("\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026");
|
|
3311
|
+
onProgress?.("\u4ECD\u5728\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026");
|
|
3231
3312
|
}
|
|
3232
3313
|
await new Promise((resolve4) => setTimeout(resolve4, 2e3));
|
|
3233
3314
|
}
|
|
@@ -3237,6 +3318,31 @@ var RemoteProvisioner = class {
|
|
|
3237
3318
|
});
|
|
3238
3319
|
}
|
|
3239
3320
|
};
|
|
3321
|
+
var PROVISION_PROGRESS = [
|
|
3322
|
+
["uploading agent package", "\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026"],
|
|
3323
|
+
["agent package uploaded", "\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026"],
|
|
3324
|
+
["preparing remote install", "\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026"],
|
|
3325
|
+
["install proxy configured", "\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026"],
|
|
3326
|
+
["downloading node.js", "\u6B63\u5728\u4E0B\u8F7D Node.js\u2026"],
|
|
3327
|
+
["installed node.js", "Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026"],
|
|
3328
|
+
["node ready", "Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026"],
|
|
3329
|
+
["installing pnpm@", "\u6B63\u5728\u5B89\u88C5 pnpm\u2026"],
|
|
3330
|
+
["installing @deepseek-ai/dsh@", "\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF DSH\uFF08\u4E0B\u8F7D\u4F9D\u8D56\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF09\u2026"],
|
|
3331
|
+
["adding plugin to profile", "\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF agent\u2026"],
|
|
3332
|
+
["restarting systemd user unit", "\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026"],
|
|
3333
|
+
["starting dsh web under nohup", "\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web\u2026"],
|
|
3334
|
+
["starting dsh web", "\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026"],
|
|
3335
|
+
["waiting for agent state", "\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u6587\u4EF6\u2026"],
|
|
3336
|
+
["agent ready", "\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026"],
|
|
3337
|
+
["installed", "\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\u2026"]
|
|
3338
|
+
];
|
|
3339
|
+
function progressForLine(line) {
|
|
3340
|
+
const normalized = line.toLowerCase();
|
|
3341
|
+
for (const [needle, message] of PROVISION_PROGRESS) {
|
|
3342
|
+
if (normalized.includes(needle)) return message;
|
|
3343
|
+
}
|
|
3344
|
+
return void 0;
|
|
3345
|
+
}
|
|
3240
3346
|
function findAgentTarball() {
|
|
3241
3347
|
const candidates = [
|
|
3242
3348
|
new URL("../assets", import.meta.url),
|
|
@@ -3703,7 +3809,7 @@ var RemoteHostsService = class {
|
|
|
3703
3809
|
phase: "installing",
|
|
3704
3810
|
modelProxy: proxy !== void 0,
|
|
3705
3811
|
modelDirect: direct !== void 0,
|
|
3706
|
-
detail: "\u6B63\u5728\
|
|
3812
|
+
detail: "\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026"
|
|
3707
3813
|
});
|
|
3708
3814
|
try {
|
|
3709
3815
|
await this.#provisioner.ensureInstalled(target, {
|
|
@@ -3881,13 +3987,14 @@ var RemoteHostsService = class {
|
|
|
3881
3987
|
this.#setRuntime(id, {
|
|
3882
3988
|
...this.#runtimeFor(id),
|
|
3883
3989
|
phase: "installing",
|
|
3884
|
-
detail: "\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5
|
|
3990
|
+
detail: "\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026"
|
|
3885
3991
|
});
|
|
3886
3992
|
try {
|
|
3887
3993
|
await this.#provisioner.ensureInstalled(target, {
|
|
3888
3994
|
...this.#modelEnvironment(proxy, proxyToken, direct),
|
|
3889
3995
|
onProgress: (detail) => this.#setRuntime(id, { ...this.#runtimeFor(id), detail })
|
|
3890
3996
|
});
|
|
3997
|
+
this.#setRuntime(id, { ...this.#runtimeFor(id), detail: "\u6B63\u5728\u8BFB\u53D6\u8FDC\u7AEF agent \u72B6\u6001\u2026" });
|
|
3891
3998
|
const discovery = await this.#discover(target);
|
|
3892
3999
|
remotePort = discovery.state.port;
|
|
3893
4000
|
token = discovery.state.token;
|
|
@@ -3924,6 +4031,7 @@ var RemoteHostsService = class {
|
|
|
3924
4031
|
phase: "connecting",
|
|
3925
4032
|
detail: "\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u5E76\u6821\u9A8C\u8FDC\u7AEF agent\u2026"
|
|
3926
4033
|
});
|
|
4034
|
+
this.#setRuntime(id, { ...this.#runtimeFor(id), phase: "connecting", detail: "\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u2026" });
|
|
3927
4035
|
let tunnel;
|
|
3928
4036
|
try {
|
|
3929
4037
|
tunnel = await Tunnel.start({
|
|
@@ -3940,6 +4048,7 @@ var RemoteHostsService = class {
|
|
|
3940
4048
|
token,
|
|
3941
4049
|
hostId: id
|
|
3942
4050
|
});
|
|
4051
|
+
this.#setRuntime(id, { ...this.#runtimeFor(id), detail: "\u6B63\u5728\u6821\u9A8C\u8FDC\u7AEF agent\u2026" });
|
|
3943
4052
|
const health = await client.health();
|
|
3944
4053
|
if (await this.#reconcileModelEnvironment(id, target, health, proxy, proxyToken, direct, tunnel)) {
|
|
3945
4054
|
return this.#doConnect(id);
|
|
@@ -3977,6 +4086,7 @@ var RemoteHostsService = class {
|
|
|
3977
4086
|
return false;
|
|
3978
4087
|
}
|
|
3979
4088
|
this.#modelReconciled.add(id);
|
|
4089
|
+
this.#setRuntime(id, { ...this.#runtimeFor(id), detail: "\u6B63\u5728\u540C\u6B65\u8FDC\u7AEF\u6A21\u578B\u73AF\u5883\u2026" });
|
|
3980
4090
|
this.ctx.logger.warn(
|
|
3981
4091
|
"dsh-remote: remote model environment for %s is %s, expected %s; reinstalling",
|
|
3982
4092
|
id,
|
package/lib/types/config.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ export interface Config {
|
|
|
27
27
|
readonly remotePnpmVersion?: string;
|
|
28
28
|
/** Node.js version installed into the remote install dir when none is usable. */
|
|
29
29
|
readonly remoteNodeVersion?: string;
|
|
30
|
+
/** Optional HTTP(S) proxy for remote provisioning; empty means auto-detect. */
|
|
31
|
+
readonly remoteInstallProxy?: string;
|
|
32
|
+
/** Comma-separated proxy bypass list. */
|
|
33
|
+
readonly remoteInstallNoProxy?: string;
|
|
30
34
|
/** Download Node.js into the remote install dir when it is missing or too old. */
|
|
31
35
|
readonly autoInstallNode?: boolean;
|
|
32
36
|
/** `systemd`, `nohup`, or `none`. */
|
|
@@ -71,6 +75,8 @@ export interface ResolvedConfig {
|
|
|
71
75
|
readonly remoteDshVersion: string;
|
|
72
76
|
readonly remotePnpmVersion: string;
|
|
73
77
|
readonly remoteNodeVersion: string;
|
|
78
|
+
readonly remoteInstallProxy: string;
|
|
79
|
+
readonly remoteInstallNoProxy: string;
|
|
74
80
|
readonly autoInstallNode: boolean;
|
|
75
81
|
readonly remoteStart: RemoteStartMode;
|
|
76
82
|
readonly provisionTimeoutMs: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-local-plugin",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "DSH remote-development local plugin: host registry, SSH tunnels, remote workspace/session discovery, an authenticated Connection RPC surface, agent tools, and a Settings page.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RPC contract shared by the host handler and the browser Settings page.
|
|
3
|
-
*
|
|
4
|
-
* The channel rides DSH's authenticated Connection transport, so it works
|
|
5
|
-
* through the web HTTP carrier and the desktop IPC carrier without a second
|
|
6
|
-
* authentication scheme.
|
|
7
|
-
*
|
|
8
|
-
* @module dsh-remote-local/rpc/contract
|
|
9
|
-
*/
|
|
10
|
-
import type { HostView } from '../hosts/types.ts';
|
|
11
|
-
import type { HostInfo, RemoteSessionSummary, RemoteWorkspace, SessionSnapshot } from '@dsh-remote/protocol';
|
|
12
|
-
/** Absolute Connection RPC channel. */
|
|
13
|
-
export declare const RPC_CHANNEL = "/dsh-remote";
|
|
14
|
-
/** Endpoint names. */
|
|
15
|
-
export type RpcEndpoint = 'state' | 'target/validate' | 'host/add' | 'host/remove' | 'host/connect' | 'host/disconnect' | 'host/refresh' | 'host/workspaces' | 'host/sessions' | 'host/session' | 'host/web-url';
|
|
16
|
-
/** Browser-safe state snapshot. */
|
|
17
|
-
export interface RemoteHostsState {
|
|
18
|
-
readonly protocolVersion: number;
|
|
19
|
-
readonly hosts: readonly HostView[];
|
|
20
|
-
}
|
|
21
|
-
/** Result of parsing a destination. */
|
|
22
|
-
export interface ValidatedTarget {
|
|
23
|
-
readonly canonical: string;
|
|
24
|
-
readonly host: string;
|
|
25
|
-
readonly user: string | null;
|
|
26
|
-
readonly port: number | null;
|
|
27
|
-
}
|
|
28
|
-
/** Result of listing workspaces. */
|
|
29
|
-
export interface WorkspacesResult {
|
|
30
|
-
readonly workspaces: readonly RemoteWorkspace[];
|
|
31
|
-
}
|
|
32
|
-
/** Result of listing sessions. */
|
|
33
|
-
export interface SessionsResult {
|
|
34
|
-
readonly sessions: readonly RemoteSessionSummary[];
|
|
35
|
-
}
|
|
36
|
-
/** Result of resolving the remote Web UI. */
|
|
37
|
-
export interface WebUrlResult {
|
|
38
|
-
readonly url: string;
|
|
39
|
-
}
|
|
40
|
-
/** Success/failure result used by the Connection RPC handler. */
|
|
41
|
-
export type RpcResult<T> = {
|
|
42
|
-
readonly ok: true;
|
|
43
|
-
readonly value: T;
|
|
44
|
-
} | {
|
|
45
|
-
readonly ok: false;
|
|
46
|
-
readonly error: {
|
|
47
|
-
readonly code: string;
|
|
48
|
-
readonly message: string;
|
|
49
|
-
readonly details: Record<string, unknown>;
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
/** Payloads accepted by each endpoint. */
|
|
53
|
-
export interface RpcPayloads {
|
|
54
|
-
state: undefined;
|
|
55
|
-
'target/validate': {
|
|
56
|
-
sshTarget: string;
|
|
57
|
-
};
|
|
58
|
-
'host/add': {
|
|
59
|
-
sshTarget: string;
|
|
60
|
-
label?: string;
|
|
61
|
-
token?: string;
|
|
62
|
-
remoteAgentPort?: number;
|
|
63
|
-
autoConnect?: boolean;
|
|
64
|
-
};
|
|
65
|
-
'host/remove': {
|
|
66
|
-
hostId: string;
|
|
67
|
-
};
|
|
68
|
-
'host/connect': {
|
|
69
|
-
hostId: string;
|
|
70
|
-
};
|
|
71
|
-
'host/disconnect': {
|
|
72
|
-
hostId: string;
|
|
73
|
-
};
|
|
74
|
-
'host/refresh': {
|
|
75
|
-
hostId: string;
|
|
76
|
-
};
|
|
77
|
-
'host/workspaces': {
|
|
78
|
-
hostId: string;
|
|
79
|
-
};
|
|
80
|
-
'host/sessions': {
|
|
81
|
-
hostId: string;
|
|
82
|
-
workspaceId?: string;
|
|
83
|
-
};
|
|
84
|
-
'host/session': {
|
|
85
|
-
hostId: string;
|
|
86
|
-
sessionId: string;
|
|
87
|
-
limit?: number;
|
|
88
|
-
};
|
|
89
|
-
'host/web-url': {
|
|
90
|
-
hostId: string;
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/** Values returned by each endpoint. */
|
|
94
|
-
export interface RpcValues {
|
|
95
|
-
state: RemoteHostsState;
|
|
96
|
-
'target/validate': ValidatedTarget;
|
|
97
|
-
'host/add': HostView;
|
|
98
|
-
'host/remove': {
|
|
99
|
-
removed: true;
|
|
100
|
-
};
|
|
101
|
-
'host/connect': HostView;
|
|
102
|
-
'host/disconnect': HostView;
|
|
103
|
-
'host/refresh': HostView;
|
|
104
|
-
'host/workspaces': WorkspacesResult;
|
|
105
|
-
'host/sessions': SessionsResult;
|
|
106
|
-
'host/session': SessionSnapshot;
|
|
107
|
-
'host/web-url': WebUrlResult;
|
|
108
|
-
}
|
|
109
|
-
/** Host capabilities advertised in the UI. */
|
|
110
|
-
export declare const HOST_CAPABILITIES: readonly ["workspace.list", "session.list", "session.snapshot"];
|
|
111
|
-
/** Informational type for the Settings page. */
|
|
112
|
-
export interface HostSummary extends Pick<HostView, 'id' | 'label' | 'sshTarget' | 'phase'> {
|
|
113
|
-
readonly hostInfo: HostInfo | null;
|
|
114
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Host-side RPC dispatch for the Settings page.
|
|
3
|
-
*
|
|
4
|
-
* @module dsh-remote-local/rpc/handler
|
|
5
|
-
*/
|
|
6
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
-
import type { RemoteHostsService } from '../service.ts';
|
|
8
|
-
import { type RpcEndpoint, type RpcResult, type RpcValues } from './contract.ts';
|
|
9
|
-
/** Register the channel; returns its asynchronous disposer. */
|
|
10
|
-
export declare function registerHostRpc(ctx: Context, service: RemoteHostsService): () => Promise<void>;
|
|
11
|
-
/** Narrow a result for callers that want a compiler-checked endpoint name. */
|
|
12
|
-
export type HostRpcResult<K extends RpcEndpoint> = RpcResult<RpcValues[K]>;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/client/index.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { ClientTerminals } from '@deepseek-ai/dsh-api-terminal-controller/client'\n\nexport const inject = ['remote', 'remote.terminal', 'connection']\nconst ROUTE = '/api/dsh-remote-terminal'\n\ninterface Handle extends AsyncIterable<unknown> {\n send(item: unknown): void\n end(): void\n dispose(): void\n}\n\nexport function apply(ctx: Context): void {\n const original = (ctx.remote as any).terminal\n const routed = route(original)\n new ClientTerminals(ctx as any, routed)\n}\n\nfunction route(original: any): any {\n const mirrored = new Map<string, Promise<boolean>>()\n const isMirror = (sessionId: string): Promise<boolean> => {\n let pending = mirrored.get(sessionId)\n if (pending === undefined) {\n pending = post({ action: 'context', sessionId })\n .then(value => (value as { mirrored?: boolean } | undefined)?.mirrored === true)\n .catch(() => false)\n mirrored.set(sessionId, pending)\n }\n return pending\n }\n const unary = (name: string) => async (...args: any[]) => {\n const sessionId = String(args[0])\n if (!await isMirror(sessionId)) return original[name](...args)\n const value = await post({ action: name, sessionId, ...payload(name, args) })\n return value === undefined ? original[name](...args) : { ok: true, value }\n }\n return {\n ...original,\n environment: unary('environment'),\n shells: unary('shells'),\n list: unary('list'),\n create: unary('create'),\n rename: unary('rename'),\n close: unary('close'),\n retain: (sessionId: string, id: string, signal: AbortSignal) => {\n const local = original.retain(sessionId, id, signal)\n return (async function* () {\n if (await isMirror(sessionId)) {\n yield { type: 'retained' }\n return\n }\n yield* local\n })()\n },\n attach: (sessionId: string, id: string, signal: AbortSignal) => new RoutedHandle(original, sessionId, id, signal, isMirror),\n }\n}\n\nfunction payload(name: string, args: any[]): Record<string, unknown> {\n if (name === 'create') {\n const request = args[1] ?? {}\n return { id: request.id, cols: request.cols, rows: request.rows, shellPath: request.shellPath }\n }\n if (name === 'rename') return { id: args[1], title: args[2] }\n if (name === 'close') return { id: args[1] }\n return {}\n}\n\nasync function post(payload: Record<string, unknown>): Promise<any> {\n const response = await fetch(ROUTE, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!response.ok) return undefined\n const body = await response.json() as { ok?: boolean; value?: unknown; mirrored?: boolean }\n if (body.mirrored !== undefined) return body\n return body.ok === true ? body.value : undefined\n}\n\nclass RoutedHandle implements Handle {\n #original: any\n #sessionId: string\n #id: string\n #signal: AbortSignal\n #isMirror: (sessionId: string) => Promise<boolean>\n #handle: Handle | undefined\n #pending: unknown[] = []\n #controller = new AbortController()\n #opening: Promise<Handle> | undefined\n\n constructor(original: any, sessionId: string, id: string, signal: AbortSignal, isMirror: (sessionId: string) => Promise<boolean>) {\n this.#original = original\n this.#sessionId = sessionId\n this.#id = id\n this.#signal = signal\n this.#isMirror = isMirror\n signal.addEventListener('abort', () => this.#controller.abort(), { once: true })\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<unknown> {\n const handle = await this.#open()\n yield* handle\n }\n\n send(item: unknown): void {\n if (this.#handle !== undefined) this.#handle.send(item)\n else this.#pending.push(item)\n }\n\n end(): void { this.#handle?.end() }\n\n dispose(): void {\n this.#controller.abort()\n this.#handle?.dispose()\n }\n\n async #open(): Promise<Handle> {\n if (this.#handle !== undefined) return this.#handle\n this.#opening ??= (async () => {\n const remote = await this.#isMirror(this.#sessionId)\n const handle: Handle = remote\n ? remoteHandle(this.#sessionId, this.#id, this.#controller.signal)\n : this.#original.attach(this.#sessionId, this.#id, this.#signal)\n this.#handle = handle\n for (const item of this.#pending.splice(0)) handle.send(item)\n return handle\n })()\n return this.#opening\n }\n}\n\nfunction remoteHandle(sessionId: string, id: string, signal: AbortSignal): Handle {\n let controller = new AbortController()\n const abort = (): void => controller.abort()\n signal.addEventListener('abort', abort, { once: true })\n return {\n async *[Symbol.asyncIterator]() {\n const response = await fetch(ROUTE, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'content-type': 'application/json', accept: 'text/event-stream' },\n body: JSON.stringify({ action: 'attach', sessionId, id }),\n signal: controller.signal,\n })\n if (!response.ok || response.body === null) throw new Error('remote terminal attach failed')\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n try {\n for (;;) {\n const { done, value } = await reader.read()\n buffer += decoder.decode(value, { stream: !done })\n let newline = buffer.indexOf('\\n')\n while (newline >= 0) {\n const line = buffer.slice(0, newline).replace(/\\r$/u, '')\n buffer = buffer.slice(newline + 1)\n if (line.startsWith('data: ')) {\n const parsed = JSON.parse(line.slice(6).trim())\n if (parsed.message !== undefined && parsed.type === undefined) throw new Error(parsed.message)\n yield parsed\n }\n newline = buffer.indexOf('\\n')\n }\n if (done) return\n }\n } finally {\n reader.releaseLock()\n }\n },\n send(item: unknown) {\n const input = item as { type?: string; data?: string; cols?: number; rows?: number; sequence?: number }\n void post(input.type === 'write'\n ? { action: 'input', sessionId, id, data: input.data ?? '', sequence: input.sequence ?? 0 }\n : { action: 'resize', sessionId, id, cols: input.cols ?? 80, rows: input.rows ?? 24, sequence: input.sequence ?? 0 })\n },\n end() {},\n dispose() { controller.abort() },\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["payload"]
|
|
7
|
-
}
|