/** * design/135 G2 (审计 [485]① 🔴) — the `Monitor` tool: run a shell command in the background and watch its * stdout as a stream of NOTIFICATION EVENTS (the自主循环 core piece: "watch this and tell me when something * happens" without burning poll turns). * * CC-parity semantics (live-harness schema, the archived ground truth): * ① every stdout LINE becomes one event; ② lines within the 200ms batch window coalesce into ONE * notification; ③ process exit ends the watch (exit code reported); ④ non-persistent watches are killed at * `timeout_ms` (default 5min, max 60min); ⑤ stderr never notifies but is spooled (TaskOutput-readable); * ⑥ an event storm auto-stops the monitor (threshold disclosed in the stop notification). * * Wiring: the process runs through the SAME ExecutionEnv background seam as Bash(run_in_background) * (`spawnBackground` — remote envs included); the watcher/batching/timeout machinery lives in * {@link TaskRegistry.registerMonitor} (background_bash G2b watcher's near kin); events ride the * TaskNotificationPayload lane at "later" priority (don't derail active work — the boundary/followUp drain). * 飞轮 [492]② (1.257): events born BETWEEN turns (run torn down / harness idle — the long-watch main case) * are no longer lost: the Runner parks them per session (bounded, drop-disclosing) and the session's next * run redelivers them through the same notification lane at its first turn boundary. * 飞轮 [511]③ (CC parity): a monitor's lifetime = min(timeout_ms, process exit, TaskStop); a `persistent` * one is SESSION-anchored (reaped at session release). NEITHER is run-anchored: the run teardown leaves an * in-window non-persistent watch alive (process on the dispose except-list, watcher ticking, row kept), so * cross-turn watching — CC's main Monitor use case — works with the default persistent:false too; its * between-turns events AND its timeout/exit terminal ride the same pending lane. * The handle is a first-class m* registry task: TaskOutput serves the re-readable spool, TaskStop stops the * watch (design/134 stoppedBy attribution applies automatically). * * Security posture: `command` is an arbitrary shell script ⇒ effect:"write", same as Bash, and prepare-task * folds Monitor into the SAME shellGate tighten (irreversibility tier + reversibility probe on the same * `command` arg) — Monitor is never a policy side-door around a gated Bash. * * 深对比残差 M17 CLOSED (2026-07-09 live-CC probe, docs/cc-probe-198/live-schema-monitor-worktree-2026-07-09.json): * the deep-dive bundle showed a `command? + ws?:{url,protocols}` dual-mode schema; the LIVE current-CC schema is * shell-single-mode ({command, description, persistent, timeout_ms} — no ws branch anywhere in desc or schema). * sema's shell-single-mode Monitor is therefore aligned with current CC — do NOT port a WebSocket event-source * branch off the stale bundle. (Full-desc density diff vs the live guidance card remains P1, a separate item.) */ import type { AgentTool, ExecutionEnv } from "../internal/harness.js"; import { type MonitorTimers, type TaskRegistry } from "../core/task-registry.js"; import type { TaskNotificationPayload } from "../core/task-notification.js"; export interface MonitorToolOptions { registry: TaskRegistry; /** Fallbacks when the runtime ctx carries no identity (direct mounts) — same posture as makeBashTool. */ owner?: string; scope?: string; /** design/129: the session id — a `persistent` monitor registers session-scoped under it (outlives the * turn; reaped by the deployment's session release via `reapSessionBackground`). */ sessionId?: string; /** The notification sink (the run-local task-notification lane). Without it the monitor still runs and * spools — readable via TaskOutput — but no events reach the model (the tool reply says so honestly). */ onTaskNotification?: (n: TaskNotificationPayload, opts?: { priority?: "now" | "next" | "later"; }) => void; /** The tracked logical cwd (shared with the hands band) — the monitor spawns there, like Bash. */ cwdRef?: { current: string; }; /** design/87: injectable timers/clock for the watcher (tests drive ticks manually; default real timers). */ timers?: MonitorTimers; /** Test/deployment knobs (defaults: 200ms window, 50 batches/min). */ batchWindowMs?: number; maxBatchesPerMinute?: number; } export declare function createMonitorTool(env: ExecutionEnv, opts: MonitorToolOptions): AgentTool; //# sourceMappingURL=monitor.d.ts.map