Commit Graph

124 Commits

Author SHA1 Message Date
8c1bec98ca feat(ai-formatting): wire dictionary_terms through PostProcessOptions to LLM prompt suffix 2026-04-18 09:25:28 +01:00
7de2feb932 chore: add CI workflows, dev launcher, and linux capability schema
.github/workflows/check.yml: cargo check on Linux + Windows + macOS
  plus Svelte/Vite build on every push to main and every PR. Fast
  feedback without paying for the full release build.

.github/workflows/build.yml: cross-platform release build producing
  .AppImage/.deb (Linux), .msi/.exe (Windows), .dmg (macOS). Triggers
  on v* tag push (attaches to a draft GitHub Release) or manual
  workflow_dispatch. Signing stubs commented out pending cert decisions.

run.sh: dev launcher that starts Vite, waits for port 1420, then runs
  tauri dev with beforeDevCommand blanked to avoid a second Vite spawn.
  Restores tauri.conf.json on exit via trap.

src-tauri/gen/schemas/linux-schema.json: Tauri-generated capability
  schema for Linux; the other platform schemas (desktop, windows) were
  already committed. Adds the missing sibling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:03:28 +01:00
cca79dec4c fix: SQL trigger-aware migration splitter, SpeechModel re-export, i64 type alignment
crates/storage/src/migrations.rs:
  Replace naive sql.split(';') with split_statements() that tracks
  BEGIN...END depth, so migrations containing trigger definitions
  execute correctly instead of being split mid-block.

crates/transcription/src/lib.rs:
  Re-export transcribe_rs::SpeechModel so callers in src-tauri can
  reference it without adding transcribe-rs as a direct dependency.

src-tauri/src/commands/models.rs:
  Use Box<dyn SpeechModel + Send> as the load_model_from_disk return
  type, matching the trait object that transcription crates produce.

src-tauri/src/commands/transcripts.rs:
  Remove the stale .map(|v| v as i32) casts on sample_rate and
  audio_channels. InsertTranscriptParams now stores these as i64
  (ebf449b), matching the i64 fields on CreateTranscriptRequest;
  casting to i32 first would silently truncate large sample rates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:03:01 +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
9f3be5c007 ui+app: Day 5+6 — Settings → Vocabulary panel + Wayland self-relaunch
VOCABULARY PANEL (Day 5):
src/lib/pages/SettingsPage.svelte gains a new collapsible "Vocabulary"
section between Audio and Transcription. Wires the dictionary commands
shipped in 1cce567:
- list_dictionary_command on mount + onfocus refresh
- add_dictionary_entry_command (term + optional note)
- delete_dictionary_entry_command
- Inline error feedback via vocabularyError
- Empty-state copy + per-entry remove button with aria-label

The dictionary terms are intended to be injected into the LLM cleanup
prompt so the model preserves user-specific vocabulary (medication
names, place names, jargon, names of people in the user's support
network — particularly important for the ND audience). The LLM client
itself is currently a stub (crates/ai-formatting/src/llm_client.rs);
when it lands, it can import list_dictionary from kon_storage and
inject terms into the prompt suffix.

WAYLAND SELF-RELAUNCH (Day 6):
src-tauri/src/lib.rs gains ensure_x11_on_wayland() which runs before
tauri::Builder. On Linux Wayland sessions (XDG_SESSION_TYPE=wayland) it
sets GDK_BACKEND=x11, WINIT_UNIX_BACKEND=x11, and
WEBKIT_DISABLE_DMABUF_RENDERER=1 — the env vars HANDOVER.md documents
the user manually prefixing.

Drops the "users have to remember the env-var prefix" friction.
Idempotent: existing values are respected. Inspired by Open-Whispr's
Chromium --ozone-platform=x11 self-relaunch.

Compile-checked: cargo check -p kon-storage clean. Settings.svelte
$state / #if balanced (28 state, 34/34 if/endif).

NEXT: Phase 6 — dogfooding readiness doc with Jake test instructions.
2026-04-17 13:16:07 +01:00
1cce5670af storage: Day 4 — FTS5 search + update_transcript + dictionary + paginated list + Tauri command surface
Finally exposes the canonical SQLite store to the frontend. Previously
the transcript/task tables existed but no Tauri command read or wrote
them — the UI lived entirely in localStorage. Closes that gap and adds
the missing commands flagged by both Codex and architecture-review.md
§13.

MIGRATIONS:
- v2 adds:
  - transcripts_fts virtual table (FTS5, porter+unicode61 tokeniser,
    diacritics-folded) backed by transcripts via content_rowid
  - INSERT/UPDATE/DELETE triggers keep FTS in sync automatically
  - dictionary table for custom vocabulary (term, note, created_at)
- Append-only as required; never modifies v1

STORAGE FUNCTIONS (crates/storage/src/database.rs):
- list_transcripts_paged(limit, offset) — pagination
- count_transcripts() — for "showing X of N" in UI
- update_transcript(id, text?, title?) — closes the historic
  architecture-review.md §13 rename-never-persists TODO
- search_transcripts(query, limit) — FTS5 wrapper
- list_dictionary / add_dictionary_entry / delete_dictionary_entry
- DictionaryEntry struct exported

TAURI COMMANDS (src-tauri/src/commands/transcripts.rs new file):
- add_transcript, list_transcripts, count_transcripts_command,
  get_transcript, update_transcript, delete_transcript,
  search_transcripts
- list_dictionary_command, add_dictionary_entry_command,
  delete_dictionary_entry_command
- TranscriptDto + DictionaryDto for camelCase frontend serialisation

REGISTRATION (src-tauri/src/lib.rs):
- All 10 new commands wired into the invoke_handler

cargo check -p kon-storage passes clean. The Tauri crate cargo check
still requires `sudo dnf install cmake clang-devel` for whisper-rs-sys
(pre-existing infra dep, unrelated to this work).

NEXT (still in this sprint):
- Wire DictationPage / FilesPage to call add_transcript on every save
  (dual-write: keep localStorage for now, add SQLite alongside)
- Wire HistoryPage rename to call update_transcript (fixes the TODO)
- Add a History search input that calls search_transcripts
- Add Settings → Dictionary panel
- Inject dictionary terms into the LLM cleanup prompt
2026-04-17 13:10:26 +01:00
19a6b83cb2 audio: Day 2 — Codex follow-up hardening (channel disconnect, spawn_blocking, fallback silence guard, requeue counting, runtime error propagation)
Closes the 6 Codex review findings on the Day 1 mic-capture work
(commits 96980c7 + 41db162). Detail in
output/reports/kon-codex-mic-capture-followup-2026-04-17.md (CORBEL
workspace).

src-tauri/src/commands/audio.rs:
- D1: Sending an explicit stop signal before dropping stop_tx, so the
  accumulator task wakes up immediately rather than waiting for the
  Disconnected detection added below.
- D2: Wrapping MicrophoneCapture::start() in tokio::task::spawn_blocking.
  start() can spend up to 350ms × N_devices × 2 passes; running it on
  the async runtime froze other Tauri commands.
- M3: Match on rx.try_recv() error variants. Empty -> sleep + continue.
  Disconnected -> exit accumulator task immediately. Previous behaviour
  was an infinite loop after the capture stream died.

crates/audio/src/capture.rs:
- D3: Added DEAD_SILENCE_FLOOR (1e-7) gate that applies even in the
  fallback pass. PulseAudio/PipeWire can stream zero-valued bytes from
  a borked device; that is worse than failing fast.
- M1: Validation requeue (`for chunk in collected { try_send }`) now
  counts drops in the same dropped_chunks counter.
- M2: New CaptureRuntimeError type. The cpal stream error callback now
  forwards errors via a separate sync_channel (capacity 16) that the
  live session can drain via take_error_rx() and surface as toasts.
  Re-exported from kon_audio crate root.

cargo check -p kon-audio passes clean.

NOT YET DONE (M4): JACK-specific monitor name patterns. Defers until
testing on a JACK host. Current is_monitor_name() may miss JACK
conventions.

Wiring the new error_rx into the live session and surfacing as toasts
lands with the Day 3 error-toast system commit.
2026-04-17 13:02:51 +01:00
41db162041 audio: wire user's microphone choice through start_native_capture + live session
Day 1 follow-up to 96980c7. The device-picker UI in Settings now
actually takes effect: settings.microphoneDevice flows from the Svelte
store, through the Tauri invoke, into MicrophoneCapture::start_with_device
on the Rust side.

Touched paths (back-to-front):
- src-tauri/src/commands/audio.rs:start_native_capture — new optional
  `device_name: Option<String>` parameter; routes to start_with_device
  when set, falls back to auto-select start() when None or empty.
- src-tauri/src/commands/live.rs:StartLiveTranscriptionConfig — new
  optional `microphone_device: Option<String>` field with same
  semantics (rename_all = "camelCase" maps it to microphoneDevice on
  the wire).
- src-tauri/src/commands/live.rs:run_live_session — picks
  start_with_device when an explicit name is provided.
- src/lib/pages/DictationPage.svelte — passes
  microphoneDevice: settings.microphoneDevice || null in the invoke.

Behaviour:
- "Auto" in the picker (empty string) -> backend auto-selects, skipping
  monitor sources and validating by RMS energy.
- Specific device -> backend opens that device by exact name; if it has
  been disconnected the user gets a clear error pointing them back at
  Settings.

cargo check -p kon-audio passes clean. Tauri-crate cargo check requires
cmake (pre-existing infra dependency for whisper-rs-sys); install via
`sudo dnf install cmake clang-devel`.
2026-04-17 12:45:19 +01:00
96980c7d5c audio: fix mic capture — skip monitor sources, validate by RMS, add device picker
Day 1 of the upgrade plan (output/reports/kon-upgrade-plan-2026-04-17.md
in the CORBEL workspace). Fixes the HANDOVER.md blocker: native live
transcription was capturing silence because PulseAudio/PipeWire monitor
sources (speaker loopback) were winning the device-selection race —
they deliver zero-valued bytes that satisfied the original
"any device that produces data within 350ms" check.

WHAT CHANGED:

crates/audio/src/capture.rs (rewrite):
- New `DeviceInfo` struct (serde-derived) for the Settings device picker
- New `MicrophoneCapture::list_devices()` enumerates inputs with metadata
- New `MicrophoneCapture::start_with_device(name)` for explicit selection
- Refactored `start()` with monitor-source filtering by name pattern
  (.monitor suffix, "Monitor of " prefix, "loopback" substring) and
  RMS-energy validation in a 350ms window
- Two-pass selection: real inputs first, monitor sources only as
  last-resort fallback with explicit warning log
- Drop counter (Arc<AtomicU64>) tracks chunks dropped by `try_send`
  failure under load — Codex review caught this as a silent-failure risk
- `dropped_chunks()` accessor for the live session
- Verbose tracing at every step for diagnosis
- Unit test for monitor-name detection
- `cargo check -p kon-audio` passes clean

crates/audio/src/lib.rs:
- Re-export `DeviceInfo`

crates/audio/Cargo.toml:
- Add serde dependency (for DeviceInfo derives)

src-tauri/src/commands/audio.rs:
- New `list_audio_devices` Tauri command (returns Vec<DeviceInfo>)

src-tauri/src/lib.rs:
- Register `list_audio_devices` in invoke_handler

src/lib/pages/SettingsPage.svelte:
- New "Audio" section with microphone picker dropdown
- Auto-populates on mount via `list_audio_devices`
- Refresh button + clear messaging about monitor sources
- Likely-monitor entries marked disabled in the dropdown
- Auto mode is the default (empty string in settings.microphoneDevice)

src/lib/stores/page.svelte.js:
- New `microphoneDevice` field in defaults (empty = auto-select)

NEXT STEPS (per the upgrade plan):
- Wire `microphoneDevice` from settings into `MicrophoneCapture::start_with_device`
  in the live and standalone capture paths (currently both still call
  the auto-selecting `start()`)
- Test on real hardware (Wayland + multiple input devices)
- Codex sanity-check of this diff is running in parallel; addendum to
  follow if anything substantive comes back

Refs: /home/jake/Documents/CORBEL-Projects/kon/HANDOVER.md
      output/reports/kon-upgrade-plan-2026-04-17.md (CORBEL workspace)
2026-04-17 12:43:13 +01:00
ecfffcbf35 agent: fix — auto-grant microphone permission on WebKitGTK/Linux
WebKitGTK denies getUserMedia by default with no permission prompt.
Connect to the permission-request signal and auto-allow, plus enable
media-stream and media-capabilities in WebKit settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:28:44 +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
4c0fd0aeda agent: foundation — sync incremental changes from legacy codebase
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:50:32 +00:00
jake
fa7e812166 agent: rust — add preferences webview injection for zero-flash hydration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:41:44 +00:00
jake
e70cfca63d refactor(kon): remove LLM command stubs — will be rewritten with llama-cpp-rs in Phase 3
- Remove 8 LLM command registrations from invoke_handler macro
- Delete commands/llm.rs stub file
- Remove pub mod llm from commands/mod.rs
- Build passes cleanly with cargo clippy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:11:11 +00:00
jake
95c8d490c3 fix(kon): harden core crate — shared System instance, accurate CPU field, serialisable errors
- Share single System::new_all() in probe_system() instead of calling it twice
- Rename CpuInfo::core_count to logical_processors (sys.cpus().len() returns logical, not physical)
- Add fallback arm to probe_os() for unsupported cfg targets
- Add serde::Serialize to KonError for structured frontend error reporting
- Annotate dead code (ProviderRegistry, TranscriptMetadata) with #[allow(dead_code)] + TODO comments
- Update downstream references in recommendation tests and tauri hardware command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:19:04 +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
c463293935 fix(kon): security audit fixes — CSP, XSS, unwraps, key rename
Security fixes from code audit:
- CSP re-enabled in tauri.conf.json with strict directives
  (was null — critical vulnerability)
- XSS fix in viewer highlightText(): HTML entities escaped before
  inserting <mark> tags via {@html}
- Removed 3 unwrap() calls in rule_based.rs British English conversion
  — replaced with safe let-else guards
- Removed unwrap() on main window lookup in lib.rs setup — now uses
  if-let for graceful handling
- Wrapped JSON.parse in DictationPage transcription-result listener
  with try/catch

Rebrand cleanup:
- Renamed all localStorage keys from ramble_* to kon_* across
  7 files (stores, viewer, float, history)

12 tests passing, clippy clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:51:47 +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
0bbdbc0591 feat(kon): replace browser clipboard with arboard
- New copy_to_clipboard Tauri command using arboard 3.6
- Replaced all 5 navigator.clipboard.writeText() calls across
  DictationPage, HistoryPage, FilesPage, and viewer with invoke()
- Native clipboard access independent of WebView permissions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:48:19 +00:00
jake
292f9716ff feat(kon): add full transcript provenance — enriched schema, metadata pipeline, error log
Schema enrichment:
- transcripts table: +engine, +model_id, +inference_ms, +sample_rate, +audio_channels,
  +format_mode, +remove_fillers, +british_english, +anti_hallucination
- New error_log table: context, error_code, message, metadata (JSON)
- 5 indices on frequently queried columns

Metadata pipeline:
- TranscriptMetadata struct in kon-core for full provenance capture
- LocalEngine tracks loaded ModelId, returns TimedTranscript with inference_ms
- std::time::Instant timing around transcribe-rs inference calls
- Tauri transcription commands emit inference_ms in event payloads
- InsertTranscriptParams accepts all provenance fields
- log_error() for structured error logging to SQLite

Every transcript is now fully reproducible from its stored metadata.
23 tests passing, clippy clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:36:44 +00:00
jake
29ff91d3f6 feat(kon): wire Tauri shell — thin commands, ProviderRegistry, tray
- lib.rs rewritten from scaffold to full app setup (~70 lines)
- AppState holds Arc<LocalEngine> for Whisper and Parakeet
- commands/models.rs: download, check, list, load for both engines
  Maps legacy size strings (Tiny/Base/Small/Medium) to ModelId
- commands/transcription.rs: transcribe_pcm, transcribe_file, transcribe_pcm_parakeet
  Delegates to LocalEngine.transcribe_sync() + post_process_segments()
- commands/audio.rs: save_audio via kon_audio::write_wav
- commands/windows.rs: open_task_window, open_viewer_window
- commands/llm.rs: 8 stub commands preserved for frontend compatibility
- tray.rs: extracted system tray setup (show, status, quit, click-to-show)
- Close-to-tray behaviour preserved
- All 25 v0.2 command names preserved for Svelte frontend compatibility
- clippy clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:15:16 +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