Commit Graph
1761 Commits
Author SHA1 Message Date
mika kuns 168ab1cd2f feat(merge): verify once per batch via skipVerify + verify_merges
Per-merge verify made an N-task batch pay N x ~7 min, each run testing
the same moving main. review_task/merge_task/continue_merge now take
skipVerify: the merge lands but the gate AND the Done transition are
deferred (status merged_verify_pending, task stays WaitingForReview).
The new verify_merges tool runs the list verify command once for the
explicitly listed tasks and promotes them to Done on success - explicit
ids so the handler own submitted task and parked verify_failed tasks
are never swept up; an Active worktree is refused per entry.

PlanningMergeOrchestrator threads the flag through the unit merge (no
more per-child verify) and skips FinalizeParentDoneAsync when verifies
were deferred. The merge-helper Merge prompt approves with
skipVerify=true and calls verify_merges once after the last merge. UI
approve is unchanged; the no-Done-without-green-verify invariant stays
server-enforced.
2026-08-26 15:29:20 +02:00
Mika Kuns c4928b4def chore: move appdata folder to .claudeDo 2026-08-26 14:26:19 +02:00
mika kuns 7fe8729603 chore(i18n): drop the locale keys nothing looks up anymore 2026-08-26 13:55:51 +02:00
mika kuns 0f007c5367 refactor: drop the remaining single-implementation interfaces
IBaseDirtyChecker, IInteractiveLaunchSpecService and the LaunchSpec wrapper
had one implementation and one caller each; ProcessRunnerAdapter existed only
to give a static class an interface, and InstallArtifactLocator used
inheritance for two constructor arguments. The external MCP container now
shares its singletons through a Share<T> helper instead of 17 near-identical
registrations.
2026-08-26 13:55:51 +02:00
mika kuns c593be2f02 refactor(ui): merge the one-expression converters into SimpleConverters.cs
Six files of three lines each. NotNullToBool is gone entirely — Avalonia
ships ObjectConverters.IsNotNull, so TaskRowView binds that directly.
2026-08-26 13:55:50 +02:00
mika kuns 8930b564e4 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.
2026-08-26 13:55:40 +02:00
mika kuns 39d8241360 refactor(data): squash the 40 migrations into one InitialCreate
The incremental chain was ~31k lines of generated Designer snapshots for a
schema no shipped database steps through anymore. MigrateAndConfigure now
baselines an existing DB onto the squashed id (pre-EF, or history ending at
AddPrimeActionKind) and throws with a reinstall message for a mid-chain DB.
MigrationBaselineTests covers all three paths with a real Migrate().
2026-08-26 13:55:30 +02:00
mika kuns 69fcceb2ed feat(worker): run both MCP servers stateless
Set Stateless = true on the internal (/mcp on the SignalR port) and external
MCP HTTP transports. Two effects:

- No Mcp-Session-Id, so a worker restart can no longer 404 a session that
  outlives it -- ConPTY tiles in the UI process and externally registered
  claude sessions keep working across a restart.
- A 2026-07-28 client is no longer refused back to the initialize handshake.
  A stateful server rejects that revision on purpose (see the SDK's
  StreamableHttpHandler.s_sessionSupportingProtocolVersions), so the new
  per-request protocol path was unreachable regardless of SDK version.

Nothing here used the stateful-only features (sampling, elicitation, resource
subscriptions, unsolicited notifications). In-tool progress notifications ride
the POST's own response stream and are unaffected -- which matters, since ~20
tools use them to hold off the client's 300s idle abort. All three consumers
(TaskRunner, PlanningSessionManager, the installer's RegisterMcpStep) already
register type: "http", so dropping the legacy SSE endpoint breaks nothing.

Verified against the running worker across two restarts: tools/list returns
57 tools over a bare POST with no initialize and no session id, and a full
2026-07-28 tools/call round-trip returns real data.
2026-08-26 11:05:31 +02:00
mika kuns f80af122e9 fix(worker): allow the done toggle from any non-Running status
MarkDoneAsync was Idle-only, so a finished task (typically a list-handler
run with no worktree to merge) could not be ticked off. Guard on Running
instead and cover the other statuses with tests.
2026-08-26 10:27:56 +02:00
mika kuns d71c0ceaef fix(ui): restore the Settings modal body and tidy the Prime schedule row
The re-templated TabControl dropped PART_ItemsPresenter, so no TabItem
containers were realized and SelectedContent stayed null -> empty body.
Keep the presenter collapsed instead. Also let the last-run label trim
with a tooltip rather than reserving a fixed MinWidth.
2026-08-26 10:27:49 +02:00
mika kuns 296251e27e refactor: collapse single-implementation interfaces
Nine interfaces had exactly one implementation and no test double — they existed
only to be named twice in a DI registration: IFindingsStore, IFindingsStoreLocator,
IPrimeScheduleSignal, IRefineRunner, IWeekReportService, IMergeCoordinator,
IMissionControlPane, IOnlineLoginService, ITaskListFilter. Consumers now depend on
the concrete type; the DTO records that shared those files moved next to their
implementation. IInteractiveLaunchSpecService stays — it carries 54 lines of
contract documentation, which is not ceremony.

IMergeCoordinator in particular had a redundant null object: MergeCoordinator with
a null Handler already no-ops, and every test used the real class with Handler set.

Filtering/ collapses from 8 files to 1. ITaskListFilter and TaskListFilterBase were
a double abstraction over four predicates, with MatchesAsContext => false declared
in both. SmartFlagFilter also compiled its expression twice (its own _flag plus the
inherited Matches cache) — it now uses the cache.

StaticTokenAuthProvider was in src but production uses ZitadelAuthProvider; it is
a test double, so it moves to the test project. Its own test goes away with it.
2026-08-26 10:12:23 +02:00
mika kuns 76d836a278 test: dedupe the nested test doubles into one shared file
TestDbFactory was redeclared as a private nested class in 40 test files,
NullServiceProvider and StubNotesApi in 14 each, DefaultStub in 5 — 73
declarations, all semantically identical (StubNotesApi differed only in
formatting and type qualification). They now live in TestDoubles.cs next to the
existing StubWorkerClient, which was already the shared-double pattern in this
project.
2026-08-26 10:11:58 +02:00
mika kuns 81994aadca 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).
2026-08-26 10:11:46 +02:00
mika kuns a1d74ab45d docs(prime): document the schedule action kinds 2026-08-25 09:12:10 +02:00
mika kuns f3cb34b904 feat(ui): add the Prime action radio group to settings 2026-08-25 09:10:25 +02:00
mika kuns 57be4961a8 feat(prime): add the action kind to the settings viewmodels 2026-08-25 09:01:33 +02:00
mika kuns 9ab17d827b fix(i18n): close the typographic quote that made de.json unparseable 2026-08-25 08:57:53 +02:00
mika kuns 514f142a4e feat(i18n): add Prime action-kind strings in en and de 2026-08-25 08:56:38 +02:00
mika kuns 4e8e0334b2 feat(prime): carry the action kind through the hub and validate custom prompts 2026-08-25 08:51:37 +02:00
mika kuns cf6a6b6208 feat(prime): branch PrimeRunner on the schedule action kind 2026-08-25 08:44:04 +02:00
mika kuns 71d2972a97 feat(prime): migrate prime_schedules with action_kind defaulting to ping 2026-08-25 08:33:17 +02:00
mika kuns c02a4cf871 test(prime): restore the PrimeScheduleRepository tests dropped in 022eaf38 2026-08-25 08:31:11 +02:00
mika kuns 022eaf385c feat(prime): add PrimeActionKind to the schedule entity 2026-08-25 08:29:40 +02:00
mika kuns 3003cfa561 feat(usage): open the TokenTracker dashboard from the usage monitor
The modal deliberately shows only a slice of the analytics; this hands off
to TokenTracker's own local dashboard for the rest. The worker starts
`tokentracker serve` on demand and returns the URL, the UI opens the browser.

Three things the spawn has to get right: port 7680 is not free on Windows
(Delivery Optimization holds [::]:7680) and serve does not fall back, so we
scan 7680-7689 with a dual-stack bind probe; --no-open because the CLI would
open the browser before the server answers; and the child is a cmd.exe shim,
so shutdown kills the process tree. --no-sync keeps our no-cloud-sync rule.
2026-08-24 16:51:00 +02:00
mika kuns 2dec590dfc docs(prime): implementation plan for schedule action kinds 2026-08-24 16:36:00 +02:00
mika kuns 884b990e22 docs(usage): add the TokenTracker analytics implementation plan 2026-08-24 16:29:10 +02:00
mika kuns c0bf7db628 docs(usage): document TokenTracker as the analytics backend 2026-08-24 16:28:52 +02:00
mika kuns a873eaa9e2 docs(prime): spec per-schedule action kind (Ping/FillMyDay/Custom) 2026-08-24 16:27:38 +02:00
mika kuns bf56cd8c75 test(ui): teach the worker-client fakes about TokenTracker status 2026-08-24 16:26:09 +02:00
mika kuns 074c0e4dbd feat(ui): show cost columns and the TokenTracker hint card in the usage monitor 2026-08-24 16:16:39 +02:00
mika kuns bac0d69a49 feat(ui): surface TokenTracker status and cost in the usage monitor 2026-08-24 16:15:02 +02:00
mika kuns 66f743dd43 feat(i18n): add TokenTracker analytics strings in en and de 2026-08-24 13:51:55 +02:00
mika kuns 3c3bb30696 feat(ui): add TokenTracker status, refresh and install to the worker client 2026-08-24 13:50:51 +02:00
mika kuns 40879705ac refactor(usage): drop the transcript aggregation path in favour of TokenTracker 2026-08-24 13:49:49 +02:00
mika kuns 44337d4b94 feat(usage): serve model and task usage from the TokenTracker export 2026-08-24 13:41:21 +02:00
mika kuns 3f3638c1ce feat(usage): cache the TokenTracker export with single-flight refresh 2026-08-24 13:39:20 +02:00
mika kuns a92180456d feat(usage): run the TokenTracker CLI through the shared executable resolver 2026-08-24 13:37:57 +02:00
mika kuns d6b22ea528 feat(usage): pin the TokenTracker CLI invocations 2026-08-24 13:36:59 +02:00
mika kuns 580d4e0717 feat(usage): hold the last good TokenTracker export fail-open 2026-08-24 13:36:59 +02:00
mika kuns 2fca0cc4d3 feat(usage): aggregate TokenTracker sessions by model and per task 2026-08-24 13:35:36 +02:00
mika kuns 106f9a374a feat(usage): parse the TokenTracker sessions export defensively 2026-08-24 13:34:01 +02:00
mika kuns 16952b6432 feat(usage): add TokenTracker export models and test fixture 2026-08-24 13:32:46 +02:00
mika kuns 1cb574bd96 feat(usage): reproduce TokenTracker session_hash for task attribution 2026-08-24 13:31:29 +02:00
mika kuns 0e74650d70 docs(usage): spec for TokenTracker as the token-analytics backend 2026-08-24 10:29:56 +02:00
Mika Kuns 664816881a refactor(claude-do): merge TaskRowViewModel: CanX und DisabledReason aus einer Gate-Met
ClaudeDo-Task: 6c4b27aa-1b5e-4d73-98f5-dcafa3935247
2026-08-24 10:08:55 +02:00
Mika Kuns 67083e1a4a refactor(claude-do): merge Dedupe: FormatRemaining aus UsagePill und UsageMonitorModal
ClaudeDo-Task: 94ea71ad-22a1-4612-8743-425d5fb43d75
2026-08-24 10:02:22 +02:00
Mika Kuns 9c59c77a28 refactor(claude-do): merge Dedupe: ShellOpen-Helper für "Pfad im Explorer öffnen" (5 Co
ClaudeDo-Task: 4084c060-3cf0-4474-930a-ea79695b9ba6
2026-08-24 09:54:37 +02:00
Mika Kuns b2a1b79029 refactor(ui): dedupe path-open helper across five view models
ListsIslandViewModel.OpenInExplorer, MergeSectionViewModel.OpenWorktree,
WorktreesOverviewModalViewModel.OpenInExplorer, AboutModalViewModel.OpenPath and
TasksIslandViewModel.OpenTaskWorktree each reimplemented "open this path in the
shell" with their own existence check, launch mechanism and error handling.
Replace all five with the new ShellOpen.Path helper and route failures through
the existing ErrorReported -> footer-strip convention instead of bare catch {}.
2026-08-24 09:38:41 +02:00
Mika Kuns d309302043 refactor(claude-do): merge Dedupe: "Liste hat ein verlinktes Repo?" — ein Prädikat stat
ClaudeDo-Task: 594ee78e-7112-427a-9cde-76f6610e7fd8
2026-08-24 09:38:36 +02:00
Mika Kuns baba921696 refactor(ui): derive TaskRowViewModel CanX/DisabledReason pairs from one gate method
SendToQueue, Cancel, Refine, Planning and OpenWorktree each had a CanX property
and a hand-written negation of it for the DisabledReason tooltip, kept in sync
only by a comment's promise. Replace each pair with a private gate method
returning (Can, Reason) so there is one source of truth per condition, and add
a state-matrix test pinning down the CanX == (Reason == null) invariant that
the old comment only asserted.
2026-08-24 09:36:00 +02:00