import { type ActiveSession } from '../active.js';
import type { SessionMeta } from '../types.js';
import { readActiveSessionsCache } from '../session-cache.js';
export declare const SESSION_WATCH_VERSION: 1;
export declare const SESSION_WATCH_HEARTBEAT_MS = 15000;
export declare const SESSION_WATCH_PREVIOUS_LIMIT = 50;
export type SessionWatchScopeStatus = 'available' | 'unavailable';
export type SessionWatchEnvelope = {
    version: 1;
    type: 'reset';
    streamId: string;
    sequence: number;
    capturedAt: number;
    scope: string;
    rows: SessionWatchRow[];
} | {
    version: 1;
    type: 'upsert';
    streamId: string;
    sequence: number;
    capturedAt: number;
    scope: string;
    rowKey: string;
    row: SessionWatchRow;
} | {
    version: 1;
    type: 'remove';
    streamId: string;
    sequence: number;
    capturedAt: number;
    scope: string;
    rowKey: string;
} | {
    version: 1;
    type: 'scope';
    streamId: string;
    sequence: number;
    capturedAt: number;
    scope: string;
    status: SessionWatchScopeStatus;
    reason?: string;
} | {
    version: 1;
    type: 'heartbeat';
    streamId: string;
    sequence: number;
    scope: string;
    capturedAt: number;
};
export interface SessionWatchRow extends Omit<ActiveSession, 'viewingIn' | 'context'> {
    context: ActiveSession['context'] | 'recent';
    /** Flat durable branch for history rows that are not currently in a worktree. */
    branch?: string;
    rowKey: string;
    sourceDevice: string;
    /** Durable index rows are kept on the stream under a distinct identity so a
     * live row can replace/disappear without erasing its recoverable history. */
    previous: boolean;
    resumable: boolean;
    unwatched: boolean;
    viewingIn: string | null;
    recovery: {
        command: 'agents';
        args: string[];
        cwd?: string;
    } | null;
}
/** Stable, opaque identity for one row within one device scope. */
export declare function sessionWatchRowKey(scope: string, row: ActiveSession): string;
export declare function toSessionWatchRow(scope: string, row: ActiveSession): SessionWatchRow;
/** Stable identity for a durable Previous row. It is deliberately distinct
 * from the live row key for the same session id: both may coexist on the one
 * stream, and the presentation layer lets the live row win while it exists. */
export declare function previousSessionWatchRowKey(scope: string, sessionId: string): string;
/** Project one durable indexed session into the same canonical watch contract
 * as live sessions. This is the only history backfill consumed by AGI EXT. */
export declare function toPreviousSessionWatchRow(scope: string, session: SessionMeta): SessionWatchRow;
/** Stream-local sequencer and convergent row diff. */
export declare class SessionWatchState {
    readonly streamId: string;
    private sequence;
    private readonly rows;
    constructor(streamId?: string);
    private base;
    /** Keep one visible Previous row per session and the newest bounded window.
     * Returns removed keys so delta callers can converge already-connected clients. */
    private prunePrevious;
    reset(scope: string, sourceRows: ActiveSession[], indexedRows?: SessionMeta[]): SessionWatchEnvelope;
    update(scope: string, sourceRows: ActiveSession[]): SessionWatchEnvelope[];
    patch(scope: string, upserts: ActiveSession[], removes: string[]): SessionWatchEnvelope[];
    scope(scope: string, status: SessionWatchScopeStatus, reason?: string): SessionWatchEnvelope;
    heartbeat(scope: string, capturedAt?: number): SessionWatchEnvelope;
}
export interface WatchLocalOptions {
    scope: string;
    signal: AbortSignal;
    emit: (event: SessionWatchEnvelope) => void;
    refreshMs?: number;
    heartbeatMs?: number;
    readCache?: typeof readActiveSessionsCache;
    readPrevious?: (scope: string) => SessionMeta[];
    journalPath?: string;
    journalPollMs?: number;
}
/** One bounded index read when the watch starts. The stream then owns this
 * projection: active rows update through the journal, and removals demote into
 * Previous rows without another transcript/index poll. */
export declare function readPreviousSessionsForWatch(scope: string): SessionMeta[];
/**
 * Keep one local subscription alive. Startup reads one canonical reset snapshot;
 * steady state tails the canonical writer journal and never invokes a gather.
 */
export declare function watchLocalSessions(options: WatchLocalOptions): Promise<void>;
export interface WatchFleetOptions {
    signal: AbortSignal;
    emit: (event: SessionWatchEnvelope) => void;
    reconnectMs?: number;
}
/**
 * Subscribe to every dialable compute device with one persistent SSH process.
 * A peer disconnect emits `scope: unavailable` but no removes; reconnecting
 * peer resets only its own scope. There is no recurring fleet list command.
 */
export declare function watchFleetSessions(options: WatchFleetOptions): Promise<void>;
