Commit Graph

563 Commits

Author SHA1 Message Date
Test
b60bdb685d fix: MCP install command always visible in Cmd+K regardless of mcpStatus
The command was gated on `mcpStatus !== 'checking'` which meant it was
hidden during the initial async status check. Changed enabled to always
be true so users can find and run the command immediately on app start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:58:46 +01:00
Test
83009d8fb9 feat: make MCP restore command always available in Cmd+K
The "Install MCP Server" command was only enabled when status was
"not_installed", preventing users from re-registering when MCP got
removed or broken. Now the command is always available:
- Shows "Install MCP Server" when not installed
- Shows "Restore MCP Server" when already installed
- Added restore/fix/repair keywords for discoverability
- Context-aware toast: "installed" vs "restored"
- Menu bar label updated to "Restore MCP Server"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:33:18 +01:00
Test
068d434344 fix: auto-save structural UI changes to disk immediately
Structural changes (sidebar visibility, label, order, template, icon/color)
now auto-create missing Type entries and call onFrontmatterPersisted to
refresh git status, so changes appear in git diff without user intervention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:06:10 +01:00
Test
bf5f5521af fix: wikilink clicks in AI chat now open note in tab
AiPanel.handleNavigateWikilink was double-resolving: it resolved the
wikilink target to an entry path, then passed the path to onOpenNote
which is notes.handleNavigateWikilink (expects a title-based target).
The path didn't match any entry's title, so navigation silently failed.

Fix: pass the wikilink target string directly to onOpenNote, letting
the parent's handleNavigateWikilink do the resolution.

Also enhanced the Playwright smoke test to verify click → tab opens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 07:14:34 +01:00
Test
42e37e035c test: add unit tests for detectFileOperation and parseBashFileCreation
24 tests covering Write/Edit/Bash file detection, edge cases
(malformed JSON, files outside vault, non-md files, undefined input),
and the parseBashFileCreation helper for redirect/tee patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:41:06 +01:00
Test
0ad0fa9b6b fix: AI-created notes now trigger vault refresh and auto-open in tab
Root causes:
- toolInputMapRef in useAiAgent was overwritten by tool_progress events
  (which arrive with input=undefined AFTER the assistant message set
  the full input), causing detectFileOperation to receive undefined
  and skip file creation detection entirely.
- MCP open_note only broadcast open_tab without vault_changed, so
  the note list didn't refresh when Claude Code called open_note.
- detectFileOperation only handled Write/Edit but not Bash commands
  that create .md files via redirects.

Fixes:
- Preserve accumulated input in toolInputMapRef (input ?? prev?.input)
- MCP open_note now broadcasts vault_changed before open_tab
- detectFileOperation now detects Bash redirect patterns (>, >>, tee)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:39:34 +01:00
Test
c37c03d6a9 fix: remove --resume from AI chat to fix conversation history
The AI chat was using both --resume (CLI session resumption) AND formatted
conversation history in the prompt simultaneously. This dual-context approach
confused the model — it saw the conversation twice (from session + from prompt
markup), leading to "I don't have context" responses on follow-ups.

Fix: remove --resume entirely from chat mode. Each CLI call is now independent,
with full conversation history formatted into the prompt via
<conversation_history> markup. trimHistory handles graceful truncation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:08:24 +01:00
Test
382ba0a6d4 test: add Playwright smoke test for wikilink rendering in AI chat
Update mock agent response to include [[wikilinks]] for testing.
Add smoke test verifying wikilinks render as clickable elements
with correct text, attributes, and styling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:58:08 +01:00
Test
4719810b10 feat: render [[wikilinks]] as clickable links in AI chat
- System prompts instruct AI to use [[Note Title]] wikilink syntax
- preprocessWikilinks converts [[Target]] to markdown links
- Custom urlTransform allows wikilink:// scheme through sanitizer
- Click handler resolves target via findEntryByTarget and opens note
- Styled as colored chips matching primary accent
- Works in both AiPanel (agent) and AIChatPanel (legacy chat)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:40:44 +01:00
Test
de00ab6794 feat: reindex vault command, indexing status bar, sync-triggered reindex
- 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>
2026-03-07 01:14:12 +01:00
Test
8da1484ebf test: Playwright smoke test for push error UX
Expose mockHandlers on window for Playwright overrides. Test that
rejected push shows "Pull first" message, auth error shows
"authentication error", and success shows "Committed and pushed".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:35:35 +01:00
Test
90ebc2e939 feat: surface actionable push error messages in frontend
Update commitWithPush to parse GitPushResult from backend and show
specific messages (rejected, auth, network) instead of generic
"push failed". Tests verify rejected + network error scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:31:46 +01:00
Test
7ddc0c14bf fix: add visible key to frontmatterToEntryPatch maps
The ENTRY_DELETE_MAP and update map in frontmatterToEntryPatch were
missing the 'visible' key. When handleDeleteProperty or
handleUpdateFrontmatter was called for 'visible', the in-memory
VaultEntry was not updated, causing the sidebar to stay stale even
after the file on disk was correctly modified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:20:51 +01:00
Test
2a00b8aac7 fix: include full conversation history in AI chat requests
- Add trimHistory() to keep most recent messages within 100k token budget
- Add formatMessageWithHistory() to prepend conversation context to each message
- Wire up in useAIChat.ts: sendMessage now includes full history
- Keep --resume as belt-and-suspenders for same-session continuity
- 14 new tests in ai-chat.test.ts and useAIChat.test.ts
2026-03-06 23:47:59 +01:00
Test
b7d2304282 test: fix Sidebar tests after Favorites removal 2026-03-06 23:22:14 +01:00
Test
50b5fa9c2e refactor: remove Favorites and Untagged from sidebar
- Remove Favorites NavItem, Star icon import, go-favorites command
- Remove Untagged NavItem, TagSimple icon import
- Remove favorites from SidebarFilter union type
- Update tests: Sidebar.test.tsx, useMenuEvents.test.ts, App.test.tsx
- Remove GO_FAVORITES constant and menu item from menu.rs
2026-03-06 23:19:37 +01:00
Test
c9a5d20c12 test: Playwright smoke test for trash → Changes badge
Also track mock frontmatter writes in mockSavedSinceCommit so the
Changes panel updates correctly in browser dev mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:08:18 +01:00
Test
586e1fcde5 fix: refresh Changes panel after trash/archive operations
Trash, archive, restore, and unarchive wrote frontmatter to disk but
never called loadModifiedFiles, so the change didn't appear in the
Changes panel until the next manual refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:01:05 +01:00
Test
75d67623ce Pulse: fix slow note open — O(1) map lookup, no reloadVault on click
Root cause: clicking a note in Pulse used an inline arrow function that:
1. Was recreated on every render (new prop ref → PulseView memo bypassed)
2. Called vault.reloadVault() (full 9000-note rescan) when path didn't match

Fix:
- Add entriesByPath Map (useMemo) — O(1) lookups instead of O(n) .find()
- Add handlePulseOpenNote (useCallback) — stable ref, never triggers reloadVault
  (Pulse notes always exist in vault; no reload needed)
- Wire PulseView to handlePulseOpenNote instead of inline arrow
- Also use entriesByPath in openNoteByPath (MCP bridge)
2026-03-06 22:25:55 +01:00
Test
18b2aaedf6 fix: add missing visible field to buildNewEntry in useNoteActions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:57:00 +01:00
Test
1706300494 test: add Playwright smoke test for visible type property
Also updates vite.config.ts vault API parser to include all VaultEntry
fields (visible, icon, color, order, etc.) so the dev server returns
complete entries for sidebar filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:52:40 +01:00
Test
d3896ddf01 refactor: remove hidden_sections from VaultConfig and delete useSectionVisibility
Sidebar section visibility is now controlled entirely by the `visible`
property on Type notes. Removes all hidden_sections references from
Rust struct, TypeScript interface, config migration, mock data, and tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:41:00 +01:00
Test
7289a60db3 feat: add handleToggleTypeVisibility to useEntryActions
Toggle visible property on Type note frontmatter: sets visible:false
to hide, deletes visible property to show (defaults to visible).
Wire up in App.tsx via onToggleTypeVisibility prop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:35:18 +01:00
Test
0cff626e48 feat: filter sidebar sections by Type entry visible property
Replace useSectionVisibility hook with direct filtering on
typeEntryMap[type]?.visible !== false. Add onToggleTypeVisibility
callback prop. Tests updated to verify visible:false hides sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:33:47 +01:00
Test
826cda852a Pulse: lazy pagination with IntersectionObserver infinite scroll
- Page size reduced from 30 → 20 commits per fetch
- Backend: add `skip` param to get_vault_pulse (git log --skip)
  → true pagination instead of re-fetching everything
- Frontend: IntersectionObserver sentinel at bottom of feed
  → auto-loads next page when user scrolls near end
- Append-only updates (no full re-render on load more)
- Add IntersectionObserver mock to test setup
2026-03-06 21:04:24 +01:00
Test
19583ea1f5 💅 Pulse: add right border, collapse commit files by default
- Add border-r border-[var(--sidebar-border)] to PulseView container
- CommitCard files default to collapsed (expanded: false) for cleaner initial state
- Update tests to reflect new collapsed-by-default behavior
2026-03-06 21:00:35 +01:00
Test
bbb29857b8 test: add regression tests for hyphenated folder sidebar duplicates
- Sidebar unit test: entries with isA 'Monday Ideas' produce exactly
  one section header (not two)
- Playwright smoke test: verify no duplicate section labels in sidebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:09:29 +01:00
Test
6f6e7d7cfe fix: vault cache misses files in new directories, breaking theme restore
Root cause: git_uncommitted_files() used `git status --porcelain` which
reports new untracked directories as `?? theme/` instead of listing
individual files inside. The .md filter skipped directory entries, so
files in newly-created directories (theme/default.md, etc.) were
invisible to the cache system.

Fix: additionally use `git ls-files --others --exclude-standard` which
lists individual untracked files, resolving directories to their
contents.

Also:
- Add type/theme.md definition (icon: palette) to restore and getting-started vault
- Seed theme/*.md vault notes in getting-started vault
- Fix mock create_vault_theme to add entries for dev mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:38:54 +01:00
Test
edcb306c7f fix: exclude .laputa-cache.json and settings.json from vault git tracking
These files are machine-specific and should never be committed or cause
conflicts when syncing vaults across devices.

Changes:
- init_repo() now writes .gitignore with .laputa-cache.json and
  .laputa/settings.json excluded before the first commit
- .DS_Store and common editor artifacts also excluded
- openConflictFileRef falls back to openLocalFile() for non-note files
  so 'Open in editor' works for .json conflict files (opens in system
  default app, e.g. TextEdit/VS Code)
- Removed stale git.rs (replaced by git/mod.rs from refactor)
- 2 new Rust tests for .gitignore creation behavior
2026-03-06 15:22:48 +01:00
Test
244deeb727 fix: sign qmd binaries with Developer ID + hardened runtime for notarization
Apple notarization rejected qmd/qmd and qmd/vec0.dylib due to:
- Not signed with valid Developer ID certificate
- Hardened runtime not enabled

Changes:
- bundle-qmd.sh: use APPLE_SIGNING_IDENTITY + --options runtime --timestamp in CI
  (falls back to ad-hoc signing in dev when no identity is set)
- useThemeManager.test.ts: add ensure_vault_themes to mock (added by theme
  editor feature, missing from stale theme ID test mock)
2026-03-06 08:43:54 +01:00
Luca Rossi
d4098d3308 refactor: split InspectorPanels.tsx into focused modules — reduce 538-line file to focused per-panel components (#189)
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 07:11:00 +01:00
Luca Rossi
1c3d677851 test: add configMigration tests — cover all migration branches (#188)
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:46:10 +01:00
Test
3da0b0e652 fix: make qmd/search work on fresh installs — auto-install, fix permissions, sign binaries
On fresh MacBook installs, the bundled qmd binary fails to run due to:
missing execute permissions, macOS quarantine attributes, and no fallback
when qmd is completely absent. This fix addresses all three issues:

- Runtime: ensure +x permissions and remove quarantine on bundled qmd
- Runtime: auto-install qmd via bun when binary not found anywhere
- Build: ad-hoc code-sign qmd and .dylib files in bundle-qmd.sh
- Build: create placeholder resource dirs so fresh clones build cleanly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:13:03 +01:00
Test
0206fb3720 fix: rank command palette results by match score, not section order
When searching in Cmd+K, groups are now ordered by their highest-scoring
match instead of the fixed section order. Empty query preserves the
default section ordering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:00:31 +01:00
Test
0183062467 fix: always show Resolve Conflicts in Cmd+K — show toast when no conflicts 2026-03-05 18:18:52 +01:00
Test
1c244a85eb refactor: extract hooks and components from NoteListInner for code health
Split NoteListInner (190 lines, 14 props) into focused units:
- useNoteListSort: sort state, migration, type frontmatter persistence
- useNoteListSearch: search/query state and toggle
- useMultiSelectKeyboard: keyboard shortcuts for bulk actions
- useModifiedFilesState: modified file tracking and status resolution
- NoteListHeader: 52px header bar with sort, search, and create

Also extracted pure helpers (handleEscapeKey, handleSelectAllKey,
handleBulkActionKey, resolveEmptyText, deriveEffectiveSort, etc.)
to reduce cyclomatic complexity in remaining functions.

NoteListInner body: 190 → 48 lines. CodeScene health: 8.54 → 9.36.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:50:42 +01:00
Test
3af9a09d29 feat: add Pulse — vault activity feed showing git commit history
Adds a new Pulse sidebar section that shows chronological git commit
history for the vault. Commits are grouped by day with message, time,
short hash (clickable GitHub link when remote configured), file list
with add/modify/delete status icons, and summary badges. Clicking a
file opens the note in the editor. Disabled with tooltip for non-git
vaults. Accessible via sidebar click or "Go to Pulse" command palette.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:27:29 +01:00
Test
013cf0ffe1 feat: move vault UI config from localStorage to vault files
Add VaultConfig infrastructure (store, hook, migration) that persists
zoom, view mode, section visibility, tag/status colors, and property
display modes to config/ui.config.md in the vault instead of localStorage.

- New vaultConfigStore module with subscribe/notify pattern
- useVaultConfig hook loads config via Tauri, binds store, runs migration
- One-time silent migration from localStorage on first load
- Config type excluded from note search and unified search
- All hooks/utils updated to read/write through vault config store
- Tests updated to use vault config store instead of localStorage mocks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:26:21 +01:00
Test
1e3c296787 fix: pass undefined to useRef for strict TypeScript compat
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:42:28 +01:00
Test
32b4a90ae5 feat: expose all theme.json properties in theme editor
Add ThemePropertyEditor component that surfaces all customizable
properties from theme.json — typography, headings, lists, code blocks,
blockquote, table, and horizontal rule — organized into collapsible
sections with appropriate input types (number, color, select, text).

- themeSchema.ts: derives flat property list from theme.json with
  auto-detected input types, units, and select options
- ThemePropertyEditor.tsx: sectioned editor with collapsible sections,
  keyboard-accessible toggles, debounced live updates
- ThemeManager: add updateThemeProperty() and activeThemeContent
- SettingsPanel: show property editor below theme list when active

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:42:28 +01:00
Test
ff3e7af65a fix: move view-toggle-backlinks to simple event map for type safety
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:34:03 +01:00
Test
75878c8b64 feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:34:03 +01:00
Test
8f0c6e04fe test: add color detection tests to propertyTypes
Verify hex colors are detected as 'color' display mode, named colors
with color-related keys are detected, and invalid colors are rejected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:57:17 +01:00
Test
adf45a51b5 feat: add color swatch + picker for property values
Add inline color swatch preview next to hex/CSS color property values in
the Properties panel. Clicking the swatch opens the native OS color
picker. Add 'color' property display mode with auto-detection for hex
values and color-related key names (background, primary, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:35:10 +01:00
Test
96bc4e935a fix: enable line wrapping in raw editor
Long lines now wrap to the next visual line instead of scrolling
horizontally off-screen, matching expected behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:57:16 +01:00
Test
eab457b388 fix: make Restore Default Themes command always enabled in Cmd+K palette
The enabled guard `!!onRestoreDefaultThemes` could evaluate to false at
runtime, hiding the command from the palette. Since the handler is always
defined via useCallback, the guard is unnecessary. Changed to enabled: true,
matching the pattern used by other always-available commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:32:32 +01:00
Test
89da970455 feat: enable full shell access for AI agent + simplify MCP tools
Remove --tools "" restriction so the agent has native bash/read/write/edit
access. Set vault path as working directory for the subprocess.

Simplify MCP to 4 Laputa-specific tools (search_notes, get_vault_context,
get_note, open_note) — everything else is handled by native tools.

Add file operation detection from Write/Edit tool calls to auto-open
created notes and refresh modified notes in the UI. Enhanced tool call
labels show bash commands, file paths, and note names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:12:12 +01:00
Test
c371e26dcb feat: Add 'Restore Default Themes' command for vaults missing theme structure
- New restore_default_themes() Rust fn: seeds both _themes/ and theme/ dirs
- Per-file idempotent: never overwrites existing files with content
- Fixed ensure_vault_themes() to include minimal.md (was missing)
- New 'Restore Default Themes' command in Cmd+K Appearance group
- 3 new Rust tests + 4 new frontend tests
- 1676 frontend tests passed
2026-03-05 11:18:53 +01:00
Test
5e84ebc28a fix: stub WebSocket in test setup to prevent Node 22 + undici crash 2026-03-05 10:49:52 +01:00
Test
5775cb0c96 fix: detect and resolve rebase conflicts in sync conflict resolution
The previous conflict detection only worked for merge-based pulls
(--no-rebase) but failed to detect pre-existing conflicts from
interrupted rebases or prior sessions. This fixes three root causes:

1. Rust: add is_rebase_in_progress/is_merge_in_progress/get_conflict_mode
   helpers, and dispatch git_commit_conflict_resolution between
   `git commit` (merge) and `git rebase --continue` (rebase)
2. Frontend: add startup conflict check via get_conflict_files before
   pulling, so pre-existing conflicts are detected on app launch
3. App.tsx: handleOpenConflictResolver now fetches conflicts directly
   when the cached list is empty, preventing the silent early-return

Also exposes get_conflict_files and get_conflict_mode as Tauri commands
so the frontend can independently check conflict state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:34:25 +01:00