import type { BashOperations } from "@earendil-works/pi-coding-agent"; import type { PiShellToolName } from "./pi-tools.js"; import { type ShellMonitorOptions, type ShellMonitorBatch } from "./shell-monitor.js"; import { type ShellReplayPage } from "./shell-replay.js"; import type { DurableShellBridge } from "../jev-fabric/bridge.js"; export { DEFAULT_SHELL_HANG_MS, SHELL_HANG_MAX_MS } from "./shell-limits.js"; export declare const SHELL_TAIL_BYTES: number; export declare const SHELL_LOG_BYTES: number; export declare const SHELL_COMPLETED_HANDLES = 256; /** Output kept readable by offset after a task finishes, like jev-fabric's 32 KiB receipt tails. */ export declare const SHELL_FINISHED_READ_BYTES: number; /** Largest single tasks.read page. */ export declare const SHELL_READ_MAX_BYTES: number; /** * One page of a task's combined output by byte offset, in jev-fabric's read * record shape. Offsets count every byte since launch and never reset; bytes * that left the retained window are disclosed in `omittedBytes`. */ export interface FabricShellReadRecord { id: string; stream: "output"; offset: number; bytes: number; omittedBytes: number; text?: string; data?: string; next: number; eof: boolean; state: FabricShellJobStatus; } export declare const wrapShellCommandForPid: (command: string, pidPath: string, tool: PiShellToolName) => string; export declare const formatShellHangNotice: (input: { elapsedMs: number; pid?: number; logPath: string; /** Set once the handed-off process has already ended; `null` when it left no exit code. */ exitCode?: number | null; }) => string; export declare const appendShellHangNotice: (output: string, notice: string) => string; export declare const parseShellPid: (text: string) => number | undefined; /** Shell tools, plus `fabric_exec` programs moved to the background. */ export type FabricTaskTool = PiShellToolName | "fabric_exec" | "monitor"; type FabricShellJobStatus = "running" | "spilled" | "exited" | "failed" | "killed" | "timed_out"; /** A task whose process is owned by a jev-fabric store, not this Pi process. */ export interface FabricDurableTaskInfo { home: string; /** jev-fabric job ID once `start` has returned. */ jobId?: string; /** Reattached after a restart or from another harness, rather than launched here. */ adopted?: boolean; } export interface FabricShellJobOptions { /** Stable task ID when reattaching a durable task; otherwise random. */ id?: string; /** Original start time when reattaching a durable task. */ startedAt?: number; durable?: FabricDurableTaskInfo; cwd?: string; ownerId?: string; description?: string; monitor?: ShellMonitorOptions; /** An observer task owns its subscription, never the target process or participant. */ observes?: { kind: "task" | "participant"; id: string; }; } export interface FabricShellJobEvent { type: "started" | "spilled" | "monitor" | "finished" | "acknowledged" | "stopping"; job: FabricShellJobInfo; output?: string; } export interface FabricShellJobInfo { id: string; tool: FabricTaskTool; command: string; pid?: number; logPath?: string; startedAt: number; spilledAt?: number; finishedAt?: number; status: FabricShellJobStatus; exitCode?: number | null; cwd?: string; ownerId?: string; description?: string; lastOutputAt?: number; monitor?: ShellMonitorOptions; observes?: { kind: "task" | "participant"; id: string; }; lastEvent?: ShellMonitorBatch & { at: number; }; durable?: FabricDurableTaskInfo; eventCount: number; unread: boolean; stopping: boolean; } export interface FabricShellJobHandle { readonly id: string; readonly tool: FabricTaskTool; readonly command: string; readonly abort: AbortController; readonly detached: AbortController; readonly durable: FabricDurableTaskInfo | undefined; readonly startedAt: number; readonly pidPath: string; pid?: number; logPath?: string; exitCode?: number | null; spilled: boolean; finished: boolean; append(data: Buffer): void; snapshotText(maxBytes?: number): string; persistLog(): Promise; readPid(): Promise; spill(): void; whenSpill(): Promise; finish(exitCode?: number | null, footer?: string): Promise; } declare class FabricShellJob implements FabricShellJobHandle { #private; readonly onChange: (type: FabricShellJobEvent["type"], output?: string) => void; readonly options: FabricShellJobOptions; readonly id: string; readonly tool: FabricTaskTool; readonly command: string; readonly abort: AbortController; /** Aborted when this session lets go of a durable process without stopping it. */ readonly detached: AbortController; readonly startedAt: number; readonly pidPath: string; readonly durable: FabricDurableTaskInfo | undefined; pid?: number; logPath?: string; spilled: boolean; finished: boolean; spilledAt?: number; finishedAt?: number; exitCode?: number | null; status: FabricShellJobStatus; lastOutputAt?: number; lastEvent?: ShellMonitorBatch & { at: number; }; unread: boolean; get eventCount(): number; constructor(tool: FabricTaskTool, command: string, onChange: (type: FabricShellJobEvent["type"], output?: string) => void, tempRoot: string, options?: FabricShellJobOptions); /** Subscribe from now; retained output is available separately through read(). */ observeOutput(observer: (data: Buffer) => void): () => void; flushMonitor(final?: boolean): void; /** Structured observer events bypass the optional stdout filter. */ recordMonitorEvent(batch: ShellMonitorBatch, retain?: boolean, notify?: boolean): void; stop(reason?: string): boolean; /** Pages retained monitor lines after a cursor, disclosing lost positions. */ replay(after: number): ShellReplayPage; /** Releases a durable process to its jev-fabric store; it keeps running. */ detach(): void; acknowledge(): void; append(data: Buffer): void; /** Bytes appended since launch: the cursor just past the newest output. */ get written(): number; /** Reads combined output from a byte offset; never blocks and never consumes. */ read(offset: number, max?: number, encoding?: "text" | "base64"): FabricShellReadRecord; /** Resolves when output past `offset` exists or the task finishes; never stops the task. */ whenOutput(offset: number, timeoutMs: number, signal?: AbortSignal): Promise; snapshotText(maxBytes?: number): string; persistLog(): Promise; readPid(): Promise; spill(): void; whenSpill(): Promise; finish(exitCode?: number | null, footer?: string): Promise; outputText(maxBytes?: number): Promise; info(): FabricShellJobInfo; } export declare const trackShellOperations: (inner: BashOperations, job: FabricShellJobHandle, tool: PiShellToolName) => BashOperations; export declare class FabricShellJobStore { #private; readonly tempRoot: string; /** Optional jev-fabric backend for durable tasks; absent on Windows and managed hosts. */ durable: DurableShellBridge | undefined; subscribe(listener: (event: FabricShellJobEvent) => void): () => void; constructor(tempRoot?: string); begin(tool: FabricTaskTool, command: string, options?: FabricShellJobOptions): FabricShellJob; /** Event-driven, bounded observation. Timeout/cancellation never stops the job. */ waitFor(id: string, options: { after?: number; timeoutMs: number; signal?: AbortSignal | undefined; }): Promise<{ task: FabricShellJobInfo; timedOut: boolean; }>; stop(id: string): boolean; acknowledge(id: string): void; get(id: string): FabricShellJob | undefined; list(): FabricShellJobInfo[]; waiting(): FabricShellJob[]; live(): FabricShellJob[]; spillWaiting(): number; killWaiting(): number; close(): Promise; } /** An active observer owns notifications; its terminal receipt also deduplicates a racing source completion. */ export declare function hasWakeObserver(jobs: FabricShellJobStore, kind: "task" | "participant", id: string): boolean; export declare const raceShellHang: (options: { execute: (signal: AbortSignal) => Promise; parentSignal: AbortSignal | undefined; hangMs: number; immediate?: boolean; job: FabricShellJobHandle; }) => Promise<{ status: "done"; value: T; } | { status: "error"; error: unknown; } | { status: "spilled"; }>; //# sourceMappingURL=shell-jobs.d.ts.map