import type { ClaimsStreamAppendEvent, GoalStreamAppendEvent, ReceiptStreamEvent, TodosStreamAppendEvent } from "./events.js"; export declare const LOCK_HOLDER_FILE = "holder.json"; export interface LockHolderInfo { readonly pid: number; readonly acquiredAt: number; } export interface GoalsFileLockOptions { /** Holder mtime age after which a lock is considered stale (default 60s). */ readonly staleAfterMs?: number; } export declare const DEFAULT_LOCK_STALE_AFTER_MS = 60000; export type GoalsLockAcquireResult = { ok: true; lock: GoalsFileLock; } | { ok: false; code: "blocked_with_holder" | "lock_error"; message: string; holder?: LockHolderInfo; }; /** Single-writer lock over the goals store (one lock covers all streams). */ export declare class GoalsFileLock { private readonly lockPath; readonly holder: LockHolderInfo; private heldState; private constructor(); get path(): string; get isHeld(): boolean; release(): void; static acquire(lockPath: string, options?: GoalsFileLockOptions): GoalsLockAcquireResult; } /** Acquire → run → always release. The fn result is propagated on success. */ export declare function withGoalsLock(lockPath: string, fn: (lock: GoalsFileLock) => T, options?: GoalsFileLockOptions): { ok: true; result: T; } | Extract; export interface GoalStorePaths { readonly dir: string; readonly goalLog: string; readonly todosLog: string; readonly claimsLog: string; readonly snapshot: string; readonly snapshotMarker: string; } /** goals//{goal,todos,claims}.log.jsonl + snapshot files. goalId is validated (no traversal). */ export declare function goalStorePaths(stateDir: string, goalId: string): GoalStorePaths; /** Global CAS receipts stream (append-only, idempotent, never compacted). */ export declare function casReceiptsPath(stateDir: string): string; export declare const DEFAULT_MAX_STREAM_BYTES: number; export interface StreamReadOptions { readonly maxStreamBytes?: number; } export type StreamTextResult = { ok: true; text: string; } | { ok: false; code: "stream_too_large" | "read_error"; message: string; size?: number; }; /** Read a whole stream with a byte cap; missing files read as empty text. */ export declare function readStreamText(filePath: string, options?: StreamReadOptions): StreamTextResult; /** Atomic whole-file replace: tmp file + fsync + rename + directory fsync. */ export declare function writeFileAtomic(filePath: string, contents: string): void; /** Durably append ONE complete JSONL line: single O_APPEND write + fsync. */ export declare function appendJsonLine(filePath: string, line: string): void; export interface StoreWriteOptions extends StreamReadOptions { /** Compaction threshold: appends past the last snapshot before compaction. */ readonly compactionThreshold?: number; /** "off" disables compaction bookkeeping (tests, explicit compaction). */ readonly compaction?: "on" | "off"; /** Optional caller view of the current head; mismatch → stale write error. */ readonly expectedRevision?: number; } export interface AppendRevisionOutcome { readonly revision: number; } export type AppendReceiptOutcome = { status: "appended"; } | { status: "replayed"; }; /** Append a runtime goal event; enforces revision = head + 1 write-side. */ export declare function appendGoalEvent(lock: GoalsFileLock, stateDir: string, goalId: string, event: GoalStreamAppendEvent, options?: StoreWriteOptions): AppendRevisionOutcome; /** Append a todo graph event; enforces graph revision = head + 1 write-side. */ export declare function appendTodoGraphEvent(lock: GoalsFileLock, stateDir: string, goalId: string, event: TodosStreamAppendEvent, options?: StoreWriteOptions): AppendRevisionOutcome; /** Append a claims/delegation side-table event (append-only, no revision gate). */ export declare function appendClaimEvent(lock: GoalsFileLock, stateDir: string, goalId: string, event: ClaimsStreamAppendEvent, options?: StoreWriteOptions): void; /** * Append a global CAS receipt. Exact duplicates are idempotent (nothing is * written, status "replayed"); a mutationId bound to a different request * hash throws; appending never happens onto an unreadable/poisoned stream. */ export declare function appendReceipt(lock: GoalsFileLock, stateDir: string, event: ReceiptStreamEvent, options?: StoreWriteOptions): AppendReceiptOutcome; /** Exposed for restore/quarantine flows: does the file exist right now? */ export declare function fileExists(filePath: string): boolean;