Commit Graph
25 Commits
Author SHA1 Message Date
mika kuns 5d362b6973 fix(worker): stop sibling worktrees from landing inside the repo tree
Path.GetDirectoryName returned workingDir itself instead of its parent
whenever list.WorkingDir ended in a directory separator, placing
.claudedo-worktrees inside the target repo's own working tree. Add
WorktreeRootResolver to normalize the trailing separator before deriving
the sibling root and to guard that the resulting worktree path never
lands inside workingDir, used by both WorktreeManager and
PlanningSessionManager. Add a startup sweep (LegacyWorktreeFolderRecovery)
that warns when a list's working dir already contains a leftover
.claudedo-worktrees folder from before the fix.
2026-08-10 11:58:34 +02:00
mika kuns b6791265d1 fix(planning): recover the planning session id from the on-disk transcript
The interactive planning TUI never reports its claude session id back, so
planning_session_id stayed NULL and UpdatePlanningSessionIdAsync had no caller
at all -- ResumeAsync always threw "No Claude session ID captured yet".

Resume now looks the id up in the transcript Claude Code writes to
~/.claude/projects/<encoded cwd>/<sessionId>.jsonl for the planning worktree
(newest file wins; a worktree hosts exactly one session) and persists it, so
the next resume is a plain DB read. No transcript -> a clear "cannot resume"
instead of resuming the wrong session.
2026-08-06 09:10:50 +02:00
Mika Kuns 30e87e698e feat(worker): in-app interactive session service, replacing the wt terminal launch
InteractiveSessionService resolves a task's list working dir + seeded prompt,
spawns a StreamingClaudeSession (claude stream-json in the list dir, model+auto
as before), registers it in LiveSessionRegistry, streams output over TaskMessage,
and broadcasts InteractiveSessionStarted/Ended (an exit watcher fires Ended). The
hub's OpenInteractiveTerminalAsync now starts this in-app session; SendInteractiveMessage
and StopInteractiveSession route to it. The external Windows-Terminal interactive
launch (LaunchInteractiveAsync / InteractiveLaunchContext / OpenInteractiveAsync) is
removed; planning sessions keep their terminal launch.
2026-06-26 16:11:52 +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 kuns 1b3c6bdbb4 refactor(prompts): planning prompts read from editable files 2026-06-04 14:09:45 +02:00
mika kunsandClaude Opus 4.7 d094a21e09 feat(planning): prevent orphaned subtasks via guards + startup repair
Three coordinated guards close the orphan-creation paths:

- CreateChildAsync refuses when the parent is not in a planning phase.
- DiscardPlanningAsync now returns a structured DiscardPlanningOutcome
  and refuses when children are queued or running; callers can opt into
  auto-dequeuing queued kids via dequeueQueuedChildren=true. Terminal
  children (Done/Failed/Cancelled) are promoted to top-level instead of
  becoming orphans when the parent's PlanningPhase is reset.
- OrphanRecovery hosted service clears ParentTaskId on any rows whose
  parent is missing or no longer in a planning phase on worker startup,
  mirroring the StaleTaskRecovery pattern.

UI surfaces the block reason: a confirm dialog offers to dequeue queued
children and retry; a running-children block is shown as a hard error
asking the user to cancel first.

WorkerClient now negotiates the JsonStringEnumConverter so the
DiscardPlanningResult enum round-trips correctly over SignalR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 16:02:15 +02:00
Mika Kuns dc3fc443b4 refactor(data): retire legacy TaskStatus values and backfill existing rows
Slice 6 of the worker state and queue consolidation refactor.

* Drop Manual, Planning, Planned, Draft, Waiting from the TaskStatus enum
  and from the EF value converter; only the lifecycle values remain
  (Idle, Queued, Running, Done, Failed, Cancelled).
* Add migration RetireLegacyTaskStatus that rewrites existing rows:
  manual/draft -> idle, planning -> idle+planning_phase=active,
  planned -> idle+planning_phase=finalized, waiting -> queued+blocked_by
  derived from sort_order via a CTE with LAG().
* Reroute every call site that compared/set legacy values to the new
  three-field model (Status + PlanningPhase + BlockedByTaskId), including
  the planning repo helpers, MCP services, the planning chain coordinator,
  and the UI view-models. TaskRowViewModel now exposes PlanningPhase to
  drive the planning badge.
* Refresh Worker/CLAUDE.md and Data/CLAUDE.md, the docs/plan.md status
  section, and the planning verification notes in docs/open.md.
2026-04-27 15:28:55 +02:00
Mika KunsandClaude Opus 4.7 4ab906ff0b feat(planning): consolidate finalize+chain via TaskStateService, fix queue pickup
Slice 4 of the worker state consolidation refactor. Eliminates the
"queue never picks up planning tasks" bug structurally by routing both
the manager and MCP finalize paths through TaskStateService and
PlanningChainCoordinator.SetupChainAsync, where the auto-wake on enqueue
guarantees the queue picker claims the first child immediately.

- Delete TaskRepository.FinalizePlanningAsync; PlanningSessionManager
  now orchestrates via _state.FinalizePlanningAsync + _chain.SetupChainAsync.
- Rename QueueSubtasksSequentiallyAsync to SetupChainAsync (internal);
  layout is now Status=Queued + BlockedByTaskId, with auto-attached agent tag.
- OnChildFinishedAsync looks up the successor by BlockedByTaskId, drops
  the legacy Waiting status lookup.
- PlanningMcpService.Finalize routes through state+chain; EditableStatuses
  drops Waiting and adds Idle; gate uses PlanningPhase==Active.
- TaskStateService.FinalizePlanningAsync clears the planning session token.
- UI: TaskRowViewModel adds BlockedByTaskId; IsQueued/IsWaiting reflect
  the new layout; TasksIslandViewModel.RemoveFromQueueAsync clears
  BlockedByTaskId on dequeue.
- New regression test PlanningEndToEndTests.FinalizeAsync_FirstChildIs
  ClaimedByPicker_WithinDeadline asserts the picker claims the first
  child within 200ms with no manual WakeQueue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:16:12 +02:00
Mika KunsandClaude Opus 4.7 8823265e5a refactor(worker/state): introduce TaskStateService and route mutations through it
Slice 2 of the worker state consolidation refactor (spec sections 2 and 8).

Adds Worker/State/ITaskStateService + TaskStateService as the single component
that mutates Status, PlanningPhase, and BlockedByTaskId. Each transition is one
atomic ExecuteUpdate with a WHERE filter on the expected source status, so
parallel claims are TOCTOU-free. Side effects (queue wake on -> Queued, hub
TaskUpdated broadcast, chain advance + parent completion on terminal child)
are owned by the service so callers no longer need to remember them.

Migrated callers (mechanical, behavior preserved):
- TaskRunner: HandleSuccess/HandleFailure/MarkFailed/RunAsync/ContinueAsync
- StaleTaskRecovery: bulk recover stale Running tasks
- TaskResetService: status flip (worktree cleanup stays in service)
- PlanningSessionManager.StartAsync: status flip via state, token write via repo
- PlanningChainCoordinator.OnChildFinishedAsync: routes the next-sibling write
  through state.UnblockAsync (Slice 4 finishes the rewrite)
- ExternalMcpService.UpdateTaskStatus: Queued case via state.EnqueueAsync

Repo Mark*Async helpers (MarkRunning/MarkDone/MarkFailed/FlipAllRunningToFailed)
are now internal; ClaudeDo.Data grants InternalsVisibleTo to ClaudeDo.Worker
and ClaudeDo.Worker.Tests for the existing repo-level tests.

DI: TaskStateService is registered as Singleton in both the main app and the
external-MCP app; the queue-wake delegate captures sp -> QueueService.WakeQueue
to break the TaskStateService -> QueueService -> TaskRunner -> TaskStateService
construction cycle. PlanningChainCoordinator takes Func<ITaskStateService> for
the same reason; Slice 3 will replace both with IQueueWaker.

Tests: TaskStateServiceTests covers happy + reject for every transition, the
parallel StartRunningAsync claim race, child-terminal chain advancement, and
stale recovery. Existing service/repo tests are updated to construct the new
state-service via a TaskStateServiceBuilder helper. Pre-existing constructor
drift in QueueService/ExternalMcp/PlanningHub tests is patched to keep the
test project building (the surrounding test logic is otherwise untouched).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 11:31:57 +02:00
mika kunsandClaude Opus 4.7 6c54759aa0 feat(ui): add Run interactively action to task context menu
Spawns Windows Terminal in the list working directory running
`claude --permission-mode auto` with the task title and description
prefilled as the initial prompt. Reuses the planning launcher
infrastructure but skips worktree, system prompt, and MCP setup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 10:02:21 +02:00
mika kunsandClaude Opus 4.7 16e1ddd129 feat(worker): add PlanningChainCoordinator for sequential subtask execution
Coordinates Waiting -> Queued transitions between sibling subtasks: when a child finishes Done, the next Waiting sibling is promoted to Queued. WorkerHub.QueuePlanningSubtasksAsync exposes this to the UI; TaskRunner advances the chain on completion. Also tightens the planning-session prompt: planner must use MCP tools, not direct edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:36:01 +02:00
mika kunsandClaude Opus 4.7 8e9f09a8e6 feat(worker): run planning agent in plan permission mode and enforce brainstorming skill
Adds --permission-mode plan to both launch paths (start and resume) so the
planning agent cannot perform file-modifying actions during the planning
conversation. Also appends instructions to the system prompt telling the
agent to always invoke the superpowers:brainstorming skill before creating
any child tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 18:38:09 +02:00
mika kunsandClaude Opus 4.7 e62485db3b fix(worker): derive planning MCP URL from configured SignalRPort
Hard-coded 47821 meant .mcp.json pointed at the wrong port for any
worker running on a custom signalr_port (e.g. 37821), causing
"Unable to connect" auth failures in the planning session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:07:44 +02:00
mika kunsandClaude Opus 4.7 48899b3df8 feat(worker): cleanup planning worktree and branch on finalize/discard
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:43:53 +02:00
mika kunsandClaude Opus 4.7 fce91bcf86 feat(worker): create ephemeral worktree and write .mcp.json in StartAsync
Rewrites StartAsync to provision a git worktree before transitioning the
task to Planning state, writes .mcp.json and .claude/settings.local.json
into the worktree, and fixes ResumeAsync to supply the updated
PlanningSessionResumeContext fields (Token, WorktreePath).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:37:42 +02:00
mika kunsandClaude Opus 4.7 975e1ce50c refactor(worker): switch MCP config to env-var token expansion
BuildMcpConfigJson drops the token argument; the literal
\${CLAUDEDO_PLANNING_TOKEN} placeholder is written to mcp.json so
claude expands it from the spawned process environment at load time.
Also declares SettingsLocalJson constant for use in later tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:30:11 +02:00
mika kunsandClaude Opus 4.7 1d61df8160 refactor(worker): add worktree path and token file helpers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:27:35 +02:00
mika kunsandClaude Opus 4.7 1370bf3dcc refactor(worker): inject GitService and WorkerConfig into PlanningSessionManager
Adds AppSettingsRepository to the test constructor, GitService and
WorkerConfig to both constructors, and updates CreateRepos() and all
its call-sites to expose the new settings tuple element.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:24:28 +02:00
mika kuns c048264b95 fix(worker): register TaskRepository in DI and guard null WorkingDir 2026-04-23 23:17:30 +02:00
mika kunsandClaude Sonnet 4.6 6cb20a9213 feat(worker): map MCP HTTP endpoint and broadcast TaskUpdated
- Add PlanningMcpContextAccessor (Option A) to read PlanningMcpContext
  from HttpContext.Items set by PlanningTokenAuthMiddleware
- Annotate PlanningMcpService with [McpServerToolType]/[McpServerTool]
  and remove PlanningMcpContext ctx parameter from all tool methods
- Broadcast TaskUpdated(parentTaskId) via HubBroadcaster after every
  mutation in PlanningMcpService
- Refactor PlanningSessionManager to accept IDbContextFactory for
  singleton-safe use in DI; keep direct-repo ctor for tests
- Register PlanningSessionManager (singleton), IPlanningTerminalLauncher,
  PlanningMcpContextAccessor, PlanningMcpService, and MCP server in
  Program.cs; wire PlanningTokenAuthMiddleware and MapMcp("/mcp")
- Update PlanningMcpServiceTests with fake HttpContext accessor and
  no-op HubBroadcaster (avoids Moq dependency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 23:12:24 +02:00
mika kuns d28164caf4 feat(worker): PlanningSessionManager.GetPendingDraftCountAsync 2026-04-23 21:04:06 +02:00
mika kuns 77f7cf1423 feat(worker): PlanningSessionManager.FinalizeAsync 2026-04-23 21:01:22 +02:00
mika kuns 84e6c2d5fc feat(worker): PlanningSessionManager.DiscardAsync 2026-04-23 20:58:55 +02:00
mika kuns 84b0ba8670 feat(worker): PlanningSessionManager.ResumeAsync 2026-04-23 20:55:01 +02:00
mika kunsandClaude Sonnet 4.6 b6bec1e63c feat(worker): PlanningSessionManager.StartAsync
Add PlanningSessionFiles, PlanningSessionStartContext/ResumeContext DTOs,
PlanningSessionManager.StartAsync (file scaffolding + status transition),
and integration tests. Also fix migration discovery by adding [DbContext]
attribute to all migration classes and switch DbFixture to EnsureCreated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 20:49:41 +02:00