Commit Graph
14218 Commits
Author SHA1 Message Date
Brennan Benson 920fa6cdbc Restore Session History resume for symlinked workspaces (#35052)
* Fix Session History resume for symlinked workspaces

* Bound history alias derivation and cover resume consumers

* Reuse equal alias values across history publications

* fix(history): verify adopted source directory before commit

* fix: preserve UTF-8 paths in directory admission probe

* fix: bypass transcript preparation for non-adopted starts
2026-10-29 13:17:40 -07:00
Brennan Benson e08cb10cc6 Prevent resting chats from delaying native command menus (#35069)
* Scope native chat command discovery to menu demand

* Fix command discovery CI imports and test timing

* fix: recover demanded command menus after context retirement

* test: load command host fixture before mocked consumers

* test: retain eager cache reads across command expiry

* test: cover command recovery after pending deadline

* test: count demanded command renders and query isolation

* test: load mobile command host fixture during collection

* test: type command batch fields from subscribe events

* test: check command event arrays without assertion

* Fix command discovery fixture project boundaries

* Name command fixture mocks with public Vitest types

* Assert opening metadata on resumed session snapshots

* test: assert passive command population boundaries

* test: cover mobile command capability handoff

* test: correct capability proof scope adapters
2026-10-29 13:16:35 -07:00
Brennan Benson e69baa3499 fix(linear): stop writes when their caller lifetime ends (#35020)
* fix(linear): bound write preparation and mutation to one caller lifetime

* fix(linear): isolate cancellable preparation from shared reads

* test(linear): keep CLI lifetime coverage in its compiler project

* fix(linear): preserve comment change failure guidance

* test(linear): place CLI and runtime coverage with integration tests

* test(linear): reset CLI exit status across runtimes

* fix(linear): preserve truthful confirmation deadline causes

* test(linear): support renamed workspace selector in fixture

* test(linear): adapt relation lifetime fixture to client factory
2026-10-29 13:15:07 -07:00
Neil e32c794f7b fix: restore record lint and session fixture validation (#36065)
Compose the exact changes from PR36056 and PR36058 so lint and session fixture contracts pass together.
2026-10-29 13:10:16 -07:00
Brennan Benson 7321b066e8 Show messages between agents as cards with the other agent's status (#34824)
* Snapshot agent message relations and verify task display prefixes

* Show native chat agent messages in navigable cards

* Keep agent message cards derived from canonical input and sidebar state

* test: correct agent card contracts and cover raw queue editing

* test: repair agent card runtime and operation contracts

* fix: preserve queued image previews and typed test measurements

* fix: use checked worker fixture and owned sender button typography

* fix: complete agent card fixtures and native presentation

* test: preserve queued edit exports and current authorship

* test: use namespace type imports in queued edit fixture

* Preserve sender progress and consolidate card contracts

* Simplify sender and notice contract instrumentation

* Remove duplicate sender and notice measurement mirrors

* Use a template literal for the dispatch boundary fixture

* Correct sender and notice verification phase accounting

* Consolidate agent message tests around user contracts

* Restore folded agent message preview on focus exit

* Consolidate agent message regression coverage

* Consolidate agent message fixture data

* Fix display text test lint diagnostics

* Use conversation view type for mail test records

* Reuse active copy control in card workflow test
2026-10-29 13:09:50 -07:00
Jinjing cb21824bd9 Optimize hidden chat subscriptions and tab projections (#36047)
* perf(tab-bar): patch tab agent projections per changed tab instead of rescanning every layout

The shared TabBar agent projection rebuilt agent types and tab-wide chat
fallback safety from every terminal layout (~2.5k at the captured scale) and
every status row whenever either map's identity changed. Status pings that
keep each pane's agent type now reuse the cached projection, and layout edits
re-resolve only the added, replaced or removed tabs. Key reorders, agent-type
changes and added/removed status rows still take the full projection.

* perf(ai-vault): keep rank and owner-only updates from re-collecting every agent conversation

The AI Vault title subscription ran two full agent-conversation collections
(every terminal tab, retained, sleeping and live record) whenever any owner
input changed identity, including worktree rank/unread patches and unrelated
settings writes. Compare worktree rows through the existing owner-rows token
so rank-only patches skip the check, and reuse the conversation workspace set
while the agent/tab maps it reads are unchanged, so owner-only updates compare
only those workspaces' hosts. Real host moves still schedule a title rescan.

* perf(native-chat): project only changed sessions on structured status feed ticks

Each host status feed tick re-captured every structured chat member on that
host (hundreds at the captured scale), resolving each tab's owner about three
times plus companion pin checks, even though a status event names one
session. Members whose feed facts (summary, observation, failure, sleep and
launch directory) and tab are unchanged since their last consumed capture are
now skipped, and tab owners are cached until an owner input changes, with
worktree rows compared through the rank-insensitive owner-rows token.

An input is marked consumed only after projection returns normally, so a
throwing store commit still retries on the next emission. The bridge remains
the only writer of slept-at and launch-directory pins, so skipping unchanged
members does not drop a needed re-assertion.

* perf(native-chat): skip the per-render scroll-margin offset walk in hidden chats

The transcript window re-read its scroll margin through an offsetTop walk in
a dependency-free layout effect, so every render of every retained chat forced
a synchronous layout read, including display:none panes where the walk cannot
produce a margin. The read now runs only while the pane is visible; becoming
visible re-renders and measures, and mount/resize measurements are unchanged.

* perf(native-chat): stop rank and catalog writes from rerendering every mounted chat

useNativeChatImageRuntimeContext shallow-subscribed each chat root to
worktree rows, runtime environments, SSH state and other owner maps, then
resolved the context in render. A worktree rank patch or a host catalog
timestamp refresh replaced one of those maps and re-rendered the whole
NativeChatStructuredSession of every mounted chat, hidden ones included (57 of
57 probes per write in the subscription benchmark). The selector now resolves
the context itself and keeps the previous identity while the result is
shallow-equal, so chats re-render only when their route or path changes.

* Optimize hidden chat subscriptions and release closed tab state

* Share layout diffs across tab bar projections

* Strengthen tab agent projection fuzz coverage

- Use a stable PRNG that exercises the full operation space
- Assert tab, agent, layout, and operation coverage
2026-10-29 12:22:50 -07:00
Neil 64c0992d2f test(wsl): pin the stopped-distro hold for a non-WSL shell in a WSL UNC folder (#35969)
* test(wsl): pin the UNC-cwd hold for a non-WSL shell on the daemon path

* test(wsl): pin the UNC-cwd hold for a non-WSL shell on the local path
2026-10-29 12:22:24 -07:00
Neil d7a33e1b12 test: use Claude flag support helper for launcher prefixes (#36052) 2026-10-29 12:21:58 -07:00
Brennan Benson 91efcc4df0 Add a per-host running terminal limit setting (#31396)
* feat: configure the running terminal limit for each host

* fix: bound terminal policy saves through fresh confirmation

* Fix truncated zero-size system file reads

* Load actual filesystem fixtures once per test module

* Preserve slept terminal ownership through capacity retries

* Fix terminal limit CI quality checks

* Correct slept terminal resume test types

* Move the slept terminal Resume fix to its own pull request

The Resume correction fixes a bug that already exists at the default limit,
so it now lives in #35401 and this change only adds the terminal limit
setting.

* Keep terminal limits effective when saved settings cannot be read

* Require a numeric edit before repairing terminal limits

* Derive terminal default from startup host capacity

* Apply terminal policy reads when validated results settle

* Align terminal limit tests with static analysis gates

* Inject daemon startup errors at the publication boundary

* Format terminal capacity using the app language
2026-10-29 12:18:02 -07:00
Brennan Benson 6d76f5a77b Keep a sleeping conversation resumable when the terminal limit is reached (#35401)
* 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
2026-10-29 12:17:37 -07:00
Brennan Benson 98f5d13689 A kill that reached the agent ends it, so the next message after Stop goes through (#34653)
* fix(native-chat): a kill that reached the agent ends it, so the next message goes through

After Stop, tab close, idle rest or workspace sleep, Orca force-kills the
agent. It used to accept the old agent as gone only when it saw the exit
report within about a second; otherwise every later message re-ran the kill
and was refused with "Couldn't stop {agent} from before." A kill delivered to
the agent itself now ends it and releases the chat with kill-delivered
evidence; the refusal remains only when the kill could not reach the agent.

When writing the chat's journal fails and the following kill can't be
confirmed, recovery now records the close with its fault instead of silently
returning, so the turn no longer stays Working and later sends retry the stop.

Tracked in STA-12354 and STA-12355.

* Preserve provider kill evidence across cleanup retries

* Exercise ACP setup gate with real managed teardown

* fix: preserve Claude writer termination evidence through settlement

* test: consolidate termination evidence contracts

* fix: restore Pi connection exit listener contract

* test: load actual ACP teardown before timed cases

* fix: correct lifecycle contract typing and test boundaries

* test: make Claude piped fixture mock types portable

* test: expect supervised OpenCode probe teardown

* test: align remaining supervised teardown expectations

* fix: align Stop feedback with terminal writer evidence

* test: remove redundant mocked Codex continuation case

* fix: keep adapter declaration and Stop fixture checks portable

* test: keep Stop fixture clock unchanged

* test: read canonical provider handle when reopening Stop journal
2026-10-29 12:15:56 -07:00
Jinjing 21cb9ebb78 perf(terminal): send typed keys to the PTY before publishing activity; split echo latency phases (#36008)
* perf(diagnostics): split terminal echo latency into queueing, round-trip, parse and paint phases

The typing diagnostic started timing at its own capture handler and lumped the
PTY round trip, renderer output scheduling and xterm parse into one interval, so
a stalled renderer could not be told apart from a slow PTY or TUI. Exact samples
now also report trusted-event input queueing, onData to first output reaching
the output scheduler, scheduler queueing, and xterm parse, plus each sample's
overlap with long animation frames. The report shape only gains fields.

* test(bench): measure terminal echo phases under accumulated workspace-update pressure

Adds a typing bench scenario that types into one real PTY while the accumulated
store receives rank-only order publications (and optional status traffic), runs
the in-app phase diagnostic beside the PTY sidecar, and moves the shared bench
knobs and report writer into a module both specs use.

* perf(terminal): send a typed key to the PTY before publishing its activity stamp

xterm fires onUserInput before onData, and the first key after a pause wrote
lastTerminalInputAtByPaneKey synchronously there, so the key waited on every
store subscriber before it was sent. Publish the stamp in a microtask instead:
the same task still records it, after the key has been handed to the transport.
At 1,620 workspaces and 2,356 store listeners, input-to-dispatch for keys after
a pause fell from p50 1.2-1.5 ms to 0.5 ms.

* Improve typing latency diagnostic accuracy

* Flush queued long tasks in live typing latency reports
2026-10-29 12:11:08 -07:00
Brennan Benson f87d68b4a4 Chat runs launcher Commands like op run -- codex for every agent (#35592)
* Support launcher command prefixes for all chat agents

* Preserve launcher path arguments and copy routing checks

* Match Japanese command guidance to the Agent settings label

* test(pi): expect version probe termination barrier

* test(chat): expect current command refusal guidance

* fix(acp): refuse copy arguments before launch preparation
2026-10-29 11:59:03 -07:00
Jinjing a4e600a663 fix(git): recognize colored stale lease rejections (#36041) 2026-10-29 11:50:37 -07:00
Jinjing d12a4b1c5c perf(sidebar): skip closed-menu catalog work and batch remote order publications (#36002)
* perf(sidebar): keep closed workspace menus and host dialogs off catalog churn

Closed row context menus subscribed to the full worktree list, worktree map
and repo map, and ran the delete-lineage traversal whenever any worktree row
changed. At 1,618 workspaces every rank-only update re-rendered each mounted
menu and rebuilt the lineage projection per menu.

- Menus now select stable empties for the catalog while closed and gate the
  lineage/sleep/delete subtree calculation on menuOpen; opening re-renders
  with the live host-qualified rows.
- Per-host HostRemoveDialog no longer resolves SSH removal scope while
  closed, retaining the last open snapshot through the exit animation.

Measured in happy-dom with 40 mounted closed menus over 1,618 rows: nine
rank bursts went from ~52 ms and 360 lineage traversals to ~2.6 ms and 0.

* perf(worktrees): batch remote order publications across repos into one commit

Hosts publish one sortOrderOnly worktreesChanged event per changed repo, and
each fast-path patch was its own store commit, so a multi-project reorder
produced back-to-back global renders (nine ~95 ms tasks in the 10-28 trace).

Published order patches now join a fixed 32 ms window and apply in a single
patchWorktreeSortOrderBatch transaction (one worktreesByRepo copy, one
sortOrderEpoch bump). Each repo handler awaits its flush, so renames and
structural refreshes queued for the same repo still run after the patch.
At flush the connection fence and host-row presence are re-checked; stale
entries fall back to the existing refetch path. Same-id host twins keep the
existing host matching.

* perf(sidebar): skip catalog index builds for closed menus

Check menuOpen before calling the catalog getters so a closed menu never
rebuilds the shared repo/worktree indexes on catalog changes.

* Prevent stale host dialog subscriptions and sort-order patches

- Unmount dialog content after exit while preserving pending removal state
- Fence batched sort updates to the submitted repository listing

* Disable host removal while its dialog closes
2026-10-29 11:47:48 -07:00
Brennan Benson e6878905be fix(wsl-host): Start connects a stopped distro once and names it when it fails (#35438)
* fix(wsl-host): Start connects a stopped distro once and names it when it fails

Start called the WSL host's connect and then the generic explicit connect, which
routes to the same WSL host again, so one click deployed and supervised the
server twice; a failure toasted main's raw text (a probe's command line).
Start now makes only the explicit connect, which still refuses a host whose
Remove is pending, and a failure says "Couldn’t start <distro>" with where to
look.

* test(wsl-host): cover moved Start admission and default failure toast

* test(wsl-host): load actual registry outside test hooks

* style(wsl-host): format admission test import

* test(wsl-host): check pending removal fixture type
2026-10-29 11:46:41 -07:00
OrcaWinandOrcaWin b3e5b9a5e0 test: remove schema inventories and redundant capability checks (#36040)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 11:38:24 -07:00
Jinjing 6a160aa5c8 fix(editor): soften file reveal flash and skip new views (#36039) 2026-10-29 11:20:49 -07:00
Neil 46e897f87b refactor(jira): group search and fallback notice owners (#36036) 2026-10-29 11:14:35 -07:00
OrcaWinandOrcaWin 2e5610316a test: remove browser capability inventories and mock receipts (#36032)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 11:03:49 -07:00
Jinjing e182f1daa2 Preserve force-with-lease rejection details in push errors (#36027) 2026-10-29 10:59:55 -07:00
NeilandManan Chataut bc228ff5cb fix(native-chat): keep a huge unbroken paste from freezing the chat (#32355) (#36031)
* fix(native-chat): keep a huge unbroken paste from freezing the chat

A long run with no whitespace ("xxxx…", "0000…", "abab…") wrapped with
kerning makes Chromium reshape it at every line, quadratic in run length:
128 KiB stalls 2.4 s, 1 MiB 19 s, 5 MiB never finishes. ProseMirror forces
that layout on paste and on each keystroke, so the composer freezes in
every terminal-backed chat, including paired servers and WSL. A sent
message stalls the transcript the same way: its fold clips the text but
still lays it all out (128 KiB: 2.5 s).

Runs over 256 characters now render with font-kerning: none, so prose of
any length and Shift+Enter lines keep kerning:
- composer: inline decorations, updated only for the lines a transaction
  touches (a keystroke beside 8,000 decorated lines ~1 ms, not ~190 ms)
- user messages in the transcript and expanded queued cards: the whole
  text when it holds such a run

Text, drafts and what is sent are unchanged. After: 1 MiB single line
84 ms, 5 MiB 312 ms (keystroke 248 ms), 1 MiB of 4000-char lines 50 ms
(was 2.3 s), transcript 128 KiB 80 ms. Worst case left kerned, 256-char
runs: 1 MiB 242 ms, 5 MiB 1.2 s, like 1 MiB of short lines (291 ms).

Fixes #32355

Co-authored-by: Manan Chataut <mananchataut@gmail.com>

* fix(native-chat): keep kerning on long CJK and Thai paragraphs

These scripts have no spaces but Chromium can break between their
characters, so a long paragraph is not one unbreakable run. Count
ideographs, kana, Hangul and Thai as break opportunities so such text
keeps kerning.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>

* fix(native-chat): rescan only the edited run, and wait out IME compositions

Splitting one run inside a block of thousands replaced every decoration
in that block, and ProseMirror's removal is quadratic: 1,411 ms for one
space in a paragraph of 8,000 long runs. A change now rescans only from
the run edge before it to the run edge after it, and removes only the
decorations that overlap: ~1 ms for the same edit.

Decorations are only mapped while an IME composition is in progress, so
the composing text node is not re-rendered. The deferred range is
rescanned with the next non-composing change, or on compositionend when
none follows.

The keystroke-timing test is replaced by deterministic ones: unaffected
decorations are reused and the result equals a full scan; a composition
defers the rescan and compositionend runs it.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>

* fix(native-chat): never split a CJK code point, and treat NBSP as glue

A supplementary ideograph (U+20000-U+3FFFF) broke a run at its high
surrogate only, so the decoration began on the low surrogate and split
the pair across elements. Both the run scan and the leftward edge scan
now treat the pair as one break.

NBSP joins words for Chromium's line breaker (UAX #14 class GL), so an
NBSP-joined paste is one unbreakable run and must lose kerning; drop it
from the break set. No other non-breaking characters were in it.

Drop a composer test whose coverage the decoration reuse test already
has.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>

* fix(native-chat): classify surrogate pairs whole at a rescan's edge

Two lone-surrogate edge cases made the incremental rescan disagree with
a full scan:
- an edit completing a pair at the window start (a lone high surrogate,
  then a pasted low surrogate and run) began the decoration on the low
  surrogate; the window now widens past the whole pair
- a lone low surrogate after any break counted as a pair end, dropping
  it from the run; that now requires a preceding high surrogate

A seeded fuzz also found inclusive decoration edges mapping across a
joined block's boundary, where ProseMirror cannot remove them; the
decorations are no longer inclusive.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>

---------

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
2026-10-29 10:56:40 -07:00
Neil 53e80ef9d4 fix(computer-use): stop relaunching the macOS permission helper on every status read (#34390) (#36028)
* 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.
2026-10-29 10:55:44 -07:00
Neil 80a2041142 fix(browser): an SSH workspace browser reaches sites through the host's proxy (#36022)
An SSH workspace's browser reaches sites from the SSH host: the host's sshd
dials each destination over a direct-tcpip channel. sshd ignores the
host's HTTPS_PROXY/HTTP_PROXY/ALL_PROXY, so on a host whose only way out is
an HTTP proxy (a Docker sandbox, for example), every external site failed
with ERR_SOCKS_CONNECTION_FAILED while localhost pages loaded.

The SSH route now reads the proxy variables an exec session on the host
gets (the environment orcad runs with) when it opens, and picks the
upstream for each destination the same way a paired server's own tunnel
does: environment proxy with its NO_PROXY list, never for loopback. An
HTTP(S) proxy is reached over the SSH channel and asked to CONNECT; a
no-auth SOCKS5 proxy gets a SOCKS handshake. This works for both the ssh2
and system OpenSSH transports. The CONNECT and SOCKS clients now run over
any transport, so the server tunnel and the SSH route share them.

Fixes #35217
2026-10-29 10:51:24 -07:00
Kelvin Amoaba 47b324b3c8 fix(browser): preview HTML files over 512 KiB from paired hosts (#36021)
The host's files.readDocPreview sends a preview file in one RPC reply, capped at 512 KiB for text, so Open in Orca Browser failed for larger HTML on managed runtimes. Add files.readDocPreviewChunk, which runs the same grant authorization and size caps per range, and page through it after a file_too_large reply. Hosts without the method keep today's 413.
2026-10-29 17:44:54 +00:00
OrcaWinandOrcaWin f4d19ca710 test: remove capability inventories and projection receipts (#36018)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 10:39:21 -07:00
Kelvin AmoabaandHEOJUNFO d61b37cbca fix(browser): return orca tab list at once when the worktree has no saved browser tab (#36017)
* fix(browser): list no tabs at once when the worktree saves no browser tab

The tab-list wake asked the window to mount the worktree's saved tab and
waited 8 s for it to register, even when nothing was saved to mount.

Co-authored-by: HEOJUNFO <100739943+HEOJUNFO@users.noreply.github.com>

* test(browser): keep the saved-tab wake check to the cases only it guards

* test(browser): drop the window cast from the no-wake check

---------

Co-authored-by: HEOJUNFO <100739943+HEOJUNFO@users.noreply.github.com>
2026-10-29 17:39:00 +00:00
Brennan Benson d61c8b8bbd Leave Claude plan mode when the user approves a plan (#34549)
* Leave Claude plan mode when the user approves a plan

Approving a proposed plan left Claude in plan mode, so it could not carry the plan out. On an approved plan, while Claude reports plan mode, ask it to return to the chat's own approval mode. The request is written before the approval and never awaited, so its failure cannot hold or reject the approval.

Tracked in STA-6663.

* Use checked types for Claude plan approval mode

* Restore Claude plan approvals by protocol action and mode

* Normalize missing Claude plan approval mode before narrowing
2026-10-29 10:24:41 -07:00
5dd4b68616 fix(browser): Next.js Server Actions work through the *.orca.localhost worktree URL (#14562)
* fix(proxy): preserve worktree forwarded host

* fix(proxy): drop the unreachable no-Host branch and trim the forwarded-host test

The proxy only forwards requests whose Host matched a label, so Host is
always set here.

---------

Co-authored-by: Yeonguk Jeon <273242699+promptprobe@users.noreply.github.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 17:24:34 +00:00
641e4792b9 Startup shows chats as Interrupted or Done without reading their history (#32146)
* feat(agent-session-journal): save each chat's open root turn beside its epoch

A restart could only tell whether a chat was cut mid-turn by replaying its
whole journal. journal_sessions now keeps the open root turn
(open_turn_id, open_turn_since), set by the row that opens a turn and
cleared only by a finish the provider reported, in that row's own
transaction. A turn a quit, crash or Stop cut short stays open, which is
what the next launch reads as Interrupted.

Journal schema version 5 adds the two nullable columns with a forward
migration; a new epoch starts with no turn open.

* fix(native-chat): restore chat tabs at startup without replaying any history

Startup opened every chat in the saved tab index and replayed its whole
journal into the main process to learn its status. With hundreds of tabs
and gigabytes of history, Orca froze in GC on every launch.

Startup now lists each restored chat from its record and publishes its
row as Interrupted (a turn was open when its host stopped, or the last
quit's resume offer lists it) or Done, through the status stream and the
agent-status sink, reading only each chat's journal_sessions row and its
newest row's time. A chat's history is read when something opens it; that
open settles what the gone generation left running and publishes the
journal's own row over the restored one.

No other startup path replays chats: restart offers list from their
markers without opening chats, and orchestration mail opens the chats it
must read one at a time. Opened chats are capped at 24 resident folds;
opening one past the cap closes the least recently active folds that are
only a cache, with the idle sweep's own close test.

* Fix lazy chat restoration and cache ownership

* Restore saved chat work across runtime restarts

* Wait for committed structural progress in migration fixture

* Correct restored ownership and bounded journal recovery

* Preserve bounded work selection during legacy recovery

* Complete deferred restart status publication

* Fix restart recovery test fixtures

* Use legal legacy recovery fixtures

* Correct population delete observation

* Bound legacy journal replay in a readonly worker

* Repair legacy worker proof oracles

* Reduce legacy scratch key serialization cost

* Decode population meter namespaces with scratch UTF-16 encoding

* Consolidate structured session imports for CI

* Remove redundant casts and document checked type exceptions

* Correct compiler contracts and retain journal fixture invariants

* Fix checked test fixture contracts after compiler validation

* Name population fixture identity type in exported signature

* Preserve historical quit presentation after rewind

* Fix structured session retry and remote worker delivery

* Preserve settlement and restored status contracts

* Enable legacy chat readiness on standalone hosts

* Repair structured session static checks

* Verify retained submission identity across rewinds

* Show saved chat status without replaying history at startup

* Keep chats closed when startup status finishes loading

* Keep startup owner recovery independent of history loading

* Preserve intentional quit verdicts in saved chat status

* Use a checked host fixture in startup restoration tests

* Group saved startup roster publication and verify scoped status work

* Use checked array access in status cut counters

* Complete checked saved status fixture typing

* Declare portable roster counter contract

* Use current saved chat startup APIs in contracts

* Preserve complete chat tab authority across startup

* Repair checked startup restoration test consumers

* Keep authority fixture module mocks in test entries

* Consolidate authority test fixture imports

* Check restore fixture contracts and recorded queue recovery

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-10-29 10:20:52 -07:00
Neil 78ef844224 refactor(jira): group linked reads and source identity owners (#36013) 2026-10-29 10:18:17 -07:00
OrcaWinandOrcaWin def1565846 test: remove scalar settings suites and mocked status receipts (#36011)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 10:10:19 -07:00
Brennan Benson a214728b75 Reopening an old tool run no longer jumps to a stale scroll position (#35866)
* fix(native-chat): forget a run scroll when its disclosure is evicted

* Reset tool run scroll when opening after choice expiry
2026-10-29 10:07:27 -07:00
Brennan BensonandCodex QA b42fcd8a00 fix(runtime): retract Orca's own Codex ready title when the next turn starts (#35547)
* fix(runtime): retract Orca's own Codex ready title when the next turn starts

A Codex that paints no working title of its own (its activity title off) kept the
"Codex ready" frame Orca writes on its Stop hook for the whole next turn, so
tui-idle waits, mailbox delivery and the tab all read it as at rest. The working
hook now replaces Orca's own rest label with one working frame, as #29429 did
for agents whose profiles synthesize working titles.

Tracked in STA-12718.

* test: cover titleless turn wait and mailbox lifecycle

* test: type title recovery write spy

* test: isolate CLI lifecycle exit state across runtimes

---------

Co-authored-by: Codex QA <codex-qa@users.noreply.github.com>
2026-10-29 10:06:42 -07:00
Jinjing e41105b5fc fix(editor): suppress ambiguous Unicode highlights in Markdown (#36009) 2026-10-29 10:05:15 -07:00
Neil 525719789f perf(terminal): read the macOS process table in process instead of forking setuid ps (#35987)
* perf(terminal): read the macOS process table in process instead of forking setuid ps (#31783)

/bin/ps is setuid root, so every exec costs an uncached syspolicyd
assessment and an EDR inspection. The terminal host forked ~7-10 ps/lsof
per second with 4 agent panes, and each stale daemon multiplied that.

node-pty's patched pty.node now exports processTable (sysctl
KERN_PROC_ALL/KERN_PROCARGS2 on a worker thread), processCwd
(PROC_PIDVNODEPATHINFO) and processPath (proc_pidpath). runPsInProcess
renders the same ps column text for the invocations Orca issues, so the
existing parsers and callers are unchanged; anything it cannot reproduce,
non-macOS hosts, and builds without the exports keep running ps/lsof.

Measured with 4 anchored panes polled every 750 ms for 60 s: ~440
ps/lsof children before, 0 after.

* fix(daemon): roll the in-process macOS process table into a fresh v54 daemon (#31783)

* fix(terminal): bound, escape and complete the in-process macOS process table like ps (#31783)

Review follow-ups for the libproc reader:

- Timeouts: every caller passes its ps timeout; a read stalled behind a
  saturated libuv pool resolves timed out (code null, timedOut) at that
  budget, exactly as the killed ps would. Identical native reads share one
  worker, each caller racing its own deadline; past 8 distinct reads in
  flight callers run ps. execFile-shaped callers reject like a failed child.
- tty naming shares one slot with captureDarwinProcessTable's guard, so a
  draining naming pass sends both paths to ps instead of naming again.
- Commands: the addon renders argv with adv_cmds' getproclline and strnvis
  (VIS_TAB|VIS_NL|VIS_NOSLASH) under the caller's LC_CTYPE via a
  thread-scoped uselocale, so newlines print as \012 instead of splitting
  tokens; zombies print <defunct>.
- Other users' processes: unreadable argv is marked commandIncomplete. Only
  -p selections and processes on a terminal under the user's own readable
  process there (sudo in a pane) get a targeted `ps -p ... -o pid=,command=`,
  cached by (locale, pid, start time); root daemons and a pane's root login
  never spawn ps.
- -t selects with KERN_PROC_TTY after ps's addelem_tty path resolution, so
  per-terminal reads skip argv for every other process (~0.3 ms vs 4 ms ps).
- -p deduplicates; rows sort by terminal then pid as pscomp(); stat adds
  ps's < N X V L modifiers. The export is renamed readProcessTable so an
  older pty.node falls back to ps rather than misreading the new query.

* test(terminal): diff the real libproc addon against /bin/ps on macOS (#31783)

Spawns a pty holder whose argv carries a newline, tab, invalid UTF-8 and é,
then compares Orca's ps invocations column by column: pid/ppid/pgid/tpgid/
lstart/tdev/tty exactly, commands for the user's own processes, and stat
modulo running/idle (thread state needs setuid ps). Rows are compared only
when two in-process reads around the ps run agree, so churn cannot flake it.

* fix(terminal): never serve a native process table read begun before the request (#31783)

A timed-out read stayed shareable, so a later descendant capture could join
an earlier poll's abandoned worker and take its rows as fresh; a descendant
that exited meanwhile could have its reused pid SIGTERMed. The addon now
reports when its worker actually began reading (startedAtMs), and
runPsInProcess refuses a shared read that began before its own request and
reads again, so every consumer that signals from rows (descendant
teardown, foreground-group signalling, identity probes) only sees rows
scanned after its stamp. Regression: pty-descendant-termination-libproc.

Also from review:
- argv recovered with setuid ps is keyed by pid, start time to the
  microsecond, comm and executable path (exec changes the latter two) with
  a 10 min TTL and 512-entry bound.
- Recovery covers a sudo use_pty tree: the unreadable chain must start on
  the terminal of the user's own readable process, so the root shell and
  agent on sudo's own pty qualify while root daemons, GUI helpers and a
  pane's root login (own pty, under a terminal-less or tty-inheriting host)
  do not.
- Concurrent tty= readers wait out the single naming pass, and readers past
  the 8-read cap queue behind one, within their deadlines, instead of
  bursting /bin/ps at startup restore (24 panes polled at once: 0 ps).
- darwin-terminal-naming-slot.ts is now darwin-terminal-naming-single-flight.ts.

* test(terminal): require /bin/ps row order in the libproc parity test (#31783)

Parsers that take the first matching row depend on ps's terminal-then-pid
order, so compare the order of the rows both captures share, not just their
contents.

* test(terminal): pin libproc read start times instead of reading the wall clock (#31783)

* fix(terminal): match native process table reads to requests by sequence, not wall clock (#31783)

Freshness compared the worker's gettimeofday with Date.now(), so a clock
step back let an abandoned read's rows through (wrong-pid SIGTERM) and a
step forward could reject fresh reads until the deadline. Each read now
takes a JS-side sequence number when created and is submitted a microtask
later; a caller joins only a read not yet submitted or created after it
registered, so callers in one turn share a worker and nothing submitted
before a request serves it. The addon drops startedAtMs again. Deadlines,
timeouts and the argv cache use performance.now().

Callers past the 8-read cap wait on one slot notifier and each joined read
has one settle notifier; both unsubscribe on timeout, so a stalled pool
retains no per-caller reactions. If the pool is still at the cap when an
overflow caller's deadline passes, the reader is marked stalled for 30s
and callers run ps, as before this branch.

Recovered argv is trusted for 30s: exec can keep pid, start time, comm and
executable (node -> node with another script) and no cheap field shows it,
so a sudo pane costs one targeted ps per process per 30s.

* fix(terminal): keep ps fallbacks off a stuck terminal naming pass (#31783)

- captureDarwinProcessTable's canonical fallback, taken while the naming
  slot is busy, now runs /bin/ps directly instead of re-entering the
  in-process reader and waiting on that same slot (a held lstat timed out
  every strict capture without one subprocess fallback).
- In-process tty= readers wait out a short pass (startup restore) but hand
  a pass older than 500ms to ps, which names terminals out of process.
- The naming single flight keeps one settle notifier per pass; waiters sit
  in a Set and drop off on timeout, so timed-out callers leave no reactions
  on a stuck pass (was one per call). The notifier moves to
  deadline-settle-notifier.ts, shared with the native read scheduler.
- Once the native read breaker has tripped, a caller finding the cap still
  held after the cool-down returns to ps at once instead of waiting out its
  timeout.
- Descendant teardown and foreground-group signalling give the native read
  half their budget and fall back to a fresh ps on a native timeout, so a
  partly stalled pool cannot cost a kill.

* fix(terminal): give signalling ps fallbacks their full baseline timeout (#31783)

Splitting the budget in half shrank ps's window behind a stalled native
read: a 750ms ps lost descendant SIGTERMs and an 80ms foreground ps lost
group SIGWINCH. Descendant teardown and foreground-group signalling now try
the native reader for min(150ms, timeout/4) (inProcessSliceMs), then give
ps the whole original timeout; readProcessTableBeforeDeadline extends the
production reader's outer deadline by that slice, so ps succeeds exactly
when it did on main. The stale-read regression test now also asserts the
fresh rows' real descendant is signalled.

* fix(terminal): carry the in-process deadline allowance through every descendant reader (#31783)

readProcessTableBeforeDeadline granted the native slice only when the
reader was readProcessTable by identity, so the daemon shutdown sweep's
sharing wrapper kept a bare 250ms deadline: a stalled native read plus a
200ms ps missed it on every retry and descendants survived shutdown.
ProcessTableReader now declares deadlineAllowanceMs; the fresh reader sets
it (0 without the addon or with a stalled pool, so Linux and ps-only hosts
keep their exact deadlines), createProcessTableSnapshotReader and the
shutdown wrapper inherit it, and injected readers default to none. The
fresh reader moves to pty-descendant-fresh-table.ts. The real-ps parity
test gets a 30s per-case timeout, since whole-table /bin/ps runs slow
under suite load.

* chore(terminal): move the descendant reader's child_process baseline entry with it (#31783)

* test(terminal): pin the libproc test locale so lstart doesn't follow the runner's LANG (#31783)
2026-10-29 09:51:53 -07:00
Kelvin Amoaba 0c0814e872 fix(browser): keep the chosen default browser profile after a restart or update (#35991)
* fix(browser): keep the chosen default browser profile across restarts

The default profile pick lived only in the renderer browser slice, so every
launch rebuilt it as Default. Store it in GlobalSettings, next to the
profile scope setting, and read it through one resolver.

* test: seed default profile map without a new cast

* fix(browser): drop a saved default profile only once it is gone

Trust the saved pick when reading it and forget it on a delete or a full
listing without it, since partial catalogs and failed fetches prove
nothing. Load this desktop's profiles at startup even when Settings shows
a paired server, so local tabs resolve the saved pick's partition.

* test: drop the default-profile test that only guarded the removed mirror

* refactor(browser): share the profile delete step and simplify the startup local fetch

* fix(browser): load this desktop's profiles at startup without a focus read

* fix(browser): apply overlapping default profile writes in order
2026-10-29 16:49:01 +00:00
OrcaWinandOrcaWin 41bfe43ebb test: remove low-value wrapper and scalar store suites (#35906)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 09:40:20 -07:00
Kelvin Amoaba 92f9431416 fix(browser): give agent set device and viewport --mobile touch input and pointer: coarse (#35982)
* fix(browser): turn on touch when an agent sets a mobile device or viewport

* docs(orca-cli): say every page load resets agent device emulation
2026-10-29 16:34:03 +00:00
Neil 89705dbf85 fix(agent-resume): quote desktop-built commands for the host's own OS and shell (#35995)
Cold restore, sleeping-agent wake and account restart on a paired Orca
server quoted the resume line for this client's own OS, so a Mac client
quoted POSIX for a Windows server and a Windows client quoted PowerShell
for a Linux one. Fresh desktop-built launches knew the server's OS but
assumed PowerShell on Windows.

One resolver, resolveHostAgentStartupShell, now decides the shell a
desktop-built command runs in: a tab's override, then the executing host's
own Windows shell (this client's setting locally, the server's reported
terminalWindowsShell remotely), then the platform default. Fresh launches
and all three resume paths use it, with the server's reported OS. A nested
SSH workspace on a server quotes for its SSH target. A host that has not
reported its OS gets POSIX quoting with OS-specific agent flags off.
2026-10-29 09:23:56 -07:00
d527f971cd fix(orcad): keep the browser sidecar's listener on loopback (#31896)
* fix(orcad): keep the browser sidecar's listener on loopback

orcad starts its headless browser sidecar as an `orca serve` child and talks to it
only over the Unix socket / named pipe. Serve mode binds its WebSocket listener to
all interfaces, so every headless host also exposed the sidecar on a random port to
its LAN and VPN. Pin the sidecar's listener to 127.0.0.1, using the owner variable
orcad already sets, so no orcad or argv change is needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(orcad): pin the sidecar to loopback using the existing sidecar launch marker

orcad already marks its browser sidecar with ORCA_ORCAD_SIDECAR, read by
isOrcadSidecarLaunch() for the foreground policy. Reuse it instead of
remembering the consumed owner variable in a new module flag.

* test: drop the stale desktop pinnedBindHost parity exception and reset the sidecar mock per test

---------

Co-authored-by: Daniel <momo.zhiwang@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 16:22:55 +00:00
Jinjing 23c146929c Fix mobile terminal overlays after delayed PTY binding (#35842)
* Refresh mobile terminal overlays after delayed PTY binding

- Show phone fit and driver-lock state when hydration precedes pane binding

* test: verify mobile overlays render after delayed PTY binding
2026-10-29 09:14:04 -07:00
Kelvin Amoaba 7c5314196a feat(native-chat): preview cards for web links, fetched with a private-address guard (#35221)
* 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&nbsp;&ndash;&nbsp;Guide showed the raw codes in preview cards.
2026-10-29 16:12:07 +00:00
Kelvin AmoabaandOliver Mee badab9cc41 fix(browser): import a cookie file into a client-hosted browser under a remote runtime (#35989)
* 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>
2026-10-29 15:53:48 +00:00
Kelvin Amoaba 75b658c278 feat(native-chat): hover cards for GitHub PR and issue links (#35199)
* feat(native-chat): hover cards for GitHub PR and issue links

Links to the chat's own repo (origin or upstream) open a card with the
state, title, author, update time, and +/- or comment count. Bare #123
references in agent replies now link too. Cards use a light one-call
lookup; older hosts ignore the flag and answer with the full lookup.

* test(github): expect the preview options argument in runtime owner/repo lookups

* fix(native-chat): route GitHub link cards by the chat's own host and retry failed repo lookups

The repo lookup took the first worktree with the chat's id, so a twin on
another host could answer, and the preview cache keyed by repo id alone.
A failed slug lookup also left cards off until the chat remounted.
2026-10-29 15:29:32 +00:00
Neil 482ff4228c fix(ai-vault): resume saved sessions for the OS of the host that runs them (#35988)
Resuming a saved session in an SSH or paired workspace assumed Linux whenever
the session had no recorded host OS, and a dropped session never passed one.
On a paired Windows server that quoted the command for the wrong shell and
could add Codex's Unix-only paste-burst flag. The resume now reads the
host's own reported OS. When the host hasn't reported it, quoting stays
POSIX, as before, and OS-specific agent flags stay off.
2026-10-29 08:27:33 -07:00
Neil 76cb99dc52 feat(automations): label workspaces a host creates with the desktop's own automation run (#35986)
* feat(automations): label workspaces a host creates with the desktop's own automation run

A desktop's own automation could create its workspace on a managed or paired
host, but the workspace lost its automation identity: no badge, and its run
pane closed instead of sleeping. The desktop now sends a capable host its run
as a label, naming itself (`local`) as the automation's owner. The host
records it with origin 'client', only for automations it does not hold, caps
its fields, and never lets a client-origin label grant run ownership, sleep
authority or automation create policy. Older hosts get nothing new; older
desktops still create plain workspaces. A client-origin label whose
automation can't be found reads as unavailable, not removed.

Refs #34433

* test(automations): keep the dropped-label warning test independent of test order

Refs #34433
2026-10-29 08:14:10 -07:00
Kelvin Amoaba 54fa31658c fix(browser): orca console and network print agent-browser's logs and honour --limit (#35981)
The agent-browser bridge cast agent-browser's {messages} and {requests} output to Orca's {entries, truncated} contract and dropped --limit, so text mode crashed and --json returned the raw shape. Map the output once at the bridge, keep the newest --limit entries, and make the contract fields agent-browser never reports optional.
2026-10-29 14:46:56 +00:00
Neil 525d17733a refactor: group native-chat image reference owner (#35807) 2026-10-29 07:46:31 -07:00
Neil 4595be8263 fix(codex): launch Codex without its paste-burst guess outside Windows (#35975)
* fix(codex): launch Codex without its paste-burst guess outside Windows

Codex treats a fast run of keys followed by Enter as a paste and turns the
Enter into a newline. Keystrokes relayed from a remote client can reach the
host bunched together, so the prompt stayed in the composer as a draft.
Orca's terminals bracket every real paste, so the guess can only misfire
there. Orca now launches and resumes Codex with disable_paste_burst=true,
except on Windows, where Codex reads console input records and relies on
the burst for pastes.

Fixes #34496

* test: expect Codex launches to disable the paste burst off Windows

Refs #34496

* fix(codex): keep the paste-burst flag out of commands that end their options

Refs #34496

* fix(codex): decide the paste-burst flag from a paired server's own OS on resume

Resume quoting on a paired server keeps the client's platform, so a macOS
client resuming Codex on a Windows server would have disabled the burst that
Windows Codex needs. The resume target now carries the server's reported OS
and leaves the flag off when it is Windows or unreported.

Refs #34496

* fix(codex): add the paste-burst flag only when the command runs Codex itself

A wrapper override may not forward -c, which would break every launch.

Refs #34496

* fix(codex): leave the paste-burst flag off compound commands and unreported SSH hosts

Refs #34496

* test: leave pass-through resume input untouched in the banner spec

Refs #34496

* test(mobile): expect AI-vault Codex resumes to disable the paste burst

Refs #34496
2026-10-29 07:45:06 -07:00