Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.
transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
-> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
as immutable audit trail). Includes architecture-map references
to magnotia_core::*, magnotia_storage::*, etc. now pointing at
lumotia_*; dev-setup.md tracing output examples (lumotia_startup
target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
("lumotia_task_sync"); magnotia_locale i18n localStorage key
renamed + migration shim added; CSS keyframe names
magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
to "lumotia era" earlier — restored).
Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
legacy detection strings in legacy_and_target_paths() so the
migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
— migration call sites reference the legacy magnotia keys
deliberately.
- docs/handovers/ — historical audit trail.
cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
111 lines
6.7 KiB
Markdown
111 lines
6.7 KiB
Markdown
---
|
|
name: Small command modules
|
|
type: architecture-map-page
|
|
slice: 02-tauri-runtime
|
|
last_verified: 2026/05/09
|
|
---
|
|
|
|
# Small command modules
|
|
|
|
> **Where you are:** [Architecture map](../../README.md) → [Tauri runtime](../README.md) → [Commands](README.md) → Small commands
|
|
|
|
**Plain English summary.** Seven short modules that each declare one or two commands. Grouped here to keep the slice navigable. Covers clipboard, filesystem write, hardware probe, meeting auto-detect poll, nudges, rituals (morning triage), and the updater stub.
|
|
|
|
## At a glance
|
|
|
|
- Modules covered:
|
|
- `clipboard.rs` (11 LOC, 1 command).
|
|
- `fs.rs` (44 LOC, 1 command).
|
|
- `hardware.rs` (69 LOC, 2 commands).
|
|
- `meeting.rs` (50 LOC, 1 command).
|
|
- `nudges.rs` (63 LOC, 1 command).
|
|
- `rituals.rs` (43 LOC, 2 commands).
|
|
- `update.rs` (16 LOC, 2 commands).
|
|
- Total: 11 commands across 7 small files.
|
|
|
|
## `clipboard.rs`
|
|
|
|
### `copy_to_clipboard(text: String) -> Result<(), String>` (`src-tauri/src/commands/clipboard.rs:5`)
|
|
|
|
Wraps `arboard::Clipboard::set_text`. No window guard. The frontend dictation path calls this when the user wants clipboard-only (no auto-paste), and the History viewer uses it for the copy button. Pairs with `commands::paste::paste_text` for the auto-paste flow.
|
|
|
|
Watch-out: arboard initialisation can fail on Linux Wayland environments without an X11 selection daemon; the error is propagated as `"Clipboard init failed: ..."`.
|
|
|
|
## `fs.rs`
|
|
|
|
### `write_text_file_cmd(path: String, contents: String) -> Result<(), String>` (`src-tauri/src/commands/fs.rs:13`)
|
|
|
|
Phase 9. Thin filesystem write for the save-dialog path. `tokio::fs::write(&path, contents)` with the path attached to the error message so the frontend toast is actionable. The caller is expected to obtain `path` via the OS save dialog (`tauri-plugin-dialog`); no traversal validation here because the dialog already constrains the user's choice.
|
|
|
|
Tests (`fs.rs:19`): `write_text_file_roundtrips_utf8` covers UTF-8 round-trip including non-ASCII; `write_text_file_errors_on_bad_parent` covers a non-existent parent directory.
|
|
|
|
## `hardware.rs`
|
|
|
|
### `SystemInfo` and `ModelRecommendation`
|
|
|
|
Frontend-facing structs. `SystemInfo` carries `ram_mb`, `cpu_brand`, `cpu_cores`, `os`, `gpu`. `ModelRecommendation` carries id / display_name / disk_size_mb / ram_required_mb / description / score / reason / is_downloaded.
|
|
|
|
### `probe_system() -> Result<SystemInfo, String>` (`src-tauri/src/commands/hardware.rs:29`)
|
|
|
|
Wraps `lumotia_core::hardware::probe_system`. Maps the OS enum to a string and the GPU vendor (if probed) to its `Debug` form.
|
|
|
|
### `rank_models() -> Result<Vec<ModelRecommendation>, String>` (`src-tauri/src/commands/hardware.rs:49`)
|
|
|
|
Calls `lumotia_core::recommendation::rank_recommendations` and decorates each entry with `lumotia_transcription::is_downloaded`. Used by Settings → Models for the "recommended for your hardware" list.
|
|
|
|
Both commands are unguarded (any window can call). Pure read-only probes.
|
|
|
|
## `meeting.rs`
|
|
|
|
### `MeetingState` (`src-tauri/src/commands/meeting.rs:16`)
|
|
|
|
Tauri-managed: `lister: Mutex<ProcessLister>`. Holds a long-lived `ProcessLister` so each poll refreshes the existing `sysinfo::System` in place rather than rebuilding the process table from scratch every 15 seconds (the previous implementation did).
|
|
|
|
### `detect_meeting_processes(state, patterns: Vec<String>) -> Result<Vec<String>, String>` (`src-tauri/src/commands/meeting.rs:34`)
|
|
|
|
Phase 8 meeting auto-capture (single-signal variant). Frontend polls this on an interval with the user's app patterns. On a positive hit, the frontend surfaces a non-modal toast that reminds the user to start recording with their hotkey. We do NOT start recording from this signal — the user decides.
|
|
|
|
If `patterns` is empty, returns an empty Vec without locking. Otherwise locks the `lister`, snapshots the process list, and runs `lumotia_core::process_watch::match_meeting_patterns` to filter. Returns the matched process names.
|
|
|
|
Watch-out: the `ProcessLister` lock is `std::sync::Mutex`. If the snapshot ever takes meaningful time, switch to async.
|
|
|
|
## `nudges.rs`
|
|
|
|
### `DeliverNudgeInput` (`src-tauri/src/commands/nudges.rs:28`)
|
|
|
|
`{ title: String, body: String }`.
|
|
|
|
### `deliver_nudge(app, window, input: DeliverNudgeInput) -> Result<(), String>` (`src-tauri/src/commands/nudges.rs:42`)
|
|
|
|
Phase 6. Main-window only via `ensure_main_window`. Trims title and body; if both are empty, return Ok silently (a blank nudge is worse than no nudge). Defaults the title to `"Lumotia"` if only the body is present. Calls `tauri_plugin_notification::NotificationExt::notification().builder().title(...).body(...).show()`.
|
|
|
|
The frontend nudge bus (`nudgeBus.svelte.ts`) owns cadence, suppression, and the hourly cap. This command is a blunt "push it now" primitive — no rate limiting at the Rust layer. Errors propagate verbatim so the bus can log + swallow.
|
|
|
|
## `rituals.rs`
|
|
|
|
### Morning-triage sentinel
|
|
|
|
Frontend owns rendering and logic; this module only persists the "last date the morning triage modal was shown" sentinel under SQLite settings key `lumotia_morning_triage_last_shown`.
|
|
|
|
- `get_last_morning_triage(state) -> Result<Option<String>, String>` (`src-tauri/src/commands/rituals.rs:23`).
|
|
- `mark_morning_triage_shown(state, date: String) -> Result<(), String>` (`src-tauri/src/commands/rituals.rs:36`). Caller passes a YYYY-MM-DD string in the user's local timezone — Rust deliberately stays timezone-agnostic.
|
|
|
|
No `ensure_main_window` guard. Acceptable: the morning triage UI lives in the main window, but the data is harmless if a secondary window ever queries.
|
|
|
|
## `update.rs`
|
|
|
|
Updater stubs.
|
|
|
|
- `check_for_update(window) -> Result<Option<String>, String>` (`src-tauri/src/commands/update.rs:6`). Main-window only. Currently always returns `Ok(None)` ("up to date").
|
|
- `install_update(window) -> Result<(), String>` (`src-tauri/src/commands/update.rs:13`). Main-window only. Currently returns `Err("Updates are disabled until release signing is configured.")`.
|
|
|
|
The matching `tauri.conf.json` `plugins.updater` entry is absent. The integration test `updater_is_signed_or_absent` (`src-tauri/tests/config_hardening.rs:35`) gates a future release: any updater config that ships must carry a non-empty `pubkey`.
|
|
|
|
## See also
|
|
|
|
- [Paste](paste.md) — the auto-paste sibling of `clipboard::copy_to_clipboard`.
|
|
- [Diagnostics](diagnostics.md) — the report bundler that consumes the same OS info `hardware::probe_system` reports.
|
|
- [Tauri config](../tauri-config.md) — the absent `plugins.updater` block that the integration test guards.
|
|
- [Capabilities and ACL](../capabilities-and-acl.md) — the notification permission set that `nudges::deliver_nudge` relies on.
|
|
- [Power assertions and security](power-and-security.md) — `ensure_main_window` guards live here.
|