refactor(ipc): declare the SignalR wire DTOs once in ClaudeDo.Data
WorkerHub and IWorkerClient each carried their own copy of every record and had already drifted — MergePreviewDto lost its verify fields on the client side, two records disagreed on their name. They now live in Data/Wire.cs and reach both sides via a <Using> item, so a hub signature change is a compile error instead of a silently dropped JSON field.
This commit is contained in:
@@ -0,0 +1,200 @@
|
|||||||
|
using ClaudeDo.Data.Models;
|
||||||
|
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
||||||
|
|
||||||
|
namespace ClaudeDo.Data.Wire;
|
||||||
|
|
||||||
|
// The SignalR contract between WorkerHub (server) and WorkerClient (client). Both used to
|
||||||
|
// declare their own copy of every record in this file; they drifted (MergePreviewDto lost its
|
||||||
|
// verify fields on the client side, two records disagreed on their name). One definition, so
|
||||||
|
// a hub signature change is a compile error instead of a silently dropped JSON field.
|
||||||
|
//
|
||||||
|
// Imported project-wide via a <Using Include="ClaudeDo.Data.Wire" /> item in the Ui, Worker
|
||||||
|
// and their test projects — that's why nothing here needs a per-file using.
|
||||||
|
|
||||||
|
public record ActiveTaskDto(string Slot, string TaskId, DateTime StartedAt);
|
||||||
|
|
||||||
|
public record WorkerBuildInfoDto(string? BuildSha);
|
||||||
|
|
||||||
|
public record AppSettingsDto(
|
||||||
|
string DefaultClaudeInstructions,
|
||||||
|
string DefaultModel,
|
||||||
|
int DefaultMaxTurns,
|
||||||
|
string DefaultPermissionMode,
|
||||||
|
int MaxParallelExecutions,
|
||||||
|
string WorktreeStrategy,
|
||||||
|
string? CentralWorktreeRoot,
|
||||||
|
bool WorktreeAutoCleanupEnabled,
|
||||||
|
int WorktreeAutoCleanupDays,
|
||||||
|
string? ReportExcludedPaths,
|
||||||
|
int StandupWeekday,
|
||||||
|
int DailyPrepMaxTasks,
|
||||||
|
List<string>? SessionSkills = null,
|
||||||
|
List<ModelPresetDto>? ModelPresets = null,
|
||||||
|
int UsageGateFiveHourPct = 80,
|
||||||
|
int UsageGateSevenDayPct = 90,
|
||||||
|
int MaxTurnsCeiling = 80,
|
||||||
|
// Throttle stages per bucket — dragged on the usage-monitor gauges, not typed in Settings.
|
||||||
|
int UsageThrottleFiveHourSoftPct = 50,
|
||||||
|
int UsageThrottleFiveHourHardPct = 65,
|
||||||
|
int UsageThrottleSevenDaySoftPct = 50,
|
||||||
|
int UsageThrottleSevenDayHardPct = 65,
|
||||||
|
bool AutoContinueOnUsageLimit = false);
|
||||||
|
|
||||||
|
public record ModelPresetDto(string Model, string Effort, int MaxTurns);
|
||||||
|
|
||||||
|
public record SessionSkillDto(
|
||||||
|
string Name,
|
||||||
|
string Description,
|
||||||
|
string SourceUrl,
|
||||||
|
string PinnedRef,
|
||||||
|
DateTimeOffset AddedAt);
|
||||||
|
|
||||||
|
public record WorktreeCleanupDto(int Removed);
|
||||||
|
|
||||||
|
public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
|
||||||
|
|
||||||
|
public record WorktreeOverviewDto(
|
||||||
|
string TaskId,
|
||||||
|
string TaskTitle,
|
||||||
|
TaskStatus TaskStatus,
|
||||||
|
string ListId,
|
||||||
|
string ListName,
|
||||||
|
string Path,
|
||||||
|
string BranchName,
|
||||||
|
string BaseCommit,
|
||||||
|
WorktreeState State,
|
||||||
|
string? DiffStat,
|
||||||
|
DateTime CreatedAt,
|
||||||
|
bool PathExistsOnDisk);
|
||||||
|
|
||||||
|
public record ForceRemoveResultDto(bool Removed, string? Reason);
|
||||||
|
|
||||||
|
public record PlanningMergeConflictStateDto(string PlanningTaskId, string SubtaskId);
|
||||||
|
|
||||||
|
public record PendingQuestionDto(string TaskId, string QuestionId, string Question);
|
||||||
|
|
||||||
|
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
|
||||||
|
|
||||||
|
public record BaseDirtyWarningDto(int ModifiedCount, int UntrackedCount);
|
||||||
|
|
||||||
|
public record SetTaskStatusResultDto(BaseDirtyWarningDto? BaseDirty);
|
||||||
|
|
||||||
|
public record MergePreviewDto(
|
||||||
|
string Status, IReadOnlyList<string> ConflictFiles, int ChangedFileCount,
|
||||||
|
int? VerifyExitCode = null, long? VerifyDurationMs = null, string? VerifyOutputTail = null);
|
||||||
|
|
||||||
|
public record MergeTargetsDto(
|
||||||
|
string DefaultBranch, IReadOnlyList<string> LocalBranches, string DefaultCommitMessage);
|
||||||
|
|
||||||
|
public record MergeConflictDocumentsDto(string TaskId, IReadOnlyList<ConflictDocumentDto> Files);
|
||||||
|
|
||||||
|
public record ConflictDocumentDto(string Path, bool IsBinary, IReadOnlyList<MergeSegmentDto> Segments);
|
||||||
|
|
||||||
|
public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string? Base, string Theirs);
|
||||||
|
|
||||||
|
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false);
|
||||||
|
|
||||||
|
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
||||||
|
|
||||||
|
public record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null);
|
||||||
|
|
||||||
|
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
||||||
|
|
||||||
|
public record SeedResultDto(int Copied, int Skipped);
|
||||||
|
|
||||||
|
public record OnlineInboxStateDto(
|
||||||
|
bool Enabled,
|
||||||
|
string ApiBaseUrl,
|
||||||
|
string Authority,
|
||||||
|
string ClientId,
|
||||||
|
string Scopes,
|
||||||
|
string RedirectUri,
|
||||||
|
bool SignedIn,
|
||||||
|
int PollIntervalSeconds);
|
||||||
|
|
||||||
|
public record OnlineInboxConfigInputDto(
|
||||||
|
bool Enabled,
|
||||||
|
string ApiBaseUrl,
|
||||||
|
int PollIntervalSeconds,
|
||||||
|
string Authority,
|
||||||
|
string ClientId,
|
||||||
|
string Scopes,
|
||||||
|
string RedirectUri);
|
||||||
|
|
||||||
|
public record UsageLimitDto(
|
||||||
|
string Kind,
|
||||||
|
string Group,
|
||||||
|
double Percent,
|
||||||
|
string Severity,
|
||||||
|
DateTimeOffset? ResetsAt,
|
||||||
|
string? ScopeModelDisplayName,
|
||||||
|
bool IsActive);
|
||||||
|
|
||||||
|
public record UsageSnapshotDto(
|
||||||
|
double? FiveHourPercent,
|
||||||
|
DateTimeOffset? FiveHourResetsAt,
|
||||||
|
double? SevenDayPercent,
|
||||||
|
DateTimeOffset? SevenDayResetsAt,
|
||||||
|
IReadOnlyList<UsageLimitDto> Limits,
|
||||||
|
int FiveHourThresholdPct,
|
||||||
|
int SevenDayThresholdPct,
|
||||||
|
bool IsGateBlocked,
|
||||||
|
string? GateReason,
|
||||||
|
DateTime? FetchedAtUtc,
|
||||||
|
bool IsStale,
|
||||||
|
string? LastError,
|
||||||
|
int ConfiguredSlots,
|
||||||
|
int EffectiveSlots,
|
||||||
|
string? ThrottleBucket,
|
||||||
|
// Throttle stages per bucket, drawn (and dragged) on the usage-monitor gauges. Defaults match
|
||||||
|
// the DB defaults so an older worker that doesn't send them yet still yields sane markers.
|
||||||
|
int ThrottleFiveHourSoftPct = 50,
|
||||||
|
int ThrottleFiveHourHardPct = 65,
|
||||||
|
int ThrottleSevenDaySoftPct = 50,
|
||||||
|
int ThrottleSevenDayHardPct = 65);
|
||||||
|
|
||||||
|
public record ModelUsageRowDto(
|
||||||
|
DateOnly Date,
|
||||||
|
string Model,
|
||||||
|
string Scope,
|
||||||
|
long InputTokens,
|
||||||
|
long OutputTokens,
|
||||||
|
long CacheReadTokens,
|
||||||
|
long CacheCreationTokens,
|
||||||
|
int Messages,
|
||||||
|
double? CostUsd = null);
|
||||||
|
|
||||||
|
public record TaskUsageRowDto(
|
||||||
|
string TaskId,
|
||||||
|
string TaskTitle,
|
||||||
|
string ListId,
|
||||||
|
string ListName,
|
||||||
|
string? Model,
|
||||||
|
int Runs,
|
||||||
|
long TokensIn,
|
||||||
|
long TokensOut,
|
||||||
|
double? CostUsd = null,
|
||||||
|
int? Retries = null,
|
||||||
|
bool? Productive = null,
|
||||||
|
bool? OneShot = null);
|
||||||
|
|
||||||
|
public record TokenTrackerDashboardDto(bool Ok, string? Url, string? Error);
|
||||||
|
|
||||||
|
public record TokenTrackerStatusDto(
|
||||||
|
bool Installed,
|
||||||
|
string? Version,
|
||||||
|
bool NodeOk,
|
||||||
|
string? NodeVersion,
|
||||||
|
DateTime? LastFetchedUtc,
|
||||||
|
string? LastError,
|
||||||
|
int? FormatVersion,
|
||||||
|
int SessionCount);
|
||||||
|
|
||||||
|
// What an embedded ConPTY terminal (UI process) needs to start a real `claude` process for
|
||||||
|
// a task's worktree, with the same setup as an autonomous run (session-skills seeded onto
|
||||||
|
// disk, the same run environment variables) plus the --resume-vs-fresh-start choice.
|
||||||
|
public sealed record LaunchSpec(
|
||||||
|
string Cwd,
|
||||||
|
string Exe,
|
||||||
|
IReadOnlyList<string> Args,
|
||||||
|
IReadOnlyDictionary<string, string> Env);
|
||||||
@@ -84,7 +84,7 @@ new editor boilerplate there rather than copying it a third time.
|
|||||||
|
|
||||||
## Services
|
## Services
|
||||||
|
|
||||||
- **WorkerClient / IWorkerClient** — SignalR client on `http://127.0.0.1:47821/hub`, auto-reconnect with exponential backoff. The surface **tracks `WorkerHub`** — treat `src/ClaudeDo.Worker/Hub/WorkerHub.cs` as the canonical method list rather than duplicating it here. Events mirror `HubBroadcaster`. Lifecycle (`StartAsync`/`StopAsync`) and a few admin methods live only on the concrete `WorkerClient`.
|
- **WorkerClient / IWorkerClient** — SignalR client on `http://127.0.0.1:47821/hub`, auto-reconnect with exponential backoff. The surface **tracks `WorkerHub`** — treat `src/ClaudeDo.Worker/Hub/WorkerHub.cs` as the canonical method list rather than duplicating it here. The wire DTOs are **not** declared here: they live once in `ClaudeDo.Data/Wire.cs` and reach both sides via a `<Using Include="ClaudeDo.Data.Wire" />` item in the csproj (Ui, Worker, and both test projects), so a hub signature change is a compile error instead of a silently dropped JSON field. Add new ones there, never a local copy. Events mirror `HubBroadcaster`. Lifecycle (`StartAsync`/`StopAsync`) and a few admin methods live only on the concrete `WorkerClient`.
|
||||||
- **INotesApi / WorkerNotesApi** — daily-note CRUD; UI DTO `DailyNoteDto(Id, Date, Text, SortOrder)`.
|
- **INotesApi / WorkerNotesApi** — daily-note CRUD; UI DTO `DailyNoteDto(Id, Date, Text, SortOrder)`.
|
||||||
- **IPrimeScheduleApi** — prime-schedule CRUD.
|
- **IPrimeScheduleApi** — prime-schedule CRUD.
|
||||||
- **UpdateCheckService** — polls releases; `LastCheckStatus`/`LatestVersion`/`CheckNowAsync` feed the shell's update banner.
|
- **UpdateCheckService** — polls releases; `LastCheckStatus`/`LatestVersion`/`CheckNowAsync` feed the shell's update banner.
|
||||||
@@ -95,8 +95,11 @@ new editor boilerplate there rather than copying it a third time.
|
|||||||
## Converters
|
## Converters
|
||||||
|
|
||||||
In `Converters/` — grep rather than list: log-level brush, dot brush,
|
In `Converters/` — grep rather than list: log-level brush, dot brush,
|
||||||
status equality, icon key, strike/italic/opacity toggles, null→bool,
|
status equality, icon key, `KeepLastNumber`. The one-expression ones
|
||||||
uppercase.
|
(strike/italic/opacity toggles, uppercase, not-a-header-row) share
|
||||||
|
`SimpleConverters.cs`; put new trivial ones there instead of a new file.
|
||||||
|
There is no null→bool converter — bind
|
||||||
|
`Converter={x:Static conv:ObjectConverters.IsNotNull}` (Avalonia ships it).
|
||||||
|
|
||||||
## Dialog Pattern
|
## Dialog Pattern
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ClaudeDo.Data\ClaudeDo.Data.csproj" />
|
<ProjectReference Include="..\ClaudeDo.Data\ClaudeDo.Data.csproj" />
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="ClaudeDo.Data.Wire" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AvaloniaResource Include="Assets/Fonts/*.ttf" />
|
<AvaloniaResource Include="Assets/Fonts/*.ttf" />
|
||||||
<AvaloniaResource Include="Assets/Fonts/OFL-InterTight.txt" />
|
<AvaloniaResource Include="Assets/Fonts/OFL-InterTight.txt" />
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public interface IWorkerClient : INotifyPropertyChanged
|
|||||||
|
|
||||||
string? LastApproveTarget { get; }
|
string? LastApproveTarget { get; }
|
||||||
|
|
||||||
IReadOnlyList<ActiveTask> GetActiveTasks();
|
IReadOnlyList<ActiveTaskDto> GetActiveTasks();
|
||||||
|
|
||||||
Task WakeQueueAsync();
|
Task WakeQueueAsync();
|
||||||
Task RunNowAsync(string taskId);
|
Task RunNowAsync(string taskId);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
|
|
||||||
namespace ClaudeDo.Ui.Services;
|
namespace ClaudeDo.Ui.Services;
|
||||||
|
|
||||||
public record ActiveTask(string Slot, string TaskId, DateTime StartedAt);
|
|
||||||
public sealed record WorkerLogEntry(string Message, WorkerLogLevel Level, DateTime TimestampUtc);
|
public sealed record WorkerLogEntry(string Message, WorkerLogLevel Level, DateTime TimestampUtc);
|
||||||
|
|
||||||
sealed class IndefiniteRetryPolicy : IRetryPolicy
|
sealed class IndefiniteRetryPolicy : IRetryPolicy
|
||||||
@@ -41,7 +40,7 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isReconnecting;
|
private bool _isReconnecting;
|
||||||
|
|
||||||
public ObservableCollection<ActiveTask> ActiveTasks { get; } = new();
|
public ObservableCollection<ActiveTaskDto> ActiveTasks { get; } = new();
|
||||||
|
|
||||||
public event Action<string, string, DateTime>? TaskStartedEvent;
|
public event Action<string, string, DateTime>? TaskStartedEvent;
|
||||||
public event Action<string, string, string, DateTime>? TaskFinishedEvent;
|
public event Action<string, string, string, DateTime>? TaskFinishedEvent;
|
||||||
@@ -77,7 +76,7 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
|
|
||||||
public string? LastApproveTarget { get; private set; }
|
public string? LastApproveTarget { get; private set; }
|
||||||
|
|
||||||
public IReadOnlyList<ActiveTask> GetActiveTasks() => ActiveTasks.ToList();
|
public IReadOnlyList<ActiveTaskDto> GetActiveTasks() => ActiveTasks.ToList();
|
||||||
|
|
||||||
public WorkerClient(string signalRUrl)
|
public WorkerClient(string signalRUrl)
|
||||||
{
|
{
|
||||||
@@ -118,7 +117,7 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
ActiveTasks.Add(new ActiveTask(slot, taskId, startedAt));
|
ActiveTasks.Add(new ActiveTaskDto(slot, taskId, startedAt));
|
||||||
TaskStartedEvent?.Invoke(slot, taskId, startedAt);
|
TaskStartedEvent?.Invoke(slot, taskId, startedAt);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -417,7 +416,7 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
{
|
{
|
||||||
ActiveTasks.Clear();
|
ActiveTasks.Clear();
|
||||||
foreach (var a in active)
|
foreach (var a in active)
|
||||||
ActiveTasks.Add(new ActiveTask(a.Slot, a.TaskId, a.StartedAt));
|
ActiveTasks.Add(new ActiveTaskDto(a.Slot, a.TaskId, a.StartedAt));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (HubException)
|
catch (HubException)
|
||||||
@@ -712,177 +711,5 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
=> await FinalizePlanningSessionAsync(taskId, queueAgentTasks, ct);
|
=> await FinalizePlanningSessionAsync(taskId, queueAgentTasks, ct);
|
||||||
async Task<int> IWorkerClient.GetPendingDraftCountAsync(string taskId, CancellationToken ct)
|
async Task<int> IWorkerClient.GetPendingDraftCountAsync(string taskId, CancellationToken ct)
|
||||||
=> await GetPendingDraftCountAsync(taskId, ct);
|
=> await GetPendingDraftCountAsync(taskId, ct);
|
||||||
|
|
||||||
// DTOs for deserializing hub responses
|
|
||||||
private sealed class ActiveTaskDto
|
|
||||||
{
|
|
||||||
public string Slot { get; set; } = "";
|
|
||||||
public string TaskId { get; set; } = "";
|
|
||||||
public DateTime StartedAt { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record AppSettingsDto(
|
|
||||||
string DefaultClaudeInstructions,
|
|
||||||
string DefaultModel,
|
|
||||||
int DefaultMaxTurns,
|
|
||||||
string DefaultPermissionMode,
|
|
||||||
int MaxParallelExecutions,
|
|
||||||
string WorktreeStrategy,
|
|
||||||
string? CentralWorktreeRoot,
|
|
||||||
bool WorktreeAutoCleanupEnabled,
|
|
||||||
int WorktreeAutoCleanupDays,
|
|
||||||
string? ReportExcludedPaths,
|
|
||||||
int StandupWeekday,
|
|
||||||
int DailyPrepMaxTasks,
|
|
||||||
List<string>? SessionSkills = null,
|
|
||||||
List<ModelPresetDto>? ModelPresets = null,
|
|
||||||
int UsageGateFiveHourPct = 80,
|
|
||||||
int UsageGateSevenDayPct = 90,
|
|
||||||
int MaxTurnsCeiling = 80,
|
|
||||||
// Throttle stages per bucket — dragged on the usage-monitor gauges, not typed in Settings.
|
|
||||||
int UsageThrottleFiveHourSoftPct = 50,
|
|
||||||
int UsageThrottleFiveHourHardPct = 65,
|
|
||||||
int UsageThrottleSevenDaySoftPct = 50,
|
|
||||||
int UsageThrottleSevenDayHardPct = 65,
|
|
||||||
bool AutoContinueOnUsageLimit = false);
|
|
||||||
|
|
||||||
// Per-model run defaults (effort + turn budget) edited in Settings → General.
|
|
||||||
public sealed record ModelPresetDto(string Model, string Effort, int MaxTurns);
|
|
||||||
|
|
||||||
public sealed record SessionSkillDto(
|
|
||||||
string Name,
|
|
||||||
string Description,
|
|
||||||
string SourceUrl,
|
|
||||||
string PinnedRef,
|
|
||||||
DateTimeOffset AddedAt);
|
|
||||||
|
|
||||||
public sealed record WorktreeCleanupDto(int Removed);
|
|
||||||
public sealed record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
|
|
||||||
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
|
|
||||||
public record BaseDirtyWarningDto(int ModifiedCount, int UntrackedCount);
|
|
||||||
public record SetTaskStatusResultDto(BaseDirtyWarningDto? BaseDirty);
|
|
||||||
public record MergePreviewDto(string Status, IReadOnlyList<string> ConflictFiles, int ChangedFileCount);
|
|
||||||
public record MergeTargetsDto(
|
|
||||||
string DefaultBranch, IReadOnlyList<string> LocalBranches, string DefaultCommitMessage);
|
|
||||||
public record MergeConflictDocumentsDto(string TaskId, IReadOnlyList<ConflictDocumentDto> Files);
|
|
||||||
public record ConflictDocumentDto(string Path, bool IsBinary, IReadOnlyList<MergeSegmentDto> Segments);
|
|
||||||
public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string? Base, string Theirs);
|
|
||||||
public sealed record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false);
|
|
||||||
public sealed record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
|
||||||
public sealed record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null);
|
|
||||||
public sealed record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
|
||||||
public sealed record SeedResultDto(int Copied, int Skipped);
|
|
||||||
|
|
||||||
public sealed record WorktreeOverviewDto(
|
|
||||||
string TaskId,
|
|
||||||
string TaskTitle,
|
|
||||||
ClaudeDo.Data.Models.TaskStatus TaskStatus,
|
|
||||||
string ListId,
|
|
||||||
string ListName,
|
|
||||||
string Path,
|
|
||||||
string BranchName,
|
|
||||||
string BaseCommit,
|
|
||||||
WorktreeState State,
|
|
||||||
string? DiffStat,
|
|
||||||
DateTime CreatedAt,
|
|
||||||
bool PathExistsOnDisk);
|
|
||||||
|
|
||||||
public sealed record LaunchSpec(
|
|
||||||
string Cwd,
|
|
||||||
string Exe,
|
|
||||||
IReadOnlyList<string> Args,
|
|
||||||
IReadOnlyDictionary<string, string> Env);
|
|
||||||
|
|
||||||
public sealed record ForceRemoveResultDto(bool Removed, string? Reason);
|
|
||||||
public sealed record PlanningMergeConflictStateDto(string PlanningTaskId, string SubtaskId);
|
|
||||||
public sealed record PendingQuestionDto(string TaskId, string QuestionId, string Question);
|
|
||||||
public sealed record WorkerBuildInfoDto(string? BuildSha);
|
|
||||||
|
|
||||||
public sealed record OnlineInboxStateDto(
|
|
||||||
bool Enabled,
|
|
||||||
string ApiBaseUrl,
|
|
||||||
string Authority,
|
|
||||||
string ClientId,
|
|
||||||
string Scopes,
|
|
||||||
string RedirectUri,
|
|
||||||
bool SignedIn,
|
|
||||||
int PollIntervalSeconds);
|
|
||||||
|
|
||||||
public sealed record OnlineInboxConfigInputDto(
|
|
||||||
bool Enabled,
|
|
||||||
string ApiBaseUrl,
|
|
||||||
int PollIntervalSeconds,
|
|
||||||
string Authority,
|
|
||||||
string ClientId,
|
|
||||||
string Scopes,
|
|
||||||
string RedirectUri);
|
|
||||||
|
|
||||||
public sealed record UsageLimitDto(
|
|
||||||
string Kind,
|
|
||||||
string Group,
|
|
||||||
double Percent,
|
|
||||||
string Severity,
|
|
||||||
DateTimeOffset? ResetsAt,
|
|
||||||
string? ScopeModelDisplayName,
|
|
||||||
bool IsActive);
|
|
||||||
|
|
||||||
public sealed record UsageSnapshotDto(
|
|
||||||
double? FiveHourPercent,
|
|
||||||
DateTimeOffset? FiveHourResetsAt,
|
|
||||||
double? SevenDayPercent,
|
|
||||||
DateTimeOffset? SevenDayResetsAt,
|
|
||||||
IReadOnlyList<UsageLimitDto> Limits,
|
|
||||||
int FiveHourThresholdPct,
|
|
||||||
int SevenDayThresholdPct,
|
|
||||||
bool IsGateBlocked,
|
|
||||||
string? GateReason,
|
|
||||||
DateTime? FetchedAtUtc,
|
|
||||||
bool IsStale,
|
|
||||||
string? LastError,
|
|
||||||
int ConfiguredSlots,
|
|
||||||
int EffectiveSlots,
|
|
||||||
string? ThrottleBucket,
|
|
||||||
// Throttle stages per bucket, drawn (and dragged) on the usage-monitor gauges. Defaults match
|
|
||||||
// the DB defaults so an older worker that doesn't send them yet still yields sane markers.
|
|
||||||
int ThrottleFiveHourSoftPct = 50,
|
|
||||||
int ThrottleFiveHourHardPct = 65,
|
|
||||||
int ThrottleSevenDaySoftPct = 50,
|
|
||||||
int ThrottleSevenDayHardPct = 65);
|
|
||||||
|
|
||||||
public sealed record ModelUsageRowDto(
|
|
||||||
DateOnly Date,
|
|
||||||
string Model,
|
|
||||||
string Scope,
|
|
||||||
long InputTokens,
|
|
||||||
long OutputTokens,
|
|
||||||
long CacheReadTokens,
|
|
||||||
long CacheCreationTokens,
|
|
||||||
int Messages,
|
|
||||||
double? CostUsd = null);
|
|
||||||
|
|
||||||
public sealed record TaskUsageRowDto(
|
|
||||||
string TaskId,
|
|
||||||
string TaskTitle,
|
|
||||||
string ListId,
|
|
||||||
string ListName,
|
|
||||||
string? Model,
|
|
||||||
int Runs,
|
|
||||||
long TokensIn,
|
|
||||||
long TokensOut,
|
|
||||||
double? CostUsd = null,
|
|
||||||
int? Retries = null,
|
|
||||||
bool? Productive = null,
|
|
||||||
bool? OneShot = null);
|
|
||||||
|
|
||||||
public sealed record TokenTrackerDashboardDto(bool Ok, string? Url, string? Error);
|
|
||||||
|
|
||||||
public sealed record TokenTrackerStatusDto(
|
|
||||||
bool Installed,
|
|
||||||
string? Version,
|
|
||||||
bool NodeOk,
|
|
||||||
string? NodeVersion,
|
|
||||||
DateTime? LastFetchedUtc,
|
|
||||||
string? LastError,
|
|
||||||
int? FormatVersion,
|
|
||||||
int SessionCount);
|
|
||||||
|
|||||||
@@ -177,7 +177,10 @@ Claude then calls `get_daily_prep_candidates`, picks an effort-aware subset capp
|
|||||||
|
|
||||||
## SignalR Hub
|
## SignalR Hub
|
||||||
|
|
||||||
`WorkerHub` is the canonical method list — grep it rather than trusting a doc inventory.
|
`WorkerHub` is the canonical method list — grep it rather than trusting a doc inventory. Its wire
|
||||||
|
DTOs live in `ClaudeDo.Data/Wire.cs` (shared with `IWorkerClient` via a `<Using>` item), **not** in
|
||||||
|
`WorkerHub.cs` — don't re-declare one locally, that's how `MergePreviewDto` lost its verify fields
|
||||||
|
on the client side.
|
||||||
Groups: execution · review/merge · conflict resolver · planning sessions · interactive ConPTY
|
Groups: execution · review/merge · conflict resolver · planning sessions · interactive ConPTY
|
||||||
launch specs · worktrees · agents/settings/lists · reports/notes/prep · diagnostics · usage.
|
launch specs · worktrees · agents/settings/lists · reports/notes/prep · diagnostics · usage.
|
||||||
`IWorkerClient` in `ClaudeDo.Ui` mirrors it.
|
`IWorkerClient` in `ClaudeDo.Ui` mirrors it.
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
<ApplicationIcon>ClaudeTaskWorker.ico</ApplicationIcon>
|
<ApplicationIcon>ClaudeTaskWorker.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="ClaudeDo.Data.Wire" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InternalsVisibleTo Include="ClaudeDo.Worker.Tests" />
|
<InternalsVisibleTo Include="ClaudeDo.Worker.Tests" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -28,174 +28,6 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace ClaudeDo.Worker.Hub;
|
namespace ClaudeDo.Worker.Hub;
|
||||||
|
|
||||||
public record ActiveTaskDto(string Slot, string TaskId, DateTime StartedAt);
|
|
||||||
|
|
||||||
/// <summary>Git SHA the running worker was built from. Null when the build wasn't stamped
|
|
||||||
/// (e.g. a local dev build without the SourceRevisionId target).</summary>
|
|
||||||
public record WorkerBuildInfoDto(string? BuildSha);
|
|
||||||
|
|
||||||
public record AppSettingsDto(
|
|
||||||
string DefaultClaudeInstructions,
|
|
||||||
string DefaultModel,
|
|
||||||
int DefaultMaxTurns,
|
|
||||||
string DefaultPermissionMode,
|
|
||||||
int MaxParallelExecutions,
|
|
||||||
string WorktreeStrategy,
|
|
||||||
string? CentralWorktreeRoot,
|
|
||||||
bool WorktreeAutoCleanupEnabled,
|
|
||||||
int WorktreeAutoCleanupDays,
|
|
||||||
string? ReportExcludedPaths,
|
|
||||||
int StandupWeekday,
|
|
||||||
int DailyPrepMaxTasks,
|
|
||||||
List<string>? SessionSkills = null,
|
|
||||||
List<ModelPresetDto>? ModelPresets = null,
|
|
||||||
int UsageGateFiveHourPct = 80,
|
|
||||||
int UsageGateSevenDayPct = 90,
|
|
||||||
int MaxTurnsCeiling = 80,
|
|
||||||
// Throttle stages per bucket — dragged on the usage-monitor gauges, not typed in Settings.
|
|
||||||
int UsageThrottleFiveHourSoftPct = 50,
|
|
||||||
int UsageThrottleFiveHourHardPct = 65,
|
|
||||||
int UsageThrottleSevenDaySoftPct = 50,
|
|
||||||
int UsageThrottleSevenDayHardPct = 65,
|
|
||||||
bool AutoContinueOnUsageLimit = false);
|
|
||||||
|
|
||||||
// Per-model run defaults (effort + turn budget) edited in Settings -> General.
|
|
||||||
public record ModelPresetDto(string Model, string Effort, int MaxTurns);
|
|
||||||
|
|
||||||
public record SessionSkillDto(
|
|
||||||
string Name,
|
|
||||||
string Description,
|
|
||||||
string SourceUrl,
|
|
||||||
string PinnedRef,
|
|
||||||
DateTimeOffset AddedAt);
|
|
||||||
|
|
||||||
public record WorktreeCleanupDto(int Removed);
|
|
||||||
public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
|
|
||||||
|
|
||||||
public record WorktreeOverviewDto(
|
|
||||||
string TaskId,
|
|
||||||
string TaskTitle,
|
|
||||||
ClaudeDo.Data.Models.TaskStatus TaskStatus,
|
|
||||||
string ListId,
|
|
||||||
string ListName,
|
|
||||||
string Path,
|
|
||||||
string BranchName,
|
|
||||||
string BaseCommit,
|
|
||||||
WorktreeState State,
|
|
||||||
string? DiffStat,
|
|
||||||
DateTime CreatedAt,
|
|
||||||
bool PathExistsOnDisk);
|
|
||||||
|
|
||||||
public record ForceRemoveResultDto(bool Removed, string? Reason);
|
|
||||||
public record PlanningMergeConflictStateDto(string PlanningTaskId, string SubtaskId);
|
|
||||||
public record PendingQuestionDto(string TaskId, string QuestionId, string Question);
|
|
||||||
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
|
|
||||||
public record BaseDirtyWarningDto(int ModifiedCount, int UntrackedCount);
|
|
||||||
public record SetTaskStatusResultDto(BaseDirtyWarningDto? BaseDirty);
|
|
||||||
// Verify* fields are always null on this path today -- the UI's live mergeability indicator never
|
|
||||||
// requests a verify run (that would mean an unrequested build on every preview poll); they exist so
|
|
||||||
// MergePreviewDto matches TaskMergeService.MergePreviewResult should a caller opt in later.
|
|
||||||
public record MergePreviewDto(
|
|
||||||
string Status, IReadOnlyList<string> ConflictFiles, int ChangedFileCount,
|
|
||||||
int? VerifyExitCode = null, long? VerifyDurationMs = null, string? VerifyOutputTail = null);
|
|
||||||
public record MergeTargetsDto(
|
|
||||||
string DefaultBranch, IReadOnlyList<string> LocalBranches, string DefaultCommitMessage);
|
|
||||||
public record MergeConflictDocumentsDto(string TaskId, IReadOnlyList<ConflictDocumentDto> Files);
|
|
||||||
public record ConflictDocumentDto(string Path, bool IsBinary, IReadOnlyList<MergeSegmentDto> Segments);
|
|
||||||
public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string? Base, string Theirs);
|
|
||||||
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false);
|
|
||||||
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
|
||||||
public record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null);
|
|
||||||
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null);
|
|
||||||
public record SeedResultDto(int Copied, int Skipped);
|
|
||||||
|
|
||||||
public record OnlineInboxStateDto(
|
|
||||||
bool Enabled,
|
|
||||||
string ApiBaseUrl,
|
|
||||||
string Authority,
|
|
||||||
string ClientId,
|
|
||||||
string Scopes,
|
|
||||||
string RedirectUri,
|
|
||||||
bool SignedIn,
|
|
||||||
int PollIntervalSeconds);
|
|
||||||
|
|
||||||
public record OnlineInboxConfigInput(
|
|
||||||
bool Enabled,
|
|
||||||
string ApiBaseUrl,
|
|
||||||
int PollIntervalSeconds,
|
|
||||||
string Authority,
|
|
||||||
string ClientId,
|
|
||||||
string Scopes,
|
|
||||||
string RedirectUri);
|
|
||||||
|
|
||||||
public record UsageLimitDto(
|
|
||||||
string Kind,
|
|
||||||
string Group,
|
|
||||||
double Percent,
|
|
||||||
string Severity,
|
|
||||||
DateTimeOffset? ResetsAt,
|
|
||||||
string? ScopeModelDisplayName,
|
|
||||||
bool IsActive);
|
|
||||||
|
|
||||||
public record UsageSnapshotDto(
|
|
||||||
double? FiveHourPercent,
|
|
||||||
DateTimeOffset? FiveHourResetsAt,
|
|
||||||
double? SevenDayPercent,
|
|
||||||
DateTimeOffset? SevenDayResetsAt,
|
|
||||||
IReadOnlyList<UsageLimitDto> Limits,
|
|
||||||
int FiveHourThresholdPct,
|
|
||||||
int SevenDayThresholdPct,
|
|
||||||
bool IsGateBlocked,
|
|
||||||
string? GateReason,
|
|
||||||
DateTime? FetchedAtUtc,
|
|
||||||
bool IsStale,
|
|
||||||
string? LastError,
|
|
||||||
int ConfiguredSlots,
|
|
||||||
int EffectiveSlots,
|
|
||||||
string? ThrottleBucket,
|
|
||||||
// Throttle stages per bucket, so the usage monitor can draw (and drag) them on each gauge.
|
|
||||||
int ThrottleFiveHourSoftPct,
|
|
||||||
int ThrottleFiveHourHardPct,
|
|
||||||
int ThrottleSevenDaySoftPct,
|
|
||||||
int ThrottleSevenDayHardPct);
|
|
||||||
|
|
||||||
public record ModelUsageRowDto(
|
|
||||||
DateOnly Date,
|
|
||||||
string Model,
|
|
||||||
string Scope,
|
|
||||||
long InputTokens,
|
|
||||||
long OutputTokens,
|
|
||||||
long CacheReadTokens,
|
|
||||||
long CacheCreationTokens,
|
|
||||||
int Messages,
|
|
||||||
double? CostUsd = null);
|
|
||||||
|
|
||||||
public record TaskUsageRowDto(
|
|
||||||
string TaskId,
|
|
||||||
string TaskTitle,
|
|
||||||
string ListId,
|
|
||||||
string ListName,
|
|
||||||
string? Model,
|
|
||||||
int Runs,
|
|
||||||
long TokensIn,
|
|
||||||
long TokensOut,
|
|
||||||
double? CostUsd = null,
|
|
||||||
int? Retries = null,
|
|
||||||
bool? Productive = null,
|
|
||||||
bool? OneShot = null);
|
|
||||||
|
|
||||||
public record TokenTrackerDashboardDto(bool Ok, string? Url, string? Error);
|
|
||||||
|
|
||||||
public record TokenTrackerStatusDto(
|
|
||||||
bool Installed,
|
|
||||||
string? Version,
|
|
||||||
bool NodeOk,
|
|
||||||
string? NodeVersion,
|
|
||||||
DateTime? LastFetchedUtc,
|
|
||||||
string? LastError,
|
|
||||||
int? FormatVersion,
|
|
||||||
int SessionCount);
|
|
||||||
|
|
||||||
public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||||
{
|
{
|
||||||
private static readonly string Version =
|
private static readonly string Version =
|
||||||
@@ -240,7 +72,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
private readonly Runner.PendingQuestionRegistry _pendingQuestions;
|
private readonly Runner.PendingQuestionRegistry _pendingQuestions;
|
||||||
private readonly LogRingBuffer? _logBuffer;
|
private readonly LogRingBuffer? _logBuffer;
|
||||||
private readonly ISessionSkillRegistry _skillRegistry;
|
private readonly ISessionSkillRegistry _skillRegistry;
|
||||||
private readonly IInteractiveLaunchSpecService? _interactiveLaunchSpec;
|
private readonly InteractiveLaunchSpecService? _interactiveLaunchSpec;
|
||||||
private readonly WorktreeManager? _worktreeManager;
|
private readonly WorktreeManager? _worktreeManager;
|
||||||
private readonly Data.Git.GitService? _git;
|
private readonly Data.Git.GitService? _git;
|
||||||
private readonly UsageSnapshotBuilder? _usageSnapshotBuilder;
|
private readonly UsageSnapshotBuilder? _usageSnapshotBuilder;
|
||||||
@@ -275,7 +107,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
Runner.PendingQuestionRegistry pendingQuestions,
|
Runner.PendingQuestionRegistry pendingQuestions,
|
||||||
ISessionSkillRegistry skillRegistry,
|
ISessionSkillRegistry skillRegistry,
|
||||||
LogRingBuffer? logBuffer = null,
|
LogRingBuffer? logBuffer = null,
|
||||||
IInteractiveLaunchSpecService? interactiveLaunchSpec = null,
|
InteractiveLaunchSpecService? interactiveLaunchSpec = null,
|
||||||
WorktreeManager? worktreeManager = null,
|
WorktreeManager? worktreeManager = null,
|
||||||
Data.Git.GitService? git = null,
|
Data.Git.GitService? git = null,
|
||||||
UsageSnapshotBuilder? usageSnapshotBuilder = null,
|
UsageSnapshotBuilder? usageSnapshotBuilder = null,
|
||||||
@@ -1162,7 +994,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
_onlineInboxConfig.PollIntervalSeconds);
|
_onlineInboxConfig.PollIntervalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetOnlineInboxConfig(OnlineInboxConfigInput input)
|
public void SetOnlineInboxConfig(OnlineInboxConfigInputDto input)
|
||||||
{
|
{
|
||||||
_onlineInboxConfig.Enabled = input.Enabled;
|
_onlineInboxConfig.Enabled = input.Enabled;
|
||||||
_onlineInboxConfig.ApiBaseUrl = input.ApiBaseUrl ?? "";
|
_onlineInboxConfig.ApiBaseUrl = input.ApiBaseUrl ?? "";
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="Xunit" />
|
<Using Include="Xunit" />
|
||||||
|
<Using Include="ClaudeDo.Data.Wire" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="12.0.4" />
|
<PackageReference Include="Avalonia" Version="12.0.4" />
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public abstract class StubWorkerClient : IWorkerClient
|
|||||||
public int ClearMyDayCalls { get; private set; }
|
public int ClearMyDayCalls { get; private set; }
|
||||||
public int RunDailyPrepNowCalls { get; private set; }
|
public int RunDailyPrepNowCalls { get; private set; }
|
||||||
|
|
||||||
public virtual IReadOnlyList<ActiveTask> GetActiveTasks() => System.Array.Empty<ActiveTask>();
|
public virtual IReadOnlyList<ActiveTaskDto> GetActiveTasks() => System.Array.Empty<ActiveTaskDto>();
|
||||||
|
|
||||||
public void RaiseTaskStarted(string slot, string taskId, DateTime startedAt) => TaskStartedEvent?.Invoke(slot, taskId, startedAt);
|
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 RaiseTaskFinished(string slot, string taskId, string status, DateTime finishedAt) => TaskFinishedEvent?.Invoke(slot, taskId, status, finishedAt);
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ public class MissionControlViewModelTests : IDisposable
|
|||||||
|
|
||||||
private sealed class SeededFakeWorker : StubWorkerClient
|
private sealed class SeededFakeWorker : StubWorkerClient
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<ActiveTask> GetActiveTasks()
|
public override IReadOnlyList<ActiveTaskDto> GetActiveTasks()
|
||||||
=> new[] { new ActiveTask("slot-1", "seed1", DateTime.UtcNow) };
|
=> new[] { new ActiveTaskDto("slot-1", "seed1", DateTime.UtcNow) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── acceptance criterion (b): RefreshQueueAsync returns Running rows first ─
|
// ── acceptance criterion (b): RefreshQueueAsync returns Running rows first ─
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="Xunit" />
|
<Using Include="Xunit" />
|
||||||
|
<Using Include="ClaudeDo.Data.Wire" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ sealed class FakeWorkerClient : IWorkerClient
|
|||||||
public Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
public Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
||||||
public Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
public Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
||||||
public Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
public Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
||||||
public IReadOnlyList<ActiveTask> GetActiveTasks() => System.Array.Empty<ActiveTask>();
|
public IReadOnlyList<ActiveTaskDto> GetActiveTasks() => System.Array.Empty<ActiveTaskDto>();
|
||||||
|
|
||||||
public Task<UsageSnapshotDto?> GetUsageSnapshotAsync() => Task.FromResult<UsageSnapshotDto?>(null);
|
public Task<UsageSnapshotDto?> GetUsageSnapshotAsync() => Task.FromResult<UsageSnapshotDto?>(null);
|
||||||
public Task<UsageSnapshotDto?> RefreshUsageAsync() => Task.FromResult<UsageSnapshotDto?>(null);
|
public Task<UsageSnapshotDto?> RefreshUsageAsync() => Task.FromResult<UsageSnapshotDto?>(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user