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/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 () => {