/** * Backup Restore Service (P1) * * Restores a workspace archive (produced by BackupArchiveService) onto this * machine to resume work after a machine dies / is replaced. * * Safety model: * - `preview()` is non-destructive (dry-run) — reports the plan + conflicts. * - `restore()` snapshots the CURRENT CREWLY_HOME first (rollback), refuses * on overlapping ids unless mode='overwrite', then applies and — on any * failure — rolls back from the snapshot. * - device.json is NEVER in the archive, so the target keeps its own identity. * - cron `nextRunAt` is reset to null so the scheduler recomputes from * `cronExpression` (no stale fires); runtime/session state is wiped so * agents start clean. * * See specs/2026-06-07-workspace-backup.md. * * @module services/backup/backup-restore.service */ import { type ComponentLogger } from '../core/logger.service.js'; import { type RestoreOptions, type RestorePlan, type RestoreResult } from './backup.types.js'; /** Thrown by restore() when mode='abort' and the target has overlapping data. */ export declare class RestoreConflictError extends Error { readonly plan: RestorePlan; constructor(message: string, plan: RestorePlan); } /** * Service that restores workspace backup archives. */ export declare class BackupRestoreService { private readonly logger; constructor(logger?: ComponentLogger); /** * Non-destructive restore plan (dry-run): what would be created/overwritten, * id conflicts, resolved project paths, and what's regenerated/discarded. * * @param options - Restore options (mode/pathMap affect conflict + path resolution) * @returns The plan; never writes to disk */ preview(options: RestoreOptions): Promise; /** * Restore the archive onto this machine. * * @param options - Restore options * @returns Summary of what was restored * @throws RestoreConflictError when mode='abort' and ids overlap * @throws Error on integrity failure or unsupported schema (no changes applied) */ restore(options: RestoreOptions): Promise; /** Extract the archive to a fresh temp dir; returns its path. */ private extract; /** Read + minimally validate the manifest from an extracted archive. */ private readManifest; /** Verify every recorded file's sha256 against the extracted bytes. */ private verifyChecksums; /** Build the dry-run plan (conflicts, resolved project paths, warnings). */ private buildPlan; /** * Copy every manifest global file from temp/home/* into CREWLY_HOME. * * @param skipSlack - Leave `slack-credentials.json` out (item 29) */ private applyGlobals; /** * Copy each resolved project's `.crewly/` — and its source files when the * archive carries them — from the archive to its target path. * * @returns Number of projects touched and number of source files written */ private applyProjects; /** Copy one archive-relative file out of the extracted temp dir, creating parents. */ private copyArchiveFile; /** True when `dir` contains any entry other than `ignore`. */ private dirHasContentBesides; /** Atomically swap chat.db into place (temp copy → rename). */ private applyChatDb; /** Rewrite projects.json `path` entries using the resolved plan mapping. */ private rewriteProjectsJson; /** Reset cron `nextRunAt` so the scheduler recomputes from cronExpression. */ private resetCron; /** Remove runtime/session state so agents start clean on the restored machine. */ private wipeRuntime; /** Recursively copy a directory tree, skipping top-level names in `skipTop`. */ private copyTree; /** Recursive copy without the top-level skip filter. */ private copyTreeRec; private pathExists; private readJson; } //# sourceMappingURL=backup-restore.service.d.ts.map