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 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? SessionSkills = null,
List? 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 ConflictFiles, string? ErrorMessage);
public record BaseDirtyWarningDto(int ModifiedCount, int UntrackedCount);
public record SetTaskStatusResultDto(BaseDirtyWarningDto? BaseDirty);
public record MergePreviewDto(
string Status, IReadOnlyList ConflictFiles, int ChangedFileCount,
int? VerifyExitCode = null, long? VerifyDurationMs = null, string? VerifyOutputTail = null);
public record MergeTargetsDto(
string DefaultBranch, IReadOnlyList LocalBranches, string DefaultCommitMessage);
public record MergeConflictDocumentsDto(string TaskId, IReadOnlyList Files);
public record ConflictDocumentDto(string Path, bool IsBinary, IReadOnlyList 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? 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? SessionSkills = null, string? PermissionMode = null);
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath, int? MaxTurns = null, List? SessionSkills = null, string? VerifyCommand = null, string? PermissionMode = null, int? TicketProjectId = null, bool PowerUseAllowed = false);
public record SeedResultDto(int Copied, int Skipped);
/// What worker.config.json holds (a command name or a full path).
/// 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.
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 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 Args,
IReadOnlyDictionary Env);
public record TicketSettingsDto(string? ApiBaseUrl, bool TokenSet);
public record TicketConnectionDto(bool Ok, string? UserName, IReadOnlyList Scopes, string? Error);
public record TicketProjectDto(int Id, string Title, string DepartmentName);
public record TicketImportResultDto(int Examined, int Created);