Commit Graph

773 Commits

Author SHA1 Message Date
Lukas May
3885a96c9d fix: strengthen signal.json prompt to prevent premature writes
Agents sometimes write signal.json before finishing output files,
causing work to be silently discarded. Replace weak "As your final
action" with explicit CRITICAL warning explaining the completion
trigger mechanism.
2026-03-07 00:51:25 +01:00
Lukas May
c3fb000f92 fix: prevent phase stuck in_progress when merge fails
In YOLO mode, if mergePhaseIntoInitiative() threw (e.g., branch
doesn't exist, merge conflict), the error propagated and completePhase()
was never called — leaving the phase permanently stuck at in_progress.

Also wrap per-phase recovery in try-catch so one failing phase doesn't
abort the entire recoverDispatchQueues() loop.
2026-03-07 00:44:46 +01:00
Lukas May
ed9184e0f1 Merge branch 'cw/improve-inbox-ui-on-hq' into cw-merge-1772839945283 2026-03-07 00:32:25 +01:00
Lukas May
b708977ef1 feat: add context panel, logs section, and task name fix to InboxDetailPanel
Enriches the HQ inbox detail view so users can answer agent questions
without navigating away from the inbox:

- Replace raw task UUID in header with human-readable task name
  (falls back to UUID, then em dash when both null)
- Add related context panel showing initiative link, task name,
  truncated/HTML-stripped description, and phase name; shows skeleton
  while loading, "No task context available" when agent has no task
- Add collapsible agent logs section using AgentOutputViewer;
  hidden when no output exists, resets on agent change
- Wire new props (taskName, phaseName, initiativeName, initiativeId,
  taskDescription, isLoadingContext) in hq.tsx from listWaitingAgents
- Add 11 tests covering all new behaviors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 00:31:32 +01:00
Lukas May
40ec85deb8 fix: resolve all failing frontend tests
- Fix vitest.config.ts React alias to point to local node_modules
  instead of nonexistent ancestor path (../../../../node_modules/react)
- Remove stale HQWaitingForInputSection tests (component was deleted
  in e8d332e0 but test cases were left behind)
2026-03-07 00:14:44 +01:00
Lukas May
40900a5641 fix: self-healing stale worktree recovery in SimpleGitWorktreeManager
When git worktree add fails with "branch already used by worktree at
<path>", parse the stale path, force-remove it, and retry once. Fixes
blocked task retries where the old agent-workdirs directory still exists
on disk and git worktree prune alone can't clear the reference.
2026-03-07 00:13:24 +01:00
Lukas May
c52fa86542 refactor: unify errand worktree paths to use agent-workdirs/<alias>/
Errands now create worktrees via ProcessManager.createWorktreesForProjects()
into agent-workdirs/<alias>/<project.name>/ instead of repos/<project>/.cw-worktrees/<errandId>.
This makes getAgentWorkdir + resolveAgentCwd work correctly for all agent types.

Key changes:
- Extract createWorktreesForProjects() from createProjectWorktrees() in ProcessManager
- Add resolveAgentCwd() to ProcessManager (probes for .cw/output in subdirs)
- Add projectId to SpawnAgentOptions for single-project agents (errands)
- Skip auto-cleanup for errand agents (worktrees persist for merge/abandon)
- Errand router uses agentManager.delete() for cleanup instead of SimpleGitWorktreeManager
- Remove cwd parameter from sendUserMessage (resolves via worktreeId)
- Add pruneProjectRepos() to CleanupManager for errand worktree refs
2026-03-07 00:02:27 +01:00
Lukas May
7e6921f01e feat: enrich listWaitingAgents with task/phase/initiative context via DB joins
Replaces the in-memory filter (agentManager.list() + filter) with a direct
repository query that LEFT JOINs tasks, phases, and initiatives to return
taskName, phaseName, initiativeName, and taskDescription alongside agent fields.

- Adds AgentWithContext interface and findWaitingWithContext() to AgentRepository port
- Implements findWaitingWithContext() in DrizzleAgentRepository using getTableColumns
- Wires agentRepository into TRPCContext, CreateContextOptions, and TrpcAdapterOptions
- Adds requireAgentRepository() helper following existing pattern
- Updates listWaitingAgents to use repository query instead of agentManager
- Adds 5 unit tests for findWaitingWithContext() covering all FK join edge cases
- Updates existing AgentRepository mocks to satisfy updated interface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 23:29:49 +01:00
Lukas May
b17c0a2b4f fix: resolve errand worktree path for sendMessage instead of using agent-workdirs
Errand agents are spawned in the errand's git worktree (managed by
SimpleGitWorktreeManager), not in agent-workdirs/<alias>/.
sendUserMessage was deriving the cwd from worktreeId which pointed to
the non-existent agent-workdirs path. Now the errand.sendMessage
procedure resolves the actual worktree path and passes it through.
2026-03-06 23:11:55 +01:00
Lukas May
bc61e658dc fix: allow re-detailing phases after all tasks are deleted
The "Detail Tasks" button was hidden when an idle detail agent from a
previous run was still associated with the phase. The frontend gate
blocked any re-detail while a detail agent existed, even if it was idle
(i.e. done). The backend already auto-dismisses stale idle agents, so
the frontend just needed to allow idle agents through the gate.
2026-03-06 22:43:56 +01:00
Lukas May
e7c95af1ca fix: skip standalone worktree when errand provides cwd
When spawn() receives an explicit cwd (errands), the manager was still
creating a standalone worktree at agent-workdirs/<alias>/ and injecting
its path into the workspace layout prompt. The agent then edited files
in the wrong directory — on a different branch than the errand's.

Now when cwd is provided, we skip worktree creation entirely and use
the caller's cwd for workspace layout, .cw/output/, and all paths.
2026-03-06 22:39:56 +01:00
Lukas May
79a0bd0a74 Merge branch 'cw/continuous-code-quality' into cw-merge-1772833031033 2026-03-06 22:37:11 +01:00
Lukas May
b21d32fd91 Merge branch 'main' into cw/continuous-code-quality-conflict-1772832123778
# Conflicts:
#	apps/server/drizzle/meta/0037_snapshot.json
#	apps/server/drizzle/meta/_journal.json
2026-03-06 22:30:21 +01:00
Lukas May
a61376812a fix: errand baseBranch defaults to project.defaultBranch instead of 'main' 2026-03-06 22:27:12 +01:00
Lukas May
3ceb991200 fix: errand output race condition + require commit before signal
Merge two useEffects in AgentOutputViewer into one to fix race where
agentId reset clears messages after data effect sets them on remount.

Add "commit before signaling" instruction to errand prompts so
Changes tab shows diff after completion.
2026-03-06 22:23:50 +01:00
Lukas May
e199188670 feat: cw task add CLI command + {AGENT_ID} prompt placeholder
- Add `createTaskForAgent` tRPC mutation: resolves agent → task → phase, creates sibling task
- Add `cw task add <name> --agent-id <id>` CLI command
- Replace `{AGENT_ID}` and `{AGENT_NAME}` placeholders in writeInputFiles() before flushing
- Update docs/agent.md and docs/cli-config.md
2026-03-06 22:22:49 +01:00
Lukas May
753b2e9fb8 fix: resolve integration issues after phase branch merges
- Register errandProcedures in appRouter (was defined but never spread)
- Fix nullable projectId guard in errand delete/abandon procedures
- Add sendUserMessage stub to MockAgentManager in headquarters and
  radar-procedures tests (AgentManager interface gained this method)
- Add missing qualityReview field to Initiative fixture in file-io test
  (schema gained this column from the quality-review phase)
- Cast conflictFiles access in CLI errand resolve command

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:16:53 +01:00
Lukas May
0211cdb8a6 Merge branch 'cw/continuous-code-quality-phase-quality-review-dispatch-hook' into cw-merge-1772831549281 2026-03-06 22:12:29 +01:00
Lukas May
425728205c chore: resolve merge conflicts — wire quality review into orchestrator handleAgentStopped
Resolved conflicts between cw/continuous-code-quality-phase-quality-review-dispatch-hook
and cw/continuous-code-quality-task-Cjc9jRT48MqxIZSQG3ypl.

- orchestrator.ts: adopted tryQualityReview() helper (incoming) over inline
  shouldRunQualityReview() call (HEAD); fixed duplicate agentManager constructor
  param; reordered optional params to agentRepository?, agentManager?
- orchestrator.test.ts: merged import blocks, used incoming mock defaults with
  .mockResolvedValue(), removed duplicate agentManager/agentRepository in
  createMocks(), used incoming createOrchestrator opts pattern; added missing
  project mock so HEAD's integration test works with tryQualityReview() flow
- docs/dispatch-events.md: kept HEAD's more explicit agent:stopped description
- container.ts: removed duplicate agentManager arg; reordered to match new
  constructor signature (agentRepository, agentManager)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:12:13 +01:00
Lukas May
30dcb8340a test: add error resilience case to orchestrator quality review hook tests
Adds the fourth test case from the spec: when shouldRunQualityReview
throws, the orchestrator must not crash, must log a warning (verified
implicitly by the catch block), and must still call scheduleDispatch()
so dispatch continuity is maintained.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:10:15 +01:00
Lukas May
6482960c6f feat: errand review & request changes
Add errand.requestChanges procedure that re-spawns an agent in the
existing worktree with user feedback. Replace raw <pre> diff blocks
with syntax-highlighted ErrandDiffView using FileCard components.
Add Output/Changes tabs to the active errand view.
2026-03-06 22:09:01 +01:00
Lukas May
953fe2e295 docs: update dispatch-events.md to reflect quality review on agent:stopped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:06:00 +01:00
Lukas May
4bc65bfe3d feat: wire quality review into orchestrator handleAgentStopped
When an agent stops, check whether a quality review should run before
auto-completing the task. If shouldRunQualityReview returns run:true,
delegate to runQualityReview (which transitions task to quality_review
and spawns a review agent) instead of calling completeTask directly.

Falls back to completeTask when agentRepository or agentManager are
not injected, or when the task lacks phaseId/initiativeId context.

- Add agentManager optional param to ExecutionOrchestrator constructor
- Extract tryQualityReview() private method to compute branch names and
  repo path before delegating to the quality-review service
- Pass agentManager to ExecutionOrchestrator in container.ts
- Add orchestrator integration tests for the agent:stopped quality hook

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:05:42 +01:00
Lukas May
b6a01e5748 Merge branch 'cw/continuous-code-quality-task-_Om84Be00WJgnctOvmkyo' into cw/continuous-code-quality-phase-quality-review-dispatch-hook
# Conflicts:
#	apps/server/execution/quality-review.test.ts
#	apps/server/execution/quality-review.ts
2026-03-06 22:04:50 +01:00
Lukas May
c3cace7604 feat: add quality-review dispatch hook to intercept agent:stopped events
When an execute-mode agent stops with task_complete and the initiative has
qualityReview=true, the orchestrator now spawns a fresh execute-mode agent
to run /simplify on changed .ts/.tsx/.js files before marking the task
completed. The task transitions through quality_review status as a recursion
guard so the review agent's stop event is handled normally.

- Add apps/server/execution/quality-review.ts with three exported functions:
  computeQualifyingFiles, shouldRunQualityReview, runQualityReview
- Add apps/server/execution/quality-review.test.ts (28 tests)
- Update ExecutionOrchestrator to accept agentManager, replace
  handleAgentStopped with quality-review-aware logic, add getRepoPathForTask
- Update orchestrator.test.ts with 3 quality-review integration tests
- Update container.ts to pass agentManager to ExecutionOrchestrator
- Update docs/dispatch-events.md to reflect new agent:stopped behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:01:02 +01:00
Lukas May
9200891a5d feat: add quality-review service with qualifying file detection and agent spawning
Adds apps/server/execution/quality-review.ts with three exported functions:
- computeQualifyingFiles: diffs task branch vs base, filters out *.gen.ts and dist/ paths
- shouldRunQualityReview: evaluates all six guard conditions (task_complete, execute mode,
  in_progress status, initiative membership, qualityReview flag, non-empty changeset)
  and returns { run, qualifyingFiles } to avoid recomputing the diff in the orchestrator
- runQualityReview: transitions task to quality_review, spawns execute-mode review agent
  on the task branch, logs the review agent ID, and falls back to completed on spawn failure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:56:18 +01:00
Lukas May
1416e6bf62 docs: update server-api.md to include qualityReview in updateInitiativeConfig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:54:17 +01:00
Lukas May
bb770407db feat: expose qualityReview via updateInitiativeConfig tRPC mutation
Adds qualityReview: z.boolean().optional() to the updateInitiativeConfig
input schema so the field passes through to the repository layer.
Includes integration tests verifying set-true, set-false, and
omit-preserves-existing round-trip behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:53:58 +01:00
Lukas May
5137a60e70 feat: add quality_review task status and qualityReview initiative flag
Adds two new fields to the database and propagates them through the
repository layer:

- Task status enum gains 'quality_review' (between in_progress and
  completed), enabling a QA gate before tasks are marked complete.
- initiatives.quality_review (INTEGER DEFAULT 0) lets an initiative be
  flagged for quality-review workflow without a data migration (existing
  rows default to false).

Includes:
- Schema changes in schema.ts
- Migration 0037 (ALTER TABLE initiatives ADD quality_review)
- Snapshot chain repaired: deleted stale 0036 snapshot, fixed 0035
  prevId to create a linear chain (0032 → 0034 → 0035), then generated
  clean 0037 snapshot
- Repository adapter already uses SELECT * / spread-update pattern so
  no adapter code changes were needed
- Initiative and task repository tests extended with qualityReview /
  quality_review_status describe blocks (7 new tests)
- docs/database.md updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:47:34 +01:00
Lukas May
dca4224d26 Merge branch 'cw/merge-hq-inbox' into cw-merge-1772829971134 2026-03-06 21:46:11 +01:00
Lukas May
a3a9076411 Merge branch 'cw/radar-screen-performance' into cw-merge-1772829950184 2026-03-06 21:45:50 +01:00
Lukas May
e8d332e04b feat: embed InboxList + InboxDetailPanel inline on HQ page
Replaces HQWaitingForInputSection with a two-column inline panel that
lets users answer agent questions directly from HQ without navigating
to /inbox. Adds SSE invalidation for listWaitingAgents/listMessages,
useState for agent selection, and all required mutations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:45:26 +01:00
Lukas May
9c468f17cb chore: update generated route tree 2026-03-06 21:44:55 +01:00
Lukas May
346d62ef8d fix: prevent stale duplicate planning tasks from blocking phase completion
Three fixes for phases getting stuck when a detail task crashes and is retried:

1. detailPhase mutation (architect.ts): clean up orphaned pending/in_progress
   detail tasks before creating new ones, preventing duplicates at the source
2. orchestrator recovery: detect and complete stale duplicate planning tasks
   (same category+phase, one completed, one pending)
3. ensureBranch: catch "already exists" TOCTOU race instead of blocking phase
2026-03-06 21:44:26 +01:00
Lukas May
ee8c7097db fix: use String() instead of .toISOString() for errand timestamps
tRPC without superjson serializes Date objects as plain strings/numbers
over the wire. The .toISOString() calls crashed because the values
aren't Date instances on the client. Matches the existing pattern used
elsewhere (e.g. agents page).
2026-03-06 21:42:26 +01:00
Lukas May
f497905043 Merge branch 'cw/merge-hq-inbox-phase-nav-badge-move-questions-count-to-hq-remove-inbox-item' into cw-merge-1772829625670 2026-03-06 21:40:25 +01:00
Lukas May
d97afa84d4 Merge branch 'cw/radar-screen-performance-phase-backfill-script-cw-backfill-metrics-cli-command-docs' into cw-merge-1772829393658 2026-03-06 21:36:33 +01:00
Lukas May
db2196f1d1 feat: add backfill-metrics script and cw backfill-metrics CLI command
Populates the agent_metrics table from existing agent_log_chunks data after
the schema migration. Reads chunks in batches of 500, accumulates per-agent
counts in memory, then upserts with additive ON CONFLICT DO UPDATE to match
the ongoing insertChunk write-path behavior.

- apps/server/scripts/backfill-metrics.ts: core backfillMetrics(db) + CLI wrapper backfillMetricsFromPath(dbPath)
- apps/server/scripts/backfill-metrics.test.ts: 8 tests covering all chunk types, malformed JSON, isolation, empty DB, and re-run double-count behavior
- apps/server/cli/index.ts: new top-level `cw backfill-metrics [--db <path>]` command
- docs/database-migrations.md: Post-migration backfill scripts section documenting when and how to run the script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:36:08 +01:00
Lukas May
1fd3a1ae4a fix: make errand.list input optional so frontend query works without args 2026-03-06 21:35:30 +01:00
Lukas May
4a9f38c4e1 perf: replace O(N·chunks) listForRadar read path with O(N·agents) metrics lookup
listForRadar previously called findByAgentIds() and JSON-parsed every chunk to
compute questionsCount, subagentsCount, and compactionsCount. Switch to
findMetricsByAgentIds() which reads the pre-computed agent_metrics table,
eliminating the chunk scan and per-row JSON.parse entirely.

Add two new test cases: agent with no metrics row returns zero counts, and
listForRadar response rows never carry chunk content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:35:29 +01:00
Lukas May
6eb1f8fc2a feat: add agent_metrics write+read path to LogChunkRepository
Wrap insertChunk in a synchronous better-sqlite3 transaction that upserts
agent_metrics counters atomically on every chunk insert. Malformed JSON
skips the upsert but always preserves the chunk row.

Add findMetricsByAgentIds to the interface and Drizzle adapter for
efficient bulk metric reads.

Add 8-test suite covering all write/read paths and edge cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:31:41 +01:00
Lukas May
0f53930610 feat: auto-create Integration phase for multi-leaf initiatives
When an initiative has multiple end phases (leaf nodes with no
dependents), queueAllPhases now auto-creates an Integration phase
that depends on all of them. This catches cross-phase incompatibilities
(type mismatches, conflicting exports, broken tests) before review.
2026-03-06 21:31:20 +01:00
Lukas May
419dda3a1a chore: update TypeScript build info after inbox route replacement 2026-03-06 21:31:10 +01:00
Lukas May
1ae7a64b4b refactor: replace InboxPage with redirect to /hq
Converts /inbox from a 270-line interactive page to a minimal
TanStack Router redirect route. Bookmarked or externally linked
/inbox URLs now redirect cleanly to /hq instead of 404-ing.

InboxList and InboxDetailPanel components are preserved for reuse
in the HQ page (Phase 569ZNKArI1OYRolaOZLhB).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:30:43 +01:00
Lukas May
cfbb9b2d1a feat: move waiting_for_input badge from Inbox to HQ nav, remove Inbox entry
Badge showing agents in waiting_for_input status now appears on HQ nav item.
Inbox link removed from the nav. Adds regression test for navItems structure.
2026-03-06 21:30:25 +01:00
Lukas May
276c342a50 feat: add agent_metrics table schema and Drizzle migration
Adds the agentMetrics table to SQLite schema for storing pre-computed
per-agent event counts (questions, subagents, compactions), enabling
listForRadar to fetch one row per agent instead of scanning log chunks.

Also fixes pre-existing Drizzle snapshot chain collision in meta/
(0035/0036 snapshots had wrong prevId due to parallel agent branches)
to unblock drizzle-kit generate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 21:25:38 +01:00
Lukas May
094b7e6307 fix: wire errand repository through tRPC adapter
ErrandRepository was instantiated in the container but never passed
from TrpcAdapterOptions into createContext(), causing all errand
procedures to throw "Errand repository not available" at runtime.
2026-03-06 21:24:19 +01:00
Lukas May
56efc0bad6 fix: detect hung agent processes via defensive signal.json polling
Claude CLI occasionally hangs after writing signal.json but never exits.
Add an optional signal check to pollForCompletion: after a 60s grace
period, check signal.json every 30s. If a valid completion signal is
found while the process is still alive, SIGTERM it and proceed to
normal completion handling.
2026-03-06 21:23:19 +01:00
Lukas May
388befd7c3 fix: register errand router in appRouter and fix build errors
errandProcedures was defined but never imported/spread into the app
router, causing "No procedure found on path errand.create". Also fixed
nullable projectId TS errors in delete/abandon and added missing
sendUserMessage to test mocks.
2026-03-06 21:17:44 +01:00
Lukas May
f5b1a3a5b9 feat: pre-populate retry dialog with crashed agent's original instruction
When a refine agent crashes, the Retry dialog now extracts the
user_instruction from the agent's stored prompt and pre-fills the
textarea, so users can re-run with the same instruction without
retyping it.
2026-03-06 21:13:03 +01:00