- Add truncate_title() function for bead titles (max 60 chars with ellipsis)
- Add escape_project() to replace / with :: in mapping keys for filesystem safety
- Add InvalidInput error code for validation errors
- Add comprehensive tests for truncation, escaping, and Unicode handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Startup sequence now:
1. Creates data directories (~/.local/share/mc/)
2. Cleans up orphaned tmp files from crashes
3. Verifies CLI dependencies (lore, br, bv) asynchronously
4. Emits startup-warnings event with missing CLI warnings
5. Emits cli-availability event with tool status
6. Emits startup-sync-ready when CLIs available
This enables the frontend to:
- Display warnings for missing tools
- Know which features are available
- Trigger reconciliation when ready
bd-3jh
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements core startup infrastructure:
- AppConfig for data directory paths
- ensure_data_dir() to create ~/.local/share/mc/
- verify_cli_dependencies() async CLI availability check
- load_with_migration() for state file loading with migration support
- init() main entry point coordinating lock acquisition and setup
- StartupWarning enum for non-fatal issues (missing CLIs, state reset)
- InitError enum with conversion to McError
Also exposes Bridge::with_data_dir() publicly (was test-only).
Includes 11 tests covering directory creation, lock acquisition,
lock contention, corrupt file handling, and config paths.
bd-3jh
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SyncOrchestrator that coordinates file watcher events with bridge sync
- Debounce rapid file changes (500ms window)
- Auto-check if full reconciliation is due (every 6 hours)
- Emit status events (Started, Completed, Failed, ReconciliationStarted/Completed)
- Support both incremental sync and full reconciliation
- 5 tests covering sync, debounce, reconciliation scheduling, and status events
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
- 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>
Integrates the bridge's cleanup_tmp_files() method into the Tauri
setup phase. This ensures any orphaned .json.tmp files from previous
crashes are cleaned up before the app starts operating.
The cleanup runs early in setup(), before tray and shortcuts, to
ensure a clean state for the bridge to operate in.
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>
Updates the Tauri app icons to use Mission Control's visual identity.
These icons appear in the dock, system tray, and window title bar.
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>
Completes the backend command layer, exposing bridge operations to the
frontend via Tauri IPC. Also adds system tray support and global hotkeys.
New commands:
- get_lore_status: Real CLI integration (was stub), returns issue/MR counts
- get_bridge_status: Mapping counts, pending items, sync timestamps
- sync_now: Trigger incremental sync (since_last_check events)
- reconcile: Full reconciliation pass (two-strike orphan detection)
- quick_capture: Create a new bead from freeform text
All commands use tokio::spawn_blocking for CLI I/O, preventing async
executor starvation. Commands accept trait objects for testability.
System integration:
- Global shortcut: Cmd+Shift+M toggles window visibility
- Global shortcut: Cmd+Shift+C opens quick capture overlay
- System tray: Left-click toggles window, right-click shows menu
- Tray menu: Show Mission Control, Quit
Tauri configuration:
- Added global-shortcut plugin with permissions
- Shell plugin scoped to lore, br, bv commands only
- Removed trayIcon config (using TrayIconBuilder instead)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds the core sync engine that maps GitLab events (from lore CLI) to beads
tasks. This is the foundational data layer for Mission Control's unified
task view.
Bridge architecture:
- GitLabBeadMap: JSON file storing event -> bead_id mappings
- MappingKey: Type-safe keys for MR reviews, issues, and authored MRs
- Cursor: Tracks last sync and reconciliation timestamps
Crash-safety features:
- Write-ahead pattern: pending=true written before bead creation
- Atomic file writes via temp file + rename
- Recovery on startup: retries pending entries with bead_id=None
- flock(2) based single-instance locking (prevents concurrent MC)
Two-strike orphan detection:
- First miss sets suspect_orphan=true (items may temporarily vanish)
- Second miss closes the bead (confirmed deleted/merged)
- Reappearance clears the flag (healed)
Sync operations:
- incremental_sync(): Process since_last_check events
- full_reconciliation(): Cross-check all open items
- recover_pending(): Handle interrupted syncs
Dependencies added:
- libc: For flock(2) system call
- thiserror: For ergonomic error types
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces McError and McErrorCode to replace string-based errors in
Tauri commands. This enables the frontend to handle errors programmatically
rather than parsing error messages.
Key design decisions:
- Error codes use SCREAMING_SNAKE_CASE for frontend pattern matching
- Each error indicates whether it's recoverable (user can retry)
- Automatic conversion from LoreError, BeadsError, and BridgeError
- Errors serialize to JSON for consistent IPC transport
Error categories:
- Lore: LORE_UNAVAILABLE, LORE_UNHEALTHY, LORE_FETCH_FAILED
- Bridge: BRIDGE_LOCKED, BRIDGE_MAP_CORRUPTED, BRIDGE_SYNC_FAILED
- Beads: BEADS_UNAVAILABLE, BEADS_CREATE_FAILED, BEADS_CLOSE_FAILED
- General: IO_ERROR, INTERNAL_ERROR
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Include necessary assets for Tauri app packaging and development:
App Icons (src-tauri/icons/):
- 32x32.png: Small icon for window title bar
- 128x128.png: Standard app icon
- 128x128@2x.png: Retina display icon
- icon.png: Source icon for tray
These are placeholder icons (simple geometric shapes) to be replaced
with proper branding before release.
Generated Schemas (src-tauri/gen/schemas/):
- acl-manifests.json: Access control list manifests
- capabilities.json: Tauri capability definitions
- desktop-schema.json: Desktop platform configuration schema
- macOS-schema.json: macOS-specific configuration schema
These schemas are auto-generated by 'cargo tauri dev' and should be
committed to enable IDE autocompletion and CI schema validation.
They regenerate automatically when tauri.conf.json changes.
Implement contract testing to catch CLI schema drift early:
Contract Test Suite (fixture_contract_tests.rs):
- parse_lore_me_empty_fixture: Validates LoreMeResponse on empty data
- parse_lore_me_with_activity_fixture: Real lore output with activity
- parse_br_list_empty_fixture: Empty beads list
- parse_br_list_with_beads_fixture: Real br output with beads
Fixtures (captured from real CLI output):
- fixtures/lore/me_empty.json: Synthetic empty response
- fixtures/lore/me_with_activity.json: Real 'lore --robot me' output
- fixtures/br/list_empty.json: Empty array []
- fixtures/br/list_with_beads.json: Real 'br list --json' output
- fixtures/br/bv_triage.json: Real 'bv --robot-triage' output
Fixture Regeneration:
- scripts/regenerate-fixtures.sh: Captures fresh CLI output
- Run periodically to update fixtures
- CI can diff against committed fixtures to detect drift
Why Contract Tests Matter:
MC depends on external CLIs (lore, br, bv) whose output format may
change. Contract tests fail fast when our Rust types diverge from
actual CLI output, preventing runtime deserialization errors.
The tests use include_str!() for compile-time fixture embedding,
ensuring tests fail to compile if fixtures are missing.
Implement the data layer with mockable CLI wrappers for testability:
CLI Traits (data/*.rs):
- LoreCli: Trait for lore --robot commands (get_me, health_check)
- BeadsCli: Trait for br commands (create, close, list)
- Both use #[automock] for unit testing without real CLI
Real Implementations:
- RealLoreCli: Shells to 'lore --robot me', parses JSON response
- RealBeadsCli: Shells to 'br create/close/list --json'
Type Definitions:
- LoreMeResponse: Full response from 'lore --robot me'
- open_issues, open_mrs_authored, reviewing_mrs, activity
- since_last_check with EventGroup for inbox functionality
- All fields use #[serde(default)] for forward compatibility
- Bead: Task from br list (id, title, status, priority, issue_type)
Local State Management (data/state.rs):
- GitLabBeadMap: Deduplication mapping (GitLab event -> bead ID)
- MappedBead: Tracks miss_count for two-strike orphan detection
- DecisionLog: Append-only JSONL for learning from user choices
- Atomic writes via .tmp files + rename pattern
Tauri Commands (commands/mod.rs):
- greet: Placeholder for IPC testing
- get_lore_status: Exposes lore health to frontend
This establishes the CLI-over-library pattern from PLAN.md:
clean boundaries, no schema coupling, full testability via mocks.