refactor(modules): extract scheduling as registry-based module
Moves the scheduling surface — 5 delivery actions (schedule_task, cancel_task, pause_task, resume_task, update_task), handleRecurrence, applyPreTaskScripts, and task DB helpers — out of core and into src/modules/scheduling/ (host) and container/agent-runner/src/scheduling/ (container). First PR to fill the MODULE-HOOK markers introduced in PR #2: - src/host-sweep.ts MODULE-HOOK:scheduling-recurrence now dynamically imports handleRecurrence from the module each sweep tick. - container/agent-runner/src/poll-loop.ts MODULE-HOOK:scheduling-pre-task dynamically imports applyPreTaskScripts before the provider call. When the marker block is empty (scheduling uninstalled), `keep` falls back to `normalMessages` so non-task messages still flow. The 5 task cases are removed from delivery.ts's handleSystemAction switch — the registry now routes them. Task DB helpers moved out of src/db/session-db.ts (which kept `nextEvenSeq` as a named export so the module can uphold the host-writes-even-seq invariant). Test suite split to match: scheduling-specific tests live in the module. No migration — tasks are messages_in rows with kind='task'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,9 +19,6 @@ import {
|
||||
getMessageForRetry,
|
||||
markMessageFailed,
|
||||
retryWithBackoff,
|
||||
getCompletedRecurring,
|
||||
insertRecurrence,
|
||||
clearRecurrence,
|
||||
} from './db/session-db.js';
|
||||
import { log } from './log.js';
|
||||
import { openInboundDb, openOutboundDb, inboundDbPath, outboundDbPath, heartbeatPath } from './session-manager.js';
|
||||
@@ -102,10 +99,7 @@ async function sweepSession(session: Session): Promise<void> {
|
||||
|
||||
// 4. Handle recurrence for completed messages.
|
||||
// MODULE-HOOK:scheduling-recurrence:start
|
||||
// When scheduling is extracted (PR #4), `handleRecurrence` moves to
|
||||
// `src/modules/scheduling/` and the `/add-scheduling` skill replaces
|
||||
// this block with a call to the module. Without scheduling
|
||||
// installed, the block is empty and recurrence is a no-op.
|
||||
const { handleRecurrence } = await import('./modules/scheduling/recurrence.js');
|
||||
await handleRecurrence(inDb, session);
|
||||
// MODULE-HOOK:scheduling-recurrence:end
|
||||
} finally {
|
||||
@@ -156,24 +150,3 @@ function detectStaleContainers(
|
||||
}
|
||||
}
|
||||
|
||||
/** Insert next occurrence for completed recurring messages. */
|
||||
async function handleRecurrence(inDb: Database.Database, session: Session): Promise<void> {
|
||||
const recurring = getCompletedRecurring(inDb);
|
||||
|
||||
for (const msg of recurring) {
|
||||
try {
|
||||
const { CronExpressionParser } = await import('cron-parser');
|
||||
const interval = CronExpressionParser.parse(msg.recurrence);
|
||||
const nextRun = interval.next().toISOString();
|
||||
const prefix = msg.kind === 'task' ? 'task' : 'msg';
|
||||
const newId = `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
|
||||
insertRecurrence(inDb, msg, newId, nextRun);
|
||||
clearRecurrence(inDb, msg.id);
|
||||
|
||||
log.info('Inserted next recurrence', { originalId: msg.id, newId, seriesId: msg.series_id, nextRun });
|
||||
} catch (err) {
|
||||
log.error('Failed to compute next recurrence', { messageId: msg.id, recurrence: msg.recurrence, err });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user