Repository navigation
Sync upstream/main to v1.4.241's cut point - #4
Merged
Merged
Conversation
…election (stablyai#33307) OpenCode model selection accepts per-major floors (1.x >= 1.18.30, 2.x >= 2.0.14; prereleases and 3.x refused) instead of exact version allowlists, so current releases launch with a picked model again. Fixes stablyai#26611. Supersedes stablyai#26683, stablyai#31985. Co-authored-by: ggbdpq <67929842+ggbdpq@users.noreply.github.com>
…switch (stablyai#31411) A CSI scan now stops at ESC/CAN/SUB (as xterm's parser does), so a hidden-startup carry ending mid-CSI no longer swallows the next OSC's introducer and leaks `104;255` onto the prompt. Fixes stablyai#31410. Co-authored-by: Neil <neil@stably.ai>
…t showing the old Done (STA-12043) (stablyai#33302) * fix(runtime): a pane's new process does not wear its previous run's Done (STA-12043) * fix(runtime): keep the superseded turn's segment and date process start at spawn request * fix(runtime): take the identity row's segment from the turn clients were shown
…ws while /side is shown (stablyai#33308) * fix(agent-status): keep a running Codex turn on paired and mobile views while /side is shown Codex's terminal title follows the thread it displays, so opening /side idles the title while the main turn runs. The paired/mobile session projection read that idle title, newer than the main turn's last hook, as the turn ending and published a title-only done row with no prompt. A Codex row whose hooks report the main turn running now owns the title interval; the turn's end still arrives by hook or rollout. Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-status): keep a Codex main turn waiting on approval through /side on paired views Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-status): leave restored Codex rows to the existing title rules Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-status): stop a running Codex turn at a PTY process replacement A replacement process on the same PTY id invalidates its predecessor's title-interval evidence; record when that happened so a predecessor's running Codex hook cannot outlive it. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…ns (stablyai#33309) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ne (stablyai#33288) Hermes 0.22's shared gateway: the status plugin reads pane identity from each session's own client env (scrub-safe aliases via terminal.client_env_passthrough) instead of the gateway's os.environ, so every pane reports its own status. Unsafe-to-edit configs fall back to main's plugin-only edit; SSH panes now get the scrub-safe aliases. Fixes stablyai#32709. Supersedes stablyai#33240, stablyai#33222. Co-authored-by: <+@users.noreply.github.com> Co-authored-by: <+@users.noreply.github.com>
…ach launch readiness (stablyai#28317) Pi's titlebar extension paints the idle title at session_start (plain Pi only, not OMP) so Pi-based harnesses that brand their own title pass worker-start agent_readiness. Fixes stablyai#28273.
… title (stablyai#33306) A hook-reported agent under an older shell title (e.g. zsh before Codex paints its title) keeps its agent status and session id, so mobile can open a fresh Codex chat; PTY titles now record when they were observed. Fixes stablyai#32030. Supersedes stablyai#32046. Co-authored-by: dorian-kwon <61652817+dorian-kwon@users.noreply.github.com>
…yai#33310) Codex native chat shows the existing approval card for MCP tool-call approvals (form-mode elicitations with no fields) instead of auto-declining them; Deny sends Codex's user-cancel reply so the turn continues. Other elicitations and turn-less requests are still declined. Fixes stablyai#25045. Supersedes stablyai#25988, stablyai#25046. Co-authored-by: u-ichi <82369+u-ichi@users.noreply.github.com>
…r it ends (stablyai#33272) Pi: a finished answer followed by Pi's own threshold compaction is announced (done/unread) when the compaction starts instead of waiting for it to end. Skipped when follow-ups are queued; the settle post still ends the row. Refs stablyai#33267 (idle-compaction case unchanged).
…e sleeps at the same time (stablyai#33283) * fix(runtime): a workspace sleep no longer fails when another workspace sleeps at the same time Sleeping two or more workspaces at once failed every one but the last with terminal_liveness_unavailable, so their terminals kept running. Each sleep asks the terminal host which PTYs are live; when a newer listing starts while one is in flight, the older answer is discarded as stale and retried once. Two sleeps leapfrog each other: each retry starts a listing that makes the other's stale, and the second retry gives up. A targeted read that a newer listing overtook now waits for that listing and uses its answer, which is at least as fresh as the read itself, instead of starting another listing. Lifecycle changes (a PTY spawning or exiting mid-listing) keep the single retry they had. The listing step moves into its own layer to keep the refresh within the file-size limit. Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): an overtaken PTY listing joins only a newer one that asked the same question A targeted read that a newer listing overtook adopts that listing's answer. That newer listing could have asked without foreground-process evidence, or waited less for slow hosts, so the read could get rows without the evidence it asked for, or fewer hosts than it would have waited for. It now joins only a newer listing with the same evidence option and a deadline at least as late as its own; otherwise it keeps its single re-list. Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): a PTY read with no deadline stops after one listing budget, however many it joins Each listing an overtaken read joined got a fresh 3 s when its caller set no deadline, so pollers starting listings faster than a slow SSH census finished could keep such a read waiting without end; before joining it gave up after two listings. The read now fixes one deadline up front (the caller's, or one listing budget from now) and every listing it joins shares it. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…l inherits (stablyai#33300) Codex native chat: follow-ups to a running goal turn are steered into it (turn/steer) instead of waiting, when the follow-up's model/effort match what the turn actually runs (newest handed-over submission, incl. ones rejected after their turn opened). Still waits while an earlier send is pending. Fixes stablyai#33056. Supersedes stablyai#33057. Co-authored-by: Nico Hu <296744606+niconicohu@users.noreply.github.com>
…stablyai#33313) * fix(terminal): keep Mac trackpad flicks continuous in fullscreen TUIs Chromium reports wheelDelta = -3 x deltaY for continuous devices, so a fast trackpad event crossed the 100-unit 'notched wheel' threshold and switched to the compressed, burst-boosted wheel curve mid-flick (2 -> 6 -> 2 reports per event). Classify the gesture instead: an off-120-grid wheelDelta marks a continuous device and the verdict sticks until the gesture goes idle. * fix(terminal): end a trackpad gesture when a Mac wheel notch arrives An on-grid event now continues the continuous gesture only with the trackpad's 3x wheelDelta shape and only shortly after off-grid input, so a notched wheel used right after the trackpad keeps its discrete feel. * fix(terminal): match wheel notches on the zoomed grid and require the trackpad ratio Chromium divides both deltaY and wheelDelta by page zoom, so a notch reports 120/zoom; derive the grid from the UI zoom. An on-grid event now continues a trackpad gesture only when 3 x |deltaY| is close to |wheelDelta|, so a Windows/Linux notch (100 px per 120) right after trackpad input stays discrete. * refactor(terminal): classify trackpad gestures without zoom or a notch grid Keep the base rule (a small wheelDelta is continuous) and extend it across the gesture: a large event within 300 ms of continuous input stays continuous only while it keeps Chromium's continuous delta shape (wheelDelta about 3x deltaY on macOS, 1x on Windows/Linux). Both deltas scale with zoom, so the shape check needs no zoom factor; notches never match it. * fix(terminal): only small wheel events extend the trackpad gesture window A notch that happens to match the continuous delta ratio (40 px per 120 on macOS) is now captured for at most 300 ms after trackpad input instead of renewing the window indefinitely. * fix(terminal): keep the whole trackpad gesture continuous through long momentum Restore the approved rule where every continuous event extends the gesture window, so a hard flick whose momentum stays above notch size for over 300 ms keeps its 1:1 row distance. Pins that with a long-momentum fixture.
…ment process boots (stablyai#33312) <!-- orca-pr-loc --> <!-- Programmatic LoC summary. Do not edit by hand; rewritten on every commit. --> | | Files | Added | Deleted | Net | | :--- | ---: | ---: | ---: | ---: | | Test | 1 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$279 | 0 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$279 | | Prod | 1 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$58 | $\color{#cf222e}{\Huge{\mathbf{−}}}$13 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$45 | <!-- /orca-pr-loc --> ## ELI5 When we restart a relay server during a routine rollout, computers that were offline during the rollout still have that server written down as "their" server. If one of them comes back during the ~45 seconds while the replacement server is starting up, the director currently tells it "your server is unavailable, try again" over and over, instead of just sending it to another server. This change lets the director send it elsewhere, but only when it has proof that the old server process is really gone. ## What Changed **Before (production, 2026-10-24 23:43Z, cell production-gce-c15):** during a same-capacity roll the cell is roll-isolated, drained, then its single VM is replaced. A desktop host that was offline during the drain reconnected in the gap between the old process stopping and the new one being ready. The director refused it for ~26 s (`assignment rejected route=assign lane=placement hinted=true reason=relay_home_cell_unavailable cause=not_ready`, x5, plus `route=resolve ... cause=unheard`, x2). It got a grant somewhere else only once the new process was live. **After:** while the replacement process is starting up (`not_ready`), the same host is moved to another cell on its first try. A host on a roll-isolated cell can be moved off even though the cell is not live, as long as the process heartbeating for the cell *started after the roll isolated it* (`relay_cell_runtime.started_at > relay_cell_admission.roll_isolated_at`), its heartbeat is fresh, and (for connection-capped cells) its latest heartbeat reports zero connections. Both lanes that move an isolated host apply it: the narrowed isolated-replacement path (`isolatedIncumbentMayMove`) and the all-rows path it falls back to. Together these serve assign and resolve, because resolve hands a non-live cell to `assign`. "Roll-isolated" is the existing predicate: `migration-only` with a roll stamp younger than 2 h. **Still refused (residual):** the `unheard` window, when the old process's heartbeat is past the 45 s TTL and the new process has not been heard yet. On c15 that was about 5-10 s. Nothing proves the drained sockets are gone there, so the refusal stays, and the client's retry recovers once the new process heartbeats. Also unchanged: an ordinary readiness dip, a `migration-only` cell without a roll stamp, a stale (over 2 h) stamp, and a new process that later goes unheard. Fence handling is untouched. ## Why The refusal exists because moving a host off a cell we cannot fully trust could leave the host's old socket served by the old process while its clients go to the new cell. Until now, the only proof the code accepted was an operator-written fence. This adds a second proof that costs no operator step: - **A new incarnation means the drained process is gone.** Each process mints a fresh incarnation UUID and `startedAt` at boot (`cell-heartbeat-client.ts`), and the director rejects a heartbeat with an older `startedAt` once a newer one is recorded. Each cell VM runs exactly one relay container (`docker run --name orca-relay --restart always`, with stale containers force-removed at boot). The cell MIG uses `replacement_method = RECREATE` with `max_surge = 0` (pinned by a Terraform assert), so the old VM is deleted before the new one is created. A same-VM container restart also produces a new incarnation and is just as safe: Docker restarts only after the old process exits, and that exit closes all of its sockets. - **Whatever the new process holds, it can enforce.** It is heartbeating (fresh), and on capped cells it reports no connections at all. A host that attaches between two heartbeats carries the old epoch, so the epoch bump this move writes makes the cell refuse it or close it with 4409. That check is the same live `verifyCellAssignment` / control-renewal read the existing live-isolated path relies on. - **Clock skew** between the cell's `startedAt` and the director's stamp is covered by the zero-connections check on capped cells only: a drained process that only *looks* post-stamp still holds its sockets, so it is refused. Uncapped cells report no counts and get no such guard; they already move off without a fence on the dead-cell path today, so this adds no new exposure there. Alternatives considered: (a) adding an incarnation column to `relay_assignments`: a schema change for no extra proof. (b) Honouring any not-live roll-isolated cell: that drops the proof. (c) Having the roll write a fence for the `unheard` window: the only fence driver refuses enabled cells, a fence is a MIG resize to 0 that would fight the roll's own apply, and the window is a few seconds the client retry already absorbs. ## Linked Issue N/A (internal production incident, 2026-10-24 c15 roll). ## Visual Proof N/A: director placement logic only, no UI. ## Testing - [x] Automated tests added: `cloud/apps/relay/src/assignment-roll-replaced-cell.test.ts` (18 cases; the redial cases run for both hinted assign and resolve): - not_ready with an incarnation started after isolation: re-placed, epoch bumped. - Refused as before: not_ready with the pre-isolation incarnation, with reported connections, after the new process goes unheard, with a stale stamp, on an ordinary unstamped readiness dip, and on an unstamped migration-only cell. Also refused: the unheard window between the old and new process. - One case per lane. The narrowed path's cross-region move fails if only the narrowed-path change is reverted. The all-rows path's move, forced by units no lease backs, fails if only the all-rows change is reverted. - [x] Full relay vitest suite, `--maxWorkers=2`: 130 files / 1344 tests passed, 39 files (201 tests) skipped. The Postgres-backed suites skip locally (no `ORCA_RELAY_TEST_POSTGRES_URL`); CI runs them. - [x] `pnpm typecheck` in `cloud/apps/relay`. ## Review ## Agent skill upstream boundary - [x] Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation. ## Notes Backwards compatibility: no schema, wire or RPC change; old directors keep refusing as today. Performance: the new query runs only when a host's home cell is roll-isolated and not live; the general sticky hot path is unchanged. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives) - [x] Before/after screenshots or videos attached for UI changes, or `N/A` with reason - [x] Self-reviewed for correctness, security, and performance - [x] Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A) - [x] `pnpm lint`, `pnpm typecheck`, `pnpm test`, and `pnpm build` pass (or CI will cover; local preferred)
… mobile checks (stablyai#33318) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…in (stablyai#33297) Antigravity usage: when agy's read times out or fails while showing its interactive browser sign-in prompt, Orca marks it signed out and skips automated re-reads for 1h (manual refresh still bypasses), instead of opening a new sign-in page on every poll. A valid reading always wins; fast-exit signed-out reads poll as before. Fixes stablyai#26484.
* fix(editor): add bounded Zig syntax highlighting Recognize .zig files and load the existing pinned Shiki Zig grammar through the lazy TextMate provider. Map its scopes to stock Monaco theme categories while preserving the shared tokenizer state and per-line bounds. Keep .zon and formatting outside this lexical-only change. Reuse the optional scope-mapping hook reviewed in Haskell PR stablyai#25411 and its refreshed candidate 12908d0, retaining the original contribution credit from stablyai#25315. Ship the existing grammar package MIT notice in renderer public assets for desktop and web. Requested by @thinkAfCod in issue stablyai#11313. This addresses highlighting only; it does not close the formatting portion of the issue title. Co-authored-by: davidwis <davidwis000@gmail.com> * fix(build): serve Zig grammar notices through allowed assets Move the unchanged Shiki notices beneath assets/ and reference both files with relative HTML metadata links. Preserve reverse-proxy prefixes and let the existing projection and serving allowlists accept the browser client. Do not expand either allowlist. Exercise real Vite output, projection, manifest validation, and static HTTP serving at root and /orca paths. Follow the relative-assets notice strategy used by the coauthored Haskell adaptation and retain its contribution credit. Co-authored-by: davidwis <davidwis000@gmail.com> * test(editor): verify Zig source and diff highlighting * chore(editor): drop Zig grammar notice assets Zig grammar comes from the existing shiki dependency (already shipped via syntax-highlighter's bundled-language loader), so no separate notice is needed. --------- Co-authored-by: davidwis <davidwis000@gmail.com>
… hooks (stablyai#33274) The Windows boundary step's managed-hook stdin test bounds each hook at 10s to catch launchers that block reading stdin. Its first encoded-PowerShell launcher was also the worker's first Windows PowerShell start, which took 5.7s on a passing run and 15.3s on a failing one before exiting 0 by itself. Run that launcher once before timing so the bound measures hook behaviour, and name the command when the bound trips.
…ked in (stablyai#32320)" (stablyai#33304) * Revert "fix(terminal): a file link opens in the workspace it was clicked in (stablyai#32320)" This reverts commit 359fec1. * test: drop redundant openFiles cast restored by the revert
…listings keep overtaking it (stablyai#33331) Co-authored-by: Claude <noreply@anthropic.com>
…yai#33281) * fix(terminal): keep keys typed before a pane's PTY exists * fix(terminal): hold pre-spawn keys only in panes with no startup work * fix(terminal): no pre-spawn hold for live-entry resumes or main-started panes * fix(terminal): keep the deferred-split hold exactly as before * fix(terminal): drop held keys if a resume or startup work appears before the bind
…Enter (stablyai#33332) Claude AskUserQuestion with option previews: Orca's ask answers now send digit (focus wiggle for option 1 with a note), optional `n`+note, then Enter, since a digit only moves the highlight in Claude's preview layout. A bare digit on a preview question no longer clears waiting. Fixes stablyai#16865. Co-authored-by: Frederic Barthelemy <209712+fbartho@users.noreply.github.com>
…lock in the noise case (stablyai#33329)
…blyai#33333) * test: run the terminal-retirement SQLite fixture's suites under Node The acknowledged-tab retirement fixture opens profile-state SQLite, but the runtime scan only sees direct imports, so its four suites ran under Bun. On macOS Bun's node:sqlite is the system SQLite, which cannot open a closed WAL database read-only, so the quit-flush durability case failed on every local macOS run. Naming the fixture as a SQLite harness runs them on Node, the runtime the product ships. * test: run every suite that opens profile-state SQLite under Node Tests that import the profile-state SQLite authority directly ran under Bun, whose macOS node:sqlite is the system SQLite. Listing the authority as a SQLite module sends them to Node with the other SQLite suites.
…ts parent's turn (stablyai#33645) Antigravity automations no longer complete (and close their tab) when an in-process invoke_subagent subagent reports back: once a conversation launches subagents, hooks from other conversations without user input are ignored until the parent's own fully idle Stop; a user-started conversation (carrying lastUserInput) clears the marker so a relaunched agy still gets status. Fixes stablyai#17650
…lds an unacknowledged batch (stablyai#33639) Fixes STA-11980 Fixes STA-11631 Supersedes stablyai#29006
… it was started in (stablyai#33659) Claude account-switch restarts now pass the folder the restarted shell opens in (tab start folder, else workspace), so stablyai#33527's `cd <start folder> &&` resume prefix applies and a session started in a subfolder resumes there. Codex account restarts benefit the same way. Refs stablyai#31545 Supersedes stablyai#32033 Co-authored-by: ASH <7201776+asunghong@users.noreply.github.com>
…d work inside pages (stablyai#31859)
* feat(agents): store each agent's permission itself instead of typing flags into Arguments Terminals and new chats read one stored choice per agent (Use the agent's own settings, Ask for approval, Accept edits, Approve for me, Full access). Orca adds the flag at launch; Arguments hold only the user's own text. A one-time move lifts Orca's flags out of saved Arguments. Older clients still see and write the flag as part of Arguments; the host translates. * fix(agents): say the all-agents switch resets agents set separately; keep primitives unstyled * test(agents): the one-time move returns every launch-profile field * Fix permission carrier ownership and surface-specific defaults * Preserve uncertain permission operands and name the option inventory * Check env entries without indexing typed agent maps * Combine Chat permission capability imports * Use folder execution-host platform for permission environment * Preserve launch map replacement and acknowledge permission saves * Keep permission feedback fallbacks statically discoverable * Provide preload platform to Agents settings render tests * Preserve Gemini approval arguments under Full access * fix(settings): retain complete environment edits through save outcomes * fix(settings): narrow local failure scope and preserve host messages * fix(settings): retire argument drafts after acknowledged saves * fix(settings): keep Goose environment editable after reset * fix(settings): show resolved arguments for legacy hosts * Preserve pending environment resets and bound launch settings work * Use agent permission choices for new chats * Let Claude resolve chat permissions from its own settings * Keep optional settings fallback in repository metadata reads * Consolidate permission report imports * Update permission choice contracts for own settings * Read repository visibility defaults through the raw settings fixtures * Match existing translated Agents settings labels * Update readback and legacy host test expectations * Align Chat behavior tests with host permission capability * Fix permission compatibility and host-owned descriptions * Prepare whole Environment edits and retire unchanged drafts * Handle null explicitly in permission report decoder * Keep Environment settings transitions in an acyclic module * Update raw settings reader test fixtures * Place test fixture safety notes on assertion starts * test: pin permission settings work and recovery contracts * test: type permission settings work fixtures * test: cover migrated permission inputs and captured CLI grammar * Publish permission reports and reuse host capability state * Combine mobile option state React imports * Honor mobile status feed capability for permission reports * test: preserve typed permissions in WSL Claude restarts * Correct permission report child and fixture type contracts * Delegate older-host chats to explicitly selected own settings * Avoid rebuilding live ACP option catalogs * test(chat): place cross-boundary permission contracts in integration project * Preserve existing chat capability gates and complete report test fixtures * fix(chat): preserve newer Claude startup permission reports * test(chat): clarify startup report fixture provenance * Show reported permission modes in chat menus * Keep reported permissions available after chat mode picks * Remove obsolete guard from concrete permission selection * Report the installed approval policy for ACP chat menus * test: keep accepted mobile mutation fixture on current fence * test: cover installed ACP approval report for own chats * test: align capability scaling contract with concrete permission menus * Ship required permission help in English runtime catalog * Adapt permission persistence test to shared menu
… state files (stablyai#20937) (stablyai#33662) Orca CLI commands inside a sandbox that blocks chmod (e.g. Claude Code's Bash sandbox) no longer fail with a misleading "file is invalid": the pre-read hardening of existing secure files ignores EPERM/EACCES/EROFS; writers still create files 0600. Fixes stablyai#20937
…tablyai#33532) * ci(wsl): rerun a WSL2 lane job once when its hosted runner freezes * ci(wsl): pin the retry to the lane workflow and keep a 30 min job cap
…default agent (stablyai#33660) Kiro's V3 engine (default from Kiro CLI 3.0) now reports status in Orca: Orca installs a global hooks file under KIRO_HOME/hooks (covering the built-in default agent, local and remote, never overwriting user files) and recognizes V3's PascalCase hook events. Fixes stablyai#31577 Supersedes stablyai#24937 Co-authored-by: Dongho Lee <126236161+LDH1103@users.noreply.github.com>
…oken (stablyai#33656) After agy silently refreshes its Google token (the new credential has no id_token), Orca still matches the saved Antigravity account by auth method + refresh token instead of refusing the launch with "native Antigravity account changed"; the vault accepts such refreshed snapshots while still rejecting one whose id_token names a different account. Fixes stablyai#31579 Supersedes stablyai#33204 Co-authored-by: biojuho <258838639+biojuho@users.noreply.github.com> Co-authored-by: Manan <100475418+thefrikidude@users.noreply.github.com>
… has no 5h/weekly window (stablyai#33655) Claude Enterprise seats (null 5h/weekly windows, limit in spend/extra_usage) now show their spend cap as a monthly usage bar in the status bar chip, tooltip and account switcher instead of an empty meter. Fixes stablyai#31061 Supersedes stablyai#31065 Co-authored-by: Frank Bernhardt <275327+frank-bee@users.noreply.github.com>
…hem after the tab closes (stablyai#31602) * Chat renames are saved as the chat's name, so Session History shows them after the tab closes Renaming a native chat tab only changed that window's tab. Session History, phones and other windows read the host's saved name, so the rename vanished from History once the tab closed or Orca restarted. A rename now goes to the host that owns the chat (agentSession.rename) and is saved as the chat's one name, the field History, tabs, sidebars and phones already read. The record remembers that the user chose it, so automatic naming never replaces it. A window's pre-upgrade tab rename is uploaded once and only fills a name Orca chose. Hosts without the new capability keep the old tab-only rename. Every native agent's History row now shows the chat's name once it has one. * Keep saved chat names consistent across readers and reconnects * Carry qualified chat names into cached readers * Reuse the history recorder context across platforms * Use recorded chat ownership for legacy name transfer * Transfer legacy chat names only from known catalog ownership * Correct recorder path matching and History subscription order * Require complete evidence for bridged parity exclusions * Preserve sparse array lengths in complete recording comparisons * Initialize History observation before loading workspace context * Integrate measured History recordings and scoped parity evidence * fix chat naming retries and certify both replay modes * fix ambiguous chat rename labels after navigation * preserve chat rename intent across tab updates * type dashboard snapshot fixtures without assertions * fix: align chat name observation with store contracts * test: update chat name consumer fixtures * test: distinguish sender naming metadata from status * Preserve saved Activity chat names across tab focus * Clarify Activity tab projection identity * Remove package-manager lockfile churn from main merge * fix(runtime): validate tab property edits before saving chat names * fix: refresh History ownership after conversation clear * fix: commit History request identity before refresh effects * Fix History scan scope typing and integration test placement * test: cover saved chat name reader contracts * test: make chat naming fixtures deterministic
…i#33643) * Bound cwd permission probes and share pending enumerations * Skip non-macOS cwd permission probes during session creation - Prevent stalled network paths from consuming filesystem workers
* Fix notification bell layout and isolate Vite tsconfig resolution * Move Vite tsconfig fix out of notification bell PR
…33675) * test(native-chat): split startup report coverage below line limit * test(native-chat): keep startup status reads synchronous * refactor(native-chat): move status child fields below line limit * test(native-chat): annotate exported startup mock types * test(chat-rename): import launch persistence from its current path
…keep stall telemetry (stablyai#33688) Reverts stablyai#29133 except its daemon async-I/O stall telemetry, so we can measure how often stalls happen on official Node before committing to a patched runtime. The macOS terminal host goes back to the official Node 24.22.1 download and the daemon protocol back to v51; no release or hourly build published v52.
…size rule (stablyai#33584) * fix(terminal): give the window and main's copy the daemon's ConPTY resize rule Every PTY a Windows machine owns is ConPTY, WSL shells included, and ConPTY repaints its own grid after a resize. The window applied xterm's ConPTY model only to native (non-WSL) panes, and main's copy for reveals and phones never did, so growing either pulled history into ConPTY's grid. Decide windowsPty from the PTY's owner backend everywhere, keeping the native-only cursor, CJK and keyboard workarounds behind isLocalNativeWindowsConpty. * fix(terminal): keep main's copy of an SSH relay PTY off the ConPTY model before its record exists Main's copy is built on the first byte, and a restored or adopted relay PTY can stream before its record carries a connection id.
* Guard managed server restarts with host work reservations * Protect legacy server update requests with host admission * Reserve chat-safe restarts in SSH and WSL server updates * Keep activation host fixtures within the module line limit * fix(orcad): preserve session queue timing during admission * Explain chat-safe update deferrals and superseded restarts * Clarify managed server Force upgrades and retry instructions * Separate chat entry delegates from conversation creation * Report child work through main's child evidence in the restart drain test * Drive main's snapshot-room tests through the restart reservation Main's room tests deployed over a serving incumbent with a census that has no chat work count and no restart admission, so the update deferred before the room probe ran. Give them the same idle census and slot admission as the other activation tests, and pin the probe before the reservation instead of before the recount it replaced. * fix(native-chat): an update keeps waiting on a chat start after its conversation is closed The restart check counted a start only while its conversation stayed open, so an idle close during a stalled start let a managed update through. Every tracked attach, create, start and open now counts as restart work in the same tracker that counts the session queue. * fix(native-chat): keep the structured session view within its line limit once formatted Main's copy sat at 400 lines only because one line was left unformatted; the merge's formatter pushed it to 401. Inlining the one-use question list keeps it at 400 with identical behavior. * fix(orcad): a recovery stop request stops the server; only an older client's empty request waits for idle Stopping a slot and restarting it for an older client's update were both an empty .orcad-stop-request file, so routing that file through restart admission let a crash recovery, stranded-setup release or rejected-candidate rollback leave the server running. New clients now write "stop-now" into the request (renamed in whole), which stops at once as before; an empty or unrecognized request takes the chat-safe restart, and a deferred restart logs why. Also gives the restart admission activation fixtures the now-required recount. * docs(orcad): say a directory at the stop-request path is refused, not restarted * docs(orcad): the plain stop request's comment states both of its meanings * style: format the restart admission files for the format check * test(wsl): count the incumbent's recount bridge after the reservation's * fix(orcad): a Windows stop request retries its rename while antivirus holds the new file Renaming the just-written stop-now request can briefly fail with EPERM, EACCES or EBUSY on Windows; the stop now retries those with the same bounded delays as record-publish instead of answering SIGNAL_FAILED and leaving the server up. * test(orcad): a real Windows host stops on the slot's stop-now request and relaunches * test(orcad): recovery stops a real server whose restart admission refuses * test(orcad): the recovery-stop cell tunnels over the cell's SSH connection * test(orcad): the recovery-stop cell names itself in the CI log * fix(settings): a deferred WSL update shows its full reason below the row * test(orcad): fixtures pass releaseIncumbentAdmission; the census test calls its own method * test(orcad): the capable-server census in the fence test reports idle chat work * Record server chat restart offers and desktop creation history * Offer interrupted chat recovery per managed runtime * Ship the remote chat resume action labels in the runtime catalog * Update removal contracts for desktop chat history cleanup * Scope remote chat recovery to each server occurrence * Preserve recovery choices and uncertain continuation outcomes * fix: preserve uncertain restart action outcomes * Fix restart recovery CI imports and fixtures * test: align resume assertions with unconfirmed outcomes * test: bound restart recovery work across scaled populations * fix(native-chat): title the remote resume dialog with the restart The dialog can appear out of nowhere when another desktop updates a shared server, so its title now says what happened: "<machine> restarted".
…e host (stablyai#33680) * fix(ssh): retry over system ssh when ssh2 shares no algorithm with the host ssh2 supports fewer algorithms than OpenSSH. A host that offers only certificate host keys (or only kex/cipher choices ssh2 lacks) fails the handshake with "Handshake failed: no matching ...", even though the system ssh binary connects fine. Treat any such negotiation failure as a client capability gap: probe system ssh once, and if that also fails, report its error, since ssh2 can never reach the host. Fixes stablyai#33582 Co-authored-by: Kyou12138 <kyou12138@gmail.com> * fix(ssh): keep hosts pinned in Orca's key store on ssh2 after a negotiation failure System OpenSSH never reads Orca's own host key store, so an on-path impostor could advertise algorithms ssh2 lacks to steer a pinned host onto system ssh and around its pin. Only fall back when Orca has no stored key for the endpoint. Co-authored-by: Kyou12138 <kyou12138@gmail.com> * fix(ssh): only the current attempt records an Orca host key pin A superseded attempt that finished its trust read late could overwrite the current attempt's pin marker, letting a negotiation failure on a pinned host fall back to system ssh. --------- Co-authored-by: Kyou12138 <kyou12138@gmail.com>
…ps propagation (stablyai#33679) * fix(link-actions): dismiss the link chooser when an outside click stops propagation * test(link-actions): wait for Radix to arm before the outside click
* Add custom font family setting for native chat * Preserve custom chat fonts in autocomplete * Preserve IME composition in font autocomplete
…al history (stablyai#33681) * fix(ssh): don't refuse a host's move over a pane that saved no terminal history A pane with an empty inline buffer, a deleted snapshot, or a zero-byte snapshot has no history to lose, but the move's projection filed it under "saved terminal history Orca could not read" and refused the whole host. Tell absent snapshots apart from unreadable ones and move the former without history; unreadable history still blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ssh): keep looking in the fallback root when a scrollback snapshot is empty A zero-byte snapshot in the primary root returned 'absent' without checking the fallback root, so a pane whose history lived there moved without it. Also check ENOENT inline rather than importing a window staging helper. * test(e2e): seed unreadable relay scrollback as an over-limit snapshot A missing snapshot file now means the pane saved no history, so the leave-behind spec needs history that exists but cannot be read. --------- Co-authored-by: Younghwan Chae <chyohw97@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…blyai#33700) The headless CLI bundle resolved jsonc-parser to its UMD build, whose relative requires fail beside the single-file bundle, so `orca agent hooks status|on|off` crashed with "Cannot find module './impl/format'". Every orcad bundle now shares one plugin list, and the build refuses any bundled UMD module. Fixes stablyai#33592
…tablyai#33701) * fix(orcad): drive Android emulators from headless orca serve hosts orcad never installed an EmulatorBridge, so every `orca emulator` verb failed with emulator_no_active once headless serve moved to orcad. The emulator modules now read host paths and HTTP through the host ports instead of importing Electron, and orcad installs the bridge and stops its managed sessions on shutdown like the desktop does. Fixes stablyai#33650 * fix(orcad): bound emulator teardown inside the shutdown deadline * fix(orcad): keep idle exit from stopping Orca-started emulators; update emulator skill scope * fix(orcad): count only still-running Orca-started emulators as idle-exit work * fix(emulator): prune managed sessions only on a successful adb census * fix(emulator): release a pruned device's stream and never prune a record reattached mid-census
…a fresh v52 daemon (stablyai#33705)
Takes the line at bd2f463, the commit on upstream/main that v1.4.241 (2026-10-26) was cut from: 1709 commits past v1.4.229's cut point. Why the newest release rather than one about a week old, as SYNC.md advises: the gap held a high-severity Electron advisory (43.8.1, GHSA-jr5w-w6x2-84p9, the compromised eMudhra intermediates), DOMPurify and KaTeX advisories, and Codex config.toml written world-readable. Carrying those as cherry-picks onto a week-old base would have meant reconciling them again on the next sync. Settledness: the one revert landed after the cut (stablyai#33823) targets stablyai#30914, which is outside the window. Open upstream bugs that come with this merge, none with a fix on main yet: - stablyai#33608: Claude Code / agy panes left in canonical mode, so Enter does nothing (reported on macOS, 1.4.238-1.4.240; upstream cannot reproduce). - stablyai#33379: agents launch without a permission flag despite Full access (1.4.239-1.4.240; upstream cannot reproduce). ERLI's default is to ask. - stablyai#33684: a Claude Code pane renders corrupted after switching tabs (since 1.4.235); workaround: terminalHiddenDeliveryGate=false. - stablyai#31767 is fixed by stablyai#30448, which is inside this window. What the resolution carried across: - Agent permissions are now a stored choice (agentPermissionDefault, stablyai#31315) rather than default argument text, defaulting to Full access. The yolo-default gate on DEFAULT_TUI_AGENT_ARGS/ENV stays, since web preferences merge them into stored args before migration lifts bypass flags into a choice; the new default itself is gated in a follow-up. - electron.vite.config.ts: upstream's DARK_BUILD_DEFINES blocks are wrapped in withErliBuildDefines; resolveBuildSourceCommit comes through erli-defines, which re-exports it, so the file gains no lines. - skills.ts: upstream added local bundled-skill handlers after the cloud ones; only the cloud handlers stay behind share-skills. - tsconfig.cli.json shrank from 304 lines to 20; the fork's include of build-constants.d.ts is carried onto the new file. - pty-input-forward.ts: the input generation is captured after upstream's new pre-ready capture, which never reaches the PTY. - pty-connection-pty-exit-teardown.spec.ts: upstream edited the five tests the fork replaces; they stay removed (the fork's live in pty-connection-failed-local-exit.test.ts). - Node runtime pin and node-server-tests.yml take upstream's copies; the fork's versions were cherry-picks of upstream's own change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 041baf3)
…ion choice Upstream now launches agents from a stored permission choice (agentPermissionDefault, stablyai#31315) that new profiles seed as Full access. The merge gated that default to 'own' when yolo-default is compiled out (contrary to its message, in the merge itself rather than a follow-up); these tests pin it: a new ERLI profile launches Claude and Codex with no bypass flag, and an explicit Full access still works. Also: the five upstream tests the fork inverts stay out of pty-connection-pty-exit-teardown.spec.ts, with the imports only they used; and the build-version canary moves to the 1.4.241 base. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
Moves ERLI's Orca from upstream v1.4.229 to v1.4.241, the newest release, so the security fixes upstream shipped since then (above all Electron 43.8.1) arrive as one merge instead of a pile of cherry-picks.
What Changed
Merges
upstream/mainatbd2f46359d, the commit v1.4.241 (2026-10-26) was cut from: 1709 commits. Upstream's release commit is cherry-picked so builds are stamped2.0.<run>-erli-upstream.1.4.241.Security fixes this brings in:
webPreferences, and Chromium/V8 backports. Linux GTK/Wayland crash fixes come with 43.8.0.config.tomlcreated owner-only (fix(codex): create Codex config.toml files owner-only stablyai/orca#31228); before, it was readable by other users of the machine and carries MCP server tokens.What the fork had to carry across (details in the merge commit):
agentPermissionDefault, Agents: store each agent's permission itself; terminals and new chats read it stablyai/orca#31315), and upstream defaults new profiles to Full access. Withyolo-defaultcompiled out, ERLI now defaults it toown: every agent launches with no bypass flag and asks. Existing profiles migrate from their stored arguments, which in ERLI carry no bypass flags, so they also land onown.electron.vite.config.ts,skills.ts(upstream added local bundled-skill handlers; only the cloud ones stay behindshare-skills),tsconfig.cli.json(304 → 20 lines upstream), the terminal input generation, settings navigation and the sidebar host selector.updater-prerelease-feed.tsnow matches the fork's release repo instead of a hard-codedstablyai/orca.Why
The newest release rather than one about a week old, against
SYNC.md's advice, because the gap held a high-severity Electron advisory; cherry-picking it onto a week-old base would mean reconciling it again on the next sync.Settledness. The one revert after the cut point (stablyai#33823) targets stablyai#30914, outside the window.
Known open upstream bugs accepted with this merge:
terminalHiddenDeliveryGate=false.Fixed by this window: stablyai#31767 (
terminal_pane_owner_changed), via stablyai#30448.New outbound hosts in the window:
auth.kimi.com(Kimi agent sign-in) anddl.google.com(Antigravity extension), both user-initiated;Linked Issue
N/A — fork maintenance.
Visual Proof
N/A — no fork UI change.
Testing
oxlint(0/0),audit:code-quality:native,audit:code-quality:type-aware,check:max-lines-ratchet,verify:skill-bundle-manifest,check:node-runtime-pinpnpm test:node: 13 501 files pass. 75 failed under load. 56 of them fail identically on a pristine checkout ofbd2f46359d. The other 19 were a stalemobile/node_modulesand timeouts under load, and pass when rerun alone.2.0.9002-erli-upstream.1.4.241, Electron 43.8.1) and launched under xvfb with an isolated profile: the updater checksERLI-SA/orcaonly, there is no traffic to stablyai, and there are no errors.ERLI releaserun after merge.AI Disclosure
Merge resolution and fixes by Claude Opus 5.5 (Claude Code), reviewed by the author.
🤖 Generated with Claude Code