- Add ErrorBoundary class component to catch React render errors
- Show fallback UI with error details (stack in dev mode) and recovery buttons
- Add ErrorDisplay component for showing structured McError messages
- Support all McErrorCode types with contextual messages and install guides
- Implement retry/dismiss actions for recoverable errors
- Add 16 comprehensive tests covering both components
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add InvariantError class and assertion utilities for runtime validation:
- invariant(condition, message) - throws if condition is falsy, acts as type guard
- assertNever(value) - for exhaustive switch statement checking
- Support for lazy message evaluation to avoid expensive string operations
These helpers enable defensive programming with clear error messages when
invariants are violated.
Closes bd-1w5
Shows THE ONE THING with:
- Focus item title, type badge, project, and age
- Quick actions: Start, Defer (1h), Skip
- Queue and inbox counts
- Link to open full window
- Empty state when nothing focused
Includes 18 tests covering all states and interactions.
bd-wlg
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Displays sync state with:
- Green dot for synced (with relative time)
- Spinner for syncing
- Amber dot for stale (auto-detected after 15min)
- Red dot for error (with retry button)
- Gray dot for offline
Includes 23 tests covering all states, time formatting,
button visibility, and click handlers.
bd-2or
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add text search across all focus items
- Support filter commands: type: and stale:
- Keyboard navigation with arrow keys + Enter
- Click to select items
- Escape or backdrop click to close
- 17 tests covering search, filters, keyboard nav, and empty state
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Log swallowed errors in file watcher and window operations (lib.rs, watcher.rs)
- Propagate recovery errors from bridge::recover_pending to SyncResult.errors
so the frontend can display them instead of silently dropping failures
- Fix useTauriEvent/useTauriEvents race condition where cleanup fires before
async listen() resolves, leaking the listener (cancelled flag pattern)
- Guard computeStaleness against invalid date strings (NaN -> 'normal'
instead of incorrectly returning 'urgent')
- Strengthen isMcError type guard to check field types, not just presence
- Log warning when data directory resolution falls back to '.' (state.rs, bridge.rs)
- Add test for computeStaleness with invalid date inputs
Fix three bugs found during code review:
1. useTauriEvent/useTauriEvents: If the component unmounts before the
async listen() promise resolves, the unlisten function was lost,
leaking the event subscription. Added a cancelled flag to call
unlisten immediately when the promise resolves after cleanup.
2. useTauriEvents: The handlers object was used directly as a useEffect
dependency, causing re-subscription on every render when callers
pass an inline object literal. Replaced with a useRef for handler
stability and a derived eventNames string as the dependency.
3. isMcError type guard: Only checked property existence via 'in'
operator, not property types. An object with wrong-typed properties
(e.g. code: 42) would pass the guard. Now validates that code and
message are strings and recoverable is boolean.
4. AppShell global shortcut listener: Same race condition as (1), plus
missing .catch() on the listen promise could produce unhandled
rejections.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ReasonPrompt dialog for capturing optional reasons
- Add quick tag buttons (Blocking, Urgent, Context switch, etc.)
- Support keyboard navigation (Escape to cancel)
- Handle text input with trimming and null for empty
- Different titles for different actions (set_focus, defer, skip)
- All 10 tests pass
Closes bd-2p0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add InboxItem types and TriageAction/DeferDuration types
- Create Inbox component with:
- Accept/Defer/Archive actions for each item
- Keyboard shortcuts (A/D/X) for fast triage
- Defer duration picker popup
- Inbox Zero celebration state
- Type-specific badges with colors
- Add comprehensive tests for all functionality
Closes bd-qvc
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Completes persistence story and crash recovery hardening.
Nav store persistence:
- Wraps nav store with zustand persist middleware
- Persists activeView to localStorage under "mc-nav-store"
- Remembers which view you were on across sessions
Bridge tmp file cleanup (src-tauri/src/data/bridge.rs):
- New cleanup_tmp_files() method removes orphaned .json.tmp files
- Called on startup to clean up from crashes during save_map()
- Logs cleaned files for debugging
- Returns count of files removed
The atomic write pattern (write to .tmp, then rename) can leave
orphan files if the app crashes between write and rename. This
cleanup ensures we don't accumulate stale tmp files over time.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wraps the focus store with zustand/middleware persist to maintain
queue state across page refreshes and app restarts.
Persists:
- current: The currently focused item
- queue: Remaining items in the work queue
Not persisted (transient state):
- isLoading: Reset on mount
- error: Reset on mount
Storage key: "mc-focus-store"
This prevents losing your place in the queue when the app restarts
or the page refreshes during development.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds real-time updates when lore syncs new GitLab data by watching
the lore.db file for changes.
React hook (src/hooks/useTauriEvents.ts):
- useTauriEvent(): Subscribe to a single Tauri event with auto-cleanup
- useTauriEvents(): Subscribe to multiple events with a handler map
- Typed payloads for each event type:
- global-shortcut-triggered: toggle-window | quick-capture
- lore-data-changed: void (refresh trigger)
- sync-status: started | completed | failed
- error-notification: code + message
Rust watcher (src-tauri/src/watcher.rs):
- Watches lore's data directory for lore.db modifications
- Uses notify crate with 2-second poll interval
- Emits "lore-data-changed" event to frontend on file change
- Handles atomic writes by watching parent directory
- Gracefully handles missing lore.db (logs warning, skips watcher)
Test coverage:
- Hook subscription and cleanup behavior
- Focus store test fix: clear localStorage before each test
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete frontend implementation for Mission Control's core workflow:
surface THE ONE THING and let the user act on it.
Layout (AppShell.tsx):
- Tab navigation: Focus | Queue | Inbox
- View switching with AnimatePresence transitions
- Global shortcut event listener for quick capture
- Batch mode overlay when active
Focus View (FocusView.tsx, FocusCard.tsx):
- Prominent display of THE ONE THING
- Type badge with staleness coloring (fresh/normal/amber/urgent)
- Context quote and requestedBy for reviews
- Action buttons: Start (Enter), 1h (Cmd+1), Tomorrow (Cmd+2), Skip (Cmd+S)
- Empty state: "All Clear" when queue is empty
Queue View (QueueView.tsx, QueueItem.tsx, QueueSummary.tsx):
- List view of all items with reordering capability
- Click to set as focus (promotes to THE ONE THING)
- Summary shows counts by type
- Links back to Focus view
Quick Capture (QuickCapture.tsx):
- Modal overlay triggered by Cmd+Shift+C
- Creates new bead via quick_capture command
- Shows success/error feedback
Batch Mode (BatchMode.tsx):
- Full-screen overlay for rapid item processing
- Progress indicator: 3/10 DONE
- Same action buttons as FocusCard
- Exit returns to regular Focus view
App entry updates:
- App.tsx now renders AppShell
- main.tsx unchanged (React 19 + StrictMode)
- Tailwind config adds MC-specific colors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the frontend state management layer using Zustand. Each store
is single-purpose and testable in isolation.
Focus Store (focus-store.ts):
- Tracks current focused item (THE ONE THING)
- Manages the queue of remaining items
- Actions: setItems, act (start/defer/skip), setFocus, reorderQueue
- Advancing through items removes from queue, promotes next to current
Navigation Store (nav-store.ts):
- Simple view routing: focus | queue | inbox
- No URL-based routing needed for native app
- Default view is "focus"
Capture Store (capture-store.ts):
- Manages quick capture overlay state
- Tracks submission status and errors
- Opens via global shortcut event listener
Batch Store (batch-store.ts):
- Manages batch processing mode for rapid item completion
- Tracks items, their statuses (pending/done/skipped), and current index
- Derives counts: completedCount, skippedCount, isFinished
- Used for "knock out all code reviews" workflow
State design principles:
- No derived state stored; computed on access
- Actions are pure mutations with logging
- Loading/error states colocated with data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Establishes type-safe communication between React frontend and Rust backend.
Types mirror the Rust structs to ensure consistency across the Tauri boundary.
Type definitions (src/lib/types.ts):
- LoreStatus, LoreSummaryStatus: Lore CLI response shapes
- BridgeStatus, SyncResult: Bridge operation results
- McError, McErrorCode: Structured error handling with type guard
- FocusItem, FocusItemType: THE ONE THING work items
- FocusAction, DecisionEntry: User action tracking
- Staleness computation: fresh/normal/amber/urgent based on age
IPC wrapper (src/lib/tauri.ts):
- Typed invoke() calls for each Rust command
- getLoreStatus, getBridgeStatus, syncNow, reconcile, quickCapture
Data transformation (src/lib/transform.ts):
- transformLoreData: Converts lore response to FocusItem[]
- Priority ordering: reviews first (blocking others), issues, authored MRs
- Generates stable IDs matching bridge mapping keys
Formatting utilities (src/lib/format.ts):
- formatIid: Prefix with ! for MRs, # for issues
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create the minimal React application structure for Mission Control:
Entry Points:
- index.html: Dark mode root (class="dark", bg-surface body)
- src/main.tsx: React 19 createRoot with StrictMode
Application Shell:
- src/App.tsx: Initial landing with "THE ONE THING" placeholder
- Uses Framer Motion for subtle fade-in animation
- Centered layout with Mission Control branding
- Surfaces the core UX principle: "What should you be doing right now?"
Styling:
- src/styles.css: Tailwind directives + custom scrollbar styling
- Dark scrollbars (zinc-700 thumb, transparent track)
- .no-select utility for draggable elements
The shell is deliberately minimal - it will evolve as beads integration
(bd-28q) and dashboard components (bd-30f) are implemented.