Remove the entire QMD search engine (semantic indexing, hybrid search,
vector embeddings) and replace with a simple walkdir-based keyword
search. QMD never worked reliably in production, added bundle bloat,
and showed "Index failed" in the status bar.
What changed:
- Rust: deleted indexing.rs, rewrote search.rs as pure keyword search
- Frontend: removed useIndexing hook, IndexingBadge, hybrid search
- Menu: removed "Reindex Vault" command from palette and menu bar
- Config: removed qmd from bundle resources and build script
- Deleted tools/qmd/ (QMD CLI tool, MCP server, tests)
- Updated docs (ARCHITECTURE, ABSTRACTIONS, GETTING-STARTED)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When push is rejected due to remote having newer commits, the bottom bar
now shows "Pull required" (orange). Clicking it pulls then auto-pushes.
Conflicted notes show an inline banner with "Keep mine" / "Keep theirs"
buttons. A new "Pull from Remote" command is available in Cmd+K and the
Vault menu. Clicking the sync badge opens a popup showing branch name,
ahead/behind counts, and a Pull button.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add "Reindex Vault" command to command palette and menu bar
- Show "Indexed Xm ago" in status bar when idle, clickable to reindex
- After git pull with updates, auto-trigger incremental reindex
- Add lastIndexedTime state to useIndexing, populated from backend metadata
- Add triggerFullReindex to useIndexing (retryIndexing is now an alias)
- Add onSyncUpdated callback to useAutoSync
- Extract formatIndexedElapsed to utils/indexingHelpers.ts
- Tests: 20 new unit tests across 5 files, 2 Playwright smoke tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add check_mcp_status Tauri command that detects whether the MCP server
is installed, Claude CLI is missing, or config needs setup. The status
bar shows a warning badge (MCP ⚠) when not installed, clickable to
trigger install. Also available via command palette "Install MCP Server".
Replaces useMcpRegistration with useMcpStatus which combines detection
and registration in a single hook.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Separate 'unavailable' (qmd not installed) from 'error' (indexing failed)
phases. Unavailable state is hidden from the status bar instead of showing
a persistent orange error. Actual errors show "Index failed — retry" with
click-to-retry. Both phases auto-dismiss after a timeout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- build.rs: remove unreliable git rev-list --count logic
- lib.rs: parse build number from Tauri package version at runtime
- Release version 0.20260303.281 -> 'b281'
- Dev version 0.1.0 -> 'dev'
- StatusBar.tsx: build number is clickable (triggers check for updates)
- App.tsx: pass handleCheckForUpdates to StatusBar
- Tests: unit tests for parse_build_label + StatusBar click behavior
Remove the hardcoded "Claude Sonnet 4" stub label and unused Sparkles
import — no model picker is planned at this stage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add git_resolve_conflict and git_commit_conflict_resolution Rust commands
- Create useConflictResolver hook for per-file resolution state management
- Create ConflictResolverModal with keyboard shortcuts (K/T/O/Enter/Esc)
- Make StatusBar conflict chip clickable to open resolver modal
- Add 'Resolve Conflicts' command to command palette (conditional)
- Pause auto-pull while conflict resolver modal is open
- Tests: 5 new Rust tests, 10 new hook tests, 1 new auto-sync test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Search now works out of the box on any vault without manual qmd
installation. On vault open, the app checks the index status and
auto-triggers background indexing (qmd update + embed) when needed.
If qmd is not installed, it auto-installs via bun.
Changes:
- New indexing.rs module: find_qmd_binary (cached), check_index_status,
ensure_collection, run_full_index with progress callbacks,
run_incremental_update, auto_install_qmd
- search.rs: delegates to indexing::find_qmd_binary (removes duplication)
- lib.rs: new Tauri commands (get_index_status, start_indexing,
trigger_incremental_index)
- useIndexing hook: auto-triggers on vault open, listens for
indexing-progress events, auto-dismisses complete state after 5s
- StatusBar: IndexingBadge shows phase + progress counts with spinner
- App.tsx: wires up useIndexing, triggers incremental index on file save
- design/search-bundle-qmd.pen: documents indexing progress UI states
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ability to remove vaults from the app list without deleting files on disk,
and restore the bundled Getting Started demo vault when needed.
Changes:
- Rust: add hidden_defaults field to VaultList for tracking removed default vaults
- useVaultSwitcher: add removeVault() and restoreGettingStarted() with auto-switch
- useCommandRegistry: add 'Remove Vault from List' and 'Restore Getting Started Vault' commands
- StatusBar: add X button per vault item in vault menu dropdown
- 25 new tests covering removal, restore, edge cases, and command palette
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vault list was stored only in React useState, lost on every app restart
or update. Now persisted to ~/.config/com.laputa.app/vaults.json via
Rust backend commands (load_vault_list, save_vault_list).
- Add vault_list.rs module with VaultEntry/VaultList types and JSON I/O
- Register load_vault_list/save_vault_list Tauri commands
- Extract vaultListStore.ts utility for frontend persistence calls
- Rewrite useVaultSwitcher to load on mount and persist on change
- Show unavailable vaults greyed out with warning icon instead of
silently removing them
- Add mock handlers for browser/test environments
- Add useVaultSwitcher tests covering persistence, availability, dedup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: show dynamic build number in status bar (bNNN format)
Replace hardcoded v0.4.2 with a dynamic build number derived from
git rev-list --count HEAD at compile time. The count is embedded via
build.rs and exposed through a get_build_number Tauri command.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: add build-number-status-bar wireframes (status bar with dynamic b-number)
* fix: use runtime env var for BUILD_NUMBER (compile-time env! not available in CI)
* style: rustfmt format get_build_number
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The commit hash link in the status bar used an <a href> tag which doesn't
open external URLs in Tauri's webview. Replaced with onClick handler that
calls openExternalUrl (Tauri opener plugin in native, window.open in browser).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: show last commit hash in status bar, remove branch name
Replace the hardcoded "main" branch display with a clickable short SHA
linking to the GitHub commit. Add Rust get_last_commit_info command that
returns the last commit hash and constructs a GitHub URL from the remote.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add design/git-status-bar.pen with new status bar layout
Shows the updated status bar with commit hash link, no branch name,
and annotated change callouts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: retrigger — runner 3 pnpm not found (env issue)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add auto-pull vault sync with conflict handling
- Add git_pull, has_remote, get_conflict_files to Rust backend
- Add GitPullResult type and auto_pull_interval_minutes to Settings
- Create useAutoSync hook (pull on launch, focus, periodic interval)
- Update StatusBar with real sync status indicator
- Add pull interval setting to SettingsPanel
- Add mock handler for git_pull
- Update existing tests for new Settings field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add tests for git pull, settings, and useAutoSync hook
- Add Rust tests: has_remote, git_pull (no_remote, up_to_date, updated),
get_conflict_files, parse_updated_files, GitPullResult serialization
- Add frontend tests: useAutoSync (mount pull, focus pull, conflict,
error, manual trigger, concurrent prevention, no_remote)
- Fix existing settings tests for new auto_pull_interval_minutes field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: add auto-pull-vault wireframes
Frames showing: sync idle, syncing, conflict indicator,
settings sync section, and conflict toast notification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add auto_pull_interval_minutes to all Settings literals
Fix build error and test fixtures missing the new field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: cargo fmt
* ci: re-trigger CI after flaky test
* ci: retrigger after disk space cleanup
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Clicking "N pending" in the status bar or the "Changes" nav item in
the sidebar shows a filtered list of notes with uncommitted changes.
The view updates in real-time as files are saved or committed.
- Add 'changes' filter to SidebarSelection type
- Make StatusBar "N pending" indicator clickable
- Add "Changes" NavItem in sidebar (visible when modifiedCount > 0)
- Filter NoteList by modifiedFiles paths for changes view
- Show "No pending changes" empty state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- NoteItem: orange dot before title for uncommitted modified notes
- TabBar: orange dot on tabs with uncommitted changes
- StatusBar: "N pending" counter with CircleDot icon when modified files exist
- useEditorSave: onAfterSave callback to refresh modified files after save
- mock-tauri: track dynamically saved files as modified, clear on commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add "Open local folder" and "Create new vault" options to the vault
picker dropdown. Uses tauri-plugin-dialog for native folder picker
in Tauri mode, falls back to prompt() in browser mode.
- Rust: add tauri-plugin-dialog, create_vault_dir command
- Frontend: pickFolder utility, StatusBar UI, App.tsx handlers
- Mock: create_vault_dir mock handler for browser testing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New GitHubVaultModal component with two tabs:
- Clone Existing: search/browse user's repos, select one, choose
local path, clone via HTTPS+token
- Create New: enter repo name, toggle private/public, create via
GitHub API then clone locally
Integration:
- "Connect GitHub repo" option in vault switcher menu
- GitHub token field added to Settings panel
- Cloned vaults auto-added to vault list and opened
- Mock handlers for github_list_repos, github_create_repo, clone_repo
- All existing tests updated for new github_token field (386 pass)
Product decision: GitHub token stored in settings rather than OAuth
flow — simpler first version, works with personal access tokens.
Users can upgrade to OAuth later.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove .dark CSS variables block from index.css
- Remove theme toggle state and Cmd+Shift+T shortcut from Sidebar
- Remove dark class initialization from main.tsx
- Hardcode BlockNote theme to 'light' in Editor
- shadcn dark: classes left in place (harmless, no-op without .dark class)