Commit Graph
809 Commits
Author SHA1 Message Date
mika kuns 51ee505057 fix(ui): strip CLAUDE_CODE_CHILD_SESSION/CLAUDECODE before every ConPTY launch
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 42s
ClaudeDo.App inherits its own process environment from whatever started it
(e.g. a dev/test launch from inside a claude session). Every embedded
claude.exe it spawns into a Mission Control tile then inherited those
markers too, so the child session mistook itself for a subagent: transcript
saving disabled and a degraded startup banner (white instead of orange,
missing box rules). PtyTerminalSession.StartAsync is the one choke point
all ConPTY launches already share for env handling, so clearing both vars
there covers task, ad-hoc, planning, and list-handler sessions regardless
of how ClaudeDo.App itself was started.
2026-09-03 07:22:59 +02:00
mika kuns bd5aa265d1 feat(mission-control): Handler-Run per Knopf abbrechen
Ein "Abandon run"-Knopf an Handler-Panes fragt HandlerRoundState.Get(handlerTaskId)
nach den noch offenen (Queued/Running) Tasks des Laufs, bestaetigt mit Anzahl,
cancelt jeden ueber den bestehenden CancelTaskAsync-Pfad und schliesst danach die
Session -- ein Schritt statt Tile schliessen + Queue separat abbrechen. Ohne
offene Tasks (oder ohne Round-Eintrag) schliesst die Aktion direkt, ohne Dialog.
Nur an den beiden Handler-Panes sichtbar (IsListHandler), normale Task-/Ad-hoc-
Panes bleiben unveraendert.
2026-09-02 22:39:12 +02:00
mika kuns b298594a2c chore(claude-do): merge fix(ui): Listen-Settings-Modal verschluckt Ladefehler nach d
ClaudeDo-Task: 9256fcfe-6cad-4350-a979-0c49cd5b9799
2026-09-02 22:38:49 +02:00
mika kuns 62855ac575 Merge branch 'claudedo/c209d54cef5642278673d41e8b98fc43' 2026-09-02 22:38:42 +02:00
mika kuns df3e7ba0c7 fix(ui): Dequeue-X auf blockierten Queue-Zeilen anzeigen und Kette konsistent halten
CanRemoveFromQueue schloss IsWaiting (queued+blocked) faelschlich aus, sodass ein
Kettenglied in der Mitte nicht entfernbar war. Zusaetzlich unblockt
TaskStateService.DequeueToIdleAsync jetzt den Nachfolger eines dequeueten
Kettenglieds, sonst bliebe er dauerhaft auf einen nicht mehr laufenden
Vorgaenger blockiert.
2026-09-02 22:34:50 +02:00
mika kuns a1b20d9f27 fix(ui): report and gate ListSettingsModal load failures instead of swallowing them
BeginLoad's fire-and-forget LoadAsync now catches instead of leaving an
unobserved task exception, reports it via the new ErrorReported event
(wired into FlashFooterError like the other modal VMs), and keeps Save
locked so the failure can't clobber list_config with blank fields.
LoadTicketProjectsAsync's empty catch now reports too; behavior for the
dropdown itself is unchanged.
2026-09-02 22:33:48 +02:00
mika kuns e0c6b670cb fix(ui): move ScrollViewer padding to inner content in modal bodies
Avalonia 12 excludes ScrollViewer.Padding from the scroll Extent, clipping
the last line of these five modal bodies unreachable at max scroll.
2026-09-02 22:30:52 +02:00
mika kuns f24654dfb8 perf(ui): show list settings modal before its seven-round-trip load finishes
OpenListSettingsAsync/CreateListAsync used to await LoadAsync (name/agent
config/list_config x2/ticket settings/ticket projects, all serial) before
showing the window -- an unreachable ticket system alone could add a 10s
HTTP timeout to every open. LoadAsync now runs via BeginLoad (fire-and-forget,
mirrors UsageMonitorModalViewModel), the modal shows immediately and fields
fill in behind it.

GetListConfigAsync no longer runs twice per open -- AgentConfigEditorViewModel
exposes the row it already fetched (LastLoadedListConfig) instead of the
caller re-fetching it. Ticket-project loading is split into its own
fire-and-forget step so a slow/unreachable ticket system can't block the
rest of the fields, and its tri-state Save logic now also treats "never
finished loading" like "not available" -- leaving the stored
TicketProjectId link untouched instead of overwriting it with 0. Save/Delete
are gated (CanExecute) on the core load being done, so a save can't land
before the fields it writes are populated.

Not measured with OperationTiming against a live worker in this session (no
running app instance available) -- verified instead via 4 new unit tests
that assert GetListConfigAsync fires exactly once and that a hung/failing
ticket-projects call neither blocks LoadAsync's other fields nor corrupts
the saved TicketProjectId. Before/after OperationTiming numbers and a visual
pass are still open follow-ups.
2026-09-02 22:18:54 +02:00
mika kuns b05b6fbaec fix(ui): Mission Control oeffnen, wenn ein Handler-Run per MCP startet oder ein Handoff eintrifft 2026-09-02 22:05:34 +02:00
mika kuns 574edf6c1a Merge branch 'claudedo/f2f0c6ee1e974c09bc8a8261978cba34'
feat(worker): Handler-Session vor dem Usage-Limit sauber uebergeben (#275); Konflikte mit start_list_handler aufgeloest, WorkerLog-Aufruf im Fire-and-forget-Pfad wieder abgesichert
2026-09-02 21:50:26 +02:00
mika kuns fe8186514f feat(worker): Handler-Session vor dem Usage-Limit warnen und Handoff bis zum Reset zurueckhalten
Eine PowerUse-Handler-Session soll am 5h-Limit nicht mehr mitten im Merge
sterben, sondern vorher selbst sauber uebergeben:

- HandlerUsageGuard (neu) warnt die laufende Session genau einmal pro Runde,
  sobald FiveHour.Utilization den Schwellwert PowerUseHandoffPct erreicht.
  Die Warnung wird per HandlerUsageWarning-Broadcast an Mission Control
  geschickt und dort in das Pane der Handler-TaskId getippt.
- handoff_list_handler broadcastet den Handoff dann nicht sofort, sondern parkt
  ihn bis ResetsAt + 60 s; das Ergebnis traegt deferredUntil. Ohne ResetsAt
  wird wie bisher sofort gesendet.
- Der geparkte Handoff liegt im HandlerRoundState (handler-rounds.json) und
  wird vom Guard-Tick ausgeloest, also auch nach einem Worker-Neustart wieder
  eingeplant bzw. sofort gesendet, wenn er ueberfaellig ist.
- Review-Befund aus #272: HandlerRestartCoordinator wartet nicht mehr selbst
  bis ResetsAt, sondern parkt den Neustart im selben Slot. AutoRestartUsed wird
  erst gesetzt, wenn der Broadcast wirklich rausging - ein Worker-Absturz
  waehrend der Wartezeit laesst die Runde nicht mehr dauerhaft tot zurueck.
  Zurueckgehaltener Handoff und Auto-Neustart teilen sich einen Slot, also
  oeffnet nie beides dieselbe Runde. UsageLimitProofPct entfaellt zugunsten von
  PowerUseHandoffPct.
- PtyTerminalSession.SendLineAsync schreibt in die laufende Session. Gegen eine
  echte claude-Session verifiziert: Text und Enter muessen zwei getrennte
  Writes sein, die Enter-Bytes kommen von Terminal.GenerateKeyInput.
2026-09-02 21:35:29 +02:00
mika kuns c2166a0d4f feat(worker): start_list_handler MCP-Tool startet einen List-Handler-Run wie der Button 2026-09-02 21:05:55 +02:00
mika kuns c3a418f077 Merge branch 'claudedo/b346a534f0fc4635bd7614a00ab2a20e' 2026-09-02 20:55:43 +02:00
mika kuns 016b9203f8 feat(worker): Handler-Session nach Usage-Limit-Reset automatisch neu starten
Eine List-Handler-ConPTY-Session, die mitten in einer Phase stirbt, war bisher
ein stilles totes Tile: InteractiveTerminalViewModel.OnSessionProcessExited
setzte nur bei einem Tod innerhalb des 5s-Grace-Fensters ein sichtbares Banner.

Neu:
- HandlerRoundState (JSON unter ~/.claudeDo/handler-rounds.json, keine
  EF-Migration): Phase + Task-Set der laufenden Runde, geschrieben von
  BuildForMergeHelperAsync ("triage") und BuildForMergeHelperHandoffAsync.
  Ohne das existieren beide nur im transienten HandoffRequested-Broadcast.
- HandlerRestartCoordinator: entscheidet den Neustart, fail-closed. Beleg fuer
  "war das Usage-Limit" ist FiveHour.Utilization >= 95 zum Todeszeitpunkt --
  eine ConPTY-Session hat kein stdout, TaskRunner.IsUsageLimitMessage hat hier
  nichts zu lesen. Nur bei PowerUse (beide Keys), max ein Neustart pro Runde,
  Warten bis FiveHour.ResetsAt, dann HandoffRequested erneut broadcasten.
  Verbraucht kein Handoff-Budget (HandoffRoundTracker.Register wird nicht
  angefasst). WorkerLog-Zeilen beim Tod und beim Neustart.
- Ui meldet den Exit-Code (nur dort bekannt) via
  WorkerHub.ReportInteractiveSessionExited, ohne selbst zu filtern.

Sibling zu UsageLimitAutoContinueCoordinator, kein Umbau davon: der sieht nur
headless Runs.
2026-09-02 19:17:51 +02:00
mika kuns 69898be5c9 feat(usage): PowerUse-Zeitfenster + Handoff-Schwellwert als Settings
Drei neue app_settings-Spalten (Migration AddPowerUseWindow):
power_use_window_start/end (HH:mm, lokal, nullable) und
power_use_handoff_pct (NOT NULL DEFAULT 95, geclampt 50-99).

Die Fensterlogik liegt als reine Funktion in PowerUseWindow
(Contains/Normalize/IsOpen): beide Grenzen leer oder nur eine gesetzt =
rund um die Uhr, Ende vor Start wrappt ueber Mitternacht, Grenzen
halboffen. Geprueft wird in ComposeHandlerPromptAsync, also pro Phase
zum Zeitpunkt des Prompt-Baus - die Uhr ist per Func<DateTime>
injizierbar. Bedienung im Usage-Monitor neben dem PowerUse-Toggle
(Commit auf Blur/Enter, ein Write fuer alle vier Felder); in
Settings->General unsichtbar, aber load->save durchgereicht.

Nebenbefund, gleicher Pfad: AppSettingsRepository.UpdateAsync kopiert
Feld fuer Feld und hat ModelPresets, PowerUseEnabled und
ListHandlerMaxHandoffs nie geschrieben - jeder Save dieser drei war
still wirkungslos. Mit ergaenzt und per Round-trip-Test gepinnt.
2026-09-02 19:09:47 +02:00
Mika Kuns 675b36e923 Merge branch 'main' into feat/poweruse-list-handler
Kollision mit #264 (Handoff-Budget im Brief sichtbar machen): beide Seiten haben
HandoffRoundTracker, HandoffMcpTools und InteractiveLaunchSpecService angefasst.

Der Konflikt war inhaltlich, nicht nur textuell. #264 liest den Cap an zwei
Stellen aus der Konstante (GetStatus und das roundInfo-Rendering), waehrend
dieser Branch ihn zum Parameter aus app_settings gemacht hat. Ein reiner
Text-Merge haette kompiliert und trotzdem gelogen: Register haette den
konfigurierten Cap durchgesetzt, waehrend der Brief dem Modell weiter "2 Runden
uebrig" gemeldet haette, obwohl es 39 hat.

Aufgeloest so, dass der Cap eine einzige Quelle hat:
- GetStatus(taskId, maxHandoffs) nimmt den Cap als Parameter, mit demselben
  Clamp wie Register. Die Rechnerei liegt damit an einer Stelle.
- GetHandoffStatus liest das Setting und gibt es weiter.
- Das roundInfo-Rendering benutzt GetStatus statt eigener Arithmetik.

Zwei Tests nageln genau diesen Drift fest, damit er beim naechsten Merge nicht
unbemerkt zurueckkommt: einer auf GetHandoffStatus, einer auf den Brief.

MaxHandoffs -> DefaultMaxHandoffs in #264s vier Test-Referenzen; die laufen alle
mit Default-Settings, die Semantik bleibt.
2026-09-02 15:48:43 +02:00
Mika Kuns 193752540b feat(ui): PowerUse-Toggle im Usage-Monitor, Opt-in pro Liste
Der Toggle sitzt unter den Gauges im Usage-Monitor, weil "das restliche Fenster
ausnutzen" eine Entscheidung ist, die man beim Blick auf das restliche Fenster
trifft. Er speichert sofort per Read-modify-write, gleiche Disziplin wie
SaveStagesAsync, damit er keine Felder ueberschreibt, die er nicht besitzt.

Zwei Stellen, die das Opt-in still ausgeschaltet haetten:
- WorkerHub.UpdateListConfig loescht die Config-Zeile, wenn alle Felder leer
  sind. PowerUseAllowed muss in diese Leer-Pruefung, sonst verschwindet das
  Opt-in sofort wieder, wenn es das einzige gesetzte Feld ist.
- SettingsModalViewModel baut das AppSettingsDto positional neu auf. Ohne
  Round-trip haette jedes Speichern der Settings PowerUseEnabled auf den
  Record-Default false zurueckgesetzt. Gleiches Muster wie _throttleStages.

Das Handoff-Budget ist als Spinner in Settings -> General editierbar, weil es
auch fuer normale (interaktive) Handler-Runs gilt und nicht an PowerUse haengt.
Das Addendum selbst ist ueber Settings -> Files anpassbar.
2026-09-02 15:44:13 +02:00
Mika Kuns c25732cff8 feat(claude-do): depends_on als Menge statt Einzelfeld
Ein Task kann jetzt auf beliebig viele Vorgaenger warten. Die Einzelspalte
tasks.depends_on_task_id wird durch die Beziehungstabelle task_dependencies
ersetzt (Composite-PK, beide FKs ON DELETE CASCADE -- das reproduziert das
alte ON DELETE SET NULL: geloeschter Vorgaenger = Kante weg = Task wieder
pickbar). BlockedByTaskId bleibt unberuehrt.

- Migration AddTaskDependencies kopiert jede bestehende depends_on_task_id
  verlustfrei in die Tabelle, bevor die Spalte fallengelassen wird
- QueuePicker gatet per doppelt negiertem NOT EXISTS: kein Task mit 0 Kanten
  wird blockiert, alle Kanten muessen done sein, eine Kante auf einen
  verschwundenen Task blockiert weiter
- SetDependsOnAsync ersetzt die ganze Menge; Zykluspruefung ist jetzt eine
  BFS ueber den Graphen, faengt also auch A->B->C->A
- blockedReason nennt alle offenen Vorgaenger (External/TaskBlocking, von
  ExternalMcpService und TaskWaitMcpTools gemeinsam genutzt)
- add_task/update_task nehmen dependsOnTaskIds; die alte Skalarform bleibt
  als Ein-Element-Menge inkl. ""-Clear-Sentinel gueltig
- UI: Fan-in-Zeile bleibt flach und listet alle Vorgaenger im After-Label,
  die lineare Kette rendert unveraendert
2026-09-02 15:08:05 +02:00
Mika Kuns b24ff614ff chore(claude-do): TaskRowViewModel: manuelle OnPropertyChanged-Kette auf [Noti
src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs enthält ~107 handgeschriebene OnPropertyChanged(nameof(...))-Aufrufe in partial void OnXChanged-Methoden. Das Projekt nutzt an anderen Stellen den Generator: [NotifyPropertyChangedFor] in DetailsIslandViewModel.cs, ConflictResolverViewModel.cs, AgentConfigEditorViewModel.cs, Installer/WizardViewModel.cs.

Das ist die eine Datei, in der eine ve

ClaudeDo-Task: 87976462-5845-4e01-8233-32afadca02bd
2026-09-02 12:16:06 +02:00
mika kuns 56bc1651a8 fix(ui): don't leave an orphaned list behind on cancel
"New list" pre-creates the DB row before opening List Settings.
Cancelling or closing that modal left an untitled empty list behind;
CreateListAsync now rolls the row back unless the modal reports Saved.

Also moves the new-list/import-repo buttons up next to the "My Lists"
label instead of a row below the list, and puts Notes above Important
in the smart-list nav order.
2026-09-02 10:00:43 +02:00
mika kuns 80fe188a48 feat(ui): add "move to list" to the task row context menu
Reuses the existing drag-drop move (MoveTaskToListAsync) so the same
running/worktree guards apply — only ListId changes.

Also count WaitingForReview tasks (not Done-with-a-branch) for the
review portion of the status pill, and localize the pill and open-task
count strings that were still hardcoded English.
2026-09-02 10:00:21 +02:00
mika kuns 6be62f02cc refactor(ui): remove the stale-worker banner
The banner compared the running worker's build SHA against the
selected list's HEAD via a git ancestor check on every list switch
and reconnect. It added a git-rev-parse MSBuild target, a hub call,
and a poll loop for a corner case that hasn't come up in practice —
not worth the moving parts.
2026-09-02 09:59:39 +02:00
mika kuns b6e5876b07 fix(ui): stop treating git worktrees and submodules as repos
.git as a file (worktrees, submodules) isn't a standalone repo — the
scanner was flooding the import list with worktree entries alongside
their real repo.
2026-09-02 09:59:12 +02:00
mika kuns 30d0611b8e fix(worker): fix Bandel ticket sync and reactivate the integration
The status PATCH needs statusName alongside statusId or the API 400s,
so every write-back had been silently failing. The board's flat
assigneeName is null on every live ticket; the real assignee list is
ticketAssignees[]. Import now also picks up In Bearbeitung tickets,
not just Offen ones.

Both issues are live-verified against the real API, so the feature
flag flips back on.
2026-09-02 09:59:06 +02:00
CubeGameLPandClaude Opus 5 f640580463 fix(notes): Shift+Enter in the capture box, not just in the note rows
The previous fix put AcceptsReturn on the rows in the DataTemplate and
missed the box you actually type new notes into, which still had it off
and only a KeyBinding for Enter — so Shift+Enter there did nothing.

Both now go through the same tunnel handler: Enter files the note,
Shift+Enter is left to the TextBox for the line break. The KeyBinding is
gone; with AcceptsReturn on it could never have fired anyway, because
TextBox consumes Enter in its own OnKeyDown before bindings or bubbling
handlers run.

Verified against the running app: a note typed with Shift+Enter is
stored as "fe\r\ndwa".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:46:59 +02:00
CubeGameLPandClaude Opus 5 b90c5855f4 fix(notes): let Shift+Enter break the line, and clear the leftovers around the editor
Shift+Enter did nothing because AcceptsReturn was only set from a style
setter and never reached the box. Setting it on the element is half the
fix: TextBox.OnKeyDown consumes Enter regardless of modifiers and runs
before any bubbling handler, so the split chain would have died in its
place. Enter is now taken in the tunnel phase and Shift+Enter is left to
the box.

Alongside, the notes list stops borrowing furniture it has no use for:
no "0 open tasks" subtitle, no show-completed and list-settings buttons,
and no details pane beside it — the editor spans that column instead of
leaving it empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:36:28 +02:00
CubeGameLPandClaude Opus 5 0f04b796f4 feat(notes): notes get their own list, a day log and an Enter chain
The editor was reachable from one button that only appeared in My Day,
which is how it got forgotten. It is now a permanent sidebar entry next
to My Day and Planned, and it fills the tasks island rather than the
details pane, because a note list is content.

Inside, the date picker is gone: today sits at the top with the capture
box, older days follow as dated groups. Enter in a note saves it and
opens the next one, Shift+Enter breaks the line so notes can be several,
Backspace on an empty note deletes it and steps back up. Deleting also
has a visible hover button instead of only "clear the text and hope".
Agent-written notes carry a marker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:19:37 +02:00
CubeGameLPandClaude Opus 5 ae0c7d3771 feat(notes): add_note MCP tool with a per-day agent cap
Agents can write into the user's daily notes, but only within limits:
max 10 agent notes a day, max 500 characters, add only — no edit, no
delete. A new from_agent column separates their lines from the user's
so the cap counts the right ones and the UI can mark them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:02:37 +02:00
mika kuns c31f79d3d4 feat(ui): wählbares Listen-Icon und aufgeräumter Task-Detail-Header
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 41s
Listen bekommen eine Icon-Spalte (Migration AddListIcon) und einen Icon-Picker
in den Listeneinstellungen; 34 kuratierte Geometrien aus der Icon-Bibliothek,
Fallback auf "Folder" bei unbekanntem Key.

Der Metadata-Footer im Task-Detail entfällt; created-at wandert in die
Header-Zeile neben das ID-Badge, der Close-Button (und CloseDetailsCommand)
fällt weg.
2026-08-28 14:17:38 +02:00
mika kuns 22e70ffcb4 feat(ui): Mission Control als Session-Hub
- "+" öffnet ein Menü mit allen Listen (working dir) statt direkt den
  Ordner-Dialog; "Ordner wählen…" bleibt als Fallback erste Zeile, damit
  das Menü auch bei fehlgeschlagener Listen-Abfrage nutzbar bleibt
- Rail-Rows: Kontextmenü "Sitzung öffnen" (gesperrt für Running — der
  Worktree gehört dort dem autonomen Lauf)
- Aktivitäts-Strip statt reiner Queue: WaitingForReview/Failed/Roadblock
  kommen dazu, Attention zuerst, unterschieden nur über Farbe (Aktionen
  bleiben in der Task-Detailansicht)
2026-08-28 14:17:38 +02:00
mika kuns 84219a9f88 refactor: Datei-Scope-Serialisierung entfernen
ScopeGlobs auf Tasks und SerializeOnFileOverlap auf der Listen-Config waren
ungenutzt: der Scope wurde nie befuellt, also hat der Queue-Picker nie
serialisiert. ScopeOverlap, das Picker-Gate, die DTO-Felder, die UI-Option und
die Spalten fallen weg (Migration DropFileScopeSerialization).
2026-08-27 16:43:14 +02:00
mika kuns 4e55f9161c feat(ui): Listeneinstellungen mit Kategorie-Sidebar
Body wie im Settings-Modal: Sidebar-Liste steuert einen retemplateten
TabControl (Allgemein/Agent/Verifikation) statt einer langen Scroll-Spalte.
2026-08-27 16:43:00 +02:00
mika kuns 8329c92598 feat(ui): Ticketsystem-Anbindung hinter einen Aus-Schalter legen
Die Bandel-API ist unter dem eingetragenen Hostnamen nicht erreichbar
(Verbindung aktiv abgelehnt), das Feature bliebe also eine Einrichtung,
die nicht funktionieren kann. TicketSettingsTabViewModel.FeatureEnabled
versteckt alle drei Einstiegspunkte: Settings-Tab, Projekt-Dropdown in
den Listen-Einstellungen, Kontextmenue-Eintrag.

Gespeicherte Base-URL, PAT und Projektverknuepfungen bleiben erhalten
und greifen beim Umlegen sofort wieder.
2026-08-27 14:13:31 +02:00
mika kuns 2fe2ac83b1 fix(ui): Import-Erfolgsmeldung nicht mehr als Fehler einfaerben
Der Footer-Strip trug schon immer ein Level, es gab nur keinen
Einstiegspunkt jenseits von FlashFooterError. "3 neue Tasks" in Rot
liest sich als Fehlschlag.
2026-08-27 13:41:03 +02:00
mika kuns e91ade9cad feat(ui): Ticket-Projekt pro Liste und Import ueber das Kontextmenue 2026-08-27 13:36:44 +02:00
mika kuns 020f93d55e feat(ui): Settings-Tab fuer die Ticketsystem-Anbindung 2026-08-27 13:29:49 +02:00
mika kuns f0a3a186dd feat(hub): Ticket-Settings, Projektliste und Import ueber den Hub 2026-08-27 13:22:54 +02:00
mika kuns 1ef677609f refactor(ui): Icon-Faerbung zentral im ICON-PAINTING-Block
Inline Foreground/Stroke an Icons entfernt — ein lokaler Wert schlaegt jeden
Style, dadurch erreichten Hover/Checked/Disabled das Icon nicht. Farbe wird
jetzt per Klasse gewaehlt (.danger, .star-btn.on, .active), alle Zustaende
liegen in einem geordneten Block in IslandStyles.axaml.

- Path.plan-icon -> Path.icon-stroke (gilt jetzt fuer Button und ToggleButton)
- Icon.Activity als gefuellte Kontur (PathIcon fuellt, Stroke-Polyline gab Blobs)
- BloodBrightBrush als Hover-Ton fuer destruktive Icons
- icon-btn:disabled bleibt transparent statt Fluent-Grau
2026-08-27 11:29:44 +02:00
mika kuns 13b81cac68 feat(settings): claude_bin im Dateien-Tab setzbar, mit Auflösungs-Check
Bisher nur per Hand in worker.config.json. Neuer Abschnitt CLAUDE CLI mit
eigenem Save-Button (die Datei gehoert dem Worker, nicht app_settings) und einer
Zeile, wohin der Wert per ExecutableResolver tatsaechlich aufloest — 'nicht im
PATH gefunden' war bisher erst am fehlgeschlagenen Run zu sehen. WorkerConfig ist
DI-Singleton und ClaudeProcess loest pro Spawn auf, also greift die Aenderung ab
dem naechsten Run ohne Neustart.

SaveOnlineInbox/SaveClaudeBin teilen jetzt ein SaveKey(), damit beide dieselbe
read-modify-write-Semantik haben (alle anderen Keys bleiben unberuehrt).
Die zugehoerigen Locale-Keys sind im vorigen Commit mitgelaufen.
2026-08-27 10:39:25 +02:00
mika kuns 31d53b0033 feat(ui): Throttle-Stufen im Ausfuehrung-Tab sichtbar machen
Die vier UsageThrottle-Prozente waren nur per Gauge-Drag im Usage-Monitor
erreichbar und wurden im Settings-Modal unsichtbar durchgeschleift. Jetzt
read-only angezeigt plus Button in den Usage-Monitor. Der Button schliesst die
Settings absichtlich: Save() schreibt die beim Oeffnen gelesenen Throttle-Werte
zurueck und wuerde ein zwischenzeitliches Draggen ueberschreiben.
2026-08-27 10:39:08 +02:00
mika kuns 4464dc6ff1 feat(config): Permission-Modus pro Liste und pro Task ueberschreibbar
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'.
2026-08-27 10:28:57 +02:00
mika kuns 5cc99bfec6 feat(ui): Listen-Einstellungen — Checkbox fuer serialize_on_file_overlap
Das Flag war bisher nur ueber MCP set_list_config erreichbar. UpdateListConfigDto
fuehrt es tri-state (null = gespeicherten Wert behalten), damit nur das
Listen-Modal es setzen/loeschen kann und kein anderer Aufrufer es per Omission
verliert.
2026-08-27 10:15:17 +02:00
mika kuns 24e1d648ee fix(ui): MergeHelperSelectionModal — Task-Nummer anzeigen, Titel wrappen, Status-Spalte verbreitern 2026-08-27 09:10:44 +02:00
mika kuns 18755910bd fix(ui): Branch-Zeile im Detail-Header — Icon stroked rendern, ohne Task ausblenden
Icon.GitBranch ist Line-Art und wurde per PathIcon gefuellt (nur Knoten sichtbar).
Zusaetzlich brach {Binding Task.HasBranch} bei leerer Auswahl (Task=null) und
IsVisible fiel auf den Default true zurueck — FallbackValue=False blendet die
Zeile jetzt aus, solange kein Task gebunden ist.
2026-08-27 08:57:57 +02:00
mika kuns d7a3aa80c3 fix(ui): Review-Merge-Button-Icon stroked rendern statt gefuellt — Linien waren unsichtbar 2026-08-27 08:52:12 +02:00
mika kuns 741c7ac58d feat(ui): Review-Merge-Button — Claude nimmt Waiting-for-Review pro Liste ab
Neuer Button in der virtuellen Review-Liste: öffnet das Merge-Helper-Auswahlmodal
im Review-Modus (alle WaitingForReview-Tasks repo-verknüpfter Listen, gruppiert
unter Listen-Headern, alle vorgetickt) und startet pro gewählter Liste eine
ConPTY-Handler-Session direkt in der Merge-Phase — via bestehendem Handoff-Spec
(nextPhase "merge"), kein Triage/Wait davor. Handler-Host-Task wie beim vollen
"Let Claude handle it"-Lauf (HandlerBaseCommit, IsManual).
2026-08-27 08:44:33 +02:00
Mika Kuns c1ab042d0a fix(ui): block delete on interactive-session tasks, clear ghost selection
Delete (row context menu + detail header) now gates on HasInteractiveSession
the same way SendToQueue already does, so an open ConPTY session's claude
process can't be orphaned by deleting its task out from under it.

Row removal (in-UI delete and the delta-refresh path for externally deleted
tasks) now clears SelectedTask via SelectFrom(null, "row-removed") when the
removed row was selected, so the detail pane no longer keeps showing a
deleted task with live buttons.
2026-08-26 15:46:40 +02:00
Mika Kuns f70aec495b fix(ui): store ScheduledFor as real UTC instead of mislabeled local time
The DB's global UtcConverter only tags DateTimes as Utc on read
(SpecifyKind), it never converts on write. SetScheduledForAsync persisted
the ThemedDatePicker's Local/Unspecified wall-clock value verbatim, so
QueuePicker's comparison against DateTime.UtcNow fired scheduled tasks late
by the local UTC offset (e.g. 2h in CEST). Convert to UTC at the write
boundary, and ToLocalTime() at the read/compare sites (overdue checks in
TaskRowViewModel/TasksIslandViewModel, the date-picker's edit seed) so
existing scheduled/overdue display doesn't shift.

Existing DB rows hold local wall-clock values mistagged as Utc; no
migration added (few rows, one-time 2h-class shift accepted per the
originating audit finding).
2026-08-26 15:46:10 +02:00
Mika Kuns 299c7b749c fix(worker): close status-force bypasses on Running tasks
update_task_status Idle/Done, WorkerHub.SetTaskStatus, and the UI's Mark
Done/Cancelled menu items could all force a Running task's status without
going through TaskStateService's guards, leaving its CLI process untracked
and its worktree writes silently dropped. Idle now routes through the
already-guarded TaskStateService.ResetToIdleAsync instead of the repo's
unconditional ResetToManualAsync; Done and SetTaskStatus explicitly reject
Running; the context menu disables both entries with a tooltip while
running. TaskRunner also now logs a warning whenever a terminal transition
(SubmitForChildren/SubmitForReview/Complete/Fail) is rejected instead of
silently discarding the run result. DeleteTask's MCP path gets the same
friendly foreign-key message WorkerHub.DeleteTask already had for a task
with children.
2026-08-26 15:01:13 +02:00
Mika Kuns c4928b4def chore: move appdata folder to .claudeDo 2026-08-26 14:26:19 +02:00