From 914095dc993d206f02581c0998c20a51faddc0c1 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Thu, 4 Jun 2026 09:44:38 +0200 Subject: [PATCH] feat(daily-prep): load persisted prep log into the terminal on open Co-Authored-By: Claude Sonnet 4.6 --- .../Services/Interfaces/IWorkerClient.cs | 1 + src/ClaudeDo.Ui/Services/WorkerClient.cs | 3 +++ .../ViewModels/Islands/DetailsIslandViewModel.cs | 15 +++++++++++++++ tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs | 2 ++ .../ViewModels/DetailsIslandPrepModeTests.cs | 12 ++++++++++++ .../UiVm/TasksIslandViewModelPlanningTests.cs | 1 + 6 files changed, 34 insertions(+) diff --git a/src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs b/src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs index 37bfdd4..44ad197 100644 --- a/src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs +++ b/src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs @@ -63,4 +63,5 @@ public interface IWorkerClient : INotifyPropertyChanged Task AddDailyNoteAsync(DateOnly day, string text); Task UpdateDailyNoteAsync(string id, string text); Task DeleteDailyNoteAsync(string id); + Task GetLastPrepLogAsync(); } diff --git a/src/ClaudeDo.Ui/Services/WorkerClient.cs b/src/ClaudeDo.Ui/Services/WorkerClient.cs index 2f68131..83cdbdd 100644 --- a/src/ClaudeDo.Ui/Services/WorkerClient.cs +++ b/src/ClaudeDo.Ui/Services/WorkerClient.cs @@ -360,6 +360,9 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC public async Task DeleteDailyNoteAsync(string id) => await _hub.InvokeAsync("DeleteDailyNote", id); + public async Task GetLastPrepLogAsync() + => await TryInvokeAsync("GetLastPrepLog") ?? string.Empty; + public async Task UpdateListAsync(UpdateListDto dto) { await _hub.InvokeAsync("UpdateList", dto); diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs index 238edbe..5360151 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs @@ -518,6 +518,21 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase Bind(null); IsNotesMode = false; IsPrepMode = true; + _ = LoadLastPrepLogIfEmptyAsync(); + } + + public async Task LoadLastPrepLogIfEmptyAsync() + { + if (_worker is null || IsPrepRunning || PrepLog.Count > 0) return; + string text; + try { text = await _worker.GetLastPrepLogAsync(); } + catch { return; } + if (IsPrepRunning || PrepLog.Count > 0) return; + foreach (var line in text.Split('\n')) + { + var trimmed = line.TrimEnd('\r'); + if (trimmed.Length > 0) AppendStdoutLine(PrepLog, trimmed); + } } public void Bind(TaskRowViewModel? row) diff --git a/tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs b/tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs index c3793f9..47384cb 100644 --- a/tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs +++ b/tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs @@ -78,6 +78,8 @@ public abstract class StubWorkerClient : IWorkerClient public virtual Task AddDailyNoteAsync(DateOnly day, string text) => Task.FromResult(null); public virtual Task UpdateDailyNoteAsync(string id, string text) => Task.CompletedTask; public virtual Task DeleteDailyNoteAsync(string id) => Task.CompletedTask; + public string LastPrepLog = ""; + public virtual Task GetLastPrepLogAsync() => Task.FromResult(LastPrepLog); protected void RaisePropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } diff --git a/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandPrepModeTests.cs b/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandPrepModeTests.cs index 1e49d3e..19e15cf 100644 --- a/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandPrepModeTests.cs +++ b/tests/ClaudeDo.Ui.Tests/ViewModels/DetailsIslandPrepModeTests.cs @@ -80,4 +80,16 @@ public class DetailsIslandPrepModeTests : IDisposable Assert.False(vm.IsNotesMode); Assert.False(vm.IsTaskDetailVisible); } + + [Fact] + public async Task ShowPrep_loads_persisted_log_when_empty() + { + var stub = new DefaultStub { LastPrepLog = "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"restored\"}]}}" }; + var vm = NewDetailsVm(stub); + + vm.ShowPrep(); + await vm.LoadLastPrepLogIfEmptyAsync(); + + Assert.NotEmpty(vm.PrepLog); + } } diff --git a/tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs b/tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs index b87d3cf..2bcb75a 100644 --- a/tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs +++ b/tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs @@ -85,6 +85,7 @@ sealed class FakeWorkerClient : IWorkerClient public Task AddDailyNoteAsync(DateOnly day, string text) => Task.FromResult(null); public Task UpdateDailyNoteAsync(string id, string text) => Task.CompletedTask; public Task DeleteDailyNoteAsync(string id) => Task.CompletedTask; + public Task GetLastPrepLogAsync() => Task.FromResult(string.Empty); } // ── Helper to build VM with pre-seeded Items ──────────────────────────────────