import * as fs from "node:fs"; import { SessionManager } from "@earendil-works/pi-coding-agent"; import { requestChildExecutionCwd } from "../runs/shared/child-execution-cwd.ts"; import { errorMessage } from "./unknown.ts"; type SubagentExecutionContext = "fresh" | "fork"; interface ForkableSessionManager { readonly getSessionFile: () => string | undefined; readonly getLeafId: () => string | null; readonly getSessionDir: () => string; } interface ForkContextResolver { readonly sessionFileForIndex: (index?: number) => string | undefined; } export function resolveSubagentContext(value?: unknown): SubagentExecutionContext { return value === "fork" ? "fork" : "fresh"; } export function createForkContextResolver( sessionManager: ForkableSessionManager, ): ForkContextResolver { const parentSessionFile = sessionManager.getSessionFile(); if (parentSessionFile === undefined || parentSessionFile === "") { throw new Error("Forked subagent context requires a persisted parent session."); } const leafId = sessionManager.getLeafId(); if (leafId === null || leafId === "") { throw new Error("Forked subagent context requires a current leaf to fork from."); } const sessionDir = sessionManager.getSessionDir(); const cachedSessionFiles = new Map(); return { sessionFileForIndex(index = 0): string | undefined { const cached = cachedSessionFiles.get(index); if (cached !== undefined && cached !== "") { return cached; } try { if (!fs.existsSync(parentSessionFile)) { throw new Error( `Parent session file does not exist: ${parentSessionFile}. Pi has not persisted enough history to fork yet.`, ); } const sessionFile = SessionManager.open( parentSessionFile, sessionDir, ).createBranchedSession(leafId); if (sessionFile === undefined || sessionFile === "") { throw new Error("Session manager did not return a forked session file."); } if (!fs.existsSync(sessionFile)) { throw new Error( `Session manager returned a forked session file that does not exist: ${sessionFile}`, ); } requestChildExecutionCwd(sessionFile); cachedSessionFiles.set(index, sessionFile); return sessionFile; } catch (error) { throw new Error(`Failed to create forked subagent session: ${errorMessage(error)}`, { cause: error, }); } }, }; }