/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */ /** * observed/source.ts, the ObservedAgentSource: the fleet's read-only view of * externally-launched coding-agent sessions on this host, plus the one genuine * steer channel (tmux send-keys) where a foreign session exposes it. * * Responsibility boundary (owner ruling): these rows are OBSERVED, not owned. * The source is composed as an OPTIONAL registry dep and is deliberately NOT a * source in fleet-count.ts, so an observed row can never count against * fleet.maxSize (proven structurally, not by a filter). Stop is never offered. * Steering rides whatever channel the foreign session genuinely exposes and * honestly says when there is none. * * Cost: detection runs at most once per `refreshIntervalMs` (a lazy TTL over the * injected clock), so folding observed rows into every fleet snapshot/tick stays * cheap, a cached read between refreshes. The CPU-delta that drives liveness is * measured across those refresh boundaries, so `active`/`quiet` reflects CPU * burned in the last refresh interval, not per-query noise. */ import type { ObservedAgentKind, ObservedLiveness, ObservedSteerChannel, SteerResult } from '../types.js'; import { type ProcessTableReader, type TmuxPaneReader } from './detect.js'; /** One observed foreign coding-agent session, assembled read-only. The adapter turns this into a ProcessNode. */ export interface ObservedAgentRow { readonly externalKind: ObservedAgentKind; readonly pid: number; readonly ppid: number; /** Full command line, the adapter derives the row label from it. */ readonly args: string; readonly cwd?: string | undefined; readonly startedAt?: number | undefined; readonly liveness: ObservedLiveness; readonly steer: ObservedSteerChannel; } /** Injectable tmux command runner for the steer send-keys, read/write to the pane only, never a shell. */ export interface TmuxCommandRunner { run(args: readonly string[]): { readonly status: number | null; readonly stderr: string; }; } /** Real send-keys runner: spawnSync tmux, hard timeout, never a shell. */ export declare function defaultTmuxCommandRunner(): TmuxCommandRunner; export interface ObservedAgentSourceDeps { readonly processReader?: ProcessTableReader | undefined; readonly paneReader?: TmuxPaneReader | undefined; readonly steerRunner?: TmuxCommandRunner | undefined; readonly now?: (() => number) | undefined; /** Detection cadence, at most one scan per this many ms (default 2500). */ readonly refreshIntervalMs?: number | undefined; } /** * The observed-agent source. `list()` returns the current observed rows, * refreshing the read-only scan at most once per `refreshIntervalMs`. `steer()` * drives a tmux-hosted foreign session with the exact three-send recipe. */ export declare class ObservedAgentSource { private readonly processReader; private readonly paneReader; private readonly steerRunner; private readonly now; private readonly refreshIntervalMs; /** pid → cumulative CPU seconds at the previous refresh (the liveness delta baseline). */ private readonly cpuByPid; private cached; private lastScanAt; private scanned; constructor(deps?: ObservedAgentSourceDeps); /** Current observed rows. Lazily re-scans (read-only) at most once per refresh interval. */ list(): readonly ObservedAgentRow[]; private scan; /** * Steer a tmux-hosted foreign session with the exact three-send recipe: one * send carries the literal message text, then two separate Enter sends. An * honest refusal (queued:false) when the row exposes no tmux channel, or when * a send-keys call fails. STOP is never offered here, this is steer only. */ steer(row: ObservedAgentRow, text: string): SteerResult; } //# sourceMappingURL=source.d.ts.map