import type { AgentToolResult } from "@earendil-works/pi-agent-core"; import { type ExtensionAPI, defineTool } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { StateStore } from "../state.ts"; export interface ArchiveDetails { agiArchive: { path: string | null; archived: string[]; }; } /** The only model-facing state lifecycle operation. File contents use normal tools. */ export function registerArchiveTool(pi: ExtensionAPI, isReadOnly: () => boolean): void { pi.registerTool( defineTool({ name: "agi_archive", label: "AGI Archive", description: "Archive the current goal.md, plan.md, and notes/ working files as opaque content while preserving memory/ and .runtime/. Use normal read, edit, and write tools for all state content.", parameters: Type.Object({ confirm: Type.Boolean({ description: "Must be true after confirming the current working state should be archived." }), }), execute: async (_id, params, _signal, _onUpdate, ctx): Promise> => { if (params.confirm !== true) throw new Error("agi_archive: set confirm=true to archive goal.md, plan.md, and notes/."); if (isReadOnly()) { throw new Error("agi_archive: this session does not hold the orchestrator lock. Use the lock-holding session for lifecycle changes."); } const result = await new StateStore(ctx.cwd).archive(); const text = result.path === undefined ? "Nothing to archive; goal.md, plan.md, and notes/ have no content." : `Archived ${result.archived.join(", ")} to ${result.path}. memory/ and .runtime/ were preserved.`; return { content: [{ type: "text", text }], details: { agiArchive: { path: result.path ?? null, archived: result.archived } }, }; }, }), ); }