feat: resume orphaned in-progress tasks on engine restart

This commit is contained in:
Dustin Byrne
2026-03-25 21:42:47 -04:00
parent 0e023c7b2b
commit 99502e4e05
2 changed files with 27 additions and 0 deletions

View File

@@ -156,6 +156,11 @@ export async function runDashboard(port: number, opts: { engine?: boolean; open?
triage.start();
scheduler.start();
// ── Startup sweep: resume orphaned in-progress tasks ──────────────
executor.resumeOrphaned().catch((err) =>
console.error("[engine] Failed to resume orphaned tasks:", err),
);
// ── Startup sweep: enqueue any tasks already in "in-review" ───────
if (settings.autoMerge) {
const existing = await store.listTasks();

View File

@@ -106,6 +106,28 @@ export class TaskExecutor {
});
}
/**
* Resume orphaned in-progress tasks (e.g., after crash/restart).
* Call once after engine startup.
*/
async resumeOrphaned(): Promise<void> {
const tasks = await this.store.listTasks();
const inProgress = tasks.filter(
(t) => t.column === "in-progress" && !this.executing.has(t.id),
);
if (inProgress.length === 0) return;
console.log(`[executor] Found ${inProgress.length} orphaned in-progress task(s)`);
for (const task of inProgress) {
console.log(`[executor] Resuming ${task.id}: ${task.title || task.description.slice(0, 60)}`);
await this.store.logEntry(task.id, "Resumed after engine restart");
this.execute(task).catch((err) =>
console.error(`[executor] Failed to resume ${task.id}:`, err),
);
}
}
async execute(task: Task): Promise<void> {
if (this.executing.has(task.id)) return;
this.executing.add(task.id);