Commit Graph
20022 Commits
Author SHA1 Message Date
Jinwoo Hong a55de38395 feat(cli): set and rm folder workspaces through the folder workspace RPCs (#39670)
* feat(cli): set and rm folder workspaces through the folder workspace RPCs

worktree set and rm on folder:<id> (or a path:/name: selector that matches a
folder) now call folderWorkspace.update and folderWorkspace.delete after the
runtime confirms the folder id is unique. Flags with no folder meaning are
refused before any change, a missing method reports incompatible_runtime, and
worktree activate refuses folder workspaces as not supported yet.

* test: read mocked method names without a cast

* fix(runtime): refuse shared folder ids inside folder update and delete

The CLI's show preflight could not make the id-only folder RPCs safe: an older
show could select one of two same-id rows, and a twin added during teardown was
deleted too. folderWorkspace.update/delete now take requireUniqueId, which
refuses a shared id before any side effect, and delete removes only the row it
checked. Hosts advertise folder-workspace.unique-id-mutation.v1; the CLI
requires it and reports incompatible_runtime otherwise.

* fix(runtime): refuse a folder delete when a twin appears during teardown

Two rows that share a folder id share every record keyed by it, so delete
can't keep one row's sessions while removing the other. After the awaited
terminal teardown, delete checks the id again before any cleanup or removal
and refuses with the duplicate-id error; only the stopped terminals remain as
an effect. Removal by row identity is no longer needed and is dropped.

* fix(cli): give only the repair step for a duplicated folder id

The generic ambiguity recovery told agents to pass folder:<id>, which can't
name one of two folders sharing that id.
2026-11-08 00:34:44 -05:00
OrcaWinandOrcaWin 88bbb00b19 refactor(i18n): resolve the diff comment popover's default labels from useTranslate (#39744)
Its placeholder and submit labels defaulted through translate() in the
parameter list, which runs before a hook can bind. Resolve them from
`t` in the render instead.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 21:34:24 -08:00
NeilandFlamingoPg 6a68dac421 fix(terminal): bound WebGL atlas pages and release removed page textures (#39715)
Cap merged atlas pages at FORCED_MAX_TEXTURE_SIZE instead of the device
MAX_TEXTURE_SIZE (16384 on Apple Silicon), stop the link render layer
from acquiring the shared atlas with a mismatched 2048 texture size, and
reset GL texture slots of removed atlas pages to the 1x1 placeholder.
Mirrors xtermjs/xterm.js#6187, #6156 and #6306 in the addon-webgl source
patch and regenerates the runtime patch and lock hash.

Co-authored-by: FlamingoPg <1106310035@qq.com>
2026-11-07 21:30:43 -08:00
OrcaWinandOrcaWin efeee83b2c refactor(i18n): read render-path translations from useTranslate in smaller component areas (activity through maintenance) (#39424)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 21:20:59 -08:00
Neil 261bc0f2be relay-edge: single-use admin tokens (jti), signing key rotation, auth-refresh metrics (#39738)
- Admin tokens with a jti (16-128 chars) are single use, enforced inside the target
  HostRelay (one storage key, expired ids pruned on each call, capped); a repeat is 409
  'replay'. Tokens without a jti are still accepted (metric admin_no_jti) unless
  ADMIN_REQUIRE_JTI=1.
- ADMIN_SIGNING_KEY_NEXT / ERASE_SIGNING_KEY_NEXT: second accepted key for rotation;
  validated >= 32 chars when set.
- Metrics auth_refresh (extended/unchanged/invalid/identity_changed) and
  auth_expired_close (seconds since the last extending refresh).
2026-11-07 21:14:12 -08:00
fb313c4745 perf(terminal): park and defer restored plain-shell tabs whose sessions no longer exist (#39725)
Restored tabs whose local daemon session is gone no longer mount and
respawn a shell at startup; they park and respawn on open.

- Separate pty:getGoneSessionIds probe, started unawaited at startup so
  it never gates reconnect; the authoritative-capability call is unchanged.
- Binding a PTY id (spawn, cold restore, attach) clears its gone mark so a
  revived pane gets parked exit/byte watchers again; late answers for bound
  ids are ignored.
- Agent tabs (launchAgent or sleeping record) and mixed live/gone splits
  keep the mounted restore path.

Replaces #37410.

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: thefrikidude <100475418+thefrikidude@users.noreply.github.com>
2026-11-07 21:11:15 -08:00
OrcaWinandOrcaWin 9dfc0bac93 refactor(i18n): render the usage charts in their test and read useTranslate there (#39737)
The usage chart test called both charts as plain functions, which kept
them on translate() and getIntlLocale(). Render them instead and
convert the charts. The pull request page's back label moves from a
parameter default into the render.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 21:11:11 -08:00
OrcaWinandOrcaWin 6d95515306 test: remove 297 low-value tests (#39720)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 21:10:57 -08:00
Neil 7ae6448b44 perf(terminal): opt-in adaptive ACK pacing for alternate-screen streams on slow remote links (#39735)
* refactor(terminal): own multiplex ACK window accounting in one module

* perf(terminal): pace alternate-screen multiplex output to the measured link BDP

Slow SSH links queued up to 2MB of superseded TUI frames ahead of keystroke
echo. orcad now estimates delivery rate and base RTT from existing output ACK
timing, caps in-flight output for alternate-screen streams near 2x BDP on links
under 4 MB/s, and replaces a backlog larger than that budget with the existing
recovery snapshot. Normal-screen streams and fast links keep the legacy
windows. ORCA_TERMINAL_ADAPTIVE_ACK_WINDOW=0 restores legacy behavior.

* perf(terminal): back off unavailable superseding snapshots and bound legacy echo checks

* perf(terminal): gate ACK pacing to measured remote links and keep supersedes history-neutral

Pacing now needs a base RTT of at least 40ms, 16 fresh window-limited samples,
and a sample within 15s, so LAN/local links and stale estimates keep the legacy
windows. Superseding snapshots are screen-only, only replace frames that never
switch screen mode (rechecked after serializing), and leave client history
untouched. Paced streams keep today's total buffering before overflow, so
overflow recovery fires no earlier than with legacy windows.

* fix(terminal): close supersede gaps found in review

Scan for screen switches and OSC side effects across frame and send
boundaries (raw and JSON-escaped), back off after an aborted supersede so it
cannot re-serialize in a loop, and keep paced pending headroom until the queue
drains so leaving the alternate screen cannot force an overflow recovery.

* fix(terminal): judge supersedable backlogs on decoded text across every seam

Scan the joined text of the whole queue (plus the sent tail) so screen
switches split across any frame, send, or covered/retained boundary are
seen; never supersede span frames; reject bells (via the shared bell
detector), OSC clipboard/notification writes and 8-bit OSC; back off for 1s
after a rejected scan instead of rescanning on every ACK.

* perf(terminal): make backlog superseding opt-in and forget the sent tail after snapshots

Every recovery snapshot makes current clients replay their reattach reset
(cursor shape/visibility, focus reporting), which is visible when it fires
routinely, so superseding is opt-in via ORCA_TERMINAL_SUPERSEDE_ALT_BACKLOG=1
until clients can skip it. Pacing stays on by default: on a slow link the
existing overflow recovery then reaches the client promptly instead of queuing
behind a 2MB window. After any snapshot the sent tail is unknown (it can end
inside an escape), so superseding waits for the next text frame.

* test(terminal): cover default pacing and opt-in superseding separately

* perf(terminal): read the supersede switch once per connection and skip its bookkeeping when off

* perf(terminal): make adaptive ACK pacing opt-in and fix review findings

- Default off: ORCA_TERMINAL_ADAPTIVE_ACK_WINDOW=1 enables it; when off every
  new path is a single flag check, so behavior matches legacy windows.
- Base RTT is a windowed minimum kept honest by periodic probes that drain our
  own queue; a paced RTT beyond what our window can add means the path changed,
  so legacy windows hold while the base re-learns (no more self-tightening to
  64KiB after an RTT increase).
- Paced pending headroom is capped by the connection window legacy would have
  used and released on drain, pause and detach.
- Superseding refuses snapshots that end inside an escape.
- Replace the latency-threshold unit test with hardcoded estimator tests and
  move the link simulation to bench:terminal-multiplex-ack-pacing.

* perf(terminal): drop backlog superseding and harden opt-in ACK pacing

- Remove the opt-in backlog-superseding snapshot path (code, env switch,
  frame classifier and tests); it needs a client capability to skip the
  reattach reset before it can ship.
- Paced-ness is decided once at admission (alt screen checked before the
  estimate) and reused by the send, so a probe starting in between cannot
  mislabel a sample.
- Base RTT is fed only by sends with a near-empty connection queue; probes end
  only on such samples from paced streams, and a probe that cannot drain backs
  off. A path change forgets the base and holds legacy windows until a drained
  sample re-learns it.
- Paced pending headroom is sized from the steady window (never a probe's
  zero) and released whenever the queue drains back within the legacy cap.
- Flow-level tests: disabled pacing keeps legacy frames on a measured slow
  link; drained headroom returns so later output overflows at the legacy cap.

* fix(terminal): release paced headroom whenever the queue drains, including after recovery
2026-11-07 21:07:59 -08:00
OrcaWinandOrcaWin 2f45e26ee7 refactor(i18n): read render-path translations from useTranslate in pull request page, agent, onboarding, stats, new workspace and feature tips (#39421)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:59:26 -08:00
Neil c99e71b315 refactor: group renderer runtime resource owners (#39571) 2026-11-07 20:52:26 -08:00
c00f8448d5 perf(mobile): stop loading unrelated RPC schemas in shared readers (#39727)
Import MAX_BLOCKS/MAX_PROMPT_BYTES from the module that defines them and
move automationCanonicalLaunchSetup into automation-launch-setup-source
(re-exported) so mobile shared readers skip unrelated RPC schema modules.

Carries #39022 unchanged.

Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
Co-authored-by: gentslava <14369958+gentslava@users.noreply.github.com>
2026-11-07 20:44:38 -08:00
Jinwoo Hong f341558b82 feat(cli): match folder workspaces by path: and name:, keep same-id ps rows apart (#39637)
* feat(cli): match folder workspaces by path: and name:, and keep same-id ps rows apart

Adds one runtime matcher for worktrees and folder workspaces. With the new
matchFolderWorkspaces opt-in (advertised as workspace-selector.folder-match.v1),
path: and name: also match folder workspaces; branch:, issue: and identity:
stay repo-backed. Several matches refuse with each choice's kind, host, path
and selector; a folder id shared by two folder workspaces refuses with the
repair step. The CLI resolves path:/name: through it, so terminal, file and
ports commands reach a folder workspace, and create/set parents record a
folder parent. Explicit ambiguous parents report LINEAGE_PARENT_AMBIGUOUS.

worktree ps now keeps rows that share an id on different hosts apart, with
their own host, identity, metadata and activity; activity whose host can't
be proven attaches to neither.

* test: let the cross-version ps harness pass the host-qualified summary lookup

* fix(cli): read each ps row's own host session; qualify folder selector help

* fix(runtime): refuse unscoped duplicate folder ids; hand lineage the matcher's typed result

Unscoped folder:<id> refuses a duplicated id even when only one copy's host
is derivable; a host-scoped lookup still picks that host's copy. A wsl: hook
stamp counts as local host evidence. The lineage controller receives the
worktree-or-folder candidate directly instead of re-deriving the kind.

* docs(cli): guide the ambiguity fallback through truncated ps and id: selectors

* fix(cli): report an ambiguous parent by its own choices; cover per-host sessions

* fix(cli): send parents to the runtime parent resolver as typed; translate WSL paths for folders too

Parent selectors skip the CLI's show-based folder lookup, so worktree.create
and worktree.set classify them with parent rules: a folder spanning hosts is
a valid parent, and ambiguity reports LINEAGE_PARENT_AMBIGUOUS. Caller-distro
Linux path translation now also matches folder workspaces.

* chore(rpc): import the computer-use recovery data directly instead of through an alias

* fix(runtime): report a missing set parent as LINEAGE_PARENT_NOT_FOUND, as create does

worktree set and worktree create now share one explicit-parent error
conversion: several matches give LINEAGE_PARENT_AMBIGUOUS and none give
LINEAGE_PARENT_NOT_FOUND, so a missing parent is no longer reported as a
bare selector_not_found that could mean the child.
2026-11-07 23:35:33 -05:00
OrcaWinandOrcaWin ebe3aac000 refactor(i18n): finish EditorFileTab and the checks tab actions on useTranslate (#39726)
ChecksTabActions is called as a plain function, so it now takes the
checks tab's `t` instead of reading translate(). EditorFileTab would go
over budget once converted, so its mode icon choice moves to its own
module first.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:34:28 -08:00
Neil 6d122f1eb5 perf(git): use git's untracked cache and reuse unchanged line stats in status reads (#39721)
* refactor(git): move porcelain status streaming into its own module

* perf(git): let status use the untracked cache and expand collapsed directories

-uall never matches the untracked cache's stored mode, so every poll rescanned the whole tree. Scan in the configured mode and list only the collapsed '? dir/' rows with ls-files, reapplying the entry cap so results match -uall exactly. Ignored reads and status.showUntrackedFiles=no keep -uall.

* refactor(git): let the settled diff cache and stamp serve multi-path reads

* perf(git): reuse status numstat passes while their stamped inputs are unchanged

Each poll re-ran up to two whole-worktree numstat diffs even when nothing changed. Cache each pass in a SettledDiffCache validated by the worktree diff stamp (HEAD, index, .gitmodules, plus every unstaged working file for the unstaged pass); racy writes, mutations and submodule rows still recompute.

* perf(git): defer status while index.lock is held

A status read during an agent's commit sees a half-written state and is immediately redone. Wait (up to 1s, abortable, inside the shared lease) for the lock in the worktree's own gitdir to go away; a lock that survives a full wait is remembered as stale so later reads skip waiting.

* perf(git): pick the untracked scan from config and fall back to -uall when expansion cannot win

Read status.showUntrackedFiles and core.untrackedCache in one config call, remember worktrees that need -uall so polls do not scan twice, and rescan with -uall when rows sit outside cwd, need more than one ls-files chunk, or list empty.

* refactor(git): keep numstat cache limits beside the file diff limits

* refactor(git): stamp host settings files and resolve the common gitdir

* perf(git): read untracked-scan config from a stamped snapshot, with a rollback switch

Cache 'git config --list --show-origin' per worktree while every config file it named (plus repo, worktree and global candidates) keeps its stamp, so steady-state polls spawn no config read. WSL and UNC checkouts keep -uall: their config cannot be stamped from the host and network mtimes cannot vouch for the untracked cache. ORCA_GIT_STATUS_UNTRACKED_EXPANSION=0 restores the plain -uall scan.

* fix(git): stamp config and attributes before reusing status numstat

Numstat output also depends on Git config (including includes) and on .gitattributes, info/attributes and core.attributesFile. Stamp all of them, plus every .gitattributes that can apply to a changed path, and skip reuse under WSL. ORCA_GIT_STATUS_NUMSTAT_REUSE=0 recomputes every pass.

* fix(git): stamp include targets and onbranch HEAD in the config snapshot, and share one read

Include and includeIf targets (and HEAD for onbranch conditions) are now stamped, so a branch switch or a filled-in include re-reads config. Concurrent cold reads coalesce, both numstat passes share one config read, folders without their own gitdir skip the snapshot, aborted reads keep the cached entry, and Windows HOME follows Git's HOMEDRIVE/HOMEPATH order.

* perf(git): expand untracked directories only when the untracked cache is opted in

Git's default core.untrackedCache=keep only reuses a cache someone already built, and fresh repos have none, so status plus ls-files cost more than one -uall scan. Expand only for core.untrackedCache=true or feature.manyFiles=true without an override.

* fix(git): bound config stamps on dead mounts and share commondir resolution

Config file stats run under the same 2s deadline as local-git-config-signature, coalesced per file set, so a hung home or network mount skips reuse instead of stalling status. readHeadComponent now uses resolveGitCommonDir.

* test(git): pin the -uall truncation contract of untracked directory expansion

* fix(git): treat an unreadable commondir as unstampable config

main's resolveGitCommonDir rethrows non-missing errors; the config snapshot must fall back to -uall rather than reject the status read.
2026-11-07 20:33:31 -08:00
OrcaWinandOrcaWin ab6a147332 refactor(i18n): read render-path translations from useTranslate in terminal pane, tab bar and work-item dialogs (#39418)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:23:56 -08:00
Neil 2ec81bc2ca feat(claude): match Claude Code's theme to the Orca terminal theme (#39447)
* feat(claude): sync the terminal theme into Claude Code

* fix(claude): retry missed theme reloads, keep settings key order, search entry

* fix(claude): persist theme ownership before settings writes, skip deliberate themes, restore only on toggle

* fix(claude): gate theme sync on Claude Code 2.1.119, follow Orca's Claude config dirs, keep restores owed

* refactor(theme): point markdown Monaco rules at the shared contrast helpers

* fix(claude): lock theme ownership edits across Orca processes, retry missed theme reloads with backoff

* test(e2e): opt-in real Claude Code theme sync journey; retry theme reloads for up to five minutes

* fix(claude): keep theme takeover recoverable when settings writes or the lock fail; steadier e2e journey

* fix(claude): serialize theme publication with takeover and restore, per-file reload retries; record the real-Claude e2e in the isolated home

* fix(claude): retry an owed restore publish, stop off-state retries, reread settings right before writing

* fix(claude): republish theme files under the cross-process lock

* refactor(theme): point chat selection contrast at the shared helpers

* feat(claude): default theme sync on for new profiles; offer it once to existing users at their next Claude launch

* fix(claude): offer theme sync to every existing profile, confirm only after the save, honest offer copy

* fix(claude): right-align the theme sync offer's two actions, primary last
2026-11-07 20:19:22 -08:00
Kelvin Amoaba 4eeba01db0 perf(mobile): tick only agent rows on the host list and keep repo looks across polls (#39636)
* perf(mobile): tick only agent rows on the host list and keep repo looks across polls

* fix(mobile): refresh the shared clock when a list comes back within one interval

A clock stopped less than one interval ago kept its old time and started a new full interval, so a quickly reopened host list could show agent ages up to about a minute old.
2026-11-07 20:19:03 -08:00
OrcaWinandOrcaWin 567b5580e2 refactor(i18n): finish IssueDialog and the run history count label on useTranslate (#39717)
IssueDialog's team list named its map parameter `t`, so the codemod
skipped the dialog; rename and convert. The run history's count label
memo reads the component's `t` and recomputes on a language switch.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:16:15 -08:00
OrcaWinandOrcaWin 8f4913fd69 test(terminal): stop re-evaluating connect-pane-pty per test in pty-connection suites (#39711)
The registered pty-connection specs called vi.resetModules() in every
beforeEach, so each case re-evaluated the whole connect-pane-pty graph
(~90-300ms per case, even for trivial ones). Suites now share one graph
and the harness clears the module state tests leave behind.

- restoreTerminalTestGlobals imports the live module instances and runs
  their existing reset hooks (delivery claims, completion identity,
  startup delivery, side-effect fact consumers, hidden restore scheduler,
  pane recovery, ...). It also discards queued output and cancels an
  output drain left armed under abandoned fake timers.
- New loadFreshTerminalModules() gives a fresh graph to tests that stub
  import-time globals (navigator UA -> CLIENT_PLATFORM) or depend on
  once-per-load subscriptions (serializer IPC listener, completion
  settings subscription). Teardown resets again so later tests never
  reuse that graph.
- notification-settings-gating keeps a fresh graph per test (shared
  settings subscription, no reset hook).

No production code changes, no tests deleted, expected values unchanged.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:10:07 -08:00
OrcaWinandOrcaWin 8d2b5a2c07 test(rpc): drop the default-RPC-manifest guard where no default remains (#39684)
RpcDispatcher now requires its method list, so these suites can no longer consume
the default manifest. Suites that still reach the registry through the RPC server
keep the guard.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 20:10:01 -08:00
Neil 340c917429 relay: edge export skip on outage, cohort-exit drain sweep, region-scoped account allow (#39707)
* relay: edge export skip on sustained outage, evacuation drain sweep, account allow scoped by region

- Leaving hosts skip the edge export once it has been unavailable for 120 s
  (ORCA_RELAY_EDGE_EXPORT_SKIP_AFTER_MS), keeping Postgres devices and
  fencing best effort, instead of 503ing until the edge is back.
- Directors drain edge hosts that left the cohort (POST /__admin/drain,
  20 per jittered 60 s tick) so connected desktops re-ask and move off.
- Account-allowlisted hosts must also be in the edge regions.
- Tests for the invite-socket edge branch.

* relay: export skip needs continuous failures; evacuation sweep runs soon after start, then every 10 min

Failures more than 30 s apart restart the unavailable clock, so one old failure cannot skip an
export. The sweep reads the edge rows (cell_id has no index): first pass 45-75 s after start (a
cohort change is a new revision), every 45-75 s while hosts are queued, else every 7.5-12.5 min.
2026-11-07 20:09:41 -08:00
OrcaWinandOrcaWin dab4c4148a refactor(i18n): read render-path translations from useTranslate in task page and automations (#39406)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:59:46 -08:00
OrcaWinandOrcaWin d530e58993 refactor(i18n): finish the status bar's render-path translations (#39708)
SshStatusSegment's target maps named their parameter `t`, so the
codemod skipped it; rename and convert. The owner usage, resource
merge and runtime host notice memos pass their hook's `t` into the
helpers they call and recompute on a language switch.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:54:11 -08:00
OrcaWinandOrcaWin 331864e249 test: remove 259 low-value tests (#39701)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:53:07 -08:00
OrcaWinandOrcaWin b69a0cd0a9 refactor(i18n): split the browser and feature-wall over-budget files and read useTranslate there (#39698)
BrowserAddressBar, AgentCapabilitiesSetupAction and FeatureWallTourSurface
would go over budget once converted. Move the address bar's form-unmount
timer clearing, the capability setup rows and the tour's skill reads to
their own modules first, then convert. The tour's parameter-default copy
moves into the render; an explicit null footer still hides it.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:51:46 -08:00
Neil 8ea8406c64 relay-edge: control liveness on any frame, signed drain op, small-volume alerts (#39706)
* relay-edge: any inbound control frame refreshes control liveness

A control that keeps sending commands or auth refreshes is alive even when
its pongs are late. Every inbound frame from an active control now refreshes
lastPongAt (field name kept so hibernated attachments read the same field);
pong_rtt_ms is still recorded for pongs only.

* relay-edge: signed admin op drain

POST /__admin/drain { relayHostId }, signed like assign/export/erase with
op 'drain'. Every control of the host gets the lease-expiry drain frame
(graceMs 0, resolve-director), closes 4503 'host leaving edge' and goes
through the normal socket-gone path. Returns 200 { outcome: 'idle' } or
{ outcome: 'drained', controls }. Assignment, devices and splices untouched.

* relay-edge: alerts that fire at small volume, and an edge probe

Absolute-count rules regardless of MIN_VOLUME: admin-failures (>= 3 admin
calls per 15 min whose label is not an expected outcome) and
auth-refusals-low-volume (>= 5 4401s below MIN_VOLUME). Optional
EDGE_PROBE_URL: each run sends an unauthenticated control upgrade and
alerts unless it gets 401 within 5 s (stateless: every failing run alerts).

* relay-edge: MVP checks for control liveness and the drain op
2026-11-07 19:51:09 -08:00
Neil 951517b14b fix(ssh): finish the move to the managed server once the last relay-era terminal exits (#39621)
* fix(ssh): finish the move to the managed server once the last bridged relay terminal exits (#29626)

When a host stayed connected and unmoved only because the legacy relay
bridge served relay-era terminals, nothing retried the move after they
ended. The registry now notes relay-proven exits and, once the bridge
serves no pane (live or unverifiable) and owes no stop, runs one
automatic connect through the existing decision path. Lost contact keeps
panes unverifiable, so it never triggers the retry.

* fix(ssh): keep a bridged host as it was when the automatic move retry is refused (#29626)

The retry now runs as a quiet automatic connect. Its attempt shows no
setup progress, so the kept bridged status is never replaced mid-way.
A refusal or failed decision republishes the kept connected status
instead of an error, and never abandons the reused transport or stops
the bridge. It also refuses to run when it would replace a pending
transport, or once the host is no longer connected and bridged. Only a
finished move publishes a new status.

* fix(ssh): keep a quiet move retry from changing what the user or host already has (#29626)

- A user's connect joining a quiet retry upgrades it to an ordinary
  connect, so refusals surface and progress shows; a quiet refusal no
  longer clears move-anyway consent.
- A quiet retry rotates the provider authority only once its move
  succeeds, so a refusal cancels no in-flight provider requests.
- On refusal, re-read the host status and republish only a still-bridged
  host, as connected only while its transport is connected.
- Exits are tracked per bridge, so a replaced bridge's exit never counts
  for its successor.

* refactor: key move-retry exits by a named bridge type
2026-11-07 19:45:45 -08:00
NeilandCopilot 1334391443 fix(terminal): preserve decorations on DOM block glyphs (#39615)
Keep default underline and strikeout colors visible while hiding block font glyphs, including link-hover shorthand resets. Restore only owned decoration overrides and preserve explicit colors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-07 19:44:59 -08:00
Neil d2506d05d6 perf(git): cache branch-compare merge-base and ahead/behind by commit pair (#39699)
* refactor(git): share common-dir resolution and stat stamps from worktree-diff-stamp

* perf(git): cache branch-compare merge-base and ahead/behind by commit OID pair

* fix(git): only store a commit-pair answer when its scope survived the walk

* refactor(git): type commit-pair stores per answer kind and pin test mtimes

* fix(git): skip the commit-pair cache whenever replace refs, grafts or relocating env could apply
2026-11-07 19:43:01 -08:00
OrcaWinandOrcaWin 9df0b13901 refactor(i18n): read render-path translations from useTranslate in status bar (#39401)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:41:27 -08:00
OrcaWinandOrcaWin 90697091d0 refactor(i18n): read render-path translations from useTranslate in the review animated visuals (#39696)
The codemod skipped both visuals because a timer-clearing callback
named its parameter `t`. Rename it to `timer` and convert their
copy to useTranslate.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:39:19 -08:00
OrcaWinandOrcaWin 532ae2b0ef refactor(i18n): pass useTranslate's t into the plugin manager's list entries (#39693)
buildPluginListEntries disambiguates plugin names with `t`; the
manager already reads it, so pass it and recompute on a language
switch. The manager would go over budget, so its entries memo and the
auto-update reads it depends on move to use-plugin-manager-entries.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:29:13 -08:00
OrcaWinandOrcaWin ff6b9a305c refactor(i18n): read render-path translations from useTranslate in browser pane and feature wall (#39399)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:27:54 -08:00
OrcaWinandOrcaWin e53d2ec3c9 test: remove 182 low-value tests (#39689)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:19:08 -08:00
Brennan Benson 00e25b55b2 Show one actionable error when an agent launch cannot prepare its workspace (#37220)
* fix: report agent launch failures once with actionable recovery

* fix: keep terminal launch controls shown but waiting while the host connects

Replace per-row pending metadata with one derived terminal-readiness flag on
the agent menu model, kept out of picker identity keys. Terminal buttons and
rows stay mounted and disabled while SSH or a paired server is still
connecting; chat and Configure stay usable, and the terminal default is not
changed. Repo targets with no workspace yet read the repo host's facts.
Invalid Source Control arguments keep their existing actionable message.

* fix: keep launch readiness and failure ownership consistent across pickers and fallbacks

A host that is still connecting now declines a terminal launch silently at the
launcher, including shortcuts and fallbacks, instead of reporting a failure.
A terminal fallback refused behind a visible chat reports through that chat's
notice rather than a second toast. The agent picker stays usable while only a
terminal waits; an armed terminal rechecks readiness on Enter; a configured
chat option no longer inherits the terminal's waiting state; waiting terminal
controls say why. Invalid CLI arguments name the actual problem for every
caller, the no-agent shortcut message is restored, and prospective repo
readiness no longer rescans repos on unrelated store writes.

* fix: keep the handoff dialog open when a host-waiting launch opens nothing

A session continuation launched through the host's admission now waits for
that launch to settle before reporting the handoff. When the host declines the
chat and its terminal fallback is declined while the host is still connecting,
nothing opens, so the dialog stays open for a retry instead of closing with no
session and no message.

* fix: let the handoff dialog close while its session is starting

Cancel, Escape and outside clicks now close the Hand Off dialog even while a
start is in flight; Start stays disabled with its spinner. Closing aborts agent
detection if it is still running, and a dialog closed during detection starts
nothing. A launch already sent settles on its own and reports through its
existing owners. The in-flight start belongs to the request it was made for, so
a late finish never closes, completes or blocks a dialog reopened since.

* test: replace type assertions in launch refusal tests with typed fixtures

* refactor: name the setup panel's launch helper launchSurface

* perf: resolve a picker's terminal host only when ownership changes

The terminal readiness check rebuilt the target's ownership chain and ran
the full OS resolver on every store write, for every mounted picker. Each
picker now keeps its target host and re-resolves it only when an ownership
slice changes; other writes read just that host's connection and contact
facts. Local hosts read nothing. The launcher's own pending decline uses
the same host pieces from execution-host-facts, so the rule has one copy.

* perf: word a declined chat's fallback failure without re-saving launches

Wording the failed chat's notice after its terminal fallback was refused
re-saved every retained launch record, though the wording itself is never
saved. Listeners now hear about it without a save; lifecycle changes still
save. The refused-fallback test moves to its own file and counts saves at
two sizes.

* test: narrow refused launch outcomes where tests read the opened tab

launchAgentInNewTab now returns a refusal instead of a tab when the
launcher declines, so tests that read the opened tab's surface or
completion narrow it first. Fixes the web typecheck.

* fix: keep Configure usable and show one reason on a waiting agent row

While the host connected, each New Chat agent row was marked
aria-disabled, so its Configure button read as disabled to assistive
tech and keyboard. The row now only blocks its launch and points to its
"Connecting…" reason. A row shows one reason, the one that stops its
launch now, and the agent name keeps its width so it is not cut to a
single letter.

* test: cover distinct repo targets and host freshness in the picker perf contract

Pickers for workspaces not created yet now count repo reads cold and after
another host's row is republished, at two scales with a repeated-target
control, and assert no unaffected renders. Two freshness controls follow
the cached host: an owner moving from local to a connecting SSH host and
back, and a paired server that is still checking versus verified with its
OS.

* fix: mark a waiting agent launch unavailable while Configure and chat stay usable

An agent row's launch item also held its Configure button (New Chat) or
its start-in-chat button (the + menu). Disabling the row while the host
connected disabled those too; leaving it enabled made the waiting launch
read as available and then do nothing.

The launch item and those controls are now siblings. While the host
connects the launch item is marked unavailable, dimmed and described
"Connecting…", and stays focusable so arrow keys still reach the
controls beside it. Configure and chat keep their own state. A chat
started from Configure or the chat button goes through the row's guarded
launch and closes the menu, without choosing the waiting item.

* fix: release the agent row button's press listeners when a press is cancelled

Each press on the button beside an agent row added a window listener that
only a pointerup removed, so cancelled touches and closed menus left them
behind. A press now owns one handler that removes both listeners on
release, cancel, the next press or the row closing; drag release onto the
button still chooses it.

* fix: give the agent launch row item its own menu item variant

The launch item beside Configure or the chat button restyled the shared
menu item (transparent focus, dimmed while unavailable), which the design
system gate rejects. That treatment is now the menu item's launch-row
variant; the rendered rows are unchanged.

* fix: route the menu's terminal host by owner and repair the e2e and ja checks

The menu's terminal readiness now reads workspace records through the
workspace record selectors and picks a not-yet-created workspace's repo by
the host it names, without the focused-host fallback; with no host named
it settles only when the id has one row, which reads the same. Its cached
host is re-checked when the settings slice changes instead of reading the
focus setting. E2E unit tests narrow refused launch outcomes, and the two
new ja strings write Agent as the rest of the catalog does.

* test: count a launch as opened only when it returned a surface

A refused launch now returns its refusal instead of null, so the parity
check asks whether a surface opened.

* perf: keep menu readiness on the workspace's owner and index the twin fallback

Terminal readiness re-resolved every mounted menu's host on any settings
write, and an unstamped worktree whose project is listed both here and by
a paired server walked the whole repo catalog to resolve. Readiness now
resolves an existing workspace's host from its resource owner only, never
the focused default a row-less setup terminal is created on, so settings
writes leave it alone. The shared-project check reads that project's rows
from the existing per-snapshot repo index instead of the whole catalog.
Setup terminals and every route keep their behavior.

* test: assert which readiness pickers render on each detected-twin update

The detected-twin perf contract now checks render deltas per update: a
catalog republication renders no picker, and stamping the first workspace
with a checking server, then that server reporting its OS, renders only
that workspace's pickers.

* test: give the structured chat fixture's owner stub the menu's resource host

The fixture replaces the whole worktree owner module with a stub, so the
menu readiness check's new resource-host export was missing and the
picker path threw before launching. The stub now answers both exports
with the scenario's owner host.

* Keep launch failures with one action owner on current menus

* Align Start work regression with its remote launch target

* Narrow refused launch outcomes in current contract tests

* Assert notified refusals in existing launch regressions

* Assert the refused keyboard launch receipt

* Narrow successful web runtime launches in tests

* Keep agent menu labels left aligned

* Keep merged launch reporting within existing checks

* Keep direct launch argument reads within the file limit
2026-11-07 19:18:39 -08:00
OrcaWinandOrcaWin 6b94c177f3 test(wsl): run the distro holder script with a 100ms poll and await its own notes (#39690)
The holder's script is the production text with pollSeconds=0.1; fixed 2.5s
'still running' windows become waits for the holder's blocked note or its
'sleep 1' wait on the requesting orcad, then a short several-poll window.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:18:11 -08:00
OrcaWinandOrcaWin 4feabd1518 test: cut ~20s of CI test time from codex app-server, --no-daemon shell and grid-serialize suites (#39687)
* test(pty): run codex --no-daemon shell cases concurrently

Each case still gets its own fresh shell and sandbox; spawning async lets
pwsh startups overlap instead of running back to back.

* test(daemon): skip raw-API serialize variants outside differential runs

Only the differential (old vs new build) I1 check reads variants 1 and 2;
a single-build replay compares variant 0, the production snapshot path.

* test(codex): shorten app-server start budgets and batch teardown races

Stand-ins arm in under 100ms on a loaded host, so a 3s start budget still
leaves wide margin; the 40 stdin-close/root-exit races run 4 at a time.

* test(codex): keep 5s start budgets for slow CI runners

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:18:04 -08:00
OrcaWinandOrcaWin ccb42eb7ed refactor(i18n): read render-path translations from useTranslate in plugins and skills (#39400)
Applies pnpm i18n:reactive-translate --helpers. Output is unchanged: t delegates
to translate() and helpers default the threaded parameter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:17:26 -08:00
OrcaWinandOrcaWin edea37f3ba refactor(i18n): read render-path translations from useTranslate in the source-control over-budget files (#39674)
use-ai reads useTranslate for its conflict-launch toast, and the
create-review header actions take the action model's `t`. Both files
would go over budget, so the recipe-save callbacks and the provisional
hosted-review provider inference move to their own modules first.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:16:31 -08:00
Kelvin Amoaba 19ea52fea5 fix(mobile): page updates when two shells fetch the same build, and stale cached generations (#39677)
* fix(mobile): share bundle read slots per connection and keep a waiting page update across relaunch

* fix(mobile): keep a page's update check across its document start

* fix(mobile): wait out a same-build update fetch and keep shared read slots from stalling

* fix(mobile): trust a waiting stage only when every asset is on disk at full size

* fix(mobile): count late window replies as connection activity

* fix(mobile): keep the launch sweep going when one host's stage is unreadable
2026-11-08 03:16:13 +00:00
OrcaWinandOrcaWin 35547956dd test: fake-clock the agent-session start backoff; drop the CLI owner-choice work-count suite (#39685)
* test(agent-session): jump the start retry backoff on a fake clock

The five-attempt cases waited 1.5s of real 100·2^n ms backoff each. Route the
backoff's promise delay through fake timers and jump it while real time still
passes for file and database work.

* test(cli): delete the owner-choice work-count suite

It asserted property visits, serialized bytes and call counts under spied
globals at 10,000 workspaces; owner election behavior stays covered by
index-workspace-owner-choice.test.ts.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:10:56 -08:00
OrcaWinandOrcaWin 88f452a665 test(e2e): follow the editor's Preview button in the paired HTML preview spec (#39686)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:10:16 -08:00
Brennan Benson 604e448255 fix(native-chat): keep text typed past a picked /fork (#39577) 2026-11-07 19:06:05 -08:00
OrcaWinandOrcaWin c61e1505f8 refactor(i18n): render the gutter menu in its owner test and read useTranslate there (#39675)
The cursor-owner test called MonacoGutterContextMenu as a plain function
and dug its action out of the element tree, which kept the component on
translate(). Render it instead, reading each item's action by label, and
convert the component.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:02:15 -08:00
Neil 7ab425dab0 perf(ssh): coalesce output longer for visible-but-unfocused remote terminal panes (#39660)
* perf(ssh): let orcad coalesce output longer for background-visible terminal streams

Adds capability-gated SetOutputCadence (opcode 20) and an initial subscribe
cadence. Background streams batch over 100ms instead of 5ms (64KB cap kept,
bytes unchanged); switching to focused, or output carrying a reply query the
view answers, flushes immediately.

* perf(ssh): report focused vs visible-background cadence for remote panes

The remote multiplexer advertises outputCadence and sends cadence changes only
after the host echoes it. Panes report focused only when visible and the
active split, resyncing on bind, visibility, focus and tab-activity changes.

* perf(ssh): resync output cadence after splits and update cadence test fixtures

* perf(ssh): add orcad output-cadence kill switch and shorten background window to 50ms

ORCA_DISABLE_TERMINAL_OUTPUT_CADENCE=1 makes orcad neither echo the capability
nor apply the background window. Only callers that retune cadence advertise it,
so other terminal subscribers keep their wire shape.
2026-11-07 19:02:12 -08:00
OrcaWinandOrcaWin ffe38b3883 refactor(i18n): read the notebook error fallback and copy button title from useTranslate (#39678)
IpynbViewer translates its invalid-notebook fallback at render instead
of inside the parse memo, so the memo still depends only on content.
CopyButton resolves its default title from `t` instead of a parameter
default.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 19:02:02 -08:00
Brennan Benson ecb350c8f8 Show each folder Source Control repo as its own card (#39277)
Each repo in a folder workspace's Source Control panel now gets its own card, so it's clear which repo a commits section belongs to.
2026-11-07 19:01:50 -08:00
OrcaWinandOrcaWin 845eddc84e test: cut ~70s of CI test time from agent-hooks helper and CLI restart-handoff suites (#39679)
* test(agent-hooks): drive Claude helper-kill transcript polls on a fake clock

The 1s transcript poll deadline made each waitFor sleep ~1s of real time.
Fake setTimeout/performance and advance the clock while file I/O stays real.

* test(orchestration): spawn the bundled CLI in the restart handoff test

Each of ~25 CLI subprocesses paid ~1s for a tsx loader start. Bundle the real
CLI once with the orcad CLI build and run it under plain Node.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 18:58:42 -08:00
Neil 6757dd6758 relay-edge: alias relay-contract subpaths to source in the local wrangler config (#39680)
Wrangler's alias does not rewrite subpaths and the package exports point them at dist/, so a
clean checkout could not run wrangler dev (or the object MVP) without a prior relay-contract
build, and a checkout with a stale build bundled it.
2026-11-07 18:58:03 -08:00