Files
Codewalkers/docs/frontend.md

13 KiB

Frontend

apps/web/ — React web UI for managing initiatives, agents, and content.

Tech Stack

Technology Purpose
React 19 UI framework
TanStack Router File-based routing
tRPC React Query Type-safe API client with caching
Tailwind CSS Utility-first styling
shadcn/ui Component library (button, card, dialog, dropdown, input, label, textarea, badge, sonner, tooltip)
Tiptap Rich text editor (ProseMirror-based)
Lucide Icon library
Geist Sans/Mono Typography (variable fonts in public/fonts/)
react-window 2.x Virtualized list rendering for large file trees in ReviewSidebar

Design System (v2)

Theme spec: docs/wireframes/v2/theme.md

  • Brand: Indigo (#6366F1) — --primary is indigo, not black
  • Dark mode: 3-state toggle (light/system/dark), persisted in localStorage('cw-theme')
  • Status tokens: 6 semantic statuses (active/success/warning/error/neutral/urgent) with bg/fg/border/dot variants. Use bg-status-{status}-bg, text-status-{status}-fg, etc.
  • Terminal tokens: Always-dark surface for agent output. Use bg-terminal, text-terminal-fg, etc.
  • Diff tokens: bg-diff-add-bg, text-diff-remove-fg, etc.
  • Shadows: 5-level system (xs-xl). Dark mode uses inset highlights + ambient glow.
  • Transitions: duration-fast, duration-normal, ease-default, ease-spring
  • Z-index: Named scale from z-base to z-tooltip
  • Radius: 6px base (down from 8px)
  • Flash prevention: Inline <script> in index.html reads theme before paint

Status-to-Entity Mapping

Use mapEntityStatus(rawStatus) from StatusDot.tsx to convert raw entity statuses to semantic tokens. StatusDot and StatusBadge both use this automatically.

Path Alias

@/* maps to ./src/* (configured in tsconfig.app.json).

Routes

Route Component Purpose
/ routes/index.tsx Dashboard / initiative list
/hq routes/hq.tsx Headquarters — action items requiring user attention
/initiatives/$id routes/initiatives/$initiativeId.tsx Initiative detail (tabbed)
/agents routes/agents.tsx Agent list with Output / Details tab panel
/settings routes/settings/index.tsx Settings page

Initiative Detail Tabs

The initiative detail page has three tabs managed via local state (not URL params):

  1. Content Tab — Page tree + Tiptap editor, proposal review
  2. Execution Tab — Pipeline visualization, phase management, task dispatch
  3. Review Tab — Pending proposals from agents

Component Inventory (74 components)

Core Components (src/components/)

Component Purpose
InitiativeCard Initiative list card with activity indicator (dot + label + phase progress), overflow menu
InitiativeHeader Initiative name, project badges, inline-editable execution mode & branch
InitiativeContent Content tab with page tree + editor
StatusDot Small colored dot using status tokens, with pulse animation
StatusBadge Colored badge using status tokens
TaskRow Task list item with status, priority, category
QuestionForm Agent question form with options
AgentDetailsPanel Details tab for agent right-panel: metadata, input files, effective prompt
InboxDetailPanel Agent message detail + response form
ProjectPicker Checkbox list for project selection
RegisterProjectDialog Dialog to register new git project
Skeleton Loading placeholder with shimmer animation
SkeletonCard Composite skeleton layouts (agent-card, initiative-card, etc.)
EmptyState Shared empty state with icon, title, description, action
ErrorState Shared error state with retry
SaveIndicator Saving/saved/error status indicator
CommandPalette Cmd+K search palette (initiatives, agents, navigation)
ThemeToggle 3-state theme toggle (Sun/Monitor/Moon)
NavBadge Numeric badge for nav items
KeyboardShortcutHint Formatted keyboard shortcut display
ConnectionBanner Offline/reconnecting state banner
HealthDot Server health indicator with tooltip
BrowserTitleUpdater Dynamic document.title with agent counts

Editor Components (src/components/editor/)

Component Purpose
TiptapEditor Core rich text editor wrapper
PageEditor Page content editor with auto-save
PhaseContentEditor Phase content editor
ContentProposalReview Accept/dismiss proposals from agents
SlashCommandMenu Slash command popup in editor

Execution Components (src/components/execution/)

Component Purpose
ExecutionTab Main execution view container
ExecutionContext React context for execution state
PhaseDetailPanel Phase detail with tasks, dependencies, plan
PhaseSidebar Phase list sidebar
TaskDetailPanel Task detail with agent status, output

Pipeline Components (src/components/pipeline/)

Component Purpose
PipelineTab Execution tab entry — fetches tasks, phase deps, task deps
PipelineGraph Horizontal DAG of phase columns with connectors
PipelineStageColumn Single depth column containing phase groups
PipelinePhaseGroup Phase card with status border accent, progress bar, TaskGraph

Review Components (src/components/review/)

Component Purpose
ReviewTab Review tab container — orchestrates header, diff, sidebar, and preview. Phase-level review has threaded inline comments (with reply support) + Request Changes; initiative-level review has Request Changes (summary prompt) + Push Branch / Merge & Push. Phase diff uses metadata-only FileDiff[] from getPhaseReviewDiff; commit diff parses rawDiff via parseUnifiedDiffFileDiffDetail[]. Passes commitMode, phaseId, expandAll to DiffViewer
ReviewHeader Consolidated toolbar: phase selector pills, branch info, stats (uses totalAdditions/totalDeletions props when available, falls back to summing files), preview controls, Expand all button, approve/reject actions
ReviewSidebar VSCode-style icon strip (Files/Commits views) with file list, root-only comment counts, and commit navigation. FilesView uses react-window 2.x List for virtualized rendering when the row count exceeds 50 (dir-headers + file rows). Scroll position is preserved across Files ↔ Commits tab switches. Directories are collapsible. Clicking a file scrolls the virtual list to that row.
DiffViewer Unified diff renderer with threaded inline comments (root + reply threads). Accepts `FileDiff[]
CommentThread Renders root comment with resolve/reopen + nested reply threads (agent replies styled with primary border). Inline reply form
ConflictResolutionPanel Merge conflict detection + agent resolution in initiative review. Shows conflict files, spawns conflict agent, inline questions, re-check on completion
PreviewPanel Docker preview status: building/running/failed with start/stop (legacy, now integrated into ReviewHeader)
ProposalCard Individual proposal display

Syntax Highlighting (use-syntax-highlight.ts + highlight-worker.ts)

useHighlightedFile(filePath, allLines) returns LineTokenMap | null. Tokenisation runs off the main thread:

  • Worker path (default): a module-level pool of 2 ES module Web Workers (highlight-worker.ts) each import shiki's codeToTokens dynamically. Requests are round-robined by requestCount % 2. Responses are correlated by UUID. Late responses after unmount are silently discarded via the pending Map.
  • Fallback path (CSP / browser-compat): if Worker construction throws, createHighlighter is used on the main thread but processes 200 lines per chunk, yielding between chunks via scheduler.yield() or setTimeout(0).

Callers receive null while highlighting is in progress and a populated Map<lineNumber, ThemedToken[]> once it resolves. LineWithComments already renders plain text when null, so no caller changes are needed.

Vite must be configured with worker.format: 'es' (added to vite.config.ts) for the worker chunk to bundle correctly alongside code-split app chunks.

UI Primitives (src/components/ui/)

shadcn/ui components: badge (6 status variants + xs size), button, card, dialog, dropdown-menu, input, label, select, sonner, textarea, tooltip.

Custom Hooks (src/hooks/)

Hook Purpose
useRefineAgent Manages refine agent lifecycle for initiative
useConflictAgent Manages conflict resolution agent lifecycle for initiative review
useDetailAgent Manages detail agent for phase planning
useAgentOutput Subscribes to live agent output stream
useChatSession Manages chat session for phase/task refinement
useConnectionStatus Tracks online/offline/reconnecting state
useGlobalKeyboard Global keyboard shortcuts (1-4 nav, Cmd+K)

Theme (src/lib/theme.tsx)

ThemeProvider wraps the app root. useTheme() returns { theme, setTheme, isDark }. The provider listens for OS prefers-color-scheme changes when in system mode.

tRPC Client

Configured in src/lib/trpc.ts. Uses @trpc/react-query with TanStack Query for caching and optimistic updates.

Key User Flows

Creating an Initiative

  1. Dashboard → "New Initiative" → enter name, optional description, select projects
  2. createInitiative mutation → auto-creates root page (seeded with description as tiptap content); if description provided, auto-spawns refine agent
  3. Navigate to initiative detail page on success

Managing Content (Pages)

  1. Content tab → page tree sidebar
  2. Click page → Tiptap editor loads content
  3. Edit → auto-saves via updatePage mutation
  4. Use slash commands for formatting

Refining Content with AI

  1. Content tab → "Refine" button
  2. spawnArchitectRefine mutation → agent analyzes pages
  3. Agent creates proposals (page edits, new phases, tasks)
  4. Proposals appear in review section → accept/dismiss each

Pipeline Visualization

  1. Execution tab → pipeline DAG shows phases as nodes
  2. Drag to add dependencies between phases
  3. Per-phase Play button: if phase is pending (with non-detail tasks), approves then queues in one click; if already approved, just queues
  4. "Execute N phases" top-level button: approves all pending phases that have tasks, then calls queueAllPhases — count includes both pending (with tasks) and approved phases
  5. Tasks auto-queued when phase starts

Detailing Phases

  1. Select phase → "Detail" button
  2. spawnArchitectDetail mutation → agent creates task proposals
  3. Accept proposals → tasks created under phase
  4. View tasks in phase detail panel

Chat with Phase/Task

  1. Execution tab → select phase → "Chat" button (or open task → "Chat" button in footer)
  2. ChatSlideOver opens as right-side panel
  3. Send message → sendChatMessage mutation → agent spawns (or resumes) in 'chat' mode
  4. Agent applies changes (create/update/delete phases, tasks, pages) → changeset created
  5. Assistant message appears with inline changeset summary + revert button
  6. Send next message → agent resumes → repeat
  7. Close chat → session closed, agent dismissed

Components: ChatSlideOver, ChatBubble, ChatInput, ChangeSetInline in src/components/chat/.

Shared Package

packages/shared/ exports:

  • sortByPriorityAndQueueTime() — priority-based task sorting
  • topologicalSort() / groupByPipelineColumn() — phase DAG layout
  • InitiativeActivity / InitiativeActivityState — server-computed activity state for initiative cards
  • Shared type re-exports from packages/shared/src/types.ts (which re-exports from apps/server/)

Initiative Activity Indicator

listInitiatives returns an activity field on each initiative, computed server-side from phase statuses via deriveInitiativeActivity() in apps/server/trpc/routers/initiative-activity.ts. This eliminates per-card N+1 listPhases queries.

Activity states (priority order): conflict agent > archived > active architect agents > pending_review > executing > blocked > complete > ready > planning > idle. Each state maps to a StatusVariant + pulse animation in InitiativeCard's activityVisual() function. Active conflict agents (name starts with conflict-) are checked first — returning resolving_conflict (urgent variant, pulsing). Active architect agents (modes: discuss, plan, detail, refine) are checked next — mapping to discussing, detailing, detailing, refining states respectively — so auto-spawned agents surface activity even when no phases exist yet. PhaseSidebarItem also shows a spinner when a detail agent is active for its phase.