Bisher gab es nur AppSettings.DefaultPermissionMode global — ein Task, der plan oder acceptEdits braucht, erzwang das Umstellen der globalen Einstellung. Neue Spalten tasks.permission_mode und list_config.permission_mode, Auflösung task -> list -> global im EffectiveRunConfigResolver (den TaskRunner und get_effective_run_config gemeinsam nutzen), ComboBox mit Inherited-Badge im geteilten Agent-Editor. MigrationBaselineTests: das Fixture baute per EnsureCreated das heutige Schema und stempelte Legacy-History darauf — jede Migration nach dem Squash lief damit in 'duplicate column name'. Es migriert jetzt gezielt bis InitialCreate und prueft 'nichts pending' statt 'InitialCreate ist die einzige Zeile'.
115 lines
5.5 KiB
C#
115 lines
5.5 KiB
C#
namespace ClaudeDo.Data.Models;
|
|
|
|
public enum TaskStatus
|
|
{
|
|
Idle,
|
|
Queued,
|
|
Running,
|
|
WaitingForReview,
|
|
WaitingForChildren,
|
|
Done,
|
|
Failed,
|
|
Cancelled,
|
|
}
|
|
|
|
public enum PlanningPhase
|
|
{
|
|
None,
|
|
Active,
|
|
Finalized,
|
|
}
|
|
|
|
public sealed class TaskEntity
|
|
{
|
|
public required string Id { get; init; }
|
|
// Global, monotonically increasing, never-reused display/lookup handle shown as `#123`.
|
|
// Allocated by TaskNumberAllocator from AppSettingsEntity.NextTaskNumber -- never MAX(number)+1,
|
|
// which would reissue a deleted task's number. The GUID Id stays the real identity everywhere else.
|
|
public int Number { get; set; }
|
|
public required string ListId { get; init; }
|
|
public required string Title { get; set; }
|
|
public string? Description { get; set; }
|
|
public TaskStatus Status { get; set; } = TaskStatus.Idle;
|
|
public PlanningPhase PlanningPhase { get; set; } = PlanningPhase.None;
|
|
public string? BlockedByTaskId { get; set; }
|
|
|
|
// A user/MCP-declared predecessor, distinct from BlockedByTaskId (the planning chain's own
|
|
// internal link): the picker also skips a Queued task while this is set and the referenced
|
|
// task's Status isn't Done. Unlike the chain, a Failed/Cancelled dependency does NOT cascade
|
|
// or auto-resolve -- the dependent just stays blocked and reports why (see TaskStateService.
|
|
// SetDependsOnAsync and QueuePicker).
|
|
public string? DependsOnTaskId { get; set; }
|
|
public DateTime? ScheduledFor { get; set; }
|
|
public string? Result { get; set; }
|
|
public string? ReviewFeedback { get; set; }
|
|
public int RoadblockCount { get; set; }
|
|
// Denormalized from the failing run, same pattern as RoadblockCount, so get_task/
|
|
// batch_get_tasks can report why a Failed task stopped without a second query.
|
|
// Null on a non-Failed task, or on a Failed task predating this field ("unknown").
|
|
public string? FailureReason { get; set; }
|
|
public int? FailureTurnsUsed { get; set; }
|
|
public int? FailureMaxTurns { get; set; }
|
|
// Set once QueueService's UsageLimitAutoContinueCoordinator fires ContinueTask for a
|
|
// FailureReason=="usage_limit" task. Guards against firing it a second time for the same
|
|
// task — never reset automatically, so auto-continue never loops on a repeat limit hit.
|
|
public DateTime? UsageLimitAutoContinuedAt { get; set; }
|
|
public string? LogPath { get; set; }
|
|
public required DateTime CreatedAt { get; init; }
|
|
public DateTime? StartedAt { get; set; }
|
|
public DateTime? FinishedAt { get; set; }
|
|
public string CommitType { get; set; } = CommitTypeRegistry.DefaultType;
|
|
public string? Model { get; set; }
|
|
public string? SystemPrompt { get; set; }
|
|
public string? AgentPath { get; set; }
|
|
public int? MaxTurns { get; set; }
|
|
// Null = inherit the list's config, then AppSettingsEntity.DefaultPermissionMode.
|
|
// One of PermissionModeRegistry.Modes.
|
|
public string? PermissionMode { get; set; }
|
|
public bool IsStarred { get; set; }
|
|
public bool IsMyDay { get; set; }
|
|
// Manual = a reminder only the user can do. Automation skips it (queue picker, daily prep,
|
|
// list handler) and the Claude affordances are hidden; a hand-driven ConPTY session is still
|
|
// allowed. New tasks in a manual list default to true.
|
|
public bool IsManual { get; set; }
|
|
public string? Notes { get; set; }
|
|
public int SortOrder { get; set; }
|
|
public string? SessionSkills { get; set; }
|
|
|
|
// Newline-separated declared file paths/globs this task expects to touch. User-supplied only
|
|
// (never inferred). Only consulted by the queue picker when the list's
|
|
// ListConfigEntity.SerializeOnFileOverlap is on, and only for this task's own overlap check --
|
|
// an unset value means "no basis to hold this task back", not "touches nothing".
|
|
public string? ScopeGlobs { get; set; }
|
|
|
|
// Review range for a worktree-less task hosting an interactive "list handler" run
|
|
// (Mission Control's "Let Claude handle it"): the handler commits its own changes
|
|
// straight to the list's working dir, so there is no per-task worktree to diff. These
|
|
// capture the repo's HEAD at session start / submit-for-review instead, so the normal
|
|
// diff/get_task_diff paths can show `HandlerBaseCommit..HandlerHeadCommit` over the
|
|
// list's working dir exactly like a merged task's commit-range diff.
|
|
public string? HandlerBaseCommit { get; set; }
|
|
public string? HandlerHeadCommit { get; set; }
|
|
|
|
// The claude session id an embedded ConPTY interactive task session is (or was last)
|
|
// running under -- generated up front and persisted before launch so a closed/aborted
|
|
// session can be resumed even if the process never got past startup. Cleared implicitly
|
|
// whenever the task's worktree is recreated (a fresh worktree has nothing to resume into).
|
|
public string? InteractiveSessionId { get; set; }
|
|
|
|
public string? ParentTaskId { get; set; }
|
|
public string? PlanningSessionId { get; set; }
|
|
public string? PlanningSessionToken { get; set; }
|
|
public DateTime? PlanningFinalizedAt { get; set; }
|
|
|
|
public string? CreatedBy { get; set; }
|
|
|
|
// Navigation properties
|
|
public ListEntity List { get; set; } = null!;
|
|
public WorktreeEntity? Worktree { get; set; }
|
|
public ICollection<TaskRunEntity> Runs { get; set; } = new List<TaskRunEntity>();
|
|
public ICollection<SubtaskEntity> Subtasks { get; set; } = new List<SubtaskEntity>();
|
|
|
|
public TaskEntity? Parent { get; set; }
|
|
public ICollection<TaskEntity> Children { get; set; } = new List<TaskEntity>();
|
|
}
|