/**
 * design/116 detach([C] gap ②)— per-tool-call detach 信号毂。
 *
 * The missing middle of mid-flight ctrl+b: `TaskStream.detach(toolCallId)` fires the controller here; a
 * detach-capable tool (Bash) picks the signal up BY toolCallId from its mount closure and threads it into
 * `env.exec({ detachSignal })`, where the env adopts the running child as a background shell. Run-local
 * (one hub per task, created in prepare-task) — never cross-task. Zero vendored surface: the loop's
 * tool-call plumbing is untouched; the hub rides the existing closure path like taskRegistry does.
 *
 * `request()` uses create-then-abort so ordering races are safe: a detach that lands BEFORE the tool
 * reads its signal still detaches (the tool receives an already-aborted signal and adopts immediately).
 */
export declare class ToolDetachHub {
    private readonly controllers;
    /** the detach verb is caller-exposed — an unknown/never-started toolCallId would otherwise
     *  strand its controller until run end (gc only fires on the real tool-completion path), a per-run memory
     *  growth vector. Bound the map: on overflow, evict the OLDEST entry (Map preserves insertion order); a
     *  live tool re-materializes its controller on the next signalFor() and an aborted one stays aborted via
     *  the tombstone set below. */
    private static readonly MAX_CONTROLLERS;
    /** Fired-but-evicted ids (bounded): keeps create-then-abort race safety across an eviction. */
    private readonly firedTombstones;
    private controllerFor;
    /** The signal a detach-capable tool threads into its env call. */
    signalFor(toolCallId: string): AbortSignal;
    /** Fire a detach request for a (possibly not-yet-started) tool call. Idempotent. */
    request(toolCallId: string): void;
    /** Drop a finished call's controller (bounded memory; called from the tool's completion path). */
    gc(toolCallId: string): void;
}
