interface Entry { name: string; cwd: string; /** ISO timestamp of the last snapshot that saw this session open. */ lastSeen?: string; /** ISO timestamp of the first snapshot that ever saw it. */ addedAt?: string; /** * The cwd was set deliberately and must not be overwritten by a sighting. * * A session's live directory is where it happens to be running, which is not * always where it belongs: Solar was started in the home directory and later * repointed at its real project. Without this the next snapshot sees the live * process still in `~`, fails to match the corrected entry — the key is * name+cwd — and adds a SECOND Solar. The correction would undo itself within * five minutes, with nothing reporting that it had. */ pinned?: boolean; } /** * Union `fresh` (what is open right now) into `existing` (the restore list). * * Pure and exported so the property that actually matters is testable: this * never returns fewer entries than `existing`. Every historical way of losing * the manifest — /exit-ing tabs one by one, a daemon outage, an iTerm restart — * reaches this function as a small or empty `fresh`, and must be a no-op rather * than a truncation. */ export declare function mergeEntries(existing: Entry[], fresh: Entry[], now: string): Entry[]; export type AckResult = "ok" | "no-ack" | "no-settle" | "unreadable"; /** Injected so the ack state machine can be tested against a simulated terminal. */ export interface SessionProbe { capture: (id: string) => string | null; send: (id: string, text: string) => void; sleep: (ms: number) => Promise; now: () => number; onRetry?: (attempt: number, of: number) => void; } export declare const POLL_MS = 500; /** Consecutive identical frames that mean "Claude stopped writing". */ export declare const SETTLE_TICKS = 4; /** Distinct frames required before we believe the prompt was actually SUBMITTED. */ export declare const ACK_TRANSITIONS = 2; /** * Send `message` to one session and prove it was consumed. * * A successful `write text` only means keystrokes reached the terminal — not * that Claude accepted the prompt. That gap is exactly what leaves you walking * to every tab by hand after a hiccup. So we watch the screen instead. * * The subtlety: "the screen changed" is NOT proof of submission. Text typed into * Claude's input box changes the screen too, so a send whose Enter was swallowed * looks identical to a successful one for one frame — and then freezes. We * therefore require ACK_TRANSITIONS *distinct* frames: a working Claude animates * (spinner, streaming tokens) and trivially clears the bar, whereas text sitting * unsubmitted in the box produces exactly one change and then stillness, so it * correctly fails and retries. * * 1. send, then poll for ACK_TRANSITIONS distinct frames -> genuinely submitted * 2. poll until SETTLE_TICKS identical frames -> Claude finished * * Frame-diffing is deliberately content-agnostic: it never parses what `pause * session` prints, so it keeps working when that output changes. */ export declare function sendVerified(sessionId: string, message: string, opts: { timeoutMs: number; retries: number; }, probe: SessionProbe): Promise; export declare function runSessions(args: string[]): Promise; export {}; //# sourceMappingURL=sessions.d.ts.map