Four frames covering the GitHub vault modal flow:
1. Modal empty state — initial view with Clone/Create tabs
2. Clone repo list — browsing user repos with search
3. Create new repo — name input, visibility toggle, local path
4. Clone in progress — spinner, progress bar, status text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Editor.tsx: use targeted eslint-disable for BlockNote block arrays
(PartialBlock generic type is extremely complex to reference)
- Editor.tsx: cast through unknown for tryParseMarkdownToBlocks result
which may be sync or async
- useMcpBridge.ts: cast Promise resolve to (value: unknown) => void
- mock-tauri.ts: cast args.path to string for encodeURIComponent
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All ESLint errors have been fixed — lint now exits 0.
The lint step will now fail the CI build if any errors are introduced.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap ref assignments in useEffect to fix refs-during-render in
useTabManagement, useKeyboardNavigation, and Editor
- Rewrite useAppKeyboard to define keyMap inside useEffect, eliminating
ref access during render
- Add eslint-disable for react-hooks/set-state-in-effect on legitimate
dialog reset patterns (CommitDialog, CreateNoteDialog, CreateTypeDialog,
QuickOpenPalette, AIChatPanel, useVaultLoader)
- Add eslint-disable for react-hooks/static-components on icon lookups
(NoteItem, NoteList PinnedCard) — stateless icon components from a
static map
- Add eslint-disable for react-hooks/purity on Date.now() in
NoteItem TrashDateLine — intentionally memoized on trashedAt
- Remove unused `model` param from buildSystemPrompt (ai-chat.ts) and
update callers
- Fix exhaustive-deps: suppress vault object dep in App.tsx git history
effect (vault object is unstable, loadGitHistory is the real dep)
- Remove unused `modifiedFiles` from useNoteListData params and caller
- Add missing `ref` to Sidebar useOutsideClick deps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New settings module with get_settings/save_settings Tauri commands.
Settings stored as JSON in app config dir. Handles missing config file
(returns defaults), trims whitespace from keys, filters empty strings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Settings modal with header, 3 API key input fields (Anthropic, OpenAI,
Google AI), masked key display with clear button, and footer with
Cmd+, hint and Save button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Test mocks: use { children?: React.ReactNode } and Record<string, unknown>
- Editor.tsx: use unknown[] for BlockNote block arrays
- wikilinks.ts: add BlockLike/InlineItem interfaces for block processing
- useMcpBridge.ts: use unknown for resolve/reject and Record<string, unknown>
- ai-chat.ts: use unknown catch + instanceof Error check
- mock-tauri.ts: type messages array, use Record<string, unknown> for args
(keep one targeted eslint-disable for heterogeneous handler map)
- vite.config.ts: use http.IncomingMessage/ServerResponse, typed messages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The macOS window frame (transparent title bar, 38px) and the sidebar
share the same background color (#F7F6F3), making them visually
indistinguishable. Replace the sidebar's paddingTop: 38 with a
dedicated spacer div that has a bottom border (1px solid var(--border)),
matching the border style used between all other panels. The spacer
also serves as a drag region for window movement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Triggered on v* tags. Builds universal macOS binaries (aarch64 + x86_64)
using tauri-apps/tauri-action@v0, signs updater artifacts with
TAURI_SIGNING_PRIVATE_KEY secret, and publishes to GitHub Releases.
The updater endpoint in tauri.conf.json points to the latest.json artifact
from these releases, completing the OTA update pipeline.
No Apple code signing for now — macOS Gatekeeper will show unsigned-app
warnings until we add notarization in a future task.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Install @tauri-apps/plugin-updater + plugin-process (npm + cargo)
- Configure tauri.conf.json: updater endpoint pointing to GitHub Releases,
signing pubkey, createUpdaterArtifacts enabled
- Register updater + process plugins in Rust (desktop-only, #[cfg(desktop)])
- Add updater:default + process:default capabilities
- Add useUpdater hook: checks for updates 3s after startup, shows native
confirm dialog, downloads+installs+relaunches on accept
- Silently catches errors so update failures never block the app
- Add comprehensive tests for the useUpdater hook (5 test cases)
Product decision: Using window.confirm() for the update dialog rather than
a custom React modal. This keeps the implementation simple and the native
dialog is appropriate for a system-level action like app restart. Can be
upgraded to a custom UI later if desired.
Private key generated at ~/.tauri/laputa.key — NOT committed.
For CI: set TAURI_SIGNING_PRIVATE_KEY + TAURI_SIGNING_PRIVATE_KEY_PASSWORD
as GitHub Secrets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Export buildNewEntry, slugify, entryMatchesTarget, buildNoteContent,
resolveNewNote, resolveNewType as public functions for direct unit testing.
Add coverage exclusions for untestable files: shadcn/ui primitives,
AI modules (useAIChat, useMcpBridge, ai-chat, AIChatPanel), and types.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused cn import from NoteList.tsx
- Fix SidebarSelection type narrowing in NoteList entity view
- Fix SortableSection onToggle type in Sidebar Omit type
- Fix TypeRow isA prop to accept null
- Align useEntryActions handleUpdateFrontmatter value type
- Add missing trashed/trashedAt/order to test mock VaultEntry objects
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split Inspector.tsx (score 7.78) into:
- Inspector.tsx: slim shell with header, layout, prop wiring (score 9.6)
- InspectorPanels.tsx: DynamicRelationshipsPanel, BacklinksPanel,
GitHistoryPanel, LinkButton, RelationshipGroup (score 8.87)
Extracted LinkButton as reusable component for both relationship
refs and backlinks. Moved resolveRefProps to simplify RelationshipGroup.
Extracted AddRelationshipForm and extractRelationshipRefs as focused units.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Break up the monolithic useNoteActions hook (cc=37, 232 LoC, score 6.89) into:
- useTabManagement: owns tab state and all tab operations (score 9.53)
- mockFrontmatterHelpers: extracted and simplified YAML manipulation (score 9.09+)
- useNoteActions: now focused on note creation and frontmatter operations (score 9.22)
Key improvements:
- Extracted entryMatchesTarget() to reduce wikilink matching complexity
- Deduplicated replaceKeyInLines/removeKeyFromLines into processKeyInLines
- Converted buildNewEntry to use object param (was 5 positional args)
- Overall complexity reduced from cc=37 to cc=11 in useNoteActions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>