refactor: delete unreachable members and redundant package refs
Eight public members had no caller anywhere in src: GitService.GetFileDiffAsync, SubtaskRepository.DeleteByTaskIdAsync, TaskRepository.GetByListAsync (a backwards-compat alias for GetByListIdAsync) and .GetByCreatorAsync, WorktreeRepository.GetByStatesAsync, TaskMonitorViewModel.SetPendingQuestion (a duplicate of the live-event lambda), PrimeClaudeTabViewModel.ApplyFiredEvent, and StreamLineFormatter.FormatFile. TaskAttachmentRepository.DeleteAllForTaskAsync was reachable only from its own test; the ON DELETE CASCADE on task_attachments already covers it. Tests for the deleted members go with them. Dropped two package refs the platform already provides: EntityFrameworkCore.Design in Worker (the design-time factory and the migrations live in Data, which has its own ref) and System.IO.FileSystem.AccessControl in Installer.Tests (net8.0-windows ships the ACL APIs in the shared framework).
This commit is contained in:
@@ -53,7 +53,7 @@ Worker's `QueuePicker` (`FromSqlRaw`), **not** here.
|
||||
- **TaskRepository** — CRUD, planning helpers (`CreateChildAsync`, `SetPlanningStartedAsync`, `DiscardPlanningAsync`, `UpdateChildAsync`), `UpdateAgentSettingsAsync`. ⚠️ Status-mutation primitives (`MarkRunningAsync`/`MarkDoneAsync`/`MarkFailedAsync`/`FlipAllRunningToFailedAsync`) are **`internal`** — only the Worker's `TaskStateService` may call them. `CreateChildAsync` produces children with `Status=Idle, PlanningPhase=None`. **Task-number allocation:** `AddAsync` (line 20) and `CreateChildAsync` (line 276) are the two sole task-creation paths; both call `TaskNumberAllocator.AddWithNumberAsync` to allocate a number atomically during the same transaction as the insert. Every other creation path (UI, MCP `add_task`, `batch_add_tasks`, Online Inbox sync, merge-helper handler tasks, planning children) routes through one of these two.
|
||||
- **ListRepository** — CRUD, `GetConfigAsync`/`SetConfigAsync` (upsert)/`DeleteConfigAsync` for `list_config`
|
||||
- **WorktreeRepository** — CRUD, `UpdateHeadAsync`, `SetStateAsync`, `SetMergedAsync` (atomically sets State=Merged **and** stamps MergeCommit in one update — the only writer of MergeCommit)
|
||||
- **TaskAttachmentRepository** — `AddAsync`, `UpdateAsync`, `GetAsync(taskId, fileName)`, `ListByTaskIdAsync`, `DeleteAsync(taskId, fileName)`, `DeleteAllForTaskAsync`
|
||||
- **TaskAttachmentRepository** — `AddAsync`, `UpdateAsync`, `GetAsync(taskId, fileName)`, `ListByTaskIdAsync`, `DeleteAsync(taskId, fileName)`. Bulk delete-per-task is the `ON DELETE CASCADE` on `task_attachments`, not a repository method.
|
||||
- **DailyNoteRepository**, **WeekReportRepository**, **TaskRunRepository**, **SubtaskRepository**, **AppSettingsRepository**
|
||||
|
||||
`TaskRepository.DeleteAsync` and `ListRepository.DeleteAsync` also delete the on-disk attachment
|
||||
@@ -74,7 +74,7 @@ dir(s) via an optional `AttachmentStore` ctor param (defaults to the production
|
||||
- Worktrees: add (**serialized** to avoid a commondir race), remove, prune, list paths for branch
|
||||
- Branches: current, list local, checkout, delete
|
||||
- Staging/commit: status porcelain, add-all, add-path, commit via stdin
|
||||
- Diffs: working tree, branch vs base, commit range `base..head` (shows a merged task's diff after the worktree is gone), per-file, diff-stat, committed files, has-changes
|
||||
- Diffs: working tree, branch vs base, commit range `base..head` (shows a merged task's diff after the worktree is gone), diff-stat, committed files, has-changes
|
||||
- Merge: ff-only, no-ff, abort, mid-merge detection (`MERGE_HEAD`), conflicted files
|
||||
- Revert: `RevertMergeCommitAsync` (`git revert --no-edit -m 1 <sha>`), `RevertAbortAsync`, `IsMidRevertAsync` (`REVERT_HEAD`, mirrors `IsMidMergeAsync`)
|
||||
- `PreviewMergeAsync` (non-destructive check via `git merge-tree --write-tree`), `CountChangedFilesAsync`, rev-parse, is-git-repo
|
||||
|
||||
@@ -215,15 +215,6 @@ public sealed class GitService
|
||||
args.AddRange(paths);
|
||||
}
|
||||
|
||||
public async Task<string> GetFileDiffAsync(string worktreePath, string? baseCommit, string relativePath, CancellationToken ct = default)
|
||||
{
|
||||
string[] args = string.IsNullOrEmpty(baseCommit)
|
||||
? ["diff", "--", relativePath]
|
||||
: ["diff", $"{baseCommit}..HEAD", "--", relativePath];
|
||||
var (_, stdout, _) = await RunGitAsync(worktreePath, args, ct);
|
||||
return stdout;
|
||||
}
|
||||
|
||||
public async Task WorktreeRemoveAsync(string repoDir, string worktreePath, bool force = false, CancellationToken ct = default)
|
||||
{
|
||||
var args = new List<string> { "worktree", "remove" };
|
||||
|
||||
@@ -33,9 +33,4 @@ public sealed class SubtaskRepository
|
||||
{
|
||||
await _context.Subtasks.Where(s => s.Id == subtaskId).ExecuteDeleteAsync(ct);
|
||||
}
|
||||
|
||||
public async Task DeleteByTaskIdAsync(string taskId, CancellationToken ct = default)
|
||||
{
|
||||
await _context.Subtasks.Where(s => s.TaskId == taskId).ExecuteDeleteAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,4 @@ public sealed class TaskAttachmentRepository
|
||||
.ExecuteDeleteAsync(ct);
|
||||
}
|
||||
|
||||
public async Task DeleteAllForTaskAsync(string taskId, CancellationToken ct = default)
|
||||
{
|
||||
await _context.TaskAttachments
|
||||
.Where(a => a.TaskId == taskId)
|
||||
.ExecuteDeleteAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,6 @@ public sealed class TaskRepository
|
||||
await _context.SaveChangesAsync(ct);
|
||||
}
|
||||
|
||||
// Kept for backwards-compatibility with callers using the old name.
|
||||
public Task<List<TaskEntity>> GetByListAsync(string listId, CancellationToken ct = default)
|
||||
=> GetByListIdAsync(listId, ct);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ids of every descendant of <paramref name="taskId"/> (children, grandchildren, ...),
|
||||
/// walking the ParentTaskId chain breadth-first. Does not include the task itself.
|
||||
@@ -142,15 +138,6 @@ public sealed class TaskRepository
|
||||
.ExecuteUpdateAsync(s => s.SetProperty(t => t.SortOrder, (maxSort ?? -1) + 1), ct);
|
||||
}
|
||||
|
||||
public async Task<List<TaskEntity>> GetByCreatorAsync(string createdBy, CancellationToken ct = default)
|
||||
{
|
||||
return await _context.Tasks
|
||||
.AsNoTracking()
|
||||
.Where(t => t.CreatedBy == createdBy)
|
||||
.OrderByDescending(t => t.CreatedAt)
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all tasks that qualify as "real" Idle backlog items for online mirroring:
|
||||
/// Status==Idle, no parent, PlanningPhase==None, not blocked.
|
||||
|
||||
@@ -65,12 +65,4 @@ public sealed class WorktreeRepository
|
||||
{
|
||||
return await _context.Worktrees.AsNoTracking().ToListAsync(ct);
|
||||
}
|
||||
|
||||
public async Task<List<WorktreeEntity>> GetByStatesAsync(
|
||||
IReadOnlyCollection<WorktreeState> states, CancellationToken ct = default)
|
||||
{
|
||||
return await _context.Worktrees.AsNoTracking()
|
||||
.Where(w => states.Contains(w.State))
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,18 +312,6 @@ public class StreamLineFormatter
|
||||
return s.Length <= max ? s : s[..max] + "…";
|
||||
}
|
||||
|
||||
public string FormatFile(string filePath)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var line in File.ReadLines(filePath))
|
||||
{
|
||||
var formatted = FormatLine(line);
|
||||
if (formatted is not null)
|
||||
sb.Append(formatted);
|
||||
}
|
||||
return Trim(sb.ToString());
|
||||
}
|
||||
|
||||
public static string Trim(string text)
|
||||
{
|
||||
if (text.Length <= MaxLength) return text;
|
||||
|
||||
@@ -140,13 +140,6 @@ public sealed partial class TaskMonitorViewModel : ViewModelBase, IDisposable
|
||||
_worker.TaskQuestionResolvedEvent += _onTaskQuestionResolved;
|
||||
}
|
||||
|
||||
// Surface a pending question (used by live event + re-attach hydration).
|
||||
public void SetPendingQuestion(string questionId, string question)
|
||||
{
|
||||
PendingQuestionId = questionId;
|
||||
PendingQuestion = question;
|
||||
}
|
||||
|
||||
private void ClearPendingQuestion()
|
||||
{
|
||||
PendingQuestionId = null;
|
||||
|
||||
@@ -100,10 +100,4 @@ public sealed partial class PrimeClaudeTabViewModel : ViewModelBase
|
||||
Rows.Remove(row);
|
||||
}
|
||||
|
||||
public void ApplyFiredEvent(PrimeFiredEvent evt)
|
||||
{
|
||||
var row = Rows.FirstOrDefault(r => r.Id == evt.ScheduleId);
|
||||
if (row is null) return;
|
||||
if (evt.Success) row.LastRunAt = evt.FiredAt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
|
||||
@@ -86,19 +86,6 @@ public sealed class TaskAttachmentRepositoryTests : IDisposable
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAllForTask_clears_all_rows_for_task()
|
||||
{
|
||||
await _repo.AddAsync(MakeAttachment("a.txt"));
|
||||
await _repo.AddAsync(MakeAttachment("b.txt"));
|
||||
await _repo.AddAsync(MakeAttachment("c.txt"));
|
||||
|
||||
await _repo.DeleteAllForTaskAsync(TaskId);
|
||||
|
||||
var list = await _repo.ListByTaskIdAsync(TaskId);
|
||||
Assert.Empty(list);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListByTaskId_ordered_by_created_at()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -91,48 +91,5 @@ public class StreamLineFormatterTests
|
||||
Assert.Null(_formatter.FormatLine(delta));
|
||||
}
|
||||
|
||||
// --- FormatFile and Trim ---
|
||||
|
||||
[Fact]
|
||||
public void FormatFile_ParsesAllLinesAndReturnsFormattedText()
|
||||
{
|
||||
var lines = new[]
|
||||
{
|
||||
"""{"type":"assistant","message":{"content":[{"type":"text","text":"Hello"}]}}""",
|
||||
"""{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"Bash","input":{"command":"ls"}}]}}""",
|
||||
"""{"type":"result","result":"Done."}""",
|
||||
};
|
||||
var file = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
File.WriteAllLines(file, lines);
|
||||
var result = _formatter.FormatFile(file);
|
||||
Assert.Contains("Hello", result);
|
||||
Assert.Contains("[Bash]", result);
|
||||
Assert.Contains("Done.", result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatFile_TrimsLargeContent()
|
||||
{
|
||||
var chunk = new string('x', 1000);
|
||||
var line = "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"" + chunk + "\"}]}}";
|
||||
var lines = Enumerable.Repeat(line, 65).ToArray();
|
||||
var file = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
File.WriteAllLines(file, lines);
|
||||
var result = _formatter.FormatFile(file);
|
||||
Assert.True(result.Length <= 50_200, $"Expected <= 50200 but got {result.Length}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
// --- Trim ---
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user