New profiles default artifactSharingEnabled to true. Existing users are
unchanged: stored settings win over defaults on load, and a stored profile
saved before the key existed loads as false instead of inheriting the new
default. The gate still requires an explicit true, sign-in is still
required, and web clients still mirror the host (their local fallback no
longer inherits the desktop default). showArtifactsButton is unchanged.
* feat(cli): read and message agent chats with orca chat list/read/send
Carried over from #33115 (squashed onto current main; conflicts with chat rename resolved).
* feat(cli): wait for a chat to settle, read text from stdin, refuse paired hosts
chat send --wait and chat wait poll the history's working flag until the
chat is idle or waits on a question, keeping a queued message pending until
it runs. chat read is one history fetch and returns a cursor. Unattached
and paired-host refusals say what they mean.
* fix(cli): settle a held queued message, skip subagent rows, resolve chat list --worktree
* fix(cli): show chat errors, keep waiting through queue handoffs, return the whole settled turn
* fix(cli): settle any queued message the host will not send, show grouped questions and only answerable prompts
* test(cli): drive chat tests through a real client and fake timers
* fix(cli): describe chat --session, --wait and --state in command help
* fix(cli): report chat wait in chat list's states, reject unknown --state, flag truncated reads
* docs(cli): say chat wait settles on the chat's own turn; no truncated flag on held
* fix(cli): chat rename help asks for a session id, not a handle
---------
Co-authored-by: YangNuoCheng <42427439+YangNuoCheng@users.noreply.github.com>
* feat(plugins): add editor.readTypography and editor.typography.changed
Plugins that render code next to Orca's editor had to open the private
profile database and reimplement Orca's font rules to match it. Host API 1.6
adds editor.readTypography (no capability; worker, panel and editor frames):
the font family and CSS stack, size with editor zoom, weight, line height in
px, ligatures, word wrap and minimap that the file editor resolves now.
editor.typography.changed carries the same values after a settings write or
an editor zoom changes them; it is the first event that needs no capability.
The pure resolution (editor typography, editor zoom, monospace font stack)
moves to src/shared so main and the renderer use one implementation.
* fix(plugins): keep editor typography resolution from throwing in main
A hand-edited profile with a non-string font family made the shared resolver
throw, which the main-process watcher would surface at startup and on every
settings write. Font values are now type-checked, the watcher catches and
logs, and it reads live settings so a write without listeners cannot leave the
event payload stale. Over-long font families are cut to the schema bound
instead of failing every read. Regenerates the testing runtime.
Shared workers (#40067) keep native addons such as the Windows process tree
and ConPTY loaded across files. Windows workers then exit with 0xC0000374
(STATUS_HEAP_CORRUPTION) in the node-server persistence lane. Production code
loads these addons lazily, so the per-file scan cannot detect them.
* Simplify Settings chrome and organize General into focused views
* Preserve search and skill actions across Settings views
* Correct Settings validation leftovers
* Keep skill conflict details visible in compact Settings rows
* Refresh Settings search and protected copy catalogs
* Use Settings design tokens and button variants
* Keep Settings test setup and translation catalogs current
* Keep Settings search metadata independent of display labels
* Build repository search groups only for the selected pane
* Keep pending skill installs and server menu labels accurate
* Use the supported role locator in the skill regression
* Keep absent skill installation actions on their supported path
* Restore the Settings sidebar to its existing appearance
* Restore shared navigation title keys in pane headings
* Preserve the Settings shell entry animation
* Drop unused Voice labels after the main sync
* Preserve main Voice translations and the moved skill module import
* docs: slim CONTRIBUTING.md to the essentials for getting a PR merged
Move dev-environment reference into docs/development.md and the maintainer
release process into docs/releasing.md.
* docs: match CONTRIBUTING visual-proof guidance to the PR template
* docs: cut dev-environment internals and drop the stale release doc
Trim docs/development.md to the setup steps people actually hit, drop
docs/releasing.md in favor of the self-documenting Cut Release workflow,
and move the RC Homebrew cask into the README.
* Document Node compatibility and dev profile cleanup
Restores the line above messages that arrived while you were away, the scroll to it on return and the screen-reader announcement, all removed in #38044. A new Chat > Behavior switch, "Mark new messages when returning to a chat" (on by default), turns it off; off tracks nothing.
* feat(release): publish a server-only Linux tarball for orca serve
Each release now also uploads orca-server-linux-x64.tar.gz and
orca-server-linux-arm64.tar.gz (orcad slot from the qualified template, the
pinned Node, and an orca-ide launcher) plus orca-server-sha256sums.txt, so a
Linux host can run orca serve without the desktop package.
The tarballs are packed and smoke-tested (serve --recipe-json, then pair a
second profile) on both architectures, including bare ubuntu:24.04 and
debian:12-slim containers. Upload runs only after the release is published
and nothing depends on it, so it cannot hold the desktop release.
* fix(release): keep the server tarball's launcher env out of its terminals; skip refs that predate it
- The launcher runs the CLI with ELECTRON_RUN_AS_NODE=1, as the packaged app does, and the CLI strips it
before starting orcad; ORCA_APP_EXECUTABLE and ORCA_SERVE_RUNTIME are cleared.
- Ship Node's LICENSE beside the runtime.
- Skip packing on release refs that predate the scripts, and upload only when both tarballs passed.
- Run the PR smoke when the CLI's serve-runtime selection changes; document service install.
* feat(plugins): add workspace.rename and project names in workspace.list
Plugins that name workspaces had to read Orca's private runtime token and call
worktree.set over the runtime socket, bypassing capability consent. workspace.rename
(workspace:write, worker only, host API 1.5) does the same update as a sidebar
rename. workspace.list rows gain the project name so plugins can prefix names
without reading the runtime's repo list.
* fix(plugins): harden workspace.rename against twin folders and hidden characters
Folder renames require a unique folder id, so twins on two hosts are not both renamed,
and fail when no folder has the id. Names refuse C1, bidi and zero-width characters,
which could make a label read as another workspace's name.
* fix(plugins): workspace.rename matches a sidebar rename for folders and reports kept names
A folder rename also cancels a pending first-agent-message rename, so the automatic
title cannot replace the plugin's name. A rename Orca does not apply (during a WSL
move) is a conflict instead of a silent success. workspace.list's project is optional,
so mocks written for host API 1.4 still validate. More invisible characters are refused.
OpenAI shuts gpt-4o-transcribe and gpt-4o-mini-transcribe down on
2027-02-26. Offer GPT Transcribe instead, retire both old entries so a
saved choice loads as the new model, and send the language hint as
languages[], which gpt-transcribe takes in place of language.
* wip
* rm execessive tooltip
* Clarify deletion options and improve resource popover layout
- Show the scope of persistent deletion choices directly in the menu
- Keep resource details accessible in short windows
- Style disabled dropdown actions consistently
* Clarify detached commits and deletion guidance
* Preserve translated tooltip guidance
A Codex chat launched codex app-server on the account home saved when the
chat was created, and nothing compared it with the selection, so after a
switch every message kept going to the old account. A chat that had hit
its usage limit kept failing with "Codex hit its usage limit" even though
the new account had quota.
Codex chats now follow the selection the way Claude chats do: the launch
prepares the selected account's home, the started process reports that
home, and the host replaces an idle chat whose account no longer matches
before its next message. Codex resumes a thread only from a rollout in its
own CODEX_HOME, so the launch links the thread's rollout into the new home
first. The chat's usage card reads the account its next turn runs on.
* Rotate the server pairing identity when ORCA_INSTANCE_ID changes
* Back up replaced identity files, keep the recorded id on reset, keep staged files once the rotating marker is published
* Add identity-reset files to the sync fs baseline and document the backup folder
* Report a reset honestly after finishing an interrupted rotation; keep first backups and the newest one
App themes may set background.videoPath: a muted, looping MP4 or WebM (H.264
recommended, VP9 or AV1; one video track, no audio; <= 60 s, 8 MB, 2.3 MP)
played over the required static background.path. Main checks it from container
headers without decoding and serves it on the orca-plugin-image slot
theme-<i>-video; images stay static-only. The renderer reveals it on its first
frame, keeps the still on any failure or a decoded size past the limits, plays
it only while main reports the window focused, shown and not minimized and no
dialog is open, and omits it under prefers-reduced-motion.
Animated WebP was measured and declined: software-decoded every frame, it cost
11-23 points of CPU vs 3-10 for the same loop as video.
Implements #38363 proposed by @dohaidang.
* feat(themes): public plugin theme tokens for chat text and selection
Themes can now set chat bold text, muted text, inline code, code blocks and
the chat selection. Omitted tokens paint exactly what chat painted before,
except the selection, which now keeps selected text 4.5:1 by default.
* docs(themes): note the bubble and code-block checks for chat text tokens
* fix(themes): never lower the chat selection under its visible floor
* feat(plugins): let plugins contribute web fonts to the font pickers
Plugins declare font families under contributes.fonts (WOFF/WOFF2 only).
Install checks each file's signature against its extension and caps file
size, family count and plugin total; main never parses a font. Files are
served over the plugin image scheme only while the plugin is enabled,
typed and nosniff. The renderer registers each family under a name that
carries the plugin key, so a plugin font cannot shadow an installed or
built-in font, and it applies only once the user picks it. Disabling or
uninstalling removes the faces; uninstalling also resets font settings
that named them.
Refs #38607
* fix(plugins): harden plugin fonts and re-measure editors when they load
- Refuse WOFF/WOFF2-wrapped font collections by checking the flavor bytes.
- Check dev folders' font files at discovery, not only at install.
- Re-check family, weight and style from the plugin list in the renderer.
- Track loaded families (case-insensitively) from document font loads, so
the code editor re-measures and terminals, previews, the SSH terminal and
the dashboard popout re-apply only when their own font changes.
- Register plugin fonts in the dashboard popout window.
- Give dev-folder font URLs their change count so edits reload.
- Keep monospace fallbacks unless the chosen family is exactly that font.
* fix(terminal): keep every fallback only for plugin font families
System font choices keep their existing fallback list unchanged.
* fix(plugins): leave the dashboard popout's plugin list alone; add the font row string
Registering fonts there started the plugin auto-update watcher in a window with no toaster, which could consume update notices. Adds the new contribution-row string to the English catalog and the fonts list to the RPC test manifest.
* 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>
* fix(packaging): require macOS 13.4, which the bundled speech engine needs
* fix(updater): keep the macOS requirement title clear of the close button
* fix(packaging): check out the Darwin floor table for adhoc builds and raise the cask floor
* refactor(updater): reuse the parsed Darwin floor for the macOS requirement
* fix(updater): use a margin to keep the macOS requirement title clear of the close button
* fix(updater): say the macOS requirement comes from Electron and the speech engine
* 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>
Antigravity automations refused --extra-agent-args, so unattended agy jobs
could only use the model and effort from agy's global settings.json. Allow
--model and --effort through the existing allowlist; permission, mode, and
other flags stay refused.
Part of #35234 (STA-12678).
Antigravity Accounts rejected a WSL account location outright. agy inside
WSL keeps its login in its file store (~/.gemini/antigravity-cli/
antigravity-oauth-token; it detects WSL the same way
isAntigravityFileStorageHost does), so save/select/remove now work there:
- A WSL credential backend reads and writes that file through runWslProcess
in the selected distro (default resolved via resolveWslDefaultDistro). It
checks the distro is running before every guest command and never starts a
stopped one. Writes are a compare-and-swap inside the guest (sha256 of the
expected file), go through a private temp file and rename, and pass the
credential on stdin rather than the command line.
- runWslProcess accepts stdin input for argv-delivered commands.
- Each distro gets its own encrypted vault, so accounts never cross distros
or the Windows host.
- Accounts "Refresh usage" is enabled for WSL now that usage reads the
selected runtime (#38985), and rejects a reading tagged with another
runtime's provenance.
Fixes#25847
Linear: STA-9624
* feat(cli): add orca host rm for saved SSH targets
orca host rm --host ssh:<target-id> calls the runtime RPC ssh.removeTarget,
the same removeSshTarget the Settings UI reaches, so the tombstone keeps the
passive ~/.ssh/config import from adding the alias back.
Also document how the import treats Match blocks and Include files.
* fix(ssh): clear a removed target's live state and rename in main for every removal path
Removing an SSH target through ssh.removeTarget (orca host rm, paired clients)
left open tabs with stale reconnect state and kept the host's rename, because
only the Settings dialogs cleaned up after their own IPC call. The shared
removal mutation now drops the display-label override and tells the renderer,
which clears the target's state once for all callers.
Fixes#37949
* fix(ssh): clean up after a removed target in the teardown every removal ends in
A recipe VM's cleanup removes its SSH target through removeRegisteredSshTarget
directly, so the window kept that target's live state. The broadcast and the
rename drop now run there, after the target is gone.
Fixes#37949
* test(cli): keep host rm's retarget-flag refusal next to its other cases
Its old file was removed on main.
Fixes#37949
* refactor(cli): give the host, managed-server and VM handler groups their own module
Keeps the handler manifest under the file-length limit.
Fixes#37949
---------
Co-authored-by: Florin Timbuc <florin@sowild.design>
* fix(sidebar): keep the selected card's host pill outline visible in dim themes
#38841 tinted the host pill outline 40% of the sidebar text into the
sidebar. A theme whose sidebar text is only 4.5:1 leaves that outline at
about 1.6:1 against the selected wash, which matches the pill's fill, so
the pill loses its shape.
When an app theme is painted, its colors are now concrete, so compute
once per theme the smallest mix (from 40%) that gives the outline 2:1
against the selected wash, the same floor focus rings use, and paint it
as --worktree-host-pill-outline-mix. main.css falls back to 40%, so
Orca's built-in themes and any theme bright enough keep today's look.
The tinted sidebar resets it, like the row wash. The wash's CSS fallback
joins the fallback table so the check (and the token reference) read
what main.css paints.
Refs #38641
* fix(sidebar): floor the host pill outline in the tinted left sidebar too
The tinted sidebar paints the app's text on its tint mixed into the app
background, so the theme's measured outline mix doesn't apply there and
it fell back to 40%: a dim theme (#919191 on #2a2a2a) at the default 8%
tint left the outline at 1.6:1 on the selected wash. Measure the tinted
colors once whenever the app theme or tint settings change, paint the
result as a root variable, and have the tinted sidebar read it. Share the
measurement (hostPillOutlineMixOver) with the theme path, and make its
comment name the actual invariant instead of the pill label's contrast.
Refs #38641
* fix(antigravity): switch agy accounts through the Linux Secret Service keyring
agy stores its Linux login with go-keyring's Secret Service provider
(service=gemini, username=antigravity, login collection or default alias)
and falls back to its credential file without a session bus, in containers,
SSH and WSL. Add a secret-tool/gdbus adapter that mirrors that collection
choice, refuses locked keyrings with a clear error, and keep the file store
for headless hosts.
Fixes#32818 (STA-11911)
* test(antigravity): avoid casts in Linux keyring adapter test
* feat(cli): select and remove any saved agent account from `orca account`
`orca account select` and `orca account rm` accepted only OpenCode and
Devin. They now cover every provider with saved accounts — Claude, Codex,
OpenCode, Devin and Antigravity — through the runtime methods the
status-bar switcher and Settings already use (accounts.selectClaude,
selectCodex/selectCodexForTarget, selectData, antigravitySelect and the
matching remove methods). No runtime or wire change.
`--account` takes an id, an email/label (case-insensitive) or `system`.
A name shared by several accounts is refused with their ids rather than
guessing which subscription to bill. `system` is refused for Antigravity
(no system default), for Claude from the WSL bridge (the RPC has no
target and would reset the Windows host), and always for `rm`.
`orca account list` now prints each account's id and a `system` row,
accepts `--agent` for every provider, and adds the Antigravity block when
the host can read it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(cli): assert the host refusal for Antigravity accounts from WSL
The host rejects every client-selected WSL target for Antigravity account
management, reads included, so the test now mirrors that refusal and checks
that no select call is made instead of asserting an impossible success path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(cli): keep only the account-selection tests that guard this change
Moves the guards into account.test.ts (the handler layer that owns them) and
drops layer-duplicating, copy-pinning, Cartesian and mock-only cases per
AGENTS.md test rules; un-exports resolveAccountId (test-only export).
---------
Co-authored-by: Maxime AUBURTIN <m@hellomax.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>