* feat(dictation): show pending dots while the engine holds speech it hasn't committed
The VAD pause segmenter already knows when a phrase is open. The recognizer
now posts speech-pending when a phrase opens and clears it once that phrase's
text is posted, and the desktop pill shows three dots after the text while it
is on. Only pause-cut on-device streams send it, so cloud, the paired web
client and phones keep today's pill.
* fix(speech): keep a lone click from turning the pending dots on
* fix(speech): let a slow on-device finish run while it still returns text
The stop timeout counted 60 s from Finish however much audio the engine still had
to decode, so a CPU model on a busy machine failed a dictation it was still
transcribing. It now fails only after 60 s without text for that dictation.
* fix(speech): count any engine answer as progress while a dictation finishes
Error rates come from Orca's speech bench (transcribe-cpp 0.4.1, Metal, pinned GGUFs):
LibriSpeech for English, 5 FLEURS dev clips for de, es, fr, ja, ko, pt, ru, tr and zh.
speechModelQuality turns them into the Voice settings word scale.
* Source Control lists Codex models from app-server model/list instead of debug models
The Codex text-action picker read 'codex debug models', a dump of Codex's whole
catalog with prompt templates (40-90 KB per model). Once it passed the 4 MiB
output cap discovery failed and the picker kept Orca's built-in list, and the
dump's hidden entries were selectable. List models with app-server model/list
(hidden rows excluded), over Source Control's own launch, lock and teardown,
with the same 4 MiB input budget and 60 s deadline.
* Bound Codex model discovery input in bytes, key its cache case-insensitively on Windows, and stop the app-server only when it ignores stdin EOF
- Count raw bytes from both streams against the 4 MiB budget.
- Read CODEX_HOME (and other account dirs) case-insensitively on Windows for the host cache key.
- Skip the post-listing kill when the app-server already exited; fail waiting listing requests once discovery settles.
- Report an incomplete model list as such.
- Tests: fake-timer grace and successor admission after a successful listing, method-not-found and unreadable-page fallbacks.
* Key the Codex discovery cache on the env spelling Windows spawn uses
Windows env names ignore case and Node's spawn takes the lexicographically first spelling, so
CODEX_HOME wins over codex_home; the cache key now picks the same one.
* Narrow Codex app-server records with the provider record guard instead of type assertions
* Read Source Control action model picks under the repo's host key, as the picker saves them
Local repos resolved generation under the 'unknown' host key because their connection id is undefined, so the saved pick was skipped and the agent default ran.
* Key Source Control model picks by connection until the repo record loads, and test with a real local repo
* Key a native Codex listing's cache on process.env when no agent env was resolved
* fix(native-chat): apply Windows environment overrides consistently
Use the same case-aware composition for native chat launches, preflight,
model discovery and naming. Canonicalize configured Windows names before
account readers and preserve account pins and POSIX case distinctions.
Tracked in #39075.
Co-authored-by: 김태겸 <oharapass@gmail.com>
Co-authored-by: Vitalii Kulish <mancunianez@gmail.com>
* test(native-chat): cover effective Windows catalog changes
* test(native-chat): retain child environment test import after sync
* test(native-chat): verify Windows child environment precedence
---------
Co-authored-by: 김태겸 <oharapass@gmail.com>
Co-authored-by: Vitalii Kulish <mancunianez@gmail.com>
* fix(native-chat): show OpenCode subagents and keep a chat open while they run
OpenCode reports each subagent as a child session when the client opts in.
Orca now opts in, files each child's tool calls and replies under its own
subagent, and keeps the subagent open until the child reports that it
completed, failed or was interrupted, including after the parent turn ends.
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* fix(native-chat): keep a subagent's tool context when its rows are read back from the journal
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* fix(native-chat): a Stop also ends running OpenCode subagents, and each subagent can be stopped from the strip
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* fix(native-chat): only a chat Stop closes OpenCode subagents, an early subagent Stop stays available, and the close request has a deadline
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* fix(native-chat): a subagent Stop that the subagent confirms while the request is out reads stopped
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* refactor(acp): close child sessions from the agent connection
Keeps the session runtime under the line limit after the main merge.
* test(acp): read a child command through a type guard
* fix(native-chat): a subagent that reports its ending reads stopped even when the close request fails
A child Stop's session/close now asks the agent to drop the call on timeout instead of withdrawing the write.
* test(native-chat): OpenCode subagent calls group with other agents' subagent calls
---------
Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com>
* Save a pasted workspace directory as the path it names
A workspace directory with a leading space (" /Users/me/dev") was saved as
typed. Readers treat it as relative, so Orca resolved it inside every
registered repository and created an empty " /Users/me/dev" tree in each.
Normalize the saved value once where settings are written and loaded, as
the leading ~ fix did: leading whitespace before an absolute or home path is
dropped, while relative paths and trailing characters stay exact. A value
repaired on load keeps its old spelling in history so checkouts under the
old root stay visible. The settings field shows the saved value.
Co-authored-by: Eng. Mahmoud Bek ElNemer <ElNeMeR70@users.noreply.github.com>
* Expand ~\ only where it is a home path; drop type casts
* Classify the padded path with the host's own path rules
On macOS and Linux a leading backslash is part of a relative name, so only
Windows treats \work as absolute.
---------
Co-authored-by: Eng. Mahmoud Bek ElNemer <ElNeMeR70@users.noreply.github.com>
* Show the setup-script choice instead of greying out Create
With a project's setup script set to "Ask every time", Create stayed
disabled until the user picked Run or Skip, but that choice only renders
inside the collapsed Advanced section, so nothing explained the greyed-out
button. Keep the choice out of the disabled gate (as the gate's own comment
already intends) and have Create open Advanced to show it.
* Annotate the partial submit fixture cast
* Bring the setup choice into view when Create needs it
Create now scrolls the Run/Skip choice into the dialog's view and focuses
it on every attempt, including when Advanced is already open, and the
late-discovered setup path uses the same reveal. A submit that only jumps
to an existing pending creation no longer asks for a setup choice.
* Reveal the setup choice once per Create attempt
The choice clears the reveal request after scrolling and focusing, so a
later remount (for example after switching projects) cannot pull focus
without a new Create.
* Drop a pending setup reveal once the user has chosen
Choosing Skip in the moment before the reveal fired could still move focus
onto Run, so a later Enter switched the choice.
Offline models write out the speech before each pause while recording goes on.
Short noises and slow window-padded decodes are held off the pause cuts, a VAD
error falls back to bounded chunks, and slow phrase decodes are judged per
dictation against the time spoken. The VAD download carries legacy files and
fetches after any GGUF model.
* Improve project group ordering across hosts
* fix(project-groups): restore each group order after a failed drop
A deleted group made the aggregate rollback stop early, leaving other groups at
the ranks from the failed drop. Restore each group independently and log the
swallowed single-update failures again.
* refactor(main): give project group RPC methods their own module
Keeps repo.ts under the 300-line cap as the project group surface grows.
* fix(dictation): join Chinese and Japanese phrases without a space, and space Korean ones
The shared transcript fold joined every phrase with a space, so the pill and
phone replies showed Chinese and Japanese text with spaces the inserted text
doesn't have. It now joins with the same rule as insertion. That rule treated
Hangul like Chinese and Japanese, so Korean phrases were inserted with no space
between sentences; Korean spaces words, so Hangul now spaces like Latin text.
* fix(dictation): don't space after Chinese and Japanese full-width punctuation
* fix(dictation): join retried phrases with the same spacing rule
* fix(dictation): escape the spacing rule's non-ASCII marks for the orcad bundle
The shared fold now pulls the spacing rule into the orcad server bundle, which
must stay ASCII. A rich-draft test pinned Hangul joining without a space; it
now expects the Korean spacing.
Stopping a CPU dictation closed the renderer's audio port while frames still
waited behind a decode in the speech worker; the close ended the stream at once
and the queued frames were dropped. A close after 'end' now leaves them to
decode. A model slower than 30 s to load also lost the start of the dictation,
since the renderer kept only 30 s of startup audio; it now keeps as much as the
host waits for the load.
* feat(speech): spell dictionary terms in dictation, with repo terms and Whisper prompt
* test(speech): pin host repo terms for phone dictation
* fix(speech): keep symbol terms whole, accept null setup params, resolve SSH repos
* refactor(speech): key transcript words once and type phone terms at the reply schema
* refactor(speech): merge speech-types imports in the speech IPC
* feat(runtime): tell phones when the desktop refreshes a PR
* fix(runtime): name every checkout a coalesced PR read stood for
* fix(runtime): don't count a read that couldn't load checks as a checks change
transcribe-cpp is now the only on-device engine on every platform, so
the sherpa-onnx packages, their packaging (extraResources, the darwin
libonnxruntime prune, the native-variant assert and the Linux libstdc++
exemption), the sherpa recognizer in the speech process and the
per-model engine choice all go. Hotwords are written as plain terms.
* perf(github): answer phone PR lookups from the desktop's last result
* fix(github): order last PR outcomes by lookup start sequence
* fix(github): keep reused phone PR outcomes out of the refresh observers
* fix(github): reuse a fallback-found PR only for the same fallback number
* feat(speech): move the speech catalog to transcribe-cpp models
Parakeet v2/v3, Whisper tiny and SenseVoice now download their GGUF
builds, which run on transcribe-cpp everywhere, Intel Macs included (on
the CPU). A model still holding its old sherpa-onnx download shows
"Update to the faster version (<size>)"; updating replaces the old
files, and dictating before then says the model needs that update.
The five models with no GGUF build are retired and their users moved
over: the Japanese Parakeet, the Chinese-English Zipformer and the
Paraformer to SenseVoice, and the Korean and Chinese streaming
Zipformers to the new Nemotron 3.5 (28 languages). Nemotron's locale
codes (ko-KR) are matched from the ISO language setting.
* feat(speech): offer the speech model update once after the engine change
A card in the notification corner tells people whose selected on-device
model needs the new download, or whose retired model was replaced, and
starts the same download as Settings > Voice. After a replacement it
offers to delete the retired model's files.
* feat(speech): move retired Korean and Chinese models to SenseVoice and offer Whisper Large v3 Turbo
On transcribe-cpp 0.4.1 with Metal, SenseVoice beat Nemotron 3.5 on Korean
and Chinese FLEURS clips, so the retired Korean and Chinese streaming
Zipformers now move to SenseVoice. Whisper Large v3 Turbo (Q8_0, 886 MB)
joins the catalog as the most accurate choice for Japanese, Korean and
Chinese. Nemotron 3.5 stays, described by the languages it does best.
* feat(mobile): keep dictating after leaving the session, with a floating pill
* feat(mobile): translate the dictation pill and its toasts
* fix(mobile): type away words without claiming the terminal, and keep the pill above screens
* fix(mobile): float the pill above bottom bars, reopen the owner's own screen, and tell a refused start wherever you are
* fix(mobile): float the dictation pill above the source control bar
* fix(mobile): keep pill state out of the host context and reopen the starting screen first
* refactor(mobile): subscribe the pill only while it shows and trim the session dictation hook
* fix(mobile): key bar clearances by symbol
* feat(mobile): save the chat when the app leaves the foreground
A swipe-kill from the app switcher can end the app before the page is
hidden: iOS fires visibilitychange only at background, and Android Recents
leaves the activity resumed. The shell now sends an appInactive frame on
iOS inactive and Android window blur, to pages that declare they read it,
and the page saves any chat rows the store doesn't hold yet.
* fix(mobile): keep the leave callback out of render
* fix(mobile): notice a changed middle row before skipping a chat save
* perf(mobile): show accounts from the last snapshot
* fix(mobile): never count a stored accounts snapshot as live
* test(mobile): pin when accounts usage counts as live
* fix(mobile): date accounts reads by when they were sent and block switches until live
* fix(mobile): show accounts usage only from this screen's own read, drop replies from before a reconnect
* feat(settings): add a Use GPU switch for on-device dictation
On by default (Auto: the GPU when it works, the CPU when it fails).
Turning it off keeps the transcribe-cpp speech process on the CPU, for
machines whose GPU driver freezes or restarts them. The row shows when
the selected model runs on transcribe-cpp.
* fix(speech): reload the warm speech model when Use GPU changes
A loaded recognizer kept the GPU choice it started with, so turning Use GPU
off left the next dictations on the GPU until the model unloaded.
* fix(speech): reload the speech model after a dictation when Use GPU changed during it
A recognizer still in use when Use GPU changed stayed loaded afterwards with
the old choice. It now unloads as soon as its last dictation ends, and the
warm-up loads it again with the new choice.
The pill showed only the current partial and went back to Listening after
each final, so pause-committed phrases from transcribe-cpp never appeared.
The host's transcript fold moves to src/shared and the desktop pill uses it
too: committed text in the foreground, tentative text muted.
Add an OpenAI-compatible model whose base URL, model and optional key
are set up in a Voice settings dialog and sealed together in ~/.orca,
so a key is never sent to a host it wasn't saved for. It reaches
OpenAI, Groq, Mistral and local servers, and replaces the unused
userModels setting.
* feat(speech): run GGUF models on transcribe-cpp, falling back to the CPU
The speech host child can now load a second engine. A model whose files
are GGUF runs on transcribe-cpp (Metal on Apple silicon, Vulkan on
Windows and Linux, CPU otherwise); everything else stays on sherpa-onnx,
which remains the only engine on Intel Macs.
A GPU that fails to load, errors, stalls for 25 s or crashes the process
moves the dictation to a CPU-only process (TRANSCRIBE_BACKENDS=cpu) that
replays the audio the GPU had not decoded yet, so no words are lost or
repeated. A GPU that crashed or would not load is remembered per
transcribe-cpp version and OS release, and voice.speechGpu = 'off' keeps
it on the CPU.
Packaging copies transcribe-cpp, koffi and the target's native package
into resources/node_modules outside asar, fails when a target's package
is missing, and ships the MSVC runtime beside transcribe.dll on Windows.
No catalog model is GGUF yet, so nothing runs on transcribe-cpp until
the catalog change that follows.
* fix(speech): keep the speech queue running after a failed task, and drop audio frames after a discard
* fix(speech): keep the engine's file reads off the main thread's hot paths
The engine lookup and the GPU failure marker are read once per process
instead of on every dictation start and mobile catalog request, the marker
is written asynchronously, and the child reads the hotwords file with
fs/promises. The baseline moves the existing engine presence checks from
stt-worker-paths to the shared package table and adds the once-per-process
marker reads.
* fix(mobile): stop Review's branch compare re-reading back to back during git bursts
fetchHostQuery re-read a compare as soon as it landed marked by a git event, so a burst of gitStatusChanged events with reads slower than the event spacing kept the desktop running compares back to back, and kept going after Review closed. A re-read now goes at once only after a quiet spell (a write's own event), otherwise floorMs after the last read landed, and stops once Review's build is no longer current. A superseded build no longer evicts the entry a newer build is reading.
* fix(mobile): show each compare that lands during a git burst while Review reads it again
* fix(mobile): keep note edits when a later compare lands on a shown Review build
The phone filters in-progress VM checkouts only when it reads its host
workspace list, so a read made before a window's hide reached the main
process kept showing the checkout until the next unrelated change. Emit
worktreesChanged for each repo whose pending checkout appears or goes
away; phones already re-read their host workspace list on that event.
* fix(vm-recipes): hide an in-progress VM checkout in every window, the phone and the jump palette
A VM create's checkout was hidden only in the sidebar of the window that
started the create. Windows now publish their pending VM checkouts to the
main process, which shares every window's set with all windows and
filters the paired phone's host workspace list and workspace context.
The jump palette and the sidebar read the shared set, and a grouped VM
project no longer draws an empty-project placeholder while its create
is pending. A window's set is dropped when it closes, crashes or reloads.
* test(project-groups): reset leaked runtime environment revisions between files