/** * Shared types and scope resolution for session persistence. * * "Scope" is the question every persistence call answers before it touches a * file: WHICH directory does this call mean? There are two answers, the * legacy per-call `workingDirectory` / `homeDirectory` / `surfaceRoot` triple, * and a declare-once `SessionSurface`, and both the durable-store half * (session-persistence.ts) and the crash-snapshot half (session-recovery.ts) * route every path through the resolvers here, so the two sibling modules can * never disagree about where a file lives. * * This module is NOT re-exported wholesale. session-persistence.ts re-exports * exactly the names that were already public before the split; everything else * below is internal plumbing shared between the two siblings. */ import { SessionManager } from '../sessions/manager.js'; import type { SessionReturnContextSummary } from './session-return-context.js'; import type { ConversationTitleSource } from '../core/conversation.js'; import type { SessionSurface } from './session-surface.js'; export type SessionSnapshot = { messages: Array>; timestamp?: number | undefined; title?: string | undefined; titleSource?: ConversationTitleSource | undefined; returnContext?: SessionReturnContextSummary | undefined; }; /** * Legacy per-call scope: `workingDirectory` / `homeDirectory` / `surfaceRoot` * resolved independently on every call. Kept working byte-for-byte unchanged * (an omitted `surfaceRoot` still silently falls back to the shared, unscoped * `.goodvibes/` directory), this is the compat path. Every call through this * shape emits a one-time-per-process deprecation warning recommending a * `SessionSurface` instead. `surface` is declared here only so it can be typed * as `undefined`, making this shape and `SessionPersistenceSurfaceOptions` * mutually exclusive at the type level (mixing the two is a compile error). */ export type SessionPersistenceLegacyOptions = { workingDirectory?: string | undefined; homeDirectory?: string | undefined; sessionManager?: SessionManager | undefined; surfaceRoot?: string | undefined; readonly surface?: undefined; }; /** * Surface-based scope: every path is read directly off a declare-once * `SessionSurface` (see session-surface.ts), no per-call scope argument is * accepted alongside it, so there is no unscoped fallback to silently resolve * to and no way for a writer and a reader to disagree about a path as long as * they share the same surface. */ export type SessionPersistenceSurfaceOptions = { readonly surface: SessionSurface; readonly workingDirectory?: undefined; readonly homeDirectory?: undefined; readonly sessionManager?: undefined; readonly surfaceRoot?: undefined; }; export type SessionPersistenceOptions = SessionPersistenceLegacyOptions | SessionPersistenceSurfaceOptions; export type SessionPersistencePaths = { readonly workingDirectory: string; readonly homeDirectory: string; }; /** * Emit the legacy-options deprecation warning exactly once per process, * regardless of how many legacy-shaped calls occur (including internal calls * chaining through, e.g. persistConversation -> saveSession -> writeLastSessionPointer). */ export declare function warnLegacyOptionsOnce(): void; /** True when `options` uses the surface-based call form. */ export declare function isSurfaceOptions(options: SessionPersistenceOptions | undefined): options is SessionPersistenceOptions & { readonly surface: SessionSurface; }; /** * Read the `SessionSurface` off surface-form options, throwing synchronously * with a clear message if it is missing a required path. This is what makes * the arity-bug class (a mis-called function silently resolving an unscoped * path because an options argument came through undefined) impossible in the * surface form: there is no fallback branch here to silently resolve to. */ export declare function requireSurface(options: SessionPersistenceOptions): SessionSurface; /** Resolve the last-session pointer path for either call form. */ export declare function resolveLastSessionPointerPath(options?: SessionPersistenceOptions): string; /** Resolve the recovery directory for either call form. */ export declare function resolveRecoveryDirPath(options?: SessionPersistenceOptions): string; /** Resolve a specific session's recovery file path for either call form. */ export declare function resolveRecoveryFilePath(options: SessionPersistenceOptions | undefined, sessionId: string): string; /** * Resolve the DURABLE session-store directory (the one holding * `.jsonl` files SessionManager writes) for either call form. This * is the directory the recovery layer compares a snapshot against to decide * whether that snapshot's own session already saved something newer, see * `sessionStoreMtimeMs` in session-recovery.ts. */ export declare function resolveSessionsDirPath(options?: SessionPersistenceOptions): string; /** * The durable store file for one session inside an already-resolved sessions * directory. The filename stem comes from the SAME rule SessionManager.save * writes with (`sanitizeSessionName`), so this path is the file that session's * clean saves actually land in, not a lookalike derived from a second rule. */ export declare function resolveSessionStorePath(sessionsDir: string, sessionId: string): string; export declare function requireWorkingDirectory(options?: Pick): string; export declare function requireHomeDirectory(options?: Pick): string; export declare function resolveSessionManager(options?: SessionPersistenceOptions): SessionManager; export declare function getUserSessionsDir(workingDirectory: string, surfaceRoot?: string): string; export declare function getLastSessionPointerPath(workingDirectory: string, surfaceRoot?: string): string; /** Filename prefix for per-session crash-recovery snapshots. */ export declare const RECOVERY_FILE_PREFIX = "recovery-"; export declare const RECOVERY_FILE_SUFFIX = ".jsonl"; /** * Directory holding per-session crash-recovery snapshots * (`/recovery/recovery-.jsonl`). Each concurrent session * owns its own file, so two sessions crashing (or snapshotting) at once never * clobber a single shared recovery file. */ export declare function getRecoveryDir(homeDirectory: string, surfaceRoot?: string): string; /** * The legacy, home-anchored, fully UNSCOPED shared recovery directory * (`~/.goodvibes/recovery/`, no surfaceRoot segment at all), the oldest * layout, predating even the surfaceRoot-scoped `getRecoveryDir` above. It * cannot be mapped to a project deterministically (any project that ever ran * with this surfaceRoot before per-project scoping could have written here), * so it is never migrated (see session-migration.ts's header), only * dual-read, one time, by the surface form of checkRecoveryFile / * loadRecoveryConversation / deleteRecoveryFile in session-recovery.ts. */ export declare function legacySharedRecoveryDir(surface: SessionSurface): string; /** The legacy shared per-session recovery file path for `sessionId` (see legacySharedRecoveryDir). */ export declare function legacySharedRecoveryFile(surface: SessionSurface, sessionId: string): string; /** * The recovery snapshot path for a specific session: * `/recovery/recovery-.jsonl`. */ export declare function getRecoveryFilePath(homeDirectory: string, sessionId: string, surfaceRoot?: string): string; //# sourceMappingURL=session-persistence-scope.d.ts.map