import type { TextWithCursors } from "reconcile-text"; import type { RelativePath } from "../persistence/database"; import type { FileSnapshot } from "../snapshot"; /** Filesystem operations act on the current user-owned namespace. * Paths are vault-relative. Never follow symlinks (including ancestor symlinks). * Only independent regular files are supported; reject hardlinks/special files. * A successful scan is complete: unreadable directories must reject, not vanish. */ export interface FileSystemOperations { listFilesRecursively: (root?: RelativePath) => Promise; /** Return undefined on missing file */ read: (path: RelativePath) => Promise; /** Reject symlinks and special files rather than following them and return undefined. */ stat: ( path: RelativePath ) => Promise<{ kind: "file" | "directory"; size: number } | undefined>; /** Includes directories. */ exists: (path: RelativePath) => Promise; /** Recursive, idempotent directory creation. */ createDirectory: (path: RelativePath) => Promise; /** Create or overwrite a file, applying optional editor cursor metadata. */ write: (path: RelativePath, snapshot: FileSnapshot) => Promise; // Atomically update the content of a text file. atomicUpdateText: ( path: RelativePath, updater: (current: TextWithCursors) => TextWithCursors ) => Promise; /** Move a file without replacing an existing destination. */ rename: (from: RelativePath, to: RelativePath) => Promise; /** Idempotently unlink one regular file. */ deleteFile: (path: RelativePath) => Promise; /** Prune directories using rmdir only. Reject files and nonempty directories. */ deleteDirectory: (path: RelativePath) => Promise; }