diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json
index 6cc41b17..8532aab2 100644
--- a/src/ClaudeDo.Localization/locales/de.json
+++ b/src/ClaudeDo.Localization/locales/de.json
@@ -253,7 +253,9 @@
}
},
"agent": {
- "openWorktreeTip": "Worktree im Datei-Explorer öffnen"
+ "openWorktreeTip": "Worktree im Datei-Explorer öffnen — benötigt einen aktiven Worktree",
+ "openDiffTip": "Diff öffnen — benötigt einen Worktree oder einen gemergten Commit-Bereich",
+ "reviewCombinedDiffTip": "Nur für Planning-Tasks mit Subtasks oder Child-Outcomes verfügbar"
},
"notes": {
"today": "Heute",
@@ -268,6 +270,9 @@
"chipFailed": "FEHLGESCHLAGEN",
"reviewContinueTip": "Dieses Feedback senden und die Aufgabe erneut ausführen",
"reviewResetTip": "Alle Änderungen verwerfen und die Aufgabe auf Leerlauf zurücksetzen",
+ "mergeDrainHint": "Merge zieht Subtasks ein — Abbrechen entsperrt sich danach",
+ "continueNoSessionTip": "Setzt den letzten Lauf fort — benötigt eine vorherige Session",
+ "resetAndRetryInteractiveTip": "Interaktive Sitzung ist offen — erst schließen",
"reviewFeedbackPlaceholder": "Feedback für nächsten Lauf"
},
"missionControl": {
diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json
index 0b8e6a72..3fecce43 100644
--- a/src/ClaudeDo.Localization/locales/en.json
+++ b/src/ClaudeDo.Localization/locales/en.json
@@ -253,7 +253,9 @@
}
},
"agent": {
- "openWorktreeTip": "Open worktree in file explorer"
+ "openWorktreeTip": "Open worktree in file explorer — requires an active worktree",
+ "openDiffTip": "Open the diff — requires a worktree or a merged commit range",
+ "reviewCombinedDiffTip": "Only available for planning tasks with subtasks or child outcomes"
},
"notes": {
"today": "Today",
@@ -268,7 +270,10 @@
"chipFailed": "FAILED",
"reviewContinueTip": "Send this feedback and re-run the task",
"reviewResetTip": "Discard all changes and reset the task to Idle",
- "reviewFeedbackPlaceholder": "Feedback for next run"
+ "reviewFeedbackPlaceholder": "Feedback for next run",
+ "mergeDrainHint": "Merge is draining subtasks — Cancel unlocks once it finishes",
+ "continueNoSessionTip": "Resumes the last run — needs a previous session to continue",
+ "resetAndRetryInteractiveTip": "Interactive session is open — close it first"
},
"missionControl": {
"windowTitle": "Mission Control",
diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs
index 1c07e0e4..35a9ad1b 100644
--- a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs
+++ b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs
@@ -1364,8 +1364,13 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
// fix); this just keeps the button from inviting a click the worker will reject anyway.
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CancelReviewCommand))]
+ [NotifyPropertyChangedFor(nameof(ShowMergeDrainHint))]
private bool _isMergeDraining;
+ // Drives the visible hint next to Cancel while a merge drain is in progress, so the
+ // silently-disabled button doesn't look broken.
+ public bool ShowMergeDrainHint => IsMergeDraining;
+
[RelayCommand(CanExecute = nameof(CanCancelReview))]
private async System.Threading.Tasks.Task CancelReviewAsync()
{
diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml
index 8f31a34e..0aeee9b1 100644
--- a/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml
+++ b/src/ClaudeDo.Ui/Views/Islands/Detail/WorkConsole.axaml
@@ -174,10 +174,14 @@
+ IsVisible="{Binding ShowContinue}"
+ ToolTip.Tip="{loc:Tr session.continueNoSessionTip}"
+ ToolTip.ShowOnDisabled="True" />
+ IsVisible="{Binding ShowResetAndRetry}"
+ ToolTip.Tip="{loc:Tr session.resetAndRetryInteractiveTip}"
+ ToolTip.ShowOnDisabled="True" />
@@ -341,9 +345,12 @@
@@ -371,6 +380,17 @@
Text="Open the diff to enable merge" />
+
+
+
+
+
+
diff --git a/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandReviewActionsTests.cs b/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandReviewActionsTests.cs
index efabc440..7ee5cabc 100644
--- a/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandReviewActionsTests.cs
+++ b/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandReviewActionsTests.cs
@@ -138,6 +138,24 @@ public class DetailsIslandReviewActionsTests : IDisposable
Assert.False(vm.ApproveReviewCommand.CanExecute(null));
}
+ [Fact]
+ public void ShowMergeDrainHint_IsTrueExactlyWhenMergeIsDraining()
+ {
+ var vm = BuildVm(new RecordingWorkerClient());
+ vm.Bind(new TaskRowViewModel { Id = "task-drain-1", Status = TaskStatus.WaitingForReview });
+
+ Assert.False(vm.ShowMergeDrainHint);
+ Assert.True(vm.CancelReviewCommand.CanExecute(null));
+
+ vm.IsMergeDraining = true;
+ Assert.True(vm.ShowMergeDrainHint);
+ Assert.False(vm.CancelReviewCommand.CanExecute(null));
+
+ vm.IsMergeDraining = false;
+ Assert.False(vm.ShowMergeDrainHint);
+ Assert.True(vm.CancelReviewCommand.CanExecute(null));
+ }
+
private sealed class ThrowingWorkerClient : StubWorkerClient
{
public override bool IsConnected => true;