Commit Graph

50 Commits

Author SHA1 Message Date
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
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
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
30b27f8b4a fix: Conflict agent auto-dismiss fails on page load/remount
prevStateRef was initialized with current state, so when the page loaded
with an already-idle conflict agent, the transition guard was immediately
false and dismiss() never fired. Initialize with null instead.
2026-03-06 14:13:42 +01:00
Lukas May
a69527b7d6 fix: Remove upward box-shadow on ReviewHeader that covers tab bar
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.
2026-03-06 12:18:31 +01:00
Lukas May
9f5715558e fix: Auto-dismiss conflict panel and re-check mergeability on completion
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.
2026-03-06 12:14:16 +01:00
Lukas May
1e723611e7 feat: Allow editing review comments
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.
2026-03-06 11:58:08 +01:00
Lukas May
49970eb1d7 fix: Use overflow-clip instead of overflow-hidden on FileCard
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.
2026-03-06 11:44:45 +01:00
Lukas May
0c04a1d273 fix: Prevent conflict resolution agent from destroying initiative branch
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.
2026-03-06 11:40:22 +01:00
Lukas May
f428ec027e fix: Sticky file headers sit below review header using CSS variable
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.
2026-03-06 11:36:28 +01:00
Lukas May
c87aac44cc fix: Cover transparent gap above sticky header with upward box-shadow
Uses a 50px upward box-shadow in bg-background color to paint over the
main padding gap that shows above the stuck review header.
2026-03-06 11:33:31 +01:00
Lukas May
5b497b84a0 fix: Restore sticky header and sidebar by simplifying layout
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.
2026-03-06 11:26:43 +01:00
Lukas May
4664644cda fix: Use pseudo-element to cover all transparent space above sticky header
Replaces negative margin hack with a ::before that extends upward from
the sticky header to paint bg-background over the main padding gap.
2026-03-06 11:22:30 +01:00
Lukas May
19cd0a2cb0 fix: Cover transparent gap above sticky review header
Use negative margin to pull sticky header into the parent space-y-3 gap,
with matching padding and bg-background to paint over it when stuck.
2026-03-06 11:21:08 +01:00
Lukas May
01f2279735 fix: Eliminate whitespace above sticky review header
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.
2026-03-06 11:17:29 +01:00
Lukas May
6cf6bd076f feat: Add merge conflict detection and agent resolution in initiative review
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.
2026-03-06 11:17:25 +01:00
Lukas May
3a01b9e9ca fix: Restore sticky positioning on header wrapper div 2026-03-06 11:15:25 +01:00
Lukas May
09624e9cb7 fix: Sidebar accounts for sticky header height via ResizeObserver
Measures the review header dynamically and offsets the sidebar's sticky
top and max-height accordingly, eliminating the gap when scrolled.
2026-03-06 11:15:02 +01:00
Lukas May
d4b466ce6d fix: Make review sidebar sticky to viewport with internal scrolling
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.
2026-03-06 11:11:46 +01:00
Lukas May
50043f4c61 fix: Use instant scroll for discussion navigation 2026-03-06 11:10:50 +01:00
Lukas May
3fcfa61914 fix: Scroll to exact comment location when clicking sidebar discussions
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.
2026-03-06 11:09:07 +01:00
Lukas May
157fa445c5 fix: Show individual discussion threads in review sidebar with navigation
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.
2026-03-06 11:03:27 +01:00
Lukas May
1bc3f85d6a fix: Merge worktree conflict when target branch already checked out
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".
2026-03-06 10:54:42 +01:00
Lukas May
1e2819eeff fix: Request changes uses in-app confirmation, requires review comments
- Replace window.prompt with in-app dropdown confirmation (matches merge dialog pattern)
- Disable button when no unresolved comments exist (comments-only, no summary)
- Remove initiative-level request changes button (no comment system there)
2026-03-06 10:43:36 +01:00
Lukas May
7695604da2 feat: Add threaded review comments + agent comment responses
Introduces GitHub-style threaded comments via parentCommentId self-reference.
Users and agents can reply within comment threads, and review agents receive
comment IDs so they can post targeted responses via comment-responses.json.

- Migration 0032: parentCommentId column + index on review_comments
- Repository: createReply() copies parent context, default author 'you' → 'user'
- tRPC: replyToReviewComment procedure, requestPhaseChanges passes threaded comments
- Orchestrator: formats [comment:ID] tags with full reply threads in task description
- Agent IO: readCommentResponses() reads .cw/output/comment-responses.json
- OutputHandler: processes agent comment responses (creates replies, resolves threads)
- Execute prompt: conditional <review_comments> block when task has [comment:] markers
- Frontend: CommentThread renders root+replies with agent-specific styling + reply form
- Sidebar/ReviewTab: root-only comment counts, reply mutation plumbing through DiffViewer chain
2026-03-06 10:21:22 +01:00
Lukas May
65bcbf1a35 fix: Fix review task completion bug + add initiative-level Request Changes
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.
2026-03-06 09:41:28 +01:00
Lukas May
84250955d1 fix: Show completed phase diffs in review tab
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.
2026-03-05 22:05:28 +01:00
Lukas May
cdb3de353d fix: Use SSE events instead of polling for preview status updates
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.
2026-03-05 22:01:16 +01:00
Lukas May
df84a877f2 fix: Prioritize polled preview status over mutation pending state
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.
2026-03-05 21:58:02 +01:00
Lukas May
4958b6624d fix: Refetch previews on start and switch to path-based routing
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.
2026-03-05 21:56:05 +01:00
Lukas May
13e009a82d feat: Add preview controls to initiative-level review
Extract PreviewControls into shared component and wire up preview
start/stop to InitiativeReview header alongside Push Branch and
Merge & Push to Default buttons.
2026-03-05 21:47:06 +01:00
Lukas May
ff398f84ac fix: Move useMemo above early returns in ReviewTab to fix hooks ordering crash
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.
2026-03-05 21:35:10 +01:00
Lukas May
a3ee581629 fix: Merge confirmation dropdown hidden behind sticky file headers
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.
2026-03-05 20:59:30 +01:00
Lukas May
865e8bffa0 feat: Add initiative review gate before push
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
2026-03-05 17:02:17 +01:00
Lukas May
143aad58e8 feat: Replace per-preview Caddy sidecars with shared gateway architecture
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
2026-03-05 12:22:29 +01:00
Lukas May
7540562933 fix: Remove rounded corners from sidebar icon tab 2026-03-05 11:51:41 +01:00
Lukas May
e56bc1bc77 fix: Move review sidebar to left side for standard editor layout
Matches VS Code / GitHub convention where file explorer sits on the left
and the main content area (diff viewer) takes the remaining space on the right.
2026-03-05 11:49:13 +01:00
Lukas May
bbaee2acf5 fix: Sort root-level files to bottom of sidebar file tree
Matches editor convention where directory-grouped files appear first
and loose root-level files (e.g., globals.css, pnpm-lock.yaml) sort last.
2026-03-05 11:47:46 +01:00
Lukas May
79966cdf20 fix: Use primary indigo for Approve & Merge button instead of garish green 2026-03-05 11:37:57 +01:00
Lukas May
7e0749ef17 feat: Wire full request-changes flow for phase review
- 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
2026-03-05 11:35:34 +01:00
Lukas May
06b768e358 feat: Polish review tab — viewed tracking, file tree, syntax highlighting, better UX
- Add file "viewed" checkmarks with progress tracking (X/26 viewed in header + sidebar)
- Add directory-grouped file tree in sidebar with review progress bar
- Add sticky file headers that stay visible when scrolling through long diffs
- Add file change type badges (NEW/DELETED/RENAMED) with colored left borders
- Add syntax highlighting via shiki with lazy loading and progressive enhancement
- Add merge confirmation dropdown showing unresolved comments + viewed progress
- Make Approve & Merge button prominently green, Request Changes styled with error tokens
- Show full branch names instead of aggressively truncated text
- Add always-visible comment dots on lines with comments, subtle hover on others
- Improve hunk headers with two-tone @@ display and context function highlighting
- Add review progress bar to sidebar with file-level viewed state
2026-03-05 11:30:48 +01:00
Lukas May
173c7f7916 feat: Persist review comments to database
Review comments on phase diffs now survive page reloads and phase
switches. Adds review_comments table (migration 0028), repository
port/adapter (13th repo), tRPC procedures (listReviewComments,
createReviewComment, resolveReviewComment, unresolveReviewComment),
and replaces useState-based comments in ReviewTab with tRPC queries
and mutations.
2026-03-05 11:16:54 +01:00
Lukas May
69d2543995 fix: Scope loading spinner to diff pane only, keep sidebar always mounted 2026-03-05 11:12:51 +01:00
Lukas May
41cbc2c76c fix: Fix sidebar layout — sticky height constraint, padding on content only 2026-03-05 11:12:06 +01:00
Lukas May
a9832fc5ae feat: Replace horizontal commit nav with VSCode-style sidebar icon switcher
Move commit navigation from a horizontal strip into ReviewSidebar with a
vertical icon strip (Files/Commits views). Delete CommitNav.tsx.
2026-03-05 11:09:25 +01:00
Lukas May
cbb8e66943 fix: Show commit nav for single-commit phases, remove early-exit guard 2026-03-05 11:03:15 +01:00
Lukas May
c58e0ea77e feat: Redesign review tab with phase selection, commit navigation, and consolidated toolbar
- 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
2026-03-05 10:20:43 +01:00
Lukas May
04c212da92 feat: Implement v2 design system with indigo brand, dark mode, and status tokens
Complete frontend design overhaul replacing achromatic shadcn/ui defaults with
an indigo-branded (#6366F1), status-aware, dark-mode-enabled token system.

Phase 1 — Theme Foundation:
- Replace all CSS tokens in index.css with v2 light/dark mode values
- Add 24 status tokens (6 statuses × 4 variants), 22 terminal tokens,
  7 diff tokens, 5 shadow tokens, 9 transition/animation tokens,
  10 z-index tokens, 10-step extended indigo scale
- Install Geist Sans/Mono variable fonts (public/fonts/)
- Extend tailwind.config.ts with all new token utilities
- Add dark mode flash-prevention script in index.html
- Add status-pulse and shimmer keyframe animations
- Add global focus-visible styles and reduced-motion media query

Phase 2 — ThemeProvider + Toggle:
- ThemeProvider context with system preference listener
- 3-state ThemeToggle (Sun/Monitor/Moon)
- Radix tooltip primitive for tooltips
- localStorage persistence with 'cw-theme' key

Phase 3 — Shared Components + Token Migration:
- StatusDot: mapEntityStatus() maps raw statuses to 6 semantic variants
- StatusBadge: uses status token bg/fg/border classes
- Badge: 6 new status variants + xs size
- EmptyState, ErrorState, SaveIndicator shared patterns
- CommandPalette: Cmd+K search with fuzzy matching, keyboard nav
- Skeleton with shimmer animation + SkeletonCard composite layouts
- KeyboardShortcutHint, NavBadge, enhanced Sonner config
- Migrate ALL hardcoded Tailwind colors to token classes across
  AgentOutputViewer, review/*, ProgressBar, AccountCard,
  InitiativeHeader, DependencyIndicator, PipelineTaskCard,
  PreviewPanel, ChangeSetBanner, MessageCard, PhaseDetailPanel

Phase 4 — App Layout Overhaul:
- Single 48px row header with CW logo, nav with NavBadge counts,
  Cmd+K search button, ThemeToggle, HealthDot
- Remove max-w-7xl from header/main; pages control own widths
- ConnectionBanner for offline/reconnecting states
- BrowserTitleUpdater with running/questions counts
- useGlobalKeyboard (1-4 nav, Cmd+K), useConnectionStatus hooks
- Per-page width wrappers (initiatives max-w-6xl, settings max-w-4xl)

Phase 5 — Page-Level Token Migration:
- ReviewSidebar: all hardcoded green/orange/red → status/diff tokens
- CommentThread: resolved state → status-success tokens
- Settings health: green → status-success-dot
2026-03-03 11:43:09 +01:00
Lukas May
34578d39c6 refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt
standard monorepo conventions (apps/ for runnable apps, packages/
for reusable libraries). Update all config files, shared package
imports, test fixtures, and documentation to reflect new paths.

Key fixes:
- Update workspace config to ["apps/*", "packages/*"]
- Update tsconfig.json rootDir/include for apps/server/
- Add apps/web/** to vitest exclude list
- Update drizzle.config.ts schema path
- Fix ensure-schema.ts migration path detection (3 levels up in dev,
  2 levels up in dist)
- Fix tests/integration/cli-server.test.ts import paths
- Update packages/shared imports to apps/server/ paths
- Update all docs/ files with new paths
2026-03-03 11:22:53 +01:00