Commit Graph

21 Commits

Author SHA1 Message Date
jars
d6bde52d6e refactor(tauri): use magnotia_core::hardware::vulkan_loader_available
Delete the local duplicate fn and libloading dependency from src-tauri;
import the canonical implementation from magnotia-core::hardware instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 12:08:16 +01:00
Claude
89c63891fa chore: rebrand from Kon/Corbie to Magnotia
Replace all instances of the legacy product names "Kon" and "Corbie" with
"Magnotia" across user-facing copy, code identifiers, package names, bundle
ids, file paths, and documentation. Preserves the unrelated "konsole" (KDE
terminal) reference and the parent CORBEL company name.

- Renames 10 Rust crates (kon-* → magnotia-*) and the tauri binary
- Updates package.json, tauri.conf.json (productName + identifier)
- Renames CSS classes (kon-rh-* → magnotia-rh-*) and animations
- Renames brand and roadmap docs
- Regenerates Cargo.lock and package-lock.json

Verified: svelte-check passes; pure-rust crates compile under new names.
2026-04-30 13:06:55 +00:00
b333c6229e chore(hardening): tighten security and footprint defaults 2026-04-24 19:03:57 +01:00
fe61661305 chore(lint): clean up clippy warnings across workspace
Auto-applied cargo clippy --fix across 11 files — needless return,
unnecessary cast, map_or simplification, repeat().take() → repeat_n(),
iter().any() → contains(), manual char comparison, lifetime elision,
push_str single-char, reference immediately dereferenced.

Also fixed three lints on file_storage.rs manually: two doc-list-item
overindentations, plus the same needless-return. Baseline main was
not clippy-clean with -D warnings before; after this pass one
needless_range_loop warning remains (live.rs:1089) that clippy's
suggested rewrite would make less readable — left for a dedicated
refactor session.

Build + workspace tests remain green (245 passing, 0 failing, 1
ignored).
2026-04-24 09:43:56 +01:00
9b0067b4c0 Land release blocker fixes and workspace 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
2026-04-23 00:16:09 +01:00
54d9adf1f0 fix(rb-07): runtime capabilities derive accelerators honestly
get_runtime_capabilities was returning `accelerators = ["cpu",
"vulkan"]` and `whisper.supports_gpu = true` regardless of build
config or runtime state. On a macOS build it falsely advertised
"vulkan" (the backend actually resolves via MoltenVK as Metal); on a
whisper-disabled build it claimed GPU support for an engine that
hadn't been linked.

Added `compose_accelerators(whisper_enabled, loader_available, target)`
— a pure helper that always emits "cpu" first and appends the
platform-appropriate GPU name only when whisper is compiled in AND the
Vulkan loader resolves. `supported_accelerators()` wraps it with the
live `cfg!(feature = "whisper")`, loader probe, and target OS.

`get_runtime_capabilities` now calls `supported_accelerators()` and
sets `whisper.supports_gpu = cfg!(feature = "whisper")`. Parakeet
stays CPU-only.

Five tests in `commands::models::tests` cover the permutation matrix:
whisper on/off, loader present/missing, macOS vs other. Both feature
configurations (`--features whisper` and `--no-default-features`)
build and pass tests.

Macos Metal-loader resolution on real hardware stays on the
ship-gate checklist — the detection logic is verifiable from Linux
but runtime behaviour is not.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 10:32:04 +01:00
e4adcc1832 fix(A.2 #13): propagate whisper feature from kon crate through to kon-transcription
Review feedback: src-tauri/src/commands/models.rs was still naming
load_whisper unconditionally, so a --no-default-features workspace
build (kon-transcription without the whisper feature) would have
compiled the transcription crate cleanly but failed in the kon crate
as soon as it tried to resolve the load_whisper symbol.

Adds a matching [features] section to src-tauri/Cargo.toml:
- default = ["whisper"]
- whisper = ["kon-transcription/whisper"]

and declares the kon-transcription dep with default-features = false so
the feature actually propagates rather than being forced-on by the
child crate's default. Cfg-gates the load_whisper import in models.rs
and adds a companion match arm that returns a runtime error when the
feature is off, keeping the API shape intact.

Verified with both cargo build -p kon and cargo build -p kon
--no-default-features.
2026-04-22 04:54:07 +01:00
8b49d0fe9c feat(A.2 #13): replace SpeechBackend enum with Transcriber trait
New crates/transcription/src/transcriber.rs defines a Transcriber
trait (Send supertrait for spawn_blocking travel) with
TranscriberCapabilities (sample_rate, channels, supports_initial_prompt).
TranscriberCapabilities.sample_rate is load-bearing for the upcoming
progressive WAV writer (#19).

Concrete impls:
- SpeechModelAdapter wraps Box<dyn transcribe_rs::SpeechModel + Send>
  for Parakeet (and any future transcribe-rs-backed engine).
- WhisperRsBackend moves its transcribe_sync body into the impl,
  widening the signature from &self to &mut self so per-call
  WhisperState can be created cleanly through the trait object.

LocalEngine now holds Box<dyn Transcriber + Send>; dispatch in
transcribe_sync collapses from a match to a direct call. Adds
LocalEngine::capabilities() for the WAV-writer.

Cargo feature flag "whisper" (default on) makes whisper-rs, num_cpus,
and the whole whisper_rs_backend module optional. cargo check
--no-default-features -p kon-transcription now builds without pulling
whisper-rs-sys — the escape hatch brief item #6 / #13 called for on
Windows / non-AVX2 / cloud-only builds. load_whisper is cfg-gated
behind the same feature.

src-tauri/src/commands/models.rs load_model_from_disk returns
Box<dyn Transcriber + Send> instead of SpeechBackend; caller chain
(ensure_model_loaded, prewarm_default_model) is unchanged.

transcriber_trait_is_object_safe test lands alongside the trait as a
compile-time witness against future Self-returning / generic-method
additions.
2026-04-22 04:33:23 +01:00
ce2b4fdac6 feat(ai B.1 #15 + A.1 #28): cleanup presets and sequential-GPU guard
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
Two new Settings → AI knobs that compose cleanly with what already
shipped (aiTier, LLM model, translator prompt framing).

**B.1 #15 — Named cleanup presets.** LlmPromptPreset enum
(Default / Email / Notes / Code) appends a short context hint onto
the CLEANUP_PROMPT just before generation. Presets shape tone and
structure ("email paragraph", "bulleted meeting notes", "preserve
technical terms") without licensing the content-editing the
translator-not-editor framing forbids. cleanup_transcript_text_cmd
now takes `preset: Option<String>` which runs through the new
LlmPromptPreset::parse (normalises aliases like "meeting-notes",
collapses unknown values to Default).

**A.1 #28 — Sequential-GPU guard.** New LocalEngine::unload drops
the backend + model_id so a subsequent load actually reclaims VRAM.
load_llm_model, load_model, and load_parakeet_model Tauri commands
grow an optional `concurrent: bool` argument. When concurrent is
Some(false), loading LLM first unloads whisper+parakeet, and vice
versa — prevents VRAM OOM on tight-VRAM setups. Default is the
previous parallel behaviour so nothing changes for multi-GB cards.
Transcribe-in-progress paths (transcribe_pcm, transcribe_file, live)
pass None, so mid-dictation model loads don't accidentally tear
down the LLM.

Settings UI (AI section):
- Cleanup preset segmented button + descriptive copy for each option.
- GPU concurrency segmented button with explicit trade-off text
  ("faster transitions vs fits in tight VRAM").

Frontend wiring:
- settings.llmPromptPreset flows from DictationPage's
  cleanupTranscriptIfEnabled into the Tauri command.
- settings.aiGpuConcurrency flows from both DictationPage (auto-load
  on record) and SettingsPage (manual load/unload buttons) as
  `concurrent: "parallel" === true` to the load commands.

Tests: three new preset cases in crates/ai-formatting/src/llm_client.rs
(parse aliases, suffix non-empty for non-default, default suffix
empty). All 139 existing lib tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:12:48 +01:00
e10f435eb1 feat(transcription A.1 #23): silent warm-up inference after Whisper model load
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
prewarm_default_model loaded the model and returned. That moves the
model into RAM, but whisper.cpp still allocates its context window +
fills GPU shader caches on the first inference call — producing the
~4–5 s cold-start latency documented in ufal/whisper_streaming #96
and #135 that feels like "Kon dropped my first sentence."

Extend the pre-warm task: after engine.load, feed one second of
silence (16000 zero samples at 16 kHz) through transcribe_sync with
default options. Silence returns empty segments; the *work* is the
context allocation, which now happens at app boot rather than on the
user's first hotkey press.

Net: the user's first real dictation should complete within ~1.5× the
steady-state RTF they'll see on subsequent runs, satisfying the A.1
#23 acceptance criterion. No new public API; all inside the existing
spawn_blocking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 16:25:09 +01:00
Cursor Agent
fafa0fc878 feat(A.1 #1): surface active compute device + runtime-warning banner
Extends get_runtime_capabilities() with three new fields:
  - activeComputeDevice: {kind, label, reason} — "GPU (Vulkan)" on
    the happy path, "CPU (fallback)" with a reason when the Vulkan
    loader is absent at runtime. libloading::Library::new probes
    libvulkan.so.1 / vulkan-1.dll / libMoltenVK.dylib per target OS.
  - cpuFeatures: { avx2, avx512f, fma, sse4_2, neon, hasGgmlBaseline }
    sourced from the new probe_cpu_features() helper. hasGgmlBaseline
    is the one flag the Settings banner actually reads.
  - parallelModeAvailable: placeholder false until Phase A.4 lands
    the real GPU VRAM probe + GpuGuard semaphore permit logic.

Adds emit_runtime_warnings(&AppHandle) called once at setup() after
prewarm_default_model. Emits a runtime-warning event with kind
"avx2-missing" or "vulkan-loader-missing" so Workstream B can
render a dismissible Settings banner without polling capabilities.

Contract matches docs/whisper-ecosystem/workstream-A.md §Item #1 for
Workstream B to consume without waiting for Phase A.2 to land the
real whisper_print_system_info bridge.

Co-authored-by: jars <jakejars@users.noreply.github.com>
2026-04-21 15:54:15 +01:00
4561810751 feat(whisper): add Distil-Whisper Small and Large v3 as first-class models
Two new registry entries (crates/core/src/model_registry.rs):
- whisper-distil-small-en — 336 MB, ~6× faster than whisper-small-en
- whisper-distil-large-v3 — 1.55 GB, near large-v3 accuracy at medium size

Both are whisper.cpp-compatible GGML binaries hosted on HF by the
distil-whisper org; no runtime change, just wider model choice. English-only
by design (matches upstream Distil-Whisper).

The Settings model picker widens to six options — Tiny, Base, Small,
Distil-S, Medium, Distil-L — ordered roughly by accuracy. Download/load
commands now take the resolved model id (whisper-distil-*) instead of the
lowercased label, so the frontend owns the label↔id mapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:39:03 +01:00
34fce3cf9e feat: OpenWhispr-inspired transcription polish pass
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
Major quality pass on top of Phase 2. Five substantive changes plus
cross-cutting touches across audio, hotkey, transcription, and Tauri
command layers.

  Transcription quality

  - Long-audio chunking in commands/transcription.rs: Parakeet and large
    file transcription now chunk-and-recompose with overlap trimming, so
    the live-path chunking advantage extends to file-based workflows.
  - Stateful live speech gate in commands/live.rs on top of the earlier
    duplicate-boundary filtering — distinguishes start-of-speech from
    mid-speech and holds state across chunks.

  Auto-learning corrections

  - New crates/ai-formatting/src/correction_learning.rs: extracts user
    text corrections from viewer edits and proposes additions to the
    active profile's vocabulary.
  - src-tauri/src/commands/profiles.rs bridge for frontend-driven
    confirmation of learned terms.
  - src/routes/viewer/+page.svelte hooks the learning path into the
    segment-edit flow so corrections feed profile_terms without a
    separate 'train this profile' UX.

  Transcript profile provenance

  - Migration v8 (crates/storage/src/migrations.rs) adds profile_id to
    transcripts, defaulting to DEFAULT_PROFILE_ID so existing rows stay
    valid.
  - crates/storage/src/database.rs: TranscriptRow + CRUD carry profile_id.
  - src-tauri/src/commands/transcripts.rs: add_transcript accepts and
    persists profile_id.
  - DictationPage.svelte + FilesPage.svelte send activeProfileId on
    capture so learned corrections are attributed to the right profile.

  Cleanup prompt contract

  - crates/ai-formatting/src/llm_client.rs hardened: the CLEANUP_PROMPT
    now specifies concrete do/do-not rules, ready for a real model-backed
    cleanup pass. The llm_client is still a stub — kon-llm remains unwired
    — but the prompt shape is final.

  Cross-cutting polish

  - Minor touches in audio (capture/decode/resample), hotkey (lib/linux/stub),
    core, transcription (concurrency/model_manager/local_engine/whisper_rs),
    and the rest of src-tauri/src/commands/*: error-path tightening, log
    clarity, TS-migration follow-ups (@ts-nocheck additions for incremental
    typing).

Verified locally: npm run check, cargo test -p kon-ai-formatting,
cargo test -p kon-storage, cargo test -p kon --lib commands::live::tests,
cargo check — all green.

Scope boundary: kon-llm crate is still a stub; task extraction remains
rule-based. Bundled local-LLM runtime is the next clean step and is not
in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:39:08 +01:00
4256383a5b refactor(transcription): LocalEngine dispatches SpeechBackend enum — Whisper now on whisper-rs 2026-04-19 20:20:03 +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
61c96d7805 fix(startup): use tauri::async_runtime::spawn for pre-warm — tokio::spawn panics before runtime is live in setup() 2026-04-18 10:10:16 +01:00
ddcf93649c feat(startup): pre-warm default Whisper model at launch in background thread 2026-04-18 09:28:03 +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
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
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