import { type CleanupReport, type JobSource, type ProcessLike, type TrackedJob } from "./job-registry.js";
/**
 * This computer's live resources for `GET /v1/resources`, the overview
 * stream's `resources` frames and the memory-free `phren computers` surface:
 * load against cores, memory, free disk on the home volume, battery, uptime
 * and the heavy jobs (simulators, emulators, xcodebuild, Gradle, agent
 * workers) with the pane that started them where one did; any other program
 * holding half a core or more across its processes shows as `busy`. macOS reads
 * sysctl, pmset and ps; Linux reads /proc, /sys and ps. Nothing here needs a
 * permission the Hook does not already have.
 */
export declare const RESOURCES_MAX_AGE_MS: number;
/** Below this much free disk, or above twice the cores in load, a computer is stressed. */
export declare const LOW_DISK_BYTES: number;
export type HeavyKind = "simulator" | "emulator" | "xcodebuild" | "gradle" | "java" | "codex" | "opencode" | "claude" | "busy";
export interface PaneRef {
    server: string;
    workspace?: string;
    pane: string;
    agent?: string;
    label?: string;
}
export interface HeavyProcess {
    kind: HeavyKind;
    name: string;
    pid: number;
    /** OS processes, including helpers; never a count of agents or working sessions. */
    processes: number;
    cpuPercent: number;
    memoryBytes: number;
    /** Why this process group is listed; resource use does not establish session activity. */
    resourceReason?: "cpu" | "memory" | "tracked";
    /** The harness that owns the job, when a pane or a registered group says so. */
    agent?: string;
    /** True when the group is one the Hook registered for a dispatched worker. */
    tracked?: boolean;
    pane?: PaneRef;
}
export interface ComputerResources {
    collectedAt: string;
    platform: string;
    uptimeSeconds: number;
    cpu: {
        cores: number;
        load1: number;
        load5: number;
        load15: number;
        loadPerCore: number;
    };
    memory: {
        totalBytes: number;
        availablePercent?: number;
        pressure?: "normal" | "warn" | "critical";
        swapUsedBytes?: number;
    };
    disk?: {
        path: string;
        totalBytes: number;
        freeBytes: number;
    };
    battery?: {
        percent: number;
        charging: boolean;
        onAC: boolean;
    };
    hardware?: ComputerHardware;
    heavy: HeavyProcess[];
    /** 0 idle to 1 saturated, per resource and overall (the highest), so every client fills its gauge the same way. */
    pressure: {
        cpu: number;
        memory: number;
        disk: number;
        overall: number;
    };
    level: "ok" | "busy" | "stressed";
    warnings: Array<"load-high" | "memory-low" | "disk-low" | "battery-low">;
}
/** What the computer is, read once per Hook run: "MacBook Pro", "Apple M1 Max",
 * 32 GB; on Linux the DMI vendor and product ("Dell XPS 13 9310") and the CPU's
 * model name. Never a serial number or any other identifier. */
export interface ComputerHardware {
    model?: string;
    chip?: string;
    memoryBytes: number;
    cores: number;
}
/** `system_profiler SPHardwareDataType -json` → model and chip. Intel Macs name
 * the processor in `cpu_type` instead of `chip_type`. */
export declare function parseMacHardware(json: string): Pick<ComputerHardware, "model" | "chip">;
/** DMI vendor and product → "Dell XPS 13 9310", "Lenovo ThinkPad X1 Carbon";
 * placeholder strings firmware leaves in are dropped. */
export declare function linuxModel(vendor: string | undefined, product: string | undefined, version?: string): string | undefined;
/** /proc/cpuinfo's first `model name`, without the (R)/(TM) marks, "CPU" and clock. */
export declare function linuxChip(cpuinfo: string): string | undefined;
/** Read once; the answer can't change while the Hook runs. */
export declare function computerHardware(platform?: NodeJS.Platform): Promise<ComputerHardware>;
/** A `ps` row; `pgid` is the process group the job registry attributes work by. */
export interface ProcessRow extends ProcessLike {
    cpu: number;
    rssKB: number;
    command: string;
    args: string;
}
/** `ps -axo pid=,ppid=,pgid=,pcpu=,rss=,comm=` paired with the `args=` listing by
 * pid. The older five-column stats (no pgid) still parse, with pgid 0. */
export declare function parsePs(stats: string, args: string): ProcessRow[];
/** What kind of heavy job a process is, if any. */
export declare function heavyKind(row: ProcessRow): {
    kind: HeavyKind;
    name: string;
} | undefined;
/**
 * The heavy jobs in a process table. Every process counts toward its nearest
 * heavy ancestor-or-self, so a Codex worker running xcodebuild shows both,
 * each with only its own share. Any other program shows as `busy` when its
 * processes together hold half a core. Known programs below both a core's
 * tenth and 200 MiB are left out, including simulators and emulators.
 * A memory-only row can be an idle session or helper; it is not evidence of
 * agent activity. Counts include OS helpers, not just the named executable.
 * On Linux, ps pcpu is a process lifetime average, so these cutoffs can miss
 * daemons that spike briefly.
 */
export declare function heavyProcesses(rows: ProcessRow[], owners?: Map<number, PaneRef>, jobs?: readonly TrackedJob[], limit?: number): HeavyProcess[];
/** `pmset -g batt`: "Now drawing from 'AC Power'" then " -InternalBattery-0 (id=…)	87%; charging; …". */
export declare function parsePmset(output: string): ComputerResources["battery"];
/** `sysctl vm.swapusage`: "total = 2048.00M  used = 798.50M  free = …". */
export declare function parseSwap(output: string): number | undefined;
/** /proc/meminfo: MemTotal, MemAvailable and swap, in kB. */
export declare function parseMeminfo(text: string): ComputerResources["memory"];
/** Gauge fill and warnings from the numbers. */
export declare function assess(value: Omit<ComputerResources, "pressure" | "level" | "warnings">): Pick<ComputerResources, "pressure" | "level" | "warnings">;
/** Seconds from `ps`'s `etime` (`[[dd-]hh:]mm:ss`), or undefined. */
export declare function parseEtime(value: string): number | undefined;
/** Each row's start time (epoch ms, to about a second) from a `pid=,etime=`
 * listing. The job registry checks a process group's leader by it, so a group
 * id the system reused for another program is never signalled. */
export declare function withStartTimes(rows: ProcessRow[], elapsed: string, now: number): ProcessRow[];
/** Every pane of every terminal server this computer knows, or undefined when
 * any server's snapshot could not be read. Cleanup ends a job only when its
 * pane is missing from a complete listing: a pane that merely failed to
 * answer, or sat past a display cap, must never look gone. */
export declare function livePanes(): Promise<{
    panes: Set<string>;
    servers: Set<string>;
} | undefined>;
/** Every pid a Herdr or tmux pane holds (its shell and foreground), for naming a job's pane. */
export declare function paneOwners(): Promise<Map<number, PaneRef>>;
export interface ResourceDeps {
    platform: NodeJS.Platform;
    now: () => number;
    home: () => string;
    processes: () => Promise<ProcessRow[]>;
    owners: () => Promise<Map<number, PaneRef>>;
    /** Every live pane and the servers listed, or undefined when the listing is incomplete (see `livePanes`). */
    panes: () => Promise<{
        panes: Set<string>;
        servers: Set<string>;
    } | undefined>;
    hardware?: () => Promise<ComputerHardware | undefined>;
    jobs?: JobSource;
}
export declare function collectResources(deps: ResourceDeps): Promise<ComputerResources>;
/** One collection at a time, reused for `RESOURCES_MAX_AGE_MS`. */
export declare class ResourceMonitor {
    private maxAgeMs;
    private cached?;
    private pending?;
    private readonly deps;
    private readonly registry;
    constructor(deps?: Partial<ResourceDeps>, maxAgeMs?: number);
    read(): Promise<ComputerResources>;
    /**
     * End only the registered process groups whose owning pane is gone. The
     * registry (job-registry.ts) does the safety checks; a failed pane read ends
     * nothing. Never the Hook's own service, never an owner's session, never an
     * unregistered process.
     */
    cleanupJobs(): Promise<CleanupReport>;
}
