TaskMonitorViewModel gains IsInteractiveLive + ComposerDraft + SubmitComposer (optimistic LogKind.User echo, then SendInteractiveMessageAsync) + StopInteractive, driven by the InteractiveSessionStarted/Ended events. Since DetailsIslandViewModel embeds this monitor, both task detail and Mission Control get the composer. Mission Control auto-creates a monitor on InteractiveSessionStarted. Adds LogKind.User.
156 lines
12 KiB
C#
156 lines
12 KiB
C#
using System.ComponentModel;
|
|
using ClaudeDo.Data.Models;
|
|
using ClaudeDo.Data.Repositories;
|
|
using ClaudeDo.Ui.Services;
|
|
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
|
|
|
namespace ClaudeDo.Ui.Tests;
|
|
|
|
/// <summary>
|
|
/// No-op <see cref="IWorkerClient"/> base for tests. Override only the members a
|
|
/// test actually exercises; everything else returns a benign default. Keeping the
|
|
/// full interface surface here means new interface members only break this file.
|
|
/// </summary>
|
|
public abstract class StubWorkerClient : IWorkerClient
|
|
{
|
|
#pragma warning disable CS0067 // interface-mandated events; tests don't raise them
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
public event Action<string, string, DateTime>? TaskStartedEvent;
|
|
public event Action<string, string, string, DateTime>? TaskFinishedEvent;
|
|
public event Action<string>? TaskUpdatedEvent;
|
|
public event Action? ConnectionRestoredEvent;
|
|
public event Action<string>? WorktreeUpdatedEvent;
|
|
public event Action<string>? ListUpdatedEvent;
|
|
public event Action<string, string>? TaskMessageEvent;
|
|
public event Action<WorkerLogEntry>? WorkerLogReceivedEvent;
|
|
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
|
public event Action<string, string>? TaskQuestionResolvedEvent;
|
|
public event Action<string>? InteractiveSessionStartedEvent;
|
|
public event Action<string>? InteractiveSessionEndedEvent;
|
|
public event Action? PrepStartedEvent;
|
|
public event Action<string>? PrepLineEvent;
|
|
public event Action<bool>? PrepFinishedEvent;
|
|
public event Action<string>? RefineStartedEvent;
|
|
public event Action<string, bool, string?>? RefineFinishedEvent;
|
|
public event Action<string, string>? PlanningMergeStartedEvent;
|
|
public event Action<string, string>? PlanningSubtaskMergedEvent;
|
|
public event Action<string, string, IReadOnlyList<string>>? PlanningMergeConflictEvent;
|
|
public event Action<string>? PlanningMergeAbortedEvent;
|
|
public event Action<string>? PlanningCompletedEvent;
|
|
public event Action<PrimeFiredEvent>? PrimeFired;
|
|
#pragma warning restore CS0067
|
|
|
|
public int ClearMyDayCalls { get; private set; }
|
|
public int RunDailyPrepNowCalls { get; private set; }
|
|
|
|
public virtual IReadOnlyList<ActiveTask> GetActiveTasks() => System.Array.Empty<ActiveTask>();
|
|
|
|
public void RaiseTaskStarted(string slot, string taskId, DateTime startedAt) => TaskStartedEvent?.Invoke(slot, taskId, startedAt);
|
|
public void RaiseTaskFinished(string slot, string taskId, string status, DateTime finishedAt) => TaskFinishedEvent?.Invoke(slot, taskId, status, finishedAt);
|
|
public void RaiseTaskMessage(string taskId, string line) => TaskMessageEvent?.Invoke(taskId, line);
|
|
public void RaiseTaskUpdated(string taskId) => TaskUpdatedEvent?.Invoke(taskId);
|
|
public void RaiseConnectionRestored() => ConnectionRestoredEvent?.Invoke();
|
|
public void RaiseTaskQuestionAsked(string taskId, string questionId, string question) => TaskQuestionAskedEvent?.Invoke(taskId, questionId, question);
|
|
public void RaiseTaskQuestionResolved(string taskId, string questionId) => TaskQuestionResolvedEvent?.Invoke(taskId, questionId);
|
|
|
|
public void RaisePrepStarted() => PrepStartedEvent?.Invoke();
|
|
public void RaisePrepLine(string line) => PrepLineEvent?.Invoke(line);
|
|
public void RaisePrepFinished(bool ok) => PrepFinishedEvent?.Invoke(ok);
|
|
|
|
public void RaiseInteractiveStarted(string taskId) => InteractiveSessionStartedEvent?.Invoke(taskId);
|
|
public void RaiseInteractiveEnded(string taskId) => InteractiveSessionEndedEvent?.Invoke(taskId);
|
|
|
|
public virtual bool IsConnected => false;
|
|
public virtual bool IsReconnecting => false;
|
|
public virtual string? LastApproveTarget => null;
|
|
|
|
public virtual Task WakeQueueAsync() => Task.CompletedTask;
|
|
public virtual Task RunNowAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task ContinueTaskAsync(string taskId, string followUpPrompt) => Task.CompletedTask;
|
|
public (string TaskId, string QuestionId, string Answer)? LastAnswer { get; private set; }
|
|
public virtual Task AnswerTaskQuestionAsync(string taskId, string questionId, string answer)
|
|
{
|
|
LastAnswer = (taskId, questionId, answer);
|
|
return Task.CompletedTask;
|
|
}
|
|
public PendingQuestionDto? PendingQuestion;
|
|
public virtual Task<PendingQuestionDto?> GetPendingQuestionAsync(string taskId) => Task.FromResult(PendingQuestion);
|
|
public virtual Task ResetTaskAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task CancelTaskAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task<List<AgentInfo>> GetAgentsAsync() => Task.FromResult(new List<AgentInfo>());
|
|
public virtual Task RefreshAgentsAsync() => Task.CompletedTask;
|
|
public virtual Task<SeedResultDto?> RestoreDefaultAgentsAsync() => Task.FromResult<SeedResultDto?>(null);
|
|
public virtual Task<ListConfigDto?> GetListConfigAsync(string listId) => Task.FromResult<ListConfigDto?>(null);
|
|
public virtual Task UpdateTaskAgentSettingsAsync(UpdateTaskAgentSettingsDto dto) => Task.CompletedTask;
|
|
public virtual Task SetTaskStatusAsync(string taskId, TaskStatus status) => Task.CompletedTask;
|
|
public virtual Task<MergeResultDto?> ApproveReviewAsync(string taskId, string targetBranch) => Task.FromResult<MergeResultDto?>(null);
|
|
public virtual Task<MergePreviewDto?> PreviewMergeAsync(string taskId, string targetBranch) => Task.FromResult<MergePreviewDto?>(null);
|
|
public virtual Task<MergeResultDto> MergeTaskAsync(string taskId, string targetBranch, bool removeWorktree, string commitMessage) => Task.FromResult(new MergeResultDto("merged", System.Array.Empty<string>(), null));
|
|
public virtual Task RejectReviewToQueueAsync(string taskId, string feedback) => Task.CompletedTask;
|
|
public virtual Task RejectReviewToIdleAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task CancelReviewAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task<MergeResultDto> StartConflictMergeAsync(string taskId, string targetBranch) => Task.FromResult(new MergeResultDto("conflict", System.Array.Empty<string>(), null));
|
|
public virtual Task<MergeConflictDocumentsDto> GetMergeConflictDocumentsAsync(string taskId) => Task.FromResult(new MergeConflictDocumentsDto(taskId, System.Array.Empty<ConflictDocumentDto>()));
|
|
public virtual Task WriteConflictResolutionAsync(string taskId, string path, string resolvedContent) => Task.CompletedTask;
|
|
public virtual Task<MergeResultDto> ContinueConflictMergeAsync(string taskId) => Task.FromResult(new MergeResultDto("merged", System.Array.Empty<string>(), null));
|
|
public virtual Task AbortConflictMergeAsync(string taskId) => Task.CompletedTask;
|
|
public virtual Task StartPlanningSessionAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
|
public virtual Task OpenInteractiveTerminalAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
|
public virtual Task ResumePlanningSessionAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
|
public virtual Task<DiscardPlanningOutcome> DiscardPlanningSessionAsync(string taskId, bool dequeueQueuedChildren = false, CancellationToken ct = default)
|
|
=> Task.FromResult(new DiscardPlanningOutcome(DiscardPlanningResult.Discarded, 0, 0));
|
|
public virtual Task FinalizePlanningSessionAsync(string taskId, bool queueAgentTasks = true, CancellationToken ct = default) => Task.CompletedTask;
|
|
public virtual Task<int> GetPendingDraftCountAsync(string taskId, CancellationToken ct = default) => Task.FromResult(0);
|
|
public virtual Task<MergeTargetsDto?> GetMergeTargetsAsync(string taskId) => Task.FromResult<MergeTargetsDto?>(null);
|
|
public virtual Task<IReadOnlyList<WorkerLogEntry>> GetRecentLogsAsync() => Task.FromResult<IReadOnlyList<WorkerLogEntry>>(Array.Empty<WorkerLogEntry>());
|
|
public virtual Task<IReadOnlyList<SubtaskDiffDto>> GetPlanningAggregateAsync(string planningTaskId)
|
|
=> Task.FromResult<IReadOnlyList<SubtaskDiffDto>>(Array.Empty<SubtaskDiffDto>());
|
|
public virtual Task<CombinedDiffResultDto?> BuildPlanningIntegrationBranchAsync(string planningTaskId, string targetBranch)
|
|
=> Task.FromResult<CombinedDiffResultDto?>(null);
|
|
public virtual Task ContinuePlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
|
public virtual Task AbortPlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
|
public virtual Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default) => Task.CompletedTask;
|
|
public virtual Task<string?> GetWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult<string?>(null);
|
|
public virtual Task<string> GenerateWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult("");
|
|
public virtual Task<bool> RunDailyPrepNowAsync() { RunDailyPrepNowCalls++; return Task.FromResult(false); }
|
|
public virtual Task ClearMyDayAsync() { ClearMyDayCalls++; return Task.CompletedTask; }
|
|
public virtual Task<AppSettingsDto?> GetAppSettingsAsync() => Task.FromResult<AppSettingsDto?>(null);
|
|
public virtual Task UpdateAppSettingsAsync(AppSettingsDto dto) => Task.CompletedTask;
|
|
public virtual Task<List<PrimeScheduleDto>> GetPrimeSchedulesAsync() => Task.FromResult(new List<PrimeScheduleDto>());
|
|
public virtual Task<PrimeScheduleDto?> UpsertPrimeScheduleAsync(PrimeScheduleDto dto) => Task.FromResult<PrimeScheduleDto?>(null);
|
|
public virtual Task DeletePrimeScheduleAsync(Guid id) => Task.CompletedTask;
|
|
public virtual Task UpdateListAsync(UpdateListDto dto) => Task.CompletedTask;
|
|
public virtual Task UpdateListConfigAsync(UpdateListConfigDto dto) => Task.CompletedTask;
|
|
public virtual Task<WorktreeCleanupDto?> CleanupFinishedWorktreesAsync(string? listId = null) => Task.FromResult<WorktreeCleanupDto?>(null);
|
|
public virtual Task<WorktreeResetDto?> ResetAllWorktreesAsync() => Task.FromResult<WorktreeResetDto?>(null);
|
|
public virtual Task<List<WorktreeOverviewDto>> GetWorktreesOverviewAsync(string? listId) => Task.FromResult(new List<WorktreeOverviewDto>());
|
|
public virtual Task<(bool Ok, string? Error)> SetWorktreeStateAsync(string taskId, WorktreeState newState) => Task.FromResult((true, (string?)null));
|
|
public virtual Task<ForceRemoveResultDto?> ForceRemoveWorktreeAsync(string taskId) => Task.FromResult<ForceRemoveResultDto?>(null);
|
|
public virtual Task<List<DailyNoteDto>> GetDailyNotesAsync(DateOnly day) => Task.FromResult(new List<DailyNoteDto>());
|
|
public virtual Task<DailyNoteDto?> AddDailyNoteAsync(DateOnly day, string text) => Task.FromResult<DailyNoteDto?>(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<string> GetLastPrepLogAsync() => Task.FromResult(LastPrepLog);
|
|
public virtual Task RefineTaskAsync(string taskId) => Task.CompletedTask;
|
|
|
|
public virtual Task<OnlineInboxStateDto?> GetOnlineInboxStateAsync() => Task.FromResult<OnlineInboxStateDto?>(null);
|
|
public virtual Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
|
public virtual Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
|
public virtual Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
|
public List<(string TaskId, string Text)> SentInteractive { get; } = new();
|
|
public virtual Task SendInteractiveMessageAsync(string taskId, string text)
|
|
{
|
|
SentInteractive.Add((taskId, text));
|
|
return Task.CompletedTask;
|
|
}
|
|
public List<string> StoppedInteractive { get; } = new();
|
|
public virtual Task StopInteractiveSessionAsync(string taskId)
|
|
{
|
|
StoppedInteractive.Add(taskId);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected void RaisePropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
|
}
|