Commit Graph

21 Commits

Author SHA1 Message Date
d6bf9ed245 refactor(frontend): migrate JS modules to TypeScript
Wholesale JS -> TS migration of the frontend — stores, utils, actions,
and all Svelte component scripts adopt type annotations. Compile-time
surfaces (app.d.ts, lib/types/) added for shared DTO types.

Build plumbing:
  - package.json: dev:frontend script that runs svelte-kit sync first
  - tauri.conf.json: beforeDevCommand points at dev:frontend
  - run.sh: dropped the sed-hack that temporarily blanked beforeDevCommand;
    now relies on npm run dev:frontend to avoid double-Vite
  - jsconfig.json: allowImportingTsExtensions

Preserves all Group 1 behaviour:
  - page.svelte.ts keeps loadHistory / loadTasks Tauri-first, no
    localStorage; saveTranscriptMeta + mapTranscriptRow + mapTaskRow
    intact; update_task_cmd and update_transcript_meta_cmd invocations
    carry the correct payload shape.
  - Toasts, preferences stores typed without behaviour change.
  - Viewer still routes segment edits through saveTranscriptMeta; the
    Task 1.5 TODO markers are gone.

taskExtractor.ts is functionally improved during the migration:
  - multi-task matches in the same sentence
  - list-style shopping-verb expansion (get bread, milk, and cheese)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:05:54 +01:00
ea48d03cee agent: dogfood polish 2026/04/19 — Linux native chrome + History redesign + mic picker cleanup
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Second dogfood sprint. Headline fix: Linux now uses native KWin/Mutter
decorations instead of fragile frameless `startResizeDragging`, which
collapsed diagonal corner resize to a single axis and made drag feel
laggy. macOS / Windows keep custom chrome via `useCustomChrome` gate.

Other changes:

- Cross-window preferences sync via `kon:preferences-changed` Tauri
  event — theme and font changes propagate live to float/viewer.
- Hotkey recorder rewritten to use capture-phase document listener
  gated by $effect; button focus was unreliable in webkit2gtk.
- History page redesigned for cognitive-load hygiene: title-first
  compact row, inline title input, Edit popout opening /viewer in
  edit mode, clipboard export as .md with YAML frontmatter, manual
  tag chips + + Add tag input, header tag filter (cap 7), global
  Starred filter, `tag:xyz` search syntax.
- `deriveAutoTags` kept as empty hook for post-Task-7 LLM topic tags;
  research found all previous auto-tag chips redundant with row UI.
- Viewer window adds edit mode with debounced-save textarea; native
  title renamed to "Kon - Transcription Editor".
- Window minimums updated per GNOME HIG + WCAG reflow research:
  main 960x600, float 360x480, editor 560x520.
- Microphone picker filters raw ALSA strings (hw:, plughw:, front:,
  sysdefault:, null) and dedupes by CARD=X. New `description` field
  on DeviceInfo reads /proc/asound/cards so Blue Yeti shows as "Blue
  Microphones" instead of the short "Microphones" card name.
- GPU reporting fixed: get_runtime_capabilities now returns
  accelerators=[cpu,vulkan] and whisper.supports_gpu=true, matching
  the transcribe-rs whisper-vulkan feature linked unconditionally.
- ResizeHandles kept for macOS/Windows frameless: 12px edges, 20px
  corners via CSS vars, pointerdown + setPointerCapture, corners
  above edges in z-order, rendered as sibling (not child) of the
  animated layout root so `position: fixed` is viewport-relative.
- Dueling drag-region handlers removed — `data-tauri-drag-region` and
  manual `startDragging()` were stacked on the same elements; kept
  the manual handler which has the button/input early-return logic.

See HANDOVER.md for the full session log and deferred items.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:30:42 +01:00
d959a82a4b fix(ui): remove cursor-following recording dot — distracting and redundant with status bar indicator 2026-04-19 10:16:53 +01:00
0b1faf0679 fix: suppress stub dead-code warnings; clarify update toast copy
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
2026-04-18 09:45:37 +01:00
8b5d92f466 feat(updater): wire tauri-plugin-updater with GitHub releases endpoint + update toast 2026-04-18 09:41:42 +01:00
Claude
ebf449b47b qa: restore boot, wire dead error rx, harden storage and config
Front-to-back QC pass turned up two independent missing-module
showstoppers (workspace did not compile; frontend did not load) plus a
handful of HANDOVER-claimed features that were wired but dead. Fixes:

P0 — gets the app booting again:
  - Add the never-committed src/lib/utils/runtime.js (hasTauriRuntime
    detection); 5 imports were resolving to nothing.
  - Add the never-committed crates/audio/src/streaming_resample.rs
    (rubato-backed StreamingResampler with new/push_samples/flush);
    declared in lib.rs and used 3x by live.rs but had no impl.
  - Drop the duplicate hasTauriRuntime import in routes/+layout.svelte.
  - Allow the transcript-viewer window to use the default capability
    (was missing from capabilities/default.json:windows, so the viewer
    window could open but not invoke any Tauri command).

P1 — features documented as working but actually dead:
  - Pump MicrophoneCapture::take_error_rx() into LiveStatusMessage::
    Warning each loop iteration in commands/live.rs. The HANDOVER
    promised cpal stream errors would surface as toasts; the channel
    was created and never read.
  - Replace .expect() on the WebKit media-permission setup with a
    logged warning. Failure no longer aborts the whole process.
  - Toast on save_preferences failure (preferences.svelte.js had a
    silent console.error — now warns once per failure run via the
    existing toasts store).

P2 — correctness/robustness:
  - add_dictionary_entry: switch INSERT OR IGNORE to ON CONFLICT
    DO UPDATE ... RETURNING id so duplicate terms get the real row id
    instead of a stale auto-increment.
  - search_transcripts: qualify ORDER BY fts.rank.
  - InsertTranscriptParams + TranscriptRow: bump sample_rate /
    audio_channels from i32 to i64 to match the Tauri DTO and avoid
    silent truncation at the boundary.
  - Drop the unused tauri-plugin-mcp dependency.
  - Promote sqlx in src-tauri/Cargo.toml from linux-only to
    unconditional (lib.rs names sqlx::SqlitePool unconditionally —
    macOS/Windows builds were latently broken).
  - hotkey/linux.rs: stop panicking the hotplug task on inotify
    failure; degrade to "no hotplug" with a stderr warning.
  - layout.svelte: store the global error/unhandledrejection handler
    refs and remove them in onDestroy so HMR/window teardown doesn't
    leak listeners.

Verified: cargo check -p kon-core -p kon-storage -p kon-cloud-providers
passes. cargo check on src-tauri/kon-audio/kon-hotkey requires alsa +
gtk system libs not present in this sandbox; their changes are
syntactically and type-checked against the rest of the workspace.
svelte-check requires npm install which is not available here.

https://claude.ai/code/session_018ozAs4UcRC8jbJbddqJtEw
2026-04-18 02:00:26 +00:00
4e6ca0ed96 platform: fix macOS data path + add get_os_info + frontend osInfo helper
CROSS-PLATFORM AUDIT:
- Linux x86_64 (Fedora 43, KDE Wayland): HIGH confidence (the dev target)
- Linux other distros / X11: MEDIUM (tested patterns, untested distros)
- Windows 10/11: LOW — theoretically supported via Tauri + CPAL + whisper.cpp
  + tauri-plugin-global-shortcut (the custom evdev hotkey is no-op on
  Windows); has had zero hands-on testing
- macOS Apple Silicon / Intel: LOW — same; macOS Info.plist needs
  NSMicrophoneUsageDescription for the bundled app, and the path bug
  fixed in this commit

REAL BUG FIXED — macOS app_data_dir was Unix-style:
crates/storage/src/file_storage.rs::app_data_dir() previously fell into
the "Unix" branch on macOS and wrote to ~/.kon/, which violates Apple
guidelines and confuses install/uninstall tooling. Now correctly:
- Windows: %LOCALAPPDATA%/kon (unchanged)
- macOS: ~/Library/Application Support/Kon/
- Linux: $XDG_DATA_HOME/kon or ~/.local/share/kon (XDG Base Directory),
         with legacy ~/.kon/ fallback so existing installs keep working
- Other Unix: ~/.kon/ (unchanged)

OS DETECTION LAYER:
- New get_os_info Tauri command in commands/diagnostics.rs returns:
  {os, arch, family, usesCmd, isWayland, customHotkeyBackend,
   primaryModifierLabel}
- New src/lib/utils/osInfo.js helper:
  - async loadOsInfo() warms a cache, called once at root layout mount
  - then isMac() / isWindows() / isLinux() / modKeyLabel() / isWayland()
    are synchronous
  - browser-preview fallback reads navigator.platform
- Lets components localise hotkey labels (Cmd vs Ctrl), file-picker
  copy ("Open Finder" vs "Open Explorer"), etc, without recomputing in
  every place.

cargo check -p kon-storage clean. Updated HANDOVER-2026-04-17.md with
a per-platform confidence table.
2026-04-17 13:52:58 +01:00
62ea58d95a diagnostics: panic hook + frontend error capture + Settings → About diagnostic report
THE BRIEF:
For the friends beta we need verbal feedback AND technical feedback —
some bugs the user cannot describe but a stack trace can. Built it in
two layers, with Layer 3 deferred until there is real volume.

PRIVACY POSTURE (matches Kon's local-first positioning):
- All capture is to disk only. Nothing is transmitted.
- The manual report bundler shows the user exactly what would be
  shared and lets them choose to copy / save it.
- No remote endpoint, no Sentry, no opt-out telemetry.

LAYER 1 — Always-on local capture:
- Rust panic hook (commands/diagnostics.rs::install_panic_hook) writes
  each panic to ~/.kon/crashes/<unix-ts>-<short-id>.crash. Captures
  thread name, OS/arch, RUST_BACKTRACE state, and the panic info.
  Installed before tauri::Builder so it catches setup-time panics too.
- Frontend window.onerror + window.unhandledrejection in
  src/routes/+layout.svelte forward to the new log_frontend_error
  Tauri command, which inserts into the existing error_log SQLite
  table. Best-effort: errors in the error handler itself are swallowed
  so logging can never crash the app.
- Existing error_log table (migration v1) is now actually used —
  closes the TODO from crates/storage/src/database.rs:409.

LAYER 2 — Manual diagnostic report:
- Settings → About → Diagnostics section: Generate report → Preview →
  Copy / Save.
- Report is plain markdown so it pastes cleanly into email, Discord,
  GitHub issues. Sections: app version + OS, sanitised settings JSON,
  recent error_log rows, last 5 crash dumps with previews, log file
  tail (8KB).
- Preview is shown in a <details> with the full text the user can
  inspect before deciding to share.
- Save writes to ~/.kon/diagnostic-reports/kon-diagnostic-<ts>.md.

NEW FILES:
- src-tauri/src/commands/diagnostics.rs (panic hook + 5 Tauri commands)

CHANGES:
- crates/storage/src/file_storage.rs: crashes_dir() + logs_dir() helpers
- crates/storage/src/database.rs: ErrorLogRow + list_recent_errors()
- crates/storage/src/lib.rs: re-exports
- src-tauri/src/commands/mod.rs: + diagnostics module
- src-tauri/src/lib.rs: install_panic_hook() before Builder; 5 new
  Tauri commands registered (log_frontend_error,
  list_recent_errors_command, list_crash_files,
  generate_diagnostic_report, save_diagnostic_report)
- src/routes/+layout.svelte: installGlobalErrorCapture() at mount
- src/lib/pages/SettingsPage.svelte: diagnostic state + buttons +
  preview block at the end of the About section

cargo check -p kon-storage clean. Settings.svelte if/each balanced.

LAYER 3 (deferred):
- Optional opt-in remote reporting (self-hosted Sentry on Tartarus or
  similar). Not for friends beta. Open up after volume justifies it.
2026-04-17 13:47:20 +01:00
69d768e803 ui: Day 3 — global toast system + first error-toast wiring on DictationPage
THE PROBLEM (Codex review + architecture-review.md §1, §14):
Multiple critical paths discard errors silently — `let _ = insert_transcript(...)`,
`.catch(() => {})`, inline `error = ...` state that not every page surfaces. ND
users in particular need explicit feedback when something fails; silent
failure is worse than no feature.

SHIPPED:

src/lib/stores/toasts.svelte.js (new):
- Minimal in-house toast store (~80 lines, no svelte-french-toast dep)
- Severity → palette: info/success → moss, warn → signal, error → ember
- Auto-dismiss durations per severity (success 3s, info 4s, warn 6s,
  error sticky)
- `invokeWithToast(invoke, command, args, errorTitle?)` helper wraps a
  Tauri invoke and toasts on failure while still throwing for callers
  that need to handle the error themselves

src/lib/components/ToastViewport.svelte (new):
- Reads from the toasts store
- Bottom-right stack, max-width clamp on small screens
- aria-live=polite + role=alert on error toasts (screen-reader friendly)
- Slide-in animation honours `html.reduce-motion` for the existing
  preferences toggle
- Severity left-border in brand colours via existing CSS variables

src/routes/+layout.svelte:
- Mounts <ToastViewport /> once at the app root so toasts work from any
  page or window

src/lib/pages/DictationPage.svelte:
- First error-toast wiring: failures starting recording now show a
  sticky toast in addition to the inline `error` panel
- Replaces a previously easy-to-miss failure-mode

NEXT (Day 4 batch):
- Wire toasts into FilesPage, HistoryPage, SettingsPage, ModelDownloader
  (all currently swallow errors)
- Add `add_transcript`, `list_transcripts`, `update_transcript` (closes the
  long-standing TODO Codex flagged), `delete_transcript` Tauri commands
  wrapping the existing storage layer
- Switch addToHistory to dual-write (localStorage + SQLite) so the
  canonical store catches up with the actual transcript flow
- FTS5 transcripts_fts virtual table + search command
- Wrap multi-row writes (decompose_and_store) in DB transactions
2026-04-17 13:06:36 +01:00
fdc4a3cba5 agent: fix — infinite reactivity loop in TaskSidebar froze entire app
prevTaskIds was declared as $state, causing the $effect that writes to
it to re-trigger itself infinitely (effect_update_depth_exceeded). The
variable is just a comparison reference — doesn't need to be reactive.
Changed to a plain let.

Also removed debug event loggers and reverted grain z-index.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:56:54 +01:00
1a8f3c7582 agent: fix — remove blocking backdrop from task sidebar entirely
The invisible z-40 overlay was still eating pointer events across the
main content. Removed the backdrop — sidebar now floats without blocking
anything. Close with Escape key.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:46:25 +01:00
e08e118e00 agent: fix — task sidebar overlay no longer blocks entire app
The full-screen backdrop (fixed inset-0 z-40) was eating all pointer
events, making the app unusable when the task sidebar was open. Replace
with a backdrop that only covers the content area (not titlebar) and
sits beside the sidebar rather than wrapping it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:42:06 +01:00
8e70cf9ff9 agent: wayland — evdev hotkey backend, download resume, SHA256 integrity
Add kon-hotkey crate with evdev-based global hotkey capture that works on
Wayland (and X11). Patterns from whisper-overlay: per-device async listeners,
inotify hotplug with udev permission retry, watch channel for live config
updates. Frontend detects Wayland at startup and selects evdev or
tauri-plugin-global-shortcut automatically.

Model downloads now support HTTP Range resume for interrupted downloads and
optional SHA256 integrity verification (incremental, no second pass).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:50:48 +01:00
jake
c5164c292f agent: layout — wire preferences store to layout, replace class-based theme toggle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:43:28 +00:00
jake
3f6d718bb2 feat(kon): collapsible sidebar — toggle with [ key, auto-collapse below 900px, icons-only mode
- Add sidebarCollapsed to settings defaults (persists via localStorage on saveSettings)
- Sidebar collapses to 48px icons-only view with smooth 200ms transition
- Toggle button (chevron) at top of nav; [ keyboard shortcut in layout (input-safe)
- Auto-collapse on window resize below 900px (checked on mount and on resize event)
- Titlebar left spacer tracks sidebar width reactively (48px / 210px)
- All labels, profile selector, status text hidden in collapsed mode; nav items show tooltips via title attribute

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:26:08 +00:00
jake
11bf7163da fix(kon): hotkey event mismatch — layout now dispatches kon:toggle-recording
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:09:48 +00:00
jake
c5b2767ad8 fix(kon): task sidebar overlay click handling
- Backdrop tint div has direct onclick to close sidebar
- Sidebar panel uses stopPropagation so clicks inside don't close
- Outer container uses target check for self-click dismiss
- Svelte 5 compatible (no |self modifier)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:33:54 +00:00
jake
fe3739fdbb fix(kon): task sidebar overlay, Parakeet model management, conditional engine settings
TaskSidebar:
- Changed from flex layout member to fixed overlay with backdrop
- Click backdrop or press Escape to close
- Content no longer shrinks when sidebar opens — buttons stay accessible
- Positioned at z-50 over main content, top offset for titlebar

Settings — Parakeet model management:
- Added Parakeet model state: download, check, load status
- New downloadParakeet() and loadParakeet() functions
- Listens for parakeet-download-progress events
- Parakeet section shows download/load/status controls

Settings — conditional engine sections:
- Whisper model selector only shows when engine === "whisper"
- Parakeet model controls only show when engine === "parakeet"
- Cleaner UI — only active engine's options visible

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:26:27 +00:00
jake
1ad2b55d9c fix(kon): float window sidebar, transcription doubling guard, branding
Float window fixes:
- Root layout now detects /float and /viewer URLs and hides Sidebar,
  Titlebar, TaskSidebar for secondary windows. Belt-and-braces fix
  since +layout@.svelte should handle this but may not in SPA mode.
- Float window title: "Ramble - To-do" → "Kon - To-do"

Transcription doubling guard:
- Added chunk_id deduplication set in DictationPage — if a chunk_id
  has already been processed, skip the duplicate result
- Set cleared on each new recording session

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:07:30 +00:00
jake
904d5fdb95 feat(kon): add first-run hardware probe and model recommendation wizard
- New probe_system command: returns RAM, CPU, OS info
- New rank_models command: scores models against detected hardware
- FirstRunPage.svelte: hardware summary, ranked model list with
  "Recommended" badge on top pick, download progress bar, skip option
- First-run detection in layout: checks list_models + list_parakeet_models,
  shows wizard if both empty
- Sidebar hidden during first-run for clean wizard experience
- clippy clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:02:01 +00:00
jake
9926a42b7a feat(kon): scaffold hybrid modular workspace
- Cargo workspace with 6 domain crates: core, audio, transcription, ai-formatting, storage, cloud-providers
- Minimal Tauri shell (lib.rs + main.rs) with plugin registration
- Svelte 5 frontend copied from Ramble v0.2
- All crates compile as empty stubs
- App identifier: uk.co.corbel.kon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:21:38 +00:00