* Allow automation CLI setup choices for new workspaces
* Explain automation --setup refusals and read back the saved choice
Name why --setup is refused and what to pass, show the setup choice in
text output, document --setup in the CLI guide, fail when a host drops
the choice, and cover the app-open Terminal dispatch.
* Refuse automation --setup on hosts that can't keep it, and fence the edit's mode
Explicit --setup now needs the host's new setup-choice capability, checked
before any write; commands without --setup are unchanged. An edit whose
setup choice relies on the current new-per-run mode sends a mode
precondition the store checks against the saved record, so a concurrent
switch to an existing worktree refuses the whole edit. Text output shows
the saved choice or "not set", the existing-workspace refusal offers a
remedy that works for every input, and the after-write readback is gone.
* Make the too-old --setup message true for edit and cover a saved setup edit
Omitting --setup on edit keeps the saved choice, so the refusal now says
to run the command without --setup. A new test saves a --setup run edit
through the controller into the store and reads it back after reload.
The PR tab now leads with the PR's identity, one row per merge gate
(checks, unresolved threads, approvals, conflicts) that opens the screen or
sheet that resolves it, a changes card and a collapsed description. Close,
Unlink, Auto-merge, Edit title and Copy link move into the ⋯ menu.
Checks and Comments become pushed screens: failures open with their
annotation and Fix / Rerun / Open / Log on the failure, running checks
next, passed folded; comments filter by Unresolved / All / Hide bots with
Resolve and Reply on each thread and a comment box at the bottom.
Merge opens a sheet that lists only the methods the repo allows, starting
on its default. Reviewers move into a sheet with search to add and remove.
Every Create PR entry point opens one sheet: title and description seeded
from the branch's commits (shared seed rule in src/shared, GitHub's own
default), Write with AI, base picker and draft. It pushes first when
needed, works for all five providers and lands on the PR tab for GitHub.
* fix(wsl): the Codex quota poll gates the distro it probes, not the default
The poll's gate asked whether the wsl -l default was running, then the
home lookup resolved its own default (and could name an account home in
another distro), so the probe could start a stopped distro the gate never
read. The distro is now resolved once, gated, and pinned for the home
lookup; a home in any other distro skips the poll.
* fix(wsl): pin the gated distro for paths only; keep the account lane
Pinning the resolved default into the target also moved the account
lookup off the default lane, so a default-lane account read the system
home. The distro is now pinned for paths and probes only: the account is
that distro's lane, then the default lane the target named. The default
distro comes from resolveWslDefaultDistro, as the exec gate's does.
* fix(wsl): the pinned quota poll reads the account lane launch reads
Drop the default-lane fallback: a pin names the distro, so the account is
that distro's lane, exactly as launch reads its named target. The test now
asserts the poll and launch's own home lookup agree.
* fix(chat): move forward readers to the covered tip after a no-op save
A write whose fold changes nothing stores no outcome record, so its
sequence never appears in a forward read. Readers placed themselves at
the last returned row and stayed behind the live cursor, so open chats
re-read an empty page and recomputed the prompt projection on every
later delivery until the next real save.
Forward journal reads now report the highest sequence they covered.
History pages move there when the read was complete, prompt reuse and
native responses compare against it, and a read cut short by its limit,
byte budget or damage still stops at the last returned row.
* fix(chat): append unlimited outcome reads without spreading, and report coverage from the mobile journal fake
* fix(chat): skip the retention scan for batches that change no journal items
The pane's keyboard only sent serve-sim HID frames over the iOS WebSocket.
Android sessions have no serve-sim socket, so every key was dropped and every
paste failed with "device is not ready".
Android panes now send typed characters, paste and editing keys over a new
emulator:scrcpyKeyboard IPC beside emulator:scrcpyTouch, keyed by the streamed
serial. Main writes them straight to the live scrcpy control socket (text
injection, and keycodes with SHIFT_LEFT held for Shift), so keys keep their
order with touches. iOS keeps the HID path.
* feat(mobile): one next-step bar under both Source Control tabs
Changes and Pull request are the only segments. A bar at the foot of both
shows the branch's one next action: the commit box, push or pull, create
the review, resolve or fix with the workspace's agent, merge when ready,
merge, or why it can't. Commits opens as a pushed screen.
* fix(mobile): keep Merge reachable and show bar failures on both tabs
* test(mobile): expect the two Source Control segments in the page render test
* fix(emulator): detect Android devices with only adb installed
SDK discovery required both adb and the emulator binary under an SDK
root, so hosts with platform-tools only, or a standalone adb such as a
distro android-tools package, saw no Android devices at all. Discovery
now needs only adb, falls back to adb on PATH, and AVD listing and boot
are skipped when the emulator package is missing.
Fixes#32126
Co-authored-by: s546126 <268420947+s546126@users.noreply.github.com>
* test(emulator): drop type assertion in adb-only inventory test
---------
Co-authored-by: s546126 <268420947+s546126@users.noreply.github.com>
* Show a card in the chat when its agent hands work to another agent
An agent that hands work off with 'orca agent launch' from a native chat
now leaves a 'Handed off to agent' card there, linking to the new chat or
terminal, the way a supervised worker-start leaves 'Started worker'.
The CLI names its chat on agent launches (same-host only); the host records
a display-only agent-handoff item after a successful launch with a submitted
prompt, once per launch operation. Nothing about the card can refuse or delay
the launch.
Tracked in STA-13209.
* Keep orca commands working in a native chat that has no terminal handle
The launch-caller evidence read the host stamp off an absent evidence object, so every orca command from an ordinary native chat threw before sending. Adds CLI tests for which requests name the launching chat, restores the lockfile to the base, and fixes the Korean heading.
* Read a card's heading from its creation flags together
A caller passing only the started flag drew a handoff as Started worker; the heading now takes the message's flags as one argument.
* Show the handoff card for every agent a chat launches
A launch without a delivered task now records the card too, with no task text, as the common pattern records every agent a chat creates. The handoff tests now run the real chat host and journal: one card per launch operation, none on replay, a removed card stays removed across a restart, and the clock is fixed.
* Head a launch card Started agent when no task reached the new agent
Handed off to agent now appears only when the card carries a task; a card for an agent started with no task (no prompt, a draft, or a prompt that wasn't delivered) reads Started agent. The heading is derived from the card's text, so nothing new is saved. Also drops a self-launch check the launch path already refuses first.
* Show the handoff headings on the phone's agent cards
The phone card passed only the started flag, so with the new heading rules it would draw every creation card as a plain message. It now passes the message and has a heading for every case, so a missing one fails the build. The heading function now requires the message's creation facts, so no caller can leave them out. Adds the phone strings in every language, and the Japanese "Started agent" now uses the catalog's term for agent.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Route hosted review refreshes to their owning host
* Route remote review operations to their owning host
- Refresh the correct hosted review after remote git operations
- Scope comment mutations and AI acknowledgements to the owner cache
* Route legacy paired SSH reviews through their server owner
- Recover proxied runtime owners for older SSH worktree listings
- Preserve direct and ambiguous host routing safeguards
* Preserve review ownership across remote workspace operations
- Route checks, comments, and linked-review clears through the selected repository owner
- Reject ambiguous or mismatched host context to prevent cross-machine mutations
* Keep check detail tabs scoped to their remote owner
* Preserve remote worktree ownership across reconstructed check tabs
* Preserve direct SSH check tabs when proxy listings overlap
* Scope PR refresh ownership state and safely roll back comment mutations
- Preserve linked-review clear scopes beyond cache eviction and clean them up on expiry
- Handle failed or refused comment reactions and thread resolutions without stale optimistic UI
* Preserve remote review ownership when SSH copies overlap
* Fix review routing for overlapping remote repository hosts
- Preserve server-owned review refreshes when a direct SSH copy exists
- Fail comment mutations and refetches safely when ownership becomes invalid
- Resolve check and sidebar data through the workspace’s owning host
* Relax cache-sensitive test expectations
* Route check refreshes to runtime owners and isolate restored requests
* Scope reconstructed check detail tabs by execution owner
* Fix review refresh ownership for shared remote hosts
- Prefer explicit execution owners when matching worktrees.
- Avoid repeated tab scans when restoring check details.
* Fix hosted review polling for workspaces on multiple hosts
* test: trim redundant review ownership scenarios
* Preserve rich Markdown viewport through bare focus returns
* Retire viewport ownership on editor remount
* Complete no-op navigation and body Tab coverage
* Keep patch metadata keys separate from dependency snapshots
* Retire the viewport before root detach callbacks
* Give the engine writer fixture its native selection
* Keep native focus navigation current in Markdown
* fix: leave smooth Markdown scrolling to native focus cancellation
* Cover focus wrapper removal and routed Markdown writers
* Type the viewport scroll spy and mark the focus-recovery wait as deliberate
* Scope Markdown viewport wheel and touch guards to the editor scroller
Same-named simulators on different iOS runtimes looked identical, and records whose runtime is gone could be picked and then failed to connect. The pane already received runtime and isAvailable from simctl; the toolbar ignored both.
* fix(browser): open target=_blank links from streamed server pages as tabs
Headless serve pages have no renderer, so a page's new-tab request was
denied. The runtime now opens the link as a tab beside the page, in front
only for the paired client whose click or key press opened it.
* test: add the offscreen tab opener to browser manager fakes
* test(e2e): drive the blank-link check through the host client
* fix(browser): credit a link only to the client whose input opened it
A click waiting in the page's command queue keeps its client until it is
delivered, input with no paired client clears an older one, and an
unattributed link no longer moves the agent's tab.
* refactor(browser): credit link opens from the page's command queue
Record the paired client at the bridge's per-page command lease, which
sees the resolved page and every command kind, instead of in four RPC
handlers. A page without a workspace keeps denying new-tab links.
* fix(browser): credit a link to the client whose click reached the page
Credit at the guest's activating input, under the popup owner's tab, to
the command delivering it, so a watcher's scroll can't claim an agent's
link. Announce a background tab at once since bridge selection no
longer does.
* fix(browser): credit a phone's DOM-activated tap before it runs
A tap with a touch radius clicks the element through Runtime.evaluate,
which fires no guest input event, so credit the tapping client first.
* test(e2e): assert the blank-link tab through the page, not the store
* refactor(browser): simplify page-link credit and tab opening
The queue owns the page command credit instead of the agent lease, the
credit skips work while idle and shares the gesture's freshness rule,
one opener serves both link paths, and one opensPageLink marker replaces
the paired follows/leavesAgentTab flags.
* test(e2e): give the blank-link spec's timeout its reason
- shot <key|dir> --scenario <name> renders the panel in that check scenario through the check
runner (a separate Node process on a mock host and mounted worker), sends the validated drawn
tree to a new plugins.shotReplay, and captures it in a throwaway preview surface: no guest,
no live host, no real storage or settings, no real worker, images as placeholders. Window
hidden or minimized only; --act, --environment and bridged shells refused; an older host
answers method_not_found (runtime_unsupported) rather than doing a live shot.
- dev watch's shot event carries pendingRequests.
Reading an agent on the desktop rebuilt notification ids for turns that
never alerted (every chat pane, silenced workers) and forwarded each one
to the phone as a silent dismiss push plus a dismissal-store record.
Only forward a clear when the store holds a live delivery for that id.
* Add Dashboard terminal HTTP link actions
* Preserve Dashboard HTTP link targets and route refusals
* Await Dashboard link fixture operation completion
* Keep nested remote Dashboard links on system destinations
* Preserve preview link defaults and correct composition fixtures
* test: verify dashboard link resource ownership and composition
* fix: align preview link and fixture type contracts
* Complete preview callback types and popout copy feedback
* Keep popout terminal links on their existing default path
* Remove unsupported role query option from preview fixture
* fix: preview remote HTML outside registered workspaces
* fix(terminal): keep HTML from hosts without re-grantable files in the editor
* fix(doc-preview): check outside-workspace reads by host-canonical path and page large workspace assets
* fix(doc-preview): check approved folders for workspace assets of outside documents
* test(e2e): read the preview guest without a type assertion
* test(e2e): explain the outside-workspace preview timeout
* test(doc-preview): type the pinned grant target in the share test
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* fix(browser): stop the paired tunnel refusing a heavy page's connections
The client capped a tunnel at 32 streams and the server refused opens past
16 pending connects, so ja.aliexpress.com (77-105 concurrent connections)
lost requests with ERR_SOCKS_CONNECTION_FAILED. Size the stream cap to
Chromium's 256-socket pool on the client, server and SOCKS listener, drop
the pending cap the stream cap already bounds, and raise the open rate to
1024 per 10 s above the measured 302.
* fix(browser): fail only the stream that overflows the tunnel receive budget
More streams per tunnel make the shared 32 MB receive budget reachable, and
a denied claim closed the whole tunnel as if the server sent invalid data.
Fail just that stream, as the server session already does.
* fix(browser): release a failed stream's claims before reporting it, update tunnel gate text
* fix(browser): keep room in the tunnel memory budget for a failed stream's Error frame
Application claims now stop 64 KiB and 64 claims short of the host and
process caps, so the Error frame for a stream failed by a full receive
budget can still be queued instead of closing the whole tunnel.
Adds github.markPRDraft (gh pr ready --undo) on the host, allowlisted for
paired phones and advertised with mobile.github.markPRDraft.v1 so older
hosts simply hide the action.
* feat(plugins): dev watch asks for first-load approval in a terminal; acronym-aware names
- In an interactive terminal without --json, a first dev watch load that needs approval shows
the grants (as plugin inspect prints them) and asks Approve and load? [y/N]; yes reloads with
the host's fingerprint and keeps watching. --json and non-TTY runs keep the exit-3 flow.
- create keeps known acronyms uppercase when it derives a name from the id (pr-queue → PR Queue).
* fix(plugins): a declined dev watch approval prints only the re-run command
The person just read the grants in the prompt, so the exit-3 error no longer repeats them:
Not approved. To approve later, run: <command>.
* feat(plugins): shots wait for the worker; --act restores the panel; Table and Tree acts
- A shot settles once the panel has no plugin.request or host call in flight and no new tree for
a quiet spell (capped at 3 s), so a cold worker's skeleton is not captured; pendingRequests
reports what was still pending.
- After --act and the capture, the guest restores every plugin-written atom it had before (new
ui.snapshot/ui.restore; persisted atoms re-persist) and Orca remounts its drawn controls;
restored: true|false. Worker-side effects are not rolled back.
- --act gains the kit's slide, sort, selectRows, activateRow, loadMore, expand, collapse,
selectItem and activateItem.
- Docs: the dev watch first-load prompt; shot settle, restore and the new verbs.
* fix(plugins): a shot waits for the theme repaint and retries a bare capture
Linux CI captured a dark --theme shot as a bare background (2 colors). The renderer now waits
until the document shows the asked color scheme and paints, adds a frame after a --width
resize, and main recaptures a panel image that is still a background and a border (two colors
or fewer) up to 8 times, 150 ms apart, before returning it. Html panels keep their guest
composite.
* fix(plugins): capture the main window with stayHidden
webContents.capturePage(rect, { stayHidden: true }) keeps a hidden window rendering for the
capture, as the components gallery screenshots do. The repaint wait stays, and the bare-capture
retry stays as a fallback.
Every floating browser pane reported the 'owned-target' shortcut scope, and a
page only takes the keyboard on activation in the focused split, so the
keyboard stayed in the hidden main-area terminal. The overlay layer now marks
the floating pane in the focused split 'owned-target-focused': it still answers
only chords from its own overlay, and it takes focus like a focused split.
* Keep pending chat visible until the new worktree tab opens
* Cancel agent launches when their chat tab is refused
* Keep workspace sidebar mounted during chat creation handoff
* Preserve the first chat message when layout refuses the tab
* Make worktree creation handoff test timestamp deterministic
* Avoid assertion in pending chat test
* Add pending chat opening translation
On an orcad server whose browser is an external Chromium, fill, clear,
select, type and select-all went straight to agent-browser, which reports
success without checking the element. Run desktop's element functions on
the exact element behind the ref, reached through agent-browser's own
`get attr` call, and type with real key presses.
* plugins: check shows what drew; responsive Table columns; quieter Table and Stack
- orca plugin check: each scenario result carries a summary (headings,
callouts, empty states, table and tree sizes, the selected tab, loading
placeholders, danger/warning text), printed under its line, and --json
adds the drawn tree. dev watch's check event keeps only the summary.
orca/testing gains panel.summary().
- Table columns take minWidth (floor for an auto column) and hideBelow
('sm' 360px, 'md' 480px), measured on the table itself; at least one
column stays. Cut-off cells and headers show their text on hover. The
kit's columnsOf(table, { width }) answers which columns fit.
- The active-row ring shows only while the grid has keyboard focus.
- A Stack with no align keeps buttons at their own width while fields,
tables and cards still fill it; align='stretch' stretches everything.
- Typings, docs, the skill's workflow reference, regenerated references;
the gallery's Kind column drops out in a narrow sidebar.
* plugins: check can render one scenario and return its drawn tree
For orca plugin shot --scenario (tree replay): checkPluginPanels takes
{ panel, scenario, drawnTree }, and with drawnTree returns each render's
validated tree exactly as Orca draws it (handlers as { $callback }),
re-validated on the CLI side. An unknown scenario is reported as an issue.
readPluginCheckScenarioNames(dir, entry) lists a panel's scenarios by
loading its .check file without mounting anything.
* fix(native-chat): keep a Claude reply visible when a Stop hook sends Claude back
Claude writes a blocking Stop hook's reason as an injected user turn, which
both Claude decoders dropped. The settled-turn fold then took the post-hook
continuation as the turn's only answer and folded the real reply away.
Both decoders now turn that feedback into a 'Stop hook feedback' row, and
the fold keeps the prose before each such row as an answer too.
* fix(native-chat): keep the Stop hook row when catching up a Claude chat transcript
* refactor(native-chat): one row table for hook outcomes
* fix(native-chat): import journal types from their new home
* fix(native-chat): import moved translation and status-block modules from their new homes
A Claude Read of a PNG returns only base64; the path is on the call. A shared
rule turns each finished file-read of a raster image into an image-ref under
the tool run header on desktop and mobile. Mobile chat prose now draws
https, data and absolute-path markdown images inline, every image in a
paragraph, through the existing host image read.
A panel that loaded before Orca focused a workspace showed nothing until the next change, and a
subscription made before the panel's push channel opened was never told at all. Now each new
subscriber gets the current context first: the panel bridge replays it once the channel is
open (or right away), and a worker's events.on('workspace.changed') reads it through
workspace.readContext. Unit tests for both, and the agents e2e checks the first event arrives
with no change happening.
* feat(plugins): orca plugin dev request; --template worker-panel
- orca plugin dev request <dir|key> <name> [--data] [--panel] [--timeout-ms] calls a dev
plugin's orca.panels.handle handler through the real panel bridge (plugins.devRequest) and
prints the answer; handler errors become plugin_request_failed with the worker's code.
- orca plugin create --template worker-panel scaffolds a build-less trusted-worker plugin: a
components panel, src/worker.ts, a shared src/protocol.ts contract, and panel and worker tests
that pass under orca plugin test and type-check with tsc.
* feat(plugins): shot --act, shots in the plugin folder, quieter logs
- orca plugin shot --act '<json>' presses, types, selects and toggles in the live components
panel (the test kit's queries and acts, through Orca's own controls and onEvent) before the
capture, waiting for each to settle. Only that plugin's panel, only with Orca's window hidden
or minimized; html panels refused; acts are not user gestures. Results in actions[].
- shot run inside a plugin folder defaults to its .orca/shots, like dev watch --shot.
- dev watch prints identical [frame] lines once per reload with a count; logged stacks drop
<anonymous>/native frames; the floating workspace button hides during a capture.
- Skill: worker-panel template in the decision table, dev request, shot --act, and a gotcha
that a worker save drops its in-memory state.
- orca plugin check mounts the plugin's worker (main) on the same mock host
as each panel, so plugin.request reaches its orca.panels.handle handlers
as in Orca; a worker that fails to activate or deactivate is an issue
named after its file. In orca/testing, a worker mounted on a host answers
that host's panel requests unless `requests` stubs the name.
- Check scenarios: <entry>.check.ts (e.g. src/panel.check.ts) exports
defineCheck({ name: { ...mockHost options, persisted, theme, events } });
check renders the panel once per scenario and labels each result.
- RelativeTime (catalog 3, since 1.4.247) and { type: 'relative', at } Table
cells: Orca ticks them (each second under a minute, then less often), so
plugins never poll. Inline inside Text; test kit reads them as drawn.
- Typings, docs, skill guide, generated references; gallery shows it.