/** * Scheduler — Generic, provider-agnostic scheduler for Squad (#296) * * Unified schedule manifest + provider adapters that replace scattered * cron jobs, polling scripts, and manual triggers with a single * `.squad/schedule.json` configuration file. * * Provider model: * - LocalPollingProvider — evaluates schedule in ralph-watch loop * - GitHubActionsProvider — generates/updates workflow files from schedule * - Custom providers via ScheduleProvider interface */ export interface ScheduleManifest { version: number; schedules: ScheduleEntry[]; } export interface ScheduleEntry { id: string; name: string; enabled: boolean; trigger: TriggerConfig; task: TaskConfig; providers: string[]; retry?: RetryConfig; } export type TriggerConfig = CronTrigger | IntervalTrigger | EventTrigger | StartupTrigger; export interface CronTrigger { type: 'cron'; cron: string; } export interface IntervalTrigger { type: 'interval'; intervalSeconds: number; } export interface EventTrigger { type: 'event'; event: string; } export interface StartupTrigger { type: 'startup'; } export interface TaskConfig { type: 'workflow' | 'script' | 'copilot' | 'webhook'; ref: string; args?: Record; /** * Explicit argument vector for `script` tasks (#1794). * * When present, `ref` is used verbatim as the executable path and is never * parsed. This is the unambiguous form and should be preferred for any * command path that contains spaces — e.g. the default Windows Node install * at `C:\Program Files\nodejs\node.exe`. */ argv?: string[]; } export interface RetryConfig { maxRetries: number; backoffSeconds: number; } export interface ScheduleState { /** Map of schedule id → last run info */ runs: Record; } export interface RunRecord { lastRun: string; nextDue?: string; status: 'success' | 'failure' | 'running'; error?: string; } export interface TaskResult { success: boolean; output?: string; error?: string; /** Captured stderr (rejection-only). Optional; populated on script failures. */ stderr?: string; /** Process exit code if known (rejection-only). */ code?: number; /** * Non-numeric failure code from the OS when the child could not be spawned * at all — e.g. `ENOENT` for a missing executable (#1794). Distinct from * `code`, which is the child's own exit status and only exists if the child * actually ran. */ spawnError?: string; /** Signal that terminated the process if known (rejection-only). */ signal?: string; /** True iff the process was killed because it exceeded the timeout. */ timedOut?: boolean; } export interface ScheduleProvider { readonly name: string; execute(entry: ScheduleEntry): Promise; /** Optional: generate platform-native config (e.g. GitHub Actions workflow) */ generate?(manifest: ScheduleManifest, outDir: string): Promise; } export declare class ScheduleValidationError extends Error { constructor(message: string); } /** * Validate a raw object against the ScheduleManifest schema. * Throws ScheduleValidationError on invalid input. */ export declare function validateManifest(data: unknown): ScheduleManifest; /** * Parse and validate a schedule.json file from disk. */ export declare function parseSchedule(filePath: string): Promise; /** * Evaluate which schedules are due now, based on trigger config and state. * Returns a list of entries that should be executed. */ export declare function evaluateSchedule(manifest: ScheduleManifest, state: ScheduleState, now?: Date): ScheduleEntry[]; /** * Minimal cron evaluation for 5-field cron expressions. * Supports: minute hour day-of-month month day-of-week * Wildcard (*) and specific values only (no ranges/lists for simplicity). */ export declare function isCronDue(cron: string, run: RunRecord | undefined, now: Date): boolean; /** * Validate a task ref for safety. Rejects null bytes and newlines which * can cause issues even without shell interpretation. * The structural protection comes from execFileSync (shell: false). */ /** * Split a script `task.ref` into argv, honouring single and double quotes. * * Quotes only *group* when they open at a token boundary. A quote character * appearing mid-token is a literal, so refs like * `node -e console.log('hi')` keep passing the inner quotes straight through * to the child exactly as they did when this function split on whitespace. * * Backslash is NOT an escape character: Windows paths are full of them * (`C:\Program Files\nodejs\node.exe`) and treating them as escapes would * mangle the modal case this exists to support (#1794). * * Returns whether the first token was quoted, because that removes all * ambiguity about where the command ends and the arguments begin. */ export declare function tokenizeTaskRef(ref: string): { tokens: string[]; firstQuoted: boolean; }; /** * Decide which leading tokens form the executable path. * * A quoted first token is authoritative. Otherwise the plain first token is * tried first, so every previously-working ref keeps its exact behaviour * (including bare names resolved via PATH, which are not files on disk). * Only when that fails do we widen across spaces, longest match first — * mirroring how Windows CreateProcess resolves an unquoted path such as * `C:\Program Files\nodejs\node.exe` (#1794). */ export declare function resolveScriptCommand(tokens: string[], firstQuoted: boolean, exists?: (p: string) => boolean): { command: string; args: string[]; }; export declare function validateTaskRef(ref: string): void; /** * Execute a scheduled task using the specified provider. * Includes retry logic if configured. */ export declare function executeTask(entry: ScheduleEntry, provider: ScheduleProvider): Promise; /** * Load schedule state from disk. Returns empty state if file doesn't exist. */ export declare function loadState(statePath: string): Promise; /** * Save schedule state to disk. */ export declare function saveState(statePath: string, state: ScheduleState): Promise; /** * LocalPollingProvider — evaluates schedule in the ralph-watch loop. * Executes tasks as local processes or stubs. */ export declare class LocalPollingProvider implements ScheduleProvider { readonly name = "local-polling"; execute(entry: ScheduleEntry): Promise; } /** * GitHubActionsProvider — generates workflow YAML files from schedule manifest. */ export declare class GitHubActionsProvider implements ScheduleProvider { readonly name = "github-actions"; execute(entry: ScheduleEntry): Promise; generate(manifest: ScheduleManifest, outDir: string): Promise; } /** * Default schedule.json template for `squad schedule init`. */ export declare function defaultScheduleTemplate(): ScheduleManifest; //# sourceMappingURL=scheduler.d.ts.map