import { type IpcRequest, type IpcResponse } from "./ipc.js"; import { Logger } from "./logger.js"; import type { BackendKind, PeerHost } from "./peer-host.js"; export type HandoffState = "embedded" | "releasing" | "daemon" | "waiting"; /** How long a vanished daemon is treated as "restarting" before auto mode * gives up on it and takes the identity back. `agentnet restart` and a * launchd/systemd kickstart are both back well inside this. */ export declare const DAEMON_GRACE_MS: number; /** One missed probe is not a verdict. The probe runs on beagle's own event * loop, so any stall here (GC, a large /api/desktop body, an npm child) fires * its timer before the queued `connect` callback runs, and a healthy daemon * reads as gone — 814 times on mac-dev while daemon pid 75338 never changed. * Only a streak of misses that also spans real time is believed. */ export declare const DAEMON_MISS_STREAK = 3; export declare const DAEMON_MISS_WINDOW_MS = 5000; /** Is the process named in /daemon.pid still there? A root daemon * answers signal 0 with EPERM, which still proves it exists. */ export declare function daemonPidAlive(dataDir: string): boolean; export interface SwitchableHostOptions { dataDir: string; /** Build a fresh embedded host. Called on first start and on every fallback, * because a stopped peer is not restartable — the SDK ties its lifetime to * the instance. */ makeEmbedded: () => Promise; makeDaemon: () => PeerHost; onChange?: (state: HandoffState, host: PeerHost | null) => void; log?: Logger; /** The backend the user pinned with `--backend`, if any. A forced backend is * never switched away from automatically — in EITHER direction. Auto mode * (undefined) keeps the full state machine. */ force?: BackendKind; /** Grace period before auto mode falls back from a vanished daemon. */ graceMs?: number; /** Liveness probe, injectable for tests. Defaults to a real connect. */ probe?: (dataDir: string) => Promise; /** Test seam: does the daemon's process exist? Default reads /daemon.pid. */ pidAlive?: (dataDir: string) => boolean; } /** * A PeerHost whose backend can change under it. * * Everything above this (the HTTP server, the UI) keeps one reference and never * learns that the peer was swapped — which is the point: a backend change must * not be a restart. */ export declare class SwitchablePeerHost implements PeerHost { #private; constructor(initial: PeerHost, opts: SwitchableHostOptions); get kind(): PeerHost["kind"]; get hasVirtualLan(): boolean; get state(): HandoffState; /** The daemon's data dir (socket and pidfile), for callers that need to * watch a daemon restart through. */ get dataDir(): string; /** Seconds left before `releasing` gives up; 0 when not releasing. */ get releaseSecondsLeft(): number; call(req: IpcRequest): Promise; stop(): Promise; /** * Step 1 of enabling: give up the identity so a daemon can take it. * * We do NOT run the installer. It needs root, and beagle escalating on the * user's behalf — even via a prompt we trigger — is a privilege we do not * want this app to have. The UI shows the command; the OS asks for the * password; the user decides. */ armForDaemon(): Promise<{ state: HandoffState; command: string; }>; /** Abandon the handoff and bring the embedded peer back. */ cancelArm(): Promise; } /** The command the user runs. Shown, never executed by us. */ export declare const INSTALL_COMMAND = "sudo agentnet service install";