Skip to content

sync: upstream c610633ed0 into swaplabs/main - #74

Merged
kiwidream merged 327 commits into
swaplabs/mainfrom
sync/upstream-20261030
Oct 30, 2026
Merged

kiwidream merged 327 commits into
swaplabs/mainfrom
sync/upstream-20261030

Conversation

@kiwidream

@kiwidream kiwidream commented Oct 30, 2026 •

Copy link
Copy Markdown
Files Added Deleted Net
Test 1138 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​63213 $\color{#cf222e}{\Huge{\mathbf{−}}}$​17372 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​45841
Prod 1862 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​62403 $\color{#cf222e}{\Huge{\mathbf{−}}}$​17118 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​45285

ELI5

Upstream Orca moved forward 326 commits since yesterday's sync (#72). This PR merges them into swaplabs/main. Two files conflicted where fork features sit in code upstream changed; each keeps the fork's behaviour on top of upstream's new code. Three more breaks that no conflict showed are fixed here too.

What Changed

Merge of upstream c610633ed0 (the fork's mirror main) into swaplabs/main 291d584bcb. Upstream range 9f62a4fa2d..c610633ed0, 326 commits (compare). Merge commit 49a97ff6e2 is signed with the sync key. It replaces #73 (head main, CONFLICTING).

Conflicts, by fork PR (2 paths, 3 hunks)

#6 auto-resume after a host restart

  • src/renderer/src/lib/agent-resume-launch-target.ts: upstream fix(agent-resume): quote desktop-built commands for the host's own OS and shell stablyai/orca#35995 (quote desktop-built commands for the host's own OS and shell) replaced the SSH-only remotePlatform branch with reportedRemotePlatform(), which also reads a paired server's reported OS, and added agentHostPlatform ("null when its remote host has not reported one"). The fork's hostPlatform (the platform the host's own scan row reported) still wins first, above upstream's reported-platform branch. It also counts as a report for agentHostPlatform, so a target resolved from a scan row is never labelled unreported. feat(resume): auto-resume an agent session after a host restart #6's only caller, agent-resume-recovery-install.ts, reads platform and shell only, so its resume command is unchanged.

#14 one download per release source in Settings → Updates

Breaks the conflict list did not show

Fork lines this sync replaces: none.

Why

Daily upstream sync.

Linked Issue

Follow-ups are noted on #41 (resume), #43 (update sources) and #45 (fork lines near line limits).

Visual Proof

N/A: the Settings change only routes the existing "Release notes" links through upstream's link setting.

Testing

Run in the merge's working tree before committing:

  • pnpm install --frozen-lockfile.
  • pnpm tc: passes. A deliberate type error made it fail, so the check is live.
  • pnpm lint with ORCA_SYNC_PR_DIFF_BASE=c610633ed0 (all ORCA_* host variables unset): all 39 steps pass. oxlint over the 44 files both sides changed first found the two max-lines breaks, and check:direct-link-open-ratchet found the two fork rows.
  • pnpm run check:code-quality:changed with ORCA_SYNC_PR_DIFF_BASE=c610633ed0: 0 new findings across 363 changed files.
  • pnpm test:
    • Every unit test file the fork carries (120), plus src/renderer/src/components/settings/ and src/renderer/src/lib/: 867 files, 8,026 tests passed.
    • After the two moves, src/main/daemon/, src/main/runtime/session-lifecycle/projection/ and the restored-pane layout-owner tests: 321 files passed. 4 tests failed, all host-only bash-wrapper tests (bash-prompt-command-composition, shell-ready-bash-wrapper). They fail the same way on a pristine upstream c610633ed0 checkout (bash 5.3.9).
    • src/main/runtime/orca-runtime.test.ts with fixture signing off: 1,473 passed. It runs the fork's worktree-ps-agent-row-dismissal.spec.ts.
  • The pre-commit hook's checks over the 3,306 staged files, run by hand: the three oxlint configs and ast-grep pass. React Doctor warnings appear only in upstream-only files. oxfmt --check flags only upstream's docs/reference/plugin-authoring.md, which the merge carries unchanged and which fails the same check on pristine upstream. The commit therefore used --no-verify, so the hook would not reformat upstream's file; signing is unaffected. git write-tree before the commit equals HEAD^{tree} after it (2964f11e4f).

Not run: the fork's Electron e2e specs.

AI Disclosure

Prepared by the "Orca upstream sync" automation (Claude Code, Claude Opus 5.5).

Agent skill upstream boundary

  • Not applicable: this PR merges upstream's history; it adds no agent skill.

Notes

orca-fork-ops status for swaplabs/main (291d584bcb) against upstream c610633ed0:

Upstream release tag v1.4.245 was copied to the fork.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

AmethystLiang and others added 30 commits October 29, 2026 12:11
…; split echo latency phases (stablyai#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
… goes through (stablyai#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
…ched (stablyai#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
* 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 stablyai#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
…NC folder (stablyai#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
* 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
…tablyai#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
Compose the exact changes from PR36056 and PR36058 so lint and session fixture contracts pass together.
stablyai#36056)

* test(claude): call the flag-support helper after the check API rename

* fix(native-chat): reuse the non-negative integer guard so the session record stays within the file-length limit

* test(claude): leave the flag-support test to stablyai#36058
)

* 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
)

* 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
* 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
…5067)

* fix(worktrees): retire Git metadata watchers on root loss

* Fix native watcher retirement after missing snapshots
…stablyai#35051)

* fix(history): open conversation files instead of storage locators

* Preserve accepted transcript extension casing and verify log consumers

* Type session log action test fixtures explicitly
* Update structured session test fixtures for command prefixes

* fix: keep session record validator within lint line limit
…ai#35748)

* Use the shared default agent resolver for work items

* Assert the preferred work-item agent opens as chat

* Use workspace owner inputs throughout work-item agent launch

* Use equivalent test syntax accepted by CI

* test: exercise real availability for direct launch defaults

* test: name public direct launch fixture mock types

* test: document partial launch store assertion exception
* fix(claude): keep unsupported child rows on their parent pane

* fix(i18n): remove obsolete Claude agent denial translations

* fix: recover unavailable Claude child navigation to parent

* test: complete agent row navigation contracts and CI compliance

* test: repair agent row localization and integration ownership
…i#36066)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…36051)

* refactor: colocate Jira cache and project selection owners

* ci: refresh Jira refactor validation after main test fix

* ci: refresh Jira owner move after main validation fixes
…the user's runtime start check a WSL folder (stablyai#35971)

* fix(wsl): hold main's background WSL start in the shared preflight; folder launch scope honours the user's act

Main's background start (no wslUserAct) is now held in resolvePtySpawnStartupTarget, before the
startup cwd probe and any provider. A runtime start the user asked for (CLI, window, phone, split)
checks a WSL folder workspace's path as their act, so it may start the distro; background work is
refused with the stopped-distro message instead of folder_workspace_path_unavailable.

* fix(wsl): agent-session create and user resume check a WSL folder as the user's act; background holds with Start

* fix(wsl): agent-session ensure and a failed start's kept pane pass the user's act to the WSL folder check

* test(e2e): a prepared terminal.create dedupes as the caller's act
…blyai#36061)

* perf(mobile): skip line stats when loading Source Control status

Mobile Changes rows never render per-file line counts, so the default
git.status line-stats pass (up to two `git diff --numstat` subprocesses
plus untracked file reads) was wasted host work on every load. Hosts
that predate the param strip the unknown key and behave as before.

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>

* test(mobile): re-record Changes-load goldens for the no-line-stats status read

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>

---------

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>
…ead of its type (stablyai#35977)

* fix(notes): name each agent in the Send notes to menu the way its sidebar row does

* chore(ratchet): prune the notes-send menu from the host-list render baseline
…ead of dropping the oldest (stablyai#35979)

* fix(browser): refuse a 21st page annotation with a visible limit message instead of dropping the oldest

The store evicted the oldest note once a page held 20, so feedback vanished unseen. It now refuses the add; picking an element on a full page shows a limit toast instead of opening a draft, and the annotate banner states the limit.

* fix(browser): name the actions that free an annotation slot

* fix(browser): skip the limit toast for a selection loading already cancelled

* refactor(browser): one isBrowserAnnotationPageFull rule for the store, hook and banner

* refactor(browser): move the annotation limit message out of the grab hook

* fix(i18n): name the annotation limit placeholder
… the agent (stablyai#36004)

* feat(browser): paste images into annotation comments and send their paths to the agent

* fix(paste): hand an image-only clipboard to native paste so Cmd+V reaches the annotation field

* fix(browser): let an open image preview keep Escape instead of exiting Design Mode

* test(paste): drop the ownership-event test the menu-claim test already covers

* refactor(browser): reuse chat preview lifetimes and the terminal's paste host for annotation images

* fix(browser): release pasted edit images when the edited note disappears
…36080)

* refactor(sidebar): move compact card reveal into existing reveal module

* test: return the current command shape in adoption fixture

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
… right (stablyai#35994)

* feat(browser): add a shortcut to open a browser tab in a split to the right

* fix(browser): keep new-browser handlers void so the focus-read ratchet passes
brennanb2025 and others added 22 commits October 30, 2026 00:36
* fix(chat): show each repeated async question

* fix(chat): keep async question identity stable across readbacks

* test(chat): preserve async question fixture types

* Keep async question cancellation scoped to individual occurrences

* Use checked types in async question test fixtures

* Share sender-aware async question retirement across chat views
…mpt dialogs on their page (stablyai#36268)

* 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
…Go module path (stablyai#36281)

The manifest publisher is deprecated and ignored for catalog and Git installs:
catalog installs use the listing id, Git URL installs the URL owner, folders
'local' (or their still-declared publisher). Existing installs keep their key.
A format 2 manifest may omit publisher only with engines.orca >=1.4.246, so
older Orca reports 'requires Orca X' instead of failing to parse it. The v2
catalog documents an optional ownerId, which older Orca already strips.
* cli: add orca plugin create, validate and inspect

* build: ship orca plugin validate's main checks as a CLI main entry
* Support conflict-safe private storage in plugin panels

* Update frame and worker tests for host API 1.1

* Use required braces in storage conflict guard

* Update renderer handshake expectation for panel storage API

* Clarify null comparisons and exclude inherited storage keys
* Reorder same-ID worktree copies independently by host

* Use host-qualified keys for Kanban drag test fixtures

* Sync board task statuses by worktree host identity

- Ensure same-ID copies update their own host's Linear issue and status

* Preserve captured workspace ownership during queued status sync

- Skip Linear updates when the original host-specific workspace is removed
- Avoid borrowing status or credentials from a same-ID twin workspace
…alls and ps fallbacks (stablyai#31783) (stablyai#36282)

* fix(terminal): bound the in-process macOS process table's blocking calls and ps fallbacks (stablyai#31783)

Follow-up to stablyai#35987 from its post-merge reviews.

- cwd and executable path: node-pty's readProcessCwd/readProcessPath now run
  PROC_PIDVNODEPATHINFO and proc_pidpath on a libuv worker (the synchronous
  exports are gone, so an older pty.node falls back to ps/lsof). JS caps them at
  two outstanding lookups and 250ms; a wedged mount or a full cap answers from
  lsof -b, which never stats, so a dead NFS/SMB/FUSE mount cannot freeze the
  daemon's event loop or take the whole pool.
- Unreadable argv prints "(comm)", as ps does, instead of a proc_pidpath lookup
  under Orca's credentials on the table worker.
- The table exports each row's euid. Argv recovery runs setuid ps only for
  another user's processes, never for our own mid-exec or exiting ones (or
  SIDL/exiting rows), which ps cannot read either: a pane looping short
  commands forked ps on ~15% of full reads, now none.
- Recovery is coalesced per process across concurrent readers and a failed
  recovery waits 5s before costing another ps. The cache keys on comm and start
  time.
- Full-table and shell-foreground captures, which feed strict evidence with
  the capture's age, take only argv ps read after their request; display
  readers keep the 30s cache.
- While the reader is down (stalled-pool breaker open, or a rejecting addon,
  which now backs off 1s..30s), runPsInProcess runs /bin/ps itself through one
  shared budget: identical invocations share a run, a burst of 4 forks then one
  a second, and a run spawned before a request never answers it. Descendant
  teardown and foreground-group signalling keep their own full-timeout ps
  (callerRunsPs). 13 pollers at 750ms: 1,040 ps/min before, 63 after.

No daemon protocol bump: the wire format is unchanged, and each daemon loads
JS and pty.node from the same runtime copy.

* fix(terminal): make the libproc reader survive worker teardown, fail closed and share one fair fork budget (stablyai#31783)

Review follow-ups to the previous commit.

- Native: every libproc AsyncWorker derives from OrcaPromiseWorker, which skips
  JS completion once an env cleanup hook marks the env closing and swallows a
  Napi::Error thrown mid-teardown. Terminating a worker_thread with cwd or table
  reads in flight aborted the process; 200 terminates each now survive.
- (comm) in a terminal's foreground group (argv neither reader recovered, e.g.
  a root `su`) judges 'unknown', never 'agent', so the launch line is not typed
  into it.
- Fresh argv only for getFreshSnapshot captures; the 500ms TTL readers keep the
  30s cache. Argv recovery runs through its own fork budget (2, then one per
  2s). Root `su` pane, 13 pollers at 750ms: TTL 79 -> 2 ps/min, fresh 158 -> 31.
- The fork budget serves invocations in FIFO turns, grouping each one's waiters
  onto one run. 13 streams: served 80,42,1,1,2,0x8 -> 10-12 each.
- Forced subprocess captures (a held naming pass) go through the fallback
  budget: 5 readers, 400 direct ps/min -> 63, 395 of 400 captures served.
- A failed recovery is retried 5s after ps gave up, not after it started.
- Tests pin Orca's euid instead of reading the runner's and assuming root is 0.
- process-cwd keeps one lsof per pid until it exits, so a dead mount no longer
  leaks one per poll; shell readiness reads the exe path through runProcess,
  which gives up on an lsof that ignores SIGTERM.
- A stablyai#35987 pty.node (table reader, no async path reads) keeps the in-process
  table; cwd/path use lsof, with a one-time warning.
- captureProcessTable moves to process-table-ps-capture.ts.

* fix(terminal): make withheld argv unverifiable and reuse recovered argv for at most 2s (stablyai#31783)

Round-2 review follow-ups.

- Worker teardown: drop OrcaPromiseWorker and its env flag (Node drains the
  pool before cleanup hooks, so it never fired). node-pty's mac pty target now
  builds with NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS, which covers both the
  call-in and completion paths. The smoke test now calls the reads from a
  timer while terminating: the previous build aborted 2 of 3 runs, this one
  survives 3/3 x 100. pty.cc is back to the first follow-up's exact content.
- A foreground process whose argv ps withheld (`(comm)`: another user's,
  exiting, or a recovery the budget skipped) makes the batch resolver, and so
  host-stamped evidence, `argv_unreadable`/unverifiable rather than live with no
  agent; agent-foreground resolution reports it unavailable.
- judgeTerminalForeground fails closed only for an unreadable shell (`(bash)`
  from a root `su`), not our own exiting `(git)`.
- Recovered argv is reused for at most 2s per identity (pid, start, comm) for
  every reader (the next commit ages evidence by it), and
  fresh reads no longer queue behind the recovery budget. Root `su` pane, 13
  fresh pollers: p50 2,989ms -> 53ms, 31 -> 26 ps/min (TTL reader 1 -> 26).
- The fork budgets serve interactive and fresh readers before display polls
  (cheap and TTL snapshot captures), FIFO within each. 20 display streams plus
  a 3s launch-paste read every 5s: 0/12 -> 12/12 served, polls 4-7 each.
- On a selected terminal, the foreground group's argv is recovered even with no
  process of ours left (`exec su`); the root login is not.
- Budgeted captures keep the 32 MiB output ceiling.

* fix(terminal): age strict evidence by its oldest recovered argv (stablyai#31783)

Round-3 review follow-ups.

- Recovered argv carried no read time, so a capture reusing it (cached, or a
  recovery still in flight) stamped its own capture time over argv up to 2s
  older, and the remote write guard could take a same-comm re-exec for the
  agent. Rows now carry when ps read their recovered argv; runPsInProcess
  reports the oldest through onArgvReadAt, and the snapshot reader stamps
  capturedAtMs at that input, so capturedAgeMs is the age of the oldest input
  and consumers' own freshness checks (the write guard's 500ms) decide. A
  recovery begun more than 2s before a reader asked no longer answers it, and
  an older recovery finishing late cannot replace a newer one.
- resolveSpawnFileForegroundFromRows reports a withheld `(node)` foreground
  unavailable.
- One budget queue entry per invocation: an interactive request promotes a
  queued poll's, a poll joins an interactive one.
- parseShellForegroundRows gets its JSDoc back.

* fix(terminal): keep a cached name from authorizing a refused write; integer, under-2s argv ages (stablyai#31783)

Round-4 review follow-ups.

- When the relay's evidence declines a write (stale, unverifiable, another
  agent), its foreground name may still prove the shell but no longer proves
  the agent: that name can be the tracker's 1s display cache, e.g. `claude`
  cached just before Claude exited to a root shell under su. Relays that send
  no evidence keep the name as before.
- Snapshot ages round up to whole milliseconds; the wire rejects fractions
  from the monotonic-to-wall conversion.
- Recovered argv is reused for at most 1.5s, so reuse plus the 500ms snapshot
  cache stays under the 2s freshness gate; reuse ages from when that ps
  spawned, not from the wait for its fork token, and only an answer is
  remembered (a timed-out or withheld run proves nothing). Fork budget
  unchanged. Root su pane, 13 pollers: 30 ps/min; fresh p50 51ms; strict
  evidence age p50 752ms, max 1,508ms.

* fix(terminal): keep the relay's agent name behind structurally unverifiable evidence (stablyai#31783)

The previous commit refused the name fallback whenever the relay sent any
evidence, so `unverifiable` evidence for structural reasons also blocked
writes: npm Codex (node codex.js spawning native codex) and Gemini (relaunching
itself) put two agent rows in the foreground group (ambiguous_foreground_group),
and remote tmux reads multiplexer_boundary. On SSH POSIX hosts that dropped
launch prompts and failed worker briefs, conversation send/cancel and
automations with agent_not_in_foreground.

The name now cannot authorize only when the evidence saw the group (`live`:
stale, or no agent in it, as in the cached-`claude`-over-root-shell repro) or
withheld a foreground argv (`argv_unreadable`, possibly a root `su` shell).
Other unverifiable reasons keep the name fallback, as before this branch.

* fix(terminal): let a relay name complete only fresh agent-positive evidence (stablyai#31783)

The SSH name fallback still let a stale or cached name authorize a write under
any unverifiable reason but argv_unreadable: ps EAGAIN (process_table_unreadable)
after the tracker cached `claude` over a root bash, anchor_missing,
tty_boundary (`sudo -i` with use_pty, a root shell on a new pty), or a 1.5s-old
ambiguous capture.

- The name now completes evidence only when it is fresh (within the guard's
  500ms bound), its reason is one that saw an agent row
  (ambiguous_foreground_group, multiplexer_boundary,
  candidate_start_time_missing), and the name is the launched agent. Every other
  reason, including ones this build does not know, reads unknown. Relays that
  send no evidence keep the name, for mixed versions.
- The relay's evidence names one agent that holds two rows of the group (npm
  Codex: node codex.js spawning native codex; Gemini relaunching itself), so a
  new relay proves them live even when its name is `node`. Two different agents
  stay ambiguous. No wire change.

* fix(terminal): judge a relay name by the host's capture age; keep old relays' npm Codex (stablyai#31783)

- Name completion compared the capture's start with the read's start, so a
  slow response made old evidence look fresh: a capture 1,500ms old arriving
  after 1,100ms passed. It now uses the host-reported capturedAgeMs against
  the 500ms bound, which latency cannot shrink. Live evidence keeps its
  capture-start rule.
- Relays before same-agent dedupe report npm Codex (node wrapper plus native
  binary) as ambiguous_foreground_group and name it `node`. For that reason
  only, `node` now completes the evidence when the launched agent is
  npm-installed per the node entrypoint tables; other agents and reasons stay
  fail-closed.

* fix(terminal): bound relay-name completion by twice the snapshot TTL (stablyai#31783)

The 500ms bound refused ~9.5% of tmux name completions on a host with 13
pollers (cached snapshot up to one 500ms TTL old plus ~30ms capture, max
528ms), and a refusal drops the launch prompt or throws with no retry. The
bound is now 2 x PROCESS_TABLE_SNAPSHOT_MAX_STALENESS_MS (1s), still on the
host-reported age: 0 of 767 reads exceed it, the delayed 1,500ms repro still
refuses, and the cached-name hazard (the tracker's ~1s display cache) is no
wider.

* fix(terminal): complete relay evidence with a name read now, not the display cache (stablyai#31783)

With the 1s bound, a capture at 0-528ms, `codex` cached at 100ms, Codex
exiting at 101ms and the guard at 999ms still let the cached name authorize a
write over the bash that replaced it.

- Name completion (structural reasons, host age within 2x the snapshot TTL)
  now asks confirmForegroundProcess, which reads the foreground now (a fresh
  scan, or node-pty's raw process name) rather than the tracker's 1s display
  cache; a null answer reads unknown. No new wire surface: the local daemon answers
  confirmForegroundProcess, paired runtimes evaluate guards locally, and the
  production controller returns null (read as unknown, failing safe) when a
  provider lacks it. Controllers without the method, and relays sending no
  evidence, keep the cached name as the legacy path.
- Live evidence also accepts a host-reported age within 2x the TTL, so a real
  agent behind a 500-528ms cached snapshot on a fast link is no longer
  refused; a capture begun after the read was asked still counts, and
  5,000ms-old evidence still refuses.

* fix(terminal): confirm live evidence older than one snapshot TTL with a fresh read (stablyai#31783)

Accepting live evidence up to 2x the TTL reopened the window the previous
commit closed for name completion: a capture at 0-528ms, the agent exiting at
~529ms, and at 999ms `live claude` still read as agent over a bash.

Live evidence begun no more than one TTL before the read was asked (so any
host age within one TTL, however long ps took) still answers alone. Between
that and 2x the TTL, confirmForegroundProcess reads the foreground now: the
launched agent proves it, a shell reads shell, anything else unknown.
Controllers without that read fall through and refuse, as before.

Reachability: the remote (host.remote) write-guard path has no production
caller since the SSH provider's removal (stablyai#27499); the registry dispatches only
local providers and paired runtimes evaluate guards locally. This is defence
in depth for any future remote provider.
…isable (stablyai#36288)

* cli: add orca plugin dev load/unload/reload, list, logs, enable and disable

* cli: move plugin handler groups out of the manifest
* Keep CLI-removed worktree branches unless requested

* Bind branch policy checks to removal connections

* Remove redundant local default removal test row

* Negotiate worktree branch policy on the mutation connection

* Fix removal integration compiler boundaries and type imports

* Use checked annotations in paired removal fixtures

* Reset CLI integration exit status across test runtimes
…k to HEAD commit (stablyai#34778)

git show :<path> and git show HEAD:<path> treat a missing blob spec as a
pathspec, exit 0, and print the HEAD commit when the path contains [, *
or ?. Orca then showed the commit header as the original side of new
files such as app/[id]/page.tsx. Read index and tree blobs with
git cat-file blob, and on older Git that only reports 'Not a valid
object name' prove absence with an empty literal ls-files/ls-tree probe.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ndow reload (stablyai#36307)

* fix(browser): find a hidden tab on the first agent command after a window reload

Right after a renderer reload, the first agent browser command on a hidden
tab failed with browser_tab_not_found. Main sent browser:activateView before
the reloaded renderer had restored its tabs, so nothing mounted; and the
bridge reused the page's agent-browser session bound to the guest the
reload destroyed.

Wait for the main window's existing readiness signal before activating a
hidden tab, and retire a session whose guest changed. agent-browser answers
`close` and exits ~100 ms later, so destroySession waits for the old daemon's
socket to go before the session name is reused.

* test(browser): read the replacement proxy's guest from its constructor call
)

* fix(git): resolve current branches without tag ambiguity

* fix(git): share tag-safe current branch reader with push-target setup and trim real-git proof matrix

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Picks up File System Access blocklist and asar hardening fixes. 43.8.4 is
excluded from minimumReleaseAge since it was published under 3 days ago.
…lyai#35390)

The fallback patch-equivalence proof only reads each line's leading +/- marker,
so the subjects printed by `git cherry -v` were unused output.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Upstream range 9f62a4f..c610633, 326 commits. 2 conflicted
paths, 3 hunks, both modified.

Conflicts:
- agent-resume-launch-target.ts (#6): upstream stablyai#35995 resolves the
  platform from what an SSH host or paired server reported and adds
  agentHostPlatform. The fork's hostPlatform (the scan row's own
  platform) still wins first, and counts as a report for
  agentHostPlatform.
- GeneralUpdateSettingsSection.tsx (#14): the fork's layout. Upstream
  stablyai#35992 routes the release-notes links by the open-links-in-Orca
  setting; its onClick follows the moved links into
  SingleSourceUpdateHint and the fork's ReleaseNotesLink.

Breaks the conflict list did not show:
- daemon-pty-runtime-state.ts reached 302 counted lines (upstream 299)
  in a clean merge. #25's draining field moves into a fork-owned
  DaemonPtyDrainState layer under DaemonPtyAdapter; the option stays.
  Now 300.
- restored-pane-materialize.ts reached 302 (upstream 290) in a clean
  merge. #30's hook-store check moves into
  openShellAfterRefusedHostResume, so the catch makes one call. Now 300.
- Upstream's new direct-link-open ratchet (stablyai#35992) flags the fork's
  installer link (#14) and managed-server help link (#17). Both rows
  are baselined as fork lines, so they still open in the system browser.

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

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T10:23:32.681395Z 49a97ff PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kiwidream
kiwidream merged commit 0d27095 into swaplabs/main Oct 30, 2026
46 of 47 checks passed
@kiwidream

Copy link
Copy Markdown
Author

Checks after the merge, read at about 10:50Z: 99 passed, 4 failed and 2 pending (ssh on managed orcad, Docker 1/2 and 2/2). None of the failures points at a fork-owned file:

Codex completed on 49a97ff with no findings; Tenki posted nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants