/** One process row: its parent, cumulative CPU seconds, and command name. */ export interface ProcRow { pid: number; ppid: number; cpuSec: number; comm: string; } /** The two OS reads the sampler needs, injectable for tests. */ export interface ProcessProbe { /** Every process on the host (or at least this daemon's subtree). */ table: () => Promise; /** The working directory of each pid that has a readable one. */ cwds: (pids: number[]) => Promise>; } /** CPU share of one core, over the time since the previous sample, that reads as busy. An idle * node CLI waiting on a model sits well under 1 %; a test runner or compiler burns 50-100 %+. */ export declare const BUSY_CPU_SHARE = 0.05; /** * Parses `ps -o time=` (`[[dd-]hh:]mm:ss[.cc]`, macOS and procps alike) to seconds; NaN when * the field is not a CPU time. */ export declare function parseCpuTime(raw: string): number; /** The host probe: `ps` everywhere POSIX, cwd via lsof (macOS) or /proc (Linux). */ export declare const hostProcessProbe: ProcessProbe; /** The two reads {@link lsofCwds} makes, injectable for tests: each answers its stdout ('' on any failure). */ export interface LsofReads { lsof: (pids: number[]) => Promise; ps: (pids: number[]) => Promise; } /** * The working directory of each of `pids` through `lsof` (macOS). `lsof` exits 1 when one of the pids * has gone, so its exit code proves nothing, and it prints NOTHING when every pid it was given has * exited between the `ps` read and this one — short-lived floor and test children do (crew#1193). So an * empty answer is checked against `ps`, with this daemon's own pid as the sentinel that the `ps` read * itself worked: every pid gone ⇒ no processes (an empty map, a good read); some still alive ⇒ `lsof` * is asked again about those alone, and an empty answer then is a failed read (crew#972, xreview). */ export declare function lsofCwds(pids: number[], reads: LsofReads, selfPid?: number): Promise>; /** One seat container's CPU reading: its name and its CPU share of one core, as a fraction. */ export interface ContainerCpu { name: string; cpuShare: number; } /** The container-runtime read the sampler needs (crew#972), injectable for tests. */ export interface ContainerProbe { /** The running seat containers (`wicked-seat-…`) with their CPU share; `[]` when none or no * runtime is installed; `null` when a runtime exists but could not be read (an unknown). */ seats: () => Promise; } /** * The prefix of a busy reading that is an UNKNOWN, not a proof of life (crew#972): the seat * containers could not be read. The 15/30-minute ladder treats it as not busy (as before the * container read existed); the silent-turn rung never acts on it. */ export declare const BUSY_UNKNOWN_PREFIX = "unknown: "; /** * The container runtime the engine would use (wicked-core `container_floor::runtime_candidates`): * `WICKED_CONTAINER_RUNTIME` when set (the only candidate), else docker / podman / nerdctl on PATH, * else the desktop install dirs a daemon's PATH often lacks. `null` = none found. */ export declare function containerRuntimeCandidates(env?: NodeJS.ProcessEnv, exists?: (p: string) => boolean, home?: string): string[]; /** (tests) Forget the cached runtime. */ export declare function resetContainerRuntimeCache(): void; export declare function containerRuntime(candidates?: string[], answers?: (rt: string) => Promise): Promise<{ runtime: string | null; installed: boolean; }>; /** `12.34%` → 0.1234; NaN when the field is not a percentage. */ export declare function parseCpuPercent(raw: string): number; /** The host probe: ` ps` for the seat containers, then one `stats --no-stream` over them. */ export declare const hostContainerProbe: ContainerProbe; /** A run id as the engine spells it in a seat container name: its first 8 ASCII alnum chars, lowercased. */ export declare function containerRunTag(runId: string): string; /** The run a seat container belongs to (`wicked-seat----`), read off the fixed suffix. */ export declare function runOfContainer(name: string, runIds: readonly string[]): string | undefined; /** The directory the engine makes its guarded floor checkouts in (`std::env::temp_dir()/…`). */ export declare const FLOOR_CHECKOUT_PARENT = "wicked-core-floor"; /** * The run `cwd` belongs to: a path segment that IS a run id (`…/wicked-worktrees//…`), or a * guarded floor checkout (`…/wicked-core-floor/--a--/…`) whose parsed * owner is a run id. Never a prefix or substring: `-tests` is another run. */ export declare function runOfCwd(cwd: string, runIds: readonly string[]): string | undefined; /** * Samples which runs have busy processes. Stateful: CPU is compared with the previous sample of * the same pid, so the first sample of a process is a baseline and never reads as busy. */ export declare class RunLivenessSampler { private readonly probe; private readonly rootPid; private readonly now; /** (crew#972) The seat containers' read; `null` = host processes only. */ private readonly containers; private prev; constructor(probe?: ProcessProbe, rootPid?: number, now?: () => number, /** (crew#972) The seat containers' read; `null` = host processes only. */ containers?: ContainerProbe | null); /** * For each of `runIds` whose processes burned at least {@link BUSY_CPU_SHARE} of a core since the * previous sample: the run id → a short description of the busiest process (`vitest pid 812`). */ busy(runIds: readonly string[]): Promise>; } //# sourceMappingURL=run-liveness.d.ts.map