CPU preset leads with Whisper small; CLIs and loaders share omnivoice.utils.dtype
(honours OMNIVOICE_CPU_DTYPE, no import cycle); the Windows-on-ARM notice and the
disk-space message are localized (setup_space takes {{gib}}: 5 for CPU installs, 9
otherwise); ARM64 payloads without a manifest fail the release check; Windows on
ARM is labelled experimental; test imports resolve at run time.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds a windows-11-arm leg to the packaging rehearsal and the release matrix
(experimental: a failed leg does not block the four established targets; the
release-asset check verifies the arm64 feed in full whenever any trace of it is
published). install.ps1 installs the native ARM64 build and falls back to x64
under emulation. README and the Windows/script docs gain a hardware table, CPU-only
and Windows-on-ARM guidance, and the external-drive recipe for #2436.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* feat(electron): publish AppImage zsync updates (#2327)
* Use FUSE-independent AppImage runtime (#2328)
* Launch packaged AppImage in Linux smoke checks
* Postprocess AppImages for source installs and dist builds
* Keep external AppImage updates on the matching release channel
* Run Linux source install smoke against the PR main revision
* Accept shallow PR commits in installer smoke source mirror
Make Electron the maintained desktop target, preserve frozen Tauri v0.5.3 updater feeds, and align setup, smoke checks, release policy and documentation. Validated by full CI, cross-platform smoke and install tests, security checks, and bot review.
Closes#1974.
The dev launcher only treated a port holder as ours when it ran out of the git
checkout. A backend the Tauri shell spawned lives under a per-app directory
named after the bundle id instead, so the launcher saw its OWN orphaned backend
as a stranger, refused to free port 3900, and aborted the run with "Refusing to
stop unrelated process" and no way forward but Task Manager.
Ownership now also accepts the app's reverse-DNS identifier in the executable
path or the command line. A bundle id is specific enough to be safe: nothing
else on the machine carries it, which is the point of the namespace.
The guard itself is unchanged in spirit — a foreign listener on the port is
still refused, and a test pins that widening ownership did not widen it to
everything, including a process from some other vendor's bundle.
Known limit, since I hit it in this repo: on Windows the check is given the
command line and executable path but not the working directory, so a backend
started by hand from an arbitrary interpreter — a bare `uvicorn` whose only
link to the checkout is a relative --app-dir — is still not recognised. That is
a different shape from the reported one and needs the cwd, which this code path
does not currently have.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ypcgSsh5j2PEonSJiAU1S
STRUCTURE.md still described the April layout: it was missing
backend/engines, worker, mcp_shim, speech_client, migrations, plugins,
hooks and config; the frontend e2e suites, i18n and src-tauri packaging
inputs; and the bin, skills, .agents/skills, notebooks, omnivoice-gallery
and .github/workflows top-level entries. Stale docs are bugs.
Three corrections beyond the missing entries:
- "all tests live here, no exceptions" was wrong. There are three homes
(tests/, backend/tests/, co-located vitest) and the split is deliberate:
pyproject testpaths, a separate ci.yml job, and the sys.modules-stub
hazard documented in backend/tests/conftest.py. Replaced the claim with
a table that records why each home exists.
- .env.example does not exist and the app never reads a repo-local .env;
the durable user env file is ~/.config/omnivoice/env
(backend/core/user_env.py), written by the Settings panel.
- .agents/ was listed as deleted, but it is back with a different job:
the canonical skill copies pinned by skills-lock.json.
Also fixes the dead blob/main/STRUCTURE.md URL in the backlink script --
the file has lived in docs/ since the cleanup pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LDyC6prbjFydox9XQGhyny
Adds the sherpa-onnx dictation model picker under the Transcription engine
row so the model the hotkey loads is switchable without opening Settings,
routes the Sherpa transcription path through that same preference, and makes
the Windows desktop dev stack recover instead of demanding Task Manager.
Refreshes the Tauri and npm dependency pins that went with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ypcgSsh5j2PEonSJiAU1S
Achados do CodeRabbit no PR #1942.
O mais grave: com o erro classificado como transitorio, o codigo mantinha o
acelerador ligado mas caia direto no `snapshot_download` na MESMA tentativa. Se
esse download desse certo, o laco terminava e o manifesto do `.part` nunca era
reusado — exatamente o recomeco-do-zero que a correcao existe para impedir.
Agora o erro transitorio e propagado para o retry externo, cuja proxima
tentativa reentra no `_segmented_snapshot` e retoma do manifesto. A decisao
virou o helper puro `_segmented_retry_plan`, testavel direto (o laco mora dentro
de `install_model`, uma rota de ~200 linhas). A ultima tentativa fica reservada
para o caminho simples, entao o acelerador continua sem poder ser o motivo de um
install falhar de vez.
Tambem deste round de revisao:
- `Invoke-CimMethod ... Terminate` tinha o retorno descartado com `$null =`. O
Win32_Process.Terminate reporta falha pelo ReturnValue, nao lancando: um kill
negado por permissao era reportado como sucesso e a porta seguia presa. Agora
o ReturnValue e validado, com exit 4 proprio e a mensagem carregando o codigo.
- O teste de concorrencia era vazio: o handler sincrono do MockTransport retorna
antes de qualquer outra task rodar, entao `peak` nunca passava de 1 e a
asserção `peak <= 4` passava sem exercitar o semaforo. Passou a segurar as
requisicoes abertas com um asyncio.Event e a exigir `peak == 4` (verificado:
com o semaforo afrouxado para 1000, o teste acusa 31).
- A doc dizia que OMNIVOICE_DOWNLOAD_MAX_WORKERS limita as faixas e que origem
sem Range cai no snapshot_download. Nenhum dos dois: `_segmented_snapshot` nao
passa `num_connections` (usa as 8 padrao) e origem sem Range vira stream unico
dentro do proprio acelerador.
- Entradas de Highlights do CHANGELOG sem o `(#NNNN)` exigido.
`canStop: !windows` fazia o script recusar qualquer parada no Windows com
"stop it in Task Manager and retry". O motivo original é legítimo: `taskkill
/pid` mira um PID reutilizável, e um PID reciclado entre o inspect e o kill
derrubaria um processo alheio.
Só que isso deixava o `bun run dev` permanentemente travado sempre que um
backend ficasse órfão — exatamente o cenário do commit anterior sobre a árvore
de processos. O predev falhava e não havia caminho de recuperação automático.
A parada agora é presa à INSTÂNCIA do processo: um único PowerShell busca a
instância CIM, confere o CreationDate contra a identidade já inspecionada e só
então chama Terminate NAQUELA instância. O terminate age sobre o objeto que a
checagem validou, não sobre um PID buscado de novo depois — a corrida some.
PID reciclado devolve exit 3 e é deixado em paz, em vez de falhar a execução.
`belongsToCheckout(..., windows = false)` respeitava a flag na hora de montar
a string, mas normalizava o caminho com `resolve()` do host. Rodando no
Windows, "/work/VoiceStudio" virava "C:\work\VoiceStudio" e não casava com
nada numa linha de comando POSIX — o mesmo valia para o separador `sep`.
Efeito prático: o teste "command ownership requires a checkout path boundary"
já falhava na `main` limpa em qualquer máquina Windows, passando só no CI
Linux. Passa a usar `path.posix` quando a flag diz POSIX.
O supervisor faz `spawn("uv", ...)` e o uv sobe o uvicorn como filho dele.
Windows não tem sinais: `child.kill()` vira TerminateProcess só no filho
DIRETO, então matar o `uv` deixava o uvicorn neto vivo segurando a porta 3900.
O spawn seguinte falhava com `[Errno 10048]`, o supervisor contava como crash,
e três desses derrubavam a stack inteira de dev — inclusive o Vite, via
`--kill-others-on-fail`.
`killProcessTree` usa `taskkill /T` no win32 e mantém o envio de sinal no
POSIX. Como o kill forçado devolve exit não-zero e sinal nulo, o reload que nós
mesmos pedimos passaria por crash; isso é tratado olhando se o tree-kill de
fato aconteceu, e não a plataforma — um crash de verdade durante um reload
continua indo para a recuperação de crash (coberto por teste que já existia).
Synchronize VoiceStudio release metadata, lockfiles, installers, container references, documentation, and the dated v0.5.2 changelog after all planned fixes landed.
Closes#1713
Adds a separately identified per-user MSI and updater channel, non-administrator install/uninstall verification, and fail-closed WebView2 handling for current-user installs.