Commit Graph
64 Commits
Author SHA1 Message Date
Matt Van Horn 1515b46adb feat(batch): watch-folder auto-ingest (#1768)
Opt-in watch folder on the batch queue: pick a directory once and new videos are auto-enqueued with the last Add-to-queue settings, with pause/stop controls and copy-in-progress protection. Files stream to the loopback backend as bytes; paths never leave the app. Also gives the batch queue a reachable UI entry point and streams multipart uploads to disk. Maintainer fix: the watched directory handle is opened with full share mode on Windows so users can rename or delete the folder while it is watched, matching macOS/Linux behaviour, with a cross-platform regression test. Thanks @mvanhorn!
2026-09-03 18:47:32 +05:30
Palash Debnath 0ed7d2ec22 chore(release): prepare v0.5.2 (#1761)
Synchronize VoiceStudio release metadata, lockfiles, installers, container references, documentation, and the dated v0.5.2 changelog after all planned fixes landed.
2026-09-02 10:26:14 +05:30
Palash Debnath 97bfbfecd1 chore(release): prepare v0.5.1 (#1688)
Prepare the tested main branch for the v0.5.1 patch release with synchronized version sources, mirrors, lockfiles, release notes, and install guidance.

Closes #1687.
2026-08-28 11:27:59 +05:30
Palash Debnath 7718a7a10b fix: cross-platform dictation delivery (#1610)
Makes dictation delivery, capture, recovery, model fallback, AEC, and localized status behavior reliable across macOS, Windows, and Linux.
2026-08-21 03:33:50 +00:00
Palash DebnathandClaude Fable 5 9184d7d625 chore: bump to 0.5.0 (#1540)
* chore: bump to 0.5.0

Owner-requested minor bump. package.json is the source of truth; the
three mirrors (Cargo.toml, pyproject.toml, _FALLBACK_VERSION), the three
lockfiles and the branding pin move in lockstep, and the accumulated
Unreleased section becomes the curated 0.5.0 release notes — quiet
Highlights first, one-liner subsections after, duplicates folded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: fresh README for the VoiceStudio era; 0.5.0 notes wear the release

README: 551 lines from 656 — a What's-new-in-0.5.0 section with real
captures, the engine tables corrected to the actual 16 TTS registrations,
a stale Settings path and a broken Colab link fixed, roadmap/FAQ/credits
trimmed to what earns its place.

Release notes: the quick-switch GIF and catalogue/gallery screenshots,
captured from the running app during the pre-bump test pass, embedded
after the Highlights; #1542's gallery work and the ffmpeg CI fallback
recorded in their subsections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: the feature inventory's Remote Model Downloads mention survives the README trim

check-docs-drift requires every docs/features.yaml name verbatim in the
README; the overhaul folded the phrase away. It now lives in the remote
workers feature line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: one blockquote, and an architecture claim that survives the opt-ins

CodeRabbit on #1540: MD028 blank line inside adjacent blockquotes, and
'every layer is on your machine' contradicted the opt-in remote paths
documented two sections away — it now states local-by-default with the
opt-ins named.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 23:50:23 +00:00
debpalash 5ae23f37d1 Merge commit '7053f1d1c01b064266a32f227ea365100a68ae21' into fix/wayland-capture-shortcut
# Conflicts:
#	CHANGELOG.md
2026-08-11 05:22:09 +00:00
debpalash fb0d62e0c1 fix: restore pre-release version 0.4.2 2026-08-11 04:28:38 +00:00
debpalash 27d76955da fix(dictation): support capture shortcuts on Wayland 2026-08-11 04:27:36 +00:00
debpalash b68d1c68de fix: correct VoiceStudio release to 0.5.0 2026-08-11 04:18:51 +00:00
Palash Debnath 04410a458d Release VoiceStudio 5.0.0 (#1487)
Complete the VoiceStudio identity, release documentation, assets, version mirrors, and safe cross-platform development startup.
2026-08-11 04:05:45 +00:00
debpalash 705544df96 Merge remote-tracking branch 'origin/main' into fix/dependabot-security
# Conflicts:
#	CHANGELOG.md
2026-08-10 04:30:23 +00:00
Palash Debnath ae46f187d0 fix(security): move host-path authority into the desktop shell (#1448)
Close unauthenticated remote mutation paths and keep filesystem destinations behind one-shot Tauri capabilities. CodeRabbit and Greptile findings were fixed on-branch; all review threads are resolved. Full CI, Security, Rust, and cross-platform smoke checks are green.
2026-08-09 21:55:43 +00:00
debpalash c20e1c1685 fix(security): raise dependency advisory floors 2026-08-09 21:23:59 +00:00
Palash DebnathandClaude Opus 5 b01c635bfe release: v0.4.2 (#1279)
Version files (package.json + the three mirrors) and both lockfiles bumped
0.4.1 → 0.4.2; [Unreleased] renamed to [0.4.2] — 2026-07-28.

Ships five user-facing fixes: the update toast, the restart guard that used
to discard in-flight work, the shutdown-is-not-a-crash 503, the self-healing
half-downloaded model, and the dub-history purge ordering — plus the
"Dismiss" mistranslation in five locales.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 15:56:37 -07:00
Palash Debnath 9736fd4859 release: v0.4.1 (#1239)
* release: v0.4.1

Seven user-reported issues fixed since v0.4.0 (#1221–#1229). Version bumped
across the single source of truth (frontend/package.json) and its three
toolchain mirrors; [Unreleased] renamed to the release section that
release.yml extracts verbatim as the GitHub Release body.

Docker tag examples in docs/install/docker.md and deploy/dockerhub-overview.md
updated to 0.4.1 (docs-sync rule).

* release: #1239 review — sync Cargo.lock to 0.4.1

Greptile: the manifest said 0.4.1 while Cargo.lock still recorded 0.4.0, so a
`cargo build --locked` (and the Tauri bundler's own locked build) would fail
on the mismatch. Regenerating locally updated it but it was never staged.

* release: re-sync [0.4.1] after the fix merges, date it 2026-07-27

Picks up everything merged since the section was first written: the first-run
wizard chrome (#1241), the MCP host allowlist (#1249), the macOS 12 startup
crash (#1245), and the six error-message fixes (#1247, #1251, #1254, #1256,
#1257, #1262).

Deliberately NOT included:
  - the dub delete-resurrection fix (#1252, #1253) — split to #1270 after it
    needed six rounds of correction, the last two finding that the fix did not
    close the reported case and that its own bound reintroduced it;
  - the Linux AppImage WebKit fix (#1258, #1244) — held on #1265 pending
    confirmation on a Mesa 26.1 host, which nobody has run.
2026-07-26 14:48:05 -07:00
debpalashandClaude Opus 4.8 9f6fb247ab release: v0.4.0
Bump the single source of truth (frontend/package.json) and the three
toolchain mirrors (Cargo.toml, pyproject.toml, backend/core/version.py) plus
the lockfiles (Cargo.lock, uv.lock) from 0.3.22 → 0.4.0, and rename the
CHANGELOG's [Unreleased] section to [0.4.0] with milestone highlights.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 06:46:46 +05:30
0d4eb0f269 release: freeze v0.3.22 — version bump, lockfiles, changelog (#1150)
The dubbing release. package.json (source of truth) + the three mirrors
(Cargo.toml, pyproject.toml, version.py fallback) to 0.3.22; uv.lock +
Cargo.lock refreshed; CHANGELOG's Unreleased section (29 entries) becomes
## [0.3.22] — 2026-07-14 with the headline, split Added blocks merged.

Gates on the frozen content, all green before any version mutation:
backend 3033 + 204, frontend 1253, format, lockstep 6/6.

Co-authored-by: mergetest <nizam4103@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 03:04:17 +05:30
4d2fdacd33 release: freeze v0.3.21 — version bump, lockfiles, changelog (#1107)
package.json (single source of truth) + the three toolchain mirrors to 0.3.21;
Cargo.lock + uv.lock regenerated (version lines only). CHANGELOG [Unreleased]
renamed to [0.3.21] — 2026-07-12, "the memory release", sections merged into
house style (one Added, one Fixed).

Ships the 16 GB OOM class fixes end to end: idle-release the dictation ASR
(#1104) + one TTS engine resident at a time (#1105), plus the scoped
Settings → Storage reset/uninstall pair (#1089/#1099/#1100) and the release-
asset-split workflow fix (#1106) so this tag uploads to a single release.

test_app_version.py lockstep: 6 passed. bun install --frozen-lockfile: clean.

Co-authored-by: mergetest <nizam4103@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 15:24:07 +05:30
94093605eb feat(settings): factory reset gets scopes — preferences, settings, assets, everything (#1100)
* feat(settings): factory reset gets scopes — preferences, settings, assets, everything

Factory reset did exactly one thing: clear localStorage. The only other option
was "Remove all data", which deletes the Python env and quits. Between "forget
my theme" and "wipe the machine" sat every reset a user actually needs — drop a
corrupt model download, remove a wedged sidecar engine, put the settings back
without losing a single voice — and none of them existed.

Settings → Storage → "Reset & remove" now offers four tiers (UI preferences /
all settings / downloaded assets & models / everything OmniVoice did) plus a
per-scope checklist. Every scope shows its real on-disk size, and the number on
the confirm button is exactly what gets freed.

Why the shell and not the backend: a loaded model memory-maps its weights out of
the HF cache (locked on Windows while mapped), and ensure_dirs() runs at import,
so a backend cannot delete voices/ or outputs/ and still write to them. reset.rs
stops the backend, deletes, and starts it again — and that restart is also the
repair: the fresh process re-runs ensure_dirs() and alembic, so a removed
database comes back empty rather than missing. retry_bootstrap's respawn path is
extracted to bootstrap::respawn_backend so both callers share one implementation.

Deliberate scope choices:
- "Everything" stops short of the managed Python env, so a reset hands back a
  working app on the first-run screen. The env is the uninstaller's business.
- A settings reset keeps the storage locations (config.json, the user env file).
  Clearing the model-cache pointer would strand gigabytes at a path the app no
  longer looks in — install shape is not a preference.
- content deletes the DB with the media: rows without files is how you get a
  library full of broken entries.
- The shared HF cache is flagged as shared only when it IS — computed, so Windows
  and portable installs (app-private cache) get no caveat they don't need.

Safety: nothing is removed unless it sits inside a validated root — one carrying
an OmniVoice-owned path component OR holding an OmniVoice signature file, which
is what lets a custom data dir on an external volume be cleared while a mis-set
data_dir: "/" is refused. Voices/projects/audio need the word typed.

9 Rust tests (guard, scope composition, shared-cache computation) + 14 frontend
(planning purity, typed confirm, disk-vs-frontend split, shared warning).
Border utilities follow the design guard (tests/test_no_literal_borders.py).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(settings): give the Storage panels a design — proportional sizes, live totals, real tokens

"Remove all data" listed four folders as a flat run of text: a 7.5 GB model cache
and a 391-byte config file rendered at identical visual weight, so the one thing
worth seeing — where the space actually went — was the one thing you couldn't.
And the 391 B folder said "0 KB", which reads as "nothing here".

- New shared StorageTargetRow, used by BOTH destructive panels so they read as
  one system: icon, label, dimmed path (truncated, full text on hover), size, and
  a proportional bar showing that row's share of what will be freed. Unticked
  rows claim none of the bar — the bars must sum to what the button promises.
- The shared HF cache moves OUT of the confirm dialog into its own "Optional"
  row with the checkbox and the caveat in the list. Ticking it now moves the
  running total in front of the user, instead of springing a different number on
  them at the point of no return. The dialog lists exactly what is going.
- One byte formatter for both panels (settings/bytes.js). models/format.fmtBytes
  floors at kilobytes, hence "0 KB"; it stays where it is for the model store.

Real fix underneath: three of the tokens these panels styled with DO NOT EXIST
(--chrome-fg-subtle, --chrome-bg-raised, --color-warning). An undefined var()
makes the declaration invalid, the browser drops it, and the element silently
inherits — which is why the paths that were meant to recede rendered at full body
weight. That is a whole class of bug that fails invisibly, so it gets a guard:
src/test/cssTokens.test.js fails on any var(--token) in JSX not defined in a
stylesheet, with runtime-injected tokens (Radix, inline-style hues) allowlisted
by reason. Six pre-existing offenders elsewhere in the app are recorded as
known-broken and ratcheted so the list can only shrink — they are real bugs, but
each is a visual change that wants its own review.

Frontend suite 1196 → 1205 (6 UninstallPanel component tests incl. the live
total and the bar proportions; 3 token-guard tests, verified fail-before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: green CI + finish the token sweep + snapshot the panels

Three things on top of the redesign:

1. CI was red on tests/probe/test_probe_i18n.py — removing the eight dead
   `factory_reset_*` keys from en.json orphaned them in all 20 other locales
   (the probe forbids a non-en key absent from en). Removed them everywhere.
   This guard scans locales at pytest time; a frontend-only run never sees it.

2. Finished the undefined-token sweep instead of grandfathering it. Six bare
   `var(--token)` references resolved to nothing; the only genuinely undefined,
   fallback-less one in shipping panels was `--chrome-input-bg` (input fields
   AND progress-bar tracks AND skeletons across StoragePanel, StorageUsagePanel,
   HistoryRetentionPanel, ModelStoreTab — tracks were rendering with no
   background at all). Repointed to --chrome-hover-bg. The rest
   (--chrome-menu-bg, --chrome-bg-inset, --border, --input-bg, --muted) already
   carry `var(--x, fallback)`, which is valid CSS. So cssTokens.test.js now
   checks only the BARE form and ships with zero exceptions — no known-broken
   ratchet, because there is nothing left broken.

3. Registered both Storage panels in the visual-regression harness (a Tauri
   `invoke` stub added to providers.jsx alongside the existing fetch stub) and
   committed baselines across all three themes. This is how I actually looked at
   the redesign: the bars render proportional (the 720 KB voices row fills, the
   391 B row is a sliver), the shared-cache row sits in its own Optional group,
   and every token now resolves in default/midnight/catppuccin. `_forceAdvanced`
   on ResetPanel opens the checklist for the snapshot; no effect on the toggle.

Full backend suite 2897 passed (incl. the i18n probe). Frontend 1205.

* style: oxfmt the new panels and specs

Format-check is a CI gate (oxfmt --check); the new files weren't run through
oxfmt --write. No behavior change.

* chore: stop tracking the node_modules symlink

A worktree-local symlink slipped past .gitignore (which lists node_modules/ —
the directory form — so it never matched the symlink file). Removed from the
index; the symlink stays on disk for local test runs.

---------

Co-authored-by: mergetest <nizam4103@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:00:13 +05:30
b0c692d26c release: freeze v0.3.20 — version bump, lockfiles, changelog (#1103)
package.json (single source of truth) + the three toolchain mirrors to 0.3.20;
Cargo.lock + uv.lock regenerated (version lines only). CHANGELOG [Unreleased]
renamed to [0.3.20] — 2026-07-12 with the release headline, sections merged into
house style (one Added, one Fixed).

Ships the #1101 stale-"ready" race fix (0.3.19 users are hitting it today), the
in-app uninstaller (#1099), and the Linux/Windows backend-log-dir fix.

test_app_version.py lockstep: 6 passed. bun install --frozen-lockfile: clean.

Co-authored-by: mergetest <nizam4103@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:12:47 +05:30
d7ca904a27 release: freeze v0.3.19 — version bump, lockfiles, changelog (#1096)
package.json (single source of truth) + the three toolchain mirrors
(Cargo.toml, pyproject.toml, core/version.py) to 0.3.19; Cargo.lock + uv.lock
regenerated (version lines only). CHANGELOG [Unreleased] renamed to
[0.3.19] — 2026-07-12 with the release headline; all six entries carry their
(#PR) refs and extract cleanly as the GitHub Release body.

Rebuilt on current main so the freeze covers everything that landed after the
first cut: #1088 (streaming preview), #1097 (uninstaller), #1098 (stream-drop
honesty), plus the backfilled #1088 changelog entry.

test_app_version.py lockstep: 6 passed. bun install --frozen-lockfile: clean.

Co-authored-by: mergetest <nizam4103@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 12:38:05 +05:30
2a22952f9c release: freeze v0.3.18 — version bump, lockfiles, changelog (#1084)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 02:01:26 +05:30
d1522cbba0 release: freeze v0.3.17 — version bump, lockfiles, changelog (#1079)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 22:05:58 +05:30
55c40be307 release: freeze v0.3.16 — version bump, lockfiles, changelog (#1057)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:56:18 +05:30
29b6f30f2b release: freeze v0.3.15 — version bump, lockfiles, changelog (#1041)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 04:59:59 +05:30
a721c1fdcf release: freeze v0.3.14 — version bump, lockfiles, changelog (#1027)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 09:12:24 +05:30
67789fb31c release: freeze v0.3.13 — version bump, lockfiles, changelog (#1023)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 02:52:25 +05:30
5871ec9d28 release: freeze v0.3.12 — version bump, lockfiles, changelog (#1001)
19-issue GitHub sweep: 16 PRs merged since v0.3.11, most fixing reports
filed same-day or in the days prior. Highlights: MLX-Audio's 6 other
curated models are finally selectable (was silently stuck on Kokoro
regardless of what was downloaded), first-run no longer dead-ends behind
restricted networks or corporate TLS-inspecting proxies, dubbing/batch
TTS honor your active engine selection, and a run of sharp community
diagnoses (ROCm wheel index, Windows dictation focus-steal, a genuine
frontend crash regression) got fixed largely because reporters did the
hard diagnostic work themselves.

Full backend suite: 2390 passed, 0 failed. Full frontend suite: 918
passed, 0 failed. Version lockstep (tests/test_app_version.py): 6/6
passed. Docker frozen-lockfile parity (bun install --frozen-lockfile):
clean, no drift.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 07:28:41 +05:30
7098be1c8b fix(dictation): Windows pill no longer steals foreground focus (#982) (#996)
Root-caused and verified against the actual code (community diagnosis in
#982 was accurate): showing the dictation pill — an always-on-top top-level
WebviewWindow — grants it Win32 foreground activation by default on
Windows, which macOS doesn't do for a shown window. Nothing marked the pill
non-activating, so on Windows the synthesized Ctrl+V from `simulate_paste`
landed back in the pill instead of the app being dictated into. Code review
also found a second, more direct culprit at the same call sites: the
global-shortcut Pressed handler's `win.set_focus()` was only skipped on
macOS (`#[cfg(not(target_os = "macos"))]`), so Windows explicitly focused
the pill on top of the implicit Win32 activation; the tray "dictate" menu
handler called `win.show(); win.set_focus();` unconditionally on every
platform, including Windows.

This is the Windows counterpart of #287 (macOS auto-paste — don't steal
focus): same class of bug, same "pill must stay unfocused so the paste
lands in the target app" intent (already stated in the `grant_webview_
media_permissions` module comment), different OS mechanism.

Fix, mirroring #287's platform-cfg pattern:
  1. WS_EX_NOACTIVATE applied to the pill's HWND once, right after creation
     (`mark_pill_noactivate`), via the `windows` crate pinned to the exact
     0.61.x tauri itself already resolves to — Cargo.lock confirms this
     unifies to the same `windows 0.61.3` already in the graph, so
     `WebviewWindow::hwnd()`'s HWND and our Win32 calls share one type and
     no new crate version was added.
  2. `ShowWindow(SW_SHOWNOACTIVATE)` (`show_pill_noactivate`) in place of
     `.show()` at the two dictation-trigger call sites (global shortcut +
     tray "Start Dictation"), since `.show()` alone still raced the style
     bit on some paths.
  3. The explicit `set_focus()` calls at those same two sites are now
     skipped on Windows too, the same way they already were on macOS.

macOS and Linux are untouched: the macOS cfg branch is unchanged, and the
Linux branch of the `set_focus()` guard still runs exactly as before.

The pill's auto-dismiss (`scheduleDismiss`/`dismiss` in CaptureWidget.jsx)
was checked and is a plain unconditional setTimeout chain — it is not
gated on any native focus-loss/paste-completion signal, so there's no
independent bug to fix there. The "never dismisses" symptom is a
consequence of the focus-steal, not a separate stall: once the pill wrongly
held foreground for the whole session, hiding it later left Windows'
foreground state inconsistent. With the pill never taking focus, the
target app stays foreground throughout and there's nothing to reconcile.

Win32 window-activation syscalls (`#[cfg(target_os = "windows")]`) can't
run under `cargo test`/`cargo build` on this non-Windows CI runner, so the
new `pill_noactivate_tests` module tests the pure flag math
(`with_noactivate_style`) instead — platform-agnostic, runs everywhere,
verified passing here. The actual HWND-touching code is logic-reviewed but
UNVERIFIED on real Windows; the reporter offered to test a patched build,
which is the recommended next step before this ships in a release.

`cargo build` and `cargo test --lib` both pass (60/60 tests, including the
3 new ones); the pre-existing `setup.rs` unreachable_code warning (#286) is
unrelated.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 04:41:25 +05:30
453db55f12 release: freeze v0.3.11 — version bump, lockfiles, changelog (#970)
package.json + three mirrors -> 0.3.11 in lockstep; Cargo.lock/uv.lock/
bun.lock regenerated; CHANGELOG [Unreleased] -> [0.3.11] — 2026-07-05
with the multi-language-release headline; nine entries since v0.3.10.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 22:28:43 +05:30
fd7d20fe1e release: freeze v0.3.10 — version bump, lockfiles, changelog (#954)
package.json (source of truth) + the three mirrors -> 0.3.10, in lockstep;
Cargo.lock/uv.lock/bun.lock regenerated (one line each; bun --frozen-lockfile
verified). CHANGELOG [Unreleased] -> [0.3.10] — 2026-07-05 with the release
headline; nine fixes since v0.3.9, mostly same-day field-report turnarounds.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 00:57:17 +05:30
bef688e9dd release: freeze v0.3.9 — version bump, lockfiles, changelog (#899)
* release: freeze v0.3.9 — version bump + lockfiles + changelog

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* release: unwrap the [0.3.9] section — release bodies hard-break single newlines

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 22:35:39 +05:30
68d456bb58 refactor(tauri): use tauri-plugin-positioner for the dictation pill (replaces hand-rolled monitor math) (#770)
The floating dictation pill (the "widget" window) was positioned bottom-center
by three near-duplicate blocks in lib.rs that each read primary_monitor(),
divided size by scale_factor, and called set_position(LogicalPosition...), with
a win.center() fallback. Replace all three with the official
tauri-plugin-positioner: window.move_window(Position::BottomCenter), preserving
the center() fallback on error.

- Add tauri-plugin-positioner = { version = "2", features = ["tray-icon"] }
  (tray-icon enabled because the app ships a system tray).
- Register .plugin(tauri_plugin_positioner::init()) after single-instance.
- Collapse the global-shortcut, tray "dictate", and pill-mode pre-position
  blocks to the plugin API. Behavior-preserving: same window, same trigger
  points, still bottom-center.

Verified with cargo check (passes; the one warning is pre-existing in setup.rs).

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:59:34 +05:30
e14644f77a fix(backend): auto-restart supervisor + client transport-retry (#567/#570/#571) (#572)
The "Can't reach the local OmniVoice backend" cluster was a long-standing
supervision gap (dates to v0.3.0/#38), not a v0.3.7 regression: the backend
was spawned once and never watched again — `spawn_backend_and_wait` returned
the instant it was healthy. When the uvicorn process then died mid-session (a
CUDA OOM/context fault under a burst of generations — #571's log shows the
startup banner replaying 6× during a 20-generate burst — an antivirus kill, any
crash), nothing restarted it, so every later request threw connection-refused
and the user was stuck on the toast until a full app restart.

Two layers, both default-mode and platform-neutral:

1. Backend auto-restart supervisor (bootstrap.rs). After Ready, the bootstrap
   thread (which used to just return) keeps watching the child and respawns it
   on a *confirmed process exit* (try_wait — never a slow health probe, so a
   busy-but-alive backend is never killed). Bounded to 5 restarts/60s (then
   Failed) so a deterministic startup crash can't fork-bomb; the #314
   broken-venv self-heal stays the venv-failure path. Strictly gated on
   AppFlags.quitting so it never resurrects the backend during shutdown. A
   single-supervisor guard (compare_exchange) prevents duplicate loops when
   Retry re-enters concurrently. Emits backend-restarting/backend-restored
   events (the splash poll stops post-Ready, so the stage alone can't show it).

2. Client transport-retry (client.ts). A *thrown* fetch (the backend briefly
   down while it respawns) is retried a bounded few times with backoff
   (~2.9s total) before surfacing the actionable ApiError, making the restart
   window invisible. HTTP errors and deliberate aborts are never retried.

Resolves the whole cluster regardless of the crash trigger. Tests: Rust
backoff-policy unit test (cap + window-pruning); 4 client-retry vitest cases
(retry-then-succeed, no-retry-on-HTTP-error, no-retry-on-abort, bounded
give-up). Also corrects a stale Cargo.lock omnivoice-studio version (0.3.6→0.3.8).

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:32:59 +05:30
4bcbc74e86 chore(deps): conservative refresh — backend, UI, Tauri (#485)
* chore(deps): refresh backend HTTP/cert/security leaf packages

Conservative, targeted refresh (no blanket re-resolve). Bumps only low-risk leaf
packages — yt-dlp 2026.3.17→2026.6.9 (extractor currency), aiohttp, requests,
urllib3, idna, certifi, charset-normalizer, pillow (HTTP/cert/security). No
major bumps, no downgrades, no transitive removals; the 91-package full
`--upgrade` was rejected because it downgraded numpy/pandas/av and pulled a
starlette 1.x major that broke WS route introspection. Full backend suite: 1674
passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(deps): bump UI deps to within-major latest

`bun update --latest` floors raised to current within-major releases — react
19.2.7, react-dom 19.2.7, vite 8.0.16, tailwindcss/@tailwindcss/vite 4.3.1,
@tanstack/react-query 5.101, @radix-ui/* minors, lucide-react 1.18, zustand
5.0.14, i18next 26.3.1, plus dev tooling (vitest 4.1.9, eslint 10.5, playwright
1.61, @tauri-apps/cli 2.11.2). Verified no major version crossings. typecheck:ci
clean; vitest 503/503.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(deps): cargo update Tauri crates within range

`cargo update` — 77 crates locked to latest semver-compatible versions (patch/
minor: bitflags, chrono, hyper, reqwest, regex, rustls-native-certs, etc.; one
in-range 0.x bump global-hotkey 0.7→0.8). No Cargo.toml range changes. `cargo
check` compiles clean (0 errors).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:56:33 +05:30
Palash DebnathandClaude Fable 5 a949b2c78a chore(version): main is always latest release + 1 — rule, bump to 0.3.6, Docker retag, auto-bump job (#338)
Versioning hard rule (owner-set 2026-06-11), codified in CLAUDE.md:
- main's three version sources (tauri.conf.json, Cargo.toml,
  pyproject.toml) always carry last release + 1 patch; bumped 0.3.5 ->
  0.3.6 now.
- Preview builds stamp BASE-N which now sorts ABOVE the last stable
  (0.3.6-N > 0.3.5) — the updater ordering becomes natural and the
  Windows MSI ProductVersion wrinkle disappears.
- Docker: :latest = rolling main preview; :stable + :X.Y.Z + :X.Y =
  tagged releases. workflow_dispatch still only emits throwaway :sha-.
- release.yml gains a version-bump job: on every stable v* tag it
  bumps main to the next patch automatically.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:16:03 +05:30
Palash DebnathandClaude Fable 5 7419986c8b fix(dictation): microphone permission — OS usage descriptions, WebView grant handler, actionable denied-state UI (#323) (#336)
On Windows 11 the dictation pill (Ctrl+Shift+Space) always reported
"Microphone access denied" even though OS-level mic permission was
granted (Voice Clone worked, backend transcribed fine). Root cause:
no WebView2 PermissionRequested handler was registered, so WebView2
fell back to its own permission UI — which the 300x64 transparent,
undecorated, deliberately-unfocused pill window can never host — and
getUserMedia() rejected with NotAllowedError.

Per-platform fixes:
- Windows (WebView2): register a PermissionRequested handler on both
  the main and widget webviews that allows microphone/camera requests
  in code, for the app's own origin only (tauri.localhost + dev
  loopback). The Windows privacy toggle still applies on top.
- Linux (WebKitGTK): the media-stream enable + permission auto-grant
  previously covered only the "main" window — the dictation widget is
  a separate WebView and was silently denied. Now applied to both.
- macOS: already correct — NSMicrophoneUsageDescription ships in
  src-tauri/Info.plist and wry grants media capture to the app origin;
  documented in the shared helper.

Frontend: getUserMedia failures are now mapped by error name
(utils/micError.js) instead of one blanket "access denied" toast —
permission denials get a per-OS "where to re-enable it" hint
(Windows hint now mentions the desktop-apps mic toggle), missing
devices and busy devices get their own messages, and the previously
hardcoded English toast in useRecording goes through i18n. New keys
added to all 21 locales.

Tests: vitest unit tests for the error mapping (19 cases) and a Rust
unit test for the WebView2 origin allow-list; Windows handler code
cross-checked against webview2-com 0.38.2 / windows-core 0.61.2.

Fixes #323

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:15:17 +05:30
Palash DebnathandClaude Fable 5 78f5db71d7 fix(updater): preview channel offers the newest build across channels (#326) (#335)
Root cause, two layers:

1. tauri-plugin-updater's default comparator is plain semver
   (remote > current). Preview builds are published as X.Y.Z-N
   (e.g. 0.3.5-41 = main, 41 builds after the 0.3.5 tag), which semver
   treats as a *pre-release* of X.Y.Z — so it sorts BELOW stable X.Y.Z.
   Once stable 0.3.5 shipped, preview users were told "you already have
   the latest version" forever.

2. The endpoint list [preview, stable] is not a "best of both" — the
   plugin stops at the first manifest that parses and uses later
   endpoints only as network fallbacks, so a reachable preview manifest
   hid a newer stable release entirely.

Fix: for the preview channel, check BOTH manifests with a custom
version_comparator implementing cross-channel ordering (higher base
version wins; on equal base a suffixed preview build outranks the bare
stable it was built on; preview-vs-preview uses numeric-aware semver
pre-release comparison), then offer the newest candidate. A manifest
error is non-fatal while the other manifest answers. The stable channel
keeps the single endpoint and the plugin's default comparison —
default behavior unchanged on all platforms.

Adds 7 unit tests covering preview ahead of stable (the bug case),
stable passing preview, equal-base both directions, equal versions
(no ping-pong), numeric build-counter ordering, and base dominance.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:14:55 +05:30
Palash DebnathandClaude Opus 4.8 f3e403193e fix(dictation): macOS auto-paste — don't steal focus, write clipboard natively (#287) (#299)
Dictation via the global shortcut transcribed fine but the text never reached
the target app on macOS, due to two stacked bugs (diagnosed, patched, and
verified by @geektf in #287):

1. The ShortcutState::Pressed handler called win.set_focus(), making the
   widget frontmost — the simulated ⌘V from simulate_paste() landed in the
   widget instead of the app being dictated into. Skip set_focus() on macOS
   (same #[cfg(not(target_os = "macos"))] guard the other widget call sites
   already use).

2. With the widget unfocused, the WebView clipboard APIs
   (navigator.clipboard.writeText / execCommand('copy')) fail silently in
   WKWebView, so ⌘V pasted whatever was previously on the clipboard.
   simulate_paste now takes Option<String> and writes the transcript to the
   clipboard natively (arboard) before sending the keystroke — no window
   focus required. CaptureWidget passes the transcript; copyText() stays as
   best-effort for browser (non-Tauri) mode, and the optional param keeps
   any text-less call sites working.

cargo check clean (the unreachable_code warning in setup.rs is pre-existing
from #286); frontend node:test suite passes. End-to-end behavior verified by
the reporter on macOS 26 / M4 Pro with both patches applied.

Fixes #287

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:36:47 +05:30
Palash DebnathandClaude Opus 4.8 43884e54a6 feat: first-run setup screen — install mode, storage choice + minimum-space gate, mirrors, compute (#286)
* feat(setup): first-run install gate — nothing installs until the user confirms a plan

New `setup` module parks first runs in BootstrapStage::AwaitingSetup instead
of auto-installing. complete_setup validates the user's InstallPlan and only
then starts the existing bootstrap:

- install modes: installed (platform dirs) / portable (one folder next to
  the exe / AppImage, config.json travels with it)
- user-chosen storage: env dir, data dir (OMNIVOICE_DATA_DIR), model cache
  (OMNIVOICE_CACHE_DIR) — None = legacy default, byte-identical behavior
- minimum-space gate: per-volume free-space check (fs4 statvfs), grouped by
  filesystem so dirs sharing a disk sum their requirements; install refused
  when short (9 GiB env + 7 GiB models + 1 GiB data, measured + headroom)
- custom mirrors (PyPI index, HF endpoint, python-build-standalone) take
  precedence over region presets in the venv/sync/backend env wiring
- ROCm torch variant selectable via config (env var still wins)
- existing installs migrate silently: venv present → setup_complete=true,
  no questions re-asked; dev trees skip the gate entirely

19 unit tests (disk probing, space grouping, mirror validation, legacy
config compat).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): first-run setup screen — mode, storage with space gate, mirrors, compute

FirstRunSetup renders when the Rust side reports awaiting_setup (lazy-loaded;
regular launches pay nothing). One screen, defaults all work:

- language picker first (rest re-renders translated), 21 locales shipped
- Installed / Portable mode cards (portable disabled with reason when the
  exe-adjacent folder isn't writable)
- storage rows with live per-path free-space probes (debounced
  check_install_target), 'needs ~X / Y free' readouts, folder pickers
- client mirrors the Rust per-volume space gate: Start installation is
  disabled with an explicit reason until every volume fits
- compute (CUDA-auto / ROCm), update channel, region + custom mirror URLs
- complete_setup errors surface inline; on success the normal bootstrap
  progress UI takes over on the next status poll

Verified on a wiped machine: gate parks (no spawn, no downloads), screen
renders, 450 GB ≥ 17 GB requirement → Start enabled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): studio-console redesign of the first-run screen

The setup screen now reads as powering on studio hardware rather than a web
form — true to a voice studio, and self-sufficient offline (every font and
asset is bundled; a first run may be on a restricted network):

- breathing waveform masthead (CSS-only, deterministic speech-cadence
  silhouette, staggered per-bar delays)
- Source Serif 4 display headline + engraved IBM Plex Mono panel labels +
  Inter body — the three faces the app already ships
- rack-unit panels with corner screws, engraved title rules, serial plate
  (OVS · vX.Y.Z)
- disk space as segmented LED capacity meters: lit = what the install
  consumes, alarm-blink red on insufficient volumes
- mode cards with indicator LEDs; 'armed' Start button — LED lights and a
  halo pulses only once every volume passes the space gate
- atmosphere: corner accent glows + SVG film grain; staggered rise-in
  choreography on load
- all motion transform/opacity only; prefers-reduced-motion holds every
  frame still; theme-token derived colors; focus-visible rings throughout

No logic changes: same IPC calls, same i18n keys, same space-gate math.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): wide desktop deck, hardware-aware Compute + Update channel cards

Three pieces of feedback addressed:

- width: the console is now a 1240px two-column deck (storage rail left,
  decision rail right) that uses desktop real estate; collapses to one
  column under 980px and stacks fully under 620px
- no outer chassis box: panels float directly on the atmospheric backdrop,
  each carrying its own rack-unit treatment
- Compute and Update channel split into separate cards with real
  information: get_setup_state now detects hardware (nvidia-smi → CUDA
  name, /sys/class/drm vendor 0x1002 → AMD/ROCm, Apple Silicon → MPS,
  CPU cores + RAM via sysinfo; best-effort, never blocks) — the Compute
  card shows a live 'Detected: …' readout, badges the option that matches
  the machine, and pre-selects ROCm on AMD boxes; both cards use LED
  radio options with full descriptions (6 new i18n keys × 21 locales)

Also pins playwright-core as an explicit devDep — bun did not materialize
it through @playwright/test, breaking programmatic browser use.

20/20 Rust tests · vite build · CJK guard green. Verified live (gate
engaged, responsive single-column) and at 1600×1000 via mocked-IPC
browser shot (two-column deck).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): move network (region + mirrors) into the masthead with language

Language and download region are the two 'where am I' choices — they now
sit together top-right of the masthead, with the custom-mirrors disclosure
tucked beneath the subtitle. The Network panel is gone, leaving a balanced
deck: Install mode + Storage left, Compute + Update channel right.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): strip the boxes — fills and rules carry the structure

One design rule now: borders only where state demands them. Panels lose
their boxes entirely (engraved mono title + rule separates sections);
option cards, storage rows, selects/inputs, the hw readout, the version
plate and the ghost buttons are all flat fills; active options glow with
an accent tint + LED; blocked rows and errors use a red tint + 2px inset
edge bar instead of a border. The badge chip is fill-only too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): quiet pass — every element earns its visual weight

- waveform becomes a whisper: 22px trace, 2px bars, ~half opacity — an
  ambient signature instead of a billboard
- storage readouts collapse to one mono line ('needs ~9 GB · 449 GB free');
  the LED meter now appears only when it carries information (install
  would consume >35% of free space, or the volume is blocked) — at 449 GB
  free a bar was a meaningless sliver
- Change… buttons go text-quiet (transparent until hover)
- custom-mirrors disclosure right-aligns under the region select it
  extends, instead of floating under the subtitle
- version plate moves to the footer next to the disk total — the masthead
  keeps only title, subtitle, and the two locale/region selects

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): platform-matrix awareness — distro+arch detection, ROCm gated to Linux, no Windows console flash

The install matrix is OS family × distro × arch × GPU vendor, and the
setup screen now both shows it and only offers choices valid for it:

- HardwareInfo gains os_name (distro PRETTY_NAME from /etc/os-release on
  Linux, macOS/Windows elsewhere) and arch (x86_64/aarch64) — the detected
  line reads 'CachyOS x86_64 · NVIDIA RTX 4070 · 32×CPU · 31 GB RAM',
  exactly what bug reports cite
- SetupState gains os; the ROCm option renders on Linux only (wheels
  don't exist elsewhere) and complete_setup clamps rocm→auto on
  non-Linux as the server-side backstop
- nvidia-smi probe gets CREATE_NO_WINDOW on Windows — no cmd flash on
  the first screen a user ever sees
- Apple Silicon → MPS, Intel mac → CPU, ARM Linux → CPU: all matrix
  cells resolve through the same base constructor

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): unify the whole first-run journey under the studio-console system

Setup → Installing → Model wizard now read as one continuous experience:
the same atmosphere, whisper waveform masthead, serif/mono type, LED
language and quiet fills across all three acts.

- Installing (BootstrapSplash): rebuilt in frs-* — segmented LED journey
  meter (completed steps + live byte progress), LED step rail (done=green,
  active=pulsing accent, pending=dim), engraved ACTIVITY panel with the
  quiet mono log (collapse/copy as text-quiet actions), failure act with
  red-tint error + hints + armed Retry. All logic untouched: stage poll,
  event subscription + backfill, dedupe, hints, region/language selects.
- Model wizard (SetupWizard): same masthead with the step rail as engraved
  mono LED steps top-right, welcome cards as option-card surfaces,
  preflight as LED check rows (pass/warn/fail), frs nav buttons with armed
  primaries, embedded Model Store / Engines / Dictation panels scroll
  inside the act. Old 556-line stylesheet replaced by ~60 lines of glue;
  BootstrapSplash.css reduced to a resolving stub.
- FirstRunSetup.css is now the journey's shared design system (step rails,
  log panel, banners, hints, wizard chrome, check rows appended).
- 2 new strings (Installing / Activity) translated across all 21 locales.

Validated end-to-end on this machine: setup screen → Start installation →
real venv bootstrap (~10 min) → backend healthy on 3900 → model wizard.

20/20 Rust tests · vite build · CJK guard green · installing act verified
via mocked-IPC screenshot at stage=installing_deps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): --setup re-entry flag + make the install-plan screen un-stealable

The setup stage is first-run-only by design (completed installs skip it),
but it must be reachable on demand and must actually win the mount when
engaged. Three fixes:

- 'omnivoice-studio --setup' parks the bootstrap in AwaitingSetup on any
  launch — checked before the attach-to-healthy-backend shortcut, so a
  running backend can't skip past it
- App routing: awaiting_setup now outranks everything (a live backend
  answering /setup/status used to route straight to the model wizard);
  the wizard additionally requires stage === 'ready' so it can't mount
  during the initial stage race
- useBootstrapStage: a transient IPC miss no longer permanently declares
  'ready' (which killed the poll loop and silently skipped the setup /
  progress screens) — it retries up to 5 ticks before conceding

Plus journey-wide titlebar clearance (content never sits under the GTK
headerbar / macOS traffic lights / Windows controls) and drag-region
mastheads on all three acts.

Verified: mocked-IPC harness with stage=awaiting_setup + a LIVE backend
answering /setup/status renders the setup screen, not the wizard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(setup): remove backdrop decoration — flat surface, state-only emphasis

The corner accent glows and SVG film grain rendered as visible banding /
noise artifacts on many panels — both gone; the journey now sits on a
clean flat chrome background. Also swept the remaining decorative bloom:
the active option card drops its glow shadow (flat accent tint + LED carry
the state), and the armed Start button loses its pulsing halo (the lit LED
already signals actionable). Remaining shadows are functional micro-detail
only: 6px LED glows, meter track inset, red edge bars.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): journey rail + verbosity diet — clean, smooth, elegant

The setup page is now visibly stage 1 of the install flow: a quiet
breadcrumb rail (SETUP → INSTALLING → MODELS & ENGINES) sits between the
waveform and the headline on both the setup and installing acts, LEDs
marking done/active/pending — one continuous story across the journey.

Verbosity halved without hiding information:
- option descriptions unfold (260ms ease) only on the selected card; the
  page shows exactly one explanation per group, collapsed cards keep the
  text as a tooltip
- storage rows drop their always-on caption (label + path + readout +
  Change… on one line; caption lives in the row tooltip)

The whole page now fits a laptop window without scrolling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): merge Models + Engines into one wizard act

Two tabs weren't necessary: models are the required gate, engines the
optional extras — now two stacked panels in a single 'Models & engines'
step (label reuses the journey-rail key, translated in 21 locales).
Wizard shrinks to 4 steps: Welcome → System check → Models & engines →
Dictation. Continue still gates on models_ready only; engines stay
optional. Welcome cards updated to the 3 remaining acts; static cards
keep their descriptions visible (the active-only fold is for radios).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(setup): wizard was skipped after first-run install — probe /setup/status on bootstrap ready

The models-needed probe started at mount with a ~30s retry ceiling. On a
first run, mount happens at the setup page — by the time the user reads
it and the multi-minute install finishes, the attempts were long burned,
so setupChecked landed as 'no wizard needed' and the studio rendered with
zero models on disk. The probe is now keyed on bootstrapStage and runs
when it hits 'ready' — the first moment a backend exists to answer.
Normal launches (backend up quickly) behave exactly as before.

Caught by running the full journey three times end-to-end: rounds 2–3
skipped Models & engines after install; with the fix the wizard mounts
with models_ready=false (Whisper large-v3 listed missing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): drop the Welcome step — wizard opens on System check

The welcome act had nothing left to say: the journey rail names the
stages, the setup page already oriented the user, and the cards repeated
both. The wizard is now three steps — System check (auto-runs on mount) →
Models & engines → Try dictation — landing the user directly on live
preflight results instead of a page about the pages to come.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(setup): true unified library — models + engines as ONE list

'Merge them' meant one list, not two panels stacked — fair criticism.
The wizard's Models & engines act is now a purpose-built WizardLibrary:
every installable is a row of the same grammar (LED · name · chip ·
size · action):

- required models lead (REQUIRED chip, Download action, live SSE
  progress bar + percent, green LED when installed) — they gate continue
- TTS engines follow (ENGINE chip): active engine glows accent,
  available ones offer one-click Use (selectEngine), heavy installs
  defer honestly to Settings ('install later in Settings' + reason
  tooltip)
- the optional-model tail folds behind 'Show N optional models'

The full management surface (search, HF token, deletes, sorting) stays
in Settings — a first run needs a checklist, not a store. 9 new strings
× 21 locales. Verified against the live backend via the browser harness:
required/installed/engine/active/Use/defer states all render in one list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:50:16 +05:30
Palash DebnathandClaude Opus 4.8 5fbc654e82 chore(release): v0.3.5 (#272)
Patch release. Version bumped across all sources + lock files; [0.3.5] CHANGELOG.

Ships:
- #270 — speaker diarization fixed on PyTorch >=2.6 (weights_only=True rejected
  the pyannote checkpoint's TorchVersion global); the loader now registers the
  shared safe-globals allowlist before loading.

Tagging v0.3.5 triggers release.yml (desktop) + docker.yml.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:45:25 +05:30
Palash DebnathandClaude Opus 4.8 fa64dcaa92 chore(release): v0.3.4 (#269)
Patch release. Version bumped across all sources + lock files; [0.3.4] CHANGELOG.

Ships:
- #255 — PyTorch-Whisper backend works as a standalone fallback (no cuDNN 8,
  no OMNIVOICE_PRELOAD_TTS_ASR=1), unblocking Windows+NVIDIA users hitting the
  cudnn_ops_infer64_8.dll error.

Tagging v0.3.4 triggers release.yml (desktop) + docker.yml.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 08:31:34 +05:30
Palash DebnathandClaude Opus 4.8 4e65774610 chore(release): v0.3.3 (#267)
Patch release. Bumps version across all sources + lock files; adds [0.3.3]
CHANGELOG.

Ships:
- #262 — Settings → About now shows the server's CPU architecture (was the
  client browser's platform, e.g. "Win32", in Docker).
- Validates the bash-3.2 checksum CI fix on a real release (the macOS
  SHA256SUMS should now upload automatically).

Tagging v0.3.3 triggers release.yml (desktop) + docker.yml (GHCR
:0.3.3/:0.3/:latest).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 07:13:34 +05:30
Palash DebnathandClaude Opus 4.8 27b4e151e1 chore(release): v0.3.2 (#264)
Patch release. Bumps the version across all sources + lock files and adds the
[0.3.2] CHANGELOG section.

Ships:
- #261 — "Loopback origin required" 403s in the Docker admin UI (and blank
  version): the image now runs in OMNIVOICE_SERVER_MODE so the loopback gate
  is relaxed for the headless deployment; desktop loopback boundary unchanged.

Tagging v0.3.2 triggers release.yml (desktop) and docker.yml (GHCR
:0.3.2/:0.3/:latest).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 06:30:27 +05:30
Palash DebnathandClaude Opus 4.8 cec15070a5 chore(release): v0.3.1 (#260)
First tagged build of the 0.3 line off main. Bumps the version across all
sources (pyproject + frontend package.json + Tauri conf + Cargo + both lock
files + the source-checkout fallback in core/version.py) and adds the [0.3.1]
CHANGELOG section.

Ships:
- #256 — browser/Docker file-export crash (invoke undefined)
- #249 — version surfaced in web/Docker UI + desktop-only updater hidden
- #255 — transcribe stream now surfaces the real ASR/model-load failure

Tagging v0.3.1 triggers release.yml (desktop binaries) and docker.yml
(GHCR :0.3.1 / :0.3 / :latest).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 02:37:50 +05:30
Palash DebnathandClaude Opus 4.8 8690833137 feat(update): move update pill into status bar + Updates panel (changelog/channel/history) (#240)
* docs(spec): updates-in-status-bar design (move pill to LogsFooter + Updates panel)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(plan): updates-in-status-bar implementation plan (11 tasks, TDD)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(plan): pin i18n task to scripts/translate_all.py backfill

* feat(update): pure chip + release presentation helpers

* feat(update): listReleases + fetchAppVersion wrappers

* feat(update): transient releasesSlice composed into store

* feat(update): app version + channel in updaterSlice

* feat(update): list_releases Tauri command (GitHub releases)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(update): UpdateStatusChip bar indicator

* feat(update): UpdatesPanel (live row + channel + releases list)

* feat(update): mount chip+panel in LogsFooter, retire floating UpdateBadge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(update): Settings channel switcher shares store value (auto-sync)

* i18n(update): add updates.* keys across 21 locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(deps): lock reqwest for list_releases command

* polish(update): a11y radiogroup on channel switch, safer release key, drop dead test seam

Addresses final-review nits (non-blocking): role=radiogroup/radio + aria-checked
on the channel Segmented; key={r.name||r.version} to avoid collisions; remove the
unused vi import + __loader seam in releasesSlice.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(update): i18n the channel-set error + correct flagged updates.* translations (PR #240 review)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(update): add 10s timeout to list_releases HTTP client (PR #240 review)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(update): guard chip Restart against in-flight dub job (greptile P1, PR #240)

The always-visible status chip's one-click Restart (ready state) called
installUpdate→relaunch without the dub-busy guard the panel uses, so a user
with a dub/transcription job running could lose in-flight work. Mirror the
panel's gate: toast update.busy and bail when dubStep === 'generating'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(update): surface channel-switch failures in the Updates panel (greptile, PR #240)

Mirror Settings' error handling: the panel's stable/preview switch now catches a
failed set_update_channel and toasts settings.channel_set_failed instead of an
unhandled rejection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 08:53:36 +05:30
Palash DebnathandClaude Opus 4.8 adf486ee03 chore: set version to 0.3.0 across all sources (+ drop v0.4 references) (#145)
* chore: drop stray v0.4 references — everything ships on the v0.3.0 line

Per the project's versioning rule (no v0.4, no unprompted version chatter):

- backend/main.py + marketplace.py: the app reported version "0.4.0" (ahead of
  even pyproject's 0.2.7 and referencing a forbidden version). Aligned to
  "0.2.7" to match pyproject.toml / tauri.conf.json — a consistency fix, not a
  bump.
- errorDocsMap.ts / indextts/bootstrap.py / _secret_key.py: reworded "v0.4"
  deferral comments to version-agnostic "deferred / later hardening pass".
- docs/install/troubleshooting.md: the "tracked for v0.4" notarization line now
  matches macos.md (signing is wired; activates on the Apple cert secrets).

Note: historical planning records under .planning/ still contain "defer to v0.4"
notes; left as-is (a record of superseded decisions) — CLAUDE.md + the
constitution are the live source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: set version to 0.3.0 across all sources (current dev line)

The current/upcoming version is v0.3.0 (0.2.7 is the prior stable). Bump every
version source so the codebase consistently reports 0.3.0 — the in-code dev
version; the git *tag* still happens later per the release cadence.

- pyproject.toml, frontend/src-tauri/Cargo.toml, tauri.conf.json,
  frontend/package.json: 0.2.7 → 0.3.0
- backend/main.py (FastAPI) + marketplace.py export metadata → 0.3.0
  (these had drifted to a phantom "0.4.0")
- CHANGELOG.md: "[0.2.7] — Unreleased" → "[0.3.0] — Unreleased"
- uv.lock + Cargo.lock reconciled (1-line each) so `--frozen` installs hold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(version): read app version from package metadata (no more drift)

Greptile (#145): the FastAPI version + marketplace bundle metadata were bare
string literals — they'd go stale-wrong again at the next bump (the exact class
of bug this PR fixes; that's how "0.4.0" happened). Read once from
importlib.metadata.version("omnivoice") via core.version.APP_VERSION, with a
"0.3.0" fallback only for a non-installed source checkout. pyproject.toml is now
the single source of truth for the runtime version.

Tests: tests/test_app_version.py (semver + equals installed metadata). 2 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 12:08:56 +05:30
Palash Debnath 545b39c912 feat: Scalar API docs, community health files, Quickstart cards (#41)
* feat: Scalar API docs, community health files, Quickstart cards, GHCR Docker

Backend:
- Replace Swagger UI with Scalar at /docs (scalar-fastapi)
- Add OpenAI-compatible /v1/audio endpoints (openai_compat router)
- Add TTS streaming endpoint (tts_stream router)
- Add voice marketplace router (marketplace)
- Update TTS backend registry

Frontend:
- Refine CaptureWidget, WaveformTimeline, App layout
- CSS polish and index.css updates

Community health:
- SECURITY.md — vulnerability reporting policy
- CODE_OF_CONDUCT.md — Contributor Covenant v2.1
- .github/FUNDING.yml — GitHub Sponsors
- .github/ISSUE_TEMPLATE/ — bug report + feature request
- .github/pull_request_template.md — PR checklist

README:
- Quickstart redesigned as 3-column progressive cards
- Docker section updated with GHCR pull instructions
- API Docs row added to service table

Infra:
- scalar-fastapi added to pyproject.toml + uv.lock
- research/ added to .gitignore

* refactor: clean up documentation and logging while enhancing desktop packaging dependencies and capture UI performance.

* fix: address CodeRabbit review — streaming, escaping, thresholds

Backend:
- marketplace: stream zip entries via ZipFile.open()/copyfileobj, add 100MB
  upload cap, fix raise-from exception chaining (OOM prevention)
- openai_compat: _encode_audio returns actual file ext so Content-Disposition
  matches real format; forward non-profile voices when DB row not found
- tts_stream: send 'start' frame after generation so sample_rate is real;
  forward non-profile voices on DB miss
- capture_ws: split MIN_BUFFER_BYTES into separate partial/final thresholds
  so short utterances (<2s) still get transcribed

Frontend (Tauri):
- lib.rs: tray 'dictate' now toggles start/stop based on widget visibility
- commands.rs: XML-escape exe path in LaunchAgent plist, shell-quote in
  .desktop Exec line to prevent injection from special-char paths
- CaptureWidget.css: fix Stylelint violations (empty lines, font-family quotes)
2026-05-04 10:57:37 +05:30
6277561639 feat: implement frameless OS-level floating dictation widget (#40)
* feat: implement frameless OS-level floating dictation widget

- Refactor CaptureButton into standalone CaptureWidget
- Add secondary transparent Tauri window configuration
- Map global hotkey to show/hide widget instead of focusing main app
- Implement auto-hide post-paste
- Add social preview image

* docs: up the game with enhanced README

- Use the high-quality social preview image as the hero image
- Bump download release links to v0.2.7
- Highlight the new Frameless Dictation Widget feature

* docs: complete README overhaul for maximum virality

- Add Highlights section with 2-column feature grid
- Move Quickstart to top with one-command install
- Collapse technical details into expandable sections
- Add 'Up Next' roadmap with concrete upcoming features
- Add star call-to-action banner
- Tighten navigation links and section hierarchy

* docs: add beta warning banner

* docs: add star request to beta banner

* docs: rewrite README with cognitive hooks, remove redundant CTAs

- Remove 2 premature star asks (beta banner + highlights)
- Rewrite highlights with loss-aversion framing
- Keep single earned CTA at the very bottom
- Use action-oriented headings that describe outcomes

* docs: rename section to 'Why OmniVoice Studio?'

* docs: rename 'What you get' to 'Features'

* docs: concise scannable features, remove duplicate section

- Each feature is one punchy emoji-led line
- No verbose paragraphs, no redundant collapsibles
- Removed duplicate Features section from merge

* docs: 3-column feature card grid for visual impact

Replaces flat bullet list with 4x3 HTML table grid.
Each feature gets its own visual cell with emoji header,
bold keywords, and 2-line description. Pops on dark mode.

* docs: fix feature grid vertical alignment

* chore: bump version to 0.2.7, add changelog entry

* fix: apply CodeRabbit auto-fixes

Fixed 1 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
2026-05-03 08:50:34 +05:30
Palash Debnath 0ecbf136e7 refactor: codebase cleanup & root folder reorganization (#38)
refactor: codebase cleanup & root folder reorganization
2026-05-03 03:12:07 +05:30