* Nest chat-UI orchestration workers under the agent that started them
Main's lineage projection only walked terminal panes, so workers running
in the chat UI never got a parent link and listed flat in the sidebar.
It now also projects chat workers, keyed by their visible chat row, and
resolves a chat creator or coordinator to that chat's visible row
instead of its handle or private mailbox pane key.
* Fix public worker lineage across assignment and row identities
* Complete terminal lineage provenance and bound active session selection
* Repair lineage test runtime boundaries and SQLite counters
* Provide read-only crew snapshots for each agent
* Batch public lineage verification after exact recency selection
* Derive crew relations once per meaningful host change
* Remove package manager lockfile churn from hook
* Use checked runtime values in lineage integration tests
* Document the trusted Dispatch SQL row boundary
* Keep lineage integration imports within their test programs
* Load native lineage fixtures before test execution
* test: complete lineage inputs in runtime and sidebar fixtures
* test: seed benchmark facts from active dispatches
* test: replace partial orchestration DB casts with typed fixtures
* test: complete stale-leaf mailbox fixture session input
* Derive durable crew parents from retained assignment proof
* fix(test): render worker lineage fixture with production list
* Add scoped terminal identity acquisition and preserve crew source wakes
* Share raw crew identity inputs through scoped production readers
* Exercise crew generation retirement through actual source owners
* Retire crew inputs on consumed ownership and visibility writes
* Use typed crew mutation and fixture access
* Repair crew fixture and RPC type contracts
* Align crew integration fixtures and RPC parameter contracts
* Encapsulate terminal identity mutations and captured reader contracts
* Seed terminal identity fixtures through canonical mutations
* Fix terminal identity fixture return type
* Cover terminal identity lifecycle schedules
* Align terminal fixtures with canonical identity sources
* Repair runtime fixture source contracts
* Use checked database fixtures for federation contracts
* Update crew source inventories and exit fixtures
* Preserve crew setup outcomes at existing subscription owners
* Match managed restore fixture to its nullable async return type
* Keep absent setup observations distinct from undefined failures
* Drive pending Crew questions from existing metadata
* Preserve nested pairing repair outcomes for shared callers
* Route attached workers to explicit local recipients
* Type Crew pending-question measurement receipts
* Match SSH repair fixture target absence to store contract
* Bound cold terminal layout construction and finite pane acquisition
* test: use public runtime identity in pane acquisition fixture
* Avoid repeated searches in cold workspace layout loading
* Verify cold loader fault identity and hook claimant effects
* Revert "Route attached workers to explicit local recipients"
This reverts commit f1335d1c06.
Keep attached workers on the existing Run-home routing path for this change.
* Omit crew peer addresses outside the active home route
* Keep crew retries on the verified runtime session
* Bound cold layout retirement and recorded-key construction
* Verify original cold layout failure identity
* fix: preserve surviving layout split references
* test: use typed retirement instrumentation properties
* test: preserve pane and retirement fixture contracts with checked types
* Prepare Crew record admission and wake identity changes
* Derive Crew recipient actions from current target owners
* Keep nested Crew process facts within selected acquisition
* Defer Crew legacy facts to consumers and complete raw coverage on success
* Use deterministic time in Crew command fixtures
* Document schema-owned Dispatch row assertions
* test: align Crew authority fixtures with typed project boundaries
* test: place Crew CLI integration in cross-surface project
* Type retained identity test meters with canonical source maps
* Document suffix Dispatch row boundary and preserve fixture unbinding
* test: migrate Crew authority arguments and mailbox observations
* Derive Crew attention and actions from complete recipient authority
* Fix Crew public-command fixture type contracts
* Align Crew fixtures with runtime reader and routing contracts
* Narrow receiving fixture calls to unary RPC methods
* Age pending question fixtures from every actual answer timestamp
* Complete Crew public-command workspace fixture result
* Test delegated helper follow-up through Crew advertised address
* Qualify Crew follow-up addresses through shared command admission
* Complete finite follow-up authority and lifetime evidence
* Assert exact remote authority acquisition error identity
* Consolidate Crew SQL test fixture imports
* Trim Crew read-model tests to the high-impact set
Keep the real CLI/RPC/database command paths, one regression per review-found bug, the cross-version contracts and one N vs 10N operation contract per scaling piece. Drop permutation matrices, equivalence oracles, near-duplicate scenarios and diagnostic output, and return the SSH, managed-server and WSL test files to main, since their production changes were reverted earlier in this PR.
* Drop diagnostic output and a duplicate error case from Crew tests
Remove two leftover console.log diagnostics, an unused 2x2 sample matrix and unused return fields in the follow-up cost contract, and the subscription AbortError serialization case that the subscription identity and preload tests already cover.
* Pass the recorded-leaf reader in main's check-details loader test
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.
* 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
* 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>
* plugins: components catalog 2 (forms, tabs, table, tree, markdown, code, images)
Adds 18 components to TSX components panels, drawn with Orca's own
primitives and gated by ui.catalog 2 / ui.has() (Orca 1.4.247):
Textarea, Checkbox, RadioGroup, Slider, Field, Tabs/Tab, Collapsible,
Toolbar, Grid, a virtualized Table with sort, selection and pull-based
paging, a keyboard Tree with lazy children, Markdown (sanitized, links
through the checked open path), CodeView (Orca's highlighter), Image
(header-checked plugin files read by main), KeyValue, Callout and
Skeleton, plus a tooltip prop on Button and IconButton.
Value controls share the edit protocol; handlers get plain JSON event
args, including small objects ({ keys }, { key, expanded }). The test kit
gains matching actions and hides unselected tabs and closed collapsibles;
a components-gallery example and e2e cover the catalog end to end.
* plugins: worker test harness, host refusals in tests and check
- orca/testing gains mountWorker(main, { host, events, commands }): it calls
the default-exported activate(orca) with the orca object Orca itself builds
(createPluginWorkerOrcaApi, moved to shared so the kit reuses it), backed by
mockHost. emit() checks payloads against Orca's event schemas and only
delivers subscribed events; command(), request() (the worker's
orca.panels.handle, as a panel's plugin.request), posts, logs, refusals and
deactivate(). Storage and settings share the mock host's in-memory store.
- orca plugin test loads a worker main's module graph as Orca's worker host
does (.ts/.mts transform, Node resolution, no runtime orca import).
- mockHost records refusals (capability_denied, not_permitted, ...) even
when plugin code catches them; panel.refusals exposes them and
orca plugin check reports them as warnings. Check dedupes repeated issues.
- Typings, docs and a generated references/testing.md skill reference; the
reference generator reads the split orca typings.
* feat(plugins): orca plugin open and shot; dev watch --shot
- orca plugin open <key> [--panel|--editor] shows a panel in the right sidebar or a file in the
plugin's custom editor, by changing renderer state only (no focus or window raise).
- orca plugin shot <key> [--panel] [--theme] [--width] [--out] [--json] waits for the panel's
current code to draw, then crops webContents.capturePage to the panel (html guests included),
with background throttling off while hidden. --width and --theme are temporary in-memory
overrides; the PNG returns base64 (5 MiB cap), so --environment works.
- dev watch --shot <dir> writes a PNG per panel after the load and each good reload.
- The authoring skill's loop is now dev watch --check --shot → read the PNG → plugin test.
* fix(plugins): shots never disturb a visible Orca
- shot --theme is skipped while the Orca window is on screen (themeApplied: false with a
themeReason); the override applies only to a hidden or minimized window.
- dev watch --shot opens the first panel (or --shot-panel <id>) once, then shoots it with
ifShown: if the user moved the sidebar away it emits one shot_skipped instead of switching.
* fix(plugins): dev loop dogfood fixes; orca plugin dev emit
- dev watch: approval re-run command drops watch-only flags and old --approve; a folder added
by a refused load is owned by the next approved load (Ctrl-C unloads it); check events
carry the plugin's status (no green while pending/errored); reloaded prints before that
reload's logs; --json errors are one NDJSON line.
- Errors: log, banner and check share source-mapped positions (a line-1 prelude hands sucrase
mappings to the components runtime); check dedupes issues and locates syntax errors;
Orca runtime frames and the error module's bogus location are dropped from logs.
- .orca/types tsconfig sets preserveSymlinks (tsc 7 loaded typings twice under /tmp).
- Templates' READMEs use dev watch.
- orca plugin dev emit <dir|key> <event> [--data] sends a test event to a dev plugin's worker
through the real delivery rules (plugins.devEmit).
* test(plugins): fixed timestamp in the dev emit test
* fix(plugins): shot captures an html panel's guest itself
On Linux the main window's capturePage leaves a <webview> guest blank. The renderer now reports
the guest's rect, and main captures the guest's own webContents and draws it over the window
capture at that rect (raw bitmaps, nativeImage only). Components panels are drawn by the host,
so the window capture alone stays right for them.
* refactor(plugins): keep plugin-service and main-process-plugins under max-lines
After rebasing onto #37013 both files crossed 300 lines. The guest log sink moves into the
desktop view binding (bindPluginDesktopViews), and plugin-service tightens emitEvent and its
event-delivery imports.
* feat(plugins): panels talk to their own worker, read storage, settings and events
- plugin.request (host API 1.2): a panel or editor asks its plugin's worker, which answers with
orca.panels.handle(name); the worker pushes with orca.panels.post. Same plugin only, JSON
checked, 1 MiB answers, 256 KiB/200-per-10s posts, a deadline and the panel's lifetime.
- Panels and editors get storage.*, settings.* and secrets.* behind the same capabilities, and
storage/settings onDidChange on every surface; events.subscribe delivers workspace and agent
events to panels that hold the read capability.
- contributes.settings: typed settings (a JSON Schema subset) with defaults and value checks.
- Frames get orca.plugin/storage/settings/secrets; components panels import plugin, storage,
settings, secrets from 'orca', and atom(key, init, { persist: 'storage' }) shares a value with
the worker. Workers get orca.panels/storage/settings/secrets sugar.
- One typed contract: declare module 'orca' { interface PluginRequests / PluginPanelEvents }.
- Desktop push channel per open panel session (plugins:openPanelPush).
* feat(plugins): Orca Settings shows and edits a plugin's contributes.settings
The plugin page lists declared settings with Orca's own controls (switch, picker, text and
number fields, Reset to default). Edits are checked against the declaration in main, written to
the plugin's settings, and reach open panels and the running worker through onDidChange.
* docs(plugins): hello-tsx talks to its worker; authoring guide covers panels, workers and data
The example now uses one of each: plugin.request answered by orca.panels.handle, a worker post
heard with plugin.on, a persist: 'storage' atom the worker watches, two contributes.settings and
agent.status.changed in the panel, all typed by one src/protocol.ts. The build-less TSX e2e
drives the whole loop.
* fix(plugins): typed bridge overloads, panel call budget, settings IPC and catalog keys
- PluginBridgeApi/PanelsApi use overloads: declared names are typed (and complete), any other
name carries JSON; no never-unions for the type-aware lint.
- The per-plugin panel call budget is 120 per 10 s, since a panel loading storage atoms,
settings and its first requests makes a burst; the hostile fixture floods past it.
- Settings IPC builds its host per call; the settings section's strings are in en.json.
* test(plugins): the example's declared settings show under the plugin with the person's value
* refactor(plugins): keep hello-tsx the minimal starter; the bridge demo is hello-worker-panel
hello-tsx goes back to a sandboxed-ui panel with no worker or capabilities. The worker, protocol,
storage atom, settings and events move to examples/plugins/hello-worker-panel, with their own
e2e (plugin-worker-panel) and PR route.
* feat(plugins): test kit covers the panel bridge and plugin data
mockHost keeps the plugin's storage, settings and secrets in memory (seeded with storage,
settings, secrets; read with host.data()) and fakes the worker with requests, so plugin.request,
storage/settings/secrets and persist: 'storage' atoms work under mount(), writes reach
onDidChange, and panel.post(event, payload) is what plugin.on hears. Typed by PluginRequests and
PluginPanelEvents.
* test(plugins): focusInGuest waits for the guest and retries focusing as one step
Under load the custom-editor guest could still be attaching, so executeJavaScript threw
'dom-ready' before the focus poll began. Wait for waitForGuestReady, then retry focusing the
webview and the element together, tolerating a guest that is still attaching or remounts.
* docs(plugins): the authoring skill covers panels, workers and data; persistence leaves the renderer
- skill-guides/orca-plugin-authoring.md gains Panels, workers and data (plugin.request/on,
orca.panels.handle/post, persist: 'storage', contributes.settings, panel events, test kit), and
its generated references read orca-services.d.ts for shell, files, on and the bridge types.
- After the dev-loop rebase, persisted-atom wiring (queue plus storage sync) moves to
createDeclarativePersistence so the renderer stays under max-lines.
* feat(plugins): panels show agents: agents.list, terminal ids on agent events, workspace.changed
- agents.list (agent:read, every surface): the focused workspace's agents with terminalId,
title, agent kind, state and stateStartedAt, from the hook server's store.
- agent.status.changed carries terminalId and title: paneKey mapped through the runtime's
terminal list (tabId:leafId) or the status's terminal handle; looked up only while a plugin
listens, in arrival order.
- workspace.readContext terminals carry title; workspace.changed (workspace:read) fires after
workspace session writes when the focused workspace or its terminals change.
- Event subscriptions are kept per panel session, so one made before the push channel opens
still counts.
- shell.openExternal never prompts on a hidden or minimized window: it settles
{ opened: false, reason: 'consent-unavailable' } and says so in the plugin log, which also
notes 'waiting for the person to confirm' while a prompt is up; the rate budget is spent only
when Orca acts. e2e launches never open a real browser or mail client.
- A worker may export activate as default or by name; docs, typings and the authoring skill
document the entry, the agent events and a live agent status recipe.
* fix(plugins): the plugin page names the workspace.changed subscription
* fix(plugins): workers activate only by default export, and say so when it is named
Orca calls the worker module's default export. A module with a named `activate` and no default
now fails to start with an error naming the fix (`export default function activate(orca)`),
instead of being called by a fallback; docs, typings and the skill say default export.
hello-worker-panel gains a picker setting (suggestionOrder) the worker reads.
* feat(plugins): build-less TypeScript workers
A worker's main may be .ts/.mts. The plugin host installs module.registerHooks scoped to the
plugin folder: .ts files are transpiled with the frames' sucrase options (lines kept, inline
source map, source maps on), relative imports fall back to the frames' candidate files, and a
value import of the type-only 'orca/worker' fails with a clear error. Needs engines.orca
>=1.4.246.
* feat(plugins): components panels hot reload with their state
- In dev folders a save swaps only the hidden guest: keyed memory atoms are handed to the new
guest (ui.retain → ui.hydrate memory), dropped when an atom's version changes.
- A save that fails to load keeps the last good render and shows an inline file:line:col
error banner; the next good save clears it. A subtle Reloaded mark follows a reload.
- Transpile and import errors carry line and column; dev worker restarts keep storage.
* feat(plugins): orca plugin dev watch
One command for the inner loop: refreshes .orca/types, dev-loads the folder, follows its frame
and worker logs (plugins.getLogs gains an optional cursor), prints reloads (optional
devChangeCount on list entries) and status changes, and unloads on Ctrl-C. --json streams
NDJSON events for agents.
* feat(skills): orca-plugin-authoring bundled skill guide
A guide for agents to build Orca plugins end to end (decision table, build-less rules, the
dev watch loop, test/check, validate, release-entry, approvals, gotchas) with references
generated from the component catalog, host API table, event schemas, manifest schema and CLI
specs, checked for drift. Fixes the components template's Reset to set(count, 0).
* feat(plugins): orca plugin dev watch --check; test kit details in the authoring skill
- --check runs orca plugin check after the load and after each reload (one at a time; saves
made meanwhile fold into one rerun) and prints each panel's render or errors inline, as a
`check` event with --json. Local folders only, since it runs the plugin's code here.
- The orca-plugin-authoring guide's Test and check section now documents orca plugin test and
check from #36969 exactly (JSON results, exit codes, test placement, the orca/testing kit and
its common mistakes), and the loop uses dev watch --check.
* refactor(plugins): move the components renderer's timing and helper constants to their own module
* feat(window): working background opacity and blur on macOS, Windows and Linux
One window material model (opaque / translucent / blurred): macOS vibrancy without transparent, Windows 11 22H2+ acrylic, Linux transparent windows. Terminals paint their translucent background once, the transparent WebGL frame clears before drawing (#6491), and Reduce Visual Effects drops modal/backdrop blur and honors prefers-reduced-transparency.
* perf(window): drop hidden macOS vibrancy while a theme image covers the window
* refactor(settings): move Reduce Visual Effects into its own setting and search files
A switch over runtime RPC (the phone's Accounts screen) changed the
selection but never reached the window's running-session handling, which
only the status bar and Settings called after their own IPC switch. The
RPC path now reports the lane and outgoing/incoming account to the main
window, which runs the same handler. The web client handles its own
switches and opts out.
* feat(skills): auto-update unedited Orca skills; ask only for edited copies
Planner already hashes each installed SKILL.md against every shipped release
digest (legacy installs included). When a plan's only writes replace such
hash-verified copies, the freshness nudge now applies it silently. Edited
copies and repairs still go through the consent toast; edited copies now raise
it too instead of only showing attention in settings.
* feat(skills): decide silent skill updates per skill and per location
Add skills.autoUpdateBundledOrca (capability-gated): the host plans the named
installed skills under their locks and applies only hash-verified released-copy
updates, re-checking each location before writing. The nudge auto-updates each
unedited skill and names only edited, unknown or repair-needing skills; the
try-once guard is keyed per skill and observed state, so one failure falls back
to the toast for that skill alone.
* fix(skills): surface preserved edits, share run ownership, re-show retracted nudges
- A silent update that moved a racing edit to a backup now shows a warning
naming the skill and backup path instead of passing as success.
- Silent updates run under skill-update-run-store's per-target ownership, so
manual and automatic runs never interleave and the dialog shows busy.
- Programmatic toast retraction releases its session marker; only a user
dismissal suppresses the nudge.
* fix(skills): report stranded edits, isolate silent runs, bound attempt memory
- An old copy whose late edits cannot be backed up now fails the op with
strandedPath naming where the edits remain; the silent caller warns with that
path, and the next plan's backup cleanup is nudged, never deleted.
- Silent runs never start over a running or unacknowledged foreground result
and never surface in the status bar.
- Auto-update attempts are keyed per target and pruned to the states the
current scan observes; unchanged states stay suppressed.
* fix(skills): warn when a silent update's result is lost
Any rejected or timed-out auto-update request may follow a committed swap
whose racing edit went to a backup. Show a persistent warning naming the
target and its skill backup directory, and settle the attempt so the same
state is handed to the nudge instead of retried.
* test(skills): guard version skippers; ledger also walks release tags
Audit of every v* tag and HEAD history found no SKILL.md bytes missing from
released-digests.json. The generator now also walks release tags (falling back
to HEAD) so a release cut off-branch can never ship unrecognized bytes. Add a
real-disk test that installs the oldest shipped orchestration (v1.3.24-rc.2) in
the npx-skills and agent-folder layouts and auto-updates it silently.
* test(skills): type the nudge mock's error without an assertion
* chore(i18n): add the silent skill update warnings to the English catalog
* fix(emulator): restore scrcpy control encoders and track the video size
Bring back the scrcpy v2.4 control-message encoders removed as unwired
in #13528 (touch, keycode, text), re-checked against control_msg.c and
the server's ControlMessageReader: generic-finger pointer id, the
official u16 pressure fixed point, and text split into <=300-byte
messages on code point boundaries.
The server drops touch events whose screen size differs from the
current video size. v2.4 reports the size once in its codec meta; after
a rotation the new size is only in the next SPS, so the session reads it
from every config packet. ScrcpyStreamSession.sendControl() returns,
the control socket disables Nagle, and the registry keeps the live
session's control target next to its video.
* fix(emulator): send Android input through the scrcpy control socket
Android pane input ran one `adb shell input` process per action (~150 ms
each on a USB phone) and replayed drags only on pointer-up as a fixed
300 ms straight swipe between the endpoints.
Pane pointer phases now go to main as they happen over a new
fire-and-forget `emulator:scrcpyTouch` IPC and are written to the live
session's scrcpy control socket, so drags and scrolls track the pointer.
CLI and agent tap, gesture, type and button use the same socket whenever
a stream is live; `adb shell input` remains the fallback without one.
Input routing and the `wm size` cache the fallback needs move into
AndroidDeviceInput. iOS is unchanged.
* test(emulator): keep the adb fallback test from leaking a failing sendControl
* docs(emulator): explain why pane touches have no per-phase adb fallback
* fix(emulator): keep iOS touch callback stable across interact changes
sendTouch depended on canInteract only for the scrcpy branch, but the new
dep also rebuilt it for iOS, so a canInteract flip mid-drag ran the frame's
cleanup, ended the live touch early and replayed the drag over RPC. The
frame already gates touch begins on canInteract.
* fix(emulator): narrow scrcpy touch payloads without a type assertion
The changed-code casting gate forbids `as`; use `in` narrowing like
the other IPC payload guards.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* fix(wsl): a restored chat or a web hooks check never starts a stopped distro (E9)
A chat pane mounting on launch restore or a remount read its transcript as a
user open and booted the transcript's stopped WSL distro. Only the mount that
the user's own switch caused, and paging, now ask main to start it; otherwise
the read refuses and the pane shows the distro's stopped copy at once (a
stopped UNC transcript was reported as missing and spun as pending).
A web client sent repo.hooksCheck without background, which a server treated
as a launch that may open the distro. The server now opens it only for an
explicit wakeWslDistro; clients send it for launches and keep background for
older servers.
* fix(native-chat): key a chat's open wake on its own workspace; update wake assertions
A chat in another workspace mounting inside the switch window no longer takes the
switch's wake. The paging and worktree-removal assertions now expect the explicit
wakeWslDistro flag.
* fix(native-chat): set the pane-key ref in the layout effect, not during render
* feat(wsl): a WSL hosts block learned mid-run stops new work at once
The live policy fetch caches a newly published block, but the gate is
fixed for the run, so the add-host and move entry points and the
in-context offer stayed until the next launch. A block the fetch learns
now stops new work in-session through one predicate,
wslHostsAcceptNewWork(): adding hosts, starting or previewing moves,
automatic and opened-project moves, and Retry. Main pushes the capability
to the renderer, which hides the offer and entry points. The gate and
what is served are unchanged until the next launch, so saved hosts and
moved projects keep working, and cancel, Restore and Not now stay.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): a live block also ends Stage 1 opt-in and stops mid-step host adds
Review follow-ups:
- wslHostsOptedIn now also needs wslHostsAcceptNewWork, and the Git router
re-applies its opt-in when a block lands, so the D1c router and the
background WSL Git gate uninstall at once, as turning the setting off does.
- D1c conversions (wslDriveProject preview/convert, wslDriveUnc:convert)
gate on the opt-in; the new-project Git default already did.
- The orchestrator re-checks before adding a host, so a step already past
its start gate adds nothing after a block.
- The window broadcast and capability push move to
wsl-host-window-broadcast.ts, keeping wsl-host-handlers.ts under max-lines.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl): keep gate mocks whole, and pin cancel after a live block
The visible-work lifetime suite mocked the gate with one export, so the
handlers' new wslHostsAcceptNewWork and onWslHostsNewWorkChanged calls
failed it; it now spreads the real module and overrides only what it
needs. A new case pins that cancelling a running move still works after
a live block while a new move is refused.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(github): start explicit Checks refreshes after the action
* fix(github): give explicit Checks refreshes fresh checks and comments
The same Refresh or Link click that now reads PR metadata after the
action also reads checks and comments after it: an explicit request no
longer joins or waits on a read begun before the click, in the renderer
or (for checks) the host coalescer. A superseded read's callers show the
owner's answer, so a late pre-click reply cannot repaint the panel, and
comments posted during either read are kept.
A lost IPC/RPC reply is reported only to the click that asked; polls stay
silent as before, and a later answer clears a failure older than itself.
The manual hook takes its verdict from its own lookup, the link flow's
card-read failure no longer skips checks, and the web shim forwards the
intent.
* fix(github): land the older Checks reply when a newer explicit read fails
When a click's checks or comments read fails while the read it replaced
succeeds, the click's read now lands that older reply through its owner
path instead of leaving the cache behind it. Post-write comments
refreshes (mutation events, bulk resolve) carry the explicit intent so
they cannot be answered by a read begun before the write.
* test(github): drop type assertions from the explicit-refresh tests
The RPC tests call the handlers with a real runtime service and spies,
and the panel test passes typed fixtures straight to the hooks.
* test(github): type the Checks panel fixtures for the renderer project
The renderer tests build their PR fixture locally instead of importing a
main-process harness, and the panel setter mocks take the hooks'
SetStateAction form.
* Make explicit hosted review refresh read current provider state
* Name the right provider and keep GitHub's own copy when a Checks refresh fails
A failed manual refresh now names the repo's provider (from the review, its link, or the remote), clears once a newer read lands for the panel, never stops GitHub checks and comments from refreshing, and gives way to GitHub's classified sign-in or rate-limit copy. The copy is one interpolated line in every locale.
* Read after the write when Orca merges, closes, reopens or edits a GitLab MR
Every GitLab merge request write now drops the host's cached review lookups for the repository, and the Checks panel's follow-up read can't join a poll that began before the write, so merging in Orca shows Merged and Delete Workspace without a manual Refresh. A user refresh also forgets Gitea's shared repository scan before reading.
* Clear a failed Checks refresh only on a real provider read
The host now tells the desktop store, when asked, whether its answer came
from a provider read it stored as current or from a cache or last-good
fallback. The Checks panel keeps a failed Refresh until such a read lands,
a click succeeds, or the context changes. On GitHub the PR read owns the
refresh status, so a failed review-card read no longer raises the generic
failure.
* Don't let a joined host lookup clear a failed Checks refresh
A poll that joins a lookup already running for an earlier request didn't
start that read, so its answer can't show the provider recovered after the
failure. Only the request that started the stored lookup reports a provider
read now. The host read also uses the shared reply outcome directly, and the
renderer writes the provider-read generation where it publishes the entry.
* Type the Checks refresh breadcrumb for every review provider
The breadcrumb already received Bitbucket, Azure DevOps and Gitea values; its
annotation now says so. Tests build typed fixtures instead of asserting types.
* Test the read-outcome reply at IPC, RPC and runtime, and the post-merge read
The flag reaches the runtime, and only a caller that asks gets the envelope,
including for a definitive null. After Orca merges, the card read starts after
the write, and its failure leaves the merge reported as done.
* Use a boolean for the empty-state fixture's remote-operation flag
* Trim redundant hosted-review refresh tests
* Keep the signed-out GitHub empty-state test
* test: remove low-value suites and cases
* test: shrink flaky-pattern counts after case removals
* test: remove empty suite and stale release workflow fixture
* feat(plugins): show public install counts in the plugin catalog
* fix(plugins): tolerate the empty stats placeholder; count bundled official plugins
* test(plugins): pin install-stats test clock
* fix(plugins): accept plain repo, release and tag page URLs in Git install
The Git URL install dialog refused anything without a #ref suffix, so pasting a
repository or GitHub release link failed with "Add a #tag or #commit". It now
reads owner/repo, repository URLs with or without .git, SSH URLs and GitHub /
GitLab release, tag, tree and commit pages, pins the newest version tag (or the
default branch's commit when there is none) with git ls-remote, shows that
version and commit, and installs only that exact commit.
* fix(plugins): let the Git install dialog close while a version check runs
* Chat UI leaves Experimental: each agent's Chat | CLI choice decides launches
Remove the experimentalNativeChat switch and every gate on it. The Chat
settings page, Default Agent Chat | CLI choice, + menu Chat/CLI rows,
source-control surface choice, Antigravity chat section and orchestration
chat-error switch are always present. What a new launch opens comes only
from the per-agent choice (no saved choice opens a chat) plus the existing
support checks.
- One lookup, nativeChatPreferenceFor, keyed by agent id so host-registered
agents read the same way; unreadable settings still open a terminal.
- A relayed desktop stamp (nativeChatDefault) maps onto the launched agent;
an explicit surface still wins. Old phones' createSupport keeps admitting
by the host's per-agent choice.
- settings.get stops publishing the retired switch keys; nothing in the
repo reads them from a host.
- Startup chat sync and hydration run when some agent can open as a chat
or the machine already holds chats.
- The retired key is stripped on load. The one-time upgrade tip from the
chat upgrade is retired with its audience record; a new record, captured
once from the raw profile, marks which existing profiles had Chat UI off.
- The window-side AI-button tab path, which only ran with the switch off,
is deleted.
* Keep profiles that had Chat UI off on the terminal
Existing users who never turned Chat UI on would otherwise see new agent
launches open as chats, since an agent without a saved choice now opens as
a chat. The one-time load step that records the new audience also sets
every known agent to CLI for those profiles, in the same save and only
when the record was absent, overwriting saved chat choices the old switch
masked. Profiles that had Chat UI on and new profiles are untouched.
Browser profiles keep their own settings, so the web client does the same
once: a stored switch that is not on seeds CLI choices, and dropping the
key marks the step done.
Agents first seen after this step open as chats.
* Agents without a saved Chat | CLI choice open as their CLI
An agent with no saved choice now opens in the terminal for everyone,
including fresh installs and agents first seen later. The one-time load
step carries what launches opened while Chat UI was experimental: with
the switch on, every known agent without a saved choice is saved as
chat; with it off, chat choices the switch masked are saved as CLI.
Existing profiles join the launch tip audience whether the switch was on
or off. Browser profiles get the same carry from their saved key.
The startup chat restore and host agent list now run only when some
agent is saved as chat or the runtime holds chats.
* Chat UI is here: a one-time tip for profiles that upgraded
Profiles saved before Chat UI left Experimental see a "Chat UI is here"
tip once, on the first launch after updating. Fresh installs, unreadable
audience records and the web client never see it.
- Had Chat UI off: says agents can now open as a chat and that the
terminal stays fully supported. "Use Chat UI" saves Chat for every
agent Orca knows (the roster the load step carries), then closes;
"Stay in terminal", close and Escape change nothing.
- Had Chat UI on: says Chat UI is now part of Orca and the terminal
stays supported; one "Got it" closes without changes.
- Both link to Settings -> Agents. The visual is an animated miniature
chat that sends a question, reads a file and draws a flow diagram,
then fades as one and repeats; reduced motion shows the finished
frame.
- The variant comes from main's once-decided audience record over a
new onboarding IPC read; the startup gate waits for it.
- FeatureTipActions takes a secondary label; the frame takes a copy
column class, used here so the buttons line up with the card's
composer. Other tips are unchanged.
- Telemetry: chat_ui_feature_tip_shown and chat_ui_feature_tip_action.
* Preserve owned terminal launches and local chat choices
* Chat UI tip: translate the miniature, honor reduced motion mid-loop
- The miniature's conversation (tab title, prompt, reply, diagram and
arrow labels) is translated in every locale; the composer, permission
chip, working row and Read verb reuse the chat's own strings. File
names, the /login route and the model name stay as written.
- The reply is one paragraph that wraps naturally; words (segmented per
locale, so scripts without spaces still stream) reveal in turn.
Diagram boxes size to their labels and arrow labels never widen the
row.
- Turning reduced motion on mid-loop jumps to the finished still with
no transitions.
- Telemetry records use_chat_ui only after the save succeeds and has a
distinct stay_in_terminal action.
- The dialog renders its own title, so the duplicate catalog copy is
gone; Use Chat UI writes the full roster without re-spreading saved
choices.
- Buttons: the primary's focus ring meets the card's bottom edge.
* Clarify chat and terminal support
* Explain worker CLI integration timeout budget
* Use checked annotations for chat graduation test fixtures
* Store agent surface default separately from per-agent overrides
* Preserve explicit Chat intent across default changes
* Preserve current browser settings during host replies
* Correct browser settings factory and regression types
* Name exported launch fixture mock types and clarify agent defaults
* Preserve settings fallbacks and complete launch test lifecycles
* Check allocated tab identity before launch fixture interpolation
* Drop file links from the Chat UI tip copy
* Register combined integration project for compiler parity probes
* Use checked settings in the launch test fixture
* Settings → Agents: "Open agents as" Chat or Terminal tiles
A new top section in Settings → Agents sets this computer's default for
how agents open: two tiles, Chat ("Rich messages, visuals and images.")
and Terminal ("Each agent's own CLI."), each with a still preview. The
chat preview reuses the tip's copy and flow diagram; the terminal preview
draws Claude Code's interface in the user's terminal theme and font.
- Picking a tile writes only agentDefaultSurface, through the same queue
as the per-agent Chat | CLI rows. The tiles show the saved default; an
agent set on its own row keeps its choice and is not reflected up top.
- If any agent's own choice differs from the new default, one toast names
them ("Claude and Codex stay in the terminal, as you set.") with "Set
all to Chat" / "Set all to Terminal", which drops those choices so they
follow the default. Only agents whose row offers Chat | CLI count. No
toast when nothing differs, and never from the tip.
- "Choose per agent" scrolls to and focuses the Installed list.
- Shown for this computer only (not on a paired host's page); the web
client gets it too. Searchable as "Open agents as".
- Copy in all locales; the tip's intro copy in other locales also drops
"file links", matching English.
* Fix Chat UI settings navigation and acknowledged preference actions
* Keep the agent default surface controls in full Settings
* Keep the per-agent navigation button free of link underlining
* Use checked types and existing presentation primitives for Chat UI tips
* Preserve retired Chat preference data privately
* Align chat E2E fixtures and capture pane lifecycle evidence
* Use typed raw settings in retention contracts
* Fix Chat UI settings search types and localization catalogs
* Consolidate transcript diagnostic imports
* Keep setup-only dependency changes out of the branch
* Update dev education history expectation for Chat UI tip
* test: align chat fixtures with live pane and native menu contracts
* test: capture relay tab selection loss diagnostics
* test: wait for owned shells before synthetic chat fixtures
* test: preserve all-host visibility in SSH observer
* test: bind synthetic transcript fixtures before provider seeding
* test: assert selected chat owner after narrow image preview
* ci: allow fifth compiler project to complete comparison
* Drop 'keeps getting better' from the Chat UI tip's terminal line
* Trim the empty space above the Chat UI tip's visual
* Tighten the space above the Chat UI tip's flow diagram; undo the card resize
* Tighten the Chat UI tip's reply and diagram spacing
* Give the tip's flow diagram a little more room and shorten its tab bar
* Type the web-terminal fixture's chat map without an assertion
* Right-click the selection itself in the chat copy spec
* Chat UI leaves Experimental: each agent's Chat | CLI choice decides launches
Remove the experimentalNativeChat switch and every gate on it. The Chat
settings page, Default Agent Chat | CLI choice, + menu Chat/CLI rows,
source-control surface choice, Antigravity chat section and orchestration
chat-error switch are always present. What a new launch opens comes only
from the per-agent choice (no saved choice opens a chat) plus the existing
support checks.
- One lookup, nativeChatPreferenceFor, keyed by agent id so host-registered
agents read the same way; unreadable settings still open a terminal.
- A relayed desktop stamp (nativeChatDefault) maps onto the launched agent;
an explicit surface still wins. Old phones' createSupport keeps admitting
by the host's per-agent choice.
- settings.get stops publishing the retired switch keys; nothing in the
repo reads them from a host.
- Startup chat sync and hydration run when some agent can open as a chat
or the machine already holds chats.
- The retired key is stripped on load. The one-time upgrade tip from the
chat upgrade is retired with its audience record; a new record, captured
once from the raw profile, marks which existing profiles had Chat UI off.
- The window-side AI-button tab path, which only ran with the switch off,
is deleted.
* Keep profiles that had Chat UI off on the terminal
Existing users who never turned Chat UI on would otherwise see new agent
launches open as chats, since an agent without a saved choice now opens as
a chat. The one-time load step that records the new audience also sets
every known agent to CLI for those profiles, in the same save and only
when the record was absent, overwriting saved chat choices the old switch
masked. Profiles that had Chat UI on and new profiles are untouched.
Browser profiles keep their own settings, so the web client does the same
once: a stored switch that is not on seeds CLI choices, and dropping the
key marks the step done.
Agents first seen after this step open as chats.
* Agents without a saved Chat | CLI choice open as their CLI
An agent with no saved choice now opens in the terminal for everyone,
including fresh installs and agents first seen later. The one-time load
step carries what launches opened while Chat UI was experimental: with
the switch on, every known agent without a saved choice is saved as
chat; with it off, chat choices the switch masked are saved as CLI.
Existing profiles join the launch tip audience whether the switch was on
or off. Browser profiles get the same carry from their saved key.
The startup chat restore and host agent list now run only when some
agent is saved as chat or the runtime holds chats.
* Preserve owned terminal launches and local chat choices
* Clarify chat and terminal support
* Explain worker CLI integration timeout budget
* Use checked annotations for chat graduation test fixtures
* Store agent surface default separately from per-agent overrides
* Preserve explicit Chat intent across default changes
* Preserve current browser settings during host replies
* Correct browser settings factory and regression types
* Name exported launch fixture mock types and clarify agent defaults
* Preserve settings fallbacks and complete launch test lifecycles
* Check allocated tab identity before launch fixture interpolation
* Register combined integration project for compiler parity probes
* Use checked settings in the launch test fixture
* Preserve retired Chat preference data privately
* Align chat E2E fixtures and capture pane lifecycle evidence
* Use typed raw settings in retention contracts
* Consolidate transcript diagnostic imports
* test: align chat fixtures with live pane and native menu contracts
* test: capture relay tab selection loss diagnostics
* test: wait for owned shells before synthetic chat fixtures
* test: preserve all-host visibility in SSH observer
* test: bind synthetic transcript fixtures before provider seeding
* test: assert selected chat owner after narrow image preview
* ci: allow fifth compiler project to complete comparison
* Type the web-terminal fixture's chat map without an assertion
* Right-click the selection itself in the chat copy spec
* plugins: tell once when an automatic update waits for review
When the auto-updater holds back an update because it asks for more access
or moved repository, show one toast per plugin version (grouped when several
wait). Review opens the existing per-plugin update review or the Updates list;
it never installs or approves. Told versions persist across restarts, kill-listed
plugins are skipped, and the copy is protected from language packs.
* test(plugins): wait on the update pass instead of sleeping in the review toast e2e
* feat(cli): open a browser tab in a split pane with `tab create --split`
`orca tab create` could only add a tab to an existing pane, so an agent
had no way to put a page beside its terminal. `--split <right|left|down|up>`
creates a new pane next to the calling terminal (ORCA_TAB_ID), falling back
to the active pane, and opens the page there without taking focus.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNtbMA9iVj9T4rBUjn5u6W
* refactor(browser): share one type for the tab-create IPC payload
The preload listener, its callback, the preload API contract and main's
sender each declared the payload separately, and the listener copy had
already drifted from the new split fields.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(browser): open the CLI split pane and its tab in one step
Creating an empty group and then filling it fails when main owns the
layout, because the window's group doesn't exist until main's frame
lands. createBrowserTab's split option carries both to whichever owner
draws them, so the rollback for a half-made pane goes away.
SSH hosts already cannot choose a new tab's group, so their CLI's split
is stripped like targetGroupId.
* fix(browser): split in the caller's workspace and refuse splits that can't happen
A CLI run outside its workspace's directory sends no workspace, so the
renderer fell back to the active one and missed the caller's terminal.
The caller's tab now picks the workspace when none was named.
An SSH host's split and an empty --split= both turned into a plain tab
reported as success; both are refused instead.
---------
Co-authored-by: Kalvin Mizzi <kalvin@mizzi.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(browser): let agents and users answer page alert, confirm and prompt dialogs on their page
* fix(browser): watch a replacement guest for dialogs and ignore the opening keypress
* fix(browser): ignore a repeated Enter in a guarded prompt field
* feat(source-control): resolve conflicts with one host operation shared by desktop and mobile
* feat(mobile): resolve merge conflicts and complete merges from Source Control
* test(mobile): pin Complete merge refusals and the older-desktop message
* fix(source-control): only resolve paths Git still reports as conflicted
* fix(source-control): refuse to keep a missing file and serialize conflict resolution per worktree
* fix(source-control): resolve only the exact conflicted path
* fix(source-control): match conflicted paths in Git's separator form on Windows and WSL
* fix(source-control): accept only the resolutions the live conflict offers
* fix(source-control): refuse to keep a both-modified file that is gone from disk
* feat(mobile): translate the merge conflict actions
* test(runtime): keep the mobile allowlist test under its line cap
* fix(mobile): let VoiceOver reach conflict action buttons
* feat: warn macOS 12 users about upcoming support changes
* fix: use explicit border tokens in macOS support notice
* fix: route compatibility guides through the app link setting
* fix: balance support notice columns in narrow windows
* test: include macOS notice in suppressed feature-tip history
* Simplify macOS 12 notice and isolate compatibility checks
* Clarify Apple compatibility wording in macOS notice
* fix(source-control): resolve delete/modify conflicts and complete merges from the panel
* fix(source-control): address review findings on conflict resolution
* fix(source-control): save every view of the file before marking a conflict resolved
* fix(source-control): match unsaved conflict views by physical file only
* test(source-control): prove completeMerge refuses with a commit template set
* refactor(source-control): reuse autosave view matching and refresh only after a completed merge
* fix(source-control): drop the untranslated Complete merge fallback text
* fix(source-control): refuse Keep file when the file is gone and re-read unsaved views on retry
* fix(source-control): let Keep file stage conflicted symlinks with missing targets
* fix(source-control): run one conflict resolution per file at a time
* fix(explorer): open folder links that lead outside the project again
#24489 replaced in-memory path grants with declared file access, and the
explorer started refusing folder links out of the project with a toast.
fs:readDir now accepts user-named access; the explorer retries a contained
listing that main refuses only as outside the project, and files listed
that way open by absolute path so their tabs keep access after restart.
* fix(explorer): let main verify outside folder links, and list them only on a gesture
Review follow-ups:
- New project-folder-link access kind, accepted only for fs:readDir: main
lists a folder only when the nearest project folder above it holds a
symlink on the path, so an unregistered root's child or an arbitrary
folder stays refused. user-file no longer lists folders.
- The explorer follows a link only on a user act or under a folder already
listed as outside; refreshes never upgrade a contained listing.
- A link target that fails to list (EPERM, ENOENT) shows its own error.
- Open Markdown Preview opens outside rows by absolute path too.
- New/Duplicate/Rename/Delete are disabled on rows listed through an
outside link, since writes stay inside projects.
* fix(explorer): keep keyboard edits off outside-link rows, and follow listed link rows on reveal
- Enter-to-rename and the delete binding skip rows listed through an outside
folder link, matching the disabled context-menu items.
- A folder the parent listing shows as a symlink may follow the link without
a click, so reveal and re-expansion after a workspace switch list it; a
folder that only became a link stays refused until clicked.
- Pass followProjectFolderLink only when set, so existing read-call
expectations hold.
* fix(explorer): limit folder-link listings to project roots; no rename on outside-row double-click
- Orca's floating folder is not a project, so a link there no longer
authorizes an outside listing (direct IPC callers included).
- Double-clicking an outside-link row's name pins the preview instead of
starting a rename main would refuse.
* fix(computer-use): replace the macOS permission status gate with one 5s launch floor (#34390)
Follows up #36028. The earlier gate grew background/explicit flags, epochs,
backoff and a setup pgrep path that reviewers could not make correct.
- Status: one probe at a time and one 5s launch floor shared by every reader, so
every path stays at <=12 helper launches/min. Readers inside the floor join the
running probe or ride one trailing probe that fires only if someone waits.
Only grants are cached (until the floor expires); denials and errors are never
served, so a grant shows within one floor locally and on web. No app epochs:
without a denial cache they bought nothing. Off macOS the gate is skipped.
- Setup: one launch per 5s across every permission, claimed synchronously; a
request inside the window is queued (latest wins) and reported as
launchQueued. Kill-and-relaunch stays so a click always re-shows the helper.
Setup reuses the gate's in-flight/cached/last result instead of probing.
- Reset checks helper availability from the bundle and invalidates after any
tccutil attempt, including partial failures.
- Remove the background flag from preload/IPC/renderer/web, the app-activity
binding, and the sidecar permission_denied invalidation.
* fix(computer-use): close the remaining gaps in the permission launch floor (#34390)
- Clear the trailing timer whenever any probe launches and re-check the floor
when it fires, so a late timer can never launch inside the floor.
- Setup reuses a denial only until the floor expires.
- A reader that joins a probe older than 300ms and gets a denial rides the next
probe, so a grant shows within about one floor even after a stale web/RPC probe.
- Setup requests are numbered on arrival, including ones that coalesce, so the
latest request wins (A, B, A launches A); a queued launch already covered by a
newer launch is dropped. Reset and will-quit cancel any queued launch.
- The settings pane says "Opening…" and the CLI says queued for queued launches.
* fix(computer-use): measure permission launch floors from real spawns and cancel setup on every host (#34390)
- Both 5s floors use performance.now, so a wall-clock step cannot stretch or skip them.
- The status floor counts from the later of claim and the actual `open` spawn, and
the setup window from after its spawn, so a slow mkdtemp or pkill can't allow a
13th spawn in a 60s window.
- Setup cancellation registers through AppEnvironment quit handlers (desktop,
headless Electron serve, orcad) and orcad's shutdown trigger; reset and
shutdown bump a generation so an Open still waiting on status never launches.
- Reset cancels queued setup before its first await.
- A setup request leaves the coalescing map when it launches, so a later request
for the same permission queues and wins (latest-wins across microtasks).
- A failed probe clears the remembered denial.
* fix(computer-use): drop setup coalescing and gate setup on a host-wide shutdown flag (#34390)
- Remove the per-permission setupInFlight map. Every Open goes through the 5s
window and seq-ordered queue; a queued request with the same args that arrived
before the last spawn was already shown by it, so concurrent same-permission
Opens still spawn once. This fixes stale entries after reset turning the next
Open into a no-op or a cancelled one.
- A cancelled Open (reset or shutdown) rejects with an error instead of returning
launchedHelper: false, which every client rendered as "setup complete".
- Replace the per-host cancel calls with src/main/host-shutdown-state.ts, set
synchronously by Electron will-quit and orcad's shutdown admission; setup
checks it before every spawn, including the queued timer.
- Track the status cache's expiry from the probe that produced it, so starting a
new probe cannot revive an expired grant.
- The queued setup timer re-checks its deadline and re-arms when early, and both
timers round delays up; a throwing spawn there is logged, not uncaught.
* fix(computer-use): keep setup latest-wins after slow probes and surface cancelled setups (#34390)
- Record the launching request's seq; an older request that resumes or is queued
after a newer one spawned is dropped, so latest-wins holds when requests
resume out of order behind a probe.
- orcad sets the host shutdown flag on every cleanup entry, including failed
startup.
- The web facade only falls back for hosts without computer.permissions; other
failures, such as a cancelled Open, reject so the pane and onboarding show them.
- The cancellation check runs before an untargeted Open can report everything granted.
- Opens that arrive mid-reset wait for it, so reset's helper cleanup cannot kill
what they open.
- Queued wording now says a newer request or a reset may replace it.
* fix(computer-use): wait out a reset before an Open reads permission status (#34390)
* feat(telemetry): report plugin installs and removals from Orca's public catalogs
* refactor(plugins): move marketplace install origin out of the installer
* Keep a sleeping conversation resumable when the terminal limit is reached
Resuming a slept pane while the host terminal limit was reached could drop
the Resume screen and fall back to a plain spawn. Route capacity refusals back
into the deferred sleep state, retry through the main-owned resume, and keep
the original session and provider until space frees up. A later Sleep or
cancellation still wins.
* Retain sleeping pane retries after transient owner failures
* Verify sleeping pane retry lookup bounds at scale
* Correct sleeping pane retry test fixture types
* Use transport attach contract in terminal test fixture
* Construct complete terminal transport test fixture
* fix(computer-use): stop relaunching the macOS permission helper while Accessibility is denied (#34390)
Every computerUsePermissions:getStatus / computer.permissionsStatus call launched a
fresh helper via open -n that polls TCC for up to ~3.5s. Three always-mounted
setup-guide hooks re-read on every window focus, so a denied Accessibility state
produced batches of helper launches and continuous TCCAccessRequest traffic.
Gate status reads in main: coalesce concurrent reads, reuse granted results for 2s,
and back off denied/failed results 10s doubling to a 120s cap. Window focus lowers
the backoff to a 10s floor; openSetup/reset invalidate it.
* fix(computer-use): never serve stale macOS permission status after the user acts (#34390)
- Re-probe once per real return to Orca (blur then focus) instead of a 10s floor,
so grants and revocations made in System Settings show without another focus.
- computer.permissionsStatus accepts an optional fresh flag (web clients send it)
that bypasses the denied backoff; older hosts strip it, older clients omit it.
- A provider permission_denied reply invalidates the cached status.
- Invalidate again after a TCC reset; stale in-flight probes get one follow-up
probe instead of an overlapping helper.
- Failed checks are shared for 2s and retried, not backed off like a denial.
* fix(computer-use): gate macOS permission re-probes on app-level returns only (#34390)
- Track did-resign-active/did-become-active instead of BrowserWindow blur/focus,
so moving between Orca's own windows never re-launches the helper.
- If the renderer's focus read reaches main before did-become-active, treat it as
the return when a window is focused, so the first read after return is fresh.
- Passive badges (setup-guide progress, feature-wall status) opt into the denied
backoff with background: true; omitted flags (older clients, active setup
screens) keep near-live reads with 2s reuse. Replaces the unreleased fresh flag.
- Obsolete probes no longer record outcomes or advance the denied backoff.
* test(computer-use): drop casts from permission IPC wiring test
* fix(computer-use): keep remote permission reads near-live and count startup as away (#34390)
- Web clients never forward background: browser focus can't activate the host,
so remote setup surfaces get 2s reuse instead of a stale denial.
- Seed the departed state when binding app activity, so a grant made during a
slow startup is picked up on the first return.
- Drop the mock-only sidecar invalidation test; keep gate constants private.
* fix(computer-use): never serve a cached denial to foreground permission reads (#34390)
- Active screens, web clients and older clients only reuse a denial by joining
an in-flight probe; granted and error results keep the 2s reuse.
- Revert the unreleased RPC background option so remote reads stay foreground.
- Drop the IPC test half that exercised events production no longer listens to.
* feat(native-chat): preview cards for web links in chat
Hovering an http(s) link that isn't the repo's own PR or issue shows the
page's image, favicon, site name, title and description. The chat's host
fetches the page with no cookies, refusing private, loopback and
link-local addresses after DNS and on every redirect, and returns images
as data URLs. A Chat > Behavior setting turns web previews off.
* perf(native-chat): cap link preview caches at 20 MB each
Preview images are held as data URLs, so a count limit alone let the
renderer and main caches grow to hundreds of MB in a long session.
* fix(link-preview): keep a > inside quoted attribute values
Page tags ended at the first >, so content="Home > Docs" was cut short
and an og tag whose content came before its property was dropped.
* fix(native-chat): keep link preview caches within budget and keyed by host
A preview that finished after newer ones stopped eviction at itself, so
both caches could stay over their byte limit. The GitHub card's load key
also left out the host its repo lives on.
* fix(link-preview): decode the named entities page titles use
Only five named entities were decoded, so titles like
Docs – Guide showed the raw codes in preview cards.
* fix(browser): import a cookie file into a client-hosted browser under a remote runtime
A paired runtime refused every cookie-file import before the picker
opened, even when this desktop hosts the runtime's browser pages. The
file import now asks main, like the native-browser import does, and
imports into the page's route partition; it is still refused when the
pages are not hosted here.
Co-authored-by: Oliver Mee <102673257+oliver-mee@users.noreply.github.com>
* chore(browser): lower the focus-read baseline for the cookie import actions
---------
Co-authored-by: Oliver Mee <102673257+oliver-mee@users.noreply.github.com>