import { headlessBrokerHost } from './host.js'; import { respawnPaneSync } from './placement.js'; /** Reap the descendant sub-DAG of `rootId`: mark each **canceled** (the user * moved on — a clean teardown, NOT a fault) + clear intent FIRST, then kill its * window (closes the daemon revive race). Edges are LEFT INTACT — descendants * keep parent=rootId. No wipe. Returns the reaped ids. * * Why `canceled` (A5, human-confirmed 2026-06-06): an externally-reaped node — * whether via `node lifecycle close` OR a root reset — did not finish its OWN work, so it * unifies on `canceled`; `done` is reserved for finish. Why marking is STILL * explicit: an abrupt broker teardown fires NO clean `session_shutdown`, so the * general quit→done rule does NOT auto-resolve a force-killed descendant — we * mark it `canceled` here via the same `cancel` event the close cascade uses. */ export declare function reapDescendants(rootId: string): string[]; /** Injectable host/viewer seam, so the fast-tier test drives relaunchRoot's pure * DB transitions without a real broker or tmux. Each field defaults to its * production verb. */ export interface RelaunchDeps { /** Boot the new node's detached broker engine. Default: headlessBrokerHost.launch. */ launchBroker?: typeof headlessBrokerHost.launch; /** Wait for the new broker's view.sock to accept. Default: waitForBrokerViewSocket. */ waitForViewSocket?: (nodeId: string, exited?: Promise<{ code: number | null; signal: NodeJS.Signals | null; }>) => boolean | Promise; /** Re-exec the viewer pane onto the new node. Default: respawnPaneSync. */ respawnViewer?: typeof respawnPaneSync; /** Tear the old broker down. Default: headlessBrokerHost.teardown. */ teardownBroker?: typeof headlessBrokerHost.teardown; } export interface RelaunchRootResult { /** The freshly-minted node now driving this pane. */ newNodeId: string; } /** Relaunch a ROOT on `/new`: park the old root `done` (kept as history) and * mint a fresh node id + broker in the same pane/cwd, re-pointing the viewer at * it. The new broker is booted FIRST and its pid confirmed BEFORE the old root * is touched, so any pre-commit failure leaves the old root fully intact and * live. Returns null when `oldId` is not a relaunchable root (unknown, a child, * or already parked), or when the new broker failed to launch. */ export declare function relaunchRoot(oldId: string, deps?: RelaunchDeps): Promise; export interface ResetRootResult { /** Descendant node ids torn down. Always empty — a child `/new` reaps nothing. */ reaped: string[]; /** Direct subscriptions dropped. Always empty — a child `/new` detaches nothing. */ detached: string[]; /** Always false — a child `/new` is not a graph reset (roots route to relaunchRoot). */ reset: boolean; } /** Refresh a non-root child's pi session id on `/new`, so a later * `--session ` wakes the right conversation. A `/new` on a child is NOT a * graph reset — a root's `/new` is handled by relaunchRoot, never here; a root * that reaches this is a no-op. */ export declare function resetRoot(nodeId: string, newSessionId?: string, newSessionFile?: string | null): ResetRootResult; export type HandleNewSessionPath = 'reset-child' | 'noop'; export interface HandleNewSessionResult { path: HandleNewSessionPath; } /** The child-side `/new` entry the stophook calls (the root side goes to * relaunchRoot directly). The broker already drove the engine-side new_session; * this only refreshes the child's session id on the SAME node id. */ export declare function handleNewSession(nodeId: string, newSessionId: string, newSessionFile?: string | null): HandleNewSessionResult; /** Resolve a cleanly-exiting node to `done`. Returns true iff it transitioned. * Guard: only a real quit, and only a node still active|idle with no pending * intent — so it never clobbers a node already routed by agent_end to done * (push final), refresh (yield), or idle-release. Pure/DB-only (no pi/tmux) so * the guard is unit-testable without a live pi. */ export declare function markCleanExitDone(nodeId: string, reason: unknown): boolean;