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.0 kB · 179 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, symlinkSync, utimesSync, writeFileSync,} from "node:fs";import { tmpdir } from "node:os";import { join } from "node:path";import { afterEach, describe, expect, it } from "vitest";import { parseArgs } from "../src/cli/args.js";import { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from "../src/core/agent-session-runtime.js";import { getMissingSessionCwdIssue, MissingSessionCwdError } from "../src/core/session-cwd.js";import { SessionManager } from "../src/core/session-manager.js";import { createSessionManager } from "../src/main.js";
function createTempDir(name: string): string { const dir = join(tmpdir(), `${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`); mkdirSync(dir, { recursive: true }); return dir;}
function writeSessionFile(path: string, cwd: string): void { writeFileSync( path, `${JSON.stringify({ type: "session", version: 3, id: "session-id", timestamp: new Date().toISOString(), cwd, })}\n`, );}
describe("session cwd handling", () => { const cleanupPaths: string[] = [];
afterEach(() => { for (const path of cleanupPaths.splice(0)) { rmSync(path, { recursive: true, force: true }); } });
it("throws a controlled error before runtime creation when the stored cwd is missing", async () => { const fallbackCwd = createTempDir("pi-session-cwd-runtime"); const sessionDir = createTempDir("pi-session-cwd-runtime-session-dir"); const sessionFile = join(sessionDir, "session.jsonl"); cleanupPaths.push(fallbackCwd, sessionDir); writeSessionFile(sessionFile, join(fallbackCwd, "does-not-exist"));
let createRuntimeCalled = false; const createRuntime: CreateAgentSessionRuntimeFactory = async () => { createRuntimeCalled = true; throw new Error("should not be called"); };
await expect( createAgentSessionRuntime(createRuntime, { cwd: fallbackCwd, agentDir: fallbackCwd, sessionManager: SessionManager.open(sessionFile), }), ).rejects.toBeInstanceOf(MissingSessionCwdError); expect(createRuntimeCalled).toBe(false); });
// Readonly startup must never repair, migrate, or follow-and-rewrite the transcript on disk. it.each([2, 3])( "reads version %s resume files without repairing, migrating, or changing symlinks", async (version) => { const dir = createTempDir("pi-readonly-resume"); cleanupPaths.push(dir); const storedCwd = join(dir, "missing-project"); const path = join(dir, "session.jsonl"); const alias = join(dir, "alias.jsonl"); const original = `not-json\n${JSON.stringify({ type: "session", version, id: "readonly", timestamp: "2026-01-01T00:00:00Z", cwd: storedCwd })}\n${JSON.stringify({ type: "session_info", id: "name", parentId: null, timestamp: "2026-01-01T00:00:00Z", name: "Reader name" })}\n{"type":"message","id":"torn`; writeFileSync(path, original); symlinkSync(path, alias);
const manager = await createSessionManager(parseArgs(["--resume", alias]), dir, dir, true);
expect(manager.isPersisted()).toBe(false); expect(manager.getCwd()).toBe(storedCwd); expect(manager.getSessionName()).toBe("Reader name"); expect(manager.getSessionFile()).toBe(alias); expect(manager.getEntries()).toHaveLength(1); expect(getMissingSessionCwdIssue(manager, dir)?.sessionCwd).toBe(storedCwd);
// An explicit --cwd overrides the stored cwd instead of reporting it missing. const overridden = await createSessionManager(parseArgs(["--cwd", dir, "--resume", alias]), dir, dir, true); expect(overridden.getCwd()).toBe(dir); expect(getMissingSessionCwdIssue(overridden, dir)).toBeUndefined();
expect(lstatSync(alias).isSymbolicLink()).toBe(true); expect(readFileSync(path, "utf8")).toBe(original); }, );
it("continues the latest matching cwd without mutating its transcript", async () => { const dir = createTempDir("pi-readonly-continue"); cleanupPaths.push(dir); const older = join(dir, "older.jsonl"); const latest = join(dir, "latest.jsonl"); const other = join(dir, "other.jsonl"); writeSessionFile(older, dir); writeSessionFile(latest, dir); writeSessionFile(other, join(dir, "other-project")); const original = `${readFileSync(latest, "utf8")}{"type":"message","id":"torn`; writeFileSync(latest, original); utimesSync(older, 100, 100); utimesSync(latest, 200, 200); utimesSync(other, 300, 300);
const manager = await createSessionManager(parseArgs(["--continue"]), dir, dir, true);
expect(manager.getSessionFile()).toBe(latest); expect(manager.getCwd()).toBe(dir); expect(manager.isPersisted()).toBe(false); expect(readFileSync(latest, "utf8")).toBe(original); });
it("keeps a no-match readonly continue as an in-memory draft", async () => { const dir = createTempDir("pi-readonly-continue-empty"); cleanupPaths.push(dir); writeSessionFile(join(dir, "other.jsonl"), join(dir, "other-project"));
const manager = await createSessionManager(parseArgs(["--continue"]), dir, dir, true);
expect(manager.isPersisted()).toBe(false); expect(manager.getSessionFile()).toBeUndefined(); expect(manager.getSessionDir()).toBe(dir); expect(manager.getCwd()).toBe(dir); });
it("resumes another project's session in its own recorded directory", async () => { const dir = createTempDir("pi-foreign-resume"); cleanupPaths.push(dir); const path = join(dir, "foreign.jsonl"); writeSessionFile(path, join(dir, "project")); const manager = await createSessionManager(parseArgs(["--resume", "session-id"]), join(dir, "here"), dir); expect(manager.getSessionFile()).toBe(path); expect(manager.getCwd()).toBe(join(dir, "project")); });
it("keeps fork output writable when startup reads are readonly", async () => { const dir = createTempDir("pi-readonly-fork"); cleanupPaths.push(dir); const source = join(dir, "source.jsonl"); writeSessionFile(source, dir);
const manager = await createSessionManager(parseArgs(["--fork", source]), dir, dir, true);
expect(manager.isPersisted()).toBe(true); expect(manager.getSessionFile()).not.toBe(source); expect(existsSync(manager.getSessionFile()!)).toBe(true); manager.appendSessionInfo("Writable fork"); expect(SessionManager.open(manager.getSessionFile()!).getSessionName()).toBe("Writable fork"); });
it("preserves writer-owned crash repair for default startup", async () => { const dir = createTempDir("pi-writer-resume"); cleanupPaths.push(dir); const path = join(dir, "session.jsonl"); writeSessionFile(path, dir); const kept = readFileSync(path, "utf8"); writeFileSync(path, `${kept}{"type":"message","id":"torn`);
const manager = await createSessionManager(parseArgs(["--resume", path]), dir, dir);
expect(manager.isPersisted()).toBe(true); expect(readFileSync(path, "utf8")).toBe(kept); manager.appendSessionInfo("After repair"); expect(SessionManager.open(path).getSessionName()).toBe("After repair"); });});