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>
This commit is contained in:
2026-04-03 17:50:48 +01:00
parent 1933604176
commit 8e70cf9ff9
12 changed files with 804 additions and 18 deletions

View File

@@ -40,6 +40,8 @@ pub struct ModelFile {
pub filename: &'static str,
pub url: &'static str,
pub size: Megabytes,
/// SHA256 hex digest for integrity verification. None to skip check.
pub sha256: Option<&'static str>,
}
/// All metadata for a single downloadable model.
@@ -74,16 +76,19 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
filename: "encoder-model.onnx",
url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/onnx/model_int8.onnx",
size: Megabytes(1),
sha256: None,
},
ModelFile {
filename: "model_int8.onnx_data",
url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/onnx/model_int8.onnx_data",
size: Megabytes(611),
sha256: None,
},
ModelFile {
filename: "tokenizer.json",
url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/tokenizer.json",
size: Megabytes(1),
sha256: None,
},
],
description: "Fastest local model — near-instant transcription",
@@ -101,6 +106,7 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
filename: "ggml-tiny.en.bin",
url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin",
size: Megabytes(75),
sha256: None,
}],
description: "Bundled with app — works instantly",
},
@@ -117,6 +123,7 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
filename: "ggml-base.en.bin",
url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin",
size: Megabytes(142),
sha256: None,
}],
description: "Good balance of speed and accuracy",
},
@@ -133,6 +140,7 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
filename: "ggml-small.en.bin",
url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin",
size: Megabytes(466),
sha256: None,
}],
description: "Accuracy-first English transcription",
},
@@ -149,6 +157,7 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
filename: "ggml-medium.en.bin",
url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.en.bin",
size: Megabytes(1500),
sha256: None,
}],
description: "Best Whisper accuracy — needs 4+ GB RAM",
},