/** * Detect project stores stranded inside CLEO worktrees (T12460). * * ## The failure this reports * * Before T12460, a `cleo` command run inside an orchestrate worktree * (`/worktrees///`) resolved the WORKTREE's own * `.cleo/` as the project directory: the nearest-`.cleo` walk (and the * `CLEO_WORKTREE_ROOT` scope) won before the gitlink step. The worktree store * opened empty, `autoRecoverFromBackup` copied the parent project's newest * snapshot into it (~1.25 GB on this repo), and `createSafetyBackup` added a * same-size `.bak` beside it. Every later write from that worktree landed in the * copy. Nothing merges it back, and worktree prune deletes or quarantines it. * * Path resolution now maps a worktree to its parent project's store, so no new * copies are created. Copies made before the fix are still on disk and may hold * the only record of writes made from inside the worktree. This scan finds them * and reports, per table, whether a copy holds rows the parent does not. * * ## Read-only contract * * Nothing is deleted, moved, or written. Every SQLite file is opened with * `readOnly: true`. To import rows a copy holds that the parent lacks, use * `cleo doctor split-brain --source ` after reviewing this report. * * @task T12460 * @see ADR-055 — worktree-by-default */ /** Per-table comparison of a stranded copy against the parent store. */ export interface WorktreeStoreTableDiff { /** Table name, e.g. `tasks_tasks`. */ readonly table: string; /** Rows in the stranded copy. */ readonly rowsInCopy: number; /** Rows of the copy whose primary key is ABSENT from the parent table. */ readonly missingInParent: number; /** * Rows present in both whose timestamp in the copy is later than the parent's * timestamp for the SAME key: updates made in the worktree that the parent's * version of the row does not reflect. */ readonly newerThanParent: number; /** Newest timestamp in the copy's column, or `null` when the table is empty. */ readonly newestInCopy: string | null; /** Newest timestamp in the parent's column, or `null` when the table is empty. */ readonly newestInParent: string | null; } /** One database-like file found under a worktree's `.cleo/`. */ export interface WorktreeStoreFile { /** Absolute path of the file. */ readonly path: string; /** Bare file name, e.g. `cleo.db` or `cleo-pre-cleo.db.bak`. */ readonly name: string; /** Size in bytes. */ readonly sizeBytes: number; /** Last modification time, ISO 8601. */ readonly modifiedAt: string; /** Whether the file carries the SQLite 3 header. */ readonly isSqlite: boolean; /** * `true` when at least one compared table holds a row the parent lacks by * key, or one newer than the parent's newest; `false` when every compared * table is covered by the parent; `null` when no comparison was possible. */ readonly hasRowsNewerThanParent: boolean | null; /** Per-table comparison; empty when no comparison was possible. */ readonly tables: readonly WorktreeStoreTableDiff[]; /** Why the comparison was skipped or failed, when it was. */ readonly note?: string; } /** One worktree whose `.cleo/` holds at least one store file. */ export interface WorktreeStoreEntry { /** Absolute worktree path. */ readonly worktreePath: string; /** Whether git still lists the worktree (`git worktree list`). */ readonly registeredWithGit: boolean; /** Store files found directly under `/.cleo/`. */ readonly files: readonly WorktreeStoreFile[]; } /** Result of {@link scanWorktreeStores}. */ export interface WorktreeStoreScanResult { /** Absolute parent project root that was scanned. */ readonly projectRoot: string; /** Absolute path of the parent project's store. */ readonly parentStorePath: string; /** Whether the parent store exists; comparisons are skipped when it does not. */ readonly parentStoreExists: boolean; /** Canonical worktree directory for this project (`/worktrees/`). */ readonly worktreeBase: string; /** Number of worktree directories inspected. */ readonly worktreesScanned: number; /** Worktrees holding store files, sorted by path. */ readonly entries: readonly WorktreeStoreEntry[]; /** Total store files found across all worktrees. */ readonly strandedFileCount: number; /** Total bytes those files occupy. */ readonly strandedBytes: number; /** Paths of files that hold rows the parent store does not. */ readonly filesWithNewerRows: readonly string[]; } /** Options for {@link scanWorktreeStores}. */ export interface WorktreeStoreScanOptions { /** Override the canonical worktree base (tests). */ readonly worktreeBase?: string; /** Skip row comparisons; list files only. Default `false`. */ readonly skipCompare?: boolean; } /** * Find project stores stranded inside the worktrees of `projectRoot`. * * Worktrees are discovered from both `git worktree list` and the canonical * worktree base, so a worktree git no longer tracks is still inspected. For * each, every database-like file directly under `/.cleo/` is listed; * SQLite files are compared against the parent's `.cleo/cleo.db` table by table. * * @param projectRoot - Parent project root (the main checkout). * @param options - Optional worktree-base override and compare switch. * @returns The scan result. Never throws for a missing directory or unreadable file. * @remarks Strictly read-only: nothing is created, moved, or deleted. * @example * ```ts * const result = scanWorktreeStores('/home/u/project'); * for (const path of result.filesWithNewerRows) console.log(path); * ``` * @task T12460 */ export declare function scanWorktreeStores(projectRoot: string, options?: WorktreeStoreScanOptions): WorktreeStoreScanResult; //# sourceMappingURL=worktree-stores.d.ts.map