/** * daemon-config-migration-io.ts, disk primitives and disclosure shapes for the * one-time move of daemon-owned keys into the daemon's own config store. * * Split from daemon-config-migration.ts so the migration policy (what wins, * what is disclosed) stays readable and both halves stay under the line cap. */ /** File name of the disclosure marker written beside the daemon config store. */ export declare const DAEMON_CONFIG_MOVED_FILE = "config-moved.json"; /** Marker schema version. A marker at any other version is re-migrated. */ export declare const DAEMON_CONFIG_MOVED_VERSION = 1; /** One daemon-owned key that changed home, and where it came from. */ export interface MovedConfigKey { readonly key: string; readonly from: string; } /** A value that was NOT kept, disclosed rather than silently dropped. */ export interface DiscardedConfigKey { readonly key: string; readonly from: string; /** Redacted when the key names a credential; otherwise the literal value. */ readonly value: unknown; /** 'conflict', a different value already won; 'duplicate', same value. */ readonly reason: 'conflict' | 'duplicate'; /** Which store's value won, so the discard is auditable. */ readonly supersededBy: string; } /** * The disclosure marker. Shaped after the existing `checkpoints-moved.json` * (movedTo / date) and extended with the per-key ledger this migration owes the * user. `status` exists so a crash mid-migration leaves a marker that is * explicitly incomplete rather than one that merely looks finished. */ export interface DaemonConfigMovedMarker { readonly version: number; readonly status: 'in-progress' | 'complete'; readonly movedTo: string; readonly primarySurface: string; readonly date: string; readonly sources: readonly string[]; readonly moved: readonly MovedConfigKey[]; readonly discarded: readonly DiscardedConfigKey[]; /** * Every key that was daemon-owned when this marker was written, not just the * ones that had a value to move. * * This is what makes the migration RE-RUNNABLE as ownership grows. A key * promoted to daemon-owned in a later release (conversationGate.* was exactly * this case) would otherwise never migrate: the marker said "complete" and * short-circuited the whole run, leaving the operator's existing value * stranded in a client file that the daemon does not read. The marker now * records the covered set, and a run whose owned set has grown migrates the * newcomers instead of declaring victory. * * Absent on a marker written before this field existed, which is treated as * "covers nothing" so those installations get one corrective pass. */ readonly coveredKeys: readonly string[]; } /** Absolute path of the disclosure marker for a daemon config store. */ export declare function daemonConfigMovedPath(daemonConfigStorePath: string): string; /** * Read and VALIDATE the marker by parsing it. Never `existsSync`, a torn or * truncated marker has already stranded user data once in this codebase, and a * file that exists but does not parse into a complete ledger must count as "not * migrated" so the migration runs again. * * Returns the marker only when it parses, is at the current version, and is * marked complete. Anything else (missing, unparseable, wrong version, * in-progress, wrong shape) returns null. */ export declare function readDaemonConfigMovedMarker(path: string): DaemonConfigMovedMarker | null; /** * Read a marker regardless of status, used to carry an interrupted run's * already-recorded ledger forward so a crash never erases the disclosure of * what a previous attempt moved. */ export declare function readAnyDaemonConfigMovedMarker(path: string): Partial | null; /** Write JSON atomically (temp file + rename) so no reader ever sees a torn file. */ export declare function writeJsonAtomic(path: string, value: unknown): void; /** Parse a settings JSON file; a missing file reads as {}, an invalid one throws. */ export declare function readSettingsFileStrict(path: string): Record; /** * Every surface settings store under `/.goodvibes/`, excluding the * daemon's own root and the surface-independent shared tier. Returns absolute * paths in a stable (alphabetical) order so a migration is deterministic. */ export declare function discoverSurfaceSettingsFiles(homeDir: string, exclude?: readonly string[]): readonly { surface: string; path: string; }[]; /** * Redact a disclosed value when the key names a credential. A * `goodvibes://secrets/...` reference is not itself a secret, so it is shown * intact, that is exactly the detail a user needs to see when two stores * pointed at DIFFERENT secret names, which is what happened here. */ export declare function discloseValue(key: string, value: unknown): unknown; //# sourceMappingURL=daemon-config-migration-io.d.ts.map