/** * The generic workflow scheduler (DES-RUNS-REVIEW-001 ยง2). Once a minute: * * 1. TICK HOOKS: work that folds terminal runs (the run review's ingest) gets the status map first. * 2. RECONCILE: a schedule's launched run that reached a terminal status records its outcome. * 3. LAUNCH: at most ONE due schedule launches. A schedule whose last run is still open is SKIPPED (it never runs * twice at once; its due time stays, so it fires once that run ends). Nothing launches while any run is * planning, distributing or executing (one governed run at a time; one parked on a person is not busy). * A refused launch backs off 2^n hours, at most a day. Missed intervals coalesce into one run. * * The next due time is persisted the moment a launch returns, before any bookkeeping, so a restart can never * launch the same interval twice. Sweeps never stack, and Run it now shares their lock. */ import type { SessionView } from 'wicked-crew-api-types'; import { type ScheduleStore, type WorkflowSchedule } from './store.js'; export declare const DEFAULT_SWEEP_MS = 60000; /** A launched run the daemon does not list holds its schedule's slot this long, then lets go. */ export declare const STALE_LAUNCH_MS: number; /** A reservation (the run id chosen before the engine was called) the daemon never lists lets go after this. */ export declare const RESERVATION_GRACE_MS: number; /** Launch one scheduled run under `runId`; resolves to the engine's run id. Throws when the launch is refused. */ export type ScheduledLaunch = (schedule: WorkflowSchedule, runId: string, trigger: 'schedule' | 'manual') => Promise; export interface SchedulerDeps { store: ScheduleStore; sessionsDetail: () => Promise; launch: ScheduledLaunch; /** Called every sweep with the run statuses (the review ingest). Errors are logged, never thrown. */ onTick?: Array<(status: ReadonlyMap) => Promise>; log: (msg: string) => void; now?: () => Date; } export declare class ScheduleBusyError extends Error { constructor(message: string); } export declare class WorkflowScheduler { private readonly deps; private timer; private lock; private sweeping; constructor(deps: SchedulerDeps); start(intervalMs?: number): void; stop(): void; private now; /** Serialize with every other sweep and Run it now. */ private exclusive; /** One sweep. Never throws; a sweep already running is not stacked. */ sweep(): Promise; private tick; private statusMap; private reconcile; /** Why `row` may not launch now, or `null`. */ private blocker; private launchDue; /** "Run it now": the same guards as a sweep, minus "is it due". Resolves to the run id. */ runNow(id: string): Promise; private launchOne; } //# sourceMappingURL=scheduler.d.ts.map