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.
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.
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).
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
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.
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>
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.
Containerize Codewalkers with a multi-stage Docker build (Node + Caddy) and
add a seed script that populates the database with a demo initiative, 3 phases,
9 tasks, 3 agents with JSONL log output, a root page, review comments, and a
git repo with real branch diffs for the review tab.
Run project-specific initialization commands (DB migrations, fixture
loading, etc.) automatically after containers are healthy, before the
preview is marked ready. Configured via per-service `seed` arrays in
.cw-preview.yml.
Refactor preview deployments to use a single shared Caddy gateway container
with subdomain routing (<previewId>.localhost:<port>) instead of one Caddy
sidecar and one port per preview. Adds dev/preview modes, git worktree
support for branch checkouts, and auto-start on phase:pending_review.
- Add GatewayManager for shared Caddy lifecycle + Caddyfile generation
- Add git worktree helpers for preview mode branch checkouts
- Add dev mode: volume-mount + dev server image instead of build
- Remove per-preview Caddy sidecar and port publishing
- Use shared cw-preview-net Docker network with container name DNS
- Auto-start previews when phase enters pending_review
- Delete unused PreviewPanel.tsx
- Update all tests (40 pass), docs, events, CLI, tRPC, frontend
- Add PhaseChangesRequestedEvent to event bus
- Add requestChangesOnPhase() to ExecutionOrchestrator: reads unresolved
comments, creates revision task (category='review'), resets phase to
in_progress, queues task for dispatch
- Expand merge-skip and branch routing to include 'review' category so
revision tasks work directly on the phase branch
- Add requestPhaseChanges tRPC procedure (reads comments from DB)
- Wire frontend: mutation replaces stub handler, window.prompt for
optional summary, loading state on button
- Track worktree removal success in autoCleanupAfterCompletion() instead of
always returning removed:true when removeAgentWorktrees() throws
- Add removeAgentBranches() call to auto-cleanup path (agent/* branches were
never cleaned after completion)
- Add filesystem cleanup (worktrees, branches, logs) to dismiss() to prevent
resource leaks until next server restart
- Add BranchManager.listCommits() and diffCommit() for commit-level navigation
- Add getPhaseReviewCommits and getCommitDiff tRPC procedures
- New ReviewHeader: consolidated toolbar with phase selector pills, branch info,
stats, integrated preview controls, and approve/reject actions
- New CommitNav: horizontal commit strip with "All changes" + individual commits,
each showing hash, message, and change stats
- Slim down ReviewSidebar: file list only with dimming for out-of-scope files
when viewing a single commit
- ReviewTab orchestrates all pieces in a single bordered card layout
commitRetryCount was being deleted in cleanupAgentState(), which runs
before tryAutoCleanup() checks the count. This reset the counter to 0
on every cycle, making MAX_COMMIT_RETRIES=1 dead code. Agents would
retry commits forever.
Move commitRetryCount cleanup to stop()/delete() only, letting
tryAutoCleanup() manage it during the retry lifecycle.
The orchestrator's agent:stopped listener only called scheduleDispatch(),
never marking the agent's assigned task as completed. Tasks stayed
in_progress forever after their agent finished.
Now handleAgentStopped() calls dispatchManager.completeTask() before
scheduling new dispatches, respecting requiresApproval and skipping
manual (user_requested) stops.
ExecutionOrchestrator now listens for phase:queued and agent:stopped
events to drive the dispatch cycle, closing the gap between queueing
phases (Execute button) and actually spawning agents. Coalesced
scheduling prevents reentrancy with synchronous EventEmitter.
Replace readFileSync/writeFileSync/mkdirSync with async equivalents from
fs/promises in default-credential-manager.ts and usage.ts to stop blocking
the Node.js event loop during credential read/write operations.
readFrontmatterFile, readFrontmatterDir, readSummary, readPhaseFiles,
readTaskFiles, readDecisionFiles, and readPageFiles all used readFileSync
and readdirSync which block the Node.js event loop during agent completion
handling. Converted to async using readFile/readdir from fs/promises and
added await at all call sites in output-handler.ts.
Removes blocking readFileSync, writeFileSync, and mkdirSync calls from the
agent spawn hot path, replacing them with async fs/promises equivalents to
avoid stalling the Node.js event loop during credential operations.
writeInputFiles, spawnDetached, and diagnostic writes now use
fs/promises (mkdir, writeFile) instead of mkdirSync/writeFileSync.
File writes in writeInputFiles are batched with Promise.all.
openSync/closeSync for child process stdio FDs remain sync as
spawn() requires the FDs immediately.
sendChatMessage was awaiting the full agentManager.spawn() which
includes worktree creation, ~50 writeFileSync calls for input files,
credential setup, and process spawning. This blocked the Node.js event
loop long enough to cause ECONNREFUSED on the SSE connection.
Now the mutation returns immediately after storing the user message
and creating the task. The heavy spawn work runs in a detached promise.
On failure, a system message is stored so the UI can display the error.
Agents were bulk-reading all context task files (39 files) because
filenames are opaque IDs and there was no way to find phase-relevant
tasks without reading every file. Now writeInputFiles generates a
context/index.json with tasksByPhase mapping phaseId to task metadata
(file, id, name, status). Prompt updated to direct agents to read
the index first.
Agents were reading all contextFiles (38 tasks + 8 phases) upfront,
wasting massive context window. Updated INPUT_FILES and SESSION_STARTUP
prompts to clearly distinguish assignment files (read all) from context
files (read only when needed).
Add findByProjectId to InitiativeRepository using a subquery on the
initiative_projects junction table. Extend the listInitiatives tRPC
procedure to accept an optional projectId filter that composes with
the existing status filter. Add a project dropdown to the initiatives
page alongside the status filter.
Pass targetId to buildChatPrompt and add <scope> block that clearly
distinguishes primary target files from context files. Context entities
may be modified when necessary (e.g. dependency links) but the agent
is instructed to focus changes on the primary target.
Added retry:true flag to sendChatMessage input. Server skips storing
the user message when retry is set. Frontend uses a dedicated
retryLastMessage function that skips the optimistic message add.