Two recon findings from the reset work, fixed properly (whole class + tests +
docs), plus the destructive reset path is now exercised end-to-end.
1. ~/.config/omnivoice/env survived every uninstall. The app persists the
model-cache location (and a possible HF_TOKEN) there via
backend/core/user_env.py, but the in-app "Remove all data" (uninstall.rs),
uninstall.sh, and uninstall.ps1 all walked past it — so a reinstall silently
inherited the old file and redirected downloads to a maybe-deleted location.
All three now remove it. It's the same expanduser("~/.config/omnivoice/env")
path on every OS, so the Windows script uses %USERPROFILE%\.config\omnivoice.
is_recognizably_ours accepts it (contains "omnivoice"); docs tables updated.
2. Disk usage measured the wrong engines dir. storage_report.default_engines_dir()
returned backend/engines (built-in engine *modules*, no venvs), while sidecar
installs live in DATA_DIR/engines/<id>. So a multi-GB IndexTTS-2 install was
invisible in the engine-venv category and rolled into data/"other". Now points
at DATA_DIR/engines and sizes the WHOLE install (venv + checkout + weights),
with the data category claiming that subtree so it isn't double-counted.
Reset hardening: extracted purge_scopes() as a pure fs function (no AppHandle),
so the actual delete loop runs in tests against a real on-disk install tree —
"everything" wipes the install but spares the venv/foreign temp/sibling folders,
a settings reset keeps content+config+models, and a poisoned data_dir="$HOME"
deletes NOTHING. This is the live drive-through of the destructive path, minus
the GUI.
Also: gitignore the node_modules symlink form (the directory rule node_modules/
never matched a worktree symlink, so it kept slipping into commits).
Tests: Rust 78 (6 new), storage_report 20 (2 new incl. once-not-twice count +
default-dir guard), frontend 1207, i18n probe green, format+lint clean.
Co-authored-by: mergetest <nizam4103@gmail.com>
Settings system-group cleanup — every fix keeps existing behavior contracts
and adds a fail-before/pass-after regression test:
- Factory reset now does what it promises: clears every locally-persisted
preference via a single registry (utils/prefKeys.js) instead of only the
zustand blob — nav-rail side, capture live-typing, stories speed, logs
footer state, last settings category, dismissed tips, donate prompts, and
the legacy omni_ui blob included. User data and connection state
(omni_transcriptions, ov_backend_url, ov_api_key) are explicitly preserved,
and prefKeys.test.js scans the source tree so any future localStorage key
must be categorized or CI fails. The failure toast now carries the actual
error message.
- Disk-usage "Clear logs" is confirm-gated with the same wording as
Settings → Logs — it truncates the crash log (the bug-report artifact), so
it can no longer be a single stray click.
- Temporary files got a reclaim action: a confirmed "Clear temp files"
button backed by POST /api/settings/storage/temp/clear, which deletes only
the omnivoice* entries in the OS temp dir (symlinks unlinked, never
followed) and invalidates the cached report.
- Performance panel goes through i18n end to end (title, row, note, hint,
errors, aria-label) — it was the last fully hardcoded panel; the
non-Windows subtitle now reads "Windows only — not needed on this
platform" instead of "not applicable".
- History retention: GET failures now surface an alert and hold Save until
a load succeeds (404 from older backends stays silent), Enter saves, the
dead !res.ok branch is gone, and the bespoke button is the shared Button.
- Logs tab: "Open folder" reveals the log file, "Copy visible log" copies
the tail, the viewer autoscrolls to the newest lines, and the scroll box
is keyboard-focusable (role=log) with a labelled source switcher.
- Storage paths: the app-data row is labelled "App data stored at" (it was
borrowing the Privacy tab's "Uploads stored at"), and all three path rows
gained Open folder.
- i18n stragglers routed through t(): storage load/open/clear fallbacks,
the backend-status badge, and the frontend log buffer label.
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Settings → Storage now opens with a Disk usage panel backed by a new
loopback-gated GET /api/settings/storage endpoint:
- Per-volume totals (grouped by st_dev) + du-style sizes for everything
the app owns: the HF model cache (with its ~10 largest models), the
app data dir broken into voices/outputs/dub_jobs/batch/preview/
database/logs/other subtotals, engine venvs (backend/engines/*/.venv
+ the app venv), and omnivoice* entries in the OS temp dir.
- Bounded scanning: per-category 10 s deadline → partial totals with an
"unreadable" warning instead of a hung request; results cached
in-process for 5 minutes, ?refresh=1 forces a rescan; the walk runs
in a worker thread so the event loop never blocks.
- Server-side warnings reuse the setup wizard's MIN_FREE_GB: free <
min → critical, free < 2×min → low, volume holding the cache/data
>90% full → volume_pressure, unreadable/timed-out paths → unreadable.
The panel renders severity-colored banners, a data-volume gauge,
proportion bars per category, Open-folder buttons (existing
/export/reveal pattern), a Model Store jump for reclaiming model
space, and the existing clear-logs action on the logs row. A critical
warning is also surfaced outside Settings via the app-wide toast —
once per session. All strings via i18n (en fallback).
Tests: tests/test_storage_report.py (sizes, thresholds, cache/refresh,
timeout partials, endpoint wiring) + StorageUsagePanel.test.jsx
(categories, banners, once-per-session toast, refresh=1, error state);
route added to tests/fixtures/api_routes.txt via the dump script.
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>