Add 'resolving_conflict' to InitiativeActivityState and detect active
conflict agents (name starts with conflict-) in deriveInitiativeActivity.
Conflict resolution takes priority over pending_review since the agent
is actively working.
- Add resolving_conflict to shared types and activity derivation
- Include conflict agents in listInitiatives agent filter (name + mode)
- Map resolving_conflict to urgent variant with pulse in InitiativeCard
- Add merge: prefix to INITIATIVE_LIST_RULES for merge event routing
- Add spawnConflictResolutionAgent to INVALIDATION_MAP
- Add getActiveConflictAgent to detail page agent: SSE invalidation
Implements a self-contained dialog that allows users to update credentials
for an existing account without deleting and re-adding it. Supports two
modes: token-based (Tab A) and credentials JSON (Tab B).
Also sets up web component test infrastructure: vitest now includes
apps/web/**/*.test.tsx files with happy-dom environment, @vitejs/plugin-react
for JSX, and @testing-library/{react,jest-dom,user-event} packages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 of 12 initiative activity state transitions were broken due to missing
event routing at three layers: SSE event arrays, live-update prefix rules,
and mutation invalidation map.
- Add initiative:changes_requested to ALL_EVENT_TYPES and TASK_EVENT_TYPES
- Add initiative:/agent: prefix rules to initiatives list and detail pages
- Add approveInitiativeReview, requestInitiativeChanges, requestPhaseChanges
to INVALIDATION_MAP; add listInitiatives to approvePhase
- Extract INITIATIVE_LIST_RULES constant for reuse
Implements three primitives needed before errand tRPC procedures can be wired up:
- agentManager.sendUserMessage(agentId, message): resumes an errand agent with a
raw user message, bypassing the conversations table and conversationResumeLocks.
Throws on missing agent, invalid status, or absent sessionId.
- writeErrandManifest(options): writes .cw/input/errand.md (YAML frontmatter),
.cw/input/manifest.json (errandId/agentId/agentName/mode, no files/contextFiles),
and .cw/expected-pwd.txt to an agent workdir.
- buildErrandPrompt(description): minimal prompt for errand agents; exported from
prompts/errand.ts and re-exported from prompts/index.ts.
Also fixes a pre-existing TypeScript error in lifecycle/controller.test.ts (missing
backoffMs property in RetryPolicy mock introduced by a concurrent agent commit).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds an Output/Details tab bar to the agents page right-panel. The Details
tab renders AgentDetailsPanel, which surfaces agent metadata (status, mode,
provider, initiative link, task name, exit code), input files with a
file-picker UI, and the effective prompt text — all streamed via the new
getAgent/getAgentInputFiles/getAgentPrompt tRPC procedures.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two-tab dialog (setup token + credentials JSON) with full validation,
error handling, provider select with fallback, and state reset on open.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- getAgentOutput now returns timestamped chunks ({ content, createdAt }[])
instead of a flat string, preserving DB chunk timestamps
- parseAgentOutput accepts TimestampedChunk[] and propagates timestamps
to each ParsedMessage
- AgentOutputViewer displays HH:MM:SS timestamps on text, tool_call,
system, and session_end messages
- Live subscription chunks get client-side Date.now() timestamps
- Fix horizontal scroll: overflow-x-hidden + break-words on content areas
- AgentLogsTab polls getTaskAgent every 5s until an agent is found,
then stops polling for live subscription to take over
- Fix slide-over layout: details tab scrolls independently, logs tab
fills remaining flex space for proper AgentOutputViewer sizing
Adds controller.test.ts with three test cases asserting that handleAccountExhaustion
correctly emits agent:account_switched with previousAccountId, newAccountId, and
reason fields — and that the emit is skipped when no new account is available or
the agent has no accountId.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The `getAgentPrompt` tRPC procedure previously read exclusively from
`.cw/agent-logs/<name>/PROMPT.md`. Once the cleanup-manager removes
that directory, the prompt is gone forever.
Adds a `prompt` text column to the `agents` table and writes the fully
assembled prompt (including workspace layout, inter-agent comms, and
preview sections) to the DB in the same `repository.update()` call
that saves pid/outputFilePath after spawn.
`getAgentPrompt` now reads from DB first (`agent.prompt`) and falls
back to the filesystem only for agents spawned before this change.
Addresses review comment [MMcmVlEK16bBfkJuXvG6h].
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Passes EventBus through LifecycleFactory and AgentLifecycleController so that
when an account is marked exhausted, an agent:account_switched event is emitted
with the previous and new account IDs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add getTaskAgent tRPC procedure to find the most recent agent for a task.
TaskSlideOver now has Details/Agent Logs tabs — logs tab renders
AgentOutputViewer when an agent exists, or an empty state otherwise.
git refuses to push to a branch that is currently checked out in a
non-bare repository. When the clone's origin is the user's local repo,
this blocks merge_and_push entirely.
On "branch is currently checked out" error, temporarily set
receive.denyCurrentBranch=updateInstead on the remote and retry.
This uses git's built-in mechanism to update the working tree safely
(rejects if dirty).
fastForwardBranch used git merge --ff-only which fails when the clone
has uncommitted files. This caused the ff to be silently skipped, the
merge to proceed on stale main, and the push to fail (non-fast-forward).
Switched to update-ref which only moves the branch pointer without
touching the working tree.
- Add `errands` table to schema with status enum and relations to agents/projects
- Add `errand` mode to agents.mode enum
- Add push rollback in orchestrator: if push fails after merge, reset to previousRef to preserve the review diff
- Extend MergeResult with previousRef for rollback support; update branch-manager and simple-git-branch-manager
- Add orchestrator tests for push rollback behaviour
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When merge_and_push failed at the push step, the local defaultBranch ref
was left pointing at the merge commit. This made the three-dot diff
(defaultBranch...initiativeBranch) return empty because main already
contained all changes — causing the review tab to show "no changes."
Now mergeBranch returns the previous ref, and approveInitiative restores
it on push failure. Also repaired the corrupted clone state.
Three bugs causing empty phase diffs when server restarts during agent
execution:
1. Startup ordering race: reconcileAfterRestart() emitted agent:stopped
before orchestrator registered listeners — events lost. Moved
reconciliation to after orchestrator.start().
2. Stuck in_progress tasks: recoverDispatchQueues() only re-queued
pending tasks. Added recovery for in_progress tasks whose agents
are dead (not running/waiting_for_input).
3. Branch force-reset destroys work: git branch -f wiped commits when
a second agent was dispatched for the same task. Now checks if the
branch has commits beyond baseBranch before resetting.
Also adds:
- agent:crashed handler with auto-retry (MAX_TASK_RETRIES=3)
- retryCount column on tasks table + migration
- retryCount reset on manual retryBlockedTask()
The sticky ReviewHeader had shadow-[0_-50px_0_0_hsl(var(--background))]
which painted a 50px background-color rectangle upward, overlapping the
tab navigation bar (only ~12px away). The header's bg-card is already
opaque, making the shadow unnecessary for scroll coverage.
Two additional fixes to prevent agents from writing .cw/output/ in the
wrong location:
1. Always create .cw/output/ at the agent workdir root during spawn,
even when no inputContext is provided. This gives the agent a visible
anchor directory so it doesn't create one inside a project subdir.
2. Add absolute output path instruction to the workspace layout prompt
for multi-project agents, explicitly telling them to write .cw/output/
relative to the workdir root, not their current cd location.
Instead of showing a manual "Re-check Mergeability" button after the
conflict agent finishes, auto-dismiss the agent and trigger mergeability
re-check immediately when the state transitions to completed.
Throws if branch and baseBranch are identical, preventing
git branch -f from force-resetting shared branches (like
the initiative branch) when accidentally passed as both.
Conflict-resolution agents (and any initiative-based agent) can write
.cw/output/signal.json inside a project subdirectory (e.g.
agent-workdirs/<name>/codewalk-district/.cw/output/) rather than the
parent agent workdir. This caused two failures:
1. spawnInternal wrote spawn-diagnostic.json before registering the
agent in activeAgents and starting pollForCompletion. If the .cw/
directory didn't exist (no inputContext provided), the write threw
ENOENT, orphaning the running process with no completion monitoring.
2. resolveAgentCwd in cleanup-manager and output-handler only probed
for a workspace/ subdirectory (standalone agents) but not project
subdirectories, so reconciliation and completion handling couldn't
find signal.json and marked the agent as crashed.
Fixes:
- Move activeAgents registration and pollForCompletion setup before
the diagnostic write; make the write non-fatal with mkdir -p
- Add project subdirectory probing to resolveAgentCwd in both
cleanup-manager.ts and output-handler.ts
approveInitiative was merging and pushing with a stale local
defaultBranch, causing "rejected (fetch first)" when origin/main
had advanced since the last project sync. Now fetches remote and
fast-forwards the target branch before merging.
Add update method to ReviewCommentRepository, updateReviewComment tRPC
procedure, and inline edit UI in CommentThread. Edit button appears on
user-authored comments (not agent comments) when unresolved. Uses the
existing CommentForm with a new initialValue prop.
overflow-hidden creates a scroll container that breaks sticky positioning
for file headers. overflow-clip provides the same visual clipping for
rounded corners without affecting the scroll/sticky context.
spawnConflictResolutionAgent was passing the initiative branch as branchName,
causing SimpleGitWorktreeManager.create() to force-reset it to the target
branch. Now spawns on a unique temp branch based off the initiative branch,
with the agent using git update-ref to advance the initiative branch after
resolving conflicts. Also fixes stale diff/commits cache after resolution.
Sets --review-header-h on the card wrapper from measured header height.
FileCard reads it for sticky top offset so file headers dock just below
the review header instead of overlapping it.
simple-git's .raw() resolves successfully even on exit code 1,
returning stdout content. git merge-tree --write-tree outputs
CONFLICT markers to stdout (not stderr), so the catch block
never fired and conflicts were reported as clean merges.
Removed wrapper divs that broke sticky positioning. ReviewHeader now
accepts a ref prop directly, with sticky top-0 on its own root element.
Card wrapper restored as the tall containing block so both header and
sidebar have room to stick within it.
merge_requires_approval (initiatives) and requires_approval (tasks)
were removed from schema.ts in the task-approval removal but left in
the DB because 0030 assumed SQLite couldn't DROP COLUMN. SQLite 3.35+
supports it. These orphaned columns caused the old stale-build approval
code path to silently set detail tasks to pending_approval, stranding
them and blocking phase completion.
Moved card border/rounding onto the sticky header wrapper itself so it
scrolls flush to top-0 with no gap. The body grid gets its own border-x
and border-b to preserve the card appearance. ResizeObserver now measures
border-box size for accurate sidebar offset.
Pre-merge mergeability check via `git merge-tree --write-tree` (dry-run, no
side effects). When conflicts exist the "Merge & Push" button is disabled and
a ConflictResolutionPanel shows conflict files with options to resolve manually
or spawn a conflict-resolution agent. Agent questions appear inline via
QuestionForm; on completion the mergeability re-checks automatically.
New server-side: MergeabilityResult type, BranchManager.checkMergeability,
conflict-resolution prompt, checkInitiativeMergeability query,
spawnConflictResolutionAgent mutation, getActiveConflictAgent query.
New frontend: useConflictAgent hook, ConflictResolutionPanel component,
mergeability badge + panel integration in InitiativeReview.
Removed overflow-hidden from grid container and changed sidebar to
sticky positioning with viewport-relative max-height. Sidebar content
scrolls independently while staying visible during diff navigation.
Adds data-comment-id attributes to comment thread rows so clicking a
discussion in the sidebar scrolls directly to the comment, not just the
file card. Includes a brief ring highlight on the target row.
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