benchworks 0.4.0 → 0.4.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.
Files changed (2) hide show
  1. package/bin/benchworks.mjs +36 -1
  2. package/package.json +1 -1
@@ -20,7 +20,7 @@ import { join } from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { promisify } from "node:util";
22
22
 
23
- const VERSION = "0.4.0";
23
+ const VERSION = "0.4.2";
24
24
  const API = (process.env.BENCHWORKS_URL ?? "https://benchworks.dev").replace(/\/+$/, "");
25
25
  const HOME = homedir();
26
26
  // the runner's own folder: its key and the folder conversations start in (BENCHWORKS_HOME moves it, for a second pairing on one Mac)
@@ -244,6 +244,8 @@ async function connect(code) {
244
244
  } else {
245
245
  if (away) say("Back in touch with Benchworks.");
246
246
  away = false;
247
+ // a newer runner is out: once no conversation is running here, it takes over in this window
248
+ if (newer(answer.body.latest, VERSION) && ![...sessions.values()].some((s) => s.busy)) return update(answer.body.latest);
247
249
  if (answer.body.ask === "folder") {
248
250
  say("Benchworks asked for a folder. The picker is open.");
249
251
  const path = await pickFolder();
@@ -582,6 +584,8 @@ async function jobs() {
582
584
  continue;
583
585
  }
584
586
  if (r.status === 401) return;
587
+ // the runner that took over asks for jobs now; one handed out here unsaid comes to it again
588
+ if (updating) return;
585
589
  for (const job of r.body.jobs ?? []) {
586
590
  acks.push(job.id);
587
591
  if (seen.has(job.id)) continue;
@@ -597,6 +601,37 @@ setInterval(() => {
597
601
  for (const s of sessions.values()) if (!s.busy && Date.now() - s.lastAt > IDLE_MS) end(s, "idle");
598
602
  }, 60_000).unref();
599
603
 
604
+ /** Whether version a (x.y.z) is newer than b. */
605
+ function newer(a, b) {
606
+ if (typeof a !== "string" || !/^\d+\.\d+\.\d+$/.test(a)) return false;
607
+ const x = a.split(".").map(Number);
608
+ const y = b.split(".").map(Number);
609
+ for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] > y[i];
610
+ return false;
611
+ }
612
+
613
+ let updating = false;
614
+
615
+ /**
616
+ * Moves to a newer runner in this same window: the conversations' Claude Code processes end (the next message resumes
617
+ * each), the new version runs as this one's child with the same key and folder, and this one waits for it and leaves with
618
+ * it. Ctrl-C reaches both, and the child is the one that answers it.
619
+ */
620
+ function update(version) {
621
+ if (updating) return;
622
+ updating = true;
623
+ say(`Benchworks runner ${version} is out. Updating; your conversations carry on with your next message.`);
624
+ for (const s of sessions.values()) end(s, "idle");
625
+ process.removeAllListeners("SIGINT");
626
+ process.on("SIGINT", () => {});
627
+ const child = spawn("npx", ["-y", `benchworks@${version}`, "connect"], { stdio: "inherit", env: { ...process.env, BENCHWORKS_HOME: OWN } });
628
+ child.on("exit", (code) => process.exit(code ?? 0));
629
+ child.on("error", (e) => {
630
+ say(warn(`Could not start ${version} (${e.message}). Run ${again} to update.`));
631
+ process.exit(1);
632
+ });
633
+ }
634
+
600
635
  function quit(code = 0) {
601
636
  for (const s of sessions.values()) s.proc.kill();
602
637
  process.exit(code);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "benchworks",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Connects your Mac to Benchworks, so the Assistant at benchworks.dev runs your own Claude Code with your logins and your files.",
5
5
  "type": "module",
6
6
  "bin": {