Commit Graph
96 Commits
Author SHA1 Message Date
mika kuns 514d6111fe fix(test): name the cancellationToken arg in the preview_merge_set subset test
Two branches merged into main independently: one added `runVerify` to
PreviewMergeSet ahead of `cancellationToken`, the other added the subset
test that passed the token positionally. Neither conflicted textually, so
the mismatch only surfaced as CS1503 at test-compile time.
2026-08-10 15:26:07 +02:00
mika kuns 66f7a8ae99 Merge branch 'claudedo/9f963a215bb34ca4a28050d4f39178d3' 2026-08-10 15:19:57 +02:00
mika kuns 8b75a92794 Merge branch 'claudedo/5c80a0aba5d9468a96cf809fc7a6e7a1' 2026-08-10 15:15:26 +02:00
mika kuns 333ce89eef Merge branch 'claudedo/16172942c1424a67a0499e01cefb7d60' 2026-08-10 15:08:51 +02:00
mika kuns a9396c1a99 Merge claudedo/89f989e04fcf43f5a80211d63df7a6d1 2026-08-10 15:07:05 +02:00
mika kuns 2fd7f829bd Merge branch 'claudedo/340b4a2df0f14235a34fe0d02b2dc06f' 2026-08-10 15:01:33 +02:00
mika kuns 474c7201c9 Merge claudedo/f319b602707f4dfdb6727e9fae5ac757 2026-08-10 14:58:58 +02:00
mika kuns 19b31450b1 Merge claudedo/e5aeaf59fae840adaea3f1e912e203e1 2026-08-10 14:58:35 +02:00
mika kuns 52b42c0a35 Merge claudedo/fc88143c0c704feab4ba6806cec49f4f 2026-08-10 14:56:55 +02:00
mika kuns 31a89bd93f Merge claudedo/21d704131b2d486cb1d103134e5ea5e8 2026-08-10 14:56:37 +02:00
mika kuns d3155e6868 feat(queue): warn when the base branch has uncommitted changes
Queuing (update_task_status, batch_update_task_status) and run_task_now
now surface a non-blocking baseDirty warning (separate modified/untracked
counts) when the list's working dir has uncommitted changes at enqueue
time, since a new worktree forks from the commit tip and silently misses
them. BaseDirtyChecker caches per working dir for a few seconds so a
batch queue over many tasks in one list only shells out to git once. The
UI surfaces the same warning via the footer error strip on queue actions.
2026-08-10 14:30:33 +02:00
mika kuns 09add29994 fix(mcp): keep wait_for_task_change alive past Claude Code's idle timeout
MCP_TOOL_TIMEOUT (raised by ClaudeDo's launchers) is a wall-clock cap unrelated
to Claude Code's idle-silence abort (default 300s for HTTP-transport MCP
servers), which no launcher raises. A wait near the 900s recommendation was
silently killed at ~300s in any session, launcher or not.

WaitForTaskChange now reports MCP progress every 30s while polling, which
resets that idle timer. Verified against a real claude -p call (no launcher
env overrides) surviving a 341s wait via 60s pings -- the same silence that
previously aborted at 300s. Tool description and the list-handler prompt no
longer claim ClaudeDo's launchers guarantee a long wait survives.
2026-08-10 14:21:18 +02:00
mika kuns a067a7bfff fix(mcp): report a Failed task's failureReason instead of a bare status
get_task/batch_get_tasks now return failureReason (max_turns|timeout|error|
cancelled|unknown) plus failureTurnsUsed/failureMaxTurns on a Failed task, so
max_turns (worktree usually fine, continue_task) is distinguishable from a
real error (reset_failed_task) without pulling get_task_log's raw NDJSON.
Classified and stamped onto TaskEntity by TaskRunner.MarkFailed via
TaskStateService.FailAsync; TaskRunEntity also keeps the CLI's raw
terminal_reason/result_subtype/errors for deeper diagnosis. reset_failed_task's
description now warns explicitly that it discards the worktree and points at
continue_task for max_turns. Surfaced on the task card's status-chip tooltip.
2026-08-10 14:20:00 +02:00
mika kuns ca6eb62b5c feat(mcp): truncate/select batch_get_tasks payload, expose roadblockText
batch_get_tasks with includeDescription=true had no size guard: 8 tasks'
full Description/Result serialized to a single 51k-char line, blowing past
the tool-result token budget and forcing a file/PowerShell workaround to
read it back. Roadblock text was also only reachable via a second get_task
call per task, since roadblockCount (in the lean ref) has no text sibling.

- descriptionMaxChars (default 1500, was unlimited) truncates Description
  and Result independently, flagged via *Truncated/*FullLength so a caller
  never silently works off a cut string.
- fields narrows taskFull to just the named properties, including the new
  roadblockText (the tail of Result after TaskRunner's roadblock marker) —
  reachable without pulling in the rest of Result/Description.
- taskFull is now BatchTaskDetailDto, a batch-only shape decoupled from
  TaskDto so get_task's own contract is untouched.
- The whole response is capped (MaxResponseChars); over that, the call
  throws naming which parameter (descriptionMaxChars/fields/taskIds) to
  adjust instead of shipping an oversized payload.

10 tasks with 5000-char descriptions (default settings) serialize to
~13.8k chars, comfortably under the 25k-char cap.
2026-08-10 14:19:16 +02:00
mika kuns 6c8ec245b3 feat(worker): dependsOn via MCP + honest staleness signal in merge preview
Adds a user/MCP-declared task dependency (DependsOnTaskId) distinct from the
planning chain's internal BlockedByTaskId: add_task/update_task can set it,
the queue picker skips a Queued task until the dependency reaches Done, a
Failed/Cancelled dependency leaves the dependent blocked instead of starving
silently, and setting a link rejects self-reference/unknown-id/cycles.
get_task/list_tasks/batch_get_tasks now report blocked/blockedReason, and
wait_for_task_change reports "Blocked" immediately instead of running out its
timeout on a task the picker will never claim.

preview_merge/preview_merge_set gain staleFiles: files a branch touches that
the target branch also changed since the branch's fork point, a more honest
staleness signal than `behind` alone.
2026-08-10 14:18:55 +02:00
mika kuns 5eea439129 fix(mcp): make set_task_config/set_list_config patch instead of overwrite
Omitted fields on set_task_config/set_list_config used to be indistinguishable
from an explicit clear, so any single-field update silently wiped every other
override (including SessionSkills, which wasn't even a tool parameter). Now
only the fields you pass are changed; clearing an override requires naming it
in the new clearFields array (a sentinel string doesn't work uniformly since
maxTurns is an int). set_list_config's "all four null deletes the config" case
is preserved but only reachable via clearFields. Return values now reflect the
full resulting config.
2026-08-10 13:55:58 +02:00
mika kuns 5653daca6e feat(mcp): expose the conflict resolver's hunk API over MCP
get_merge_conflicts and resolve_conflict_hunk let an MCP caller resolve a
leaveConflictsInTree merge hunk-by-hunk (ours/theirs/base/literal text)
instead of grep-parsing diff3 markers itself. Reuses the existing
TaskMergeService/ConflictMarkerParser machinery (adds MergeSegment.StartLine
and a non-staging TaskMergeService.WriteConflictFileAsync) rather than a
second parser. A partially resolved file is written without git add so
continue_merge keeps refusing while any hunk still has markers.
2026-08-10 13:49:07 +02:00
mika kuns 07ee535b7d feat(claude-do): feat(queue): Option pro Liste — Tasks mit überlappendem Date
## Befund (Batch-Lauf 2026-08-06, Liste "Bandel.Hub")
maxParallelExecutions = 5, 23 Geschwister-Tasks auf demselben Plugin. Die Parallelitaet hat die
Ausfuehrung verkuerzt, aber die Konfliktlast erhoeht: eine CSS-Datei wurde von 10 Tasks
angefasst, drei Razor-Dateien von je 6. Der Engpass des Gesamtdurchlaufs war nicht die
Ausfuehrung, sondern Review und Merge — die sind zwingend seriell. Netto wa

ClaudeDo-Task: 89f989e0-4fcf-43f5-a802-11d63df7a6d1
2026-08-10 13:41:38 +02:00
mika kuns c715c96af9 feat(mcp): paths filter for get_task_diff, subset hint for preview_merge_set
get_task_diff gained an optional paths param (git pathspec, both stat and
full-diff modes) so a large multi-file task can be narrowed to the files
actually in question instead of shipping the whole diff.

preview_merge_set now also reports Subsets: pairs where one task's changed
files are a proper subset of another's in the same set, the strongest
available post-hoc signal that a task may be redundant with another.
2026-08-10 13:39:55 +02:00
mika kuns effece3a41 feat(worker): build/test the merge preview, not just the post-merge merge
preview_merge could only see file-overlap cleanliness via git merge-tree, never
whether the result compiles -- the two costliest findings of the 2026-08-06 batch
run were both merge-tree-clean but build-broken. When a list has a verify command
configured, a clean preview is now additionally materialized (via a commit-tree +
detached scratch worktree, outside the real repo, always cleaned up) and
built/tested there, without ever touching the real working tree.

preview_merge always attempts a verify run when a command is configured;
preview_merge_set only does when its new runVerify parameter is set (default off),
so a set preview never starts N builds unasked. The post-merge verify gate is
unchanged.
2026-08-10 12:10:17 +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 c792765ed3 refactor(mcp): rewrite external MCP tool descriptions for trigger clarity
Every tool description now leads with what the tool does AND when to reach for
it, since MCP clients rank tools by that text. Per-parameter prose moved onto
the parameters as [Description], exhaustive result-shape enumerations and
design/history rationale dropped, and the repeated boilerplate clauses
(lean-task-ref, batch cap, refused-while-Running) pulled into McpToolDocs,
which also documents the style for future tools.

Tool-level description text: 20494 -> 13605 chars (-34%); combined with the new
parameter descriptions 18517 (-10%).

Closes gaps that caused wrong calls rather than just verbose ones:
- list_task_attachments returns metadata only, no file content
- run_task_now shares continue_task's single override slot and throws when busy
- list_runs is ordered oldest-first and feeds get_run
- workingDir on create_list/update_list is an existing local git repo path,
  unvalidated until the first task run
- get_task_worktree's behind=0 also means the main ref was unreachable

Removes get_task_status_values: a whole tool entry for static reference text.
GetTask's description is now the canonical place for status meanings.
2026-08-07 09:25:45 +02:00
mika kuns 7f03f04268 Merge branch 'claudedo/9c0bff67147148f3beeee180e70b5503' 2026-08-06 13:46:52 +02:00
mika kuns efee14780b fix(worker): filter the transliterated 'fuer' stopword, not the untransliterated 'fur'
NormalizeTitleWords transliterates umlauts before tokenizing ('für' ->
'fuer'), but TitleStopWords listed 'fur' -- a token the pipeline can
never produce -- so 'für' was never filtered as filler and could push
unrelated titles past the near-duplicate threshold.
2026-08-06 13:37:35 +02:00
mika kuns 774f9d3d13 fix(worker): claim Running before creating run resources
TaskRunner.RunAsync created the worktree (PrepareRunDirectoryAsync)
before claiming Running via StartRunningAsync. RunNow dispatches by
task id with no atomic claim of their own, so a Queued task racing
the queue picker's atomic SQL claim could hit WorktreeManager's
branch-collision self-heal, which force-removes and recreates the
winner's live worktree mid-run.

Move the claim before any resource creation and bail out immediately
when it's rejected. OverrideSlotService.RunNow also fast-rejects a
task already Running in the DB (defense in depth). RunCancellationRegistry
now refuses (and logs) a double registration instead of silently
overwriting the first CTS, so a losing dispatch's cleanup can no
longer unregister the winner's cancellation token.
2026-08-06 13:33:23 +02:00
mika kuns 0358bcf8b2 Merge branch 'claudedo/001ee94a1d8d46b0906f7466ea6beb32' 2026-08-06 12:04:47 +02:00
mika kuns e59f6c2438 fix(worker): surface empty review ranges and blocked children over MCP
preview_merge/preview_merge_set now report isEmpty (ahead==0, or
HandlerBaseCommit==HandlerHeadCommit for a worktree-less list-handler
task) instead of leaving an empty branch indistinguishable from a small
one. preview_merge also stops throwing for worktree-less handler tasks,
falling back to their fixed commit range. review_task's parent approve
returns emptyChildren, naming the Done children whose review range
contributed nothing before the unit merge lands. TaskRefDto/TaskDto now
expose roadblockCount so a CLAUDEDO_BLOCKED child is identifiable over
MCP, since it still reaches Done per the unified parent model.
2026-08-06 11:54:46 +02:00
mika kuns 4a60c2bfa8 Merge branch 'claudedo/0733742e0da8407d8e2be1bc5886bf9b' 2026-08-06 11:40:47 +02:00
mika kuns f3e16412f4 Merge branch 'claudedo/c1d2a92d8d8c4705ac93d5f0b2cacaa0' 2026-08-06 11:38:32 +02:00
mika kuns af16830060 feat(worker): add treatWaitingForChildrenAsBusy to wait_for_task_change
WaitingForChildren already counted as "changed" since it's outside Queued/Running,
so waiting on a planning parent returned immediately even though its children were
still running. The new opt-in flag (default false, unchanged behavior) keeps polling
through WaitingForChildren and only reports changed once the parent reaches
WaitingForReview or a terminal status.
2026-08-06 11:32:00 +02:00
mika kuns f8c48e2ed7 fix(worker): make list_tasks/batch_get_tasks lean by default
list_tasks on a list of ~100 verbosely-described tasks could return
390k+ characters in one call, blowing past the caller's token limit.
Both tools now default to lean TaskRefDto references (no
Description/Result) and take an includeDescription flag to opt back
into the full TaskDto payload — same flag-alongside-nullable-payload
idiom already used by BatchGetTaskResult/TaskConfigResult. get_task is
unchanged.
2026-08-06 11:25:32 +02:00
mika kuns 3e07536ee9 feat(worker): warn on near-duplicate titles in add_task/batch_add_tasks
add_task and batch_add_tasks now report up to 3 open (non-terminal)
tasks in the same list with a strongly overlapping title, so a
parallel agent can notice and mention a likely duplicate instead of
silently creating one. The task is always created regardless. Uses a
cheap normalized-word overlap heuristic (no embeddings/LLM call),
robust to German umlaut/digraph spelling variants. Breaking change:
AddTask now returns AddTaskResult { task, possibleDuplicates } instead
of a bare TaskRefDto; BatchAddTaskResult gained a PossibleDuplicates
field.
2026-08-06 11:24:17 +02:00
mika kuns ad2d91f658 Merge claudedo/ccd650a8d2b04a7092e81ed07c16dbe0 2026-08-05 22:46:37 +02:00
mika kuns cdfd0614dd Merge claudedo/616befd0f8a64dcb9e3dac9d6499de16 2026-08-05 22:45:32 +02:00
mika kuns 1d258a3e2c Merge claudedo/123b0241b5e94b69bfa592fde89c51aa 2026-08-05 22:44:47 +02:00
mika kuns d43b5fcefc feat(worker-mcp): raise wait_for_task_change timeout, expose queue slot state
MaxTimeoutSeconds was 170s against runs that take tens of minutes, forcing
a dozen full-context wait rounds per long-running batch. Raise it to 900s
and raise MCP_TOOL_TIMEOUT in lockstep (ClaudeProcess + every
InteractiveLaunchSpecService launch spec) to 930000ms so the client
connection actually stays open that long instead of aborting first.

Add get_queue_state (QueueStateMcpTools): configured vs. effective
parallel-slot count (via QueueService.GetSlotCountsAsync, extracted from
the former GetEffectiveMaxParallelAsync), active slots with taskId +
startedAt including the run_task_now override slot, and queued tasks in
pick order -- so a caller can observe queue occupancy instead of inferring
it from maxParallelExecutions.
2026-08-05 20:47:57 +02:00
mika kuns a768bc4163 feat(worker): add get_effective_run_config MCP tool
Adds a read-only get_effective_run_config(taskId) tool that reports the
model/max-turns/effort/permission-mode/agent-path/system-prompt/skills a
task will actually run with, each tagged with its source (task/list/
preset/global), plus max-turns' raw requested value and clamp status.

Extracted the model/max-turns/agent-path resolution out of
TaskRunner.ResolveConfigAsync into EffectiveRunConfigResolver so the run
path and the new reporting tool share one codepath instead of risking
drift, per docs/explore-notes/worker-task-pipeline.md's max-turns trap.
2026-08-05 20:39:35 +02:00
mika kuns ecba12997a perf(worker): stop echoing task description from writing MCP tools
update_task, update_task_status, add_task, add_subtask, set_my_day,
abort_merge, review_task, and their batch variants now return a lean
TaskRefDto (id/listId/title/status/sortOrder/isMyDay) instead of the
full TaskDto. Those tools were re-sending the caller's own description
text back on every call, wasting a large share of session context on
list-handler-style runs. get_task/list_tasks/batch_get_tasks are
untouched and still return the full DTO.
2026-08-05 20:37:30 +02:00
mika kuns 4ef01274f9 feat(list-handler): hand off to a fresh session after Phase 2
The merge-helper ("Let Claude handle it") system prompt now calls a new
handoff_list_handler MCP tool once every surviving task is enhanced,
instead of continuing into Phases 3-5 in the same session -- avoiding
paying for Phases 0-2's dedupe/rewrite context on every polling round of
the run/review/merge phases.

The tool broadcasts HandoffRequested; Mission Control opens a second
ConPTY tile for the SAME handler task id (no new task, HandlerBaseCommit
untouched) running a fresh handoff brief that starts at Phase 3. The
original tile stays open. Adds PromptKind.MergeHelperHandoff,
InteractiveLaunchSpecService.BuildForMergeHelperHandoffAsync, and the
GetMergeHelperHandoffLaunchSpec hub method.
2026-08-05 20:27:39 +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 1aaa40b894 Merge branch 'claudedo/0b2fbb48d44c41558c21d3464c0bd5c2' 2026-08-05 12:11:55 +02:00
mika kuns 3e7126b3f2 Merge branch 'claudedo/9e3071992eca4eb79057d2c675cc57ca' 2026-08-05 12:05:18 +02:00
mika kuns 10e561f336 feat(worker): record merge commit SHA and add revert_merge tool
Persists the merge commit SHA on WorktreeEntity for every successful
single-task and unit merge, and adds a TaskMergeService.RevertMergeAsync
+ revert_merge MCP tool that undoes a merged task's merge via
`git revert -m 1` (never reset/rewrite, since the target checkout is
shared). Rejects cleanly when there's no recorded SHA, the repo is
mid-merge/mid-revert, or the target has foreign uncommitted changes;
a conflicting revert aborts immediately. Also exposes the new
mergeCommit field via get_task_worktree.
2026-08-05 11:46:51 +02:00
mika kuns 42c70fb28c Merge branch 'claudedo/99732497092746d193b80b8296804374' 2026-08-05 11:21:12 +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 394febadeb feat(worker): add preview_merge and preview_merge_set MCP tools
Give an autonomous reviewer a non-destructive merge-tree preview
(status/conflicts/changedFileCount/behind) for a task's worktree branch,
plus a file-overlap check across a batch of tasks so same-file collisions
between sibling branches are visible before merging. MergeHelperDefault's
Phase 4 now calls preview_merge_set before merging a batch.
2026-08-05 11:15:43 +02:00
mika kuns 1ee21b560d Merge task branch for: Worker: UsageGate — Queue ab Schwelle pausieren 2026-08-05 11:11:24 +02:00
mika kuns 8f8c2a65b2 feat(claude-do): Worker: UsageGate — Queue ab Schwelle pausieren
> **Stand 2026-08-05 (List-Handler):** Der Roadblock aus dem letzten Lauf ist erledigt. Beide Voraussetzungen sind jetzt auf `main` gemerged: die `app_settings`-Schwellen `UsageGateFiveHourPct`/`UsageGateSevenDayPct` (Merge-Commit `b1efcdc`) und `UsageState`/`IUsageClient`/`UsageMonitorService` unter `src/ClaudeDo.Worker/Usage/` (Merge-Commit `b126a21`). Dein Worktree ist frisch von diesem `main`

ClaudeDo-Task: 06a7cc32-6ab7-4758-98f4-bee77149b2bf
2026-08-05 11:10:30 +02:00
mika kuns 6c5acd09b9 Merge claudedo/0020cd0c4696431996a158f8e1b91cba 2026-08-05 11:05:36 +02:00
mika kuns c871f35513 chore(worker): external MCP tools return explicit results instead of empty responses
set_task_config/set_list_config now echo which fields were set vs cleared, get_list_config/get_task_config return an explicit found=false instead of null, and delete_list/run_task_now/reset_failed_task/remove_task_attachment return a confirmation record — matching the found/ok convention already used by batch_get_tasks and get_task_log.
2026-08-05 10:58:28 +02:00