/** * Age-based sweeper for tool-output storage. * * Three targets are reaped, all strictly scoped to tool output: * * - `/-/` — the per-session temp trees created by * `session-temp-dir.ts`. * - `//tool-results/` — persisted tool results under the * default, project-nested session roots. * - `/tool-results/` — the same, for a custom session directory * chosen with `--session-dir`, `ATOMIC_CODING_AGENT_SESSION_DIR`, or the * `sessionDir` setting, where there is no project nesting to walk. * * Transcripts, `.jsonl` session files, and every other file under session * storage are out of scope: the walk only ever descends into a `tool-results` * directory, and only ever deletes inside it. * * The throttle/lock shape mirrors `packages/subagents/src/shared/artifacts.ts`: * a `.last-cleanup` marker skips the scan for a day, a `.cleanup.lock` exclusive * lock keeps concurrent sessions from racing, a stale lock left by a crashed * process is broken, and lock ownership is rechecked before every destructive * step. Those two names are required, but the subagents sweep already owns them * inside the default sessions roots, so session-storage scans keep their * marker/lock pair in a coding-agent control root keyed by target instead of * writing into the scanned directory. The temp root, which nothing else owns, * carries its pair directly. * * Symlinks are never followed. A scan root or a `tool-results` entry that is a * symlink is skipped rather than read or deleted, because `readdirSync` and * `rmSync` resolve links and would otherwise reach outside the target. */ /** How long a tool-output tree survives without being touched. */ export declare const SESSION_TEMP_RETENTION_DAYS = 30; export declare const SESSION_TEMP_RETENTION_MS: number; /** Minimum interval between two sweeps of the same root. */ export declare const SESSION_TEMP_CLEANUP_INTERVAL_MS: number; /** A lock older than this belonged to a process that died holding it. */ export declare const SESSION_TEMP_CLEANUP_LOCK_STALE_MS: number; /** How long after startup the sweep runs, so it never sits on the startup path. */ export declare const SESSION_TEMP_CLEANUP_DELAY_MS = 10000; export declare const CLEANUP_MARKER_FILE = ".last-cleanup"; export declare const CLEANUP_LOCK_FILE = ".cleanup.lock"; /** * Control root for session-storage scans, inside the owner-scoped temp root. * A session id can never sanitize to this name (leading dots are stripped), so * it cannot collide with a session temp tree. */ export declare const CLEANUP_CONTROL_SUBDIR = ".cleanup"; export type SweepOutcome = "swept" | "throttled" | "locked" | "missing"; export interface SweepOptions { /** Clock override for tests. */ now?: number; /** Age past which an untouched entry is reaped. */ retentionMs?: number; /** Minimum interval between sweeps of this root. */ throttleMs?: number; /** Directories that must survive regardless of age. */ protectedPaths?: Iterable; /** Parent of the per-target control directories. Defaults to `/.cleanup`. */ controlRoot?: string; } /** Default parent for the marker/lock pair of a session-storage scan. */ export declare function getCleanupControlRoot(): string; /** * Control directory for one scan target: `/`. * Keyed by the target path so two roots never share throttle state. */ export declare function getCleanupControlDir(target: string, controlRoot?: string): string; interface FileIdentity { dev: bigint; ino: bigint; } interface CleanupLock extends FileIdentity { token: string; } /** * Take an exclusive lock so two sessions never scan the same target at once. * * `wx` creation is the exclusivity primitive. Returns an ownership token; a lock * left behind by a crashed process is broken once stale, and release only * removes a lock that still carries the caller's token. */ declare function acquireCleanupLock(lockPath: string, now: number, staleMs: number): CleanupLock | null; declare function releaseCleanupLock(lockPath: string, lock: CleanupLock): void; /** * Reap per-session temp trees under `/-/`. * * A tree is removed only when nothing at any depth inside it is newer than the * retention cutoff, and never when it belongs to a session this process * registered as live. A symlinked root is refused outright. */ export declare function sweepSessionTempRoot(root?: string, options?: SweepOptions): SweepOutcome; /** * Reap stale `tool-results` directories under one project-nested sessions root. * Only `//tool-results` is touched — never the sibling * `.jsonl` transcripts. */ export declare function sweepToolResultsRoot(sessionsRoot: string, options?: SweepOptions): SweepOutcome; /** * Reap `/tool-results` for a directly chosen session directory. * * A custom `--session-dir` has no project nesting: session files live in the * directory itself, so only its own `tool-results` child is in scope and its * siblings — including transcripts — are never touched. */ export declare function sweepSessionDirToolResults(sessionDir: string, options?: SweepOptions): SweepOutcome; export interface SessionTempCleanupOptions extends SweepOptions { /** Temp root override; defaults to the owner-scoped root. */ tempRoot?: string; /** Project-nested sessions roots; defaults to the configured agent session roots. */ sessionsRoots?: readonly string[]; /** Directly chosen session directories (custom `--session-dir` and friends). */ sessionDirs?: readonly string[]; } /** Run every sweep once. Each failure is swallowed: cleanup is housekeeping. */ export declare function runSessionTempCleanup(options?: SessionTempCleanupOptions): void; /** * Schedule one deferred sweep for the current pending batch. * * Calls made before or during a sweep merge their targets into sets. The active * callback drains one snapshot, remains marked active while it runs, then rearms * one new unref'd timer only when later roots arrived. */ export declare function scheduleSessionTempCleanup(options?: SessionTempCleanupOptions): void; /** Test seam: cancel pending work and forget scheduler state. */ export declare function resetSessionTempCleanupScheduleForTesting(): void; /** Narrow lock seam for descriptor-mode and release tests. */ export declare const sessionTempCleanupTestHooks: { acquireCleanupLock: typeof acquireCleanupLock; releaseCleanupLock: typeof releaseCleanupLock; }; export {}; //# sourceMappingURL=session-temp-cleanup.d.ts.map