/**
 * Sub-agent residual-observability recorder (lanes A/B/D — CC harness parity).
 *
 * A parent observing a child agent — especially one that was stopped mid-flight by a stream drop or
 * TaskStop — needs more than final text + terminal status to write a PRECISE resume prompt ("you
 * stopped at file X, step Y"). CC's harness feeds the parent a compact step tail + the child's edited
 * files + a one-line "currently doing" progress string. This recorder derives those three from the
 * child's live `TaskEvent` stream (the same `onForwardEvent` sink the display/tick lanes already tap),
 * so no new engine plumbing is needed — it is a pure observer.
 *
 * Scope: ONE direct child. A child that itself spawns a grandchild re-threads the same forward sink,
 * so grandchild events bubble through here too. Scoping is EXPLICIT, not first-come-first-served
 * (CORE-2 — the old "first `sourceTaskId` seen" lock assumed direct-child content always precedes
 * any grandchild frame, an ordering the shared sink does not guarantee):
 *   1. the spawn site calls {@link SubagentStepRecorder.lockTo} the moment the child's taskId is known
 *      (fork lanes: the forked sessionId; retained lanes: the pre-minted child sessionId) — after that,
 *      only `sourceTaskId === lockedSource` frames are recorded;
 *   2. lanes where the child id is minted inside `runTask` (plain sync / non-retained background) anchor
 *      by FRAME PAIRING instead: the runner stamps `sourceTaskId` + `parentToolCallId` together on every
 *      child content event, and the DIRECT child's `parentToolCallId` is THIS delegation's own tool-call
 *      id (a grandchild's frames carry the child's delegation id) — so the provisional lock only seeds
 *      from a matching frame;
 *   3. without either anchor (bare construction — tests/legacy), the first-source lock applies as before.
 * Everything is BOUNDED (step ring ≤ {@link STEP_CAP}, fields truncated) so a pathological child can't
 * balloon the parent's notification/report.
 */
import type { TaskEvent } from "../core/types.js";
/** One completed tool step in the child's tail — enough for the parent to say "you stopped at X". */
export interface SubagentStep {
    /** Tool name (or its distinct {@link ToolSpec.label} when set). */
    tool: string;
    /** The step's primary argument, one line: file path / command / pattern. May be "". */
    target: string;
    /** Result first line — or `error: …` when the tool failed. May be "" (a result that was only an engine
     *  reminder block has no line of its own). The engine's marked reminder blocks are not part of a result. */
    outcome: string;
}
/** A file the child mutated, with how many times (Write/Edit/MultiEdit/NotebookEdit). */
export interface SubagentEditedFile {
    path: string;
    edits: number;
}
/** Keep the last N tool steps (CC's tail is ~this deep; older steps are rarely load-bearing for resume). */
export declare const STEP_CAP = 10;
/** Hard-bound a line to `max` UTF-16 units — a pure prefix, no marker appended. When the cut would split a
 *  redaction marker, it moves back to the marker's start (the bound holds, and the output never shows a
 *  marker fragment); when it would split a surrogate pair, it moves back one unit (never a lone surrogate). */
export declare function cutAt(line: string, max: number): string;
/**
 * Redact, THEN bound — the order every display cut in this module (and the runner's `steering_injected`
 * previews) uses. Exported so a preview minted elsewhere gets the same marker-aware cut rather than a
 * raw `slice` that can leave a half marker at the bound. Keeps newlines: a multi-line body is the
 * caller's shape; only the bound and the redaction are this function's.
 */
export declare function redactThenCut(s: string, max: number): string;
/** The tool's primary argument as a single short line (best-effort; unknown shapes → a compact JSON head). */
export declare function extractTarget(args: unknown): string;
/**
 * Observes a single child's forwarded `TaskEvent`s and derives the residual-observability projection.
 * Feed it every event via {@link record}; read {@link recentSteps}/{@link editedFiles}/{@link currentAction}
 * at report/notify/tick time. Swallow-safe: `record` never throws (an observer must never fault a run).
 */
export declare class SubagentStepRecorder {
    private lockedSource;
    private lockedResolved;
    private readonly parentToolCallId;
    private readonly steps;
    private readonly pending;
    private readonly edits;
    private action;
    private actionTool;
    private actionTarget;
    /**
     * @param parentToolCallId THIS delegation's own tool-call id (`ctx.toolCallId` — the exact value the
     *   spawn threads as `RunInternals.parentToolCallId`, which the runner stamps back onto every direct-child
     *   content event). Used to seed the provisional lock ONLY from a direct-child frame while no explicit
     *   {@link lockTo} anchor is set. Optional: absent falls back to the legacy first-source lock.
     */
    constructor(parentToolCallId?: string);
    /**
     * CORE-2 — explicitly anchor the observed DIRECT child by its taskId (= its sessionId on every
     * delegation lane: `buildChildSpec` never sets `spec.taskId`). Call as soon as the id is known at the
     * spawn site. If events arrived BEFORE the anchor and the provisional lock caught a DIFFERENT source
     * (a grandchild racing through the shared sink), everything recorded so far belongs to the wrong
     * descendant — reset it and re-lock, so the projection never mixes generations.
     */
    lockTo(taskId: string): void;
    /** Drop everything recorded under a mis-locked source (see {@link lockTo}). */
    private resetRecorded;
    /** True when the event belongs to the observed direct child (see the class doc for the 3-tier anchor). */
    private inScope;
    record(e: TaskEvent): void;
    /** The child's last ≤{@link STEP_CAP} completed tool steps; undefined if none observed. */
    recentSteps(): SubagentStep[] | undefined;
    /** Files the child mutated with edit counts; undefined if none. */
    editedFiles(): SubagentEditedFile[] | undefined;
    /** The child's most recent tool intent as one human line ("Bash npm test", "Edit src/x.ts"); undefined if none. */
    currentAction(): string | undefined;
    /** {@link currentAction} pre-formatted into a fleet-view Progress-section
     *  shape — the SAME `{tool, target}` pair `currentAction` already concatenates into one line, exposed
     *  separately so a consumer can look the tool up in its own registry instead of parsing prose.
     *  Undefined if none observed (mirrors {@link currentAction}'s own undefined case exactly). */
    currentActionStructured(): {
        toolName: string;
        target?: string;
    } | undefined;
}
/** One step read back from a session's persisted messages: a {@link SubagentStep} plus WHEN. */
export interface TranscriptStep extends SubagentStep {
    /** Epoch ms: the result message's timestamp when the call has a result, the calling message's when it
     *  has none. Absent when that message carries no finite timestamp. */
    at?: number;
    /** Present (`true`) exactly when the transcript holds the call but no result for it — the call is still
     *  in flight, or the run stopped before its result was recorded. */
    inFlight?: true;
}
/**
 * Residual lane C — derive the last `lastN` tool steps from a session's PERSISTED messages (the pull-model
 * `AgentTranscript` read face). Mirrors {@link SubagentStepRecorder} but sources from committed history
 * instead of the live event stream, so a parent can retrospectively read a child's tail on demand. Walks
 * assistant `toolCall`s paired with the following `toolResult`, oldest→newest, then keeps the last N.
 */
export declare function stepsFromMessages(messages: readonly unknown[], lastN: number): TranscriptStep[];
