(input)
| 80 | return getCronFilePath() |
| 81 | }, |
| 82 | async validateInput(input): Promise<ValidationResult> { |
| 83 | if (!parseCronExpression(input.cron)) { |
| 84 | return { |
| 85 | result: false, |
| 86 | message: `Invalid cron expression '${input.cron}'. Expected 5 fields: M H DoM Mon DoW.`, |
| 87 | errorCode: 1, |
| 88 | } |
| 89 | } |
| 90 | if (nextCronRunMs(input.cron, Date.now()) === null) { |
| 91 | return { |
| 92 | result: false, |
| 93 | message: `Cron expression '${input.cron}' does not match any calendar date in the next year.`, |
| 94 | errorCode: 2, |
| 95 | } |
| 96 | } |
| 97 | const tasks = await listAllCronTasks() |
| 98 | if (tasks.length >= MAX_JOBS) { |
| 99 | return { |
| 100 | result: false, |
| 101 | message: `Too many scheduled jobs (max ${MAX_JOBS}). Cancel one first.`, |
| 102 | errorCode: 3, |
| 103 | } |
| 104 | } |
| 105 | // Teammates don't persist across sessions, so a durable teammate cron |
| 106 | // would orphan on restart (agentId would point to a nonexistent teammate). |
| 107 | if (input.durable && getTeammateContext()) { |
| 108 | return { |
| 109 | result: false, |
| 110 | message: |
| 111 | 'durable crons are not supported for teammates (teammates do not persist across sessions)', |
| 112 | errorCode: 4, |
| 113 | } |
| 114 | } |
| 115 | return { result: true } |
| 116 | }, |
| 117 | async call({ cron, prompt, recurring = true, durable = false }) { |
| 118 | // Kill switch forces session-only; schema stays stable so the model sees |
| 119 | // no validation errors when the gate flips mid-session. |
nothing calls this directly
no test coverage detected