/** * SQLite-based implementation of the DataAccessor interface. * * Materializes TaskFile/ArchiveFile/SessionsFile from SQLite tables, * allowing core modules to continue using whole-file data structures * while storage is backed by the relational database. * * Uses existing sqlite.ts engine (node:sqlite / drizzle-orm) and * tasks-sqlite.ts / session-store.ts for row-level operations. * * @epic T4454 */ import type { DatabaseSync, SQLInputValue } from 'node:sqlite'; import { type WorktreeScope } from '../project-scope.js'; import type { DataAccessor, TaskClaimGuard, TransactionAccessor } from './data-accessor.js'; /** Write metadata through the same ownership queue as task mutations. */ export declare function setMetaValue(cwd: string | undefined, key: string, value: unknown): Promise; /** * Advance the task-id sequence (`tasks_schema_meta`, key `task_id_sequence`) * on the caller's native handle and read the new counter back. * * Synchronous on purpose: `allocateNextTaskId` calls it inside its own * SAVEPOINT, together with the stored-id inventory that supplies `floor`, so * no other caller can rewind the counter between the two statements. * * @param nativeDb - The project `cleo.db` native handle holding the savepoint. * @param floor - Lower bound for the counter (the highest stored numeric id). * @returns The advanced counter, or `undefined` when the sequence row is missing. * @task T12535 */ export declare function advanceTaskIdSequence(nativeDb: DatabaseSync, floor: number): number | undefined; /** A local column that holds a task's display id (from store/display-id-alias.ts). */ export interface TaskReferenceColumn { readonly table: string; readonly column: string; readonly jsonArray: boolean; } /** * Give the task with `uid` the display id `toId`: a compare-and-set on the * stored version AND claim lease that advances the version (so a stale * `--if-match` writer fails, #1698), with the claim columns carried unchanged * (#1701), then every local reference rewritten. Runs in the caller's * transaction with foreign keys deferred to its commit. * * A collision re-mint is a system write: it passes no claim guard and never * takes or drops a lease, but the version bump makes the lease holder's next * guarded write re-read. A caller acting for a session (a manual rename) * passes `guard`: `expectedUpdatedAt` fails with `E_CONFLICT` when the task * moved on, `claim` fails with `E_TASK_CLAIMED` when another session holds it. * * @param nativeDb - The project `cleo.db` handle holding the transaction. * @param uid - Uid of the task to rename. * @param toId - Its new display id. * @param refs - Columns that hold task display ids. * @param guard - Optional version / claim guard. * @returns The id it had and the rows rewritten per `table.column`. * @task T12341 * @task T12748 */ export declare function renameTaskDisplayIdNative(nativeDb: DatabaseSync, uid: string, toId: string, refs: readonly TaskReferenceColumn[], guard?: { readonly expectedUpdatedAt?: string; readonly claim?: TaskClaimGuard; }): { fromId: string; rewritten: Record; }; /** * Rewrite every reference to the task id `fromId` as `toId`: plain columns, * and JSON arrays of ids (`jsonArray` refs, e.g. a session's * `tasks_completed_json`), element by element. * * @param nativeDb - The database holding the columns. * @param refs - Columns that hold task ids (see `taskReferenceColumns`). * @param fromId - The id being replaced. * @param toId - Its replacement. * @returns Rows rewritten per `table.column` (only columns that changed). * @task T12341 * @task T13172 - shared with the reconcile's legacy-task renumbering */ export declare function rewriteTaskIdReferencesNative(nativeDb: DatabaseSync, refs: readonly TaskReferenceColumn[], fromId: string, toId: string): Record; /** Table names {@link rederiveAcIdsNative} works on: the consolidated store's by default. */ export interface AcTableNames { /** The acceptance-criteria table. */ readonly criteria: string; /** Tables whose `ac_id` follows a criterion's id. */ readonly followers: readonly string[]; } /** * After a task's display id changed from `fromId` to `toId`, re-derive the * ids of the acceptance criteria derived from it (`buildAcRowId(taskId, * identity)`): the task's own criteria, and a parent's child-projection * criteria (`child:`, whose source key is rewritten too). The binding and * history rows that point at a re-derived id follow. A criterion whose id was * not derived from the old id (an explicit id) keeps it. Without this, two * tasks that once shared a display id keep identical ids for same-text * criteria ("tests pass") and collide on every merge (T12799). * * @param nativeDb - The project `cleo.db` handle, inside the rename's transaction. * @param fromId - The task's old display id. * @param toId - Its new display id (the task row already carries it). * @param tables - The criteria and follower tables; a legacy `tasks.db` copy * passes its unprefixed names (T13172). * @returns Rows rewritten per `table.column`. * @task T12799 */ export declare function rederiveAcIdsNative(nativeDb: DatabaseSync, fromId: string, toId: string, tables?: AcTableNames): Record; /** One row of `tasks_display_id_aliases`. */ export interface DisplayIdAliasRow { readonly uid: string; readonly entityTable: string; readonly displayId: string; readonly entityUid: string; readonly reason: string; readonly origin: string | null; readonly displacedHlc: string | null; readonly createdAt: string; /** Birth fingerprint of the entity, so a uid collision cannot confuse two rows. */ readonly entityBirthFp: string | null; } /** * Insert a display-id alias row. Idempotent on its uid, and order-independent * (T12800): when two displacements write one alias uid, the stored row is * replaced only when `precedes(incoming, stored)` says the incoming one ranks * first, so every replica keeps the same row whatever order the ops arrived * in. The caller ranks by HLC order (`compareHlc`), never by text: stored * values may be in either HLC format (T12802). * * @param nativeDb - The project `cleo.db` handle. * @param row - The alias. * @param precedes - Whether `incoming` ranks before the `stored` row of the same uid. * @task T12341 */ export declare function insertDisplayIdAliasNative(nativeDb: DatabaseSync, row: DisplayIdAliasRow, precedes: (incoming: DisplayIdAliasRow, stored: DisplayIdAliasRow) => boolean): void; /** * Delete one display-id alias row (a local alias whose entity was re-keyed is * re-inserted under its new entity uid by the caller). * * @param nativeDb - The project `cleo.db` handle. * @param uid - The alias row's uid. * @task T12341 */ export declare function deleteDisplayIdAliasNative(nativeDb: DatabaseSync, uid: string): void; /** One row of `tasks_uid_aliases`. */ export interface UidAliasRow { readonly uid: string; readonly entityTable: string; readonly oldUid: string; readonly oldBirthFp: string; readonly newUid: string; readonly origin: string | null; readonly displacedHlc: string | null; readonly createdAt: string; } /** * Insert a uid re-key alias row (idempotent on its uid). * * @param nativeDb - The project `cleo.db` handle. * @param row - The alias. * @task T12341 */ export declare function insertUidAliasNative(nativeDb: DatabaseSync, row: UidAliasRow): void; /** One row of `tasks_identity_quarantine`. */ export interface QuarantineRow { readonly entityTable: string; readonly uid: string; readonly birthFp: string; readonly reason: 'uid-collision' | 'display-id-collision' | 'key-collision' | 'ref-pending' | 'invalid' | 'unsupported-wire'; readonly contestedId: string | null; readonly rowJson: string; readonly receivedHlc: string | null; readonly createdAt: string; } /** * Hold an incoming row the merge cannot place yet (replacing an older hold of * the same row). * * @param nativeDb - The project `cleo.db` handle. * @param row - The held row. * @task T12341 */ export declare function insertQuarantineNative(nativeDb: DatabaseSync, row: QuarantineRow): void; /** * Drop a held row (released or superseded). * * @param nativeDb - The project `cleo.db` handle. * @param key - The held row's table, uid and birth fingerprint. * @task T12341 */ export declare function deleteQuarantineNative(nativeDb: DatabaseSync, key: { readonly entityTable: string; readonly uid: string; readonly birthFp: string; }): void; /** * Write a row-identity meta value (the recipe marker, a re-mint record). * * @param nativeDb - The project `cleo.db` handle. * @param key - Meta key. * @param value - Meta value. * @task T12341 */ export declare function writeRowIdentityMetaNative(nativeDb: DatabaseSync, key: string, value: string): void; /** * Hand a criterion back the uid its deleted predecessor carried (AC uid * graveyard re-link, spec §6.5), with that predecessor's birth fingerprint. * * @param nativeDb - The project `cleo.db` handle. * @param acId - The criterion to re-link (its uid is NULL). * @param uid - The uid to hand back. * @param birthFp - The fingerprint that goes with it, when recorded. * @returns Rows changed (0 or 1). * @task T12341 */ export declare function relinkAcUidNative(nativeDb: DatabaseSync, acId: string, uid: string, birthFp: string | null): number; /** * Empty the AC uid graveyard (after the open pass consumed it). * * @param nativeDb - The project `cleo.db` handle. * @task T12341 */ export declare function clearAcUidGraveyardNative(nativeDb: DatabaseSync): void; /** The birth of a stored task, read before an overwrite replaces the row (T12806). */ export interface ReplacedTaskBirth { /** Its `created_at` before the overwrite. */ readonly createdAt: string | null; /** Its uid before the overwrite. */ readonly uid: string | null; } /** * Read the birth of task `taskId` before an overwrite replaces it. * * @param nativeDb - The project `cleo.db` handle. * @param taskId - The task about to be overwritten. * @returns Its birth, or `undefined` when there is no such row. * @task T12806 */ export declare function readReplacedTaskBirthNative(nativeDb: DatabaseSync, taskId: string): ReplacedTaskBirth | undefined; /** * After an overwrite import replaced task `taskId`, keep or re-key its * identity (T12806 review): * * - the SAME task (same id, same birth instant as before the overwrite) keeps * its identity. Sameness is decided on the immutable birth facts, never on * the title or type: a task retitled here and re-imported unchanged stays * the same row; * - refused once identity is shared: the overwrite would re-point a uid other * devices hold at different work; * - otherwise the task, the natural rows keyed by it (dependencies, * relations, labels) and its criteria are re-derived from the new row, now, * and every AC history row and binding that pointed at one of those * criteria is RE-KEYED to the criterion's new uid, found by the criterion's * old uid as well as by its current id. A binding whose `ac_id` is stale * (#1731) keeps resolving: its evidence is kept, never dropped. * * @param nativeDb - The project `cleo.db` handle holding the transaction. * @param taskId - The overwritten task. * @param before - Its birth before the overwrite ({@link readReplacedTaskBirthNative}). * @task T12806 */ export declare function clearReplacedTaskIdentityNative(nativeDb: DatabaseSync, taskId: string, before?: ReplacedTaskBirth): void; /** * Fill a NULL identity column (`uid`, `birth_fp`, a stored reference uid) of a * declared table from its recipe SQL (the row-uid open pass, spec §6.1). * * @param nativeDb - The `cleo.db` handle holding the cold-open lease. * @param table - Declared table. * @param column - Identity column. * @param valueSql - Recipe expression over `main.""` columns. * @param rowid - One row only (the clash fallback); all NULL rows otherwise. * @returns Rows written. * @task T12341 */ export declare function fillIdentityColumnNative(nativeDb: DatabaseSync, table: string, column: string, valueSql: string, rowid?: number): number; /** * Clear one pre-release birth fingerprint so the fill re-derives it (spec §12.1). * * @param nativeDb - The `cleo.db` handle holding the cold-open lease. * @param table - Declared minted table. * @param rowid - The row. * @task T12341 */ export declare function clearBirthFpNative(nativeDb: DatabaseSync, table: string, rowid: number): void; /** * Set the given identity columns of every row of a declared identity table to * NULL: the clearing step of a full from-scratch refill on a provably unshared * store (T13231). The fill re-derives every value right after. * * @param nativeDb - The project `cleo.db` handle. * @param table - Declared identity table. * @param columns - Its identity columns present in the store. * @task T13231 */ export declare function clearIdentityColumnsNative(nativeDb: DatabaseSync, table: string, columns: readonly string[]): void; /** * Insert one row into a declared identity table, with the columns the row * carries that the table has (a row released from the identity quarantine). * * @param nativeDb - The project `cleo.db` handle. * @param table - Declared table. * @param row - Column → value. * @task T12341 */ export declare function insertIdentityRowNative(nativeDb: DatabaseSync, table: string, row: Readonly>): void; /** * Give the row of `table` identified by (`oldUid`, `birthFp`) the uid * `newUid` (a uid re-key; the birth fingerprint never changes). * * @param nativeDb - The project `cleo.db` handle. * @param table - Declared minted table. * @param oldUid - The colliding uid. * @param birthFp - The row's birth fingerprint. * @param newUid - Its new uid. * @returns Rows changed (0 or 1). * @task T12341 */ export declare function setRowUidNative(nativeDb: DatabaseSync, table: string, oldUid: string, birthFp: string, newUid: string): number; /** * Rename the counter display key (`D####`, `SN-###`) of one brain row and * point the rows that reference it by key at the new key (T13405): a * decision's `supersedes` / `superseded_by`, a sticky note's tags. The * caller defers foreign keys for the transaction. * * @param nativeDb - The store handle (project or global). * @param table - `brain_decisions` or `brain_sticky_notes`. * @param uid - The row's uid. * @param fromId - Its current key. * @param toId - The new key. * @returns Rows changed per `table.column`. * @sync-side-effect identity.local-minting the re-mint of a colliding counter key renames its local references (T13405) * @task T13405 */ export declare function renameBrainDisplayKeyNative(nativeDb: DatabaseSync, table: 'brain_decisions' | 'brain_sticky_notes', uid: string, fromId: string, toId: string): Record; /** * Point every `decision:` reference at `decision:` (T13405): * the decision's page node (minted, so its uid stays), the page edges that * name it (natural on the raw ids, so each is re-inserted under its new key * and the old row deleted), and the `decision:` evidence atoms in task * verification payloads. An atom only matches as a whole token, so `D5` * never rewrites `D50`. * * With `onlyOrigin`, only the edges and atoms that replica wrote are touched * (T13433, T13456): every replica, the re-minting origin included, re-points * only its own text, since an atom another replica wrote names whatever that * writer had placed under the old key. The writer is the referencing column's * field HLC replica in the sync row meta; a row with no meta is local text. * * @param nativeDb - The store handle (project or global). * @param fromId - The decision's old key. * @param toId - Its new key. * @param onlyOrigin - Limit edges and atoms to those this replica wrote. * @param renameNode - Rename the decision's page node (default: when unlimited). * @returns Rows changed per `table.column`. * @sync-side-effect identity.local-minting the re-mint of a colliding counter key renames its local references (T13405) * @task T13405 */ export declare function repointDecisionReferencesNative(nativeDb: DatabaseSync, fromId: string, toId: string, onlyOrigin?: string, renameNode?: boolean): Record; /** * Point a stored reference uid column (`ac_uid`) of the rows that reference * the re-keyed row by key at its new uid. Scoped by the key column, so a row * referencing the OTHER holder of a colliding uid is never touched. * * @param nativeDb - The project `cleo.db` handle. * @param table - Table holding the column. * @param column - The stored reference uid column. * @param fromColumn - The column that references the row by key (`ac_id`). * @param key - The re-keyed row's local key. * @param oldUid - Old referenced uid. * @param newUid - New referenced uid. * @returns Rows changed. * @task T12341 */ export declare function rewriteStoredRefUidNative(nativeDb: DatabaseSync, table: string, column: string, fromColumn: string, key: string, oldUid: string, newUid: string): number; /** * Clear one row's uid so the natural recipe re-derives it (a uid re-key * changed an endpoint's uid). * * @param nativeDb - The project `cleo.db` handle. * @param table - Declared natural table. * @param rowid - The row. * @task T12341 */ export declare function clearRowUidNative(nativeDb: DatabaseSync, table: string, rowid: number): void; /** * Delete a row-identity meta value (a re-mint record that moved with a re-key). * * @param nativeDb - The project `cleo.db` handle. * @param key - Meta key. * @task T12341 */ export declare function deleteRowIdentityMetaNative(nativeDb: DatabaseSync, key: string): void; /** * Set a natural row's uid by its current uid (a re-key re-derives the natural * uids keyed by the re-keyed row; a receiver applies the published values). * * @param nativeDb - The project `cleo.db` handle. * @param table - Declared natural table. * @param oldUid - Current uid. * @param newUid - New uid. * @returns Rows changed. * @task T12341 */ export declare function setNaturalUidNative(nativeDb: DatabaseSync, table: string, oldUid: string, newUid: string): number; /** * Rewrite a held row (identity quarantine) under a new uid: a uid re-key of a * row this replica holds but has not placed. * * @param nativeDb - The project `cleo.db` handle. * @param key - The held row's table, uid and birth fingerprint. * @param newUid - Its new uid. * @param rowJson - Its wire form with the new uid. * @task T12341 */ export declare function rekeyQuarantineNative(nativeDb: DatabaseSync, key: { readonly entityTable: string; readonly uid: string; readonly birthFp: string; }, newUid: string, rowJson: string): void; /** * Add labels to a task's label junction (idempotent), for writers that * insert a task with raw SQL (the sentient proposal ticks). * * @param nativeDb - The project `cleo.db` handle. * @param taskId - The task. * @param labels - Labels to add. * @task T12341 */ export declare function addTaskLabelsNative(nativeDb: DatabaseSync, taskId: string, labels: readonly string[]): void; /** * Serialize work with the foreground writers and committed effects of one * native handle, without opening a SQL transaction: `work` starts once every * earlier queued transaction or effect on `native` has finished, and later * ones wait for it. The change journal's apply frame (T12344, spec §3.2 step * 2) runs through this so a remote apply never interleaves with a local * accessor transaction on the same handle. * * @param native - The shared native handle. * @param work - The work; it opens its own transaction if it needs one. * @returns What `work` returned. * @example * ```ts * await scheduleTaskBackground(native, async () => applyFrame()); * ``` */ export declare function scheduleTaskBackground(native: DatabaseSync, work: () => Promise): Promise; /** * Compatible task-accessor name for the shared project ownership capture policy. * @remarks This is the same function as `captureProjectScope`; identity validation * and routing policy live in the dependency-leaf project scope module. * @example * ```ts * const scope = captureTaskAccessorScope(getProjectRoot(), worktreeScope.getStore()); * ``` */ export { captureProjectScope as captureTaskAccessorScope } from '../project-scope.js'; /** How long after a local rename a write to the old id is still read as meant for the renamed task. */ export declare const RENAMED_RECENT_MS: number; /** * Bind all asynchronous accessor methods, including transaction ports, to one project. * @typeParam T - Concrete accessor contract retained by the scoped wrapper. * @param accessor - Canonical, safety-wrapped, or transaction accessor to bind. * @param scope - Immutable project scope captured at construction. * @returns An accessor preserving method arguments, results and receiver semantics. * @remarks The wrapper changes only worktree path scope. The existing transaction * AsyncLocalStorage, savepoint queues and postcommit result semantics remain authoritative. * A newly inherited execution cannot bypass a captured operation's cancellation or ownership. * @example * ```ts * const bound = bindTaskAccessorScope(accessor, scope); * await bound.upsertSingleTask(task); * ``` */ export declare function bindTaskAccessorScope(accessor: T, scope: WorktreeScope): T; /** * Create a SQLite-backed DataAccessor. * * Opens (or creates) the consolidated SQLite database at `.cleo/cleo.db` and returns * a DataAccessor that materializes/dematerializes whole-file structures * from the relational tables. * * @param cwd - Explicit project root, or canonical root captured before initialization. * @returns An accessor whose methods and transaction ports retain captured ownership. * @remarks Later ambient scope changes cannot redirect this accessor's I/O. Active * execution ownership is checked against persisted identity before method entry. * @example * ```ts * const accessor = await createSqliteDataAccessor('/projects/example'); * const task = await accessor.loadSingleTask('T001'); * ``` */ export declare function createSqliteDataAccessor(cwd?: string): Promise; //# sourceMappingURL=sqlite-data-accessor.d.ts.map