import type { CachePolicy, CacheStoreAdapter, CandidateContext, ExecutionRecord, NormalizedPipeline, NormalizedTask, TaskResult, TaskSourceContext, TaskStep } from "../core/index.js"; import type { ExecutionGraphSnapshot } from "../core/graph.js"; export interface PipelineStore { root: string; asyncDir: string; runsDir: string; cacheDir: string; sourcesDir: string; } export interface TaskCacheKeyOptions { steps?: TaskStep[]; candidate?: CandidateContext; source?: TaskSourceContext; prepareCommands?: string[]; dependencyFingerprints?: Record; /** Run-scoped memo so overlapping inputs across tasks hash once per run. */ fileHashCache?: FileHashCache; } export interface ResolvedFileOptions { exclude?: readonly string[]; includeMissing?: boolean; pruneDefaultDirs?: boolean; /** When present, directory walks are memoized for the life of the cache. */ fileHashCache?: FileHashCache; } export interface FileHashCacheStats { digestHits: number; digestMisses: number; walkHits: number; walkMisses: number; } interface FileDigestEntry { size: bigint; mtimeNs: bigint; digest: string; } /** * Run-scoped memo for input hashing. Digest reuse is revalidated against a * fresh `stat` (size plus nanosecond mtime) on every lookup, so a file * rewritten by an earlier task in the same run re-hashes instead of reusing a * stale digest. Directory walks cannot be revalidated that cheaply, so the * runner calls `invalidateWalks()` whenever a task or source prepare * completes and may have written new files. The cache never outlives one * process run; nothing here is persisted. */ export interface FileHashCache { digests: Map>; walks: Map>; stats: FileHashCacheStats; invalidateWalks(): void; } export declare function createFileHashCache(): FileHashCache; export interface CacheOutputManifest { version: 1; generatedAt: string; outputs: string[]; files: CacheOutputFile[]; } export interface CacheOutputFile { path: string; size: number; sha256: string; } export interface CacheStoreAccess { adapter: CacheStoreAdapter; storeName: string; policy: CachePolicy; runId?: string; taskId?: string; } export declare function createStore(root: string): Promise; /** * Write-fsync-then-rename so readers never observe a truncated file, even if * the process or machine dies mid-write. rename(2) is atomic within a * filesystem, and the fsync keeps a crash from publishing an empty file. */ export declare function writeFileAtomic(path: string, data: string | Uint8Array): Promise; export declare function writeExecution(store: PipelineStore, record: ExecutionRecord): Promise; export declare function writeGraphSnapshot(store: PipelineStore, runId: string, snapshot: ExecutionGraphSnapshot): Promise; export declare function writeTaskLog(store: PipelineStore, runId: string, taskId: string, log: string): Promise; export declare function writeAgentPrompt(store: PipelineStore, runId: string, taskId: string, prompt: string): Promise; export declare function writeAgentTranscript(store: PipelineStore, runId: string, taskId: string, transcript: string): Promise; export declare function readCacheEntry(store: PipelineStore, cacheKey: string): Promise; export declare function readCacheEntryWithStore(store: PipelineStore, cacheKey: string, access: CacheStoreAccess): Promise; export declare function createFileCacheStoreAdapter(options?: { root?: string; }): CacheStoreAdapter; export declare function createMemoryCacheStoreAdapter(): CacheStoreAdapter; export interface RunLock { path: string; release(): Promise; } export declare function isPidAlive(pid: number): boolean; /** * One run at a time per `.async` store: concurrent runs would race on cache * entries, run records, and restored outputs. The lock file records the * holder pid; a lock whose holder is no longer alive is reclaimed. */ export declare function acquireRunLock(store: PipelineStore): Promise; /** * Remove task-cache entries whose last use is older than `maxAgeDays`. * Cache reads refresh mtime, so hot entries survive. `0` disables pruning. */ export declare function pruneCacheEntries(cwd: string, maxAgeDays: number): Promise; export declare function writeCacheEntry(store: PipelineStore, cacheKey: string, result: TaskResult, outputOptions?: { cwd: string; outputs: readonly string[]; }, access?: CacheStoreAccess): Promise; export declare function computeTaskCacheKey(pipeline: NormalizedPipeline, taskDefinition: NormalizedTask, cwd: string, options?: TaskCacheKeyOptions): Promise; export declare function writeCacheInputManifest(store: PipelineStore, cacheKey: string, manifest: TaskInputManifest, access?: CacheStoreAccess): Promise; export declare function readCacheInputManifest(store: PipelineStore, cacheKey: string, access?: CacheStoreAccess): Promise; export interface TaskBaseline { schemaVersion: 1; taskId: string; cacheKey: string; recordedAt: string; } /** Points at the task's most recent passing cache entry: the diff baseline. */ export declare function writeTaskBaseline(store: PipelineStore, taskId: string, cacheKey: string): Promise; export declare function readTaskBaseline(store: PipelineStore, taskId: string): Promise; export interface InputDiff { added: string[]; removed: string[]; changed: string[]; } export declare function diffInputManifests(baseline: TaskInputManifest, current: TaskInputManifest): InputDiff; export interface TaskContextPack { schemaVersion: 1; task: string; runId: string; status: "failed"; error: string; attempts: number; cacheKey?: string; reproduce: string; /** Redacted tail of the task log, capped well below the log cap. */ logTail: string; inputDiff: ({ baselineCacheKey: string; baselineRecordedAt: string; } & InputDiff) | { baselineMissing: true; }; /** Claim ids from tests/claims.json whose registered test titles appear in the task log. */ claims?: string[]; } export declare function writeContextPack(store: PipelineStore, runId: string, taskId: string, pack: TaskContextPack): Promise; export declare function readContextPacks(store: PipelineStore, runId: string): Promise; export type TaskCacheDecision = "hit" | "miss" | "disabled" | "bypassed" | "unknown"; export interface TaskCacheReceipt { schemaVersion: 1; task: string; runId: string; cacheEnabled: boolean; decision: TaskCacheDecision; dependencyFingerprints: Record; recordedAt: string; cacheKey?: string; store?: string; policy?: CachePolicy; graphNodeFingerprint?: string; reason?: string; restoredOutputs?: boolean; inputManifestRecorded?: boolean; } export declare function writeTaskCacheReceipt(store: PipelineStore, runId: string, taskId: string, receipt: TaskCacheReceipt): Promise; export declare function readTaskCacheReceipts(store: PipelineStore, runId: string): Promise; export interface TaskInputManifest { schemaVersion: 1; /** Relative input path -> `sha256:` content digest, or `[missing]`. */ files: Record; } export interface TaskCacheKeyDetails { cacheKey: string; inputs: TaskInputManifest; } /** * The cache key plus the per-file digest manifest computed in the same input * walk. The key folds each input's own content digest into the rolling hash * (Merkle-style), so the key stays content-addressed while a run-scoped * `FileHashCache` lets overlapping inputs across tasks hash once per run. * Capturing per-file digests here is what makes "which inputs changed since * this task last passed" answerable later without re-hashing against a * baseline that no longer exists (ADR-0003). */ export declare function computeTaskCacheKeyDetailed(pipeline: NormalizedPipeline, taskDefinition: NormalizedTask, cwd: string, options?: TaskCacheKeyOptions): Promise; /** * The digest manifest for a task's current input state, without computing a * cache key: no step resolution, no deferred callbacks — file reads only. * Powers `explain --diff-inputs`. */ export declare function computeTaskInputManifest(pipeline: NormalizedPipeline, taskDefinition: NormalizedTask, cwd: string, fileHashCache?: FileHashCache): Promise; export declare function computeCandidateContext(pipeline: NormalizedPipeline, cwd: string, fileHashCache?: FileHashCache): Promise; export declare function resolveInputFiles(cwd: string, inputs: readonly string[]): Promise; export declare function resolveInputFiles(cwd: string, inputs: readonly string[], options: ResolvedFileOptions): Promise; export declare function resolveOutputFiles(cwd: string, outputs: readonly string[]): Promise; export declare function restoreCacheOutputs(store: PipelineStore, cacheKey: string, cwd: string, outputs: readonly string[], access?: CacheStoreAccess): Promise; export declare function outputFilesExist(cwd: string, files: readonly string[]): Promise; export {}; //# sourceMappingURL=store.d.ts.map