agent: lumotia-rebrand — rust workspace crates magnotia-* -> lumotia-*
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

Phase 2 of the rebrand cascade. Renames all 9 workspace crates from
magnotia-* to lumotia-* plus the src-tauri binary crate name:

- magnotia-ai-formatting   -> lumotia-ai-formatting
- magnotia-audio           -> lumotia-audio
- magnotia-cloud-providers -> lumotia-cloud-providers
- magnotia-core            -> lumotia-core
- magnotia-hotkey          -> lumotia-hotkey
- magnotia-llm             -> lumotia-llm
- magnotia-mcp             -> lumotia-mcp
- magnotia-storage         -> lumotia-storage
- magnotia-transcription   -> lumotia-transcription
- magnotia                 -> lumotia (src-tauri binary)
- magnotia_lib             -> lumotia_lib (src-tauri lib target)

Crate directories (crates/audio/ etc.) stay as-is; only the Cargo.toml
[package] name field changes plus all consumer module imports
(magnotia_core -> lumotia_core, etc.).

Remaining magnotia_* references at this point are intentional and
scoped to later phases: tracing targets (Phase 4), DB setting keys
magnotia_preferences/magnotia_history (Phase 5).

cargo build --workspace passes. cargo test --workspace: 330 pass, 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 08:48:09 +01:00
parent bc2db91520
commit 089349d966
60 changed files with 372 additions and 372 deletions

326
Cargo.lock generated
View File

@@ -2752,6 +2752,169 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
name = "lumotia"
version = "0.1.0"
dependencies = [
"arboard",
"base64 0.22.1",
"gdk",
"gtk",
"lumotia-ai-formatting",
"lumotia-audio",
"lumotia-cloud-providers",
"lumotia-core",
"lumotia-hotkey",
"lumotia-llm",
"lumotia-storage",
"lumotia-transcription",
"objc2",
"objc2-foundation",
"serde",
"serde_json",
"sqlx",
"tauri",
"tauri-build",
"tauri-plugin-autostart",
"tauri-plugin-dialog",
"tauri-plugin-global-shortcut",
"tauri-plugin-notification",
"tauri-plugin-opener",
"tauri-plugin-window-state",
"tempfile",
"tokio",
"tracing",
"tracing-subscriber",
"uuid",
"webkit2gtk",
]
[[package]]
name = "lumotia-ai-formatting"
version = "0.1.0"
dependencies = [
"lumotia-core",
"lumotia-llm",
"regex-lite",
"tracing",
]
[[package]]
name = "lumotia-audio"
version = "0.1.0"
dependencies = [
"cpal",
"hound",
"lumotia-core",
"regex",
"rubato",
"serde",
"symphonia",
"tokio",
"tracing",
]
[[package]]
name = "lumotia-cloud-providers"
version = "0.1.0"
dependencies = [
"async-trait",
"lumotia-core",
"serde",
]
[[package]]
name = "lumotia-core"
version = "0.1.0"
dependencies = [
"async-trait",
"libloading 0.8.9",
"num_cpus",
"serde",
"serde_json",
"sysinfo",
"tempfile",
"thiserror 2.0.18",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "lumotia-hotkey"
version = "0.1.0"
dependencies = [
"evdev",
"lumotia-core",
"nix 0.29.0",
"notify",
"serde",
"tokio",
"tracing",
]
[[package]]
name = "lumotia-llm"
version = "0.1.0"
dependencies = [
"encoding_rs",
"futures-util",
"llama-cpp-2",
"lumotia-core",
"reqwest 0.12.28",
"serde",
"serde_json",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]]
name = "lumotia-mcp"
version = "0.1.0"
dependencies = [
"anyhow",
"lumotia-storage",
"serde",
"serde_json",
"sqlx",
"tempfile",
"tokio",
]
[[package]]
name = "lumotia-storage"
version = "0.1.0"
dependencies = [
"log",
"lumotia-core",
"serde",
"sqlx",
"thiserror 1.0.69",
"tokio",
"uuid",
]
[[package]]
name = "lumotia-transcription"
version = "0.1.0"
dependencies = [
"async-trait",
"futures-util",
"lumotia-cloud-providers",
"lumotia-core",
"num_cpus",
"reqwest 0.12.28",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
"transcribe-rs",
"whisper-rs",
]
[[package]]
name = "lzma-rust2"
version = "0.15.7"
@@ -2785,169 +2948,6 @@ dependencies = [
"libc",
]
[[package]]
name = "magnotia"
version = "0.1.0"
dependencies = [
"arboard",
"base64 0.22.1",
"gdk",
"gtk",
"magnotia-ai-formatting",
"magnotia-audio",
"magnotia-cloud-providers",
"magnotia-core",
"magnotia-hotkey",
"magnotia-llm",
"magnotia-storage",
"magnotia-transcription",
"objc2",
"objc2-foundation",
"serde",
"serde_json",
"sqlx",
"tauri",
"tauri-build",
"tauri-plugin-autostart",
"tauri-plugin-dialog",
"tauri-plugin-global-shortcut",
"tauri-plugin-notification",
"tauri-plugin-opener",
"tauri-plugin-window-state",
"tempfile",
"tokio",
"tracing",
"tracing-subscriber",
"uuid",
"webkit2gtk",
]
[[package]]
name = "magnotia-ai-formatting"
version = "0.1.0"
dependencies = [
"magnotia-core",
"magnotia-llm",
"regex-lite",
"tracing",
]
[[package]]
name = "magnotia-audio"
version = "0.1.0"
dependencies = [
"cpal",
"hound",
"magnotia-core",
"regex",
"rubato",
"serde",
"symphonia",
"tokio",
"tracing",
]
[[package]]
name = "magnotia-cloud-providers"
version = "0.1.0"
dependencies = [
"async-trait",
"magnotia-core",
"serde",
]
[[package]]
name = "magnotia-core"
version = "0.1.0"
dependencies = [
"async-trait",
"libloading 0.8.9",
"num_cpus",
"serde",
"serde_json",
"sysinfo",
"tempfile",
"thiserror 2.0.18",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "magnotia-hotkey"
version = "0.1.0"
dependencies = [
"evdev",
"magnotia-core",
"nix 0.29.0",
"notify",
"serde",
"tokio",
"tracing",
]
[[package]]
name = "magnotia-llm"
version = "0.1.0"
dependencies = [
"encoding_rs",
"futures-util",
"llama-cpp-2",
"magnotia-core",
"reqwest 0.12.28",
"serde",
"serde_json",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]]
name = "magnotia-mcp"
version = "0.1.0"
dependencies = [
"anyhow",
"magnotia-storage",
"serde",
"serde_json",
"sqlx",
"tempfile",
"tokio",
]
[[package]]
name = "magnotia-storage"
version = "0.1.0"
dependencies = [
"log",
"magnotia-core",
"serde",
"sqlx",
"thiserror 1.0.69",
"tokio",
"uuid",
]
[[package]]
name = "magnotia-transcription"
version = "0.1.0"
dependencies = [
"async-trait",
"futures-util",
"magnotia-cloud-providers",
"magnotia-core",
"num_cpus",
"reqwest 0.12.28",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
"transcribe-rs",
"whisper-rs",
]
[[package]]
name = "markup5ever"
version = "0.14.1"

View File

@@ -1,11 +1,11 @@
[package]
name = "magnotia-ai-formatting"
name = "lumotia-ai-formatting"
version = "0.1.0"
edition = "2021"
description = "Text post-processing pipeline: filler removal, British English conversion, formatting for Magnotia"
[dependencies]
magnotia-core = { path = "../core" }
magnotia-llm = { path = "../llm" }
lumotia-core = { path = "../core" }
lumotia-llm = { path = "../llm" }
regex-lite = "0.1"
tracing = "0.1"

View File

@@ -3,7 +3,7 @@
//! The llm_client is not yet wired to a running model. This module defines
//! the prompt contract so that wiring it produces correct, hardened output.
use magnotia_llm::{EngineError, LlmEngine};
use lumotia_llm::{EngineError, LlmEngine};
/// System prompt sent before every cleanup call.
///
@@ -161,7 +161,7 @@ pub fn cleanup_text(
#[cfg(test)]
mod tests {
use super::*;
use magnotia_llm::EngineError;
use lumotia_llm::EngineError;
#[test]
fn empty_terms_returns_empty_string() {

View File

@@ -1,6 +1,6 @@
use magnotia_core::constants::SMART_PARAGRAPH_GAP_SECS;
use magnotia_core::types::Segment;
use magnotia_llm::LlmEngine;
use lumotia_core::constants::SMART_PARAGRAPH_GAP_SECS;
use lumotia_core::types::Segment;
use lumotia_llm::LlmEngine;
use crate::{llm_client, rule_based, to_plain_text::to_plain_text};

View File

@@ -13,7 +13,7 @@
//! is the whitespace pass and empty-segment filter, plus a single
//! public function the pipeline can depend on.
use magnotia_core::types::Segment;
use lumotia_core::types::Segment;
/// Join transcription segments into a single plain-text string
/// suitable for feeding to an LLM cleanup prompt.

View File

@@ -1,11 +1,11 @@
[package]
name = "magnotia-audio"
name = "lumotia-audio"
version = "0.1.0"
edition = "2021"
description = "Audio capture (cpal), VAD, resampling (rubato), file decoding (symphonia), WAV I/O (hound) for Magnotia"
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
# Microphone capture
cpal = "0.17"

View File

@@ -8,7 +8,7 @@ use regex::Regex;
use serde::{Deserialize, Serialize};
use std::sync::OnceLock;
use magnotia_core::error::{MagnotiaError, Result};
use lumotia_core::error::{MagnotiaError, Result};
const AUDIO_CHANNEL_CAPACITY: usize = 32;
@@ -149,7 +149,7 @@ impl MicrophoneCapture {
for device in devices {
let name = device_display_name(&device).unwrap_or_default();
if name == device_name {
tracing::info!(target: "magnotia_audio", "start_with_device: opening explicit device '{name}'");
tracing::info!(target: "lumotia_audio", "start_with_device: opening explicit device '{name}'");
return open_and_validate(device, &name, /* require_audio = */ true);
}
}
@@ -196,7 +196,7 @@ impl MicrophoneCapture {
});
tracing::info!(
target: "magnotia_audio",
target: "lumotia_audio",
device_count = all_devices.len(),
default = %default_name,
"enumerated input devices"
@@ -211,7 +211,7 @@ impl MicrophoneCapture {
match open_and_validate(device.clone(), &name, true) {
Ok(result) => return Ok(result),
Err(e) => {
tracing::warn!(target: "magnotia_audio", device = %name, error = %e, "candidate device rejected");
tracing::warn!(target: "lumotia_audio", device = %name, error = %e, "candidate device rejected");
}
}
}
@@ -219,7 +219,7 @@ impl MicrophoneCapture {
// Second pass: accept anything that delivers bytes (monitor sources
// included). Better to capture from a monitor than fail entirely.
tracing::warn!(
target: "magnotia_audio",
target: "lumotia_audio",
"no non-monitor mic produced audio; falling back to monitor/loopback sources"
);
for device in &all_devices {
@@ -227,7 +227,7 @@ impl MicrophoneCapture {
match open_and_validate(device.clone(), &name, false) {
Ok(result) => {
tracing::warn!(
target: "magnotia_audio",
target: "lumotia_audio",
device = %name,
"capturing from likely monitor source; recordings may be silent or contain system audio"
);
@@ -367,7 +367,7 @@ fn open_and_validate(
let format = config.sample_format();
tracing::info!(
target: "magnotia_audio",
target: "lumotia_audio",
device = %name,
sample_rate,
channels,
@@ -467,7 +467,7 @@ fn open_and_validate(
let rms = (sum_sq / total_samples as f64).sqrt() as f32;
tracing::info!(
target: "magnotia_audio",
target: "lumotia_audio",
device = %name,
samples = total_samples,
rms,
@@ -499,7 +499,7 @@ fn open_and_validate(
}
}
tracing::info!(target: "magnotia_audio", device = %name, "selected microphone");
tracing::info!(target: "lumotia_audio", device = %name, "selected microphone");
Ok((
MicrophoneCapture {
stream: Some(stream),
@@ -547,7 +547,7 @@ where
move |err| {
// Surface stream errors to the live session via err_tx so the
// frontend can show a toast.
tracing::error!(target: "magnotia_audio", error = %err, "capture stream error");
tracing::error!(target: "lumotia_audio", error = %err, "capture stream error");
if err_tx
.try_send(CaptureRuntimeError {
device_name: err_device_name.clone(),
@@ -560,7 +560,7 @@ where
// even if the frontend never received the typed event.
let prior = dropped_errors.fetch_add(1, Ordering::Relaxed);
tracing::warn!(
target: "magnotia_audio",
target: "lumotia_audio",
device = %err_device_name,
dropped_error = prior + 1,
"capture error channel full; dropping runtime error"

View File

@@ -1,7 +1,7 @@
use std::path::Path;
use magnotia_core::error::Result;
use magnotia_core::types::AudioSamples;
use lumotia_core::error::Result;
use lumotia_core::types::AudioSamples;
use crate::decode::decode_audio_file;
use crate::resample::resample_to_16khz;
@@ -16,6 +16,6 @@ pub async fn decode_and_resample(path: &Path) -> Result<AudioSamples> {
})
.await
.map_err(|e| {
magnotia_core::error::MagnotiaError::AudioDecodeFailed(format!("Task join error: {e}"))
lumotia_core::error::MagnotiaError::AudioDecodeFailed(format!("Task join error: {e}"))
})?
}

View File

@@ -9,8 +9,8 @@ use symphonia::core::io::MediaSourceStream;
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::AudioSamples;
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::AudioSamples;
/// Decode an audio file to mono f32 PCM samples.
/// Supports all formats symphonia handles: mp3, aac, flac, wav, ogg, etc.

View File

@@ -2,9 +2,9 @@ use rubato::{
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
};
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::AudioSamples;
use lumotia_core::constants::WHISPER_SAMPLE_RATE;
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::AudioSamples;
/// Resample audio to 16kHz mono using sinc interpolation (rubato).
/// Returns a new AudioSamples at the target sample rate.

View File

@@ -27,8 +27,8 @@ use rubato::{
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
};
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
use magnotia_core::error::{MagnotiaError, Result};
use lumotia_core::constants::WHISPER_SAMPLE_RATE;
use lumotia_core::error::{MagnotiaError, Result};
/// Number of input samples the rubato resampler consumes per `process()`
/// call. Matches the chunk size used in `resample::resample_to_16khz`.

View File

@@ -7,7 +7,7 @@
// For now, all audio is treated as speech. This matches v0.2 behaviour
// (no VAD) and doesn't affect core functionality.
use magnotia_core::constants::VAD_SPEECH_THRESHOLD;
use lumotia_core::constants::VAD_SPEECH_THRESHOLD;
/// Stub speech detector. Treats all audio as speech.
#[derive(Default)]

View File

@@ -1,8 +1,8 @@
use std::io::BufWriter;
use std::path::Path;
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::AudioSamples;
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::AudioSamples;
/// Append-friendly WAV writer for long-running captures.
///

View File

@@ -1,11 +1,11 @@
[package]
name = "magnotia-cloud-providers"
name = "lumotia-cloud-providers"
version = "0.1.0"
edition = "2021"
description = "Provider trait and BYOK cloud STT scaffolding for Magnotia (Wyrdnote pending rebrand)"
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
# Async-native trait. async_trait converts async fn into Pin<Box<dyn
# Future>> at the trait surface so TranscriptionProvider stays

View File

@@ -16,8 +16,8 @@
use std::fmt;
use async_trait::async_trait;
use magnotia_core::error::Result;
use magnotia_core::types::{AudioSamples, ModelId, Transcript, TranscriptionOptions};
use lumotia_core::error::Result;
use lumotia_core::types::{AudioSamples, ModelId, Transcript, TranscriptionOptions};
use serde::{Deserialize, Serialize};
/// Stable, lower-kebab-case identifier for a provider. Used in user
@@ -70,7 +70,7 @@ pub enum CostClass {
}
/// Capabilities a provider advertises to the orchestrator and the UI.
/// Superset of `magnotia_transcription::TranscriberCapabilities` for
/// Superset of `lumotia_transcription::TranscriberCapabilities` for
/// local providers, with extra fields cloud providers populate.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProviderCapabilities {

View File

@@ -1,5 +1,5 @@
[package]
name = "magnotia-core"
name = "lumotia-core"
version = "0.1.0"
edition = "2021"
description = "Core types, constants, traits, hardware detection, and model registry for Magnotia"

View File

@@ -9,11 +9,11 @@
//! exactly one INFO line; subsequent calls with the same tuple are
//! silenced by the per-process log-once cache.
use magnotia_core::tuning::{inference_thread_count, Workload};
use lumotia_core::tuning::{inference_thread_count, Workload};
fn main() {
tracing_subscriber::fmt()
.with_env_filter("magnotia_core=info")
.with_env_filter("lumotia_core=info")
.with_target(true)
.with_writer(std::io::stderr)
.init();

View File

@@ -34,7 +34,7 @@ pub enum MagnotiaError {
#[error("file not found: '{}'", .0.display())]
FileNotFound(PathBuf),
/// Structured storage failure flowed up from `magnotia_storage::Error` via
/// Structured storage failure flowed up from `lumotia_storage::Error` via
/// its `From` impl. Display reads through to `detail` so the operation +
/// source context produced by the storage crate isn't double-prefixed.
#[error("{detail}")]
@@ -58,7 +58,7 @@ pub enum MagnotiaError {
/// Coarse discriminator for `MagnotiaError::Storage`. The storage crate maps
/// its full typed error onto one of these kinds at the boundary. Backend code
/// that wants finer-grained branching pattern-matches on
/// `magnotia_storage::Error` directly.
/// `lumotia_storage::Error` directly.
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum StorageKind {

View File

@@ -89,7 +89,7 @@ pub fn inference_thread_count(workload: Workload, gpu_offloaded: bool) -> usize
if let Ok(mut seen) = log_seen().lock() {
if seen.insert(key) {
tracing::info!(
target: "magnotia_core::tuning",
target: "lumotia_core::tuning",
threads = final_value,
workload = ?workload,
gpu_offloaded,

View File

@@ -1,11 +1,11 @@
[package]
name = "magnotia-hotkey"
name = "lumotia-hotkey"
version = "0.1.0"
edition = "2021"
description = "Wayland-compatible global hotkey listener for Magnotia — evdev backend with device hotplug"
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
tokio = { version = "1", features = ["rt", "sync", "macros", "time"] }
serde = { version = "1", features = ["derive"] }
tracing = "0.1"

View File

@@ -1,5 +1,5 @@
[package]
name = "magnotia-llm"
name = "lumotia-llm"
version = "0.1.0"
edition = "2021"
description = "Local LLM engine for Magnotia (Qwen3.5 / Qwen3.6 via llama-cpp-2): transcript cleanup, task extraction, micro-step decomposition"
@@ -7,7 +7,7 @@ description = "Local LLM engine for Magnotia (Qwen3.5 / Qwen3.6 via llama-cpp-2)
[features]
# Default desktop build keeps the existing openmp + vulkan acceleration.
# Mobile / CPU-only targets can drop one or both via:
# cargo build -p magnotia-llm --no-default-features
# cargo build -p lumotia-llm --no-default-features
# These are independent so an Android Vulkan build can opt into vulkan
# without openmp (the NDK ships OpenMP libs but the toolchain configuration
# is fragile across NDK versions).
@@ -16,7 +16,7 @@ gpu-vulkan = ["llama-cpp-2/vulkan"]
openmp = ["llama-cpp-2/openmp"]
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
encoding_rs = "0.8"
futures-util = "0.3"
llama-cpp-2 = { version = "0.1.146", default-features = false }

View File

@@ -9,7 +9,7 @@ use llama_cpp_2::llama_batch::LlamaBatch;
use llama_cpp_2::model::params::LlamaModelParams;
use llama_cpp_2::model::{AddBos, LlamaChatMessage, LlamaChatTemplate, LlamaModel};
use llama_cpp_2::sampling::LlamaSampler;
use magnotia_core::tuning::{inference_thread_count, Workload};
use lumotia_core::tuning::{inference_thread_count, Workload};
use serde::{Deserialize, Serialize};
pub mod grammars;

View File

@@ -240,7 +240,7 @@ pub fn recommend_tier(total_ram_bytes: u64, total_vram_bytes: Option<u64>) -> Ll
}
pub fn model_dir() -> PathBuf {
magnotia_core::paths::app_paths().llm_models_dir()
lumotia_core::paths::app_paths().llm_models_dir()
}
pub fn model_path(id: LlmModelId) -> PathBuf {

View File

@@ -10,7 +10,7 @@
use std::env;
use std::path::PathBuf;
use magnotia_llm::{is_valid_intent, LlmEngine, LlmModelId};
use lumotia_llm::{is_valid_intent, LlmEngine, LlmModelId};
#[test]
fn extract_content_tags_returns_valid_pair() {

View File

@@ -11,8 +11,8 @@
use std::env;
use std::path::PathBuf;
use magnotia_llm::LlmEngine;
use magnotia_llm::LlmModelId;
use lumotia_llm::LlmEngine;
use lumotia_llm::LlmModelId;
#[test]
fn llama_cpp_2_smoke_generates_and_wraps() {
@@ -32,7 +32,7 @@ fn llama_cpp_2_smoke_generates_and_wraps() {
let completion = engine
.generate(
"Write exactly one short greeting.",
&magnotia_llm::GenerationConfig {
&lumotia_llm::GenerationConfig {
max_tokens: 32,
temperature: 0.0,
stop_sequences: vec!["\n".to_string()],

View File

@@ -1,18 +1,18 @@
[package]
name = "magnotia-mcp"
name = "lumotia-mcp"
version = "0.1.0"
edition = "2021"
description = "Read-only MCP stdio server exposing Magnotia transcripts and tasks to external agents"
[[bin]]
name = "magnotia-mcp"
name = "lumotia-mcp"
path = "src/main.rs"
[lib]
path = "src/lib.rs"
[dependencies]
magnotia-storage = { path = "../storage" }
lumotia-storage = { path = "../storage" }
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "sqlite"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

View File

@@ -206,7 +206,7 @@ async fn list_transcripts_tool(pool: &SqlitePool, args: Value) -> Result<Value,
};
let limit = args.limit.unwrap_or(20).clamp(1, 200);
let rows = magnotia_storage::list_transcripts(pool, limit)
let rows = lumotia_storage::list_transcripts(pool, limit)
.await
.map_err(|e| error(-32603, format!("DB error: {e}")))?;
@@ -239,7 +239,7 @@ async fn get_transcript_tool(pool: &SqlitePool, args: Value) -> Result<Value, Js
let args: Args = serde_json::from_value(args)
.map_err(|e| error(-32602, format!("Invalid arguments: {e}")))?;
let row = magnotia_storage::get_transcript(pool, &args.id)
let row = lumotia_storage::get_transcript(pool, &args.id)
.await
.map_err(|e| error(-32603, format!("DB error: {e}")))?
.ok_or_else(|| error(-32000, format!("Transcript {} not found", args.id)))?;
@@ -273,7 +273,7 @@ async fn search_transcripts_tool(pool: &SqlitePool, args: Value) -> Result<Value
.map_err(|e| error(-32602, format!("Invalid arguments: {e}")))?;
let limit = args.limit.unwrap_or(20).clamp(1, 100);
let rows = magnotia_storage::search_transcripts(pool, &args.query, limit)
let rows = lumotia_storage::search_transcripts(pool, &args.query, limit)
.await
.map_err(|e| error(-32603, format!("DB error: {e}")))?;
@@ -296,7 +296,7 @@ async fn search_transcripts_tool(pool: &SqlitePool, args: Value) -> Result<Value
}
async fn list_tasks_tool(pool: &SqlitePool) -> Result<Value, JsonRpcError> {
let rows = magnotia_storage::list_tasks(pool)
let rows = lumotia_storage::list_tasks(pool)
.await
.map_err(|e| error(-32603, format!("DB error: {e}")))?;
@@ -460,7 +460,7 @@ mod tests {
});
let pool = sqlx::SqlitePool::connect("sqlite::memory:").await.unwrap();
magnotia_storage::migrations::run_migrations(&pool)
lumotia_storage::migrations::run_migrations(&pool)
.await
.unwrap();
let response = handle_message(&pool, request).await.expect("has response");

View File

@@ -1,12 +1,12 @@
//! Stdio entry point for magnotia-mcp. Reads newline-delimited JSON-RPC messages
//! from stdin, dispatches via `magnotia_mcp::handle_message`, writes responses to
//! from stdin, dispatches via `lumotia_mcp::handle_message`, writes responses to
//! stdout. Logs land on stderr so they don't collide with the JSON-RPC stream.
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
let db_path = magnotia_storage::database_path();
let db_path = lumotia_storage::database_path();
eprintln!(
"[magnotia-mcp] opening Magnotia database at {} (read-only)",
db_path.display()
@@ -15,7 +15,7 @@ async fn main() -> anyhow::Result<()> {
// to the user's database, regardless of which tools the dispatcher
// exposes. Migrations are deliberately skipped — this binary never owns
// the schema; the main app is the single migration writer.
let pool = magnotia_storage::init_readonly(&db_path).await?;
let pool = lumotia_storage::init_readonly(&db_path).await?;
eprintln!("[magnotia-mcp] ready, waiting for JSON-RPC on stdin");
let mut lines = BufReader::new(tokio::io::stdin()).lines();
@@ -28,7 +28,7 @@ async fn main() -> anyhow::Result<()> {
}
let response = match serde_json::from_str::<serde_json::Value>(trimmed) {
Ok(raw) => match magnotia_mcp::handle_message(&pool, raw).await {
Ok(raw) => match lumotia_mcp::handle_message(&pool, raw).await {
Some(response) => response,
None => continue, // notification — no reply
},
@@ -39,7 +39,7 @@ async fn main() -> anyhow::Result<()> {
// clients saw silence instead of a structured error
// (2026-04-22 review MAJOR).
eprintln!("[magnotia-mcp] parse error: {err}");
magnotia_mcp::parse_error_response(&err.to_string())
lumotia_mcp::parse_error_response(&err.to_string())
}
};

View File

@@ -1,11 +1,11 @@
[package]
name = "magnotia-storage"
name = "lumotia-storage"
version = "0.1.0"
edition = "2021"
description = "SQLite persistence, BM25 search, and file storage for Magnotia"
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
# SQLite with compile-time checked queries
# default-features = false strips sqlx's `any`, `macros`, `migrate`, `json` —
@@ -24,7 +24,7 @@ serde = { version = "1", features = ["derive"] }
# Logging
log = "0.4"
# Structured error derivation for magnotia_storage::Error.
# Structured error derivation for lumotia_storage::Error.
thiserror = "1"
# UUIDs for profile + profile_terms ids (v7 random).

View File

@@ -1,7 +1,7 @@
//! Storage-local typed error.
//!
//! Backend code that wants to branch on storage failure modes pattern-matches
//! on [`Error`] directly. The crate boundary into [`magnotia_core::error::MagnotiaError`]
//! on [`Error`] directly. The crate boundary into [`lumotia_core::error::MagnotiaError`]
//! flattens this into a [`MagnotiaError::Storage`] variant carrying a serde-friendly
//! `kind`, an `operation` label, and the Display output as `detail` — so the
//! frontend (which still receives stringified errors from Tauri commands today)
@@ -14,7 +14,7 @@
use std::borrow::Cow;
use std::path::PathBuf;
use magnotia_core::error::{MagnotiaError, StorageKind};
use lumotia_core::error::{MagnotiaError, StorageKind};
/// Kinds of database-open operation that can fail before the pool is ready.
#[derive(Debug, Clone, Copy)]

View File

@@ -1,28 +1,28 @@
use std::path::PathBuf;
pub fn app_data_dir() -> PathBuf {
magnotia_core::paths::app_paths().app_data_dir()
lumotia_core::paths::app_paths().app_data_dir()
}
/// Path to the SQLite database file.
pub fn database_path() -> PathBuf {
magnotia_core::paths::app_paths().database_path()
lumotia_core::paths::app_paths().database_path()
}
/// Directory for saved audio recordings.
pub fn recordings_dir() -> PathBuf {
magnotia_core::paths::app_paths().recordings_dir()
lumotia_core::paths::app_paths().recordings_dir()
}
/// Directory for crash dumps written by the Rust panic hook.
/// Each crash is a single text file: `<unix-ts>-<short-id>.crash`.
/// Used by the diagnostic-report bundler in Settings → About.
pub fn crashes_dir() -> PathBuf {
magnotia_core::paths::app_paths().crashes_dir()
lumotia_core::paths::app_paths().crashes_dir()
}
/// Directory for the rolling Rust log file (magnotia.log + rotated magnotia.log.1, etc).
/// Subscribers configured in src-tauri/src/lib.rs at startup.
pub fn logs_dir() -> PathBuf {
magnotia_core::paths::app_paths().logs_dir()
lumotia_core::paths::app_paths().logs_dir()
}

View File

@@ -1,5 +1,5 @@
[package]
name = "magnotia-transcription"
name = "lumotia-transcription"
version = "0.1.0"
edition = "2021"
description = "Speech-to-text engine wrappers, model management, and inference concurrency for Magnotia"
@@ -15,18 +15,18 @@ build = "build.rs"
# `whisper-vulkan` is a separate feature so a non-Vulkan target (Android
# without GPU drivers, a CPU-only Windows build) can pull in whisper-rs
# but skip the Vulkan backend. Build CPU-only with:
# cargo build -p magnotia-transcription --no-default-features --features whisper
# cargo build -p lumotia-transcription --no-default-features --features whisper
default = ["whisper", "whisper-vulkan"]
whisper = ["dep:whisper-rs"]
whisper-vulkan = ["whisper-rs?/vulkan"]
[dependencies]
magnotia-core = { path = "../core" }
lumotia-core = { path = "../core" }
# TranscriptionProvider async trait + EngineProfile + ProviderId. The
# trait lives in cloud-providers so an OEM licensee can implement it
# without depending on transcription internals.
magnotia-cloud-providers = { path = "../cloud-providers" }
lumotia-cloud-providers = { path = "../cloud-providers" }
# Async-trait for the LocalProviderAdapter impl.
async-trait = "0.1"
@@ -57,12 +57,12 @@ thiserror = "2"
tracing = "0.1"
[dev-dependencies]
# TcpListener fixture for the download resume tests (mirrors magnotia-llm).
# TcpListener fixture for the download resume tests (mirrors lumotia-llm).
# `macros` and `rt-multi-thread` enable #[tokio::test] and the multi-threaded
# scheduler used by the orchestrator tests.
tokio = { version = "1", features = ["rt", "rt-multi-thread", "sync", "net", "io-util", "macros"] }
tempfile = "3"
# Test-only — used by tests/thread_sweep.rs to label physical vs logical
# core counts in the scaling table. Production code uses the
# `magnotia_core::constants::inference_thread_count` helper instead.
# `lumotia_core::constants::inference_thread_count` helper instead.
num_cpus = "1"

View File

@@ -11,7 +11,7 @@
//! workspace ever pulls `tokenizers` into the dependency graph on a
//! Windows target. If we ever legitimately need it we can reintroduce
//! it via a sidecar (isolated process, separate CRT) rather than
//! linking it into `magnotia_lib`.
//! linking it into `lumotia_lib`.
//!
//! The check is advisory on non-Windows targets — it still prints a
//! cargo:warning if `tokenizers` appears, so the Windows failure isn't

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::{AudioSamples, TranscriptionOptions};
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::{AudioSamples, TranscriptionOptions};
use crate::local_engine::{LocalEngine, TimedTranscript};

View File

@@ -23,11 +23,11 @@ pub use transcribe_rs::SpeechModel;
pub use transcriber::{Transcriber, TranscriberCapabilities};
// Re-export the trait surface so downstream crates depend only on
// `magnotia_transcription` to access both local engines and the
// provider trait without a separate `magnotia_cloud_providers`
// `lumotia_transcription` to access both local engines and the
// provider trait without a separate `lumotia_cloud_providers`
// dependency. This is the seam an OEM licensee uses when they swap
// providers.
pub use magnotia_cloud_providers::{
pub use lumotia_cloud_providers::{
CostClass, EngineProfile, NetworkRequirement, ProviderCapabilities, ProviderId, ProviderKind,
ProviderTranscript, TranscriptionProvider,
};

View File

@@ -4,8 +4,8 @@ use std::time::Instant;
use transcribe_rs::{SpeechModel, TranscribeOptions, TranscriptionResult};
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::{
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::{
AudioSamples, EngineName, ModelId, Segment, Transcript, TranscriptionOptions,
};
@@ -28,7 +28,7 @@ pub struct SpeechModelAdapter(pub Box<dyn SpeechModel + Send>);
impl Transcriber for SpeechModelAdapter {
fn capabilities(&self) -> TranscriberCapabilities {
TranscriberCapabilities {
sample_rate: magnotia_core::constants::WHISPER_SAMPLE_RATE,
sample_rate: lumotia_core::constants::WHISPER_SAMPLE_RATE,
channels: 1,
supports_initial_prompt: false,
}

View File

@@ -2,9 +2,9 @@ use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::sync::{LazyLock, Mutex};
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::model_registry::{find_model, ModelFile};
use magnotia_core::types::{DownloadProgress, ModelId};
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::model_registry::{find_model, ModelFile};
use lumotia_core::types::{DownloadProgress, ModelId};
static ACTIVE_DOWNLOADS: LazyLock<Mutex<HashSet<String>>> =
LazyLock::new(|| Mutex::new(HashSet::new()));
@@ -40,12 +40,12 @@ impl Drop for DownloadReservation {
/// Windows: %LOCALAPPDATA%/magnotia/models
/// Unix: ~/.magnotia/models
pub fn models_dir() -> PathBuf {
magnotia_core::paths::app_paths().models_dir()
lumotia_core::paths::app_paths().models_dir()
}
/// Get the directory path where a specific model's files are stored.
pub fn model_dir(id: &ModelId) -> PathBuf {
magnotia_core::paths::app_paths().speech_model_dir(id)
lumotia_core::paths::app_paths().speech_model_dir(id)
}
/// Check whether all files for a model have been downloaded.
@@ -61,7 +61,7 @@ pub fn is_downloaded(id: &ModelId) -> bool {
/// List all downloaded model IDs.
pub fn list_downloaded() -> Vec<ModelId> {
magnotia_core::model_registry::all_models()
lumotia_core::model_registry::all_models()
.iter()
.filter(|m| is_downloaded(&m.id))
.map(|m| m.id.clone())
@@ -117,7 +117,7 @@ fn verified_manifest_path(dir: &Path) -> PathBuf {
}
fn verified_manifest_matches(
entry: &magnotia_core::model_registry::ModelEntry,
entry: &lumotia_core::model_registry::ModelEntry,
dir: &Path,
) -> bool {
let manifest = match std::fs::read_to_string(verified_manifest_path(dir)) {
@@ -140,7 +140,7 @@ fn verified_manifest_matches(
}
fn write_verified_manifest(
entry: &magnotia_core::model_registry::ModelEntry,
entry: &lumotia_core::model_registry::ModelEntry,
dir: &Path,
) -> std::io::Result<()> {
let mut lines = Vec::with_capacity(entry.files.len() + 1);
@@ -357,7 +357,7 @@ mod tests {
let list = list_downloaded();
// In test environment, no models are downloaded
// This just verifies the function doesn't panic
assert!(list.len() <= magnotia_core::model_registry::all_models().len());
assert!(list.len() <= lumotia_core::model_registry::all_models().len());
}
#[test]
@@ -481,7 +481,7 @@ mod tests {
let file = ModelFile {
filename: leak(dest.file_name().unwrap().to_string_lossy().into_owned()),
url: leak(format!("http://{addr}/fixture.bin")),
size: magnotia_core::types::Megabytes(0),
size: lumotia_core::types::Megabytes(0),
sha256: leak(expected_sha.clone()),
};
let id = ModelId::new("test-fixture");
@@ -516,7 +516,7 @@ mod tests {
let file = ModelFile {
filename: leak(dest.file_name().unwrap().to_string_lossy().into_owned()),
url: leak(format!("http://{addr}/fixture.bin")),
size: magnotia_core::types::Megabytes(0),
size: lumotia_core::types::Megabytes(0),
sha256: leak(expected_sha),
};
let id = ModelId::new("test-fixture");
@@ -571,7 +571,7 @@ mod tests {
let file = ModelFile {
filename: leak(dest.file_name().unwrap().to_string_lossy().into_owned()),
url: leak(format!("http://{addr}/fixture.bin")),
size: magnotia_core::types::Megabytes(0),
size: lumotia_core::types::Megabytes(0),
sha256: leak("0".repeat(64)),
};
let id = ModelId::new("test-fixture");
@@ -599,7 +599,7 @@ mod tests {
let file = ModelFile {
filename: leak(dest.file_name().unwrap().to_string_lossy().into_owned()),
url: leak(format!("http://{addr}/fixture.bin")),
size: magnotia_core::types::Megabytes(0),
size: lumotia_core::types::Megabytes(0),
sha256: leak("deadbeef".repeat(8)),
};
let id = ModelId::new("test-fixture");

View File

@@ -18,12 +18,12 @@
use std::sync::Arc;
use async_trait::async_trait;
use magnotia_cloud_providers::{
use lumotia_cloud_providers::{
CostClass, EngineProfile, ProviderCapabilities, ProviderId, ProviderKind, ProviderTranscript,
TranscriptionProvider,
};
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::types::{AudioSamples, TranscriptionOptions};
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::types::{AudioSamples, TranscriptionOptions};
use crate::local_engine::LocalEngine;
use crate::registry::EngineRegistry;
@@ -68,7 +68,7 @@ impl TranscriptionProvider for LocalProviderAdapter {
ProviderCapabilities {
sample_rate: local
.map(|c| c.sample_rate)
.unwrap_or(magnotia_core::constants::WHISPER_SAMPLE_RATE),
.unwrap_or(lumotia_core::constants::WHISPER_SAMPLE_RATE),
channels: local.map(|c| c.channels).unwrap_or(1),
initial_prompt_supported: local.map(|c| c.supports_initial_prompt).unwrap_or(false),
language_hint_supported: true,
@@ -153,7 +153,7 @@ mod tests {
use std::sync::atomic::{AtomicUsize, Ordering};
use magnotia_core::types::{Segment, Transcript};
use lumotia_core::types::{Segment, Transcript};
/// Mock provider that returns a canned transcript and counts
/// invocations. Used to validate the orchestrator's dispatch logic

View File

@@ -15,7 +15,7 @@
use std::collections::HashMap;
use std::sync::Arc;
use magnotia_cloud_providers::{ProviderId, TranscriptionProvider};
use lumotia_cloud_providers::{ProviderId, TranscriptionProvider};
/// Catalogue of providers known to the orchestrator.
pub struct EngineRegistry {
@@ -82,11 +82,11 @@ mod tests {
use super::*;
use async_trait::async_trait;
use magnotia_cloud_providers::{
use lumotia_cloud_providers::{
CostClass, EngineProfile, ProviderCapabilities, ProviderKind, ProviderTranscript,
};
use magnotia_core::error::Result;
use magnotia_core::types::{AudioSamples, Transcript, TranscriptionOptions};
use lumotia_core::error::Result;
use lumotia_core::types::{AudioSamples, Transcript, TranscriptionOptions};
struct DummyProvider {
id: ProviderId,

View File

@@ -9,8 +9,8 @@
//! `whisper` feature — `WhisperRsBackend` (direct whisper-rs, the only
//! path that pipes `initial_prompt`).
use magnotia_core::error::Result;
use magnotia_core::types::{Segment, TranscriptionOptions};
use lumotia_core::error::Result;
use lumotia_core::types::{Segment, TranscriptionOptions};
/// Static capabilities a `Transcriber` advertises to callers.
///

View File

@@ -10,10 +10,10 @@ use std::path::Path;
use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
use magnotia_core::error::{MagnotiaError, Result};
use magnotia_core::hardware::vulkan_loader_available;
use magnotia_core::tuning::{inference_thread_count, Workload};
use magnotia_core::types::{Segment, TranscriptionOptions};
use lumotia_core::error::{MagnotiaError, Result};
use lumotia_core::hardware::vulkan_loader_available;
use lumotia_core::tuning::{inference_thread_count, Workload};
use lumotia_core::types::{Segment, TranscriptionOptions};
use crate::transcriber::{Transcriber, TranscriberCapabilities};
@@ -42,7 +42,7 @@ impl WhisperRsBackend {
impl Transcriber for WhisperRsBackend {
fn capabilities(&self) -> TranscriberCapabilities {
TranscriberCapabilities {
sample_rate: magnotia_core::constants::WHISPER_SAMPLE_RATE,
sample_rate: lumotia_core::constants::WHISPER_SAMPLE_RATE,
channels: 1,
supports_initial_prompt: true,
}

View File

@@ -9,8 +9,8 @@
use std::env;
use std::time::Instant;
use magnotia_core::hardware::vulkan_loader_available;
use magnotia_core::tuning::{inference_thread_count, Workload};
use lumotia_core::hardware::vulkan_loader_available;
use lumotia_core::tuning::{inference_thread_count, Workload};
use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
#[test]

View File

@@ -1,22 +1,22 @@
[package]
name = "magnotia"
name = "lumotia"
version = "0.1.0"
description = "Magnotia — Think out loud"
description = "Lumotia — Think out loud"
authors = ["CORBEL Ltd"]
edition = "2021"
[lib]
name = "magnotia_lib"
name = "lumotia_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[features]
# Default build includes the Whisper backend. Disabling this feature
# also drops it from magnotia-transcription (see Cargo.toml in that crate)
# also drops it from lumotia-transcription (see Cargo.toml in that crate)
# so a --no-default-features workspace build does not pull whisper-rs-sys.
# load_model_from_disk returns a runtime error for Engine::Whisper when
# this feature is off; Parakeet continues to work.
default = ["whisper"]
whisper = ["magnotia-transcription/whisper"]
whisper = ["lumotia-transcription/whisper"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
@@ -28,14 +28,14 @@ serde_json = "1"
[dependencies]
# Workspace crates
magnotia-core = { path = "../crates/core" }
magnotia-audio = { path = "../crates/audio" }
magnotia-transcription = { path = "../crates/transcription", default-features = false }
magnotia-ai-formatting = { path = "../crates/ai-formatting" }
magnotia-storage = { path = "../crates/storage" }
magnotia-cloud-providers = { path = "../crates/cloud-providers" }
magnotia-hotkey = { path = "../crates/hotkey" }
magnotia-llm = { path = "../crates/llm" }
lumotia-core = { path = "../crates/core" }
lumotia-audio = { path = "../crates/audio" }
lumotia-transcription = { path = "../crates/transcription", default-features = false }
lumotia-ai-formatting = { path = "../crates/ai-formatting" }
lumotia-storage = { path = "../crates/storage" }
lumotia-cloud-providers = { path = "../crates/cloud-providers" }
lumotia-hotkey = { path = "../crates/hotkey" }
lumotia-llm = { path = "../crates/llm" }
# Tauri. The `tray-icon` feature, the global-shortcut/window-state/
# autostart plugins are desktop-only — gated below under

View File

@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
use tauri::Manager;
use crate::commands::security::ensure_main_window;
use magnotia_audio::{DeviceInfo, MicrophoneCapture};
use lumotia_audio::{DeviceInfo, MicrophoneCapture};
/// Enumerate every input device available to cpal, with metadata for the
/// Settings device-picker UI. Includes a flag for likely PulseAudio /

View File

@@ -15,7 +15,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use serde::{Deserialize, Serialize};
use magnotia_storage::{
use lumotia_storage::{
app_data_dir, crashes_dir, list_recent_errors, log_error, logs_dir, ErrorLogRow,
};
@@ -335,7 +335,7 @@ async fn generate_diagnostic_report_inner(
if opts.include_settings {
out.push_str("## Settings (sanitised)\n\n");
match magnotia_storage::get_setting(&state.db, "magnotia_preferences").await {
match lumotia_storage::get_setting(&state.db, "magnotia_preferences").await {
Ok(Some(json)) => {
out.push_str("```json\n");
out.push_str(&sanitise_preferences_json(&json));
@@ -520,7 +520,7 @@ pub async fn save_diagnostic_report(
let _ = app; // reserved for future dialog integration
let report = generate_diagnostic_report_inner(&state, options).await?;
let dir = magnotia_storage::app_data_dir().join("diagnostic-reports");
let dir = lumotia_storage::app_data_dir().join("diagnostic-reports");
fs::create_dir_all(&dir).map_err(|e| format!("create dir: {e}"))?;
let ts = SystemTime::now()

View File

@@ -5,7 +5,7 @@
use serde::Deserialize;
use magnotia_storage::{
use lumotia_storage::{
record_feedback as db_record_feedback, FeedbackTargetType, RecordFeedbackParams,
};

View File

@@ -1,7 +1,7 @@
use serde::Serialize;
use magnotia_core::hardware::{self, Os};
use magnotia_core::recommendation;
use lumotia_core::hardware::{self, Os};
use lumotia_core::recommendation;
#[derive(Serialize)]
pub struct SystemInfo {
@@ -53,7 +53,7 @@ pub fn rank_models() -> Result<Vec<ModelRecommendation>, String> {
Ok(ranked
.into_iter()
.map(|scored| {
let downloaded = magnotia_transcription::is_downloaded(&scored.entry.id);
let downloaded = lumotia_transcription::is_downloaded(&scored.entry.id);
ModelRecommendation {
id: scored.entry.id.as_str().to_string(),
display_name: scored.entry.display_name,

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use tauri::Emitter;
use tokio::sync::{mpsc, Mutex};
use magnotia_hotkey::{EvdevHotkeyListener, HotkeyCombo, HotkeyEvent};
use lumotia_hotkey::{EvdevHotkeyListener, HotkeyCombo, HotkeyEvent};
/// Managed state for the evdev hotkey listener.
pub struct HotkeyState {
@@ -30,7 +30,7 @@ pub fn is_wayland_session() -> bool {
/// Check whether evdev hotkey capture is available (user in `input` group, etc.).
#[tauri::command]
pub fn check_hotkey_access() -> Result<(), String> {
magnotia_hotkey::check_evdev_access()
lumotia_hotkey::check_evdev_access()
}
/// Start the evdev global hotkey listener. Emits "magnotia:hotkey-pressed" and

View File

@@ -7,7 +7,7 @@
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use magnotia_storage::{
use lumotia_storage::{
delete_implementation_rule as db_delete_rule, get_task_by_id,
insert_implementation_rule as db_insert_rule, list_implementation_rules as db_list_rules,
mark_implementation_rule_fired as db_mark_rule_fired,

View File

@@ -19,13 +19,13 @@ use crate::commands::models::{default_model_id_for_engine, ensure_model_loaded};
use crate::commands::power::PowerAssertion;
use crate::commands::security::ensure_main_window;
use crate::AppState;
use magnotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
use magnotia_audio::{
use lumotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
use lumotia_audio::{
AudioChunk, CaptureRuntimeError, MicrophoneCapture, StreamingResampler, WavWriter,
};
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
use magnotia_core::types::{AudioSamples, Segment, TranscriptionOptions};
use magnotia_transcription::LocalEngine;
use lumotia_core::constants::WHISPER_SAMPLE_RATE;
use lumotia_core::types::{AudioSamples, Segment, TranscriptionOptions};
use lumotia_transcription::LocalEngine;
const CHUNK_SAMPLES: usize = 32_000; // 2s at 16kHz
const OVERLAP_SAMPLES: usize = 4_000; // 0.25s at 16kHz
@@ -450,7 +450,7 @@ struct InferenceTask {
chunk_start_sample: u64,
trim_before_secs: f64,
duration_secs: f64,
rx: std::sync::mpsc::Receiver<Result<magnotia_transcription::TimedTranscript, String>>,
rx: std::sync::mpsc::Receiver<Result<lumotia_transcription::TimedTranscript, String>>,
}
#[derive(Debug, Clone)]
@@ -503,15 +503,15 @@ pub async fn start_live_transcription_session(
let resolved_profile_id = config
.profile_id
.clone()
.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
.unwrap_or_else(|| lumotia_storage::DEFAULT_PROFILE_ID.to_string());
let profile = magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
let profile = lumotia_storage::database::get_profile(&state.db, &resolved_profile_id)
.await
.map_err(|e| e.to_string())?
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
let profile_terms: Vec<String> =
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
lumotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
.await
.map_err(|e| e.to_string())?
.into_iter()
@@ -1555,8 +1555,8 @@ mod tests {
let stop_flag = Arc::new(AtomicBool::new(false));
let (tx1, rx1) = std::sync::mpsc::channel();
tx1.send(Ok(magnotia_transcription::TimedTranscript {
transcript: magnotia_core::types::Transcript::new(
tx1.send(Ok(lumotia_transcription::TimedTranscript {
transcript: lumotia_core::types::Transcript::new(
vec![segment(0.0, 0.8, "first chunk")],
"en".into(),
0.8,
@@ -1597,8 +1597,8 @@ mod tests {
);
let (tx2, rx2) = std::sync::mpsc::channel();
tx2.send(Ok(magnotia_transcription::TimedTranscript {
transcript: magnotia_core::types::Transcript::new(
tx2.send(Ok(lumotia_transcription::TimedTranscript {
transcript: lumotia_core::types::Transcript::new(
vec![segment(0.0, 0.9, "second chunk")],
"en".into(),
0.9,

View File

@@ -3,10 +3,10 @@ use tauri::{Emitter, State};
use crate::commands::power::PowerAssertion;
use crate::commands::security::ensure_main_window;
use crate::AppState;
use magnotia_ai_formatting::{llm_cleanup_text, LlmPromptPreset};
use magnotia_core::hardware;
use magnotia_llm::model_manager::{self, model_info};
use magnotia_llm::{ContentTags, LlmModelId};
use lumotia_ai_formatting::{llm_cleanup_text, LlmPromptPreset};
use lumotia_core::hardware;
use lumotia_llm::model_manager::{self, model_info};
use lumotia_llm::{ContentTags, LlmModelId};
#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
@@ -369,9 +369,9 @@ pub async fn cleanup_transcript_text_cmd(
) -> Result<String, String> {
ensure_main_window(&window)?;
let resolved_profile_id =
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
profile_id.unwrap_or_else(|| lumotia_storage::DEFAULT_PROFILE_ID.to_string());
let profile_terms: Vec<String> =
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
lumotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
.await
.map_err(|e| e.to_string())?
.into_iter()

View File

@@ -7,7 +7,7 @@
use std::sync::Mutex;
use magnotia_core::process_watch::{self, ProcessLister};
use lumotia_core::process_watch::{self, ProcessLister};
/// Tauri-managed state for the meeting poller. Holds a long-lived
/// `ProcessLister` so each poll refreshes the existing `sysinfo::System`

View File

@@ -5,14 +5,14 @@ use tauri::Emitter;
use crate::commands::security::ensure_main_window;
use crate::AppState;
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
use magnotia_core::hardware::{self, vulkan_loader_available, CpuFeatures};
use magnotia_core::model_registry::{self, Engine, LanguageSupport, ModelEntry};
use magnotia_core::types::{AudioSamples, ModelId, TranscriptionOptions};
use lumotia_core::constants::WHISPER_SAMPLE_RATE;
use lumotia_core::hardware::{self, vulkan_loader_available, CpuFeatures};
use lumotia_core::model_registry::{self, Engine, LanguageSupport, ModelEntry};
use lumotia_core::types::{AudioSamples, ModelId, TranscriptionOptions};
#[cfg(feature = "whisper")]
use magnotia_transcription::load_whisper;
use magnotia_transcription::model_manager;
use magnotia_transcription::{load_parakeet, LocalEngine, Transcriber};
use lumotia_transcription::load_whisper;
use lumotia_transcription::model_manager;
use lumotia_transcription::{load_parakeet, LocalEngine, Transcriber};
/// Map legacy size strings to ModelId.
fn whisper_model_id(size: &str) -> ModelId {

View File

@@ -1,5 +1,5 @@
// Tauri commands wrapping magnotia_storage profile + profile_term CRUD.
// Pattern mirrors tasks.rs — flat imports from `magnotia_storage` with a `db_`
// Tauri commands wrapping lumotia_storage profile + profile_term CRUD.
// Pattern mirrors tasks.rs — flat imports from `lumotia_storage` with a `db_`
// alias prefix to avoid name collisions with the command functions, plain
// snake_case parameters (Tauri 2.x auto-converts camelCase JS keys),
// `.map_err(|e| e.to_string())` for error conversion, and camelCase DTOs
@@ -11,8 +11,8 @@
use serde::Serialize;
use magnotia_ai_formatting::extract_corrections;
use magnotia_storage::{
use lumotia_ai_formatting::extract_corrections;
use lumotia_storage::{
add_profile_term as db_add_profile_term, create_profile as db_create_profile,
delete_profile as db_delete_profile, delete_profile_term as db_delete_profile_term,
list_profile_terms as db_list_profile_terms, list_profiles as db_list_profiles,

View File

@@ -7,10 +7,10 @@
//! filtering rather than adding a second query path.
//!
//! Stored under the existing SQLite settings table via
//! `magnotia_storage::{get_setting, set_setting}` — same bag as
//! `lumotia_storage::{get_setting, set_setting}` — same bag as
//! `magnotia_preferences`.
use magnotia_storage::{get_setting, set_setting};
use lumotia_storage::{get_setting, set_setting};
use crate::AppState;

View File

@@ -1,4 +1,4 @@
// Tauri commands wrapping magnotia_storage task CRUD.
// Tauri commands wrapping lumotia_storage task CRUD.
// Pattern mirrors transcripts.rs — TaskDto is the camelCase frontend shape,
// storage functions are aliased with db_ prefix to avoid name collisions.
@@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid;
use magnotia_llm::prompts::FeedbackExample as LlmFeedbackExample;
use magnotia_storage::{
use lumotia_llm::prompts::FeedbackExample as LlmFeedbackExample;
use lumotia_storage::{
complete_subtask_and_check_parent as db_complete_subtask, complete_task as db_complete_task,
delete_task as db_delete_task, get_task_by_id as db_get_task,
insert_subtask as db_insert_subtask, insert_task as db_insert_task,
@@ -228,7 +228,7 @@ fn to_llm_examples(rows: Vec<FeedbackRow>) -> Vec<LlmFeedbackExample> {
Ok(v) => v,
Err(e) => {
tracing::warn!(
target: "magnotia_lib::feedback",
target: "lumotia_lib::feedback",
row_id = r.id,
error = %e,
"skipping feedback row with malformed context_json"

View File

@@ -9,9 +9,9 @@ use crate::commands::build_initial_prompt;
use crate::commands::models::{default_model_id_for_engine, ensure_model_loaded};
use crate::commands::security::ensure_main_window;
use crate::AppState;
use magnotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
use magnotia_core::types::{AudioSamples, Segment, Transcript, TranscriptionOptions};
use lumotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
use lumotia_core::constants::WHISPER_SAMPLE_RATE;
use lumotia_core::types::{AudioSamples, Segment, Transcript, TranscriptionOptions};
const PARAKEET_CHUNK_THRESHOLD_SECS: usize = 18;
const PARAKEET_CHUNK_SECS: usize = 15;
@@ -29,7 +29,7 @@ struct ChunkingStrategy {
fn pick_engine(
state: &AppState,
engine: &str,
) -> Result<Arc<magnotia_transcription::LocalEngine>, String> {
) -> Result<Arc<lumotia_transcription::LocalEngine>, String> {
match engine {
"whisper" => Ok(state.whisper_engine.clone()),
"parakeet" => Ok(state.parakeet_engine.clone()),
@@ -70,11 +70,11 @@ fn trim_overlap_segments(segments: &mut Vec<Segment>, trim_before_secs: f64) {
}
fn transcribe_samples_sync(
engine: Arc<magnotia_transcription::LocalEngine>,
engine: Arc<lumotia_transcription::LocalEngine>,
engine_name: &str,
samples: Vec<f32>,
options: TranscriptionOptions,
) -> Result<magnotia_transcription::TimedTranscript, String> {
) -> Result<lumotia_transcription::TimedTranscript, String> {
let Some(strategy) = pick_chunking_strategy(engine_name, samples.len()) else {
let audio = AudioSamples::mono_16khz(samples);
return engine
@@ -128,7 +128,7 @@ fn transcribe_samples_sync(
chunk_start = chunk_end.saturating_sub(strategy.overlap_samples);
}
Ok(magnotia_transcription::TimedTranscript {
Ok(lumotia_transcription::TimedTranscript {
transcript: Transcript::new(
all_segments,
options.language.clone().unwrap_or_else(|| "en".to_string()),
@@ -165,15 +165,15 @@ pub async fn transcribe_file(
) -> Result<serde_json::Value, String> {
ensure_main_window(&window)?;
let resolved_profile_id =
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
profile_id.unwrap_or_else(|| lumotia_storage::DEFAULT_PROFILE_ID.to_string());
let profile = magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
let profile = lumotia_storage::database::get_profile(&state.db, &resolved_profile_id)
.await
.map_err(|e| e.to_string())?
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
let profile_terms: Vec<String> =
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
lumotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
.await
.map_err(|e| e.to_string())?
.into_iter()
@@ -199,7 +199,7 @@ pub async fn transcribe_file(
let engine_name_for_worker = engine_name.clone();
let path_for_probe = Path::new(&path);
if let Some(duration_secs) =
magnotia_audio::probe_audio_duration_secs(path_for_probe).map_err(|e| e.to_string())?
lumotia_audio::probe_audio_duration_secs(path_for_probe).map_err(|e| e.to_string())?
{
if duration_secs > MAX_FILE_TRANSCRIPTION_SECS {
return Err(format!(
@@ -210,12 +210,12 @@ pub async fn transcribe_file(
}
let timed = tokio::task::spawn_blocking(move || {
let audio = magnotia_audio::decode_audio_file_limited(
let audio = lumotia_audio::decode_audio_file_limited(
Path::new(&path),
Some(MAX_FILE_TRANSCRIPTION_SECS),
)
.map_err(|e| e.to_string())?;
let resampled = magnotia_audio::resample_to_16khz(&audio).map_err(|e| e.to_string())?;
let resampled = lumotia_audio::resample_to_16khz(&audio).map_err(|e| e.to_string())?;
transcribe_samples_sync(
engine,
&engine_name_for_worker,

View File

@@ -1,4 +1,4 @@
// Tauri commands wrapping the magnotia_storage transcript CRUD.
// Tauri commands wrapping the lumotia_storage transcript CRUD.
// These are the bridge that lets the Svelte frontend treat SQLite as the
// canonical store rather than localStorage.
//
@@ -13,7 +13,7 @@
use serde::{Deserialize, Serialize};
use magnotia_storage::{
use lumotia_storage::{
delete_transcript as db_delete_transcript, get_transcript as db_get_transcript,
insert_transcript as db_insert_transcript, list_transcripts_paged,
search_transcripts as db_search_transcripts, update_transcript as db_update_transcript,
@@ -110,7 +110,7 @@ pub async fn add_transcript(
profile_id: transcript
.profile_id
.as_deref()
.unwrap_or(magnotia_storage::DEFAULT_PROFILE_ID),
.unwrap_or(lumotia_storage::DEFAULT_PROFILE_ID),
title: transcript.title.as_deref(),
audio_path: transcript.audio_path.as_deref(),
duration: transcript.duration,

View File

@@ -12,15 +12,15 @@ use sqlx::SqlitePool;
use tauri::Manager;
use tracing_subscriber::EnvFilter;
use magnotia_core::types::EngineName;
use magnotia_llm::LlmEngine;
use magnotia_storage::{database_path, get_setting, init as init_db, prune_error_log, set_setting};
use lumotia_core::types::EngineName;
use lumotia_llm::LlmEngine;
use lumotia_storage::{database_path, get_setting, init as init_db, prune_error_log, set_setting};
/// How long to retain `error_log` rows. Pruned once on startup.
/// 90 days is long enough to triage "this happened a few weeks ago"
/// reports and short enough that the table stays kilobyte-scale.
const ERROR_LOG_RETENTION_DAYS: i64 = 90;
use magnotia_transcription::LocalEngine;
use lumotia_transcription::LocalEngine;
static TRACING_INIT: Once = Once::new();
@@ -162,7 +162,7 @@ fn init_tracing() {
TRACING_INIT.call_once(|| {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new(
"warn,magnotia=info,magnotia_lib=info,magnotia_audio=info,magnotia_startup=info,magnotia_hotkey=info,magnotia_ai_formatting=info",
"warn,magnotia=info,lumotia_lib=info,lumotia_audio=info,magnotia_startup=info,lumotia_hotkey=info,lumotia_ai_formatting=info",
)
});

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
magnotia_lib::run()
lumotia_lib::run()
}