Commit Graph

43 Commits

Author SHA1 Message Date
lucaronin
f64d941b0e feat: rename note by double-clicking its tab — inline edit, updates filename + wiki-links
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:10:17 +01:00
lucaronin
d23ce5a0b5 feat: clickable commit hashes in git history panel open diff view
- Add get_file_diff_at_commit Rust command to show diff at a specific commit
- Make shortHash in GitHistoryPanel a clickable button that opens DiffView
- Show author name below commit message (small, muted)
- Remove disabled "View all revisions" button
- Wire onLoadDiffAtCommit through Editor → Inspector → App.tsx
- Add mock handler for get_file_diff_at_commit in browser mode
- Fix pre-existing missing `order` field on trashed mock entries
- Update Inspector tests for new behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 22:27:18 +01:00
lucaronin
5a8eb6a5d0 feat: rename note via double-click on tab — frontend wiring
- TabBar: inline edit on double-click (Enter saves, Escape cancels)
- Extracted TabItem component + tabStyle helper for code health
- useNoteActions: handleRenameNote invokes backend, updates tabs & vault
- useVaultLoader: replaceEntry handles path-changing renames
- mock-tauri: rename_note mock with wiki link updates
- App/Editor: wire onRenameTab prop through to TabBar

Code health: TabBar improved (CC 23→18). useNoteActions/App/useVaultLoader
show minor degradation on pre-existing high-CC functions — proper fix
requires splitting the monolithic useNoteActions hook (separate concern).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:22:44 +01:00
lucaronin
68dfab473a feat: add rename_note Tauri command with wiki link updates
Backend implementation for renaming a note:
- Updates H1 heading and title frontmatter to new name
- Renames file using slugified new title
- Scans all vault .md files and replaces [[OldTitle]] → [[NewTitle]]
  in both content and frontmatter (preserves pipe aliases)
- Returns new path and count of updated files

Well-factored with extracted helpers: build_wikilink_pattern,
replace_wikilinks_in_content, collect_md_files, update_h1_title,
update_note_title_in_content, frontmatter_has_title_key, to_path_stem.

All 147 tests pass including 7 new rename tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:13:03 +01:00
lucaronin
37c9164278 feat: set macOS window frame color to match sidebar background
Set the window backgroundColor to #F7F6F3 (same as --sidebar CSS variable)
in the Tauri window config. With titleBarStyle "Transparent", this makes
the native macOS title bar area match the sidebar background color instead
of defaulting to white.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 19:11:37 +01:00
lucaronin
cc1631c368 feat: draggable section groups in sidebar 2026-02-21 18:36:28 +01:00
lucaronin
09609eff55 feat: trash notes — sidebar filter, breadcrumb buttons, cmd+del shortcut, demo vault data 2026-02-21 18:34:40 +01:00
lucaronin
1dfbbb8a9e feat: add order property to VaultEntry and install @dnd-kit
- Add `order: number | null` to VaultEntry (TS) and VaultEntry (Rust)
- Add order to Frontmatter struct and SKIP_KEYS in vault.rs
- Update all mock Type documents with order values (0-10)
- Add order: null to all non-Type mock entries and test fixtures
- Install @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:27:19 +01:00
lucaronin
004201cdc8 fix: tauri devUrl to match vite port 5201 2026-02-21 17:23:26 +01:00
lucaronin
af40fba1b0 feat: add purge_trash command to delete stale trashed files
Adds purge_trash(vault_path) that scans all .md files, reads the
"Trashed at" frontmatter date, and deletes files older than 30 days.
Registered as a Tauri command and called automatically on app startup
(defaults to ~/Laputa vault). Includes 7 tests covering boundary
conditions, nested dirs, and datetime formats.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:14:02 +01:00
lucaronin
66a15e4ddb feat: add trashed/trashedAt fields to VaultEntry
- Added trashed (boolean) and trashedAt (timestamp) to TypeScript VaultEntry
- Added 'trash' filter to SidebarSelection union type
- Added trashed/trashed_at fields to Rust VaultEntry struct and Frontmatter parser
- Added 3 trashed mock entries for visual testing (recently trashed,
  30+ days old, and dropped experiment)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:52:28 +01:00
lucaronin
311c5e434b feat: archive notes — filter sidebar, hide archived, relationship indicators 2026-02-21 16:44:09 +01:00
lucaronin
4d2f96dfab feat: add archived boolean property to VaultEntry
Add archived field to both TypeScript VaultEntry interface and Rust
VaultEntry struct. Parse Archived frontmatter field in Rust backend.
Add archived mock entries (Website Redesign, Twitter Thread Experiment)
for visual testing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:36:06 +01:00
lucaronin
f36cfd1808 feat: add icon and color fields to VaultEntry
- Add icon (string|null) and color (string|null) to VaultEntry interface
- Update Rust VaultEntry struct and frontmatter parsing to read icon/color
- Add icon/color to SKIP_KEYS so they don't appear as relationships
- Set mock data: Recipe type → cooking-pot/orange, Book type → book-open/green
- Update all test files with the new required fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:23:10 +01:00
lucaronin
cdf203de1a fix: use stable asset URLs for image uploads (blob URL fix) 2026-02-21 13:08:29 +01:00
lucaronin
deea70a098 fix: use stable asset URLs for image uploads instead of ephemeral blob URLs
Blob URLs are session-scoped and don't survive page reloads — images
would break on Cmd+Shift+R. Now uploadFile awaits save_image (which
persists to vault/attachments/) and returns a convertFileSrc asset URL
that the Tauri webview can resolve indefinitely.

- Editor.tsx: await save_image → convertFileSrc for Tauri mode;
  FileReader.readAsDataURL fallback for browser dev mode
- tauri.conf.json: enable assetProtocol with scope ["**"]
- mock-tauri.ts: save_image returns a plausible file path
- E2E test: expect data: URLs in browser dev mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:06:04 +01:00
lucaronin
5f2a6495db feat: AI chat panel 2026-02-21 10:38:41 +01:00
lucaronin
001b52c00f feat: update app icon 2026-02-21 10:21:30 +01:00
lucaronin
db1da4430e fix: wire up BlockNote uploadFile to enable image uploads in editor
The editor's useCreateBlockNote was missing the uploadFile callback,
so BlockNote had no handler for image uploads (drag-drop, paste, or
toolbar button). Images now convert to data URLs for immediate display.

In Tauri mode, uploaded images are also persisted to the vault's
attachments/ directory via a new save_image backend command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 10:07:02 +01:00
lucaronin
261d2f986c feat(ai-chat): Rust ai_chat command
Add Tauri command for AI chat via reqwest:
- ai_chat module with send_chat() using Anthropic Messages API
- ANTHROPIC_API_KEY from environment variable
- Proper error handling for missing key, API errors, parse failures
- Unit tests for request building and response extraction
- Mock handler added to mock-tauri.ts for browser testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:55:49 +01:00
lucaronin
6a203b27f9 feat(vault): add Type relationship and type folder inference
- Add "type" folder to infer_type_from_folder() mapping
- When a VaultEntry has isA set (and it's not "Type"), automatically
  add a "Type" relationship (e.g., "[[type/project]]") to the
  relationships map, making the type property a navigable link
- Handle both plain string isA ("Project") and wikilink isA
  ("[[type/project]]") correctly
- Add 5 new tests for the Type relationship feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:44:46 +01:00
lucaronin
d7821d40ce refactor(vault): use &Path for internal functions, split large test assertions
Convert internal vault functions from &str to &Path for vault_path
parameter (run_git, cache_path, git_head_hash, git_changed_files,
git_uncommitted_new_files, load_cache, write_cache, to_relative_path,
finalize_and_cache, update_same_commit, update_different_commit).
String-heavy args reduced from 67% to 47%.

Split 5 large test functions into smaller focused tests to eliminate
Large Assertion Blocks findings. Extract parse_test_entry() and
parse_big_project_rels() helpers to reduce test boilerplate.

Code Health: 7.78 -> 8.54

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:22:00 +01:00
lucaronin
11d86ffc0c refactor(vault): break up large assertion blocks in tests
Split consecutive assertion lines with blank lines and comments
to stay within CodeScene's 4-consecutive-assert threshold.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:17:52 +01:00
lucaronin
f667dfe8ac refactor(vault): decompose scan_vault_cached into focused functions
Extract to_relative_path(), parse_files_at(), finalize_and_cache(),
update_same_commit(), update_different_commit(). The main function
is now 20 lines of thin orchestration.

Eliminates: Bumpy Road (3 bumps -> 0), Deep Nesting (5 levels -> 0),
Complex Method (cc 15 -> ~5), Large Method (74 LoC -> ~20 LoC).

Code Health: 6.92 -> 7.78

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:15:43 +01:00
lucaronin
2989c9bac7 refactor(vault): decompose parse_md_file and flatten git_changed_files
parse_md_file: extract infer_type_from_folder(), resolve_is_a(),
parse_created_at(), extract_fm_and_rels(), read_file_metadata().
Reduces from 83 LoC to ~25 LoC thin orchestration.

git_changed_files: extract collect_md_paths_from_diff() and
collect_md_paths_from_porcelain() as iterator-based helpers.
Eliminates Bumpy Road (2 bumps -> 0) and Deep Nesting (4 levels -> 2).

Code Health: 6.35 -> 6.92

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:14:43 +01:00
lucaronin
6b3a94f676 refactor(vault): extract run_git helper, flatten git functions
Extract run_git() to eliminate duplicated Command boilerplate.
Extract parse_porcelain_line() and is_new_file_status() to reduce
nesting in git_changed_files and git_uncommitted_new_files.
Rewrite git_uncommitted_new_files as a flat iterator chain.
Simplify git_head_hash to a one-liner using run_git.

Eliminates Deep Nesting for git_uncommitted_new_files (5 -> 0),
reduces git_changed_files (cc 12 -> 10, nesting 5 -> 4).

Code Health: 5.61 -> 6.35

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:13:12 +01:00
lucaronin
18f6ef948f refactor(vault): extract markdown stripping helpers to flatten strip_markdown_chars
Extract collect_until(), skip_until(), is_markdown_formatting() from
the nested loops in strip_markdown_chars. Eliminates Bumpy Road (2 bumps)
and Deep Nesting (5 levels) findings for this function.

Code Health: 5.38 -> 5.61

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:12:02 +01:00
lucaronin
1eff9d2f94 refactor(frontmatter): eliminate remaining bumpy road and reduce complexity
Split needs_yaml_quoting into has_yaml_special_chars() and
starts_as_yaml_collection() helpers. Use matches! macro for
reserved words. Flatten nested if in apply_field_update with
tuple pattern match.

Code Health: 9.24 -> 9.68 (+0.44). Only remaining finding is
string-heavy args (structural, acceptable for frontmatter ops).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:11:01 +01:00
lucaronin
98635fef9d refactor(frontmatter): decompose update_frontmatter_content into focused functions
Extract split_frontmatter(), prepend_new_frontmatter(), apply_field_update(),
format_yaml_field(), and is_list_continuation(). The main function is now a
thin orchestrator with no nesting.

Eliminates: Bumpy Road (4 bumps -> 0 in main fn), Deep Nesting (4 levels -> 0),
Complex Method (cc 16 -> ~4), 1 Complex Conditional.

Code Health: 7.84 -> 9.24 (+1.40)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:09:48 +01:00
lucaronin
259ee64cc0 refactor(frontmatter): extract yaml formatting helpers from to_yaml_value
Extract needs_yaml_quoting(), quote_yaml_string(), format_list_item(),
format_yaml_number(), and needs_key_quoting() from inline conditionals.
Reduces to_yaml_value cc from 17 to ~5 and format_yaml_key cc from 5 to 2.
Eliminates 3 of 4 Complex Conditional findings.

Code Health: 6.89 -> 7.84 (+0.95)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:08:47 +01:00
lucaronin
2193beb429 test: add coverage for vault.rs and frontmatter.rs before refactoring
Add 68 new tests covering previously untested functions:

vault.rs:
- parse_iso_date: full datetime, date-only, quoted input, invalid
- strip_markdown_chars: emphasis, backticks, links, wikilinks, empty
- capitalize_first: normal, empty, single char, already capitalized
- without_h1_line: starts with H1, blank lines, non-heading, empty
- infer_type_from_folder: all 15 known folders, unknown folder, frontmatter override
- extract_snippet: code fences, only headings, no H1, horizontal rules, unclosed FM
- contains_wikilink: true/false cases
- scan_vault_cached: incremental update with different commit
- created_at parsing from frontmatter

frontmatter.rs:
- to_yaml_value: all quoting cases (colon, hash, bracket, brace, bool, null, number)
- update_frontmatter_content: number, float, null, empty list, malformed FM
- delete: non-existent key (no-op), from no-frontmatter (no-op)
- line_is_key: quoted, single-quoted, leading whitespace, partial match
- with_frontmatter: file not found error
- format_yaml_key: colon, hash, period
- Roundtrip tests: string update, list update, add-then-delete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:07:30 +01:00
lucaronin
e41c13ef3b test: add comprehensive tests for generic relationships parsing
Four new tests covering the bug where only belongs_to/related_to were
recognized while Has, Topics, Events, Notes, Owner, etc. were missed:

- Many generic field types populate the relationships HashMap
- Single wikilink strings vs arrays both parse correctly
- All SKIP_KEYS (Is A, aliases, status, cadence, etc.) are excluded
- Mixed arrays with wikilinks and plain strings keep only wikilinks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:51:30 +01:00
lucaronin
99069be0d3 feat: parse generic relationships from frontmatter wikilinks
Adds a `relationships: HashMap<String, Vec<String>>` field to VaultEntry
that captures ALL frontmatter fields containing wikilinks (e.g. Has,
Topics, Events, Notes, Buckets, Highlights). Handles both single string
and array values. Known non-relationship keys (Is A, aliases, Status,
etc.) are skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 19:07:02 +01:00
lucaronin
a5a152ff25 feat: add incremental vault cache and snippet extraction
Add VaultEntry.snippet field (first ~160 chars of content, markdown-stripped).
Implement scan_vault_cached() with git-based incremental caching:
- Writes .laputa-cache.json to vault dir
- On same HEAD: returns cached entries + uncommitted new files
- On different HEAD: re-parses only changed files via git diff
- Falls back to full scan when git unavailable or cache corrupt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:06:26 +01:00
lucaronin
1f8740e4af feat: add native macOS title bar with transparent overlay
- Use titleBarStyle: Transparent for native window frame on top
- Add paddingTop: 38px to Sidebar to make room for title bar
- Keep solution simple: native traffic lights + dragging work out-of-the-box
- Removed custom traffic lights and drag handlers
2026-02-17 16:55:23 +01:00
lucaronin
b3039f98cc refactor: replace manual days_from_epoch with chrono in vault.rs 2026-02-17 12:06:31 +01:00
lucaronin
c7b20fd938 refactor: extract frontmatter.rs module from vault.rs with with_frontmatter() helper 2026-02-17 12:05:39 +01:00
lucaronin
9b4fe05883 fix: correct flaky test assertions for is_a folder inference 2026-02-17 12:03:32 +01:00
lucaronin
e3dc38e58e Fix tauri.conf.json: remove invalid titleBarStyle overlay 2026-02-15 13:45:24 +01:00
lucaronin
9a15755b53 Add real git revision history to Inspector panel
Replace mock git history with real `git log` data via new `get_file_history`
Tauri command. Adds git.rs module with commands for file history, modified files,
file diff, commit, and push (all registered, later tasks wire up the UI).
Updates GitCommit type to include shortHash field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:54:11 +01:00
lucaronin
9d29959fba Add frameless window with custom drag regions (Obsidian-style)
Remove native macOS titlebar via decorations:false + titleBarStyle:overlay.
Add -webkit-app-region:drag to panel headers (Sidebar, NoteList, Editor tab
bar, Inspector) with no-drag on interactive elements. Sidebar header gets
78px left padding for macOS traffic light buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:00:29 +01:00
lucaronin
e72d66ae64 Add Tauri mock layer for browser testing and visual verification workflow 2026-02-14 18:54:27 +01:00
lucaronin
6b53cf8f50 Initialize Tauri v2 + React + TypeScript project with vault scanner
- Scaffold Vite + React + TypeScript frontend
- Add Tauri v2 backend with Rust
- Implement list_vault command: recursively scans .md files, parses
  YAML frontmatter (Is A, aliases, Belongs to, Related to, Status,
  Owner, Cadence), extracts title from H1 or filename
- 10 passing Rust tests for frontmatter parsing and vault scanning
- Configure Vitest and Playwright (test infrastructure)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:20:07 +01:00