demobite 1.18.4 → 1.18.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.
Files changed (2) hide show
  1. package/launcher/index.mjs +13 -7
  2. package/package.json +1 -1
@@ -25,6 +25,7 @@ import os from "node:os";
25
25
  import path from "node:path";
26
26
  import { fileURLToPath } from "node:url";
27
27
  import { execFileSync, spawnSync } from "node:child_process";
28
+ import { createHash } from "node:crypto";
28
29
 
29
30
  const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
30
31
  const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
@@ -61,7 +62,12 @@ const LOCK = path.join(HOME, "listen.lock");
61
62
  const LOG = path.join(HOME, "listen.log");
62
63
  const STATE = path.join(HOME, "state.json");
63
64
  const CHILDREN = path.join(HOME, "children.json");
64
- const SERVICE_LABEL = "com.demobites.listen";
65
+ // A second home (DEMOBITE_HOME, used by tests and rigs) gets its own service name, so `off` on a rig can
66
+ // never unload the real one (2026-10-16: a scratch rig's `off` removed the founder's service).
67
+ const HOME_TAG = process.env.DEMOBITE_HOME ? "." + createHash("sha1").update(HOME).digest("hex").slice(0, 8) : "";
68
+ const SERVICE_LABEL = `com.demobites.listen${HOME_TAG}`;
69
+ const SERVICE_UNIT = `demobite${HOME_TAG}.service`;
70
+ const RUN_NAME = `DemoBites${HOME_TAG}`;
65
71
  const SERVICE = process.argv.includes("--service");
66
72
  const launcherPath = fileURLToPath(import.meta.url);
67
73
  const readJson = (f) => { try { return JSON.parse(fs.readFileSync(f, "utf8")); } catch { return null; } };
@@ -70,11 +76,11 @@ const pidAlive = (pid) => { if (!pid) return false; try { process.kill(pid, 0);
70
76
  const ago = (iso) => { const s = Math.max(0, Math.round((Date.now() - new Date(iso).getTime()) / 1000)); return s < 60 ? `${s} s ago` : s < 3600 ? `${Math.round(s / 60)} min ago` : `${Math.round(s / 3600)} h ago`; };
71
77
  const serviceDef = () => {
72
78
  if (process.platform === "darwin") return { file: path.join(os.homedir(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`) };
73
- if (process.platform === "linux") return { file: path.join(os.homedir(), ".config", "systemd", "user", "demobite.service") };
79
+ if (process.platform === "linux") return { file: path.join(os.homedir(), ".config", "systemd", "user", SERVICE_UNIT) };
74
80
  return { file: path.join(HOME, "service.vbs") };
75
81
  };
76
82
  const serviceInstalled = () => {
77
- if (process.platform === "win32") { const r = spawnSync("reg", ["query", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", "DemoBites"], { encoding: "utf8" }); return r.status === 0; }
83
+ if (process.platform === "win32") { const r = spawnSync("reg", ["query", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", RUN_NAME], { encoding: "utf8" }); return r.status === 0; }
78
84
  return fs.existsSync(serviceDef().file);
79
85
  };
80
86
  const killListener = () => {
@@ -107,8 +113,8 @@ if (arg === "logs") {
107
113
  if (arg === "off") {
108
114
  const def = serviceDef();
109
115
  if (process.platform === "darwin") spawnSync("launchctl", ["bootout", `gui/${process.getuid()}/${SERVICE_LABEL}`], { stdio: "ignore" });
110
- else if (process.platform === "linux") spawnSync("systemctl", ["--user", "disable", "--now", "demobite.service"], { stdio: "ignore" });
111
- else spawnSync("reg", ["delete", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", "DemoBites", "/f"], { stdio: "ignore" });
116
+ else if (process.platform === "linux") spawnSync("systemctl", ["--user", "disable", "--now", SERVICE_UNIT], { stdio: "ignore" });
117
+ else spawnSync("reg", ["delete", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", RUN_NAME, "/f"], { stdio: "ignore" });
112
118
  fs.rmSync(def.file, { force: true });
113
119
  const pid = killListener();
114
120
  // the browsers of an interrupted take go with it
@@ -322,14 +328,14 @@ if (arg === "on") {
322
328
  fs.writeFileSync(def.file, unit);
323
329
  killListener();
324
330
  spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" });
325
- const r = spawnSync("systemctl", ["--user", "enable", "--now", "demobite.service"], { encoding: "utf8" });
331
+ const r = spawnSync("systemctl", ["--user", "enable", "--now", SERVICE_UNIT], { encoding: "utf8" });
326
332
  if (r.status !== 0) { warn(`systemd refused the service: ${(r.stderr || "").trim()}`); process.exit(1); }
327
333
  } else {
328
334
  // Windows: a Run entry that starts the listener hidden at logon (no console window), via a tiny script.
329
335
  const q = (t) => `""${t}""`;
330
336
  const vbs = `Set sh = CreateObject("WScript.Shell")\nsh.CurrentDirectory = "${cwd}"\nsh.Run "${args.map((a) => q(a)).join(" ")} >> ${q(LOG)} 2>&1", 0, False\n`;
331
337
  fs.writeFileSync(def.file, vbs);
332
- spawnSync("reg", ["add", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", "DemoBites", "/t", "REG_SZ", "/d", `wscript.exe "${def.file}"`, "/f"], { stdio: "ignore" });
338
+ spawnSync("reg", ["add", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", RUN_NAME, "/t", "REG_SZ", "/d", `wscript.exe "${def.file}"`, "/f"], { stdio: "ignore" });
333
339
  killListener();
334
340
  spawnSync("wscript.exe", [def.file], { stdio: "ignore" });
335
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "demobite",
3
- "version": "1.18.4",
3
+ "version": "1.18.5",
4
4
  "description": "The DemoBites agentic recorder — you prompt, it films a real browser, and DemoBites turns the take into an editable demo bite.",
5
5
  "bin": {
6
6
  "demobite": "launcher/index.mjs"