Something went wrong. Try again.
fork of prime agent with changes i want but are not upstreamable probqbly (and some fixes)
Something went wrong. Try again.
7.4 kB · 191 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192import { createHash } from "node:crypto";import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";import { tmpdir } from "node:os";import { join } from "node:path";import { describe, expect, it } from "vitest";import { type DaemonInfo, evaluateShutdownQuietPeriod, planReap, planShutdownAll, planShutdownConfirmation, reapStaleWorkerSessions, verifyHelloSupervisorPid,} from "../src/cli/daemon-ps.js";import { canonicalSessionPath, getProcessStartId } from "../src/core/session-lease.js";
describe("evaluateShutdownQuietPeriod", () => { it("requires a full quiet period independently of the convergence window", () => { expect(evaluateShutdownQuietPeriod(10_500, 10_000)).toBe("waiting"); expect(evaluateShutdownQuietPeriod(11_000, 10_000)).toBe("complete"); });});
describe("verifyHelloSupervisorPid", () => { it("accepts the hello pid only while its process identity still matches", () => { const processStartId = getProcessStartId(process.pid); expect(verifyHelloSupervisorPid(process.pid, processStartId)).toBe(process.pid); if (processStartId) { expect(verifyHelloSupervisorPid(process.pid, `${processStartId}-stale`)).toBeUndefined(); } });});
describe("planReap", () => { it("never touches the default daemon or daemons with live sessions", () => { const plan = planReap( [ makeDaemon({ socketPath: "/tmp/default.sock", status: "stale", isDefault: true, sessionCount: 0, pid: 1 }), makeDaemon({ socketPath: "/tmp/busy.sock", status: "current", sessionCount: 3, pid: 2 }), ], true, ); expect(plan.map((action) => action.kind)).toEqual(["skip", "skip"]); });
it("removes orphan files and stops reachable idle non-default daemons", () => { const plan = planReap( [ makeDaemon({ socketPath: "/tmp/idle.sock", status: "current", sessionCount: 0, pid: 5 }), makeDaemon({ socketPath: "/tmp/orphan.sock", status: "orphan-file" }), ], false, ); expect(plan.map((action) => action.kind)).toEqual(["shutdown", "remove-file"]); });
it("removes a stale default socket file but never stops a live default daemon", () => { const plan = planReap( [ makeDaemon({ socketPath: "/tmp/default.sock", status: "orphan-file", isDefault: true }), makeDaemon({ socketPath: "/tmp/live-default.sock", status: "current", isDefault: true, sessionCount: 0 }), ], true, ); expect(plan[0]!.kind).toBe("remove-file"); expect(plan[1]!.kind).toBe("skip"); });
it("only kills unreachable daemons with --force", () => { const daemon = makeDaemon({ socketPath: "/tmp/hung.sock", status: "unreachable", pid: 7 }); const skipped = planReap([daemon], false)[0]!; expect(skipped.kind).toBe("skip"); expect(skipped.kind === "skip" ? skipped.reason : "").toContain("prime-agent shutdown --force"); expect(planReap([daemon], true)[0]!.kind).toBe("kill"); });
it("refuses to kill a pid that backs more than one discovered daemon", () => { const plan = planReap( [ makeDaemon({ socketPath: "/tmp/listening.sock", status: "current", sessionCount: 4, pid: 99 }), makeDaemon({ socketPath: "/tmp/phantom.sock", status: "unreachable", pid: 99 }), ], true, ); const phantom = plan.find((action) => action.daemon.socketPath === "/tmp/phantom.sock"); expect(phantom?.kind).toBe("skip"); expect(phantom && phantom.kind === "skip" ? phantom.reason : "").toContain("also backs another daemon"); });});
describe("planShutdownAll", () => { it("targets every service when forced", () => { const plan = planShutdownAll( [ makeDaemon({ socketPath: "/tmp/default.sock", status: "current", isDefault: true, sessionCount: 0, pid: 1, }), makeDaemon({ socketPath: "/tmp/busy.sock", status: "current", sessionCount: 3, pid: 2 }), makeDaemon({ socketPath: "/tmp/hung.sock", status: "unreachable", pid: 7 }), makeDaemon({ socketPath: "/tmp/orphan.sock", status: "orphan-file" }), ], true, ); expect(plan.map((action) => action.kind)).toEqual(["shutdown", "shutdown", "kill", "remove-file"]); });
it("never skips a service when forced", () => { const plan = planShutdownAll( [ makeDaemon({ socketPath: "/tmp/a.sock", status: "stale", pid: 9 }), makeDaemon({ socketPath: "/tmp/b.sock", status: "unreachable", pid: 10 }), ], true, ); expect(plan.some((action) => action.kind === "skip")).toBe(false); });
it("removes the socket file for an unreachable daemon with no pid", () => { const plan = planShutdownAll([makeDaemon({ socketPath: "/tmp/c.sock", status: "unreachable" })], false); expect(plan[0]!.kind).toBe("remove-file"); });
it("requires force for unreachable tracked workers", () => { const daemon = makeDaemon({ socketPath: "/tmp/worker-only.sock", status: "unreachable", hasTrackedWorkers: true, }); expect(planShutdownAll([daemon], false)[0]!.kind).toBe("skip"); expect(planShutdownAll([daemon], true)[0]!.kind).toBe("remove-file"); });});
describe("planShutdownConfirmation", () => { it("never prompts when JSON output was requested", () => { expect(planShutdownConfirmation(1, true, false, true)).toBe("json-error"); });
it("prompts only for non-JSON shutdown at a TTY", () => { expect(planShutdownConfirmation(1, false, false, true)).toBe("prompt"); expect(planShutdownConfirmation(1, false, false, false)).toBe("tty-error"); expect(planShutdownConfirmation(1, true, true, true)).toBe("none"); expect(planShutdownConfirmation(0, false, false, true)).toBe("none"); });});
function makeDaemon(options: Partial<DaemonInfo> & { socketPath: string; status: DaemonInfo["status"] }): DaemonInfo { return { isDefault: false, ...options, };}
describe("reapStaleWorkerSessions", () => { it("detects and clears recovering worker with dead pid, stale lease, and socket", () => { const root = mkdtempSync(join(tmpdir(), "prime-reap-test-")); try { const sessionFile = join(root, "session-test.jsonl"); const socketPath = join(root, "worker.sock"); const workerDir = join(root, "daemon-workers", "test-hash"); mkdirSync(workerDir, { recursive: true }); const descPath = join(workerDir, "w1.json"); const journalPath = join(workerDir, "w1.recovery.jsonl"); writeFileSync( descPath, `{"version":2,"workerId":"w1","pid":2147483647,"socketPath":"${socketPath}","recoveryJournalPath":"${journalPath}","supervisorSocketPath":"/tmp/s.sock","sessionFile":"${sessionFile}","lifecycle":"recovering","consecutiveFailures":8}`, ); writeFileSync(journalPath, "{}\n"); writeFileSync(socketPath, ""); const leaseKey = createHash("sha256").update(canonicalSessionPath(sessionFile)).digest("hex"); const leaseDir = join(root, "session-leases", `${leaseKey}.lock`); mkdirSync(leaseDir, { recursive: true }); writeFileSync(join(leaseDir, "owner.json"), `{"version":1,"pid":2147483647,"sessionPath":"${sessionFile}"}`);
const reaped = reapStaleWorkerSessions(root); expect(reaped).toEqual([ expect.objectContaining({ socketPath: "session session-test", action: expect.stringContaining("cleared") }), ]); expect(existsSync(descPath)).toBe(false); expect(existsSync(journalPath)).toBe(false); expect(existsSync(leaseDir)).toBe(false); expect(existsSync(socketPath)).toBe(false); } finally { rmSync(root, { recursive: true, force: true }); } });});