feat(coordinator): UI components, control banners, and coordinator entry points (PR 4/4)#125
feat(coordinator): UI components, control banners, and coordinator entry points (PR 4/4)#125brooksc wants to merge 3 commits into
Conversation
…task model Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…restore Wires the coordinator MCP engine (PR 2) into the frontend store and Electron IPC layer. Feature is dark by default — coordinatorModeEnabled defaults to false; nothing is user-visible until PR 4 adds the Settings checkbox and NewTaskDialog entry point. Key additions: - Task model: coordinatorMode, coordinatedBy, controlledBy, stagedNotification, mcpStartupStatus, signalDone*, needsReview, and 3 global coordinator fields - initMCPListeners(): subscribes to 7 MCP push events (TaskCreated, TaskClosed, CleanupFailed, NotificationStaged/Cleared/Orphaned, TaskStateSync, TaskHydrated) - MCP startup state machine: markTaskMcpPending/Ready/Error, retryTaskMcpStartup - setTaskControl(): coordinator ↔ human hand-off; collapseTask guard for children - closeTask(): calls MCP_CoordinatedTaskClosed / MCP_CoordinatorDeregistered on close - Session restore: App.tsx calls StartMCPServer for each persisted coordinator task on startup, rewriting .mcp.json with the new session port/token; children start pending until MCP_HydrateCoordinatedTask returns - Persistence: all coordinator fields round-tripped through saveState/loadState; tasks with coordinatorMode/coordinatedBy load with mcpStartupStatus pending - coordinator-preamble.ts: system preamble injected into coordinator agent prompts - mcpStatus.ts: polls GetMCPStatus every 3 s; inert when no coordinator is active - Deregister fix: suppresses spurious needsReview notification for children that never received their prompt (assignedPromptDelivered false) - Tests: ~40 new cases across tasks, notifications, taskStatus, persistence Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…points, and e2e fixes
Adds all user-visible coordinator UI on top of the store/IPC layer (PR 3).
Feature becomes live: Settings checkbox sets coordinatorModeEnabled, and
NewTaskDialog exposes the coordinator mode option.
UI components:
- SubTaskStrip: nested sub-task status strip rendered inside coordinator task panel
- Sidebar: groups coordinator + children, hides children from flat list, control banner
- TaskPanel: coordinator detail view, sub-task list, merge/close actions
- PromptInput: staged notification display, send/edit/dismiss controls, autofire tick
- SettingsDialog: coordinator mode toggle + notification delay slider
- NewTaskDialog: coordinator mode checkbox + propagate-skip-permissions option
- TaskTitleBar, TaskAITerminal, TerminalView, SidebarFooter, StatusDot: coordinator-aware rendering
- CloseTaskDialog: warns when closing coordinator with active children
- terminalDisableStdin: utility for blocking input on coordinator-controlled terminals
Autofire notification:
- autofire-tick.ts: fires staged notification after configurable delay
- 2-minute grace period for coordinator mode without ❯ prompt marker, so
notifications fire even during long tool-call loops (no prompt visible)
- prompt-control.ts: coordinator-aware send gate
Bug fixes (found during live e2e testing):
- show_notification IPC: changed ipcMain.on → ipcMain.handle to satisfy ipcRenderer.invoke
- merge_task git lock: retry once after 2 s when index.lock is held by a crashed process
- getBranchCommits: guard against missing worktree (existsSync before git spawn)
- getWorktreeStatus: wrap exec in try/catch to handle ENOENT race after worktree deletion
- wait_for_signal_done timeout: resolve with { timedOut: true } instead of reject,
so coordinator Claude receives a structured result rather than isError: true
Test fixes:
- register-mcp.test.ts: eliminate TOCTOU port race by passing port: 0 directly
- coordinator.test.ts: update 5 timeout assertions from rejects.toThrow to timedOut===true
- docker.integration.test.ts: replace 'coord-1' fixture with valid UUID constant
- MCPStatus type mismatch, PTY preservation, multi-agent rendering regressions
CI / tooling:
- Pin GitHub Actions to exact SHAs (supply chain hardening)
- Husky pre-push: runs full test suite before push
- Husky commit-msg: enforces conventional commit format
- pre-commit: lockfile integrity check (fails if package.json changes without package-lock.json)
Tests: 284 new cases in PromptInput.test.ts covering autofire tick, staged notification
rendering, coordinator control state, send gate, and 2-min grace period behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for the coordinator UI work. I did another pass with multiple reviewers focused on autofire/control flow, backend lifecycle sync, and UI entry points. A few blockers stood out:
Smaller follow-ups: I would add regression coverage around the |
Overview
This is PR 4 of 4 in the coordinator series splitting #100 as requested in the round-4 review. It is stacked on PR 3 (#124) (
coordinator-3-store-ipc) and must be merged after that one. The diff shown here includes PRs 1–3's content; the meaningful delta for this PR is the UI components and entry points described below.PR sequence:
coordinator-1-securitycoordinator-2-mcp-backendcoordinator-3-store-ipccoordinator-4-uiThis PR makes coordinator mode user-visible for the first time. After it merges, users can enable coordinator mode in Settings and create coordinator tasks from
NewTaskDialog.What's in this PR (delta over PR 3)
New component:
SubTaskStripNested status strip rendered inside a coordinator task's panel. Shows each sub-task's name, status dot, branch, and action buttons (send prompt, merge, close). Collapses to a compact summary when the coordinator panel is not focused.
Sidebar— coordinator groupingCoordinator tasks render with their children nested beneath them in the sidebar. Children are hidden from the flat task list (already excluded by PR 3's
isCoordinatedChildguard). A control banner appears below the coordinator's terminal whencontrolledBy === 'coordinator'to show the user they can take control.TaskPanel— coordinator detail viewFull coordinator task panel with sub-task list, per-sub-task diff summary, merge/close actions, and MCP startup status display (
pending/ready/errorwith retry button).PromptInput— staged notification and autofireautofire-tick.ts: fires the staged notification after the configured delay; 2-minute grace period for coordinator mode when no❯prompt marker is visible, so notifications fire even during long tool-call loopsprompt-control.ts: coordinator-aware send gate — blocks input whencontrolledBy === 'coordinator'SettingsDialog— coordinator settingsNew "Coordinator Mode" section with:
coordinatorModeEnabled)NewTaskDialog— coordinator entry pointNew "Coordinator mode" checkbox in the advanced section. When checked, exposes a "Propagate skip permissions" option. Creates the task with
coordinatorMode: true.Other component updates
TaskTitleBar: shows coordinator badge; sub-tasks show "controlled by coordinator" indicatorTaskAITerminal: rendersSubTaskStripfor coordinator tasksTerminalView: disables stdin whencontrolledBy === 'coordinator'; re-enables on hand-offSidebarFooter: shows MCP server status indicatorStatusDot: renders'review'state (orange dot) for tasks withneedsReviewCloseTaskDialog: shows warning when closing a coordinator with active childrenPlanViewerDialog: minor coordinator-aware rendering fixBug fixes (live e2e testing)
show_notificationIPC:ipcMain.on→ipcMain.handleto satisfyipcRenderer.invokemerge_taskgit lock: retry once after 2 s whenindex.lockis held by a crashed processgetBranchCommits: guard against missing worktree (existsSyncbefore git spawn)getWorktreeStatus: wrapexecin try/catch to handle ENOENT race after worktree deletionwait_for_signal_donetimeout: resolve with{ timedOut: true }instead of reject, so coordinator Claude receives a structured result rather thanisError: trueCI / tooling
pre-push: runs full test suite before pushcommit-msg: enforces conventional commit formatpre-commit: lockfile integrity check (fails ifpackage.jsonchanges withoutpackage-lock.json)Tests
src/components/PromptInput.test.tssrc/components/prompt-control.test.tssrc/lib/terminalDisableStdin.test.tselectron/ipc/register-mcp.test.tsfindFreePort()calls replaced withport: 0electron/mcp/coordinator.test.tsrejects.toThrowtotimedOut === trueAssumptions and important notes
coordinatorModeEnabledcan be set totruevia the Settings toggle. First coordinator task can be created fromNewTaskDialog.❯visible) need a time-based fallback to fire staged notifications; without it, the notification would never send until the agent returned to prompt.🤖 Generated with Claude Code