feat(KB-154): persist worktree pool across engine restarts
- Add rehydrate() method and scanIdleWorktrees() to restore idle worktrees from disk on startup - Add cleanupOrphanedWorktrees() to remove stale worktrees when recycling is disabled - Wire startup rehydrate/cleanup into dashboard command based on recycleWorktrees setting - Export new functions from @kb/engine and update dashboard imports - Add unit tests for rehydrate/scan/cleanup and integration tests for restart resilience
This commit is contained in:
@@ -2,7 +2,7 @@ import { exec } from "node:child_process";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { TaskStore } from "@kb/core";
|
||||
import { createServer } from "@kb/dashboard";
|
||||
import { TriageProcessor, TaskExecutor, Scheduler, AgentSemaphore, WorktreePool, aiMergeTask, UsageLimitPauser, PRIORITY_MERGE } from "@kb/engine";
|
||||
import { TriageProcessor, TaskExecutor, Scheduler, AgentSemaphore, WorktreePool, aiMergeTask, UsageLimitPauser, PRIORITY_MERGE, scanIdleWorktrees, cleanupOrphanedWorktrees } from "@kb/engine";
|
||||
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
function openBrowser(url: string): void {
|
||||
@@ -47,6 +47,28 @@ export async function runDashboard(port: number, opts: { open?: boolean } = {})
|
||||
//
|
||||
const pool = new WorktreePool();
|
||||
|
||||
// ── Startup: rehydrate or clean up worktrees from previous runs ────
|
||||
//
|
||||
// When `recycleWorktrees` is true, scan the .worktrees/ directory for
|
||||
// idle worktrees (not assigned to any active task) and load them into
|
||||
// the pool so new tasks can reuse them instead of creating fresh ones.
|
||||
//
|
||||
// When `recycleWorktrees` is false, clean up orphaned worktrees left
|
||||
// behind by previous engine runs to avoid disk waste.
|
||||
//
|
||||
if (initialSettings.recycleWorktrees) {
|
||||
const idlePaths = await scanIdleWorktrees(cwd, store);
|
||||
if (idlePaths.length > 0) {
|
||||
pool.rehydrate(idlePaths);
|
||||
console.log(`[engine] Rehydrated pool with ${idlePaths.length} idle worktree(s)`);
|
||||
}
|
||||
} else {
|
||||
const cleaned = await cleanupOrphanedWorktrees(cwd, store);
|
||||
if (cleaned > 0) {
|
||||
console.log(`[engine] Cleaned up ${cleaned} orphaned worktree(s)`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Usage limit pauser ──────────────────────────────────────────────
|
||||
//
|
||||
// Shared pauser that triggers globalPause when any agent hits an API
|
||||
|
||||
Reference in New Issue
Block a user