(missed: CronTask[])
| 540 | * sees this notification. |
| 541 | */ |
| 542 | export function buildMissedTaskNotification(missed: CronTask[]): string { |
| 543 | const plural = missed.length > 1 |
| 544 | const header = |
| 545 | `The following one-shot scheduled task${plural ? 's were' : ' was'} missed while Claude was not running. ` + |
| 546 | `${plural ? 'They have' : 'It has'} already been removed from .claude/scheduled_tasks.json.\n\n` + |
| 547 | `Do NOT execute ${plural ? 'these prompts' : 'this prompt'} yet. ` + |
| 548 | `First use the AskUserQuestion tool to ask whether to run ${plural ? 'each one' : 'it'} now. ` + |
| 549 | `Only execute if the user confirms.` |
| 550 | |
| 551 | const blocks = missed.map(t => { |
| 552 | const meta = `[${cronToHuman(t.cron)}, created ${new Date(t.createdAt).toLocaleString()}]` |
| 553 | // Use a fence one longer than any backtick run in the prompt so a |
| 554 | // prompt containing ``` cannot close the fence early and un-wrap the |
| 555 | // trailing text (CommonMark fence-matching rule). |
| 556 | const longestRun = (t.prompt.match(/`+/g) ?? []).reduce( |
| 557 | (max, run) => Math.max(max, run.length), |
| 558 | 0, |
| 559 | ) |
| 560 | const fence = '`'.repeat(Math.max(3, longestRun + 1)) |
| 561 | return `${meta}\n${fence}\n${t.prompt}\n${fence}` |
| 562 | }) |
| 563 | |
| 564 | return `${header}\n\n${blocks.join('\n\n')}` |
| 565 | } |
| 566 |
no test coverage detected