import { type PathCtx } from '../config/paths.js'; /** * A session directory per running session, instead of one shared by all of them. * * Starting a session copies the chosen account's login into its config * directory, because that is how ccx makes Claude run as that account. While * every session shared ONE directory, the second one to start overwrote the * first one's login, and from that moment the first terminal was running as * somebody else while ccx still reported the account it had chosen. * * That is not a display problem. Two things follow from it, and both were seen: * a limit hit by one account gets recorded against the other, and the save-back * that copies a refreshed login home writes the borrowed one into the wrong * profile. Once two profiles hold one token, `renewalWouldBreakOthers` treats * them as the same account and carries every later renewal across, so they can * never come apart again. Three accounts here spent a day as one that way. * * Giving each session its own directory removes the shared thing they were * fighting over, so none of that can start. */ /** Where per-session directories live. */ export declare function sessionsRoot(c?: PathCtx): string; /** This session's own config directory. */ export declare function sessionDirFor(pid: number, c?: PathCtx): string; /** * Is this a ccx terminal session directory? * * Accepts the pre-split single directory too. A session started before an * upgrade is still running in it, and its status line should keep working * rather than start reporting the session as something else. */ export declare function isSessionDir(dir: string, c?: PathCtx): boolean; /** The pid a session directory belongs to, or null when the name is not one. */ export declare function pidOfSessionDir(name: string): number | null; /** * Where session settings are kept BETWEEN sessions. * * The model pin lives in the session directory, because that is the config * directory Claude writes to when you use /model. A directory per session would * therefore forget the pin every time, silently putting you back on whatever * the default is, so it is carried out here as a session ends and back in as the * next one starts. */ export declare function keptSettingsPath(c?: PathCtx): string; /** * Give a fresh session directory the settings the last one ended with. * * Falls back to the pre-split single directory, which is where the pin lives * for anyone upgrading: without that, the first session after the change starts * on a different model than the one they left running. */ export declare function seedFromKeptSettings(sessionDir: string, c?: PathCtx): boolean; /** * What a session changed, as opposed to everything it was holding. * * The kept settings win over the user's real ones when the next session is * built, so anything in here overrides `~/.claude/settings.json` from now on. * Keeping a whole copy therefore froze the user's settings at the moment a * session last ended: editing the real file after that changed nothing, and * the frozen value could not be removed by any normal means. That is exactly * how `"tui": "fullscreen"` became unkillable. * * So only the keys that actually DIFFER from the real settings are carried, * which is the smallest set that still does the job it exists for (holding a * `/model` pin). It is also self-healing: once the real settings agree, the * override drops out on its own. */ export declare function changedFromUser(session: Record, user: Record): Record; /** * Carry a finished session's changes out before its directory is deleted. * * Newest wins, so sweeping several dead sessions at once cannot let the oldest * of them overwrite a pin set later. */ export declare function preserveSettings(sessionDir: string, c?: PathCtx): void; export interface SweepOptions { /** Injected in tests. */ isAlive?: (pid: number) => boolean; /** Never swept, even if the check says otherwise. */ keepPid?: number; } /** * Remove the session directories whose process is gone, and report which. * * Session directories hold a LOGIN, so leaving them behind after a crash leaves * credentials on disk for a session that no longer exists. Swept at startup * rather than on exit, because a session that is killed never gets to clean up * after itself, and that is exactly when one is left behind. */ export declare function sweepDeadSessionDirs(c?: PathCtx, options?: SweepOptions): string[]; /** * Delete one session directory without ever deleting through a link. * * `projects` inside a session directory is a junction to the user's real * `~/.claude/projects`, which holds every transcript and project memory they * have. A recursive delete that walked into it would take all of that with it, * so every link is unlinked first and the recursive delete only ever sees plain * files. This is the one operation in here that could destroy something * irreplaceable, which is why it does not rely on the delete being link-aware. */ export declare function removeSessionDir(dir: string): boolean;