feat(worker): Handler-Session nach Usage-Limit-Reset automatisch neu starten
Eine List-Handler-ConPTY-Session, die mitten in einer Phase stirbt, war bisher
ein stilles totes Tile: InteractiveTerminalViewModel.OnSessionProcessExited
setzte nur bei einem Tod innerhalb des 5s-Grace-Fensters ein sichtbares Banner.
Neu:
- HandlerRoundState (JSON unter ~/.claudeDo/handler-rounds.json, keine
EF-Migration): Phase + Task-Set der laufenden Runde, geschrieben von
BuildForMergeHelperAsync ("triage") und BuildForMergeHelperHandoffAsync.
Ohne das existieren beide nur im transienten HandoffRequested-Broadcast.
- HandlerRestartCoordinator: entscheidet den Neustart, fail-closed. Beleg fuer
"war das Usage-Limit" ist FiveHour.Utilization >= 95 zum Todeszeitpunkt --
eine ConPTY-Session hat kein stdout, TaskRunner.IsUsageLimitMessage hat hier
nichts zu lesen. Nur bei PowerUse (beide Keys), max ein Neustart pro Runde,
Warten bis FiveHour.ResetsAt, dann HandoffRequested erneut broadcasten.
Verbraucht kein Handoff-Budget (HandoffRoundTracker.Register wird nicht
angefasst). WorkerLog-Zeilen beim Tod und beim Neustart.
- Ui meldet den Exit-Code (nur dort bekannt) via
WorkerHub.ReportInteractiveSessionExited, ohne selbst zu filtern.
Sibling zu UsageLimitAutoContinueCoordinator, kein Umbau davon: der sieht nur
headless Runs.
This commit is contained in:
@@ -44,6 +44,7 @@ public sealed class InteractiveLaunchSpecService
|
||||
private readonly GitService _git;
|
||||
private readonly string _claudePath;
|
||||
private readonly HandoffRoundTracker _handoffRounds;
|
||||
private readonly HandlerRoundState _roundState;
|
||||
|
||||
public InteractiveLaunchSpecService(
|
||||
IDbContextFactory<ClaudeDoDbContext> dbFactory,
|
||||
@@ -52,7 +53,8 @@ public sealed class InteractiveLaunchSpecService
|
||||
WorktreeManager wtManager,
|
||||
GitService git,
|
||||
WorkerConfig cfg,
|
||||
HandoffRoundTracker handoffRounds)
|
||||
HandoffRoundTracker handoffRounds,
|
||||
HandlerRoundState roundState)
|
||||
{
|
||||
_dbFactory = dbFactory;
|
||||
_skillSeeder = skillSeeder;
|
||||
@@ -61,6 +63,7 @@ public sealed class InteractiveLaunchSpecService
|
||||
_git = git;
|
||||
_claudePath = cfg.ClaudeBin;
|
||||
_handoffRounds = handoffRounds;
|
||||
_roundState = roundState;
|
||||
}
|
||||
|
||||
/// <summary>Builds a LaunchSpec for opening an interactive session in a task's worktree.
|
||||
@@ -342,9 +345,20 @@ public sealed class InteractiveLaunchSpecService
|
||||
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
|
||||
};
|
||||
|
||||
// The opening round. Recorded so anything watching a handler run knows which round is live
|
||||
// (the deferred-handoff follow-up needs that), but marked "triage" rather than a
|
||||
// MergeHelperPhase value on purpose: there is no handoff spec for this phase, so
|
||||
// HandlerRestartCoordinator will not reopen it.
|
||||
_roundState.Save(new HandlerRound(handlerTaskId, TriagePhase, taskIds, DateTime.UtcNow));
|
||||
|
||||
return new LaunchSpec(repoDir, resolvedClaude, args, env);
|
||||
}
|
||||
|
||||
/// <summary>The <see cref="HandlerRound.Phase"/> marker for the initial (dedupe/enhance) handler
|
||||
/// session. Deliberately not a <see cref="MergeHelperPhase"/> value — that set is exactly the
|
||||
/// phases <see cref="BuildForMergeHelperHandoffAsync"/> can rebuild.</summary>
|
||||
public const string TriagePhase = "triage";
|
||||
|
||||
// Builds the LaunchSpec for the fresh session a merge-helper run hands off to for the given
|
||||
// phase -- SAME handler task id as the run that called handoff_list_handler, so
|
||||
// HandlerBaseCommit/HandlerHeadCommit and the review range stay untouched; this never creates
|
||||
@@ -449,6 +463,11 @@ public sealed class InteractiveLaunchSpecService
|
||||
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
|
||||
};
|
||||
|
||||
// Persist the round that is about to start. Phase + task set only exist in the transient
|
||||
// HandoffRequested broadcast otherwise, so without this a dead tile cannot be reopened at
|
||||
// the same phase with the same set (see HandlerRestartCoordinator).
|
||||
_roundState.Save(new HandlerRound(taskId, nextPhase, survivingTaskIds, DateTime.UtcNow));
|
||||
|
||||
return new LaunchSpec(repoDir, resolvedClaude, args, env);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user