import type Database from "better-sqlite3";
import type { TaskStoreDocument } from "../types.js";
import type { WishlistStoreDocument } from "../wishlist/wishlist-types.js";
type TableShape = "legacy-dual" | "task-only";
type PersistOptions = {
    expectedPlanningGeneration?: number;
    persistScope?: "full" | "incremental";
    dirtyTaskIds?: string[];
    newTransitionIds?: string[];
    newMutationIds?: string[];
};
/** Single-file SQLite backing for task JSON document; legacy rows may include wishlist_store_json until collapsed on store open. */
export declare class SqliteDualPlanningStore {
    private db;
    private _dbFileIdentity;
    private _reloadOnNextRead;
    readonly dbPath: string;
    private readonly _workspaceRoot;
    private _taskDoc;
    private _wishlistDoc;
    private _tableShape;
    /** When true, load/save tasks via task_engine_tasks + envelope log columns. */
    private _relationalTasks;
    /** Monotonic optimistic-lock counter for unified planning SQLite row (tasks + wishlist + logs). */
    private _planningGeneration;
    constructor(workspacePath: string, databaseRelativePath: string);
    get taskDocument(): TaskStoreDocument;
    get wishlistDocument(): WishlistStoreDocument;
    get tableShape(): TableShape;
    /** True when this DB uses relational task rows (not blob-only for task bodies). */
    get relationalTasksEnabled(): boolean;
    /** Current planning generation (SQLite `workspace_planning_state.planning_generation`). */
    getPlanningGeneration(): number;
    getDisplayPath(): string;
    /** Opened SQLite handle (creates file + migrations as needed). For read-only helpers (feature registry). */
    getDatabase(): Database.Database;
    /**
     * Close the SQLite handle if open. Use when another code path must reopen the same `dbPath`
     * in-process (avoids multi-handle races on the same file).
     */
    closeDatabase(): void;
    private closeReplacedDatabaseHandle;
    private currentDbFileIdentityChanged;
    private readPlanningGenFromOpenDb;
    private reloadIfCachedStateStale;
    private reloadBeforeReuseIfNeeded;
    private openDatabase;
    private ensureDb;
    private refreshPlanningGenFromOpenDb;
    private loadRelationalTasks;
    private parseLogs;
    private loadEvidenceLogs;
    /** Load documents from an existing database file; otherwise start empty (no file created). */
    loadFromDisk(): void;
    /** Replace in-memory documents (used by migrate). */
    seedFromDocuments(taskDoc: TaskStoreDocument, wishlistDoc: WishlistStoreDocument): void;
    /** Switch to relational persistence and flush current in-memory task document + wishlist (transactional). */
    enableRelationalPersistenceAndPersist(): void;
    private runPersistMutation;
    private persistRelational;
    private taskInsertStatement;
    /** Incremental path only — UPDATE-in-place avoids DELETE that trips depends_on RESTRICT FKs. */
    private taskUpsertStatement;
    private insertTaskRow;
    private insertTransitionEvidence;
    private insertMutationEvidence;
    private persistRelationalIncremental;
    private persistRelationalFull;
    private persistBlobOnly;
    persistSync(options?: PersistOptions): void;
    /**
     * Run synchronous work inside one SQLite transaction, then flush with planning generation bump.
     * Pass `expectedPlanningGeneration` when using optimistic concurrency (must match row before work runs).
     */
    withTransaction(work: () => void, options?: PersistOptions): void;
    /**
     * Drop legacy `wishlist_store_json` column by recreating the table (task JSON only).
     * Caller must persist an empty wishlist document first if migrating off legacy data.
     */
    migrateToTaskOnlyTableSchema(): void;
}
export {};
