Commit Graph

746 Commits

Author SHA1 Message Date
Lukas May
16565ce42d feat: switch ReviewTab phase diff from rawDiff to metadata file list
- Split FileDiff into FileDiff (metadata-only) and FileDiffDetail (with hunks)
  so the phase branch diff no longer requires client-side diff parsing
- ReviewTab now reads diffQuery.data.files (FileStatEntry[]) and maps
  path → newPath for sidebar and DiffViewer; no parseUnifiedDiff call
  in the phase branch view path
- Commit view still parses rawDiff via parseUnifiedDiff → FileDiffDetail[]
- Pass phaseId, commitMode, comments, expandAll to DiffViewer
- Pass totalAdditions/totalDeletions from server to ReviewHeader stats bar
- Wire Expand all button in ReviewHeader to expandAll toggle state
- Update FileCard to use FileDiffDetail and status (replaces changeType)
- Update ReviewSidebar to use file.status instead of file.changeType

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 20:06:49 +01:00
Lukas May
cb4519439d feat: add CompactionEventsDialog and SubagentSpawnsDialog with tests
Implements two Radar drilldown dialog components following the
AddAccountDialog pattern (Radix UI Dialog + tRPC lazy query + skeleton
loading). CompactionEventsDialog shows a simple table of compaction
events; SubagentSpawnsDialog adds expandable rows that reveal the full
Agent tool prompt. Shared DrilldownDialogProps type in types.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 20:06:32 +01:00
Lukas May
a50ee01626 test: Add DiffCache unit tests and getPhaseReviewDiff cache integration tests
Creates diff-cache.ts module with generic DiffCache<T> class (TTL, prefix
invalidation, env-var configuration) and exports phaseMetaCache / fileDiffCache
singletons. Wires cache into getPhaseReviewDiff via getHeadCommitHash on
BranchManager. Adds 6 unit tests for DiffCache and 5 integration tests
verifying cache hit/miss behaviour, prefix invalidation, and NOT_FOUND guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 20:06:28 +01:00
Lukas May
5968a6ba88 feat: split FileDiff into metadata FileDiff + hunk-bearing FileDiffDetail
Prepares the review components for the backend phase that returns
metadata-only file lists from getPhaseReviewDiff. FileDiff now holds
only path/status/additions/deletions; FileDiffDetail extends it with
hunks. Renames changeType→status and adds 'binary' to the union.

Also fixes two pre-existing TypeScript errors: InitiativeReview was
passing an unknown `comments` prop to DiffViewer (should be
commentsByLine), and ConflictResolutionPanel destructured an unused
`agent` variable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:52:18 +01:00
Lukas May
9bdf89fc20 chore: update TypeScript build info after react-window addition 2026-03-06 19:51:46 +01:00
Lukas May
0996073deb feat: add in-memory diff cache with TTL and commit-hash invalidation
Adds DiffCache<T> module, extends BranchManager with getHeadCommitHash,
and wires phase-level caching into getPhaseReviewDiff and getFileDiff.
Cache is invalidated in ExecutionOrchestrator after each task merges into
the phase branch, ensuring stale diffs are never served after new commits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:51:04 +01:00
Lukas May
0323b42667 feat: virtualize ReviewSidebar file list for >50 items with scroll preservation
Adds windowed rendering to FilesView in ReviewSidebar.tsx using
react-window 2.x (List component). File lists with more than 50 rows
render only visible items, keeping the DOM lean for large diffs.

- Install react-window 2.x and @types/react-window in apps/web
- Flatten directory-grouped file tree into a typed Row[] array via useMemo
- Use VariableSizeList-equivalent react-window 2.x List with rowHeight fn
  (32px for dir-headers, 40px for file rows); falls back to plain DOM
  render for ≤50 rows to avoid overhead on small diffs
- Directories are collapsible: clicking the dir-header toggles collapse,
  removing its file rows from the Row[] and from the virtual list
- Preserve sidebar scroll offset across Files ↔ Commits tab switches via
  filesScrollOffsetRef passed from ReviewSidebar into FilesView
- Clicking a file calls listRef.scrollToRow({ index, align: "smart" })
  to keep the clicked row visible in the virtual list
- Root-level files (directory === "") render without a dir-header,
  preserving existing behavior
- Add resolve.dedupe for react/react-dom in vitest.config.ts to prevent
  duplicate-React errors after local workspace package installation
- Add 6 Vitest + RTL tests covering: large-list DOM count, small-list
  fallback, collapse, re-expand, tab-switch smoke, root-level files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:50:53 +01:00
Lukas May
2c00ad902d Merge branch 'cw/review-tab-performance-phase-frontend-move-syntax-highlighting-off-main-thread' into cw-merge-1772822818316 2026-03-06 19:46:58 +01:00
Lukas May
eb09f1a5fe test: add missing fallback test scenarios for useHighlightedFile
Add single-chunk equivalence test (≤200 lines produces complete token
map with no missing line entries) and AbortController abort spy test
(unmount during chunked fallback triggers abort signal) to cover the
remaining spec scenarios not included by the implementation branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:46:31 +01:00
Lukas May
90978d631a Merge branch 'cw/review-tab-performance-phase-backend-split-full-diff-into-metadata-per-file-procedures' into cw-merge-1772822786257 2026-03-06 19:46:26 +01:00
Lukas May
647f45c3bd Merge branch 'cw/review-tab-performance-task-7G4gkfUa2t87cIN6-rGVv' into cw-merge-1772822785439 2026-03-06 19:46:25 +01:00
Lukas May
4890721a92 feat: split getPhaseReviewDiff into metadata + add getFileDiff procedure
Rewrites getPhaseReviewDiff to return file-level metadata (path, status,
additions, deletions) instead of a raw diff string, eliminating 10MB+
payloads for large repos. Adds getFileDiff for on-demand per-file hunk
content with binary detection via numstat. Multi-project initiatives
prefix file paths with the project name to avoid collisions.

Adds integration tests that use real local git repos + in-memory SQLite
to verify both procedures end-to-end (binary files, deleted files,
spaces in paths, error cases).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:45:57 +01:00
Lukas May
c22a550bfc docs: document Web Worker syntax highlighting architecture in frontend.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:40:26 +01:00
Lukas May
0608900a53 feat: move syntax highlighting off main thread via Web Worker pool
Adds a 2-worker pool in use-syntax-highlight.ts so shiki tokenisation
runs off the main thread. Callers continue to receive null while the
worker is in flight and a LineTokenMap once it resolves — no caller
changes needed.

Fallback: if Worker construction is blocked (e.g. CSP), the hook falls
back to the existing createHighlighter singleton but processes 200 lines
at a time, yielding between chunks via scheduler.yield()/setTimeout(0)
to avoid long tasks.

Also adds worker.format:'es' to vite.config.ts (required when the app
uses code-splitting) and covers all paths with Vitest tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:39:31 +01:00
Lukas May
05eb160749 feat: add diffBranchesStat and diffFileSingle to BranchManager
Adds FileStatEntry type and two new primitives to the BranchManager
port and SimpleGitBranchManager adapter, enabling split diff
procedures in the tRPC layer without returning raw multi-megabyte diffs.

- FileStatEntry captures path, status, additions/deletions, oldPath
  (renames), and optional projectId for multi-project routing
- diffBranchesStat uses --name-status + --numstat, detects binary
  files (shown as - / - in numstat), handles spaces in filenames
- diffFileSingle returns raw unified diff for a single file path
2026-03-06 19:36:36 +01:00
Lukas May
9894cdd06f feat: add diffBranchesStat and diffFileSingle to BranchManager
Adds FileStatEntry type and two new primitives to the BranchManager
port and SimpleGitBranchManager adapter, enabling split diff
procedures in the tRPC layer without returning raw multi-megabyte diffs.

- FileStatEntry captures path, status, additions/deletions, oldPath
  (renames), and optional projectId for multi-project routing
- diffBranchesStat uses --name-status + --numstat, detects binary
  files (shown as - / - in numstat), handles spaces in filenames
- diffFileSingle returns raw unified diff for a single file path
2026-03-06 19:33:47 +01:00
Lukas May
ec86b62d8d perf: Pre-index review comments into Map to eliminate O(n) filtering
Build a Map<string, ReviewComment[]> once in ReviewTab and thread it
down through DiffViewer → FileCard → HunkRows, replacing O(n) filter
calls with O(1) map lookups. With 200 comments and 5000 diff lines,
this reduces ~1M iterations per render cycle to ~5K.

Key: "${filePath}:${lineNumber}:${lineType}" for line-level comments,
"${filePath}:file" for file-level (lineNumber === null) comments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:31:57 +01:00
Lukas May
2b7660f019 ci: Switch to OIDC trusted publishing for npm (no token needed) 2026-03-06 17:04:20 +01:00
Lukas May
c0096503b2 fix: Re-record cassettes and exclude workdir from test discovery
Re-recorded all 4 cassette files to reflect current prompt templates.
Added `workdir/**` to vitest exclude list to prevent test discovery
in agent worktree directories.
2026-03-06 17:00:46 +01:00
Lukas May
a30f98d532 ci: Alias NODE_AUTH_TOKEN to NPM_TOKEN for semantic-release verification 2026-03-06 16:53:14 +01:00
Lukas May
28521e1c20 chore: merge main into cw/small-change-flow
Integrates main branch changes (headquarters dashboard, task retry count,
agent prompt persistence, remote sync improvements) with the initiative's
errand agent feature. Both features coexist in the merged result.

Key resolutions:
- Schema: take main's errands table (nullable projectId, no conflictFiles,
  with errandsRelations); migrate to 0035_faulty_human_fly
- Router: keep both errandProcedures and headquartersProcedures
- Errand prompt: take main's simpler version (no question-asking flow)
- Manager: take main's status check (running|idle only, no waiting_for_input)
- Tests: update to match removed conflictFiles field and undefined vs null
2026-03-06 16:48:12 +01:00
Lukas May
91efbabee6 ci: Use NODE_AUTH_TOKEN and bump semantic-release to latest versions 2026-03-06 16:45:49 +01:00
Lukas May
5598e1c10f feat: implement Radar backend tRPC procedures with repository extensions
Add five new tRPC query procedures powering the Radar page's per-agent
behavioral metrics (questions asked, subagent spawns, compaction events,
inter-agent messages) plus the batch repository methods they require.

Repository changes:
- LogChunkRepository: add findByAgentIds() for batch fetching without N+1
- ConversationRepository: add countByFromAgentIds() and findByFromAgentId()
- Drizzle adapters: implement all three new methods using inArray()
- InMemoryConversationRepository (integration test): implement new methods

tRPC procedures added:
- agent.listForRadar: filtered agent list with per-agent metrics computed
  from log chunks (questionsCount, subagentsCount, compactionsCount) and
  conversation counts (messagesCount); supports timeRange/status/mode/initiative filters
- agent.getCompactionEvents: compact system init chunks for one agent (cap 200)
- agent.getSubagentSpawns: Agent tool_use entries with prompt preview (cap 200)
- agent.getQuestionsAsked: AskUserQuestion tool calls with questions array (cap 200)
- conversation.getByFromAgent: conversations by fromAgentId with toAgentName resolved

All 13 new unit tests pass; existing test suite unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:40:18 +01:00
Lukas May
1e16ad82e8 fix: Show conflict resolution agents in HQ dashboard
getHeadquartersDashboard had no section for active conflict agents,
so initiatives with a running conflict-* agent disappeared from all
HQ sections. Add resolvingConflicts array to surface them.
2026-03-06 16:39:48 +01:00
Lukas May
02ca1d568e fix: Disable EventEmitter maxListeners warning for SSE subscriptions
Each SSE client registers a listener per event type (30+ types), so a
few concurrent connections easily exceed the previous limit of 100.
Listeners are properly cleaned up on disconnect via eventBusIterable's
finally block, so this is not a real leak.
2026-03-06 16:39:36 +01:00
Lukas May
85f5f77927 ci: Switch from GitLab Package Registry to npmjs for publishing 2026-03-06 16:39:18 +01:00
Lukas May
cb95ac1c6e fix: Logo link navigates to HQ instead of Initiatives 2026-03-06 16:33:10 +01:00
Lukas May
da3218b530 Merge branch 'cw/small-change-flow-phase-cli-errand-commands' into cw-merge-1772810965256 2026-03-06 16:29:25 +01:00
Lukas May
0ec1022aba Merge branch 'cw/small-change-flow-task-3yaqNLqG3kk5ku6rH0exF' into cw-merge-1772810964768 2026-03-06 16:29:25 +01:00
Lukas May
6b922b633e ci: Add GitLab CI with semantic-release to @carealytix package registry
- .gitlab-ci.yml: single release stage, builds and runs semantic-release on main
- .releaserc: commit-analyzer, release-notes, npm publish, gitlab release, git tag
- package.json: rename to @carealytix/codewalkers, add repository, release script, semantic-release devDeps
- README.md: add GitLab Package Registry install instructions with .npmrc config
2026-03-06 16:29:20 +01:00
Lukas May
813979388b feat: wire conflictFiles through errand.get and add repository tests
- `errand.get` now returns `conflictFiles: string[]` (always an array,
  never null) with defensive JSON.parse error handling
- `errand.get` returns `projectPath: string | null` computed from
  workspaceRoot + getProjectCloneDir so cw errand resolve can locate
  the worktree without a second tRPC call
- Add `apps/server/db/repositories/drizzle/errand.test.ts` covering
  conflictFiles store/retrieve, null for non-conflict errands, and
  findAll including conflictFiles
- Update `errand.test.ts` mock to include getProjectCloneDir and fix
  conflictFiles expectation from null to []

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:28:56 +01:00
Lukas May
711dd99c8b Merge branch 'cw/small-change-flow-task-xkTnL_zsa-dgZP4H4txnl' into cw-merge-1772810891213 2026-03-06 16:28:11 +01:00
Lukas May
14041d007f feat: add Errands nav item, /errands route, and CreateErrandDialog
- AppLayout: add Errands nav entry with pending_review badge count
- /errands route: list table with ID, description, branch, status, agent, created columns; empty state with CLI hint; slide-over integration
- CreateErrandDialog: description (max 200 chars with counter), project select, optional base branch; no optimistic UI due to agent spawn latency
- ErrandDetailPanel: checkout from completed dependency commit (4j3ZfR_ZX_4rw7j9uj6DV)

TypeScript compiles clean. Route uses TanStack Router file-based routing; routeTree.gen.ts auto-regenerated on build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:27:44 +01:00
Lukas May
e86a743c0b feat: Add all 9 cw errand CLI subcommands with tests
Wires errand command group into CLI with start, list, chat, diff,
complete, merge, resolve, abandon, and delete subcommands. All
commands call tRPC procedures via createDefaultTrpcClient(). The
start command validates description length client-side (≤200 chars)
before making any network calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:26:15 +01:00
Lukas May
2eccde0ee1 Merge branch 'cw/improved-agent-outputs' into cw-merge-1772810637670 2026-03-06 16:23:57 +01:00
Lukas May
09e4e3d4f0 feat: add ErrandDetailPanel slide-over component
Implements the errand detail panel with three context-aware views:
- Active: live agent output via AgentOutputViewer, chat input, Mark Done/Abandon
- Pending review/conflict: diff block, conflict notice with file list, Merge/Delete/Abandon
- Merged/abandoned: read-only diff, info line with relative date, Delete only

Follows TaskSlideOver.tsx patterns: Framer Motion slide-in, backdrop, Escape key close.
Shift+click skips window.confirm on all destructive actions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:23:49 +01:00
Lukas May
377e8de5e9 feat: Add errand tRPC router with all 9 procedures and comprehensive tests
Implements the errand workflow for small isolated changes that spawn a
dedicated agent in a git worktree:
- errand.create: branch + worktree + DB record + agent spawn
- errand.list / errand.get / errand.diff: read procedures
- errand.complete: transitions active→pending_review, stops agent
- errand.merge: merges branch, handles conflicts with conflictFiles
- errand.delete / errand.abandon: cleanup worktree, branch, agent
- errand.sendMessage: delivers user message directly to running agent

Supporting changes:
- Add 'errand' to AgentMode union and agents.mode enum
- Add sendUserMessage() to AgentManager interface and MockAgentManager
- MockAgentManager now accepts optional agentRepository to persist agents
  to the DB (required for FK constraint satisfaction in tests)
- Add ORDER BY createdAt DESC, id DESC to errand findAll
- Fix dispatch/manager.test.ts missing sendUserMessage mock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:21:01 +01:00
Lukas May
e50eb17c3f Merge branch 'cw/headquarters' into cw-merge-1772810307192 2026-03-06 16:18:27 +01:00
Lukas May
e4b750ceb9 docs: Rewrite README as proper project documentation
Replace the original design document / brainstorm with a focused project
README covering what Codewalkers does, getting started, architecture,
supported providers, CLI reference, workflow, development, testing, and
links to detailed docs.
2026-03-06 16:09:56 +01:00
Lukas May
313cf82ea4 Merge branch 'cw/headquarters-task-i16XYnxexfeqf8VCUuTL3' into cw-merge-1772809739062 2026-03-06 16:08:59 +01:00
Lukas May
2ec4ddb2fd feat: Wire up hq.tsx with query, live updates, loading/error states, and section rendering
Replaces the placeholder body in apps/web/src/routes/hq.tsx with the
full Headquarters page. The component fetches from getHeadquartersDashboard,
subscribes to live SSE invalidations via useLiveUpdates, and renders the
four action sections or an empty state. Includes skeleton loading and
error-with-retry states. Also adds apps/web/src/components/ui/skeleton.tsx
(standard shadcn component not yet in the project).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:08:35 +01:00
Lukas May
f6938ae7e1 feat: Add live todo strip and Task result preview to AgentOutputViewer
- Derives currentTodos from the most recent TodoWrite tool_call on each render
- Renders a TASKS strip between the header and scroll area with status icons
  (CheckCircle2 for completed, Loader2/animate-spin for in_progress, Circle for pending)
- Caps the strip at 5 rows and shows "+ N more" for overflow
- Updates collapsed tool_result preview to show "{subagent_type} result" for
  Task tool results instead of the raw first-80-chars substring
- Adds 10 new tests covering all todo strip states and Task preview variants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:05:48 +01:00
Lukas May
32f58ddb43 Merge branch 'cw/improved-agent-outputs-phase-parser-enhancement-types-bug-fixes-tool-correlation' into cw-merge-1772809398045 2026-03-06 16:03:18 +01:00
Lukas May
ee6b0da976 feat: Add tool correlation, toolInput metadata, and unknown-type fallbacks to parser
- Extend ParsedMessage.meta with toolInput to expose raw tool arguments
- Add toolUseRegistry to correlate tool_result blocks back to originating tool_use
- Set toolInput on tool_call messages and populate meta.toolName/toolInput on tool_result
- Fix tool_result with is_error:true now correctly produces type "error"
- Add catch-all for unknown top-level event types (emits system message)
- Add catch-all for unknown assistant content block types (emits system message)
- Add unit tests covering all 8 scenarios including regression cases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:02:50 +01:00
Lukas May
752bb67e3a feat: collapse tool_result blocks by default; restyle system messages
tool_result messages now render as a single collapsible preview line
(ChevronRight + first 80 chars) and expand on click to show full content.
system messages drop the Badge/border-l and render as a dim mono inline
line. expandedResults state resets when agentId changes.

Adds full test coverage in AgentOutputViewer.test.tsx (9 tests).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:02:20 +01:00
Lukas May
30d5f68f91 feat: Add HQ section components for Headquarters page
Implements the five section components consumed by the HQ page:
- HQWaitingForInputSection, HQNeedsReviewSection, HQNeedsApprovalSection,
  HQBlockedSection, HQEmptyState with typed props from RouterOutputs.
- Shared types.ts defines the 5 item types from getHeadquartersDashboard.
- Adds RouterOutputs export to trpc.ts via inferRouterOutputs<AppRouter>.
- 22 unit tests verify rendering, navigation CTAs, truncation, and edge cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 15:53:15 +01:00
Lukas May
3a328d2b1c feat: Add errands schema, repository, and wire into tRPC context/container
Creates the errands table (with conflictFiles column), errand-repository
port interface, DrizzleErrandRepository adapter, and wires the repository
into TRPCContext, the DI container, _helpers.ts requireErrandRepository guard,
and the test harness. Also fixes pre-existing TS error in controller.test.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 15:49:26 +01:00
Lukas May
f244304c6f Merge branch 'cw/headquarters-phase-backend-hq-dashboard-trpc-procedure' into cw-merge-1772807905914 2026-03-06 15:38:26 +01:00
Lukas May
89c98d38cc feat: Add getHeadquartersDashboard tRPC procedure for HQ action items
Aggregates all user-blocking action items into a single composite query:
- waitingForInput: agents paused on questions (oldest first)
- pendingReviewInitiatives: initiatives awaiting content review
- pendingReviewPhases: phases awaiting diff review
- planningInitiatives: active initiatives with all phases pending and no running agents
- blockedPhases: phases in blocked state with optional last-message snippet

Wired into appRouter and covered by 10 unit tests using in-memory Drizzle DB
and an inline MockAgentManager (no real processes required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 15:35:54 +01:00
Lukas May
67658fb717 fix: require signal.json for all errand agent exit scenarios
Option A ("ask inline, session stays open") described a path where the
errand agent could ask questions without writing signal.json, which broke
the server's completion detection (checkAgentCompletionResult polls for
done|questions|error status). Remove the Option A/B distinction and make
signal.json with questions status the single mechanism for all user-input
requests, consistent with how other agents handle blocking questions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 15:35:11 +01:00