import type { BackgroundJobRegistryRef } from '../../types/tool/index.js'; /** * Waiting on a background job, bounded by two different questions — the * shell-job counterpart to `waitForTaskWithBounds` * (`../coordinator/wait-with-idle-bound.ts`), which this mirrors. * * A delegated agent task reports its own progress through * `TaskScheduler.onTaskProgress`. A shell job has no such channel: the only * signal it ever produces is bytes on stdout/stderr. So where the task * version resets its idle clock on a progress EVENT, this one resets it on * OBSERVED OUTPUT GROWTH — read on every tick, compared against the last * tick's offset. A tick that finds nothing new is not progress; treating it * as progress would make the idle bound unable to fire for a wedged job at * all, which is the exact failure this exists to catch. * * - the **wall-clock bound** counts elapsed time and is never refreshed. It * exists for a job that stays busy forever (a server, a stuck build). * - the **idle bound** counts time since output last grew, and resets * whenever it does. It exists for a job that stopped producing anything * without exiting. * * Neither bound cancels the job. A wait that ran out is a statement about * the WAITER, not the work — the job keeps running, and its output is still * there to read with `job` or a later `wait_for_job` call. */ export interface JobWaitOptions { /** Elapsed-time ceiling, never refreshed. */ readonly wallMs: number; /** * Time-without-new-output ceiling, refreshed whenever `read` returns * more than it did last tick. Omit to bound by the turn clock alone. */ readonly idleMs?: number; /** Resume from here rather than the start of what the job has retained. */ readonly fromOffset?: number; /** Stop preempts a wait that has not resolved yet; the job is untouched. */ readonly signal?: AbortSignal; } interface JobWaitProgress { readonly output: string; readonly nextOffset: number; readonly droppedBytes: number; } export type JobWaitOutcome = ({ readonly kind: 'exited'; readonly status: string; readonly exitCode?: number; } & JobWaitProgress) | ({ readonly kind: 'timeout'; /** Which clock ran out. */ readonly cause: 'idle' | 'wall'; readonly elapsedMs: number; } & JobWaitProgress); /** * Await a job under both bounds, accumulating its output as it goes. * * Returns the output gathered so far either way: a completed wait has all * of it, and a timed-out one has everything read up to the moment it gave * up, so the caller never has to throw away a partial answer. */ export declare function waitForJobWithBounds(jobs: Pick, id: string, options: JobWaitOptions, now?: () => number): Promise; /** What to tell the model, in the words that fit what actually happened. */ export declare function describeJobWaitTimeout(id: string, outcome: Extract): string; export {}; //# sourceMappingURL=wait-for-job-bounds.d.ts.map