Drei neue app_settings-Spalten (Migration AddPowerUseWindow): power_use_window_start/end (HH:mm, lokal, nullable) und power_use_handoff_pct (NOT NULL DEFAULT 95, geclampt 50-99). Die Fensterlogik liegt als reine Funktion in PowerUseWindow (Contains/Normalize/IsOpen): beide Grenzen leer oder nur eine gesetzt = rund um die Uhr, Ende vor Start wrappt ueber Mitternacht, Grenzen halboffen. Geprueft wird in ComposeHandlerPromptAsync, also pro Phase zum Zeitpunkt des Prompt-Baus - die Uhr ist per Func<DateTime> injizierbar. Bedienung im Usage-Monitor neben dem PowerUse-Toggle (Commit auf Blur/Enter, ein Write fuer alle vier Felder); in Settings->General unsichtbar, aber load->save durchgereicht. Nebenbefund, gleicher Pfad: AppSettingsRepository.UpdateAsync kopiert Feld fuer Feld und hat ModelPresets, PowerUseEnabled und ListHandlerMaxHandoffs nie geschrieben - jeder Save dieser drei war still wirkungslos. Mit ergaenzt und per Round-trip-Test gepinnt.
224 lines
8.6 KiB
C#
224 lines
8.6 KiB
C#
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 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,
|
|
// PowerUse master switch — toggled on the usage monitor, not typed in Settings. Only takes
|
|
// effect for a list that also set PowerUseAllowed.
|
|
bool PowerUseEnabled = false,
|
|
int ListHandlerMaxHandoffs = 4,
|
|
// PowerUse time window (`HH:mm`, local, null = round the clock) + the 5h-usage percentage at
|
|
// which a PowerUse handler session should hand off. Also usage-monitor-owned, so Settings has
|
|
// to round-trip them too.
|
|
string? PowerUseWindowStart = null,
|
|
string? PowerUseWindowEnd = null,
|
|
int PowerUseHandoffPct = 95);
|
|
|
|
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, string? Icon = null);
|
|
|
|
// TicketProjectId is tri-state on purpose: a caller that doesn't own the field (anything but the
|
|
// list-settings modal) must not be able to clear it by omission — SetConfigAsync copies the entity
|
|
// verbatim. Its scale: null = keep stored, <= 0 = clear the link, > 0 = set it.
|
|
// PowerUseAllowed is nullable for the same reason: null = keep stored, false = revoke the opt-in.
|
|
// A non-nullable bool here would let any caller that omits it silently revoke PowerUse for the list.
|
|
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null, string? PermissionMode = null, int? TicketProjectId = null, bool? PowerUseAllowed = null);
|
|
|
|
public record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? PermissionMode = null);
|
|
|
|
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List<string>? SessionSkills = null, string? VerifyCommand = null, string? PermissionMode = null, int? TicketProjectId = null, bool PowerUseAllowed = false);
|
|
|
|
public record SeedResultDto(int Copied, int Skipped);
|
|
|
|
/// <param name="Value">What worker.config.json holds (a command name or a full path).</param>
|
|
/// <param name="ResolvedPath">Where it actually resolves to right now, or null if nothing resolves —
|
|
/// the whole point of surfacing this setting is telling those two cases apart.</param>
|
|
public record ClaudeBinDto(string Value, string? ResolvedPath);
|
|
|
|
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);
|
|
|
|
public record TicketSettingsDto(string? ApiBaseUrl, bool TokenSet);
|
|
public record TicketConnectionDto(bool Ok, string? UserName, IReadOnlyList<string> Scopes, string? Error);
|
|
public record TicketProjectDto(int Id, string Title, string DepartmentName);
|
|
public record TicketImportResultDto(int Examined, int Created);
|