/** * `GET /api/v1/system` — the Nerve Center snapshot (DES-SYSTEM-VIEW, api-types 0.136.0). * * One derived, READ-ONLY answer to "is anything stopping work, why, and what fixes it?": the CLIs * with their 7-day record, every unfinished run with a COMPUTED liveness, the infrastructure as * real probes, the governance instruments, and `attention[]`, the union of every item that needs a * look. The honesty rules this module keeps: * * - every infra row is a probe run for THIS request under a bounded timeout. A probe that does not * answer reads `unknown` with its timeout — never `ok`, and never a cached flag; * - `working` needs evidence (an event on the relay or in the durable log, or a busy child process) * inside the quiet threshold; past the stall threshold the run is `stalled`; * - a number the daemon cannot count is `null` (or the field is absent where the wire says so); * - the whole snapshot answers inside {@link SYSTEM_BUDGET_MS} even when a probe hangs. * * Everything here is a pure function of injected readers, so the tests drive each state and each * liveness verdict from fixtures; `routes.ts` wires the daemon's real readers. */ import type { AcpCliDiagnostics, DiagnosticsSeatGovernanceEntry, RecordedEvent, SeatHealth, SessionView, SystemAttentionItem, SystemCli, SystemCliStats, SystemGovernanceCard, SystemInfraKey, SystemInfraRow, SystemRun, SystemSnapshot, SystemState, SystemUnresolvedItem } from '../core/types.js'; /** The whole snapshot answers within this, even when probes hang. */ export declare const SYSTEM_BUDGET_MS = 8000; /** Each infra probe's own bound. */ export declare const PROBE_TIMEOUT_MS = 4000; /** The 7-day folds are real IO over every recent run's log; they are kept this long (`asOf`). */ export declare const SYSTEM_STATS_TTL_MS = 30000; /** The window the CLI stats and governance cards fold. */ export declare const SYSTEM_STATS_DAYS = 7; /** Runs read for the folds at most (newest first), as `GET /roster/record` caps. */ export declare const SYSTEM_STATS_RUN_CAP = 200; export type Settled = { kind: 'ok'; value: T; ms: number; } | { kind: 'timeout'; ms: number; } | { kind: 'error'; error: string; ms: number; }; /** Run `fn` against `timeoutMs`. A hang settles as `timeout` (the work may continue; nothing waits). */ export declare function settleWithin(fn: () => Promise, timeoutMs: number): Promise>; export type ExecLike = (file: string, args: string[], opts: { timeout: number; }) => Promise<{ stdout: string; stderr: string; }>; export declare function infraRow(key: SystemInfraKey, state: SystemState, reason: string, remedy: string | null, startedAt: number, details?: Record, timeoutMs?: number): SystemInfraRow; /** The engine's gateway container name: `wicked-agw-` + the first 6 bytes (hex) of the SHA-256 of the * gateway directory, exactly `seat_gateway.rs` `gateway_name`. */ export declare function gatewayName(gatewayDir: string): string; /** The container runtime CLI the engine would use (`container_floor.rs` `runtime_candidates`): * `WICKED_CONTAINER_RUNTIME` (the only candidate when set), else docker / podman / nerdctl on PATH, * else the desktop install dirs. `null` when none is found. */ export declare function resolveContainerRuntime(env?: NodeJS.ProcessEnv): string | null; export interface GatewayProbeInput { /** Whether the container seat floor is on (only then does a gateway exist). */ containerFloor: boolean; /** The engine's gateway dir (canonical state home + `gateway`); `null` without a store. */ gatewayDir: string | null; runtime: string | null; exec: ExecLike; timeoutMs?: number; } /** The model gateway, as the container runtime reports it: `container inspect` of the engine's own * gateway name. Running → ok; stopped → down; absent → degraded (the engine starts it before the * next container seat); the runtime unreachable → down; no answer inside the bound → unknown. */ export declare function probeGateway(input: GatewayProbeInput): Promise; /** One CLI's credential-broker reading (`seat-login status`, `SeatContainerStatus`). */ export interface BrokerReadingLike { state: 'signed_in' | 'signed_out' | 'expired' | 'refresh_failing' | 'unknown'; reason?: string; expires_at?: number; } export interface BrokerProbeInput { containerFloor: boolean; /** The container-login CLIs on the roster. */ clis: string[]; /** A FRESH status read for one CLI (never the cache). */ status: (cli: string) => Promise; timeoutMs?: number; } /** The credential broker, read fresh per CLI. Any refresh failing → degraded; no CLI signed in → * degraded; no CLI answered inside the bound → unknown. */ export declare function probeBroker(input: BrokerProbeInput): Promise; export interface InteractiveProbeInput { /** The bridge roots this daemon knows (its default root and every pooled one). */ roots: string[]; /** `/.wi-serve.json`, or null — read asynchronously, inside the probe's bound. */ readLock: (root: string) => Promise<{ host: string; port: number; pid: number; } | null>; /** GET the bridge's `/api/health`; resolves the HTTP status. */ health: (url: string, timeoutMs: number) => Promise; timeoutMs?: number; } /** The interactive bridge: started on demand, so no lockfile is `off`; a recorded bridge must answer * its `/api/health` inside the bound. */ export declare function probeInteractive(input: InteractiveProbeInput): Promise; /** `/.wi-serve.json` read asynchronously (the `bridge-pool.ts` `readLock` shape): a missing * file, a non-regular one (a FIFO, a link) or an incomplete record is `null`. */ export declare function readBridgeLockAsync(root: string): Promise<{ host: string; port: number; pid: number; } | null>; export interface EstateProbeInput { /** The memory store the daemon reads and writes (`memoryStoreInfo`). */ memoryStore: { path: string; source: string; notice: string | null; }; /** One read-only call: `memory.coverage` on a `wicked-estate-mcp --readonly` (which opens an * existing store read-only and never creates one). Resolves the tool's JSON-RPC answer. */ call: (timeoutMs: number) => Promise>; /** Whether the store file exists (injectable for tests). */ exists?: (path: string) => Promise; timeoutMs?: number; } /** The production estate call: `memory.coverage` on a spawn-per-call `wicked-estate-mcp --readonly` * pinned to the daemon's memory store and to NO graph store (`:memory:`): a read-only server opens * an existing store without schema work and never creates one (wicked-estate 0.29). */ export declare function estateReadonlyCall(memoryDbPath: string): (timeoutMs: number) => Promise>; /** Estate, through one read-only MCP call on the daemon's memory store. */ export declare function probeEstate(input: EstateProbeInput): Promise; export interface BusProbeInput { /** Why the boot handed the engine no bus, if it did not. */ unavailable: { reason?: unknown; } | null; /** The engine has the bus but not the calls crew reaches it through. */ seamsOff: unknown; /** The bus db file (`WICKED_BUS_DB`), or null when none was exported. */ dbPath: string | null; /** The watch registry's bus source, when it is armed. */ watchBus: 'up' | 'down' | 'degraded' | null; tailLagMs: number | null; } /** The event bus: the boot's own verdict, then the file (stat, never opened: one SQLite library per * file per process), then the watch registry's live tail. */ export declare function probeBus(input: BusProbeInput): Promise; export interface VaultProbeInput { /** `DiagnosticsVault`, or null on a route set without the engine adapter. */ vault: { bin: string | null; source: string; finding: { message: string; remedy: string; } | null; } | null; exec: ExecLike; timeoutMs?: number; } export declare function probeVault(input: VaultProbeInput): Promise; /** `DiagnosticsSkills` → a row. */ export declare function skillsRow(skills: { state: string; findings: Array<{ severity?: string; message?: string; kind?: string; }>; } & Record): SystemInfraRow; /** `DiagnosticsStateHome` → a row. */ export declare function stateHomeRow(home: { refusesLaunches: boolean; findings: Array<{ severity?: string; message?: string; }>; remedy?: string; error?: string | null; } | null): SystemInfraRow; /** crew#1145: the disk row is `down` under this many free bytes (or over 95% used). */ export declare const DISK_DOWN_BYTES: number; /** …and `degraded` under this many (or over 90% used). */ export declare const DISK_DEGRADED_BYTES: number; export declare function diskRow(path: string | null, statfsFn?: (p: string) => Promise<{ bavail: number | bigint; bsize: number | bigint; blocks: number | bigint; }>, timeoutMs?: number): Promise; export declare function loadRow(read?: () => { load1: number; cores: number; }, platform?: NodeJS.Platform): SystemInfraRow; /** The whole week fold; past it the in-flight fold is dropped (never cached) and retried later. */ export declare const WEEK_FOLD_MAX_MS = 90000; export interface WeekFold { since: number; until: number; runsRead: number; truncated: boolean; clis: Map; floors: Record; qe: { passed: number; failed: number; }; judgedGates: number; } /** Fold the window's runs into per-CLI stats and the governance week. Ownership follows * `seat-record.ts` (`unitDistributed.cli`, moved by `unitReassigned.newCli`, else `assigned_cli`). */ export declare function foldWeek(runs: ReadonlyArray<{ view: SessionView; events: readonly RecordedEvent[]; }>, opts: { days: number; now: number; truncated: boolean; }): Promise; /** Pick the runs that can touch the window (newest first, capped), read each log, fold. `null` when * the engine has no event-log read binding. */ export declare function readWeek(views: readonly SessionView[], readEvents: (runId: string) => Promise, opts: { days: number; now: number; runReadTimeoutMs?: number; }): Promise; /** A short-TTL, in-flight-deduplicated holder for the week fold: the snapshot never waits past its * bound for it, and a fold that finishes late lands for the next read. */ export declare class WeekFoldCache { private readonly ttlMs; private readonly now; private readonly maxMs; private value; private inFlight; constructor(ttlMs?: number, now?: () => number, maxMs?: number); get(compute: () => Promise): Promise; } /** The roster fields the snapshot reads (`RosterSeat`). */ export interface RosterSeatLike { key: string; display_name?: string; auth?: string; signed_in?: boolean | null; health?: SeatHealth; council_eligible?: boolean; council_ineligible_reason?: string; work_eligible?: boolean; work_ineligible_reason?: string; login_note?: string; auth_evidence?: string; login_invocation?: string; sign_in?: string; version?: { installed?: string | null; version?: string | null; observed?: string | null; } | null; version_pin?: { pinned: string; observed: string | null; matched: boolean; } | null; governance_class?: unknown; governance_mode?: Record | null; recent_bench?: { kind: string; reason: string; lifts_at: string; last_at: string; runs: number; source: string; } | null; } export declare function buildClis(input: { roster: RosterSeatLike[]; acp: Record; seatGovernance: DiagnosticsSeatGovernanceEntry[]; containerFloor: boolean; hostBoundary: string | null; week: WeekFold | null; weekNote?: string; }): SystemCli[]; /** The open gate or question a paused run waits on (`InteractionRequest`, or the gate cache). */ export interface OpenGateLike { interactionId: string | null; ord: number | null; kind: string | null; prompt: string | null; /** ISO-8601 of the gate's arrival, when known. */ receivedAt?: string | null; } export interface RunEvidence { at: number; source: 'event_log' | 'relay' | 'process'; } /** The liveness thresholds from `workerStallMinutes`: stalled at the stall threshold, quiet at a * third of it (at most 5 min). */ export declare function livenessThresholds(stallMinutes: number | undefined): { quietAfterMs: number; stallAfterMs: number; }; /** One run's computed liveness. Pure: every input is a reading. */ export declare function runLiveness(input: { view: SessionView; now: number; evidence: RunEvidence | null; gate: OpenGateLike | null; quietAfterMs: number; stallAfterMs: number; }): SystemRun; export declare function unfinished(views: readonly SessionView[]): SessionView[]; export declare function sortRuns(runs: SystemRun[]): SystemRun[]; /** Some seat that can work, and a seat that can judge it distinct from it — or `null` when none. */ export declare function distinctJudgePair(clis: SystemCli[]): { creator: string; judge: string; } | null; /** For each unfinished run: the seats that could judge its next gate distinct from its creator, and, * when there are none, the seats in its pool that cannot (with why). */ export declare function judgeGaps(runs: Array<{ view: SessionView; run: SystemRun; }>, clis: SystemCli[]): Array<{ run: SystemRun; creator: string | null; blockedBy: SystemCli[]; }>; export interface GovernanceInput { /** `DiagnosticsGovernance`. */ /** `DiagnosticsGovernance`; `null` when diagnostics did not answer (`governanceNote` says why). */ governance: { store: { path: string; source: string; } | null; records: { total: number | null; sinceBoot: number | null; }; deadletters: { count: number; } & Record; findings: Array<{ kind: string; severity: string; message: string; }>; } | null; governanceNote?: string; skillsFindings: Array<{ kind?: string; severity?: string; message?: string; }>; decisions: unknown; clis: SystemCli[]; judgeGapCount: number; week: WeekFold | null; weekNote?: string; /** Gate decisions by a human operator in the window (audit `gate.decided`); `null` unreadable. */ gatesByYou: number | null; /** Steering rules loaded (not retired); `null` when unreadable. */ steeringRules: number | null; steeringNote?: string; } export declare function buildGovernance(g: GovernanceInput): SystemGovernanceCard[]; export { buildNeeds, needsLevel as levelOf } from './needs.js'; /** Assemble the wire answer from its parts. */ export declare function assembleSnapshot(parts: { startedAt: number; clis: SystemCli[]; runs: SystemRun[]; infra: SystemInfraRow[]; governance: SystemGovernanceCard[]; attention: SystemAttentionItem[]; unresolved: SystemUnresolvedItem[]; unresolvedSpend: NonNullable; toReview: number | null; }): SystemSnapshot; //# sourceMappingURL=system-snapshot.d.ts.map