Files
ClaudeDo/docs/superpowers/plans/2026-07-24-merge-helper.md
T

6.3 KiB

Merge Helper — Implementation Plan

Spec: docs/superpowers/specs/2026-07-24-merge-helper-design.md Approach: subagent-driven (one subagent per task, sonnet, TDD, stage files by path — never git add -A). Build with -c Release per-csproj (a running Worker locks Debug). Commit per task, Conventional Commits.


Phase A — Worker MCP conflict tools

Independently useful; merges first. All in src/ClaudeDo.Worker/External/ExternalMcpService.cs + tests in tests/ClaudeDo.Worker.Tests/.

A1 — Verify engine surface (spike, no commit)

Read TaskMergeService.MergeAsync / ContinueMergeAsync / AbortMergeAsync and the hub conflict flow (WorkerHub.StartConflictMerge/ContinueConflictMerge/AbortConflictMerge). Pin down:

  • exact ContinueMergeAsync / AbortMergeAsync signatures and how in-progress-merge state is located (repo + target branch from task/list, not shared hub state);
  • how the childless approve path (ApproveAndMergeAsync) threads leaveConflictsInTree. Record findings in the task notes; feeds A2/A3.

A2 — leaveConflictsInTree on review_task / merge_task

  • TDD: tests in Worker.Tests (real git) — clean merge → Done; conflict + flag → conflict_in_tree, markers present, task stays WaitingForReview, repoPath returned.
  • Add optional param leaveConflictsInTree = false to MergeTask and ReviewTask (approve branch). When true, call the leaveConflictsInTree:true engine path and map the conflict result to { mergeStatus/merged, conflicts, repoPath }.
  • Keep default behaviour (abort-on-conflict) byte-identical when the flag is absent/false.
  • Commit: feat(worker): let review_task/merge_task leave conflicts in tree via MCP

A3 — continue_merge + abort_merge MCP tools

  • TDD: continue after on-disk resolution → committed, task Done, worktree merged; continue with markers remaining → returns conflicts; abort → markers gone, task WaitingForReview; both on no-active-merge → clean MCP error; TaskUpdated fired.
  • Add [McpServerTool] continue_merge(taskId)ContinueMergeAsync; abort_merge(taskId)AbortMergeAsync. Locate the merge from the task's repo/target. Emit TaskUpdated.
  • Route both single-task and orchestrated (parent/children) in-progress merges where locatable from the task (per A1 findings): detect the kind and call the matching engine continue/abort (TaskMergeService vs PlanningMergeOrchestrator.Continue/Abort). If the orchestrated path can't be located without hub UI state, leave it to the manual fallback (documented in the B1 prompt) and note the gap in docs/open.md.
  • Commit: feat(worker): add continue_merge and abort_merge MCP tools

Phase B — Worker launch for the merge-helper session

B1 — Prompt templates

  • Add PromptKind.MergeHelper + PromptKind.MergeHelperInitial to ClaudeDo.Data/PromptFiles.cs (file names merge-helper-system.md / merge-helper-initial.md, built-in DefaultFor, Render tokens for the initial brief).
  • System prompt encodes §7 behaviour (per-status algorithm, ask-on-uncertainty, summary format). Merge-state rule: prefer MCP tools whenever they apply; hand-merge (Edit + git commit -- <paths>) is an accepted fallback only for merges the MCP tools can't reach (§5.3), never a shortcut around them.
  • Initial brief renders a task table {id,title,status,list,repo} + scope label.
  • TDD: PromptFiles tests — kinds resolve, defaults non-empty, Render substitutes brief tokens.
  • Commit: feat(data): add merge-helper prompt templates

B2 — BuildForMergeHelper launch spec

  • TDD (Worker.Tests): distinct-repo --add-dir set computed from selected tasks; correct cwd per scope (per-list repo vs first repo global); brief file written to ~/.todo-app/merge-helper-sessions/<guid>/brief.md; allowed-tools + --permission-mode default + MCP_TOOL_TIMEOUT env correct; single-line kickoff points at the brief.
  • Implement InteractiveLaunchSpecService.BuildForMergeHelper(IReadOnlyList<string> taskIds, MergeHelperScope scope, ct). Reuse the planning brief-file/kickoff pattern.
  • Commit: feat(worker): build merge-helper interactive launch spec

B3 — Hub endpoint + client method

  • WorkerHub.GetMergeHelperLaunchSpec(string[] taskIds, string? listId); IWorkerClient.GetMergeHelperLaunchSpecAsync(...) + WorkerClient impl.
  • Update hand-rolled IWorkerClient fakes in both test projects (see gotcha memory).
  • Commit: feat(worker): expose merge-helper launch spec over the hub

Phase C — UI

C1 — Selection dialog (View + VM)

  • New MergeHelperSelectionViewModel + MergeHelperSelectionDialog.axaml (compiled bindings, TaskCompletionSource<T> pattern). Checkbox rows (title, status badge, list/repo), grouping in global mode, default ticks per §4, select-all/none, confirm disabled when empty.
  • Candidates via existing list_tasks/worker client; filter client-side.
  • TDD (Ui.Tests): default-tick logic, empty→confirm-disabled, returns ordered selected IDs + list mapping.
  • Commit: feat(ui): add merge-helper task selection dialog

C2 — Entry points + event plumbing

  • Per-list context-menu item "Let Claude handle it" in ListsIslandView.axaml (user-list rows) + one global entry in the footer. Bind to LetClaudeHandleCommand on ListsIslandViewModel (param = ListNavItemViewModel or a global sentinel).
  • VM raises LetClaudeHandleRequested(MergeHelperScope); IslandsShellViewModel forwards to Mission Control.
  • Commit: feat(ui): add "Let Claude handle it" entry points

C3 — Mission Control wiring

  • MissionControlViewModel.OpenMergeHelperConPtySessionAsync(scope): open selection dialog → on confirm, GetMergeHelperLaunchSpecAsync → wrap in TerminalLaunchDescriptor → new ConPtyPaneViewModel (never deduped) → add to ConPtySessions/Panes.
  • Commit: feat(ui): open merge-helper ConPTY tile from selection

Verify (per task + at the end)

  • Read each subagent diff; build the touched csproj -c Release; run the relevant test project.
  • locales/en.json + de.json parity for any new UI strings (Localization.Tests enforces it).
  • Flag visual-verification gaps (dialog layout, tile) for the user — never claim UI works without a run.
  • End-to-end ConPTY smoke (real Claude) is a manual item in docs/open.md.

Commit docs first

docs(merge-helper): spec + implementation plan (this file + the spec).