import { type PullRequest } from "./return-contract.js";
import { sessionStalls } from "./stalls.js";
import { z } from "zod";
import { type OriginPane, type Receipt } from "./dispatch.js";
import { type BriefArrival } from "./launch-brief.js";
import { type LostTurn } from "./codex-servers.js";
import { findGrant } from "./grants.js";
import { peerRequest, type HookPeer } from "./peers.js";
import { type ApprovalDecision, type Json, type Provider, type Target } from "./protocol.js";
import { type FinalTurn } from "./schedule-watch.js";
import { type TurnRecord } from "./turn-records.js";
import { type MovedWorker, type MoveRecord } from "./session-move.js";
import { type Uncommitted } from "./worker-unfinished.js";
export { truncateUtf8 } from "./turn-records.js";
/**
 * The conductor's returns loop. The worker's computer answers what its
 * dispatched panes are doing (`workerStates`): from the turn record its
 * agent's own hooks wrote (turn-records.ts) when there is one, else from the
 * Herdr snapshot its Hook already shares and the transcript. The dispatching
 * Hook asks each peer once per poll for all of its open dispatches, records
 * transitions in the receipts, and tells an idle dispatching agent that
 * returns are waiting (`DispatchReturns`).
 */
/** Longest final reply kept in a receipt, in UTF-8 bytes. */
export declare const REPLY_LIMIT = 4000;
/** How often the dispatching Hook asks peers about open dispatches. */
export declare const POLL_MS = 15000;
/** Allow the new process and its terminal identity to appear before declaring
 * an unobserved launch gone. An observed worker never gets this grace. */
export declare const LAUNCH_GRACE_MS = 60000;
/** Shortest gap between two notices typed into the same dispatching pane. */
export declare const NOTICE_MS = 120000;
/** Receipts older than this are no longer watched. */
export declare const WATCH_MS: number;
/** How long a stopped worker whose harness still runs background tasks is
 * waited on before it counts as done anyway. Measured from the latest Stop,
 * and every task that finishes wakes the worker (a new prompt, a new Stop), so
 * it only elapses when no background task has finished for two hours: a dev
 * server the worker left running. It is then reported done with the count
 * still running. */
export declare const BACKGROUND_WAIT_MS: number;
export declare const workerRequestSchema: z.ZodObject<{
    targets: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
        server: z.ZodString;
        workspace: z.ZodString;
        tab: z.ZodString;
        pane: z.ZodString;
        source: z.ZodEnum<{
            claude: "claude";
            codex: "codex";
            copilot: "copilot";
            opencode: "opencode";
            phren: "phren";
        }>;
        session: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
        dispatch: z.ZodOptional<z.ZodString>;
    }, z.core.$strip>, z.ZodObject<{
        server: z.ZodString;
        workspace: z.ZodString;
        tab: z.ZodString;
        pane: z.ZodString;
        source: z.ZodEnum<{
            claude: "claude";
            codex: "codex";
            copilot: "copilot";
            opencode: "opencode";
            phren: "phren";
        }>;
        starting: z.ZodLiteral<true>;
        startingToken: z.ZodString;
        dispatch: z.ZodOptional<z.ZodString>;
    }, z.core.$strip>]>>;
}, z.core.$strict>;
/** What a worker pane shows right now, as its own computer reads it. */
export interface WorkerObservation {
    /** Herdr's status for the pane, or gone when the pane or its conversation is no longer there. */
    state: "working" | "idle" | "done" | "blocked" | "unknown" | "gone" | "closed" | "unavailable";
    session?: string;
    completed?: boolean;
    reply?: string;
    truncated?: boolean;
    /** The error the harness ended the turn on (Codex's usage limit). */
    error?: string;
    /** The state comes from the agent's own turn events, not from how the pane looks. */
    hook?: true;
    /** When the turn's Stop arrived, on the worker's clock; names the turn. */
    endedAt?: string;
    stopSeq?: number;
    /** Background tasks the harness still runs: waited on while `working`;
     * when `done`, left running (after BACKGROUND_WAIT_MS, or not awaited), so
     * the pane is not closed on them. */
    background?: number;
    /** The owner stopped the turn in the worker's terminal. */
    interrupted?: true;
    /** A permission request the pane's worker is waiting on, forwarded by its Hook (`AgentHooks.workerApproval`). */
    approval?: Json;
    prs?: PullRequest[];
    stalled?: boolean;
    stalledSince?: string;
    stallFor?: number;
    /** Why a turn that ended is not done (worker-unfinished.ts): it announced a
     * next step, or left uncommitted work and no PR. Returned as needs-you. */
    unfinished?: string;
    /** The worker's checkout could not be read in time: the turn may be done,
     * but it is not closed on that (worker-close.ts). */
    unchecked?: true;
    /** Where a worker that hit its Claude usage limit was working, for the dispatch that continues it. */
    checkout?: {
        path: string;
        branch?: string;
    };
    /** The worker is being moved to another agent (session-move.ts): the move's id. */
    moving?: string;
    /** The worker was moved to another agent; the state above is the new agent's. */
    moved?: MovedWorker;
}
export interface WorkerReaders {
    snapshot: (server: string) => Promise<Json>;
    freshSnapshot?: (server: string) => Promise<Json>;
    identity: (server: string, pane: Json) => Promise<string | undefined>;
    finalTurn: (source: Provider, session: string) => Promise<FinalTurn | undefined>;
    /** The turn record the pane's agent reported through its hooks (or OpenCode's plugin). */
    turn?: (server: string, pane: Json, source: Provider) => Promise<TurnRecord | undefined>;
    /** What the worker in this conversation is waiting on, from the Hook that runs it. */
    approval?: (target: Target) => Json | undefined;
    /** Running child agents (sub-agents, teammates, workflows, fan-outs) of the
     * worker's conversation, counted like the session rows count them. */
    children?: (source: Provider, session: string) => Promise<number>;
    now?: () => number;
    stall?: typeof sessionStalls.observe;
    /** The turn a Codex pane lost with its app-server, which no Stop will end. */
    lost?: (server: string, pane: string, session?: string) => LostTurn | undefined;
    /** Tracked files with uncommitted changes in the worker's checkout. */
    uncommitted?: (directory: string) => Promise<Uncommitted>;
    /** Whether other panes' folders share the worker's checkout, whose changes then are not only its own. */
    shared?: (directory: string, folders: readonly unknown[]) => Promise<boolean>;
    /** The branch checked out in a folder. */
    branch?: (directory: string) => Promise<string | undefined>;
    /** This computer's session moves (session-move.ts), newest first. */
    moves?: () => Promise<MoveRecord[]>;
}
export declare function paneTurn(server: string, pane: Json, source: Provider): Promise<TurnRecord | undefined>;
/** The default readers with the approval reader of the Hook that runs the workers. */
export declare const workerReaders: (approval: NonNullable<WorkerReaders["approval"]>) => WorkerReaders;
/** The receiving side of `/v1/dispatch/workers` on a Hook: leases the panes'
 * permission asks for the dispatching Hook's next polls and reads what each
 * worker is waiting on. */
export declare function hookWorkers(hooks: {
    leaseDispatch: (targets: readonly {
        server: string;
        pane: string;
        source: string;
    }[]) => void;
    workerApproval: (target: Target) => object | undefined;
}): (input: unknown) => Promise<{
    workers: WorkerObservation[];
}>;
/** Receiving side: the state of each dispatched pane, from its agent's turn
 * record when its hooks wrote one, else from the shared snapshot and, once
 * the agent has stopped, the final reply in its transcript. */
export declare function workerStates(input: unknown, readers?: WorkerReaders): Promise<{
    workers: WorkerObservation[];
}>;
/** A worker's forwarded permission request as its Hook sent it; an invalid one is ignored, not a reason to drop the state. */
declare const approvalObservation: z.ZodObject<{
    actionId: z.ZodString;
    tool: z.ZodDefault<z.ZodString>;
    title: z.ZodOptional<z.ZodString>;
    request: z.ZodOptional<z.ZodString>;
    requestKind: z.ZodOptional<z.ZodEnum<{
        command: "command";
        edit: "edit";
        other: "other";
        question: "question";
        tool: "tool";
    }>>;
    terminal: z.ZodOptional<z.ZodBoolean>;
    conductor: z.ZodOptional<z.ZodObject<{
        action: z.ZodEnum<{
            dispatch: "dispatch";
            hand_off: "hand_off";
        }>;
        project: z.ZodOptional<z.ZodString>;
        computer: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>>;
    expiresAt: z.ZodOptional<z.ZodString>;
    pushed: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
export type ObservedApproval = z.infer<typeof approvalObservation>;
/** What the owner is told when the worker's turn was interrupted in its terminal. */
export declare const INTERRUPTED = "The worker's turn was interrupted in its terminal before it finished.";
export declare function workerTurnKey(seen: {
    endedAt?: string;
    stopSeq?: number;
    reply?: string;
}, error?: string): string | undefined;
/** Apply one observation to a receipt. Returns true when the receipt changed. */
export declare function observe(receipt: Receipt, value: unknown, now: number, peers?: readonly HookPeer[], self?: {
    id: string;
    name: string;
    verifiedHomeMove?: string;
}): boolean;
/** One line for the dispatching agent: who returned, how, and where to read it. */
export declare function noticeLine(receipts: readonly Receipt[]): string;
/** What `dispatch_returns` lists for one unread return. */
export declare function returnRow(receipt: Receipt): Json;
export interface DispatchReturnsOptions {
    /** This Hook's stable identity, for a worker moving back home. */
    localComputer?: {
        id: string;
        name: string;
    };
    peers?: () => Promise<HookPeer[]>;
    request?: typeof peerRequest;
    forward?: (origin: OriginPane, text: string, deliveryId: string) => Promise<{
        delivered: boolean;
    } | undefined>;
    /** Worker states on this computer, for dispatches placed here without SSH. */
    localWorkers?: (input: Json) => Promise<{
        workers: unknown[];
    }>;
    isLocal?: (computer: string) => boolean;
    /** A recent Herdr snapshot of a local server, to see whether the dispatching agent is idle. */
    snapshot?: (server: string) => Promise<Json>;
    identity?: (server: string, pane: Json) => Promise<string | undefined>;
    /** Types the notice into the dispatching agent, through the ordinary hand-off
     * path; the same notice keeps one delivery id, so a retry is never typed twice. */
    deliver?: (target: Target, text: string, deliveryId: string) => Promise<{
        delivered: boolean;
    }>;
    /** What a worker's hooks reported for a brief launched on this computer. */
    localArrival?: (id: string) => Promise<BriefArrival | undefined>;
    /** The standing grant for a conductor call, on this computer. */
    findGrant?: typeof findGrant;
    /** Answers a worker's approval placed on this computer, without SSH (the Hook's own `AgentHooks.answer`). */
    localAnswer?: (target: Target, actionId: string, decision: ApprovalDecision) => Promise<unknown>;
    /** A worker's new forwarded request was recorded. Returns true when this Hook pushed it to its phone. */
    onApproval?: (receipt: Receipt, approval: NonNullable<Receipt["approval"]>) => boolean | void;
    close?: (receipt: Receipt, verifiedPeer?: HookPeer) => Promise<Json>;
    /** Continues Claude workers stopped by their usage limit on another account, after each poll (account-failover.ts). */
    failover?: {
        run: () => Promise<void>;
    };
    now?: () => number;
}
/** The same returns to the same origin keep their id on retry. A role
 * hand-over gets a fresh delivery instead of reusing the old chat's receipt. */
export declare function noticeDeliveryId(receipts: readonly Receipt[]): string;
/** Dispatching side: follows open dispatches and delivers their returns. */
export declare class DispatchReturns {
    private readonly forward?;
    private readonly localComputer?;
    private readonly peers;
    private readonly request;
    private readonly localWorkers;
    private readonly isLocal;
    private readonly snapshot;
    private readonly identity;
    private readonly deliver;
    private readonly localArrival;
    private readonly now;
    private readonly grant;
    private readonly localAnswer?;
    private readonly onApproval?;
    private readonly close?;
    private readonly failover?;
    private lastPoll;
    private readonly lastNotice;
    /** A return is waiting for a dispatching agent that was busy: try again on
     * the next tick instead of the next poll. */
    private noticesDue;
    private running?;
    constructor(options?: DispatchReturnsOptions);
    private isSelf;
    private verifiedMovedPeer;
    /** Send a decision for a worker's request to the Hook that runs it. */
    private sendAnswer;
    /** Answer the permission request a dispatched worker is waiting on. It is
     * cleared from the receipt once answered, or once its Hook says it is no
     * longer pending (answered in the terminal, or timed out). */
    answerApproval(id: string, decision: ApprovalDecision, actionId: string, caller?: OriginPane): Promise<void>;
    /** Called from the Hook's activity tick. Polls peers at most every POLL_MS;
     * a return waiting for its notice is tried on every tick, so one recorded
     * while the dispatching agent was busy reaches it as soon as it stops. */
    tick(): Promise<void>;
    /**
     * A brief that went with the launch but was not confirmed while the dispatch
     * was placed (a startup screen held it, the agent was slow): ask the
     * worker's computer whether its hook has confirmed it since.
     */
    confirmArrivals(peers: HookPeer[]): Promise<void>;
    /** Ask each peer, once, about every open dispatch placed on it. */
    poll(): Promise<void>;
    /** A conductor call the owner's standing grant covers is answered here at
     * once, and its request is left off the observation so it never becomes a
     * return. Anything else, or an answer that failed, is left for the owner. */
    private grantAnswered;
    /** Type one line into each idle dispatching agent that has returns it was
     * not told about. A pane still working is tried again on the next tick. */
    notify(): Promise<void>;
    /** Forward a structured report with one stable id; queued is a durable
     * acceptance, while uncertain is retained and never replaced. */
    forwardPrs(): Promise<void>;
    cleanup(): Promise<void>;
    private closeRemote;
    /** A remote successor acknowledges only the exact return version it received. */
    acknowledge(rows: Json[]): Promise<void>;
    /** Every unread return, oldest first, marked read as it is handed over. */
    take(consume?: boolean): Promise<Json[]>;
}
