Commit Graph

183 Commits

Author SHA1 Message Date
Test
d3ea632673 feat: detect MCP server status and show warning in status bar
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>
2026-03-04 13:11:58 +01:00
Test
197aad0e97 feat: add reasoning streaming, markdown response, structured context snapshot
- Rust: add ThinkingDelta event to ClaudeStreamEvent for reasoning chunks
- ai-agent.ts: forward ThinkingDelta events via onThinking callback
- useAiAgent: stream reasoning live, accumulate response internally,
  reveal as complete block on done
- AiMessage: auto-collapse reasoning when done, use MarkdownContent
  for response rendering, update tests for new behavior
- ai-context: add buildContextSnapshot() for structured JSON context
  with activeNote, openTabs, noteListFilter, vault summary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:09:02 +01:00
Test
55a2509658 fix: MCP UI tools (highlight, open_note) now work in real-time
Root causes:
- index.js tried to start its own UI bridge server on port 9711, but
  ws-bridge.js (spawned by Tauri) already owns it → broadcastUiAction
  was a no-op. Fixed by connecting index.js as a WebSocket CLIENT that
  sends messages through the existing bridge.
- ws-bridge.js UI bridge had no relay — client messages weren't forwarded.
  Added relay so messages from the MCP server reach the React frontend.
- useAiActivity hook existed but was never imported in App.tsx.
- useAiActivity only handled highlight, not open_note/open_tab/set_filter.
- No vault_changed events after write operations.
- set_filter payload used `type` key which overwrote `type: 'ui_action'`.

Changes:
- mcp-server/index.js: connect as WS client instead of starting server;
  broadcast vault_changed after all write operations
- mcp-server/ws-bridge.js: add message relay in UI bridge; broadcast
  vault_changed after write operations; fix set_filter payload key
- useAiActivity: handle all UI actions (highlight, open_note, open_tab,
  set_filter, vault_changed); accept callbacks; auto-reconnect on close
- App.tsx: wire useAiActivity into vault/notes/selection actions; apply
  ai-highlight CSS class to editor and note list panels
- App.css: add ai-highlight-glow keyframe animation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:05:43 +01:00
Test
ed5e6d6820 fix: auto-provision theme files on vault open for any vault
seed_vault_themes now writes individual missing/empty files instead of
skipping when the theme/ directory already exists. A new
ensure_vault_themes Tauri command is called by useThemeManager on every
vault open so vaults without a theme/ folder get default.md and dark.md
seeded automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:34:51 +01:00
Test
feb97caa87 fix: show 'Installing search...' when qmd missing instead of 'Indexing...'
On fresh installs without qmd, show the accurate "Installing search..."
phase instead of briefly flashing "Indexing..." before switching to
unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:45:24 +01:00
Test
5bcd344d5f fix: replace 'Index error' with graceful handling on fresh installs
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>
2026-03-03 21:36:10 +01:00
Test
ceee8b04ea feat: make AI chat tool use blocks expandable with input/output details
Tool call blocks in AI Chat are now clickable and expandable to show
tool name, input parameters (pretty-printed JSON), and output/result.
Collapsed by default, keyboard accessible (Tab/Enter/Space/Esc).

Backend: Rust stream events now carry tool input (accumulated from
input_json_delta chunks) and tool output (from tool_result events).
Frontend: AiActionCard is a disclosure widget with aria-expanded,
error output shown in red, long content truncated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:08:48 +01:00
Test
d5b621e174 fix: trash/archive banner appears immediately without reopening note
Tabs stored a snapshot of VaultEntry at open time. When updateEntry()
changed vault.entries (e.g. trashing a note), the active tab's entry
stayed stale, so the banner never appeared until the note was reopened.

Add a useEffect that syncs tab entries with vault.entries whenever the
vault state changes, using reference equality to skip unchanged entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:51:49 +01:00
Test
3a623d48bb feat: replace raw editor textarea with CodeMirror 6
Adds line numbers, current line highlight, and syntax highlighting
(YAML frontmatter keys/values, --- delimiters, markdown headings).
Extracted useCodeMirror hook and frontmatterHighlight extension.
Preserves wikilink autocomplete, Cmd+S save, and Escape dismiss.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:40:39 +01:00
Test
17eeac75cd fix: open newly created theme in editor after New Theme command
After createTheme(), the theme file was created and the sidebar navigated
to the Theme section, but the note was never opened in the editor.
Now captures the returned path and opens it via handleSelectNote.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:29:32 +01:00
Test
2dad764ea7 fix: check-for-updates command always visible in Cmd+K, handles all update states 2026-03-03 16:46:47 +01:00
Test
0c87e51037 feat: add Check for Updates command to native menu and Cmd+K palette
- Add APP_CHECK_FOR_UPDATES constant and menu item in menu.rs (between About and Settings)
- Wire onCheckForUpdates handler through useMenuEvents and useAppCommands
- Add test for app-check-for-updates dispatch
2026-03-03 13:19:09 +01:00
Test
7df1961172 feat: persist note list sort preference in type file frontmatter
Sort preferences for each type's note list are now stored in the type
file's frontmatter (e.g. `sort: modified:desc` in `type/person.md`)
instead of localStorage. This makes preferences portable with the vault
and versionable in git.

- Add `sort` field to Rust Frontmatter/VaultEntry and TS VaultEntry
- NoteList reads sort from type entry's frontmatter when viewing a type
- Sort changes write to type file via update_frontmatter
- Silent migration from localStorage on first access per type
- Relationship group sorts still use localStorage (no type file)
- Fallback to `modified:desc` when no sort preference exists

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:18:40 +01:00
Test
ec74f86d53 fix: restore theming system after dark-editor merge regression
The merge of the dark-theme-editor feature (cadb350) into the
themes-editable rewrite (19bc3c6) broke the entire theming UI:
themes weren't listed, switching didn't work, and new theme creation
was broken.

Root causes and fixes:
- Stale theme ID from old JSON system ("untitled-2") never cleared:
  added detection that clears IDs not matching any known vault theme,
  with a ref to skip IDs just set by switchTheme/createTheme
- set_active_theme Rust command only accepted String, not Option:
  now accepts Option<String> so null can clear the setting
- Theme colors empty in UI: entryToThemeFile now extracts colors
  from frontmatter content via extractColorsFromContent
- color-scheme/data-theme-mode not set: added updateColorScheme
  and clearColorScheme to sync DOM attributes on theme apply/clear
- isDark broken in Tauri (allContent is {}): moved isDark tracking
  into useThemeApplier as state, updated when vars are applied
- SettingsPanel passed activeThemeId as name to createTheme: fixed
  to call createTheme() with no arguments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:53:00 +01:00
Luca Rossi
d86dfbfcb6 refactor: extract useEditorSaveWithLinks and useNavigationGestures from App.tsx (#186)
App.tsx had 539 lines and 112 git touches in 30 days — highest churn in
the codebase. Two self-contained hooks were defined inline with no
dependency on App internals:

- useEditorSaveWithLinks: wraps useEditorSave to also extract and update
  outgoing wikilinks on save. Moved to src/hooks/useEditorSaveWithLinks.ts.

- useNavigationGestures: registers mouse button 3/4 back/forward and
  macOS trackpad horizontal swipe listeners. Moved to
  src/hooks/useNavigationGestures.ts.

App.tsx shrinks from 539 → 473 lines (-66 lines). Both hooks are now
independently testable and reusable.

Co-authored-by: Test <test@test.com>
2026-03-03 07:10:34 +01:00
Test
818707603e fix: add useIndexing import and hook call, wire indexingProgress and onRemoveVault to StatusBar 2026-03-03 02:48:10 +01:00
Test
bf6312000e feat: add sync conflict resolution — resolve merge conflicts in-app
- 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>
2026-03-03 02:45:42 +01:00
Test
eb77607401 feat: auto-index vault on open + qmd auto-install + status bar progress
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>
2026-03-03 02:37:49 +01:00
Test
5b1804e5e1 feat: vault management — remove vault from list and restore Getting Started
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>
2026-03-03 02:36:33 +01:00
Luca Rossi
2c5cfe2923 feat: sort picker shows custom frontmatter properties (#185)
The sort dropdown now discovers all scalar properties (string, number,
boolean, date) across notes in the current list and shows them below a
separator after the built-in options. Properties that no longer exist
in the current list are gracefully handled by falling back to Modified.

Rust backend extracts custom properties during vault scan so they are
available on every VaultEntry without loading file content on demand.

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 02:31:18 +01:00
Luca Rossi
4d7252c78f feat: add command palette toggles for all BreadcrumbBar panels (#184)
Adds toggle commands to Cmd+K for:
- Toggle Properties Panel (prop/inspector)
- Toggle Diff Mode (diff) — disabled without note changes
- Toggle Backlinks (back) — disabled without note

Updates:
- useCommandRegistry.ts: 5 new commands with proper disabled states
- useAppCommands.ts: wires onToggleDiff and onToggleBacklinks
- Editor.tsx: added diffToggleRef prop (mirrors rawToggleRef pattern)
- App.tsx: creates diffToggleRef, passes to Editor, wires commands

10 new tests in useCommandRegistry.test.ts covering all new commands.

Co-authored-by: Test <test@test.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-03 02:00:48 +01:00
Test
a33a000c57 fix: remove persistLastVault assertions from onboarding test 2026-03-03 00:59:09 +01:00
Test
f0b456bb8c fix: remove stale persistLastVault and unused imports after rebase 2026-03-03 00:57:47 +01:00
Test
b489fa8e3e fix: persist vault list across app updates
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>
2026-03-03 00:57:05 +01:00
Test
1a92b4694c fix: persist last vault path so app reopens correct vault after update
The vault path was stored only in React state (useState), which resets
on every app restart. Now the last active vault path is written to
~/Library/Application Support/com.laputa.app/last-vault.txt on every
vault switch, and loaded on startup. If the saved vault no longer exists,
the existing onboarding flow shows the vault picker instead of silently
falling back to the demo vault.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:33:55 +01:00
Test
6b9ff9a4a2 feat: add "New Type" command to command palette (Cmd+K) 2026-03-03 00:31:10 +01:00
Test
80baa74175 feat: add 'Check for Updates' command to command palette
Users can now trigger an update check from Cmd+K → "Check for Updates"
without leaving the app. Shows toast for up-to-date/error states,
and the existing UpdateBanner for available updates. Command is
disabled while an update is downloading or ready to install.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:53:37 +01:00
Test
f71e6d07e7 feat: rename demo vault from 'Demo v2' to 'Getting Started', remove 'Laputa' vault entry
- Rename 'Demo v2' → 'Getting Started' in vault switcher
- Remove 'Laputa' personal vault from default vault list
- Update default Getting Started vault path from Documents/Laputa to Documents/Getting Started
- Update mock handlers and tests to reflect new vault path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:49:36 +01:00
Test
fd100e1c3b fix: sync changes badge count with list by invalidating stale vault cache
When .laputa-cache.json was committed to git, cloned vaults carried
absolute paths from the original machine. The badge (from get_modified_files)
used fresh local paths while the list filtered entries by stale cached paths,
causing a mismatch.

Three-layer fix:
- Invalidate cache when vault_path differs from current machine (CACHE_VERSION bump)
- Exclude .laputa-cache.json via .git/info/exclude to prevent future commits
- Defense-in-depth: match entries by relative path suffix in NoteList
- Surface error message when modified files fetch fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:29:27 +01:00
Test
2793024904 feat: add Rename section to sidebar context menu
- Add handleRenameSection to useEntryActions: writes/deletes 'sidebar label'
  frontmatter key on the Type note with optimistic in-memory update
- Add InlineRenameInput to SidebarParts: autoFocus input rendered in-place
  of section title, submits on Enter/blur, cancels on Escape
- Add 'Rename section…' as first item in sidebar section context menu
- Wire onRenameSection from App.tsx through Sidebar props
- Add 10 new tests (4 unit, 6 component) covering the full rename flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 23:17:36 +01:00
Test
e239d71a48 fix: add isDark to useThemeManager return value 2026-03-02 23:09:02 +01:00
Test
e2f1fe239e fix: remove stale deriveThemeVariables call and update test assertions after conflict resolution 2026-03-02 23:07:58 +01:00
Test
8495f0e2e6 test: add theme command registry tests and minor fixes 2026-03-02 23:06:12 +01:00
Test
19bc3c67e3 wip: themes-editable — theme management system WIP (13 files, 1014 insertions) 2026-03-02 23:06:12 +01:00
Test
f5bbcb81a4 fix: defer H1 selection to second rAF so content swap completes first
The previous implementation called selectFirstHeading() in the same rAF
as editor.focus(), but the new note's content (applied via queueMicrotask
inside a React effect) hadn't been swapped in yet. React's MessageChannel
scheduler runs the re-render between animation frames, so the heading
block didn't exist in the TipTap document when the selection ran.

Fix: move selectFirstHeading() into a nested requestAnimationFrame inside
doFocus(). Between rAF 1 (focus) and rAF 2 (select), all pending
macrotasks — React's re-render + the queueMicrotask content swap — run
to completion, guaranteeing the H1 block is in the document before we
try to select it.

Updated tests: add rAF mock to the timeout-path select test (which now
needs it since selection is deferred via rAF); add a regression test
that explicitly verifies focus in rAF1 and selection in rAF2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 21:27:26 +01:00
Test
db5e53f77e fix: register Cmd+\ keyboard shortcut to toggle raw editor mode
Cmd+\ was not wired to the raw editor toggle. Added onToggleRawEditor
to KeyboardActions interface and mapped '\\' in the cmdKeyMap so the
shortcut fires handleToggleRaw via the existing rawToggleRef.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 21:02:54 +01:00
Test
185feb5a2c feat: raw editor mode — plain textarea with frontmatter + wikilink autocomplete
Adds a third editor mode (alongside WYSIWYG and Diff) that shows the raw
markdown file in a monospaced textarea. Includes:

- useRawMode hook with derived state (no setState-in-effect) and onFlushPending
- RawEditorView: textarea with 500ms debounce, YAML error banner, wikilink
  autocomplete via [[  trigger, Cmd+S save
- BreadcrumbBar Code icon toggles raw mode; mutual exclusion with diff mode
- Command palette: "Toggle Raw Editor" (View group, requires active tab)
- useEditorModeExclusion hook extracted to keep Editor.tsx under complexity threshold
- buildViewCommands extracted from useCommandRegistry for same reason
- RawToggleButton and RawModeEditorSection components extracted for clean CC

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 18:44:47 +01:00
Test
f04dfdbd37 feat: auto-focus editor with H1 title selected on new note creation
When a new note is created (Cmd+N or via command palette), the editor
immediately focuses and selects all text in the H1 title block, so the
user can start typing the note name right away without clicking.

- signalFocusEditor now accepts { selectTitle?: boolean } and passes it
  in the laputa:focus-editor event detail
- handleCreateNoteImmediate dispatches with selectTitle: true
- useEditorFocus reads selectTitle from event and calls selectFirstHeading
- selectFirstHeading walks the ProseMirror document to find the first
  heading node and uses TipTap's chain().setTextSelection() to select it
- Opening existing notes is unaffected (selectTitle defaults to false)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 18:31:53 +01:00
Test
cadb3500f1 feat: dark theme applies to editor content area
Three changes make the editor respect the active theme:

1. useThemeManager now derives app-specific CSS variables (--bg-primary,
   --text-primary, --border-primary, etc.) from the theme's core colors,
   so the editor's EditorTheme.css variables resolve correctly for both
   light and dark themes.

2. BlockNoteView theme prop is now dynamic (isDark ? 'dark' : 'light')
   instead of hardcoded to 'light', so BlockNote's own UI chrome (menus,
   toolbars) matches the active theme.

3. Removed forced light-mode class removal from main.tsx that was
   preventing dark mode from being applied.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:35:22 +01:00
Luca Rossi
32b8e2ee57 feat: toggle archive/trash shortcuts — Cmd+E unarchives, Cmd+⌫ restores (#175)
Cmd+E and Cmd+Delete now toggle: archiving a normal note or unarchiving
an archived one, trashing a normal note or restoring a trashed one.
Command palette labels update to reflect the current state.

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:55:51 +01:00
Luca Rossi
b75b917538 fix: use openExternalUrl for release notes link in Tauri app (#171)
window.open() doesn't open URLs in the system browser from Tauri's
WebView. Switch to the existing openExternalUrl utility which uses
@tauri-apps/plugin-opener in native mode.

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>
2026-03-02 11:36:44 +01:00
Luca Rossi
24bb64841e fix: customize icon & color works for types without Type entry (#173)
Types without a dedicated Type definition note in the vault silently
failed to save icon/color customizations. Both applyCustomization
(Sidebar) and handleCustomizeType (useEntryActions) returned early
when no Type entry existed. Also fixed a race condition where two
concurrent handleUpdateFrontmatter calls could overwrite each other.

Changes:
- useNoteActions: add createTypeEntrySilent for headless Type file creation
- useEntryActions: auto-create Type entry when missing, serialize writes
- Sidebar: applyCustomization proceeds with defaults when no Type entry
- App: wire createTypeEntrySilent into useEntryActions config

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:22:03 +01:00
Luca Rossi
df2452dcaf fix: back/forward nav arrows reopen replaced tabs instead of skipping them (#172)
handleReplaceActiveTab removes the old tab from the tabs array, but the
old path remained in the navigation history. goBack(isTabOpen) then
skipped it because the tab was no longer open, returning null and making
the buttons appear broken.

Fix: filter by vault entry existence (not tab-open state) and reopen
closed tabs via handleSelectNote when navigating back/forward.

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:00:41 +01:00
Luca Rossi
89d0e39ad2 feat: note templates per type (💡 Note templates per tipo) (#170)
* feat: add template field to type entries and template-aware note creation

- Rust: add template field to Frontmatter, VaultEntry, SKIP_KEYS
- Rust: support YAML block scalar (|) for multi-line strings in frontmatter
- Rust: fix value continuation detection to handle block scalars properly
- TypeScript: add template to VaultEntry, buildNewEntry, frontmatterToEntryPatch
- Add DEFAULT_TEMPLATES for Project, Person, Responsibility, Experiment
- resolveNewNote/buildNoteContent accept optional template parameter
- handleCreateNote and handleCreateNoteImmediate look up type template
- Tests for all new behavior (Rust + TypeScript)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire template UI through Sidebar and App, add TypeCustomizePopover template section

- Add template textarea with debounced save to TypeCustomizePopover
- Wire handleUpdateTypeTemplate through useEntryActions → Sidebar → App
- Add useDebouncedCallback hook for 500ms template save debounce
- Add tests for handleUpdateTypeTemplate and TypeCustomizePopover template UI
- Create design/note-templates.pen placeholder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: useRef type arg + template field in bulk mock entries

* style: rustfmt

---------

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>
2026-03-02 08:37:06 +01:00
Luca Rossi
e3977a6042 feat: contextual AI chat on open note (Cmd+I) (#169)
- Cmd+I toggles AI panel with context from the active note
- Context bar shows note title in AI panel when a note is open
- useAiAgent accepts optional contextPrompt used as system prompt
- ai-context.ts extracts structured context from note + related entries
- Updated AiPanel, EditorRightPanel, App, useAppCommands, useCommandRegistry
- 1292 frontend tests pass, coverage 78.96%

Co-authored-by: Test <test@test.com>
2026-03-02 05:00:29 +01:00
Luca Rossi
4cdc534c01 feat: add daily note command — Cmd+J creates or opens today's journal note (#168)
* feat: add daily note command — Cmd+J creates or opens today's journal note

Adds "Open Today's Note" command accessible via:
- Keyboard shortcut: Cmd+J
- Command Palette (Cmd+K → "Open Today's Note")
- File menu bar entry

If journal/YYYY-MM-DD.md exists, opens it. Otherwise creates it with
Journal type frontmatter and Intentions/Reflections template sections.

Also refactors useNoteActions to extract a shared persistNew callback,
reducing code duplication and keeping CodeScene complexity thresholds green.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: trigger CI for PR #168

---------

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:08:15 +01:00
Luca Rossi
1a93acdce7 fix: show new (untracked) notes in Changes view (#161)
* fix: show new (untracked) notes in Changes view

Two fixes:
1. Use `git status --porcelain --untracked-files=all` so individual
   untracked files in subdirectories are listed (instead of just the
   directory name, which gets filtered out by the .md extension check).
2. Call loadModifiedFiles after persistOptimistic completes, so notes
   created via handleCreateNote/handleCreateType appear in Changes
   immediately without requiring a manual Cmd+S.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: trigger CI for PR #161

---------

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>
2026-03-02 03:07:02 +01:00
Luca Rossi
8d9862ffef feat: allow custom sidebar label for type sections (#165)
* feat: allow custom sidebar label for type sections

- Adds sidebarLabel field to vault type config (Rust + frontend)
- Overrides auto-pluralization with user-defined label in sidebar
- Tests updated to cover custom label display

* fix: add missing sidebarLabel field to buildNewEntry and bulk mock generator

---------

Co-authored-by: Test <test@test.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-02 02:01:21 +01:00
Luca Rossi
f08b807a0c feat: show dynamic build number in status bar (bNNN format) (#163)
* 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>
2026-03-02 01:50:41 +01:00
Luca Rossi
b521736102 fix: preserve scroll position independently per editor tab (#162)
Cache scrollTop alongside blocks in the tab swap cache. On tab leave,
capture the scroll container position; on tab restore, apply it via
requestAnimationFrame after blocks are rendered.

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:50:06 +01:00