dsh-plugin-capabilities 0.1.1 → 0.1.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 +16 -11
- package/lib/client.js +60 -6
- package/lib/client.js.map +2 -2
- package/lib/index.js +67 -0
- package/lib/index.js.map +3 -3
- package/package.json +1 -1
- package/src/client/McpTab.tsx +44 -6
- package/src/client/index.ts +8 -1
- package/src/client/locales.ts +10 -0
- package/src/restart.test.ts +52 -0
- package/src/restart.ts +94 -0
- package/src/routes.ts +24 -0
package/lib/index.js
CHANGED
|
@@ -796,6 +796,52 @@ function sendJson(response, status, body) {
|
|
|
796
796
|
response.end(payload);
|
|
797
797
|
}
|
|
798
798
|
|
|
799
|
+
// src/restart.ts
|
|
800
|
+
import { spawn } from "node:child_process";
|
|
801
|
+
import { openSync } from "node:fs";
|
|
802
|
+
import { tmpdir } from "node:os";
|
|
803
|
+
import { dirname, resolve } from "node:path";
|
|
804
|
+
function dshLaunch(argv = process.argv, execArgv = process.execArgv) {
|
|
805
|
+
const entry = argv[1];
|
|
806
|
+
if (entry !== void 0 && /[\\/](?:bin\.(?:js|ts)|dsh)$/.test(entry)) {
|
|
807
|
+
const abs = resolve(entry);
|
|
808
|
+
return { file: process.execPath, args: [...execArgv, abs, ...argv.slice(2)], cwd: dirname(abs), viaShell: false };
|
|
809
|
+
}
|
|
810
|
+
return { file: "dsh", args: [...argv.slice(2)], cwd: void 0, viaShell: process.platform === "win32" };
|
|
811
|
+
}
|
|
812
|
+
function scheduleRestart(launch) {
|
|
813
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
814
|
+
const logOut = `${tmpdir()}${tmpdir().endsWith("/") ? "" : "\\"}dsh-plugin-capabilities-restart-${stamp}.out.log`;
|
|
815
|
+
const logErr = logOut.replace(".out.log", ".err.log");
|
|
816
|
+
const child = spawn(launch.file, launch.args, {
|
|
817
|
+
cwd: launch.cwd,
|
|
818
|
+
stdio: ["ignore", openSync(logOut, "a"), openSync(logErr, "a")],
|
|
819
|
+
env: process.env,
|
|
820
|
+
shell: launch.viaShell,
|
|
821
|
+
windowsHide: true
|
|
822
|
+
});
|
|
823
|
+
child.unref();
|
|
824
|
+
setTimeout(() => process.kill(process.pid, "SIGTERM"), 500);
|
|
825
|
+
return { pid: process.pid, replacementPid: child.pid, logOut, logErr };
|
|
826
|
+
}
|
|
827
|
+
function trustedRestartRequest(request, socketAddress) {
|
|
828
|
+
const address = socketAddress ?? (request.socket.remoteAddress ?? "");
|
|
829
|
+
if (address !== "127.0.0.1" && address !== "::1" && address !== "::ffff:127.0.0.1") return false;
|
|
830
|
+
if (request.headers.forwarded !== void 0 || request.headers["x-forwarded-for"] !== void 0 || request.headers["x-real-ip"] !== void 0) return false;
|
|
831
|
+
const origin = request.headers.origin;
|
|
832
|
+
const host = request.headers.host;
|
|
833
|
+
if (origin === void 0 || host === void 0) return false;
|
|
834
|
+
try {
|
|
835
|
+
const parsed = new URL(origin);
|
|
836
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.host === host;
|
|
837
|
+
} catch {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function restartOwnedByShell(env = process.env) {
|
|
842
|
+
return env.DSH_DESKTOP === "1";
|
|
843
|
+
}
|
|
844
|
+
|
|
799
845
|
// src/skills.ts
|
|
800
846
|
import { existsSync as existsSync2, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
801
847
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -1217,6 +1263,27 @@ function mountCapabilitiesRoutes(host, config) {
|
|
|
1217
1263
|
sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
1218
1264
|
}
|
|
1219
1265
|
}
|
|
1266
|
+
}),
|
|
1267
|
+
host.webServer.register({
|
|
1268
|
+
kind: "exact",
|
|
1269
|
+
path: "/dsh-plugin-capabilities/restart",
|
|
1270
|
+
handler: (request, response) => {
|
|
1271
|
+
if (request.method !== "POST") {
|
|
1272
|
+
response.writeHead(405, { allow: "POST" });
|
|
1273
|
+
response.end();
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (!trustedRestartRequest(request)) {
|
|
1277
|
+
sendJson(response, 403, { error: "untrusted origin" });
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
if (restartOwnedByShell()) {
|
|
1281
|
+
sendJson(response, 409, { error: "restart is owned by the desktop shell" });
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
const { pid, replacementPid, logOut } = scheduleRestart(dshLaunch());
|
|
1285
|
+
sendJson(response, 200, { ok: true, pid, replacementPid, logOut });
|
|
1286
|
+
}
|
|
1220
1287
|
})
|
|
1221
1288
|
];
|
|
1222
1289
|
return () => {
|