feat(claude-do): merge Stream Claude CLI update progress into the footer strip
ClaudeDo-Task: 92130a5d447b4b0da301ce72e42c041a
This commit is contained in:
@@ -866,7 +866,7 @@
|
|||||||
},
|
},
|
||||||
"vm": {
|
"vm": {
|
||||||
"connection": { "online": "Online", "connecting": "Verbinden…", "offline": "Offline" },
|
"connection": { "online": "Online", "connecting": "Verbinden…", "offline": "Offline" },
|
||||||
"shell": { "unexpectedError": "Unerwarteter Fehler: {0}", "shutdownConfirm": "Dadurch wird der ClaudeDo-Worker beendet (laufende Task-Runs und interaktive Sitzungen brechen ab) und die App geschlossen. Fortfahren?" },
|
"shell": { "unexpectedError": "Unerwarteter Fehler: {0}", "updatingClaudeCli": "Claude CLI wird aktualisiert…", "shutdownConfirm": "Dadurch wird der ClaudeDo-Worker beendet (laufende Task-Runs und interaktive Sitzungen brechen ab) und die App geschlossen. Fortfahren?" },
|
||||||
"mainWindow": { "closeConfirm": { "message": "{0} Mission-Control-Sitzung(en) laufen noch. Beim Beenden werden sie abgebrochen. Trotzdem schließen?" } },
|
"mainWindow": { "closeConfirm": { "message": "{0} Mission-Control-Sitzung(en) laufen noch. Beim Beenden werden sie abgebrochen. Trotzdem schließen?" } },
|
||||||
"agentStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "review": "Prüfung", "children": "Wartet auf Teilaufgaben", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen" },
|
"agentStatus": { "idle": "Leerlauf", "queued": "In Warteschlange", "running": "Läuft", "review": "Prüfung", "children": "Wartet auf Teilaufgaben", "done": "Fertig", "failed": "Fehlgeschlagen", "cancelled": "Abgebrochen" },
|
||||||
"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", "waiting": "Wartet" },
|
"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", "waiting": "Wartet" },
|
||||||
|
|||||||
@@ -866,7 +866,7 @@
|
|||||||
},
|
},
|
||||||
"vm": {
|
"vm": {
|
||||||
"connection": { "online": "Online", "connecting": "Connecting…", "offline": "Offline" },
|
"connection": { "online": "Online", "connecting": "Connecting…", "offline": "Offline" },
|
||||||
"shell": { "unexpectedError": "Unexpected error: {0}", "shutdownConfirm": "This stops the ClaudeDo worker (any running task or interactive session is interrupted) and closes the app. Continue?" },
|
"shell": { "unexpectedError": "Unexpected error: {0}", "updatingClaudeCli": "Updating Claude CLI…", "shutdownConfirm": "This stops the ClaudeDo worker (any running task or interactive session is interrupted) and closes the app. Continue?" },
|
||||||
"mainWindow": { "closeConfirm": { "message": "{0} Mission Control session(s) are still running. Closing the app will end them. Close anyway?" } },
|
"mainWindow": { "closeConfirm": { "message": "{0} Mission Control session(s) are still running. Closing the app will end them. Close anyway?" } },
|
||||||
"agentStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "review": "Review", "children": "Waiting for Subtasks", "done": "Done", "failed": "Failed", "cancelled": "Cancelled" },
|
"agentStatus": { "idle": "Idle", "queued": "Queued", "running": "Running", "review": "Review", "children": "Waiting for Subtasks", "done": "Done", "failed": "Failed", "cancelled": "Cancelled" },
|
||||||
"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", "waiting": "Waiting" },
|
"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", "waiting": "Waiting" },
|
||||||
|
|||||||
@@ -206,6 +206,9 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
|||||||
// paint a good outcome red, which reads as a failure.
|
// paint a good outcome red, which reads as a failure.
|
||||||
public void FlashFooterSuccess(string message) => FlashFooter(message, WorkerLogLevel.Success);
|
public void FlashFooterSuccess(string message) => FlashFooter(message, WorkerLogLevel.Success);
|
||||||
|
|
||||||
|
// Same strip, for neutral in-progress text (e.g. a CLI's progress lines).
|
||||||
|
public void FlashFooterInfo(string message) => FlashFooter(message, WorkerLogLevel.Info);
|
||||||
|
|
||||||
private void FlashFooter(string message, WorkerLogLevel level)
|
private void FlashFooter(string message, WorkerLogLevel level)
|
||||||
{
|
{
|
||||||
if (level == WorkerLogLevel.Error)
|
if (level == WorkerLogLevel.Error)
|
||||||
@@ -749,8 +752,10 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
|||||||
{
|
{
|
||||||
_updatingClaudeCli = true;
|
_updatingClaudeCli = true;
|
||||||
UpdateClaudeCliCommand.NotifyCanExecuteChanged();
|
UpdateClaudeCliCommand.NotifyCanExecuteChanged();
|
||||||
|
var finished = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
FlashFooterInfo(Loc.T("vm.shell.updatingClaudeCli"));
|
||||||
var dto = Worker is null ? null : await Worker.GetClaudeBinAsync();
|
var dto = Worker is null ? null : await Worker.GetClaudeBinAsync();
|
||||||
if (dto is null)
|
if (dto is null)
|
||||||
{
|
{
|
||||||
@@ -758,18 +763,24 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (success, message) = await RunClaudeUpdateAsync(dto);
|
// `finished` is only touched on the UI thread: a queued line can't overwrite the final flash.
|
||||||
|
var (success, message) = await RunClaudeUpdateAsync(dto, line => Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
if (!finished) FlashFooterInfo(line);
|
||||||
|
}));
|
||||||
|
finished = true;
|
||||||
if (success) FlashFooterSuccess(message);
|
if (success) FlashFooterSuccess(message);
|
||||||
else FlashFooterError(message);
|
else FlashFooterError(message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
finished = true;
|
||||||
_updatingClaudeCli = false;
|
_updatingClaudeCli = false;
|
||||||
UpdateClaudeCliCommand.NotifyCanExecuteChanged();
|
UpdateClaudeCliCommand.NotifyCanExecuteChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<(bool Success, string Message)> RunClaudeUpdateAsync(ClaudeBinDto dto)
|
private static async Task<(bool Success, string Message)> RunClaudeUpdateAsync(ClaudeBinDto dto, Action<string> onStdoutLine)
|
||||||
{
|
{
|
||||||
var resolved = ClaudeDo.Data.Environment.ExecutableResolver.Resolve(dto.Value);
|
var resolved = ClaudeDo.Data.Environment.ExecutableResolver.Resolve(dto.Value);
|
||||||
if (resolved is null) return (false, $"Update failed: '{dto.Value}' not found.");
|
if (resolved is null) return (false, $"Update failed: '{dto.Value}' not found.");
|
||||||
@@ -785,7 +796,12 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
|||||||
using var process = new System.Diagnostics.Process { StartInfo = psi };
|
using var process = new System.Diagnostics.Process { StartInfo = psi };
|
||||||
var stdout = new System.Text.StringBuilder();
|
var stdout = new System.Text.StringBuilder();
|
||||||
var stderr = new System.Text.StringBuilder();
|
var stderr = new System.Text.StringBuilder();
|
||||||
process.OutputDataReceived += (_, e) => { if (e.Data is not null) stdout.AppendLine(e.Data); };
|
process.OutputDataReceived += (_, e) =>
|
||||||
|
{
|
||||||
|
if (e.Data is null) return;
|
||||||
|
stdout.AppendLine(e.Data);
|
||||||
|
if (!string.IsNullOrWhiteSpace(e.Data)) onStdoutLine(e.Data.Trim());
|
||||||
|
};
|
||||||
process.ErrorDataReceived += (_, e) => { if (e.Data is not null) stderr.AppendLine(e.Data); };
|
process.ErrorDataReceived += (_, e) => { if (e.Data is not null) stderr.AppendLine(e.Data); };
|
||||||
|
|
||||||
try { process.Start(); }
|
try { process.Start(); }
|
||||||
|
|||||||
Reference in New Issue
Block a user