//#region src/types.d.ts /** * Configuration for the checkpoint engine. */ interface CheckpointConfig { /** Whether checkpointing is enabled. */ readonly enabled: boolean; /** Whether to create a checkpoint automatically on every turn. */ readonly autoCheckpoint: boolean; /** Whether to attempt file restore when forking a session. */ readonly restoreOnFork: boolean; /** Whether to attempt file restore when cloning a session. */ readonly restoreOnClone: boolean; /** Whether to attempt file restore when resuming a session. */ readonly restoreOnResume: boolean; /** Whether checkpoint-backed tree restore is enabled at the SDK layer. */ readonly restoreOnTree: boolean; /** Default instructions for summarization during rewind. */ readonly defaultSummaryInstructions: string; /** Final internal exclude patterns written to checkpoint storage. */ readonly exclude: readonly string[]; /** User include patterns re-applied after internal and user excludes. */ readonly include: readonly string[]; /** Skip files larger than this many MB when staging checkpoints. */ readonly maxFileMB: number | undefined; } /** * Statistics for a single file change within a checkpoint. */ interface FileChange { /** Relative path of the changed file. */ readonly path: string; /** Number of lines added. */ readonly added: number; /** Number of lines removed. */ readonly removed: number; } /** * Metadata stored for each checkpoint. */ interface CheckpointMeta { /** Session entry id that triggered this checkpoint. */ readonly entryId: string; /** Git commit hash of the checkpoint. */ readonly commitHash: string; /** Unix timestamp when the checkpoint was created. */ readonly timestamp: number; /** Truncated user prompt that created this checkpoint. */ readonly prompt: string; /** Number of unique files touched in this turn. */ readonly fileCount: number; /** Per-file change statistics. */ readonly fileChanges: readonly FileChange[]; } //#endregion //#region src/config.d.ts declare const defaultConfig: CheckpointConfig; /** * Merge user-provided settings with hard-coded defaults. * * Every field is validated at runtime via type guards so the * returned object is guaranteed to conform to {@link CheckpointConfig}. */ declare function loadConfig(settings: Record): CheckpointConfig; /** * Load configuration from `/settings.json`. * * Returns defaults when the file is missing; re-throws any other * error (e.g. permission denied) so the caller can decide what to do. */ declare function loadConfigFromFile(configDir: string): CheckpointConfig; //#endregion //#region src/repo-manager.d.ts type SafeCheckoutFailureReason = "dirty" | "dirty-check-failed" | "storage-missing" | "storage-corrupt" | "target-missing" | "invalid-target" | "path-safety-failed" | "lock-failed" | "exclude-refresh-failed" | "checkout-failed" | "rollback-failed" | "preflight-failed"; /** * Outcome of {@link RepoManager.safeCheckout}. * * Discriminated union so callers handle every path at the type level. */ type SafeCheckoutResult = { readonly ok: true; readonly safetyHash?: string; } | { readonly ok: false; readonly reason: SafeCheckoutFailureReason; readonly message?: string; readonly error?: string; readonly rollbackError?: string; }; /** * * Each session gets its own bare repo under `~/.pi/agent/ayu/checkpoints/sessions/`. * The work tree points to the user's project directory so that `git add/checkout` * operate directly on the project files. */ declare class RepoManager { /** Absolute path to the bare `.git` directory. */ private gitDir; /** Absolute path to the project working directory. */ private workTree; private env; private repoDir; private excludePatterns; private maxFileBytes; /** `setExclude` has already scanned nested repositories for the next stage operation. */ private excludeIsFresh; constructor( /** Absolute path to the bare `.git` directory. */ gitDir: string, /** Absolute path to the git index file (outside the work tree). */ indexFile: string, /** Absolute path to the project working directory. */ workTree: string); /** * Execute `fn` while holding an exclusive filesystem lock on this repo. * * Serialises concurrent access across processes and separate package installs. */ withLock(fn: () => Promise): Promise; setMaxFileBytes(maxFileBytes: number | undefined): void; private gitArgs; private static configureIdentity; /** Initialize a fresh bare repo and set default git config. */ init(): Promise; /** Initialize the bare repo while holding the repo lock. */ lockedInit(): Promise; /** * Silently re-initialise the bare repo if it has been deleted externally. * * Used before operations that assume the repo exists (e.g. checkpoint). * Does nothing when the repo is still intact. */ ensureReady(excludePatterns?: readonly string[]): Promise; /** Ensure the bare repo exists while holding the repo lock. */ lockedEnsureReady(excludePatterns?: readonly string[]): Promise; private findNestedGitRepoExcludes; private writeExclude; private refreshExclude; /** Write exclude patterns to `info/exclude` inside the bare repo. */ setExclude(patterns: readonly string[]): Promise; /** Write exclude patterns while holding the repo lock. */ lockedSetExclude(patterns: readonly string[]): Promise; private commitStagedCheckpoint; /** * Stage all files and create a checkpoint commit. * * @param entryId - Session entry id to embed in the commit message. * @returns The 40-character commit hash. */ checkpoint(entryId: string): Promise; /** * Create a checkpoint from the already staged index. * * Callers must only use this after staging changes relative to the intended base. */ checkpointStaged(entryId: string): Promise; /** * Stage all files and create a checkpoint only when they differ from `baseCommit`. * * If the base commit is no longer available, creates a complete checkpoint instead * of risking an unprotected Turn boundary. */ checkpointIfChanged(entryId: string, baseCommit: string): Promise; /** Create a checkpoint while holding the repo lock. */ lockedCheckpoint(entryId: string): Promise; /** Hard-reset the work tree to `commitHash` and remove untracked files. */ checkoutCommit(commitHash: string): Promise; /** Check out a commit while holding the repo lock. */ lockedCheckoutCommit(commitHash: string): Promise; /** * Create a temporary safety commit capturing the current work tree state. * * Used before destructive operations so we can roll back on failure. * @returns The safety commit hash. */ createSafetyCommit(): Promise; /** Create a safety commit while holding the repo lock. */ lockedCreateSafetyCommit(): Promise; /** Clone a bare repo (used when forking/cloning a session). */ static cloneFrom(srcGitDir: string, dstGitDir: string): Promise; /** Update a git ref to point at `commitHash`. */ updateRef(ref: string, commitHash: string): Promise; /** Update a git ref while holding the repo lock. */ lockedUpdateRef(ref: string, commitHash: string): Promise; /** * Return `--numstat` diff between the commit's parent and the commit itself. * * Falls back to `git show --numstat` for the first commit (no parent). */ diffStats(commitHash: string): Promise; /** Return `--numstat` diff between `commitHash` and the current working tree. */ diffWorkingTree(commitHash: string): Promise; private workTreeIsGitWorkTree; private findGitignoreIgnoredPaths; private removeIgnoredFromIndex; private removeWindowsReservedPathsFromIndex; private removePathsFromIndex; private findLargeChangedPaths; private stageGitignoreIgnoredPaths; private stageAllAfterRefresh; /** Stage all changes in the working tree. */ stageAll(): Promise; /** Stage all changes while holding the repo lock. */ lockedStageAll(): Promise; /** Return `--numstat` diff between the staged index and `commitHash`. */ diffAgainst(commitHash: string): Promise; private failure; private passesPathSafetyChecks; private validateRepoStorage; private isValidCommitReference; private hasCommit; /** * Safely check out `targetCommit` with dirty-guard, safety-commit, and * automatic rollback on failure. * * The entire sequence runs inside {@link withLock} so concurrent callers * are serialised. * * @param targetCommit - The commit hash to check out. * @param dirtyBaseCommit - If provided, compare the working tree against * this commit to detect unsnapshotted changes. When dirty, returns * `{ ok: false, reason: "dirty" }`. */ safeCheckout(targetCommit: string, dirtyBaseCommit?: string): Promise; } //#endregion //#region src/resolver.d.ts /** Root directory for all session checkpoint repos. */ declare function getCheckpointSessionsRoot(): string; /** * Resolve the checkpoint repo directory for a given session file. * * @param sessionFile - Absolute path to the session `.jsonl` file. * @returns Directory where the bare repo and index should live. */ declare function getRepoDir(sessionFile: string | undefined): string; /** Resolve the bare `.git` directory inside a repo dir. */ declare function getGitDir(repoDir: string): string; /** Resolve the external git index file path (kept outside the work tree). */ declare function getIndexPath(repoDir: string): string; //#endregion //#region src/exec.d.ts /** * Git environment variables required by {@link RepoManager}. */ interface ExecEnv { GIT_DIR: string; GIT_WORK_TREE: string; GIT_INDEX_FILE: string; } interface ExecOptions { readonly timeoutMs?: number; readonly input?: string; } /** * Discriminated union representing the outcome of a command. * * Using a union instead of throwing lets callers handle errors * explicitly at the type level (skill: discriminated unions). * * @example * const result = await execSafe('git', ['status']); * if (!result.ok) { * console.error(result.error); * return; * } * console.log(result.value.stdout); */ type Result = { readonly ok: true; readonly value: T; } | { readonly ok: false; readonly error: E; }; /** * Run a shell command and return its stdout/stderr. * * Rejects on non-zero exit code or spawn failure. */ declare function exec(command: string, args: string[], env?: ExecEnv, cwd?: string, options?: ExecOptions): Promise<{ stdout: string; stderr: string; }>; /** * Variant of {@link exec} that never throws. * * Returns a {@link Result} so failure paths are visible to the type checker. */ declare function execSafe(command: string, args: string[], env?: ExecEnv, cwd?: string, options?: ExecOptions): Promise>; //#endregion //#region src/diff-parser.d.ts /** * Parse `git diff --numstat` output into structured file changes. * * Expected line format: `\t\t` * Binary files show `-\t-\t` and are mapped to `0/0`. * Non-standard lines fall back to `{ path: line, added: 0, removed: 0 }`. */ declare function parseDiffStats(stdout: string): readonly FileChange[]; //#endregion //#region src/checkpoint-entry.d.ts /** * Pull `pi-checkpoint` custom entries out of a raw session entry list. * * Checkpoint-aware extensions use this to read checkpoint metadata from the * session history without duplicating the extraction logic. */ declare function extractCheckpointData(entries: readonly unknown[]): readonly unknown[]; /** * Checkpoint metadata stored as a Pi session custom entry. * * Introduces before/after commit pairs so that rewind can restore to the state * *before* a turn, while other restore flows can navigate between before and * after snapshots. */ interface CheckpointEntry { /** Schema version. */ readonly v: 2; /** Entry kind discriminator. */ readonly kind: "checkpoint"; /** Stable turn identifier. */ readonly turnId: string; /** Session entry id of the user message that triggered this turn. */ readonly userEntryId: string; /** Git commit hash captured at turn_start. */ readonly beforeCommit: string; /** Git commit hash captured at turn_end (may equal beforeCommit). */ readonly afterCommit: string; /** Truncated user prompt that created this checkpoint. */ readonly prompt: string; /** Number of unique files touched in this turn. */ readonly fileCount: number; /** Per-file change statistics (computed at turn_end). */ readonly fileChanges: readonly FileChange[]; /** ISO timestamp when the checkpoint was finalized. */ readonly createdAt: string; } /** Type guard for {@link CheckpointEntry}. */ declare function isCheckpointEntry(value: unknown): value is CheckpointEntry; /** * Extract checkpoint entries from a list of session entry data objects. * * @param dataList - Raw `.data` values from session custom entries. * @returns Only the valid {@link CheckpointEntry} objects, in order. */ declare function filterCheckpointEntries(dataList: readonly unknown[]): readonly CheckpointEntry[]; /** * Extract checkpoint entries from a raw session entry list. * * Convenience wrapper combining {@link extractCheckpointData} and * {@link filterCheckpointEntries}. */ declare function getCheckpointEntries(entries: readonly unknown[]): readonly CheckpointEntry[]; //#endregion //#region src/lock.d.ts interface RepoLockOptions { readonly acquireTimeoutMs?: number; } /** * Execute `fn` while holding an exclusive filesystem lock on `repoDir`. * * The lock is released in a `finally` block so crashes inside `fn` do not * leak it indefinitely (the stale-detection mechanism handles that edge case). */ declare function withRepoLock(repoDir: string, fn: () => Promise, options?: RepoLockOptions): Promise; //#endregion //#region src/session-state-map.d.ts /** * Per-session state container used by Pi extensions. * * Wraps a `Map` with lazy-init (`get` + factory) and convenience * methods that mirror the patterns repeated across checkpoint-aware extensions. */ declare class SessionStateMap { private map; /** Return existing state or create via `factory`, cache, and return. */ get(sessionId: string, factory: () => T): T; /** Return state if it exists, otherwise `undefined`. */ getOrUndefined(sessionId: string): T | undefined; /** Explicitly set state for a session (overwrites if present). */ set(sessionId: string, state: T): void; /** Remove state for a session. Returns `true` if it existed. */ delete(sessionId: string): boolean; /** Check whether state exists for a session. */ has(sessionId: string): boolean; /** Remove all sessions. */ clear(): void; /** Number of tracked sessions. */ get size(): number; } //#endregion //#region src/restore.d.ts interface RestoreUi { notify(message: string, level: "info" | "warning" | "error"): void; } interface NavigateTreeOptions { readonly summarize?: boolean; readonly customInstructions?: string; readonly replaceInstructions?: boolean; readonly label?: string; } interface NavigateTreeResult { readonly editorText?: string; readonly cancelled: boolean; } type NavigateTreeFnFalse = (entryId: string, options: { readonly summarize: false; }) => Promise; interface RestoreOptions { readonly repo: RepoManager; readonly ui: RestoreUi; readonly navigateTree: NavigateTreeFnFalse; readonly targetCommit: string; readonly dirtyBaseCommit: string | undefined; readonly targetLeafId: string; readonly dirtyMessage: string; readonly failedPrefix: string; readonly rollbackFailedPrefix: string; readonly successMessage: string; } type RestoreResult = { readonly ok: true; } | { readonly ok: false; }; /** * Safely check out a commit and navigate the conversation tree. * * Handles dirty-worktree guard, checkout failure with rollback, * and conversation-tree navigation in one call. */ declare function safeRestore(options: RestoreOptions): Promise; //#endregion //#region src/repo-provider.d.ts /** * Storage seam for repo lifecycle. * * Production uses an in-memory Map-backed adapter. Tests inject a * mock adapter so they never reach the real filesystem. * * One adapter = hypothetical seam. Two adapters (default + mock) = real seam. */ interface RepoProvider { getRepo(sessionId: string): RepoManager | undefined; setRepo(sessionId: string, repo: RepoManager): void; deleteRepo(sessionId: string): void; } /** Default production adapter backed by an in-memory Map. */ declare function createDefaultRepoProvider(): RepoProvider; //#endregion //#region src/session-checkpoint-storage.d.ts interface SessionCheckpointStorageOptions { readonly sessionFile: string | undefined; readonly cwd: string; } interface EnsureSessionCheckpointStorageOptions extends SessionCheckpointStorageOptions { readonly exclude: readonly string[]; } interface CloneSessionCheckpointStorageOptions extends SessionCheckpointStorageOptions { readonly previousSessionFile: string; readonly exclude?: readonly string[]; } type CloneSessionCheckpointStorageResult = Exclude | { readonly ok: false; readonly reason: "source-not-found" | "destination-exists"; }; type SessionCheckpointStorageResult = { readonly ok: true; readonly repo: RepoManager; readonly repoDir: string; readonly gitDir: string; readonly indexFile: string; } | { readonly ok: false; readonly reason: "not-found"; }; declare function resolveSessionCheckpointStorage(options: SessionCheckpointStorageOptions): Promise; declare function cloneSessionCheckpointStorage(options: CloneSessionCheckpointStorageOptions): Promise; declare function safeCloneSessionCheckpointStorage(options: CloneSessionCheckpointStorageOptions): Promise; declare function ensureSessionCheckpointStorage(options: EnsureSessionCheckpointStorageOptions): Promise>; declare function safeEnsureSessionCheckpointStorage(options: EnsureSessionCheckpointStorageOptions): Promise>; //#endregion //#region src/session-repo-binder.d.ts /** * Bind a checkpoint repo to the given session. * * If the session already has a repo bound, returns it immediately. * If `exclude` is provided, ensures the repo exists (creates + initializes if needed). * Otherwise resolves an existing repo; returns undefined if none exists. */ declare function bindSessionRepo(sessionId: string, sessionFile: string | undefined, cwd: string, repos: RepoProvider, options: { readonly exclude: readonly string[]; }): Promise; declare function bindSessionRepo(sessionId: string, sessionFile: string | undefined, cwd: string, repos: RepoProvider, options?: { readonly exclude?: readonly string[]; }): Promise; //#endregion //#region src/storage-manifest.d.ts interface CheckpointStorageManifest { readonly version: 1; readonly sessionId: string; readonly sessionFile: string; readonly cwd: string; readonly firstUserMessage: string; readonly createdAt: string; readonly updatedAt: string; } interface CheckpointStorageManifestRecord { readonly repoDir: string; readonly modifiedAt: string; readonly manifest: CheckpointStorageManifest; } type DeleteSessionCheckpointStorageResult = { readonly ok: true; } | { readonly ok: false; readonly reason: "path-safety-failed" | "manifest-missing" | "storage-corrupt" | "active-session" | "storage-busy" | "delete-failed"; readonly message: string; readonly error?: string; }; declare function readCheckpointStorageManifest(repoDir: string): Promise; declare function writeCheckpointStorageManifest(repoDir: string, manifest: CheckpointStorageManifest): Promise; declare function listCheckpointStorageManifests(): Promise; declare function deleteSessionCheckpointStorage(repoDir: string, activeSessionFile: string | undefined): Promise; declare function purgeSessionCheckpointStorage(repoDir: string, activeSessionFile: string | undefined): Promise; //#endregion export { type CheckpointConfig, type CheckpointEntry, type CheckpointMeta, type CheckpointStorageManifest, type CheckpointStorageManifestRecord, type CloneSessionCheckpointStorageOptions, type CloneSessionCheckpointStorageResult, type DeleteSessionCheckpointStorageResult, type EnsureSessionCheckpointStorageOptions, type ExecEnv, type FileChange, type NavigateTreeOptions, type NavigateTreeResult, RepoManager, type RepoProvider, type RestoreResult, type Result, type SafeCheckoutResult, type SessionCheckpointStorageOptions, type SessionCheckpointStorageResult, SessionStateMap, bindSessionRepo, cloneSessionCheckpointStorage, createDefaultRepoProvider, defaultConfig, deleteSessionCheckpointStorage, ensureSessionCheckpointStorage, exec, execSafe, extractCheckpointData, filterCheckpointEntries, getCheckpointEntries, getCheckpointSessionsRoot, getGitDir, getIndexPath, getRepoDir, isCheckpointEntry, listCheckpointStorageManifests, loadConfig, loadConfigFromFile, parseDiffStats, purgeSessionCheckpointStorage, readCheckpointStorageManifest, resolveSessionCheckpointStorage, safeCloneSessionCheckpointStorage, safeEnsureSessionCheckpointStorage, safeRestore, withRepoLock, writeCheckpointStorageManifest };