MCPcopy
hub / github.com/codeaashu/claude-code / createCronScheduler

Function createCronScheduler

src/utils/cronScheduler.ts:142–531  ·  view source on GitHub ↗
(
  options: CronSchedulerOptions,
)

Source from the content-addressed store, hash-verified

140}
141
142export function createCronScheduler(
143 options: CronSchedulerOptions,
144): CronScheduler {
145 const {
146 onFire,
147 isLoading,
148 assistantMode = false,
149 onFireTask,
150 onMissed,
151 dir,
152 lockIdentity,
153 getJitterConfig,
154 isKilled,
155 filter,
156 } = options
157 const lockOpts = dir || lockIdentity ? { dir, lockIdentity } : undefined
158
159 // File-backed tasks only. Session tasks (durable: false) are NOT loaded
160 // here — they can be added/removed mid-session with no file event, so
161 // check() reads them fresh from bootstrap state on every tick instead.
162 let tasks: CronTask[] = []
163 // Per-task next-fire times (epoch ms).
164 const nextFireAt = new Map<string, number>()
165 // Ids we've already enqueued a "missed task" prompt for — prevents
166 // re-asking on every file change before the user answers.
167 const missedAsked = new Set<string>()
168 // Tasks currently enqueued but not yet removed from the file. Prevents
169 // double-fire if the interval ticks again before removeCronTasks lands.
170 const inFlight = new Set<string>()
171
172 let enablePoll: ReturnType<typeof setInterval> | null = null
173 let checkTimer: ReturnType<typeof setInterval> | null = null
174 let lockProbeTimer: ReturnType<typeof setInterval> | null = null
175 let watcher: FSWatcher | null = null
176 let stopped = false
177 let isOwner = false
178
179 async function load(initial: boolean) {
180 const next = await readCronTasks(dir)
181 if (stopped) return
182 tasks = next
183
184 // Only surface missed tasks on initial load. Chokidar-triggered
185 // reloads leave overdue tasks to check() (which anchors from createdAt
186 // and fires immediately). This avoids a misleading "missed while Claude
187 // was not running" prompt for tasks that became overdue mid-session.
188 //
189 // Recurring tasks are NOT surfaced or deleted — check() handles them
190 // correctly (fires on first tick, reschedules forward). Only one-shot
191 // missed tasks need user input (run once now, or discard forever).
192 if (!initial) return
193
194 const now = Date.now()
195 const missed = findMissedTasks(next, now).filter(
196 t => !t.recurring && !missedAsked.has(t.id) && (!filter || filter(t)),
197 )
198 if (missed.length > 0) {
199 for (const t of missed) {

Callers 1

useScheduledTasksFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected