Commit Graph
452 Commits
Author SHA1 Message Date
mika kuns 54b179fb0b fix(diff): resolve themed brushes and stop recomputing alignment on layout toggle 2026-08-07 10:23:45 +02:00
mika kuns f7fa8292e0 refactor(diff): render planning mode per file and retire DiffLinesView 2026-08-07 09:56:02 +02:00
mika kuns cf80fe3cd6 feat(diff): add persisted side-by-side and wrap toggles to the diff viewer 2026-08-07 09:42:43 +02:00
mika kuns 14e0cffa25 feat(diff): sync vertical scrolling across the split panes 2026-08-07 09:37:38 +02:00
mika kuns 861ba12f7f feat(diff): tint diff rows and changed words via background renderers 2026-08-07 09:36:37 +02:00
mika kuns e299421f76 feat(diff): draw old and new line numbers in a custom margin 2026-08-07 09:35:21 +02:00
mika kuns ffc60c4101 feat(diff): add AvaloniaEdit-based diff control with TextMate highlighting 2026-08-07 09:27:34 +02:00
mika kuns 57c61a2043 fix(ui): gate Mission Control submit-for-review, add retry, fix event leak
Submit for Review is now disabled while a ConPTY pane is starting, has
failed to launch, or has already exited, and MissionControlViewModel
guards against a rapid double-click racing two SubmitTaskForReviewAsync
calls. A failed launch no longer permanently occupies its TaskId dedupe
slot -- a Retry button re-fetches the launch spec and restarts the pane
in place. CloseConPtySession/Dispose now also unsubscribe
SubmitForReviewRequested, matching the other pane event handlers. Also
fixes the pre-existing nullable-dereference warning in
IslandsShellViewModel.SyncInteractiveSessionChips.
2026-08-06 13:42:06 +02:00
mika kuns aac84e48b7 fix(ui): keep ConPTY sessions alive across Mission Control layout rebuilds
TerminalView kills its child process on any logical-tree detach unless
BeginReparent() suppressed it, and RebuildOverviewGrid() detaches every
existing pane whenever one is added - so opening a second interactive
session killed the first. Focus-mode tab switches had the same defect.

PtyTerminalSession now puts the control in permanent reparent mode after
launch (teardown stays explicit via ConPtyPaneViewModel.Dispose -> Kill),
and the new ConPtyPaneHost reparents each pane's single long-lived view
across grid rebuilds and tab switches instead of letting the DataTemplate
instantiate a dead replacement.
2026-08-06 12:43:55 +02:00
mika kuns 20bce9b424 Merge branch 'claudedo/75514ee68371402b814638290af47cca' 2026-08-06 12:11:38 +02:00
mika kuns 5d1d2d89d0 fix(ui): suppress auto-open conflict resolver during MCP-driven merges
review_task/continue_merge on a planning parent always leaves conflicts in
the tree, and the UI auto-opened the resolver on every PlanningMergeConflict
broadcast regardless of who started the merge -- so a running Claude session
resolving a unit-merge conflict could race a human editing the same shared
checkout in a resolver window neither of them asked for.

PlanningMergeOrchestrator.StartAsync now takes an externallyDriven flag (set
by ExternalMcpService's MCP-driven review_task path, left false for the UI's
ApproveReview) that rides along on the PlanningMergeConflict broadcast. The
UI only auto-opens the resolver when it's false; otherwise it shows a
persistent banner with a manual "Open resolver" button, cleared on
PlanningMergeAborted/PlanningCompleted. A new GetActiveExternalConflictsAsync
query (checked against GitService.IsMidMergeAsync rather than the in-memory
flag alone) lets the UI resync the banner on reconnect instead of trusting a
one-shot broadcast that isn't replayed after a restart.

The childless single-task conflict path was checked and needed no change --
it only broadcasts the generic TaskUpdated, never PlanningMergeConflict.
2026-08-06 12:04:52 +02:00
mika kuns abac5e5150 Merge claudedo/c97dcaafbb3542bda9c670e502ffffb6 2026-08-06 11:43:07 +02:00
mika kuns 7240b39f16 Merge claudedo/3a3e87648400492bba6e9643007703db 2026-08-06 11:41:55 +02:00
mika kuns 8bc7bc0c4f feat(ui): warn when the running worker predates the selected repo's merged HEAD
Stamps ClaudeDo.Worker's build with its exact git SHA (SourceRevisionId ->
InformationalVersion) and exposes it via a new GetWorkerBuildInfo hub call.
For the currently selected list, the shell compares that SHA against the
list's git HEAD (GitService.IsAncestorAsync) and shows a persistent footer
banner -- never auto-clearing, never shown on an unrelated repo or when the
ancestry can't be determined -- so "verified against a merge" claims aren't
silently made against a stale process. No auto-restart; the banner just
offers the existing RestartWorkerCommand.
2026-08-06 11:36:26 +02:00
mika kuns b54a133c16 fix(worker,ui): clean up three review leftovers from the list-handler run
Remove the redundant TaskUpdated broadcast in TaskRunner.ContinueAsync's
queue-claim path, consolidate InteractiveLaunchSpecService's seven
MCP_TOOL_TIMEOUT literals into one constant (fixing the merge-helper handoff
spec's stale 200000ms value), and surface OpenQuickClaudeSession's two
failure cases via ErrorReported/footer instead of a silent no-op, with a
less ambiguous icon.
2026-08-06 11:31:03 +02:00
mika kuns 70322c203c Merge claudedo/7e54be27bc474883bc2389802123f55e 2026-08-06 11:13:30 +02:00
mika kuns 423ab7f2a9 chore(ui): remove dead AgentStripView fragment
AgentStripView was superseded by WorkConsole during the task-detail
redesign but never wired into any view and never deleted. Drops the
unused Border.agent-strip / diff-meter styles and the 14 agent.* locale
keys that only it referenced, and marks A4 in the feature-unification
spec as resolved by deletion.
2026-08-06 11:09:32 +02:00
mika kuns 68aa2f5f4b fix(ui): remove duplicate list-settings context menu entry
List settings were reachable via three doors (header button, context
menu, double-click). Drop the context menu entry, matching the same
cut already made for the "Let Claude handle it" entry point.
2026-08-06 11:07:31 +02:00
mika kuns 56f7d64f07 fix(ui): stop NumericUpDown from writing null into non-nullable settings
Clearing the text box to type a new value sets Value to null, which the TwoWay
binding then wrote into an int/decimal target -- InvalidCastException on the
normal way of editing eight settings fields. KeepLastNumberConverter maps that
null to BindingOperations.DoNothing so the source keeps its last value.
2026-08-06 10:20:53 +02:00
mika kuns 23794ed21b Merge claudedo/e3c29bf4538e491e9631ab80076b6fb4 2026-08-05 22:44:05 +02:00
mika kuns 0ce5bad9c1 Merge claudedo/5d8e6246af9444afa500fbb4546873e7 2026-08-05 22:43:41 +02:00
mika kuns f143d5fc18 Merge claudedo/64a2e2653d244714b76d637b3e0f3be8 2026-08-05 22:42:57 +02:00
mika kuns 487e75c031 Merge claudedo/a49fd666577a48b4b7d809bb915dfd48 2026-08-05 22:42:28 +02:00
mika kuns 6887b1d08d fix(ui): make Files-tab system prompts view-only, drop external-editor edit path
Editing a prompt file (even externally via "Open in editor") freezes it as a
user customization and blocks future default updates. The Files tab no longer
opens an external editor; it shows each prompt's content read-only in-app via
a new ViewPromptCommand, dropping the file-seeding side effect. Reset to
default and the customized-prompts deviation list are unchanged.
2026-08-05 21:00:34 +02:00
mika kuns df16989435 fix(ui): remove duplicate Let-Claude entry point and icon collision
Context-menu "Let Claude handle it" on list rows duplicated the header
button; both routed to the same ListsIslandViewModel command via the
shell, so only the context menu entry (and its now-unused locale key)
is removed. The header button also shared Icon.Broom with Clear Day —
gave it Icon.AgentSuggested instead.
2026-08-05 20:51:19 +02:00
mika kuns 8c251c78b1 feat(ui): add copy-last-40-lines button to log visualizer 2026-08-05 20:26:04 +02:00
mika kuns 2975f90f9d feat(settings): make max-turns ceiling editable in General tab 2026-08-05 20:21:05 +02:00
mika kuns 95eba1d5e7 feat(claude-do): Quick-Claude-Button in der Kopfleiste der Tasks-Insel: oeffn
## Ziel

Ein kleines Icon in der Kopfleiste der Tasks-Insel, das fuer die gerade ausgewaehlte Liste **sofort** eine interaktive ConPTY-Claude-Session im Arbeitsverzeichnis dieser Liste oeffnet — ohne Task, ohne Dialog, ohne Ordnerauswahl.

## Ausgangslage (verifiziert 2026-08-05)

Der komplette Unterbau existiert schon; das ist im Kern Verdrahtung:

- `MissionControlViewModel.OpenAdHocConPtySessio

ClaudeDo-Task: 5d8e6246af9444afa500fbb4546873e7
2026-08-05 20:18:22 +02:00
mika kuns 2700c3d817 fix(usage): stop 429s with an activity-dependent poll cadence + manual refresh
The usage monitor polled the undocumented OAuth usage endpoint every 60s and
earned 429s. It now polls every 5 min while any task is Running and every
15 min while idle (usage_poll_interval_active_seconds / _idle_seconds, both
clamped to >= 60; the old single usage_poll_interval_seconds key is gone).

A 429 comes back as UsageRateLimitedException carrying Retry-After and adds
exponential backoff on top, capped at 30 min and never shorter than the normal
cadence; the strike count resets on the first success. The schedule arithmetic
is the pure static UsagePollSchedule.NextDelay.

Since the idle cadence is slow on purpose, WorkerHub.RefreshUsage drives
UsageMonitorService.RefreshNowAsync behind a Refresh now button in the Usage
Monitor modal: an out-of-band poll that pushes the loop's next-due time out so
no double poll follows, with a 10s cooldown so click-spam can't earn a 429.

Staleness now measures against the slower (idle) interval so an idle worker
isn't flagged stale just for not polling.
2026-08-05 16:40:34 +02:00
mika kuns 79a1403834 Merge branch 'claudedo/87105f5ec4f44af4ae6089cd2e153e3c' 2026-08-05 16:10:37 +02:00
mika kuns 91eb2996c8 Merge branch 'claudedo/2de2f008758640b3a75e95719b1555bf' 2026-08-05 16:07:10 +02:00
mika kuns 19003e68b6 Merge claudedo/38394081d47048fea82317c6c52e01a5 2026-08-05 16:05:19 +02:00
mika kuns 2a217336e8 Merge claudedo/1b599d6711914658b9857b3df996f6e0 2026-08-05 16:03:14 +02:00
mika kuns b153869216 fix(prompts): stop on-disk prompt overrides from freezing forever
EnsureExists blindly seeded ~/.todo-app/prompts/*.md with the bundled
default and never revisited it, so any file created by opening the
Files settings tab shadowed every later default change permanently
(SuggestImprovement/AskUser sections never reached real runs since
2026-06-04). PromptFiles now hashes what a file was seeded/saved with
in prompts/.defaults.json: Classify() tells missing/current-default/
known-past-default/edited apart, ReconcileStaleDefaults() drops files
that only ever matched a superseded default, and real edits are left
alone and surfaced in the Files tab with a diff + reset-to-default
action. QuarantineOrphans() moves stale-named leftovers (agent.md,
planning.md) into prompts/_orphans instead of silently deleting them.
Wired as a Worker startup sweep (PromptFileRecovery) alongside the
existing OrphanRecovery/AttachmentOrphanRecovery services.
2026-08-05 15:59:03 +02:00
mika kuns a201d3f43d chore(claude-do): UsageGate: Parallelitaet stufenweise drosseln statt erst bei
## Kontext: Limits sind Fenster, nicht Summen

Die Runs laufen ueber das Claude-Abo. Limits greifen pro 5h-Fenster und pro 7 Tage. Nicht die Wochensumme tut weh, sondern dass ein Agent-Burst ein Fenster leerraeumt, in dem Mika selbst interaktiv arbeiten will.

## Messgrundlage (alle Transcripts unter ~/.claude/projects)

Agent-Runs sind ueber die ganze Historie nur **18,4 %** des Account-Verbrauch

ClaudeDo-Task: 87105f5e-c4f4-4af4-ae60-89cd2e153e3c
2026-08-05 15:53:15 +02:00
mika kuns 7d3d6d7b54 fix(worker): record real raw token usage per run, not the uncached remainder
task_runs.tokens_in only ever held the API's uncached "input_tokens" field
(off by a factor of ~400,000 on a resumed session), and tokens_out summed
only the last result event instead of the whole session. TaskRunner now
reads each run's cache-read/cache-write/input/output totals from the
session transcript via a new ITranscriptUsageReader.ReadSessionTotalsAsync,
storing the delta against prior runs on the same session so a --resume
doesn't double-count. New task_runs.cache_read_tokens/cache_write_tokens
columns; the Session tab now shows the raw total (what actually counts
against the 5h/7d usage limit) with a breakdown tooltip.
2026-08-05 15:44:20 +02:00
mika kuns 08ac8bf7b1 feat(worker): clamp max-turns to a configurable ceiling
Runaway sessions were the single biggest cost driver: model_presets was
never persisted (stayed code-only), default_max_turns shipped at 100, and
ResolveMaxTurns had no upper bound, so a task/list override could run
hundreds of turns unchecked.

- TaskRunner.ResolveMaxTurns now clamps the resolved value to
  AppSettings.MaxTurnsCeiling (new column, default 80) and logs a warning
  with task id / requested / effective value when it clamps.
- default_max_turns default lowered from 100 to 40 (entity, EF config,
  and the seeded row via the new AddMaxTurnsCeiling migration).
- AppSettingsRepository.GetAsync backfills model_presets with the
  shipping defaults on first read instead of leaving the column null.
- Settings > General's per-model preset table and the task/list agent
  editor now show a hint when a set max-turns value exceeds the ceiling.
2026-08-05 15:40:02 +02:00
mika kuns 3ea48ff76d feat(mission-control): make overview panes and queue strip individually resizable
Replace the UniformGrid (all tiles forced to equal size) with a real
Grid + GridSplitters built in code-behind per pane count/column count,
so panes resize individually. The queue strip's fixed 210px column
becomes a drag-resizable Grid column (min 160px) that collapses to 0
when nothing is queued, replacing the old dock-based fixed width.
2026-08-05 15:29:00 +02:00
mika kuns 57326f1d3b fix(ui): avoid int CommandParameter cast crash in usage monitor presets
RelayCommand<int> casts its object parameter directly rather than
converting it, so a string CommandParameter ("7"/"30") would throw
InvalidCastException at runtime. Split into two parameterless commands.
2026-08-05 13:58:40 +02:00
mika kuns 8103006e26 feat(ui): add usage monitor modal with gauges and model/task usage analysis
Adds a Usage Monitor modal (Worker menu + wired to the footer/Mission-Control
usage pill's Open command): dynamic gauges built from UsageSnapshotDto.Limits
with gate-threshold marks, a stale/blocked-gate band, and Models/Tasks tabs
backed by GetModelUsageAsync/GetTaskUsageAsync over a 7d/30d/custom range.
2026-08-05 13:57:21 +02:00
mika kuns 1e88fefbda feat(claude-do): UI: Gate-Schwellen im Settings-Modal (General)
Macht die zwei Schwellen einstellbar. Setzt den Data-Subtask (Felder in `app_settings`) und den Hub-Subtask voraus.

**Zu bauen**
1. `AppSettingsDto` durchziehen: `WorkerHub` (`GetAppSettings` / `UpdateAppSettings`) und der UI-seitige Record in `WorkerClient.cs` bekommen `UsageGateFiveHourPct` und `UsageGateSevenDayPct`.
2. `GeneralSettingsTabViewModel`: zwei `[ObservableProperty]`-Felder, Validie

ClaudeDo-Task: 06068810-5b5c-4635-80dd-62eeba89fb8c
2026-08-05 13:38:05 +02:00
mika kuns 7cbd4e66ae feat(ui): add usage pill to footer and mission control header
Adds the IWorkerClient/WorkerClient usage surface (GetUsageSnapshot,
GetModelUsage, GetTaskUsage, UsageUpdated event) and a shared
UsagePillViewModel hosted once in IslandsShellViewModel (footer) and
once in MissionControlViewModel (header), showing "5h X% · 7d Y%"
with warn/blocked/stale states via existing design tokens. The
OpenMonitorCommand is wired but currently a no-op, pending the usage
monitor modal.
2026-08-05 13:16:29 +02:00
mika kuns 519ea5a8e0 Merge claudedo/8c1c213004574c4fad6beb75b84b70d7 2026-08-05 12:15:21 +02:00
mika kuns d2ca7fb500 feat(ui): add roadblock reply field to the ROADBLOCK card
A task that reports a roadblock but finishes successfully (Done/WaitingForReview/
Failed/Cancelled) had no way to answer it short of a full reset-and-rerun, losing
the run's context. Adds a reply textbox + Send button to the existing ROADBLOCK
card, modeled on the AskUser question card, that resumes the session via
ContinueTaskAsync with the user's own text. Gated on LatestRunSessionId (disabled
with a hint when there's nothing to resume); failures surface through the footer
error strip instead of a modal.
2026-08-05 11:49:33 +02:00
mika kuns c9ba1e2645 feat(worker): add post-merge verification gate for list merges
Per-list optional VerifyCommand (list_config.verify_command) runs via
VerifyCommandRunner in the list's working dir right after a successful
merge/continue-merge, before the task is allowed to reach Done. A
non-zero exit or timeout leaves the merge in place but keeps the task
out of Done and reports StatusVerifyFailed with an output excerpt
through MergeResultDto/review_task; no command configured behaves
exactly as before. Merges against the same repo are now serialized
per working dir so a running verify can't be interrupted by a second
merge landing mid-build. Adds the field to the List Settings modal
(en/de localized) and covers success/failure/timeout in
TaskMergeServiceTests + VerifyCommandRunnerTests.
2026-08-05 11:19:22 +02:00
mika kuns cc3013a76e Merge claudedo/ff453a6b9db849cd9b076fc63fe5399a 2026-08-05 09:29:51 +02:00
mika kuns 7d29ec0725 Merge branch 'claudedo/df0e925e1ff4419d8b7a45f8a184f6d0' 2026-08-05 09:26:46 +02:00
mika kuns 47edab5907 feat(ui): show newest log entries first in Log Visualizer
Reverses row order in LogVisualizerViewModel.Apply() so the most recent
entry sits at index 0, matching the "what just happened" use case;
filtering and refresh are unaffected since the reversal happens after
the warn/error filter is applied.
2026-08-05 09:08:30 +02:00
mika kuns 87de53e052 refactor(ui): remove pick-up-in-terminal, keep ConPTY as the single session entry
Two context-menu entries opened a Claude session for the same task via different
mechanisms (embedded ConPTY vs. an external wt terminal). Drop the external-terminal
path entirely, including its worker hub method, launcher plumbing, and localization
keys, since the embedded ConPTY session already covers every case it did.
2026-08-05 09:05:46 +02:00
mika kuns c82ea2eea1 chore(ui): remove dead Mission Control monitor-pane stack
Auto-seeding of monitor tiles was disabled in 724814f; Mission Control now
only shows ConPTY panes. Removes Monitors/EnsureMonitor/SeedActive, the
detach/re-dock machinery, MonitorPaneView and the detached monitor window,
plus their tests and orphaned localization keys.

TaskMonitorViewModel itself stays: DetailsIslandViewModel still uses it as
the backing state for the task Log/AgentState/AskUser-question UI, so only
its Mission-Control-only members (Title/DisplayTitle, detach, cancel command,
IMissionControlPane) were stripped. IMissionControlPane/Panes were kept
(now a 1:1 mirror of ConPtySessions) rather than dissolved, to avoid
churning the still-live ConPTY pane tests and AXAML for a single-implementer
interface.

Visual verification still open: Mission Control with several open ConPTY
tiles, and the Focus/Overview toggle.
2026-08-05 09:03:55 +02:00