char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Sombetter prompt change ui + configurable subagent enablement51b5eef

main
1.4 KiB42 linesraw
1// Runs berry, and runs it again when it exits to restart, or crashes.
2
3import { fromFileUrl } from "@std/path";
4import { denoExecutable } from "./deno.ts";
5
6/** The exit code berry restarts with. */
7export const RESTART = 75;
8
9if (import.meta.main) {
10  const main = fromFileUrl(new URL("./main.ts", import.meta.url));
11  let stopping = false;
12  let child: Deno.ChildProcess | undefined;
13  // the terminal's ^C reaches berry too; either way, berry stops and then so does this
14  for (const signal of ["SIGINT", "SIGTERM"] as const) {
15    Deno.addSignalListener(signal, () => {
16      stopping = true;
17      try {
18        child?.kill(signal);
19      } catch {
20        // already gone
21      }
22    });
23  }
24
25  let backoff = 1_000;
26  while (true) {
27    const started = Date.now();
28    child = new Deno.Command(denoExecutable(), { args: ["run", "-A", main] }).spawn();
29    const { code } = await child.status;
30    if (stopping || code === 0) Deno.exit(code);
31    if (code === RESTART) {
32      console.log("[berry] restarting");
33      backoff = 1_000;
34      continue;
35    }
36    // a long run means the crash is news, not the same broken code again
37    if (Date.now() - started > 60_000) backoff = 1_000;
38    console.error(`[berry] exited with ${code}; starting again in ${backoff / 1000}s`);
39    await new Promise((resolve) => setTimeout(resolve, backoff));
40    backoff = Math.min(backoff * 2, 30_000);
41  }
42}