535 Commits
Author SHA1 Message Date
mika kuns d258ab4164 test(worker): start_list_handler ins erwartete MCP-Tool-Inventar aufnehmen
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 42s
2026-09-02 21:57:16 +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 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 453d61ca58 feat(worker): PowerUse-Addendum an die Handler-Prompts, Cap aus den Settings
HandoffRoundTracker.Register nimmt den Cap jetzt als Parameter statt aus einer
Konstante; HandoffMcpTools liest ihn pro Aufruf aus app_settings. Werte unter 1
werden auf 1 geklemmt (in WorkerHub UND in Register): der Cap ist das Einzige,
was eine entlaufene Handoff-Kette begrenzt, "0 = unbegrenzt" darf kein Aufrufer
waehlen koennen.

InteractiveLaunchSpecService.ComposeHandlerPromptAsync haengt das PowerUse-
Addendum an den Phasen-Prompt, aber nur wenn globaler Schalter und Listen-Opt-in
beide gesetzt sind. Bewusst ein Addendum statt einer zweiten Prompt-Garnitur:
die gemeinsamen 95% bleiben an einer Stelle, und ein Run ohne PowerUse bekommt
einen byte-identischen Prompt wie vorher. Das Addendum ist als Override der
interaktiven Regeln formuliert (nie fragen, entscheiden und protokollieren;
Konflikte loesen oder abbrechen, nie im Tree liegen lassen; Arbeit ernten, wenn
eine Runde sonst leer laeuft).

Drei Tests pinnen alle vier Ecken des UND, weil die Sicherheitsaussage des
Features genau daran haengt.
2026-09-02 15:43:48 +02:00
Mika Kuns b00bdf28ae Merge branch 'claudedo/0a185f8e823d42fc9a5b97c5eb91c616' 2026-09-02 15:30:04 +02:00
Mika Kuns 91a37984c6 feat(claude-do): merge Handoff-Budget im Brief sichtbar machen und pro Task mitzähl
ClaudeDo-Task: bdcd601a-2fed-44d8-9164-6d2d008e7f31
2026-09-02 15:28:59 +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 2330b426c6 feat(claude-do): Expose HandoffRoundTracker budget via an MCP tool (e.g. get_
The handoff-budget task (round/remaining/final now surfaced in the handoff.md brief via HandoffRoundTracker.GetStatus, wired through InteractiveLaunchSpecService.BuildForMergeHelperHandoffAsync) only reaches the session at the start of a handoff round. There is no way to query the current round/remaining budget for a handler task mid-session or from outside (e.g. the UI, or a script). Consider add

ClaudeDo-Task: 0a185f8e-823d-42fc-9a5b-97c5eb91c616
2026-09-02 14:43:44 +02:00
Mika Kuns 81a5fc5d33 feat(worker): surface the handoff round budget in the merge-helper handoff brief
A handler session only learned the chain was capped when handoff_list_handler
threw at the end of its work, stranding open tasks. The round count already
lived in HandoffRoundTracker the whole time -- it just never reached the
brief. InteractiveLaunchSpecService now reads HandoffRoundTracker.GetState
(read-only, doesn't advance the round) and renders round N of MaxHandoffs
plus the remaining count into the handoff brief, replacing the old one-line
finalNote. The rejection error also names the next action (start a new
handler run) instead of just failing.
2026-09-02 14:26:56 +02:00
Mika Kuns 4ee1d05f06 fix(worker): carry ExpectsNoDiff into the relocated merge MCP tools
Conflict resolution for the #266 merge: #247 had moved PreviewMerge/PreviewMergeSet
and MergePreviewSetEntryDto out of ExternalMcpService into MergeMcpTools, so #266's
in-place edits to those had to be re-applied at the new location, together with the
PreviewMergeSet_ReportsExpectsNoDiffPerTask test.
2026-09-02 13:59:22 +02:00
Mika Kuns 7e847638cf Merge branch 'claudedo/9a02814991ef42a5a9a063d5ea579d62' 2026-09-02 13:49:56 +02:00
Mika Kuns c2ef446fe1 test(data,worker): cover ExpectsNoDiff persistence and MCP wiring
Data.Tests: default-false and true-roundtrip on TaskEntity.
Worker.Tests: add_task/update_task set/clear/leave-unchanged, and
preview_merge_set surfaces the flag per task.
2026-09-02 13:39:25 +02:00
Mika Kuns 7bcca3647e refactor(claude-do): refactor(worker): move the merge and worktree MCP tools out
`src/ClaudeDo.Worker/External/ExternalMcpService.cs` ist **1897 Zeilen** (nachgezählt 2026-09-02; die Datei ist seit dem Anlegen dieses Tasks von 1696 weiter gewachsen): ~30 DTO-Records oben plus ~25 Tool-Methoden — während **13** Geschwisterdateien `*McpTools.cs` im selben Ordner das Topic-Split-Muster schon tragen (`ListMcpTools`, `ConfigMcpTools`, `BatchMcpTools`, `NotesMcpTools`, `QueueStateMc

ClaudeDo-Task: 1862e160-ffde-4a50-aa03-bb7251f56088
2026-09-02 13:28:33 +02:00
Mika Kuns 244ba9b72f chore: merge main into task branch 2026-09-02 13:13:59 +02:00
Mika Kuns 0b506f529a feat(data): add ExpectsNoDiff flag for verification/audit tasks
An empty diff from a review/audit/verification task looks identical to
one that silently failed to commit. ExpectsNoDiff (TaskEntity, add_task/
update_task, preview_merge_set, review_task via TaskRefDto) lets the
merge helper tell them apart instead of treating every 0-changed-files
result as suspicious.
2026-09-02 13:13:13 +02:00
Mika Kuns 7a0b97df59 refactor(claude-do): refactor(worker): move the merge and worktree MCP tools out
`src/ClaudeDo.Worker/External/ExternalMcpService.cs` ist **1897 Zeilen** (nachgezählt 2026-09-02; die Datei ist seit dem Anlegen dieses Tasks von 1696 weiter gewachsen): ~30 DTO-Records oben plus ~25 Tool-Methoden — während **13** Geschwisterdateien `*McpTools.cs` im selben Ordner das Topic-Split-Muster schon tragen (`ListMcpTools`, `ConfigMcpTools`, `BatchMcpTools`, `NotesMcpTools`, `QueueStateMc

ClaudeDo-Task: 1862e160-ffde-4a50-aa03-bb7251f56088
2026-09-02 13:02:10 +02:00
Mika Kuns a0c277100e test(worker): assert the full external MCP tool-name inventory
Guardrail for the upcoming ExternalMcpService.cs topic split: proves the
move is name-preserving by pinning the complete set of registered tool
names (computed via the SDK's own McpServerTool.Create, not a
reimplementation of the naming rule) before any file is moved.
2026-09-02 13:02:10 +02:00
Mika Kuns 651ddbc31c chore(claude-do): merge feat(worktrees): warn about git worktrees ClaudeDo doesn't k
ClaudeDo-Task: 765fed13-db66-44e4-9285-c4b2d415b443
2026-09-02 13:01:57 +02:00
Mika Kuns 477a216567 chore(claude-do): merge refactor(tests): one IWorkerClient test double instead of tw
ClaudeDo-Task: 9ff7ec49-36c9-4b09-8747-e57bf74e37f2
2026-09-02 13:00:14 +02:00
Mika Kuns 6a4fa15372 fix(claude-do): merge batch_get_tasks: failureReason wird im fields-Parameter abge
ClaudeDo-Task: df16476b-5a10-446c-9ebc-99ddcc64e476
2026-09-02 12:59:52 +02:00
Mika Kuns 411eb7487b chore(claude-do): merge TaskRowViewModel: manuelle OnPropertyChanged-Kette auf [Noti
ClaudeDo-Task: 87976462-5845-4e01-8233-32afadca02bd
2026-09-02 12:59:35 +02:00
Mika Kuns dc1e67d07b fix(tests): stop Ui.Tests order-dependent flakiness on shared Loc.Current
Loc.Current (src/ClaudeDo.Ui/Localization/Loc.cs) is a process-wide mutable
static; which localizer is active depended on xUnit's parallel test
scheduling. Ui.Tests: disable collection parallelization (cheap, pure VM
suite) and install the real localizer in a module initializer so no test
can ever observe the uninitialized key-echo default. Worker.Tests: install
the same module initializer but leave parallelization on — disabling it
measured a 27% wall-clock regression on its real-SQLite/git suite, and the
initializer alone already removes the race. AgentConfigEditorViewModelTests
now installs its own localizer instead of relying on ambient state.
2026-09-02 12:55:51 +02:00
Mika KunsandClaude Haiku 4.5 912201770f fix(worker): add failureReason field to batch_get_tasks
The tool description claimed Failed tasks carry failureReason, but the field
was missing from BatchTaskDetailDto and rejected when requested in `fields`.
Add failureReason to the DTO, KnownDetailFields, and BuildDetail so list
handlers and other callers can read failure reasons without per-task get_task
calls. Tested: 31 BatchMcpToolsTests pass, including two new cases for
failureReason retrieval on Failed and Idle tasks.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-02 12:20:02 +02:00
Mika Kuns 9f90e75a85 refactor(tests): share StubWorkerClient between Ui.Tests and Worker.Tests
Worker.Tests carried its own hand-rolled FakeWorkerClient implementing the
whole IWorkerClient surface, duplicating StubWorkerClient in Ui.Tests. Every
hub-signature change had to be applied twice. Link StubWorkerClient.cs into
Worker.Tests via a csproj Compile Include and subclass it there; add
SetTaskStatusCalls tracking to the shared stub (the one behavior Worker.Tests
needed that Ui.Tests didn't have).
2026-09-02 12:17:00 +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 25ead4c8dd chore(claude-do): feat(worktrees): warn about git worktrees ClaudeDo doesn't k
From `docs/open.md` (re-verified against the code 2026-09-02, still open): nothing reconciles `git worktree list` against the `worktrees` table. `ExternalMcpService.ListWorktrees` and the Worktrees overview read DB rows only; `WorktreeManager` calls git solely inside its self-heal path (`ListWorktreePathsForBranchAsync`). Observed once: 22 git-registered worktrees + 26 `claudedo/*` branches in `C:

ClaudeDo-Task: 765fed13-db66-44e4-9285-c4b2d415b443
2026-09-02 12:09:12 +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 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 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
CubeGameLP e0748ba351 fix(worktree): auto-bootstrap commit-less repos before creating worktrees
Covers autonomous runs, interactive ConPTY sessions (GetInteractiveLaunchSpec),
planning sessions, and improvement/planning children — every path that needs a
base commit now self-heals on a fresh 'git init' repo instead of surfacing
"ambiguous argument 'HEAD'" as a HubException.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit ec16a85c495ceceaa22f922e077a27dcda54f035)
2026-08-28 20:33:45 +02:00
CubeGameLP de44196b9a fix(git): bootstrap commit-less repos and survive missing git identity
A fresh 'git init' repo (unborn HEAD) failed every worktree-based flow with raw
git stderr ('ambiguous argument HEAD'). EnsureHeadCommitAsync now creates an
empty initial commit via plumbing only (mktree/commit-tree/update-ref) so the
user's index and working tree are untouched; broken HEADs get a clear error.
CommitAsync retries once with a ClaudeDo identity when the machine has none,
and RevParseHeadAsync reports 'no commits yet' instead of raw git output.
Also: git stdin is now BOM-less UTF-8 (git rejects BOM-prefixed input).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 21af231f3e7b2cf056efe475916627f0cfeeb5c6)
2026-08-28 20:33:45 +02:00
Mika Kuns 8d597df448 fix(worker): make re-approve after revert_merge do a real merge, not a silent no-op
ApproveAndMergeAsync treated any non-Active worktree (including Kept, the
state RevertMergeAsync leaves behind) the same as "never had a worktree",
so re-approving a reverted task ran only the verify gate and marked the
task Done without merging anything back.

Now a Kept worktree is distinguished: if its branch is gone (the common
case, since approve normally deletes it), approve returns Blocked instead
of a fake "merged". If the branch survives, its tip is already an ancestor
of the target (from the original merge), so a plain `git merge` would
silently no-op ("Already up to date."); cherry-picking the original merge
commit's own diff (-m 1) is what actually restores the content, recorded
as a fresh MergeCommit.
2026-08-28 14:17:38 +02:00
Mika Kuns 1affb39716 fix(worker): survive a worker restart when cancelling a mid-merge unit-merge parent
CancelAsync only checked PlanningMergeOrchestrator's in-memory HasActiveMerge, which is
empty after a restart. IActiveMergeState gains an async fallback that checks on-disk
(GitService.IsMidMergeAsync) for a WaitingForReview parent with children, so the guard
still blocks cancel until the merge is continued or aborted.
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 3322152b9c fix(worker): Base-URL ohne Schema laesst die Ticket-Anbindung scheitern
Ein blanker Hostname ist eine relative URI; HttpClient lehnt sie mit
InvalidOperationException ab. Die lief an dem zu engen catch-Filter
vorbei, flog roh aus dem Hub und wurde von TryInvokeAsync zu null
verschluckt - die UI meldete "Worker not reachable", obwohl der Worker
lief und die Ursache eine Eingabe war.

- TicketSystemConfig ergaenzt fehlendes http://
- BandelTicketClient uebersetzt jede Transport-Exception in eine
  lesbare TicketApiException
- TestTicketConnection faengt alles und antwortet mit dem Grund
- GetTicketSettings liefert die effektive URL, damit die Ergaenzung
  sichtbar ist
2026-08-27 14:03:52 +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 2e236736a7 feat(worker): Ticket-Import pro Liste 2026-08-27 13:05:38 +02:00
mika kuns 5aafeb6c3d feat(worker): Ticket-Status-Rueckmeldung ueber TaskStateService 2026-08-27 12:53:38 +02:00
mika kuns 1065278021 feat(worker): BandelTicketClient fuer die Ticketsystem-REST-API 2026-08-27 12:42:22 +02:00
mika kuns 2a3c937f70 feat(worker): TicketSystemConfig + ticket_api_base_url in worker.config.json 2026-08-27 12:34:24 +02:00
mika kuns 41bfc242fa refactor(worker): OnlineTokenStore zu DpapiTokenStore verallgemeinert 2026-08-27 12:27:34 +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 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 89f0371279 fix(claude-do): merge Modify/Delete- und Rename-Konflikte im Merge sichtbar machen
ClaudeDo-Task: 059bcf98-34d5-4ca0-822d-317980fadf8d
2026-08-26 15:46:51 +02:00
Mika Kuns 421f06866e fix(claude-do): merge Status-Force-Bypässe auf laufende Tasks schließen (MCP + UI-
ClaudeDo-Task: 3b2c4015-226b-41a1-80c4-3a8d5537f2a5
2026-08-26 15:45:56 +02:00