fix(worker,ui): clean up three review leftovers from the list-handler run

Remove the redundant TaskUpdated broadcast in TaskRunner.ContinueAsync's
queue-claim path, consolidate InteractiveLaunchSpecService's seven
MCP_TOOL_TIMEOUT literals into one constant (fixing the merge-helper handoff
spec's stale 200000ms value), and surface OpenQuickClaudeSession's two
failure cases via ErrorReported/footer instead of a silent no-op, with a
less ambiguous icon.
This commit is contained in:
mika kuns
2026-08-06 11:31:03 +02:00
parent b66ce580de
commit b54a133c16
10 changed files with 220 additions and 17 deletions
+1 -1
View File
@@ -638,7 +638,7 @@
"taskStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "waitingForReview": "Wartet auf Prüfung", "waitingForChildren": "Wartet auf Teilaufgaben", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen", "parked": "Geparkt", "interactive": "Interaktiv" },
"planningBadge": { "active": "PLANUNG", "finalized": "GEPLANT" },
"taskRow": { "createdPrefix": "Erstellt {0}", "stepsText": "{0}/{1} Schritte" },
"tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}", "planningOpenFailed": "Planungssitzung konnte nicht geöffnet werden: {0}", "planningResumeFailed": "Planungssitzung konnte nicht fortgesetzt werden: {0}", "approveFailed": "Genehmigen & Mergen fehlgeschlagen: {0}", "moveRunningRejected": "Ein laufender Task kann nicht in eine andere Liste verschoben werden.", "moveWorktreeRejected": "Verschieben nicht möglich — dieser Task hat einen aktiven Worktree, der auf sein aktuelles Repo zeigt.", "moveRepoConfirm": "Unterschiedliche Repos — {0} → {1}. Task trotzdem verschieben?", "moveConfirmUnavailable": "Verschieben nicht möglich — der Bestätigungsdialog ist nicht verfügbar." },
"tasksIsland": { "completedHeader": "ABGESCHLOSSEN", "completedHeaderCount": "ABGESCHLOSSEN · {0}", "planningOpenFailed": "Planungssitzung konnte nicht geöffnet werden: {0}", "planningResumeFailed": "Planungssitzung konnte nicht fortgesetzt werden: {0}", "approveFailed": "Genehmigen & Mergen fehlgeschlagen: {0}", "moveRunningRejected": "Ein laufender Task kann nicht in eine andere Liste verschoben werden.", "moveWorktreeRejected": "Verschieben nicht möglich — dieser Task hat einen aktiven Worktree, der auf sein aktuelles Repo zeigt.", "moveRepoConfirm": "Unterschiedliche Repos — {0} → {1}. Task trotzdem verschieben?", "moveConfirmUnavailable": "Verschieben nicht möglich — der Bestätigungsdialog ist nicht verfügbar.", "quickClaudeNoWorkingDir": "Für diese Liste ist kein Arbeitsverzeichnis konfiguriert.", "quickClaudeDirMissing": "Arbeitsverzeichnis existiert nicht mehr: {0}" },
"diff": { "loadFailed": "Diff konnte nicht geladen werden: {0}", "noChanges": "Keine Änderungen anzuzeigen.", "unavailable": "Diff nicht mehr verfügbar — Commit-Bereich unvollständig." },
"planningDiff": { "hubError": "Kombinierte Vorschau konnte nicht erstellt werden (Hub-Fehler).", "conflict": "Kombinierte Vorschau nicht möglich: Teilaufgabe {0} steht im Konflikt mit einer früheren Teilaufgabe ({1} Dateien).", "buildFailed": "Kombinierte Vorschau konnte nicht erstellt werden: {0}" },
"merge": { "commitMessage": "Merge-Aufgabe: {0}", "workerOfflineBranches": "Worker offline — Branches können nicht aufgelistet werden.", "loadBranchesFailed": "Branches konnten nicht geladen werden: {0}", "merged": "Zusammengeführt.", "conflict": "Merge-Konflikt — Ziel-Branch wiederhergestellt. Manuell oder über Fortsetzen lösen, dann erneut versuchen.", "blocked": "Blockiert: {0}", "verifyFailed": "Merge ist gelandet, aber das Verify-Kommando der Liste ist fehlgeschlagen — die Aufgabe wurde nicht auf Erledigt gesetzt.", "unknownStatus": "Unbekannter Status: {0}", "mergeFailed": "Merge fehlgeschlagen: {0}" },
+1 -1
View File
@@ -638,7 +638,7 @@
"taskStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "waitingForReview": "Waiting for Review", "waitingForChildren": "Waiting for Subtasks", "done": "Done", "failed": "Failed", "cancelled": "Cancelled", "parked": "Parked", "interactive": "Interactive" },
"planningBadge": { "active": "PLANNING", "finalized": "PLANNED" },
"taskRow": { "createdPrefix": "Created {0}", "stepsText": "{0}/{1} steps" },
"tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}", "planningOpenFailed": "Couldn't open planning session: {0}", "planningResumeFailed": "Couldn't resume planning session: {0}", "approveFailed": "Approve & merge failed: {0}", "moveRunningRejected": "Can't move a running task to another list.", "moveWorktreeRejected": "Can't move — this task has an active worktree pointing at its current repo.", "moveRepoConfirm": "Different repos — {0} → {1}. Move the task anyway?", "moveConfirmUnavailable": "Can't move — the confirmation dialog isn't available." },
"tasksIsland": { "completedHeader": "COMPLETED", "completedHeaderCount": "COMPLETED · {0}", "planningOpenFailed": "Couldn't open planning session: {0}", "planningResumeFailed": "Couldn't resume planning session: {0}", "approveFailed": "Approve & merge failed: {0}", "moveRunningRejected": "Can't move a running task to another list.", "moveWorktreeRejected": "Can't move — this task has an active worktree pointing at its current repo.", "moveRepoConfirm": "Different repos — {0} → {1}. Move the task anyway?", "moveConfirmUnavailable": "Can't move — the confirmation dialog isn't available.", "quickClaudeNoWorkingDir": "This list has no working directory configured.", "quickClaudeDirMissing": "Working directory no longer exists: {0}" },
"diff": { "loadFailed": "Failed to load diff: {0}", "noChanges": "No changes to show.", "unavailable": "Diff no longer available — commit range incomplete." },
"planningDiff": { "hubError": "Could not build combined preview (hub error).", "conflict": "Cannot build combined preview: subtask {0} conflicts with an earlier subtask ({1} files).", "buildFailed": "Could not build combined preview: {0}" },
"merge": { "commitMessage": "Merge task: {0}", "workerOfflineBranches": "Worker offline — cannot list branches.", "loadBranchesFailed": "Failed to load branches: {0}", "merged": "Merged.", "conflict": "Merge conflict — target branch restored. Resolve manually or via Continue, then retry.", "blocked": "Blocked: {0}", "verifyFailed": "Merge landed, but the list's verify command failed — the task was kept out of Done.", "unknownStatus": "Unknown status: {0}", "mergeFailed": "Merge failed: {0}" },
@@ -88,7 +88,16 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
private void OpenQuickClaudeSession()
{
var dir = _currentList?.WorkingDir;
if (string.IsNullOrWhiteSpace(dir) || !System.IO.Directory.Exists(dir)) return;
if (string.IsNullOrWhiteSpace(dir))
{
ErrorReported?.Invoke(Loc.T("vm.tasksIsland.quickClaudeNoWorkingDir"));
return;
}
if (!System.IO.Directory.Exists(dir))
{
ErrorReported?.Invoke(Loc.T("vm.tasksIsland.quickClaudeDirMissing", dir));
return;
}
OpenQuickClaudeSessionRequested?.Invoke(dir);
}
@@ -39,7 +39,7 @@
</Button>
<Button Classes="icon-btn" IsVisible="{Binding IsQuickClaudeVisible}"
Command="{Binding OpenQuickClaudeSessionCommand}" ToolTip.Tip="{loc:Tr tasks.quickClaudeTip}">
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Plus}"/>
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.ArrowOut}"/>
</Button>
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
Command="{Binding ClearDayCommand}" ToolTip.Tip="{loc:Tr tasks.clearDayTip}">
+2 -2
View File
@@ -60,8 +60,8 @@ public sealed class ClaudeProcess : IClaudeProcess
// wait_for_task_change blocks up to TaskWaitMcpTools.MaxTimeoutSeconds (900 s) and the
// in-task AskUser tool blocks up to 3 min waiting for the user, so lift the cap well
// past the longer of the two (with margin) or that wait would be killed early. Harmless
// for every other tool. Keep in sync with InteractiveLaunchSpecService's MCP_TOOL_TIMEOUT.
psi.Environment["MCP_TOOL_TIMEOUT"] = "930000";
// for every other tool. Shares the value with InteractiveLaunchSpecService.McpToolTimeoutMs.
psi.Environment["MCP_TOOL_TIMEOUT"] = InteractiveLaunchSpecService.McpToolTimeoutMs;
using var process = new Process { StartInfo = psi };
process.Start();
@@ -27,6 +27,11 @@ namespace ClaudeDo.Worker.Runner;
// `--resume` pickup in a Windows Terminal window.
public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
{
// Claude Code caps HTTP MCP tool calls at 60s unless raised; every ConPTY spec built by this
// service lifts it well past wait_for_task_change's 900s server-side cap. Keep in sync with
// ClaudeProcess's own MCP_TOOL_TIMEOUT (same value, set independently for headless runs).
public const string McpToolTimeoutMs = "930000";
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
private readonly ISessionSkillSeeder _skillSeeder;
private readonly ISessionSkillRegistry _skillRegistry;
@@ -111,7 +116,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
// it is harmless for every other tool. Keep in sync with ClaudeProcess's MCP_TOOL_TIMEOUT.
var env = new Dictionary<string, string>
{
["MCP_TOOL_TIMEOUT"] = "930000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
return new LaunchSpec(worktree.Path, resolvedClaude, args, env);
@@ -129,7 +134,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
{
["MAX_THINKING_TOKENS"] = "20000",
["CLAUDEDO_PLANNING_TOKEN"] = ctx.Token,
["MCP_TOOL_TIMEOUT"] = "930000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
return new LaunchSpec(
@@ -147,7 +152,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
var env = new Dictionary<string, string>
{
["CLAUDEDO_PLANNING_TOKEN"] = ctx.Token,
["MCP_TOOL_TIMEOUT"] = "930000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
return new LaunchSpec(
@@ -170,7 +175,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
var env = new Dictionary<string, string>
{
["MCP_TOOL_TIMEOUT"] = "930000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
// No task and no list here — the global default model's preset decides the effort.
@@ -247,7 +252,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
var env = new Dictionary<string, string>
{
["MCP_TOOL_TIMEOUT"] = "930000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
return new LaunchSpec(repoDir, resolvedClaude, args, env);
@@ -320,7 +325,7 @@ public sealed class InteractiveLaunchSpecService : IInteractiveLaunchSpecService
var env = new Dictionary<string, string>
{
["MCP_TOOL_TIMEOUT"] = "200000",
["MCP_TOOL_TIMEOUT"] = McpToolTimeoutMs,
};
return new LaunchSpec(repoDir, resolvedClaude, args, env);
-1
View File
@@ -266,7 +266,6 @@ public sealed class TaskRunner
await _broadcaster.TaskUpdated(taskId);
}
await _broadcaster.TaskStarted(slot, taskId, now);
await _broadcaster.TaskUpdated(taskId);
await _skillSeeder.SeedAsync(runDir, resolvedConfig.SkillNames, wtCtx is not null, ct);