/** * JobsObserver * * Single, event-driven aggregator over the two background-work sources surfaced * by the status-line jobs widget and the jobs overlay: * - monitor jobs (bash jobs started by the `monitor` tool, tracked in `AsyncJobManager`) * - cron jobs (tracked in the cron module's owner-scoped schedule store) * * It subscribes to change hooks on both sources (no polling), debounces bursts * to a microtask, and exposes a precomputed snapshot so the status-line render * loop never scans the underlying stores. A failure latch keeps the widget red * until `acknowledgeFailures()` is called (when the overlay opens), so a failed * job that evicts before the user looks is not silently lost. */ import type { AsyncJob, AsyncJobManager } from "../async"; export type JobsWorstState = "none" | "running" | "failed"; export interface MonitorJobView { id: string; label: string; status: AsyncJob["status"]; startTime: number; } export interface CronJobView { id: string; humanSchedule: string; cronExpression: string; prompt: string; recurring: boolean; nextFireAt?: number; /** A cron firing whose spawned job is currently running. */ firing?: boolean; createdAt: number; } export interface JobsSnapshot { monitors: MonitorJobView[]; crons: CronJobView[]; activeMonitorCount: number; activeCronCount: number; worstState: JobsWorstState; failedUnacknowledged: boolean; } export declare const EMPTY_JOBS_SNAPSHOT: JobsSnapshot; export declare class JobsObserver { #private; constructor(manager: AsyncJobManager, ownerId: string | undefined); /** Subscribe to debounced change events. Returns an unsubscribe function. */ onChange(cb: () => void): () => void; /** Return the precomputed snapshot (recomputed on each upstream change). */ getSnapshot(): JobsSnapshot; /** Clear the failure latch (called when the user opens the jobs overlay). */ acknowledgeFailures(): void; /** Cancel a running monitor job. Returns true when the job was cancelled. */ cancelMonitor(id: string): boolean; /** Delete a visible scheduled cron job. Returns true when removed. */ deleteCron(id: string): boolean; /** Bounded tail of a monitor job's captured output (for the detail view). */ getMonitorOutput(id: string): string; dispose(): void; }