import { type Json } from "./protocol.js";
import type { FinalTurn } from "./schedule-watch.js";
import { type TurnRecord } from "./turn-records.js";
/**
 * What a live session's row says about itself beyond Herdr's own status and
 * title, from the pane's turn record (turn-records.ts) and the dispatch label
 * (launch-brief.ts):
 *
 * - A session whose turn ended while work it started still runs is still
 *   working: running sub-agents, teammates, workflow agents and fan-out jobs
 *   (its child tree, Claude and Codex alike), and for Claude the background
 *   shells and monitors started since the owner's last prompt that are not
 *   endless streams (`FinalTurn.awaited`, bounded by its Stop's count less the
 *   tasks finished since, for at most BACKGROUND_STALE_MS). A log tail, a
 *   watcher or a shell left over from an earlier exchange runs on without
 *   anyone waiting for it, so it does not count. Herdr reports such a session
 *   idle, so the phone listed it under IDLE with a moon badge. The tab keeps
 *   `agentStatus: "working"` and gains `backgroundTasks`, the count.
 * - A dispatched worker is named by its dispatch label. Claude and Codex title
 *   a session after its first prompt, which for a brief launch is
 *   "Read and follow the brief in <path>" (or "Brief d35c6189" once they
 *   shorten it), so those titles are never shown.
 */
/** The record, only when it belongs to this pane's terminal and conversation
 * (the guard dispatch returns use): a leftover record of an earlier terminal
 * or session in the same pane must not speak for this one. */
export declare function ownRecord(record: TurnRecord | undefined, pane: Json, source: unknown, session: string | undefined): TurnRecord | undefined;
/** The pane's own turn record. OpenCode has no Stop hook to report background work or a dispatch id here. */
export declare function paneRecord(server: string, pane: Json, session: string | undefined): Promise<TurnRecord | undefined>;
/** How long after its Stop a background count may keep a row working. A task
 * whose finish the transcript never shows (a dev server left running, a
 * persistent monitor, a notification the tail no longer holds) would
 * otherwise keep it working forever. Matches dispatch returns' wait. */
export declare const BACKGROUND_STALE_MS: number;
/** Background tasks the recorded turn ended with that are still running:
 * the Stop's count less those `finishedTasks` (FinalTurn's) says finished
 * after it. Undefined once none are left or the Stop is BACKGROUND_STALE_MS old. */
export declare function recordedBackground(record: TurnRecord | undefined, finishedTasks?: readonly string[], now?: number): number | undefined;
/** The background shells and monitors a turn still awaits, from its transcript
 * final turn. A recorded ended turn bounds `FinalTurn.awaited` by the Stop's
 * count less the tasks that finished since, and by the 2-hour cap; a Stop that
 * named no count leaves the transcript's own awaited shells, and a Stop the
 * Hook never saw falls back to them too. Undefined once none is awaited. A log
 * tail, a watcher or a shell left from an earlier exchange is not awaited, so
 * it never holds a turn open. */
export declare function awaitedShells(record: TurnRecord | undefined, final: FinalTurn | undefined, now?: number): number | undefined;
/** The live work a finished turn still waits on: its awaited shells and
 * monitors plus the running children (sub-agents, teammates, workflows,
 * fan-out jobs) the caller counted. Leftover shells are awaited by neither, so
 * they do not hold a session or a dispatched worker open. */
export declare function liveWork(record: TurnRecord | undefined, final: FinalTurn | undefined, runningChildren?: number, now?: number): number | undefined;
/** Every background task the finished turn left running, awaited or not, less
 * the endless streams (a log tail, a dev server): the Stop's count less the
 * tasks finished since, else the transcript's own count, and nothing once the
 * Stop is BACKGROUND_STALE_MS old. A turn whose reply says it waits on such a
 * task is still working, and a pane running one is not closed. */
export declare function runningTasks(record: TurnRecord | undefined, final: FinalTurn | undefined, now?: number): number;
/** The background shells and monitors a pane's ended Claude turn is waiting
 * on (`FinalTurn.awaited`), at most `recordedBackground`. Reads the transcript
 * (`readFinalTurn`, passed in: schedule-watch imports herdr, which imports
 * this) only when the Stop left background work; only Claude's Stop reports
 * a count. Sub-agents are not in it: the overview adds its running children.
 * An unreadable transcript counts nothing, since the Stop's count alone
 * cannot tell a build from a log tail. */
export declare function liveBackground(record: TurnRecord | undefined, readFinal: (source: "claude", session: string) => Promise<FinalTurn | undefined>, now?: number): Promise<number | undefined>;
/**
 * Marks a tab whose main turn ended but whose background work continues:
 * an idle or done tab becomes `working` with `backgroundTasks: count`. Called
 * again with a fuller count (the awaited shells plus the running children,
 * once the child tree is read), it keeps the larger. A tab that is working,
 * blocked or waiting on its own is left alone, so `backgroundTasks` never
 * sits on a tab with a live turn.
 */
export declare function markBackground(tab: Json, count: number | undefined): void;
/** How much of a turn's last reply a session row carries. */
export declare const REPLY_EXCERPT_CHARS = 240;
/**
 * The ended turn's last reply as one short line for a session row
 * (`lastReply`): what the agent said before it stopped, so a waiting row can
 * say what it waits for. Markdown emphasis, headings and code fences are
 * dropped and whitespace collapsed. Undefined while a turn runs (its prompt
 * is newer than the Stop) or when the Stop carried no reply.
 */
export declare function replyExcerpt(record: TurnRecord | undefined): string | undefined;
/** A tab or workspace label worth showing as a name: not empty, not Herdr's bare numbering, not an id. */
export declare function meaningfulLabel(value: unknown): string | undefined;
/** A terminal title without the spinner or status glyphs around it, nor the
 * separator they leave dangling (Codex's "⠸ | phren" before its thread has a
 * title); undefined when nothing else is left. */
export declare function plainTitle(value: unknown): string | undefined;
/** A harness title made from the brief launch's first prompt rather than the work: the prompt itself, the brief path, or "Brief <id>". */
export declare function isBriefTitle(title: string): boolean;
/**
 * The name a session is shown under, first that applies:
 * 1. the agent pane's own label, when meaningful (a rename from the phone or
 *    from Herdr or tmux itself; a pane has none until someone sets one);
 * 2. the dispatch label its dispatcher gave it;
 * 3. for a dispatch with no stored label (sent before labels were kept), the
 *    tab label, else the workspace label, when meaningful;
 * 4. the harness's own title, unless it is brief boilerplate, which is
 *    replaced by a meaningful tab or workspace label or dropped (the phone
 *    then falls back to the label).
 * Never leaves a row blank: when none applies and `fallbackLabel` (passed, even
 * if undefined) is the label the phone shows without a title and is blank, the raw harness title stands.
 */
export declare function sessionTitle(input: {
    dispatched: boolean;
    paneLabel?: unknown;
    dispatchLabel?: string;
    harnessTitle?: unknown;
    tabLabel?: unknown;
    workspaceLabel?: unknown;
    fallbackLabel?: unknown;
}): string | undefined;
/** `sessionTitle` for a pane, given its own turn record (the guarded one from `paneRecord`). */
export declare function recordTitle(record: TurnRecord | undefined, input: {
    paneLabel?: unknown;
    harnessTitle?: unknown;
    tabLabel?: unknown;
    workspaceLabel?: unknown;
    fallbackLabel?: unknown;
}): Promise<string | undefined>;
