feat(FN-4068): add branch conflict detection and recovery for stale worktre

Implements branch conflict detection and recovery across the Fusion engine, CLI, and dashboard — surfacing git worktree conflicts when tasks conflict with unrelated branch state, and providing a recovery workflow to resolve them. The executor and worktree pool now integrate typed branch conflict che

Fusion-Task-Id: FN-4068
This commit is contained in:
Fusion
2026-05-12 17:10:26 -07:00
committed by gsxdsm
parent ceccc382b1
commit bddcc3a931
28 changed files with 1341 additions and 209 deletions

View File

@@ -118,7 +118,7 @@ async function loadCommandHandlers() {
const { runServe } = await import("./commands/serve.js");
const { runDaemon } = await import("./commands/daemon.js");
const { runDesktop } = await import("./commands/desktop.js");
const { runTaskCreate, runTaskList, runTaskMove, runTaskMerge, runTaskUpdate, runTaskLog, runTaskLogs, runTaskShow, runTaskAttach, runTaskPause, runTaskUnpause, runTaskImportFromGitHub, runTaskDuplicate, runTaskArchive, runTaskUnarchive, runTaskRefine, runTaskPlan, runTaskDelete, runTaskRetry, runTaskComment, runTaskComments, runTaskSteer, runTaskSetNode, runTaskClearNode, runTaskPrCreate } = await import("./commands/task.js");
const { runTaskCreate, runTaskList, runTaskMove, runTaskMerge, runTaskUpdate, runTaskLog, runTaskLogs, runTaskShow, runTaskAttach, runTaskPause, runTaskUnpause, runTaskImportFromGitHub, runTaskDuplicate, runTaskArchive, runTaskUnarchive, runTaskRefine, runTaskPlan, runTaskDelete, runTaskRetry, runTaskComment, runTaskComments, runTaskSteer, runTaskSetNode, runTaskClearNode, runTaskPrCreate, runTaskBranchRecovery } = await import("./commands/task.js");
const { runSettingsShow, runSettingsSet } = await import("./commands/settings.js");
const { runSettingsExport } = await import("./commands/settings-export.js");
const { runSettingsImport } = await import("./commands/settings-import.js");
@@ -163,6 +163,7 @@ async function loadCommandHandlers() {
runTaskPlan,
runTaskDelete,
runTaskRetry,
runTaskBranchRecovery,
runTaskComment,
runTaskComments,
runTaskSteer,
@@ -280,6 +281,8 @@ Usage:
fn task set-node <id> <node-name-or-id> Set a per-task node override
fn task clear-node <id> Clear a per-task node override
fn task retry <id> Retry a failed task (clears error, moves to todo)
fn task branch-recovery <id> [--reclaim <branch>] [--discard <branch> --yes]
Inspect, reclaim, or discard stranded task branches
fn task pr-create <id> [--title <title>] [--base <branch>] [--body <body>]
Create a GitHub PR for an in-review task
fn task import <owner/repo> [opts] Import GitHub issues as tasks
@@ -522,6 +525,7 @@ async function main() {
runTaskPlan,
runTaskDelete,
runTaskRetry,
runTaskBranchRecovery,
runTaskComment,
runTaskComments,
runTaskSteer,
@@ -1117,6 +1121,20 @@ async function main() {
await runTaskRetry(id, projectName);
break;
}
case "branch-recovery": {
const id = args[2];
if (!id) {
console.error("Usage: fn task branch-recovery <id> [--reclaim <branch>] [--discard <branch> --yes]");
process.exit(1);
}
const reclaimIdx = args.indexOf("--reclaim");
const discardIdx = args.indexOf("--discard");
const reclaim = reclaimIdx !== -1 && reclaimIdx + 1 < args.length ? args[reclaimIdx + 1] : undefined;
const discard = discardIdx !== -1 && discardIdx + 1 < args.length ? args[discardIdx + 1] : undefined;
const yes = args.includes("--yes");
await runTaskBranchRecovery(id, { reclaim, discard, yes }, projectName);
break;
}
case "pr-create": {
const id = args[2];
if (!id) {