import type { BackendType, PersistentBackendTarget, SessionProbe } from '../adapters/backend/types.js'; import type { DaemonSession } from './types.js'; import type { Session } from '../types.js'; export type PersistentBackendType = Extract; /** * Decide whether a post-kill probe still blocks a cold replacement. * * ZMX owns sessions by labels + frozen PID, so an inconclusive confirmation * must remain fail-closed. The older mux backends only have best-effort * process/session probes: after a successful kill, `unknown` is not proof that * the target survived (notably zellij reports zero live sessions with exit 1). */ export declare function shouldRejectPersistentPostKillProbe(backendType: PersistentBackendType, probe: SessionProbe): boolean; export declare function isSuspendableBackendType(backendType: BackendType | undefined): backendType is PersistentBackendType; /** * Resolve which persistent backend (if any) backs a session. * * Precedence, most authoritative first: * 1. `ds.initConfig?.backendType` — the live worker's resolved backend this run. * 2. `ds.session.backendType` — the backend stamped on the persisted session * at spawn time (survives daemon restart; see Session.backendType). * 3. An explicit per-bot `backendType` — authoritative even for legacy * sessions, since the bot's choice didn't change across the PTY退役 flip. * * If NONE of those resolve, the session predates backendType stamping AND its * bot pins no backend, so it ran on the OLD probe-based daemon default — which * could have been PTY on a tmux-less host. We deliberately do NOT fall back to * the current `config.daemon.backendType` (now always tmux): doing so would * make `restoreActiveSessions` probe for a `bmx-` pane that never existed, * find it 'missing', and zombie-close a perfectly recoverable session. Treating * it as non-persistent keeps the worker-less active record for lazy resume; a * genuinely surviving tmux pane still reattaches lazily on the next message * (and gets stamped then). */ export declare function getSessionPersistentBackendType(ds: DaemonSession): PersistentBackendType | undefined; /** * Freeze-once backend resolution for a forkWorker spawn. An already-running * session keeps the backend stamped at its FIRST spawn (`sessionStamp`); only a * brand-new session (no stamp) resolves from the bot's live config, then the * daemon default. worker-pool's forkWorker calls this so a live dashboard * backendType edit only affects NEW sessions and never re-derives a running * session onto a different backend (which would strand its persistent pane). */ export declare function resolveSpawnBackendType(sessionStamp: BackendType | undefined, botType: BackendType | undefined, defaultType: BackendType): BackendType; /** * CLIs that are NOT local processes: they have an empty `resolvedBin` and their * backend translates write() into remote API / headless-CLI calls. For each of * these the cliId and the backendType share a name and must stay paired. * * Adding a remote CLI means adding it here — the alternative (another * hardcoded `=== 'riff'` chain in every helper below) is exactly what made this * generalization necessary. */ /** True for a backend that runs the agent off-box (no local PTY to own). */ export declare function isRemoteBackendType(type: BackendType): boolean; export { isRemoteCliId } from './remote-cli-ids.js'; /** * Enforce the `cliId === ⇔ backendType === ` pairing invariant * at the ONE spawn chokepoint, so every config entry point (dashboard, `/config * set cli|backendType`, `botmux setup`, hand-edited bots.json) converges: * - a remote CLI on a local backend → force its own backend (a pty/tmux spawn * would fail on the empty resolvedBin); * - a non-remote CLI on a remote backend → fall back to the daemon default * (the CLI's PTY chunked writes would otherwise fan out into remote tasks). * Manual pty/tmux/herdr/zellij overrides for local CLIs pass through. * * NOTE: kept under its historical name `reconcileRiffBackendType` on purpose — * it is imported by name in several modules and renaming it would bloat this * behaviour-preserving refactor into a cross-cutting rename. */ export declare function reconcileRiffBackendType(cliId: string, resolved: BackendType, defaultType: BackendType): BackendType; /** Resolve the frozen/live/default backend precedence and then enforce the * Riff CLI/backend pairing. Keep spawn-time callers on this single helper so * worktree push decisions cannot drift from the backend forkWorker will use. */ export declare function resolvePairedSpawnBackendType(cliId: string, sessionStamp: BackendType | undefined, botType: BackendType | undefined, defaultType: BackendType): BackendType; /** Whether the live/persisted session is frozen onto the remote Riff backend. * Restart guards must use the session stamp rather than the bot's mutable * current config: changing a bot later must not make an existing Riff * generation look locally restartable. */ export declare function isRiffBackendSession(ds: DaemonSession): boolean; /** Whether the live/persisted session is frozen onto ANY remote backend. * Same frozen-stamp rule as isRiffBackendSession. Used by the guards that * must reject BEFORE mutating persisted state (e.g. /cd repin): killWorker * refuses unprepared live retirement for every remote backend, so a caller * that mutates first and retires after would report success while the live * generation keeps running against the old state — the split-brain the riff * guard has always prevented, now needed for mojo too. */ export declare function isRemoteBackendSession(ds: DaemonSession): boolean; /** * How a session's worker is torn down at daemon shutdown, branched on the * session's FROZEN backend (via getSessionPersistentBackendType), NOT live config: * 'detach' — persistent backend (tmux/herdr/zellij): SIGTERM the worker only, * leaving the multiplexer session alive for re-attach. * 'close' — non-persistent (frozen pty, or unresolvable legacy): killWorker. * Freezing here stops a live backendType edit from changing how a running session * tears down — e.g. detach-preserving a "herdr" session whose real pane is tmux. */ export declare function shutdownBackendDisposition(ds: DaemonSession): 'remote-drain-detach' | 'detach' | 'close'; /** Deterministic backing-session name (`bmx-`, same rule across backends). */ export declare function persistentSessionName(backendType: PersistentBackendType, sessionId: string): string; /** * Resolve the exact backing resource for daemon lifecycle work. The persisted * worker-selected target wins only when it still matches the frozen backend; * legacy rows fall back to the historical deterministic whole-session target. */ export declare function resolvePersistentBackendTarget(backendType: PersistentBackendType, sessionId: string, persisted?: PersistentBackendTarget): PersistentBackendTarget; export declare function persistentBackendTargetForSession(ds: DaemonSession): PersistentBackendTarget | undefined; /** Exact managed resources to remove when a single-bot CLI changes. * Adopted panes are user-owned; machine-wide Herdr agents must be returned as * agent-scoped targets rather than collapsing to the shared host session. */ export declare function managedTargetsForCliChange(backendType: PersistentBackendType, sessions: readonly Pick[]): PersistentBackendTarget[]; export declare function probePersistentBackendTarget(target: PersistentBackendTarget): SessionProbe; /** * `sessionId` is REQUIRED for ZMX: its destruction is identity-verified against * the botmux labels stamped on the session, and `killPersistentSession` refuses * a name-only ZMX kill rather than risk destroying a same-named user session. * Callers that hold the owning session must always pass it through. */ export declare function killPersistentBackendTarget(target: PersistentBackendTarget, sessionId?: string): void; export declare function probePersistentSession(backendType: PersistentBackendType, name: string): SessionProbe; /** * Take one liveness snapshot for a set of backing-session names. * * ZMX and Zellij expose all session states in one command, so probing each row * separately would repeatedly scan the same control plane (and makes `botmux * list` quadratic for ZMX). tmux and Herdr keep their established per-session * probes, but duplicate names are still coalesced here. */ export declare function probePersistentSessions(backendType: PersistentBackendType, names: Iterable): ReadonlyMap; /** * Kill a backing session. ZMX additionally requires the complete botmux UUID: * its public name contains only eight UUID characters, so name-only deletion * could destroy a different session after a prefix collision. */ export declare function killPersistentSession(backendType: PersistentBackendType, name: string, sessionId?: string): void; //# sourceMappingURL=persistent-backend.d.ts.map