* fix(agents): workspaces created on a paired host use the host's launch settings
Creating a workspace with agent picks or a draft could launch the paired host's agent with desktop settings, or lose the picks during recovery. Let capable hosts compose those launches from their own settings and preserve the user's inputs through fallback creation. Older hosts retain their existing requests.
* fix(agents): workspaces created on a paired host use the host's launch settings
When a workspace is created on a paired computer, agent picks and Arguments can be replaced by this computer's defaults or dropped during recovery. Keep explicit choices with the submission and let the paired computer resolve its own launch settings.
Preserve older-host request behavior, disabled-agent draft substitution and prompt submission, and restore the composer if compatibility preparation fails.
* fix(agents): workspaces created on a paired host use the host's launch settings
Keep the submitted choices available when a background launch has no prepared startup carrier. Tighten the regression checks for restored composer names, legacy commands and prompt submission so recovery preserves the user's work.
* fix(agents): workspaces created on a paired host use the host's launch settings
Creating a workspace on a paired machine could ignore its agent settings or lose a draft while the terminal connected. Keep the selected launch inputs and the pending text together through fallback and reconnect, and never replay partially written input. Preserve older hosts' launch commands and ordinary new-tab prompts' editable behavior.
* fix(agents): workspaces created on a paired host use the host's launch settings
Keep a workspace's pending prompt attached to its original terminal while the pane reconnects. Stop automatic delivery before reporting a final failure, retain the recoverable text, and recognize a launch handed off to the paired host even before its tab appears. Avoid delaying creation on a redundant host status request.
* fix(agents): workspaces created on a paired host use the host's launch settings
New workspaces on a paired computer could lose their first prompt when the terminal briefly disconnected. Delayed delivery could also continue after reporting failure, or leave terminal-only agents without an accessible copy of their prompt.
Keep pending prompts through attachment loss, stop content writes when automatic delivery ends, and offer the existing composer to recover unsent text. Preserve launch identity without inventing empty Arguments or treating missing metadata as a replacement.
* fix(agents): workspaces created on a paired host use the host's launch settings
A replacement pane can learn its terminal before the layout catches up after reconnecting. Re-registering the effective launch settings then dropped the original first-prompt identity.
Recover that identity from the existing verified terminal binding so later remounts keep the same pending prompt.
* fix(agents): workspaces created on a paired host use the host's launch settings
A terminal binding can identify the launch before its effective Arguments are known. Keep permission notifications working in that state without assuming a launch-settings recipe exists.
* fix(agents): workspaces created on a paired host use the host's launch settings
Keep an unsent prompt attached to its launch when a paired host briefly disappears, so reconnecting the same terminal can finish delivery. Clear the rest of the exited pane's status as before, and release the binding after delivery or a confirmed end.
Offer Copy prompt when automatic delivery finally fails, so the prompt can be pasted into the terminal that already opened. Keep creation-failure Reopen separate.
* fix(agents): preserve paired prompt recovery across transport updates
Resolve the consumed startup token through the pane's verified binding instead of reading renderer ownership during every remote attach. Keep the transport's host-authoritative exit and reconnect behavior and its fixture guards.
Settle pending prompt delivery when the host reconfirms a closed surface, including after it discards the terminal's exit record. Update the remount fixture for the Windows PTY model binding.
* fix(agents): merge duplicate imports flagged by type-aware lint
* test(agents): fix type assertions in paired launch fixtures
Type the repository rows, mutable agent choice and terminal tab used by
launch regressions. Reuse the session binding across its real installers
and document the partial-fixture adapters required by the runtime APIs.
Keep the RPC, remount and prompt-delivery assertions unchanged.
* fix(agents): route workspace terminals through their owning host
Creating a terminal for an existing workspace could send it to another focused server. Resolve its owning host when no explicit route was supplied, and keep the host-shaped draft regression within the shared startup contract so renderer checks do not pull in main-process code.
* test(agents): align launch fixtures with runtime dependencies
Retain real i18n exports while replacing translation output, hoist the terminal restore toast spy, and supply the explicit host environment used by paired terminal callers. Keep the existing behavior assertions unchanged.
* fix(agents): isolate prompt failure notice dependencies
Load the prompt failure notice only when a settled hosted launch needs it,
so workspace recovery consumers do not initialize toast and localized agent
catalogs just by importing delivery code. Keep prompt retirement and its
recoverable draft synchronous, and preserve the existing Copy prompt action.
Restore the ordinary new-tab failure toast's original invocation and verify
that Fix Checks retains its edited request through the activation handoff.
* test(agents): route legacy wire launches to their fixture host
Pass the paired environment explicitly in legacy terminal-creation fixtures,
matching real launch callers instead of relying on the focused host. Keep
all compatibility and accepted-creation assertions unchanged.
* fix(agents): preserve paired work-item completion without a startup plan
Blank-terminal work-item launches on paired hosts now keep their successful activation result. If the agent command cannot be built, show that error once instead of reporting an activation failure.
* refactor(agents): deliver paired creation prompts once like agent tabs
Drop the retained hosted-prompt lifecycle (pending map, rebind, deadline,
terminal retirement, token recovery). After the host creates the session the
desktop attempts the prompt once; failure shows the prompt-not-sent toast with
Copy prompt.
* fix(agents): silence prompt failures after closing a workspace terminal
Closing a paired workspace terminal before the agent was ready could report a prompt failure after that terminal was gone. Use shared launch completion and existing tab records to keep deliberate closes silent while preserving one Copy prompt notice after an interrupted delivery. Prepared launches now decide client delivery from the host request.
* fix(agents): report every failed paired prompt delivery
A paired host can retract its tab from inventory without the user cancelling the launch. Always report a failed prompt attempt with Copy prompt, using the same single-attempt completion as agent tabs.
* test(agents): name host-session fixture mock types
* refactor: place native chat media and link code with defining owners
* refactor: preserve code control copy protection after relocation
* style: format rebased native chat owner imports
* fix(cursor): write workspace trust where cursor-agent reads it
cursor-agent names ~/.cursor/projects/<dir> by replacing every
non-alphanumeric character with '-', collapsing repeats, and trimming
dashes. Orca only replaced Windows-illegal characters, so paths with
'_', '.', spaces or non-ASCII got a marker cursor-agent never reads and
the trust menu appeared on every fresh worktree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(cursor): cover space, non-ASCII and Windows paths in the trust slug test
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
* refactor(backend): use defining owners for orchestration and ACP startup
* test(orchestration): trim redundant observations and retain safety cases
* test(orchestration): seed restored sessions with one fixed operation clock
agy has no Full access session mode, so Full access chats always fell back to
Orca's managed runtime, which kept most people off the host's agy (and off
Intel Macs, where only the host can run it). agy 1.5.2+ `agy acp` accepts
--dangerously-skip-permissions, which approves tool requests but not plans.
Host chats now launch with that flag only in Full access, in agy's default
mode. Switching permission mid-chat already restarts the ACP process and
resumes the session, so the flag follows the chat's mode. The flag never
approves plans, and Orca still leaves agy's requests to the person, so plan
approvals keep surfacing.
The cached readiness check launches with the flag, so a build that rejects it
keeps chats on Orca's runtime without an extra spawn; such a binary is not
checked again until it changes. Because ask and Full access both run agy's
default mode, the reported mode is read per launch, so a Full access chat
does not show as Ask.
Refs #39006, #33188
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.
* refactor(renderer): organize host and terminal implementation owners
* fix(refactor): align active adoption reliability references
* refactor(terminal): remove forwarding shells and stale mocks
* fix(renderer): consolidate direct owner imports
* fix(refactor): route incoming issue trust type to its owner
* test(runtime): give independent status viewers separate pairing tickets
* style(refactor): normalize rebased terminal mock formatting
Store absolute deadlines instead of two last-seen timestamps, and let
scroll events with no wake pending return before reading the clock.
Behaviour is unchanged.
* fix(plugins): don't count time asleep as worker idle time
The idle reaper measured idleness with the wall clock, so after a sleep longer than the reap window its first sweep reaped every worker before their own timers could fire. A sweep gap well past the 60s interval now starts a fresh idle window.
* fix(plugins): count a sleep before the first idle sweep as asleep, not idle
Start the reaper's sleep-detection clock when the first worker starts, so the
first sweep after waking can see the gap even if no sweep ran before the lid
closed.
* fix(plugins): keep worker manager under max-lines and restore real timers after sleep tests
Move the idle-candidate filter into PluginWorkerIdleClock so the rebased manager
stays within the 300-line lint cap, and reset fake timers after the idle-reap
tests so the sleep-before-first-sweep case does not leak them.
---------
Co-authored-by: petersindex <287557875+petersindex@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
The managed-runtime install message now names the observed cause after the
existing headline: a timeout, an exit code with a redacted stderr excerpt, or
the version the server answered as. The host agy check that shares the
initialize helper is unchanged.
Takes over #34167 by @Jinwoo-H (away), ported onto main after #39006.
Co-authored-by: Jinwoo-H <73622457+Jinwoo-H@users.noreply.github.com>
Live foreground output with background colors or in-place rewrites
requested a synchronous xterm row repair after every write, on top of
the dirty-row frame xterm had already queued while parsing. Busy
OpenCode frames all carry background SGR, so DOM panes painted each
frame twice.
The synchronous repair exists for Windows ConPTY DOM rendering. Keep it
there and let other platforms merge the repair into xterm's queued
frame. Replay and snapshot refresh policy is unchanged.
Drop tests that only asserted the private synchronous refresh call.
Fixes#22458
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(plugins): surface reserved-identity install errors for local forks
Official template forks keep stablyai/orca-* identities that correctly
cannot install from a local path, but the UI swallowed the reason as a
generic failure. Keep the security block and show actionable rename
guidance in the install dialog (#12598).
* test(plugins): mock i18n for reserved-identity error presentation
* fix(plugins): match reserved-identity errors before git heuristic
Production trust strings mention github.com; the broad /(git|...)/ check
matched the "git" substring inside "github" and mis-surfaced reserved
fork installs as fetch failures. Prefer reserved-identity matching and
lock presentation tests to the full pluginInstallTrustError strings.
* fix(plugins): map the current reserved-name install refusal to rename guidance
Main now refuses reserved plugin keys from every non-official source with
"<key> uses a name reserved for official Orca plugins; ...", so the
author's matcher on the old "reserved plugin identity" string never fired
and forks of official templates still saw the generic install failure.
Match the current string (before the Git heuristic), use one message that
tells the user to rename id/publisher, and register the English key.
Refs #12598
---------
Co-authored-by: Neil <neil@stably.ai>
* fix(plugins): resolve the active workspace context on remote hosts
* fix(plugins): scope the remote workspace context to its host
* docs(plugins): document the remote context resolver
* fix(plugins): keep remote context ids raw and never fall back for local rows
The stored-row fallback returned host-qualified ids (ssh:host|repo::path), which no
terminal selector or agent-status row matches, so agents.list stayed empty for the
remote workspace. It also answered for a removed local worktree, turning a stale
focus that used to read null into a context for a workspace that no longer exists.
* fix(plugins): resolve a focused paired-server workspace from the desktop's server rows
A paired orcad server's workspaces live in that server's store, so neither the local
catalog nor the desktop's stored rows can name one and workspace.readContext,
workspace.changed and agents.list saw no context. The runtime now asks the relay host
catalog, which answers from the worktree.ps rows the desktop already caches. Only a
miss on a reachable server fetches, bounded at 1.5 s and at most once per 10 s per
missing workspace; an unreachable or hung server answers null.
* fix(plugins): keep a stale local focus stamp resolving as before, and cover #38653 end to end
A focus stamped 'local' whose repo row now routes elsewhere resolved through the
unscoped selector before #38653; the host-scoped lookup turned it into null. A
local stamp now retries unscoped, so local and unstamped focus answers exactly
what main did. Remote stamps keep the scoped lookup, so a paired-server focus
never borrows a local twin's context.
Tests: real-git parity of local, folder and SSH contexts against the pre-change
selector answer for every session shape the renderer writes; panel polling
against a hung or failing server (one fetch, one bounded wait per 10 s window);
an e2e that pairs a desktop with a headless Orca server, clicks a local and a
server row, reads workspace.readContext from a plugin panel, and keeps polling
fast after the server goes away.
---------
Co-authored-by: Neil <neil@stably.ai>
* 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
React Compiler skips any function containing `??=`, `||=` or `&&=`. Rewrite
the statement-position ones whose target re-reads without side effects
(identifiers and plain member chains) as the equivalent `if`:
a ??= b -> if (a == null) { a = b }
a ||= b -> if (!a) { a = b }
a &&= b -> if (a) { a = b }
21 files; 25 fewer bailouts and 12 more compiled functions in the
compiler-compat baseline.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(plugins): isolate development watcher retries by root
* test(plugins): keep coverage for late binding checks after housekeeping disposal
The per-root rewrite replaced the old housekeeping unit tests; restore the
disposal/coalescing case so a slow check that resolves after dispose cannot
restart a watcher or refresh, and per-root checks do not stack.
* fix(plugins): skip the full plugin rediscovery while a dev folder retry keeps failing
A maintenance retry that subscribes already refreshes itself; one that keeps failing (an
unreachable WSL share) rediscovered every plugin each tick. Only a changed root binding needs
discovery now.
Also covers what the per-root rewrite must keep: adding/removing a folder leaves the others'
watchers and frame revisions alone and releases its subscriptions, a rejecting registration
retries once per tick, Linux sibling folders keep separate parent watches, and an Electron e2e
where deleting/recreating/removing one dev folder never reloads another folder's open panel.
---------
Co-authored-by: be0hhh <182023099+be0hhh@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
A focused plugin frame resolved Mod+B/Mod+L to the sidebar toggles and
Mod+=/-/0 to zoom, but the guest forwarder had no sidebar branch and
dropped zoom for non-page guests, so the plugin kept the keys.
* fix(plugins): keep a workspace-scoped panel edit made just before a workspace switch
The guest's persist queue holds atoms, not values, and the renderer stored each
ui.persist under whichever workspace was active when it arrived. An edit made
less than 0.4 s before a switch was flushed after the new workspace's hydrate,
so workspace B's value was written under B and A's edit was lost.
The host now names each ui.hydrate; the guest flushes pending writes before
applying the next hydrate and tags ui.persist with the hydration its values came
from, and the renderer stores the write under that hydration's workspace.
(STA-13316)
* test(plugins): cover workspace-persist hydration routing edge cases and add switch e2e
Adds unit coverage for A->B->A routing, legacy (no hydration) persists, the eight-hydration window, plugin-scope entries, and guest flush/tagging; adds an Electron e2e that types in workspace A, switches inside the persist debounce, and checks both workspaces after switching back and after the panel's guest is recreated. Regenerates orca-testing.mjs after rebasing on main.
* fix(plugins): stop a late replacing command from repeating the built-in action
The renderer ran Orca's own action after 2 s but the still-running replacing
command could then call commands.run for the same action, doing it twice.
Main now owns the 2 s cutoff: it rejects at the deadline (the renderer falls
back on that answer) and from then refuses the late handler's commands.run of
the replaced action; a handler that already ran the action is not followed by a
fallback. The deadline now starts when the renderer asked, not after plugins
load. The renderer's own timer is only a safety net. (STA-13530)
* test(plugins): cover replacement races and verify the sidebar toggles once end to end
A handler's commands.run now counts for the oldest in-flight press only, so a second
concurrent press whose handler fails still gets Orca's fallback. Adds unit cases for a
throwing/crashed handler, two presses racing, and a press after a late handler returns,
plus an Electron e2e spec driving fast, late (2.1 s), throwing and no-op replacements of
sidebar.left.toggle.
* fix(plugins): stop terminal inventories for agent status events nobody hears
Each agent.status.changed event for plugins lists the workspace's terminals,
which refreshes every PTY provider and host. Interest was only checked when an
event was admitted, so after the last panel closed the queued backlog kept
running full inventories with no one to deliver to.
Recheck interest before each lookup and drop the backlog once nobody listens,
and let events queued behind a slow lookup share one listing per workspace
while keeping arrival order. (STA-13319)
* fix(plugins): keep the agent status queue moving past a throwing delivery
A synchronous throw from one emitEvent dropped the rest of its batch and left
later queued events waiting for the next arrival. Catch per delivery, and cover
a failed listing, a 1000-event storm, a panel reopening mid-lookup, and several
panels on the real bridge; the panel e2e now checks a burst arrives in order.
(STA-13319)