Commit Graph
177 Commits
Author SHA1 Message Date
mika kuns 659bf3e743 feat(ui): show child tasks as children in the merge-helper picker
MergeHelperSelectionModalViewModel now loads ParentTaskId and orders
rows hierarchy-aware (parent immediately followed by its children,
mirroring TasksIslandViewModel.Regroup). Children render indented with
the same indent-track visual as the main task list; ticking a parent
cascades selection to its children, while a child can still be
deselected on its own. A child whose parent got filtered out (e.g.
already Done) renders top-level with an explicit hint instead of
disappearing. Confirm keeps returning parents ahead of their children.
2026-08-10 13:47:55 +02:00
mika kuns f74c7dd70b fix(ui): diff viewer opens non-modal and maximizable
The diff viewer used ShowDialog at both call sites (task details, worktrees
overview), blocking navigation of the rest of the app while open. Switch both
to Window.Show(owner) and reuse the one open window (swap DataContext,
Activate()) instead of stacking a second one on re-open.

Add an opt-in maximize/restore button + double-click-titlebar toggle to
ModalShell (ShowMaximizeButton, default false so other modals are untouched),
wired on for DiffViewerView only. Reuses the existing Icon.WinMax/WinRestore
geometry and OffScreenMargin inset from MainWindow's own maximize handling.

The review gate (Approve & Merge locked until the diff is opened) already
fires DiffViewed before the dialog/window is shown, so it is unaffected by
the modal-to-non-modal change.
2026-08-10 13:46:56 +02:00
mika kuns 1b7f7f38ae feat(prime): wire prompt_override into the daily prep prompt
The prime_schedules.prompt_override column existed end-to-end but was
never populated or read. DailyPrepPrompt.BuildPrompt now takes an
optional override and appends it as an extra paragraph after the fixed
prompt (additive, never a replacement, so a user can't disable the
required get_daily_prep_candidates/set_my_day flow). PrimeRunner passes
schedule.PromptOverride through. The Prime tab in Settings now has a
multiline field per schedule wired to a new PromptOverride property on
PrimeScheduleRowViewModel (blank persists as null).
2026-08-10 11:57:54 +02:00
mika kuns 696abd0a7a feat(ui): toggle whether the findings folder is committed 2026-08-10 10:43:12 +02:00
mika kuns 9437121f3a fix(diff): label split panes, unify the mode switch, sync split scrolling
Three things were wrong with the fresh side-by-side viewer:

- The panes scrolled independently. The sync hunted the editors' templated
  ScrollViewers at load time, but the viewer starts collapsed (no file selected),
  so nothing was ever measured, no template existed, and the hook silently
  no-opped for the lifetime of the window. Reading now goes through
  TextView.ScrollOffsetChanged, which exists from construction; writing goes
  through a lazily resolved ScrollViewer.Offset. TextEditor.ScrollToVerticalOffset
  is NOT usable here - it is a silent no-op in AvaloniaEdit 12.0.0 even with the
  editor templated (verified headlessly).
- Neither pane said what it showed. Added a BASE | WORKTREE header row inside
  DiffTextView, sharing the pane grid's columns so each label sits over its editor.
- The layout picker was two lookalike ToggleButtons. It is now a segmented switch
  (Border.segmented + Button.segment.active), with wrap demoted to an icon toggle
  since it is orthogonal to the layout mode.

The scroll sync, TextMate setup, grammar switching, brush fallback and segment
struct were duplicated between this control and the 3-pane conflict resolver,
which the design doc had used as a copy-paste template. They now live in
DiffEditorSetup; both surfaces migrated. They stay separate controls on purpose -
a read-only two-way renderer over aligned rows with filler lines is not a variant
of a three-way editor over a writable document.

The resolver thereby also picks up the fixed scroll sync and the TryFindResource
brush lookup (its TryGetResource never resolved anything). All four merge tokens
happen to equal their hardcoded fallbacks, so nothing changes on screen.
2026-08-07 13:30:34 +02:00
mika kuns 6dff72f27c Merge branch 'main' into worktree-diff-side-by-side
# Conflicts:
#	src/ClaudeDo.Ui/CLAUDE.md
2026-08-07 11:16:49 +02:00
mika kuns 7eeb8f5086 feat(usage): split throttle thresholds per bucket, add draggable gauge markers 2026-08-07 11:01: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 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 f143d5fc18 Merge claudedo/64a2e2653d244714b76d637b3e0f3be8 2026-08-05 22:42:57 +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 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 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 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 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 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 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 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 149e2adadb feat(ui): accent color presets in Settings → General
Adds Moss / Peat / Sea preset swatches to the General settings tab.
Selecting a preset mutates the live SolidColorBrush objects in the
Application resource dictionary so all StaticResource consumers update
instantly; the choice is persisted to ui.config.json and re-applied
at startup. Missing or unknown saved value falls back to Moss.
2026-07-29 09:08:13 +02:00
Mika Kuns 3a648b7d77 feat(tasks): mark tasks and lists as manual
Reminders written down as todos had no home: every task looked like Claude work.
A manual task now shows a MANUAL badge and hides send-to-queue, refine and the
planning session; the queue picker, daily prep and the list handler all skip it,
with a TaskStateService guard so the MCP surface and hub cannot start one either.
Opening a hand-driven ConPTY session stays available on purpose.

A list can be marked manual in its settings, which makes tasks created there
(UI and MCP add_task) start out manual. Toggle per task from its context menu.
2026-07-27 15:02:51 +02:00
Mika Kuns fde9615b34 feat(settings): per-model effort and turn presets
ClaudeDo never passed --effort, so every session inherited whatever effortLevel
the user's Claude Code config happened to carry. Settings -> General now holds one
row per model alias (haiku medium/20, sonnet high/30, opus high/40, fable high/25)
supplying the global effort and turn defaults; list- and task-level max-turns
overrides still win, and the agent editor's inherited badge follows the model.

--effort is applied to autonomous runs and to every ConPTY spec (task session,
planning start/resume, ad-hoc, list handler). The model itself is deliberately not
forced on interactive sessions. The single global 'Max turns' field is replaced by
the table, and 'fable' joins ModelRegistry.Aliases.

The migration also adds the is_manual columns used by the next commit.
2026-07-27 15:02:51 +02:00
Mika Kuns 6c8de4aef3 style(ui): pad the diff-viewer file-tree stats off the right edge 2026-07-27 15:02:50 +02:00
Mika Kuns 40eb979924 refactor(ui): scope "Let Claude handle it" to a single list 2026-07-27 15:02:50 +02:00
mika kuns 327ae2b69c feat(ui): add merge-helper task selection dialog 2026-07-24 14:21:26 +02:00
mika kuns b9b3053051 fix(ui): clearer rename display in diff viewer
Show renames as old → new in the file header and suppress the misleading
"+0 −0" stats for a pure rename (the R badge already conveys it).
2026-07-24 11:21:20 +02:00
mika kuns 85d0f9dcec feat(ui): session-skills empty-state + neutral subtask terminology
Show an explanatory empty-state under the install row when no skills are
installed. Rename the unified-parent status/labels from "Improvements" to
neutral "Subtasks" (waitingForChildren, agentStatus.children,
childOutcomesLabel) since WaitingForChildren now covers planning too.
2026-07-24 11:14:01 +02:00
Mika Kuns 7c3c061428 feat(ui): session skills registry tab + per-level selectors 2026-07-23 16:47:14 +02:00
Mika Kuns df84fc3f2c fix(ui): make worktree state chips readable with on-theme tints
The state badge in the worktrees overview used bright off-palette Material colors
with hardcoded near-black text (via WorktreeStateColorConverter), which was hard
to read. Switch to the existing chip pattern (subtle tint background + matching
border + colored text): active=blue, merged=green, kept=amber, discarded=gray.
Drop the now-unused WorktreeStateColorConverter.
2026-06-26 16:11:50 +02:00
Mika Kuns 167d2fec6a refactor(diff): single DiffViewer replaces DiffModal + WorktreeModal + PlanningDiff 2026-06-26 16:11:49 +02:00
Mika Kuns c4f74a7aea feat(ui): Log Visualizer overlay reachable from a clickable footer log line 2026-06-26 16:11:49 +02:00
Mika Kuns eb0ddb56d3 refactor(agent-config): single AgentConfigEditor for list + task scopes 2026-06-26 16:11:49 +02:00
Mika Kuns 5231ad6b86 fix(worktrees): hide batch Merge All in the global overview
The select-all + target picker + Merge All cluster only makes sense per-list: a single target branch is meaningless across repos. Now gated on !IsGlobal; Refresh/Cleanup/Status stay available globally.
2026-06-26 16:11:47 +02:00
Mika Kuns 3e4e4a03f7 feat(ui): move review feedback to the Output tab + review/worktree polish
- Feedback box + a new "Resume session" button move from the Git tab to the
  Output tab; the Git review block keeps Approve & Merge / Park / Cancel / Reset.
- Add a "Parked" chip for Idle tasks that still hold an Active worktree.
- Stop showing the "Session was Cancelled" band on cancel (failed-only now).
- Fix the Worktrees-overview state-chip contrast (dark text on the colour).
2026-06-19 09:31:53 +02:00
mika kunsandClaude Opus 4.8 80a2de6c74 feat(ui): Online Inbox settings tab + auth-code/PKCE login
New Settings tab: enable toggle, config fields, sign-in/out + status.
OnlineLoginService runs the PKCE loopback flow (Duende.IdentityModel.OidcClient
7.1.0), opens the system browser, captures the callback, hands the refresh
token to the Worker. en/de localized. Fixes: loopback callback URL built from
host:port base (avoids doubled redirect path); PollIntervalSeconds threaded
through the state DTO so it loads instead of resetting to 60.

Visual layout + the live sign-in round-trip need manual verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 11:02:14 +02:00
mika kunsandClaude Opus 4.8 f21c65be18 feat(ui): richer diff viewer + surface child roadblocks on parents
Changelog / changelog (push) Successful in 1s
Release / release (push) Successful in 38s
- UnifiedDiffParser detects added/deleted/renamed/binary files; diff
  modal shows a file list, binary/empty placeholders, and can diff a
  merged task by commit range after its worktree is gone
- DetailsIslandViewModel flags children needing attention (failed,
  cancelled, awaiting review, or with roadblocks) on the parent
- GitService gains worktree head-commit/range support; planning chain,
  merge orchestration, and session manager tweaks with updated tests
- refresh app/installer/worker icons

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 16:40:59 +02:00
mika kunsandClaude Opus 4.8 a41b8de47a feat(i18n): localize task-header, task-row and prime-schedule tooltips
Replace hardcoded tooltips with loc keys (kill-session, delete-task, toggle-subtasks, agent-suggested, star, remove-schedule) and drop the unused console.maximizeTip key; en/de kept in parity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 09:34:26 +02:00
mika kunsandClaude Sonnet 4.6 d52243ccd1 refactor(ui): render worktree modal diff via canonical DiffLinesView
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:00:19 +02:00
mika kuns 5edb433755 feat(ui): batch-merge cockpit view with checkboxes and conflicts panel 2026-06-05 10:54:34 +02:00
mika kunsandClaude Opus 4.7 22a1ba7f30 refactor(ui): share color-coded diff rendering between per-task and combined diff viewers
Extract the unified-diff parser into UnifiedDiffParser and the styled line
renderer into a reusable DiffLinesView control. The combined (planning) diff
now parses its unified-diff string and renders color-coded rows (green
additions / red deletions, file headers) identical to the per-task viewer
instead of dumping plain text into a TextBox.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-04 17:56:06 +02:00
mika kuns bd1e3db1d9 feat(ui): expose all editable prompt files, drop agent prompt 2026-06-04 14:07:43 +02:00
mika kuns d0ab382973 feat(ui): show inherited markers and max-turns override in list settings 2026-06-04 12:32:28 +02:00
mika kuns 5e0859fbb8 feat(daily-prep): add DailyPrepMaxTasks editor to Prime Claude settings 2026-06-03 16:33:00 +02:00