/**
 * Device resource probing for `agents devices list`.
 *
 * One SSH round-trip per device gathers load average, memory pressure, disk, and core
 * count (mac + linux via a POSIX snippet, windows via a CIM one-liner), parsed
 * into a {@link DeviceStats}. Probes run in parallel with a bounded timeout so
 * the list stays responsive — a slow or hung box degrades to "no stats" instead
 * of blocking the whole table.
 *
 * The parsers are pure and unit-tested (health.test.ts). They mirror the ones in
 * AGI EXT (apps/ext/src/core/deviceHealth.ts) — kept as a
 * separate copy on purpose: the CLI does not import across packages.
 */
import type { DeviceProfile } from './registry.js';
/** Default per-device probe budget, for a device reachable over a DIRECT
 * Tailscale path. Short enough that the list never hangs on a wedged box. */
export declare const PROBE_TIMEOUT_MS = 2500;
/**
 * Probe budget for a device whose last handshake was DERP-relayed
 * ({@link DeviceTailscale.direct} === false).
 *
 * This constant used to not exist: 2.5s was applied to every device and its
 * docstring claimed to be "long enough for a cold relayed SSH handshake". That
 * was false, and on a fleet with no direct paths it broke `--device auto`
 * outright (PHNX-3682). Measured on a 9-box relayed fleet, probed in parallel
 * with cold paths: 1686/1805/1914/2688/2706/2749/3082/5586/6588 ms — six of nine
 * over budget, every one of them healthy (rc=0 within 10s). Warm, the same
 * probes take 512-872ms, which is what made the failure intermittent.
 *
 * A relayed hop pays DERP path setup on top of the TCP+SSH handshake, so it
 * gets the same budget the readiness probe already allows
 * (`READY_PROBE_TIMEOUT_MS`) rather than the direct-path one.
 */
export declare const RELAYED_PROBE_TIMEOUT_MS = 8000;
/**
 * The probe budget for one device. A relayed peer gets
 * {@link RELAYED_PROBE_TIMEOUT_MS}; a direct (or unknown-path) peer keeps the
 * tight {@link PROBE_TIMEOUT_MS}. Windows keeps its own larger budget, which
 * already exceeds both.
 *
 * `direct` is only meaningful when a tailscale snapshot exists — a
 * `via:"manual"` device never gets a peer entry, so absence is "unknown path",
 * not "relayed", and must not silently widen every manual device's budget.
 */
export declare function probeBudgetMs(device: DeviceProfile): number;
/** Windows probe budget. The first CIM query of a PowerShell session pays a
 * "Preparing modules for first use" cost on top of PowerShell startup, which
 * routinely blows the 2.5s POSIX budget on a relayed connection. */
export declare const WIN_PROBE_TIMEOUT_MS = 6000;
/** One-shot remote snapshot: load, memory, core count, then root filesystem. */
export declare const PROBE_SNIPPET = "uptime; echo ---AGSTAT---; (vm_stat 2>/dev/null || cat /proc/meminfo 2>/dev/null); echo ---AGSTAT---; (nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null); echo ---AGSTAT---; df -Pk / 2>/dev/null | tail -1";
/** Windows equivalent, one labeled line via CIM. PowerShell 5.1-safe: no `||`
 * chaining, plain string concatenation. `LoadPercentage` is $null on some
 * hosts/VMs, which concatenates to an empty field — the parser treats that as
 * "no load signal" and headroom falls back to memory pressure alone.
 * wrapRemoteCommand base64-encodes this for powershell-shell devices, so the
 * quoting survives ssh intact. */
export declare const WIN_PROBE_SNIPPET = "$os = Get-CimInstance Win32_OperatingSystem; $cpu = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average; $disk = Get-CimInstance Win32_LogicalDisk -Filter \"DeviceID='C:'\"; Write-Output ('AGWINSTAT load=' + $cpu + ' freeKb=' + $os.FreePhysicalMemory + ' totalKb=' + $os.TotalVisibleMemorySize + ' ncpu=' + $env:NUMBER_OF_PROCESSORS + ' diskFreeKb=' + ($disk.FreeSpace / 1KB) + ' diskTotalKb=' + ($disk.Size / 1KB))";
export declare function localProbeInvocation(platform: NodeJS.Platform): {
    file: string;
    args: string[];
};
export interface DeviceStats {
    host: string;
    reachable: boolean;
    /**
     * The probe exceeded its budget rather than being refused or unresolvable.
     * Only meaningful when `reachable` is false — it separates "this box did not
     * answer in time" from "this box actively could not be reached", so callers
     * report a slow link honestly instead of calling a healthy device offline
     * (PHNX-3682).
     */
    timedOut?: boolean;
    loadAvg1?: number;
    ncpu?: number;
    /** Load normalized to core count (the "has room" number): loadAvg1 / ncpu *
     * 100 on mac/linux, CPU utilization % directly on windows (no loadAvg1). */
    loadPercent?: number;
    memPercent?: number;
    memTotalBytes?: number;
    memFreeBytes?: number;
    diskTotalBytes?: number;
    diskFreeBytes?: number;
    diskUsedPercent?: number;
    /** When the static ncpu/RAM/disk totals were last observed. */
    specsFetchedAt?: number;
    fetchedAt: number;
}
/** Compact human byte size: 512M, 64G, 1.5T (binary units, ≤1 decimal). */
export declare function fmtBytes(bytes: number | undefined): string;
export declare function parseUptime(out: string): {
    loadAvg1?: number;
};
interface MemStats {
    memPercent?: number;
    memTotalBytes?: number;
    memFreeBytes?: number;
}
export declare function parseVmStat(out: string): MemStats;
export declare function parseLinuxMemInfo(out: string): MemStats;
export declare function parseNcpu(out: string): {
    ncpu?: number;
};
interface DiskStats {
    diskTotalBytes?: number;
    diskFreeBytes?: number;
    diskUsedPercent?: number;
}
/** Parse the final data row from `df -k /`, deriving usage from block counts. */
export declare function parseDf(out: string): DiskStats;
/** Assemble a DeviceStats from the four snippet sections. */
export declare function parseProbeOutput(host: string, stdout: string, fetchedAt: number): DeviceStats;
/** Assemble a DeviceStats from the windows one-liner. A missing marker line
 * (e.g. CIM unavailable) keeps `reachable: true` — ssh answered — with no
 * numbers, mirroring how garbage POSIX output degrades. */
export declare function parseWinProbeOutput(host: string, stdout: string, fetchedAt: number): DeviceStats;
export interface FleetCapacity {
    reachable: number;
    cores: number;
    memTotalBytes: number;
    memFreeBytes: number;
}
/** Sum cores and memory across reachable devices for the summary footer. */
export declare function fleetCapacity(statsList: Iterable<DeviceStats>): FleetCapacity;
/** Headroom bucket from the worst of normalized-load and memory. */
export type Headroom = 'idle' | 'light' | 'busy' | 'loaded' | 'unknown';
export declare function headroom(stats: DeviceStats | undefined): Headroom;
/** Probe one device over the same ssh path as `agents ssh <name>`. Never throws;
 * an unreachable/slow/misconfigured device resolves to `reachable: false`. */
export declare function probeDeviceStats(device: DeviceProfile, opts?: {
    timeoutMs?: number;
    now?: number;
}): Promise<DeviceStats>;
/** Probe the local machine directly (no ssh round-trip) — used for the "this
 * machine" row so it always shows real numbers even if it isn't ssh-reachable
 * from itself. */
export declare function probeLocalStats(host: string, opts?: {
    timeoutMs?: number;
    now?: number;
}): Promise<DeviceStats>;
/** Probe many devices concurrently; returns a name→stats map. Bounded by the
 * per-probe timeout, so total wall time ≈ the slowest single probe. The device
 * named `selfName` is probed locally instead of over ssh. */
export declare function probeFleetStats(devices: DeviceProfile[], opts?: {
    timeoutMs?: number;
    selfName?: string;
}): Promise<Map<string, DeviceStats>>;
export {};
