import type { ResumeEntry } from '../domain/costs/resume-registry.js'; export declare const SCHEDULES_FILE: string; export declare const CHANNEL_REGISTRY_FILE: string; /** Where a fired scheduled-task should land. Resolved by the cortex_schedule_add MCP tool * (or schedule-cli) at create time — `__current__` placeholders are concretized then, so * list/get always show real IDs. The 4 kinds map to the dispatch branches in * scheduling/jobs/scheduled-task.ts. */ export type ScheduleTarget = { kind: 'fresh'; } /** Fire into the project — spawns a fresh session in the project's channel. */ | { kind: 'project'; projectId: string; } /** Continue a specific thread; only valid while thread.status is running|waiting. */ | { kind: 'thread'; threadId: string; channel: string; }; export interface ScheduleTask { id: string; type: 'interval' | 'daily' | 'weekly' | 'once'; message: string; projectId: string; profile: string | null; intervalMs?: number; time?: string; dayOfWeek?: number; delay?: number; runAt?: number; nextRun?: number | null; createdAt: number; isPaused?: boolean; pausedAt?: number | null; pausedBy?: 'user' | 'rate-limit' | null; lastRun?: number | null; lastSkipped?: number | null; dispatchType?: string; preCheck?: string; taskConfigHash?: string; /** Dispatch routing — defaults to { kind: 'fresh' } for legacy records. */ target?: ScheduleTarget; /** What to do when the target thread no longer exists at fire time. * fresh: silently fall back to fresh-thread dispatch. * skip: record lastSkipped, post a Slack one-liner, do not run. * wait: reschedule short delay (max 3 retries), then fall back to fresh. */ fallback?: 'fresh' | 'skip' | 'wait'; } export interface SchedulesData { tasks: ScheduleTask[]; rateLimitThrottle?: { resetsAt: number; activatedAt: number; modes?: string[]; } | null; /** Sessions/threads interrupted by a rate limit, awaiting auto-resume when the * window resets. Owned by domain/costs/resume-registry.ts. */ resumeQueue?: ResumeEntry[] | null; } /** Convenience: reverse-lookup projectId from a Slack channel via channel-registry.json. */ export declare function channelToProjectId(channel: string): string | null; export declare class ScheduleRepo { private _repo; private _channelRegistryPath; constructor(filePath?: string, channelRegistryPath?: string); read(): Promise; addTask(task: ScheduleTask): Promise; removeTask(id: string): Promise; updateTask(id: string, fn: (task: ScheduleTask) => void): Promise; findTask(id: string): Promise; setRateLimitThrottle(meta: { resetsAt: number; activatedAt: number; modes?: string[]; } | null): Promise; getRateLimitThrottle(): Promise<{ resetsAt: number; activatedAt: number; modes?: string[]; } | null>; setResumeQueue(entries: ResumeEntry[] | null): Promise; getResumeQueue(): Promise; /** Generic mutate passthrough for composite operations. */ mutate(fn: (data: SchedulesData) => { next: SchedulesData; result: R; }): Promise; /** Drop the in-memory cache so the next read() fetches from disk. Test hook. */ invalidate(): void; /** Wait for any in-flight mutate() to complete. For graceful SIGTERM drain. */ flush(): Promise; } export declare const scheduleRepo: ScheduleRepo;