handleTaskCompleted and handlePhaseAllTasksDone both bailed early when
initiative had no branch, silently skipping phase status transitions.
Also, merge failures would skip the phase completion check entirely.
- Decouple phase completion check from branch existence
- Wrap merge in try/catch so phase check runs even if merge fails
- Route updateTaskStatus through dispatchManager.completeTask when
completing, so the task:completed event fires for orchestration
Discussions section was showing only aggregate counts (total/resolved/unresolved)
with no way to see or navigate to individual threads. Now lists each root comment
with file:line location, body preview, resolved status, and reply count. Clicking
a discussion scrolls to its file in the diff viewer.
Adds a new mutation that accepts an email + raw OAuth token and upserts
the account — creating it if it doesn't exist, updating credentials if
it does. Covers all four scenarios with unit tests (new, existing,
empty-email, empty-token validation).
Use a temp branch + update-ref to avoid "already checked out" error
when merging into the default branch. Also show actual branch name
in the Merge & Push button instead of "Default".
When re-dispatching tasks, the branch from a previous run may still
exist. Instead of failing with "a branch named X already exists",
reset the existing branch to the base and check it out.
Snapshots were stale since migration 0008. Generated a schema-derived
snapshot at 0032 so drizzle-kit generate works again (zero diff on
current schema.ts). Also fixed migration 0032 to use statement-breakpoint
separator required by better-sqlite3.
- Added 0032_snapshot.json derived from current schema.ts
- Fixed 0032 SQL to use --> statement-breakpoint between statements
- Updated CLAUDE.md and database-migrations.md with correct workflow
drizzle-kit generate has been broken since migration 0008 (stale snapshots).
The actual workflow is hand-written SQL + manual _journal.json registration.
Updated CLAUDE.md and database-migrations.md to reflect reality and prevent
future migrations from silently failing to apply.
The migration file existed but wasn't in _journal.json, so drizzle-kit's
migrator never applied it. Adds the journal entry for 0032_add_comment_threading.
Critical: review/merge tasks hit an early return in handleTaskCompleted()
that skipped the phase completion check, leaving phases stuck in
in_progress forever. Changed to an if-block wrapping only the merge step.
Also adds requestChangesOnInitiative() which creates/reuses a
"Finalization" phase for initiative-level review feedback, with dedup
guards for both phase and initiative request-changes flows.
Path-prefix routing (`localhost:9100/<id>/`) broke SPAs because absolute
asset paths (`/assets/index.js`) didn't match the `handle_path /<id>/*`
route. Subdomain routing (`<id>.localhost:9100/`) resolves this since
all paths are relative to the root. Chrome/Firefox resolve *.localhost
to 127.0.0.1 natively — no DNS setup needed.
The Caddyfile was using the host port (e.g., 9100) as the Caddy listen
address, but Docker maps host:9100 → container:80. Caddy inside the
container was listening on 9100 while Docker only forwarded to port 80,
causing all health checks to fail with "connection reset by peer".
Completed phases showed "No phases pending review" because:
1. Frontend filtered only pending_review phases
2. Server rejected non-pending_review phases
3. After merge, three-dot diff returned empty (merge base moved)
Fix: store pre-merge merge base hash on phase, use it to reconstruct
diffs for completed phases. Frontend now shows both pending_review and
completed phases with read-only mode (Merged badge) for completed ones.
httpBatchLink batches polling queries behind the long-running
startPreview mutation, so refetchInterval never fires independently.
Replace polling with preview: event invalidation via the existing
useLiveUpdates SSE subscription — preview:building/ready/stopped/failed
events now trigger listPreviews and getPreviewStatus invalidation.
The startPreview mutation blocks server-side through the entire Docker
build + health check + seed cycle. isPending was checked first, so even
after polling detected containers running, the UI stayed on "Building..."
until the full mutation resolved. Now polled status (running/failed)
takes priority, falling back to isPending only when no status exists.
Two fixes:
- Call previewsQuery.refetch() in startPreview.onSuccess so the UI
transitions from "building" to the preview link without a page refresh.
- Switch from subdomain routing (*.localhost) to path-based routing
(localhost:<port>/<id>/) since macOS doesn't resolve wildcard
localhost subdomains.
Docker compose requires project names to be lowercase alphanumeric
with hyphens/underscores only. The default nanoid alphabet includes
uppercase and special characters, causing build failures.
Extract PreviewControls into shared component and wire up preview
start/stop to InitiativeReview header alongside Push Branch and
Merge & Push to Default buttons.
Adds exitCode to AgentInfo type and propagates it through all toAgentInfo()
implementations. Enhances getAgent to also return taskName and initiativeName
from their respective repositories. Adds two new filesystem-reading tRPC
procedures for the Agent Details tab: getAgentInputFiles (reads .cw/input/
files with binary detection, 500 KB cap, sorted) and getAgentPrompt (reads
.cw/agent-logs/<name>/PROMPT.md with 1 MB cap and structured ENOENT handling).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Same orphaned-changeset pattern as deletePhase: manually deleting all
tasks from a detail changeset now marks it reverted. Also added
deleteTask to the invalidation map (was missing entirely).
The allFiles useMemo was declared after two early-return branches. Approving
the last phase empties pendingReviewPhases, triggering the early return and
causing React to see fewer hooks than the previous render.
Manually deleting phases left their parent changeset as "applied",
causing the Plan tab to show a stale "Created N phases" banner with
no phases visible.
- deletePhase now checks if all phases from a changeset are gone and
marks it reverted
- PlanSection filters out dismissed agents so dismissed banners stay
hidden
- revertChangeSet marks reverted before entity deletion to prevent
ghost state on partial failure
- deletePhase invalidation now includes listChangeSets
refetchInterval: 3000 on listPreviews and getPreviewStatus is now
redundant. Phase oMHtTekCDgdnBG0kkk25A wired useLiveUpdates in
$id.tsx to invalidate both queries on every preview:* SSE event,
so queries refetch exactly once per state change instead of on
a fixed 3-second timer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both phaseQueue and taskQueue are in-memory Maps lost on restart. Now
the orchestrator's start() method scans active initiatives and:
- Re-queues approved phases into the phase dispatch queue
- Re-queues pending tasks for in_progress phases into the task dispatch queue
- Triggers a dispatch cycle if anything was recovered
This fixes stuck phases/tasks after server restarts.
The in-memory phaseQueue (Map) in DefaultPhaseDispatchManager is lost on
server restart. After approving a phase review, dispatchNextPhase() found
nothing in the empty queue, so the next unblocked phase never started.
Now the orchestrator re-queues all approved phases for the initiative from
the DB before attempting to dispatch, making the queue self-healing.
Remove overflow-hidden from ReviewTab outer wrapper (was clipping the
absolutely-positioned dropdown), make ReviewHeader sticky with z-20 to
sit above file headers (z-10), and bump the dropdown to z-30.
Adds `cw account extract [--email <email>]` subcommand to the accountCommand
group. Reads directly from the local Claude config via extractCurrentClaudeAccount()
without requiring a server connection. Supports optional email verification,
outputting JSON with email, configJson (stringified), and credentials fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the addAccountByToken procedure to accountProcedures(), which
accepts an email and raw OAuth token, stores the token as claudeAiOauth
credentials, and upserts the account (create or updateAccountAuth based
on findByEmail). Covers the four scenarios with unit tests: new account,
existing account, empty email, and empty token validation errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Strip the unused .input(z.object({ lastEventId })) from all 6 subscription
procedures — the parameter was never consumed by eventBusIterable. Remove the
now-unused zod import. Add at-most-once delivery JSDoc to the EventBus interface
to make the real guarantee explicit. Add compliance comment above
onConversationUpdate noting what to wire when a conversation view is built.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task dispatch computed baseBranch as the phase branch name but never
ensured it existed in the git clone. When phases weren't dispatched
through the PhaseDispatchManager (which creates branches), the
git worktree add failed with "fatal: invalid reference".
Now DefaultDispatchManager calls ensureBranch for both the initiative
and phase branches before spawning, matching what PhaseDispatchManager
already does.
Blocked tasks (from spawn failures) were a dead-end with no way to
recover. Add retryBlockedTask to DispatchManager that resets status
to pending and re-queues, a tRPC mutation that also kicks dispatchNext,
and a Retry button in the task slide-over when status is blocked.
agent:output is high-frequency streaming data that was included in
ALL_EVENT_TYPES and AGENT_EVENT_TYPES, causing every onEvent/onAgentUpdate
SSE subscription to register a listener. With multiple subscriptions per
browser tab plus reconnections, this exceeded the 100 listener limit.
The dedicated onAgentOutput subscription handles output streaming already.
Bonus: stops useLiveUpdates from refetching listAgents on every output chunk.
Prevents two bugs in the resumeForCommit flow:
1. Agent navigated to main repo instead of worktree due to relative paths
in commit prompt — now uses absolute paths from getDirtyWorktreePaths
2. git add -A staged unrelated files (screenshots, other agents' work) —
now uses git add -u to only stage tracked modified files
Task-level approval (requiresApproval, mergeRequiresApproval,
pending_approval status) was redundant with executionMode
(yolo vs review_per_phase) and blocked the orchestrator's
phase completion flow. Tasks now complete directly;
phase-level review via executionMode is the right granularity.
Removed: schema columns (left in DB, removed from Drizzle),
TaskPendingApprovalEvent, approveTask/listPendingApprovals
procedures, findPendingApproval repository method, and all
frontend approval UI.
When all phases complete, the initiative now transitions to
pending_review status instead of silently stopping. The user
reviews the full initiative diff and chooses:
- Push Branch: push cw/<name> to remote for PR workflows
- Merge & Push: merge into default branch and push
Changes:
- Schema: Add pending_review to initiative status enum
- BranchManager: Add pushBranch port + SimpleGit adapter
- Events: initiative:pending_review, initiative:review_approved
- Orchestrator: checkInitiativeCompletion + approveInitiative
- tRPC: getInitiativeReviewDiff, getInitiativeReviewCommits,
getInitiativeCommitDiff, approveInitiativeReview
- Frontend: InitiativeReview component in ReviewTab
- Subscriptions: Add initiative events + missing preview/conversation
event types and subscription procedures
- Add getActiveRefineAgent to spawn mutation optimistic updates and
live event invalidation rules so the refine panel reflects agent
state immediately without manual refresh
- Accept optional instruction param in buildRefinePrompt() and inject
it as <user_instruction> block so the agent knows what to focus on
- Pass input.instruction through in architect router spawn call
Wrap agentManager.spawn() in try/catch — on failure, block the task
instead of crashing the entire dispatch cycle. Move phase status update
to after branch creation succeeds — on branch failure, block the phase
and skip task queuing. Fix statement-breakpoint markers in migration
0020 to use separate lines.
Replace browser online/offline event listeners with tRPC onEvent subscription
status, so the connection indicator reflects actual server reachability rather
than general network availability.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>