demobite 1.20.0 → 1.21.0

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 +23 -2
  2. package/package.json +1 -1
@@ -113,12 +113,16 @@ if (arg === "logs") {
113
113
  let text = ""; try { text = fs.readFileSync(LOG, "utf8"); } catch { /* none */ }
114
114
  const lines = text.trimEnd().split("\n"); console.log(lines.slice(-n).join("\n") || " (no log yet)"); process.exit(0);
115
115
  }
116
- if (arg === "off") {
116
+ // The login service, removed: the file, the registration, and (unless we ARE the service) the listener.
117
+ const removeService = () => {
117
118
  const def = serviceDef();
119
+ fs.rmSync(def.file, { force: true });
118
120
  if (process.platform === "darwin") spawnSync("launchctl", ["bootout", `gui/${process.getuid()}/${SERVICE_LABEL}`], { stdio: "ignore" });
119
121
  else if (process.platform === "linux") spawnSync("systemctl", ["--user", "disable", "--now", SERVICE_UNIT], { stdio: "ignore" });
120
122
  else spawnSync("reg", ["delete", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", RUN_NAME, "/f"], { stdio: "ignore" });
121
- fs.rmSync(def.file, { force: true });
123
+ };
124
+ if (arg === "off") {
125
+ removeService();
122
126
  const pid = killListener();
123
127
  // the browsers of an interrupted take go with it
124
128
  for (const c of readJson(CHILDREN) ?? []) { try { process.kill(process.platform === "win32" ? c : -c, "SIGTERM"); } catch { /* gone */ } }
@@ -600,8 +604,25 @@ if (arg === "listen") {
600
604
  waitOn();
601
605
  };
602
606
 
607
+ // DISCONNECT FROM THE APP (1.21.0, founder 2026-10-16: "go back to the connected machine via my browser
608
+ // and disconnect"): the app's order, taken at check-in. Says so to the app first (the key is needed for
609
+ // that), then the sign-ins, the ledger and the key go from this machine, the login service is removed,
610
+ // and the process ends. `demobite on` with a new line from the app connects it again.
611
+ const runOff = async (job) => {
612
+ console.log(`\n ⏏ Disconnecting this machine, on your word from the app.`);
613
+ noteState({ busy: true, job: job.id });
614
+ await event(job.id, "started", { machine: name });
615
+ await event(job.id, "ready", { disconnected: true, machine: name });
616
+ const rec = path.join(process.cwd(), ".recorder");
617
+ for (const f of ["profile", "signins.json", "config.json", "listen.json"]) fs.rmSync(path.join(rec, f), { recursive: true, force: true });
618
+ noteState({ busy: false, job: null, last_error: null, disconnected: true });
619
+ console.log(` ○ Disconnected. The sign-ins and the key are gone from this machine; the login service is removed.`);
620
+ if (SERVICE) removeService(); // bootout ends this process; the handlers below clear the lock
621
+ bye("OFF");
622
+ };
603
623
  const runJob = async (job) => {
604
624
  waitOff();
625
+ if (job.kind === "off") return runOff(job);
605
626
  if (job.kind === "look" || job.kind === "signin" || job.kind === "signout") return runLookOrSignin(job);
606
627
  const model = typeof job.model === "string" && job.model ? job.model : JOB_MODEL;
607
628
  // Alive while filming (1.13.1): a heartbeat every 5 s so the rail never shows this machine
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "demobite",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
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"