* test: remove low-value automation and shared suites
* test: retire stale gate references and stabilize retained fixture date
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(native-chat): show the page a browser run drove, not another chat's
* fix(browser): run each queued agent command in its own RPC call
* fix(native-chat): once a chat claims its browser activity, ignore unclaimed activity
* feat(orchestration): mail agents on a paired server with send --on, replies come back by themselves
* fix(orchestration): gate --on on the carrying Orca, ack retried deliveries, refuse payloads and federated workers
* chore(orchestration): annotate peer-mail row casts and drop a wall-clock wait in its test
* chore(orchestration): name mail-between-servers codes server_mail_unsupported and mail_requires_server_pairing
* docs(cli): list --on in the orchestration reply usage
* fix(orchestration): name --environment, the flag on main, in agent mail refusals and the guide
* chore(orchestration): mark the two deliberate agent-kind branches mail between servers needs
* docs(cli): leave --on out of the reply usage; it is accepted only to refuse it
* fix(orchestration): keep peer conversations to peer ids, survive resets and re-pairs, keep pulling on a registry error
- A server takes only peerconv_ conversation ids, so a paired computer cannot name another Orca's dispatch in the relay.
- A replayed reply after a mail reset is acknowledged, not retried forever; reset tasks keeps replies waiting to be pulled.
- A re-paired server starts a new conversation instead of refusing every later send and reply.
- A failed registry read keeps the pull loop retrying.
- Drop the two ast-grep-ignore lines that only #40193's rule needed.
* fix(orchestration): worker-start --on runs on the caller's own Orca, like send --on
An inherited ORCA_ENVIRONMENT sent worker-start --on to that server, so the
--on command the agent refusal suggests did not work. One rule now keeps
send, reply and worker-start with --on on the caller's own Orca.
* fix(orchestration): refuse reply --on on both sides of a conversation between servers
The side that opened the conversation still took --on when it named the right
server; the reply usage says --on is accepted only to refuse it.
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.
* 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.
* refactor: separate execution route and child exit owners
* refactor: move browser data into defining feature owners
* refactor: give runtime RPC entry its shutdown implementation
* refactor: use defining process types and colocate host telemetry test
* docs(process-host): point piped child contract to Node owner
* docs(process-host): clarify both piped contract owners
* feat(cli): create workspaces on environment recipes
`orca worktree create --recipe <id>` creates the workspace on a new
environment from one of the repo's environment recipes, and
`orca vm recipe list` shows which recipes it accepts.
The desktop app on the provisioning computer runs the same main-side
provisioning the composer uses (write-ahead record, per-step timeouts,
cancellation), registers the project on the environment's Orca server,
then creates (orca-worktree) or adopts (provisioned-root) the
workspace there. Named progress steps ride on long-poll keepalive
frames, so the CLI prints them to stderr; older CLIs ignore them. A
failure after the VM exists destroys it through the shared cleanup and
returns recipe_workspace_create_failed with the failed step, the
recipe failure code and whether the destroy finished. Ctrl+C aborts
the request and destroys a started environment.
Paired devices cannot start a recipe create. Hosts advertise
worktree.recipe-create.v1 only when the desktop wires the recipe
service, so orcad and older hosts are refused before anything runs.
Based on #39228 by jutaz, a port of #28439.
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
* fix(cli): report the VM outcome when connecting fails; record no cross-host parent
* fix(vm-recipes): destroy the VM when recording its environment fails; reset exitCode in CLI tests
* perf(types): keep recipe orchestration out of the runtime's type graph
---------
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
* refactor: use concrete browser and input owners
* refactor: bind remote runtime callers to concrete transport owners
* Use checked subscription mock argument types
* Type browser lease mock with its subscription contract
* refactor: bind sleeping VM status probe test to socket owner
* fix(runtime): move the local RPC socket to a short path when userData is too long
A long userData path made the local RPC socket path exceed the Unix
sun_path limit (104 bytes on macOS, 108 on Linux), so listen failed with
EINVAL and the CLI could not reach the runtime. Reuse the terminal
daemon's relocation: resolveDaemonUnixSocketPath moves the socket to a
private /tmp/.orca-daemon-<uid>/<hash> dir, the server creates and
verifies that dir before listening, and the orphan sweep covers it.
The CLI and the browser sidecar check the dir is private to this user
before they send the auth token, as the daemon client does.
* fix(runtime): verify the relocated socket dir before sweeping it; probe relocated holder sockets
Check that the relocated /tmp/.orca-daemon-<uid>/<hash> dir is private to
this user before the orphan sweep lists or unlinks anything in it, and skip
that dir when the check fails. The orcad stale-lock reclaim now also scans
the relocated dir for the holder's runtime socket, so a live holder there
is probed and its lock is not reclaimed.
* fix(runtime): ship the socket-dir check with the packaged CLI; keep main sync fs flat
The CLI imports daemon-socket-endpoint-path, but electron-vite replaces
out/main, so packaging lost the module and the installed CLI crashed.
Add it to the CLI main entries and unpack it with its mode constants.
The lifecycle sweep and the stale-lock reclaim now use async fs for the
relocated dir, so the main sync-fs count stays at its baseline.
---------
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
* refactor: import journal queue state from defining owners
* refactor(shared): organize execution and automation owners
* fix: retain type imports used by surviving test cases
* refactor: finish work item owners and refresh validation metadata
* test: infer reconnect status fixture type
* test(claude): resolve source files beside same-named directories
* test(runtime): group repository creation mock registrations
* feat(pairing): Add server and orca environment add exchange the link for their own token
After verifying the host, Add server (and repair) swap the access link's
token for one generated on this computer when the host advertises
pairing.ticket-exchange.v1, and save that instead. orca environment add does
the same with a short best-effort probe. Any failure saves the link as today;
the host keeps accepting it until the new token is used.
* test(pairing): Add server and CLI leave links unchanged for a released host
* fix(pairing): Add server and orca environment add sign in once after exchanging, and the CLI rejects a refused code
After exchanging a link, sign in once with the new token so the host
retires the link right away instead of at the first later use; a host
downgraded in between would not know the new token.
orca environment add no longer saves a pairing code the host refuses
(for example one another device already used); it asks for a new code.
* feat(remote-runtime): use E2EE v2 for desktop and CLI connections to remote runtimes
Desktop connections to remote runtimes (orca serve, orcad, managed SSH,
browser bridge) and the orca CLI now use E2EE v2 framing for hosts that
support it, and fall back to the legacy framing for hosts that do not.
- One-shot requests try v2 first. A host that refuses the v2 hello
(hosts from before v2) or refuses capabilities on v2 token auth gets
one transparent legacy redial; nothing but the handshake is sent before
authentication, so the redial is safe.
- After a v2 sign-in succeeds, the host's pinned key is remembered in the
profile (shared by the app and the CLI). Every connection to that host,
including long-lived sockets, then uses v2 and never falls back.
- Long-lived sockets keep legacy framing until a host has proven v2, so
they never see an older host refuse a v2 hello.
- Hosts accept clientCapabilities on direct v2 token auth, so desktop and
CLI clients keep their capability negotiation on v2. Relay token auth
stays exact.
* feat(remote-runtime): recover a latched host that was downgraded, without a legacy downgrade path
A host this profile had signed in to over v2 was refused for good if it
was later downgraded below capability-carrying v2 token auth. Hosts now
advertise pairing.e2ee-v2-token-capabilities.v1. When a latched host
refuses v2, a one-shot request asks the host over legacy framing (keyed
to its pinned key, so only the real host can answer) for status.get:
- no capability: the host itself says it was downgraded; the latch is
dropped and the request goes ahead over legacy;
- capability present, or no answer: the request fails with an error
that says to update the host or check the network path. Only the
read-only status check ever ran over legacy.
A refusal faked on the path cannot produce the host's answer, so it
cannot force legacy framing for a latched host.
* feat(serve): refuse public source addresses on orca serve unless allowed
`orca serve` listens on every interface. It now accepts connections from
loopback, private LAN (10/8, 172.16/12, 192.168/16, 169.254/16, fc00::/7,
fe80::/10) and Tailscale (100.64/10, fd7a:115c:a1e0::/48) sources, and drops
public-source TCP connections before HTTP parsing or the WebSocket upgrade.
Public sources stay accepted when:
- --allow-public is passed (orca serve, orcad, serve service install);
- a paired device has authenticated from a public address (persisted flag);
- --pairing-address is a hostname or a public IP literal;
- any device paired before this server first ran the check is still paired.
The startup log states which rule applies; the first refused public address
each hour is logged with the flag name. Desktop listeners and Orca Relay are
unaffected.
* feat(serve): accept on-link public addresses and add --refuse-public
A public source inside a prefix of one of this host's own interfaces (os.networkInterfaces, re-read at most every 5 s) is a same-network peer, such as a LAN client using global IPv6, and is now admitted. Prefixes wider than /16 (IPv4) or /48 (IPv6) are ignored.
--refuse-public (orca serve, orcad, serve service install) refuses public addresses regardless of grandfathered pairings, a remembered public connection or the pairing address; it cannot be combined with --allow-public.
* feat(cli): pair clients with a running Orca via `orca pair`
A headless Orca could only print a pairing offer at startup, so pairing a
phone with `orca serve service install` meant stopping the service. `orca
pair` asks the running runtime for an offer over the owner's local socket
through a new `pairing.createOffer` method (pairing-admin, never granted to
paired clients or phones). It reuses the desktop's offer logic, now shared
by the Settings IPC handlers: mobile offers stay LAN-only unless --relay,
and the first network pairing widens a loopback bind as the desktop does.
Also honor an explicit ORCA_SERVE_RUNTIME=orcad on packaged macOS. Electron
serve needs a desktop login and aborts in an SSH session with nobody logged
in; orcad is plain Node and serves there, at the cost of no in-app updater.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(cli): move the serve-restore and pair handler groups out of the manifest
handler-group-manifest.ts was already at the 300-line limit on main, so
adding the pair group failed lint. Group the two serve/pairing entries in
their own file, as jira, linear and reference already are.
* test(mobile): pin the desktop pairing IPC handlers' replies and runtime calls
Characterizes mobile:getPairingQR and mobile:getRuntimePairingUrl across
every branch (explicit and default address, LAN-only with no address,
Relay without an address, relay failures, this-computer reach, widening
and its failure, unavailable offers). The same file passes unchanged on
main and on this branch, so moving the offer logic into
pairing-offer-requests.ts did not change the desktop path.
* test(mobile): type the QR stub instead of casting it
---------
Co-authored-by: Office exitnote <h@Offices-MBP.lan>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Neil <neil@stably.ai>
* feat(serve): add bind address option
* fix(serve): validate service bind address
* fix(serve): validate bind flag values
* fix(serve): reject scoped bind addresses
* docs(serve): document bind option paths
* docs(serve): note that --mobile-pairing needs an all-interfaces bind
* fix(serve): move bind address parsing to shared so the packaged CLI can load it
The packaged CLI ships out/cli and out/shared but not out/main/orcad, so
cli/runtime/serve-bind-flag.js failed the packaged runtime-import check
(and would fail to load) when it imported main/orcad/orcad-bind-address.
Move the module, unchanged, to src/shared and point orcad, Electron serve
and the CLI at it.
* test(serve): pin down the default listener and the --bind startup paths
- Extract the Electron serve listener pin into resolveServePinnedBindHost
and test that serve without --bind stays unpinned (all interfaces, as
before), an explicit --bind pins it from either argv form, and the orcad
browser sidecar stays on loopback.
- Golden the orcad and Electron serve argv without --bind against the
pre---bind output.
- Test that the CLI passes bind only when given and refuses --bind with
--mobile-pairing before launching.
- Guard that serve-bind-flag and the shared serve validation load only CLI
and shared modules, which is what the packaged CLI ships.
---------
Co-authored-by: lw <13579959+bertramlongwuyan@user.noreply.gitee.com>
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: xuanchangfeng <210147232+xuanchangfeng@users.noreply.github.com>
A recipe VM workspace runs on its VM's own Orca server, so a phone, the CLI or
the desktop reaching it while the VM slept dialed a server that was not there
and failed. Only the host window's click ran the recipe's resume.
- The VM wake owner (WorkspaceSleepCoordinator) tracks the VM operations it
was asked for and answers where the VM stands: a pending wake or a running
suspend outranks the stored record.
- The host holds a request that opens the workspace (worktree.activate,
defined once in shared code) until the VM is up: three minutes for the
desktop and the CLI, and for a phone only as long as still lets the relay
connect inside the phone's 30-second deadline. A VM still up keeps a sleep
on its way from suspending it; a VM asleep or suspending wakes after what is
running, joining a wake already pending. The open answers waking only when
the hold runs out, wake_failed when the wake fails, and asleep when a Sleep
asked for while it was held won; that open then wakes nothing more. Other
requests answer waking or asleep instead of dialing nothing. A Sleep asked
for during a wake keeps its place in the lifecycle queue and starts once the
wake is done. A caller that gives up stops waiting and frees its queue
place; the wake goes on.
- An open of a server the user disconnected is refused before anything wakes
its VM, and cancelled if they disconnect while it waits. A wake carries the
SSH host's user hold from when it was accepted and every Disconnect since,
so its connect never lifts a hold; the VM still resumes and its new SSH
address is saved for the user's own Connect.
- A wake re-pairs a paired VM's server. The request that waited for it is
held to its caller's pairing as of before the wake (a stale caller is
refused before it can wake anything), then to exactly the pairing revision
the resume produced (including a re-pair its SSH reconnect made), whatever
process now serves it; any other change still
refuses it. A phone link still preparing for an open survives only the
re-pair its own wake made; any other retirement, or a user Disconnect, ends
it, and a link preparing for anything else is retired at once.
- The hold lives in the desktop's environment preparation, which its own calls
and subscriptions, the phone relay and the CLI all go through. A phone open
on a link to a server whose VM is not up gets a fresh link; the old link's
requests are answered waking or asleep. Further opens join a link already
waiting on the wake. A phone link's whole open (server preparation with any
hold, grant sync and the socket) shares one deadline inside the phone's
own, for every server.
- The CLI dials a VM directly, so `orca worktree activate` asks the desktop
(runtimeEnvironment.wakeRecipeVm) to open the VM and reads the server's
pairing again; the refusals (including runtime_manually_disconnected) keep
their codes over RPC, and a host without recipe VMs answers that one RPC
with method_not_found. Hosts that do this advertise
host.recipe-vm-wake.v1.
- A workspace this host runs on a recipe VM over its SSH target wakes on this
host's own activation, through the resume's explicit connect
(wakeWorkspaceVm -> resumeVm -> connectRuntimeOwnedSshTarget). That connect
runs whenever the VM is in SSH mode, even when its recipe had no resume step,
since suspend tore down the transport.
Fixes#36923
Co-authored-by: ggbdpq <ggbdpq@gmail.com>
* fix(cli): keep read-only commands working when environment usage can't be recorded
The CLI recorded each environment's last-used time with a strict store write,
so a profile whose directory refuses chmod (EPERM) failed commands whose reply
had already arrived. The desktop already skipped such failures in one path.
Move that best-effort recorder to shared code and route every desktop and CLI
usage write through it.
Fixes#38673
* test: assert the usage write failure, not call counts
Refs #38673
* test: skip the chmod EPERM case on Windows and drop a cast
Refs #38673
* fix(cli): use the terminal's worktree when cwd is outside every worktree
Browser, terminal and computer commands run from an unmanaged cwd fell back to the worktree focused in the window. They now use the calling terminal's ORCA_WORKTREE_ID or folder ORCA_WORKSPACE_ID before that default. Fixes#37899.
* fix(cli): resolve the terminal worktree against the catalog
Match ORCA_WORKTREE_ID on the caller's host so ids shared across hosts
go out as identity:, accept folder: ids from either terminal env var,
and keep the runtime default when worktree.list cannot be read.
* fix(cli): refuse a stale terminal worktree instead of using the focused one
When ORCA_WORKTREE_ID names a worktree the catalog no longer lists on the
caller's host, fail with a --worktree hint rather than silently targeting the
workspace focused in Orca. Clear the terminal's workspace env in the test setup
so CLI tests run the same inside an Orca terminal.
* fix(cli): keep the floating terminal on the runtime default
The floating terminal's ORCA_WORKTREE_ID is a sentinel with no catalog row, so it must not hit the stale-workspace error. Word that error as what the CLI can tell: the workspace is not listed, which also covers hidden worktrees.
* fix(cli): ignore terminal workspace ids from another Orca profile
A shell from the installed app that targets a dev build or throwaway serve carries worktree ids that runtime never issued. Reuse the runtime-source fence rule to skip them, so those commands keep the target runtime's default instead of failing.
* test(cli): drop tests that pass without the terminal-workspace fallback
Remove the list-failure and cwd-precedence cases, which pass on main, and the SSH stubs the folder case never reads.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
The CLI now measures the serialized runtime request against the shared
1 MiB local transport limit before writing any bytes. Oversized requests
fail with invalid_argument and requestSent=false instead of being cut off
by the server mid-frame, and the client skips mutation recovery for these
unsent requests so it never suggests resending the same payload.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(orcad): yield a lost instance lock and refuse non-durable terminals under a supervisor
Fixes#37605
* fix(orcad): treat an unstattable lock as unproven; scope supervised help to orcad
Fixes#37605
* fix(daemon): report fresh-terminal ownership from current spawn routing
Fixes#37605
* fix(daemon): narrow fresh-spawn routing check to degraded providers
Fixes#37605
* test(orcad): cover lock-loss yield and fix stale test paths after rebase
Fixes#37605