Repository navigation
Conversation
…e drain (stablyai#23001) * perf(push): keep retention sweeps from overlapping * perf(push): drain a saturated retention sweep instead of idling out the tick The overlap guard on the shared prune timer removed a side effect the sweeper had been relying on: overlap was the only thing that let a backlog exceed the 50-batch-per-call cap inside one 60-second tick. With the guard, a sweep that spent its whole budget went idle for the rest of the interval, so a large backlog drained far slower exactly when retention matters most. The timer is now a chained setTimeout rather than an interval. `deleteInBatches` reports whether it exhausted its batch budget, `prune()` returns `{ deleted, saturated }`, and a saturated sweep is rescheduled immediately. The connection gate hands a freed slot to the longest waiter, so one serial sweeper looping back to back still parks a single statement ahead of a worker claim: claim latency keeps the value the guard bought while the maximum drain rate returns to what it was before. The loop is self-limiting and stops once the backlog clears. A sweep that has not settled a full interval after it started now logs `orca_push_prune_overdue` with its target. Admission waits have no timeout, so a lost slot release could previously wedge retention permanently and silently. Chaining makes the overlap guard structural, so there is no flag to scope. The two single-DELETE sweeps state through `unbatchedSweep` that they have no batch budget to exhaust, which keeps the immediate-resume path readable as delivery-only. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…#23296) The WSL "is this path gone?" probe decided a path was missing by matching GNU coreutils' exact wording, `stat: cannot statx ...`. BusyBox writes `stat: can't stat ...`, so on an Alpine-style distro a successful orphaned worktree delete was still reported as a permanent failure, on every retry. Match only the trailing strerror text, which is POSIX and already pinned to English by the probe's LC_ALL=C. Permission failures still report failure.
* ci: scope orcad smoke and parallelize Linux package formats * ci: validate packaging when its copy dependency changes --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
* perf: avoid rescanning partial notebook output frames * perf(notebook): stream bridge frames and skip the unused size accounting The reader buffered every record of a chunk before delivering the first one, and asked the framer for byte accounting it can never use. An unbounded line limit cannot reject, so the per-segment `Buffer.byteLength` and the rejection-prefix retention were pure overhead for the notebook and Codex readers; both are now skipped once, behind a hoisted check. Frames are handed to the consumer as each line completes, so the first output of a chunk paints without waiting for the last. The dropped buffer only ever preserved a trailing partial record across a consumer throw, which cannot help: that throw leaves the stdout 'data' listener and takes main down with it. Rejections are no longer discarded either — the bridge keeps fd 1 to itself, so an unreadable line means the frame channel is damaged and now says so. Tests move into notebook-kernel.test.ts beside the reader's existing coverage, and add the never-terminated record and a guard that no record bytes are measured when no limit applies. Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…23293) * fix(kimi): don't crash if config.toml is deleted mid-write writeConfigToml checked existsSync(configPath) then called statSync(configPath) to preserve the file's mode, with no error handling in between. If the file was deleted in that window (e.g. a concurrent uninstall), statSync threw ENOENT and the exception escaped install()/getStatus() uncaught. Now a missing-file stat during that race is treated the same as a missing file at the check: fall back to the default 0o600 mode and continue the write. Any other stat error still throws, preserving the existing mode-read-failure behavior. * fix(kimi): use isDefinitiveAbsence for the config delete-race check Reuse the repo's canonical absence check instead of a hand-rolled ENOENT comparison, per review feedback on stablyai#23293. isDefinitiveAbsence also covers ENOTDIR (an ancestor directory replaced by a file), which the inline check missed but is equally "the config is definitively not there."
…hadow-xs (stablyai#23307) The inline AI-note draft card in the diff view used a fourth, hand-rolled box-shadow tier with raw rgba values instead of the documented shadow-xs token, so it didn't track theme/token updates like the rest of the UI. Restated the value under `.dark` too, since it shares selector specificity with `.orca-diff-comment-popover`'s dark shadow later in the file and would otherwise lose the cascade to that unrelated rule.
…2973) * perf(mobile): coalesce stalled connection log persistence * fix(mobile): bound connection-log writes and flush the log before the app suspends The coalescing pass counted a pending persistence attempt per append and then burned that whole budget on unblock. With failing storage, 500 appends during a stall released ~1000 back-to-back `setItem` calls — and slow storage and failing storage are the same device condition, so the amplification fired in exactly the scenario the coalescing was for. The counter is gone. A single `dirtyHosts` flag replaces it: the host's revision always holds the newest entries, so counting appends bought nothing but writes. The loop re-reads the revision after each save, so a stall costs the in-flight snapshot plus one attempt at the newest one, whatever the append count. That also retires the compound `finally` condition and its unreachable `(… ?? 1) - 1`. A failed snapshot no longer gets an immediate second `setItem` against a store that just rejected. It gets one retry after 200 ms, and none at all once a newer snapshot is queued, because that snapshot already carries the same entries. `flush()` closes a data-loss gap that predates the coalescing: a write that failed was only retried by the next append, so when the disconnect was the last thing to happen the entries explaining it never reached storage. It drains the in-flight save and makes one more attempt at the newest snapshot, wired to AppState `background` the way `subscribeConnectionRevivalTriggers` wires resume. Two revisions tests asserted the retry budget as intended behaviour (6 writes for 3 appends; 3 for one failure) and now assert one write per snapshot generation instead. `connection-log-buffer.test.ts` is untouched, including its requirement that one transient failure self-heals without another append — that is what the single delayed retry keeps. Co-Authored-By: Claude <noreply@anthropic.com> * fix(mobile): type the background-flush test mock so the tests ratchet passes The new test copied `ReturnType<typeof vi.fn>` from connection-revival-triggers.test.ts, which is grandfathered in the tests-typecheck baseline for that exact TS2345. The ratchet only shrinks, so type the mock instead of adding a baseline entry. --------- Co-authored-by: Claude <noreply@anthropic.com>
…tart (stablyai#23298) * fix(ssh): name the missing unzip when Bun archive extraction cannot start Extracting the downloaded Bun runtime shells out to `unzip` on POSIX hosts, which a minimal Debian/Ubuntu install does not ship. runProcess rejects a missing program with a bare `spawn unzip ENOENT`, which the caller's non-zero-exit branch never sees, so the operator got an errno instead of a remedy. Translate that one errno into a message naming the tool and the ORCA_UNZIP_BIN override. * fix(ssh): reuse the canonical absence predicate for extractor launch failures isDefinitiveAbsence is the repo's single errno allowlist for "definitively not there", and it also covers ENOTDIR — which spawn throws synchronously when a configured ORCA_UNZIP_BIN has a regular file for a parent. That case previously escaped as a bare `spawn ENOTDIR` naming no path at all. Also correct the comment: a deleted working directory is not a second source of these errnos, because runProcess leaves cwd unset and the child inherits the parent's without resolving it. Verified on macOS, Linux and Windows.
…3048) * perf: avoid repeatedly encoding retained VM recipe output * perf: capture retained VM recipe output as raw bytes in the shared byte buffer The previous commit added a third byte-retention buffer to the repo. This replaces it with the one that already existed and removes the remaining encoding work. `runRecipeCommand` no longer calls `setEncoding('utf8')` on the child's stdout and stderr. It keeps the raw `Buffer` chunks and runs one `StringDecoder` per stream to feed the existing string callbacks, which is exactly how `setEncoding` is implemented, so callbacks see the same characters at the same boundaries. With the bytes already in hand the capture encodes nothing: the 4,194,304 bytes the ring still encoded for 4 MiB of output drop to 0, and the UTF-8 continuation trim collapses from one scan per chunk to a single scan when the tail is decoded. Retention is now `GrowingByteBuffer.appendRetainedSuffix`, which had no production consumer. It gained an O(1) head offset, so `discardPrefix` and `retainSuffix` mark bytes dead instead of moving the whole tail and `append` slides or grows only when the head offset runs out of room. Quick Open path accumulation and the SOCKS handshake buffer get that win too. Without the offset the per-chunk memmove costs 12.36 ms for 4 MiB; with it, 0.25 ms against the ring's 0.53 ms and the old per-chunk re-encode's 265.78 ms. Two behaviour notes. Odd capture limits are clamped once at entry instead of carrying a per-chunk coercion path no production caller could reach, so an infinite or NaN cap is now bounded at 1 MiB rather than retaining everything. And malformed UTF-8 yields a different tail: replacement characters no longer inflate the byte count, so a malformed tail keeps more of what the recipe actually wrote. The encoding-budget assertions no longer spy on `Buffer` itself, where any unrelated allocation in the same tick could flip them. They count bytes through the capture's own buffer class and still assert the deterministic oracle: at most 5 MiB moved for 4 MiB of output, exactly 4 MiB appended, 1 MiB decoded, and the stored chunks identical to the Buffers the stream delivered. Co-Authored-By: Claude <noreply@anthropic.com> * test(vm-recipe): emit Buffers from the doctor stream doubles Dropping setEncoding('utf8') means stdout and stderr now deliver Buffers, so the hand-rolled EventEmitter doubles emitting strings threw inside the data listener — the capture retained nothing and the exit path never settled. --------- Co-authored-by: Claude <noreply@anthropic.com>
* perf(history): coalesce tombstone directory rescans * perf(history): reuse one tombstone listing instead of re-reading per completion Refilling the 64-slot tombstone removal window used to list the whole `.pending-delete` directory again, synchronously, after every removal that finished. A backlog of 1,024 tombstones cost 1,026 listings of a directory that starts 1,024 entries long, all on the main process thread. Each history root now keeps the names from its last listing and takes the next one from memory when a slot frees, listing the directory again only once that list runs out. The listing moved to `fs.promises.readdir`, so it no longer blocks the main thread. This replaces the previous coalescing-on-setImmediate approach, which left the directory being re-listed once per completion batch and needed a deferred-roots set, an event-loop turn of latency, and an unref'd immediate whose freed slots could go unfilled at exit. Holding the names removes all three. Two behaviours are kept deliberately: - Freed slots are offered across roots, so a root displaced at the shared cap is not stranded until the next startup. - A listing cannot re-submit a removal that was already under way when it started, including one that finished before the listing resolved. Five real-filesystem samples per version, 1,024 tombstone directories each holding a meta.json, macOS arm64 / Node 24. Medians: directory listings 1,026 to 6, names enumerated 494,348 to 1,077, blocking main-thread time in this path 820 to 7 ms, total drain 886 to 75 ms. The 886 ms breaks down as 266 ms of `readdirSync`, ~554 ms of per-entry work over those 494k names and its garbage, and ~70 ms of actual recursive rm, which is the unchanged floor the remaining 75 ms consists of. Average concurrent removals return to 62 of 64 from the 46 a deferred refill left idle. Adds coverage for a listing that fails mid-drain with later completions still able to recover, and for both roots draining under one shared cap. The heavy drain tests now run on real timers so real `fs.promises` and microtask ordering are exercised. Co-Authored-By: Claude <noreply@anthropic.com> * fix(history): warn when a tombstone root read fails for a reason other than absence readTombstoneNames swallowed every readdir error, so EACCES or ENOTDIR on the initial enumeration left tombstones in place with no diagnostic until a later completion happened to re-read. An absent root stays silent; it is the norm. --------- Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#23308) * fix(terminal): recognize a Git Bash launcher by its install layout * fix(terminal): require git-bash.exe in the launcher install-layout check * test(terminal): pin each Git Bash launcher install-layout marker as necessary
…tablyai#23329) * ci: share mobile route analysis and scope mobile test runs * ci: cover mobile web runner process dependencies * test: verify mobile web selectors through the new runner --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
…3318) Allow dotted browser domains with explicit numeric ports through the existing URL normalizer. Co-authored-by: KAPUIST <thsxornjs12@gmail.com>
Infer zero weekly Grok usage for a confirmed explicit zero quota while retaining unreported and monthly precedence safeguards. Adapted from huiq777’s PR stablyai#22303 and the payload analysis from deminit02-hue in issue stablyai#20657. The accepted exception is limited to explicit zero cap. Co-authored-by: Hui <a3239737781@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…tablyai#23322) Retain Japanese middle dots and tildes in rooted and explicitly relative terminal file paths; preserve existing path routing and suffix handling. Co-authored-by: Yi-111-a <47240345+Yi-111-a@users.noreply.github.com>
Exclude root notes files from packaging while retaining nested runtime notes assets. Co-authored-by: lurunzi <lurunzi@gmail.com> Co-authored-by: Codex <noreply@openai.com>
) Show unread emphasis in compact workspace rows using the existing pane acknowledgment state. Based on drakeo338’s bounded PR stablyai#22870. pinhaum reported stablyai#22857 and proposed the broader stablyai#22899 variant; the local candidate preserves the existing acknowledgement policy. Co-authored-by: drakeo338 <paranoyouz@gmail.com>
Keep grouped commas intact when building search filters for ripgrep and Git. Based on contributor proposal stablyai#22915. Co-authored-by: KAPUIST <thsxornjs12@gmail.com>
Highlight Typst files and diffs through the existing lazy TextMate provider. Based on contributor proposal stablyai#22884. Co-authored-by: Quan Nguyen <qnguyen.dev2@gmail.com>
…lead (stablyai#23325) Deliver Dispatch mail and ordinary replies to the current lead Run, preserving original delivery receipts and pre-bind mail draining. Based on Seongho Bae proposals stablyai#22977 and stablyai#22979. Co-authored-by: Seongho Bae <seonghobae@me.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#23320) Keep keyboard focus in the workspace list during selection changes, and transfer it to the selected terminal on Enter only when focus actually moves. Based on Kelvin Amoaba proposal stablyai#22911. Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
…#23324) Preserve supported Hermes YAML values and comments while installing or removing Orca hooks. Adapted from manthis and Pr1p proposals stablyai#22366 and stablyai#20632. Co-authored-by: Maxime AUBURTIN <m@hellomax.io> Co-authored-by: Chen <zwq19980411@gmail.com>
…ablyai#23343) * ci: reuse recording compilation, split families, and refresh shard timings * Keep recording suite intact after hosted performance comparison --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
…tablyai#23328) Respect disabled OpenCode variants, preserve explicit config ownership, and refresh WSL guest settings safely across reconnects. Based on Harshul Rathod proposal stablyai#22805. Co-authored-by: Harshul Rathod <harshulrathod1640@gmail.com>
…)" (stablyai#23350) This reverts commit a86fae0.
…3182) * fix: retire stale review lookups after cache invalidation * test: pin the fence a retired review lookup answer has to clear The extraction widened canAdoptDetachedAnswer: a retired owner is no longer in the in-flight index, so with no replacement reader the scope generation is the only thing stopping its pre-invalidation "no review" from being adopted as current — which would short-circuit the lookup for the review Orca just opened. Cover that interleaving, and restore the invariant comments the extraction dropped (token identity, expire idempotency, and that a size-cap eviction forfeits the wall-clock sweep).
* perf: share pending plugin translation startup requests * fix(plugins): retry a wedged language-pack startup request instead of joining it Sharing the pending startup request removed the duplicate IPC call, but the suppression was permanent: plugins:listLanguagePacks awaits plugin discovery, so a request that never settles left ensurePluginLanguagePacksLoaded a no-op for the session. Every later consumer joined a request that would never finish, where before each one retried — loaded stayed false, pinning the UI on built-in translations and suppressing the TCC notices that gate on it. Bound the join to a window instead of a boolean: a request that is merely slow is still shared, one past the window is treated as wedged and a later consumer starts its own. Adds the stalled-request test the change was missing.
* perf: skip macOS DNS probes for unrelated errors * review(dns-probe-admission): single-source the probe gate and widen resolution-failure coverage The admission guard duplicated the hint predicate at a second call site, so a gate that drifted stricter than the hint test would silently drop the DNS diagnostic for a real lookup failure. Route both through isMacTailscaleDnsHintCandidate, evaluated once per call, and add a parity test asserting admission never changes the message the ungated hint decision produces. Also: widen the predicate to the resolution-failure wordings it missed (EAI_NONAME / EAI_FAIL / ENODATA / getaddrinfo / "could not resolve" / "name or service not known" / ERR_NAME_RESOLUTION_FAILED), gate the probe on process.platform === 'darwin' explicitly rather than relying on the reader's internal check, make the hint idempotent so a re-wrapped hinted message neither duplicates copy nor re-probes, and rewrite the cache-window test to assert the resolver state the next relevant error reports instead of pinning an exact probe count.
…tablyai#23351) Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
* fix: remove PDF export temp files after setup failures * fix(export): keep PDF temp cleanup to files this export created, and time out a hung load Two holes in the temp-document cleanup: - The write was not an exclusive create, so anything already sitting at the generated temp path (a symlink planted in the shared temp dir) would be written through, and the cleanup would then unlink an entry this export did not create. The write now uses `flag: 'wx'`, and the one failure that means "this path is not ours" (EEXIST) skips cleanup entirely. - The 60s timeout only covered render-and-print, started after the load had already finished. An export document whose script never yields fires neither `did-finish-load` nor `did-fail-load`, so the load await hung forever and the hidden window plus its temp file leaked for the life of the app. The timer now starts before `loadFile` and races the whole load-render-print sequence. Tests cover the preserved foreign file, a never-settling load, a load that resolves without either event, `did-fail-load`, and that one export's cleanup cannot touch a concurrent export's in-flight temp file.
…blyai#23667) * refactor(agent-hooks): one predicate for whether an agent's status hooks are on "Global switch on and this agent not turned off" was spelled out separately in the startup controls, the settings reconcile, the retained-home reconcile, the WSL preflight RPC, the CLI preflight and the OpenCode plugin selection. They now share one function, in a module light enough for the CLI's per-launch Codex preflight to load. The PTY spawn env derives the Codex flag from the switch and opt-out list it already carries, the same way it does for OpenCode and Pi, instead of receiving a second copy. * fix(codex): launch and resume prep honour Codex's per-agent hook opt-out Turning Codex off in the per-agent hook settings removes Orca's Codex hook entry, but launch prep and session resume read only the global hooks switch, so the next Codex launch or resume wrote the entry straight back into the real ~/.codex or the account's home. Both now read the per-agent predicate, which the PTY spawn env and startup already honoured. * fix(codex): turning Codex off per agent clears the real ~/.codex entry While the real-home lane owns ~/.codex/hooks.json, the legacy system-home sweep stands down. That gate read only the global switch, so turning Codex off per agent ran remove() with the sweep still suppressed and left Orca's entry in the real ~/.codex. The gate now reads the per-agent predicate, the same as turning every hook off. * test(codex): cover the system ~/.codex sweep gate for Codex turned off The gate that lets the legacy system-home sweep run was an inline closure in startup, so reverting it to the global switch left CI green. It is now a pure function beside the gate it feeds, with a table test and a remove() test on a seeded ~/.codex: turning Codex off strips Orca's entry and keeps user hooks; with Codex on the entry stays. * fix(cli): keep the agent-status hooks predicate loadable by the packaged CLI The CLI's prepare-codex handler imported the predicate from src/main, but the Electron build rebuilds out/main from its declared entries only, so the packaged `orca agent hooks` commands could not load it (package jobs and the CLI bundle-parity test were red). The predicate reads only settings, so it now lives in src/shared, which the CLI compiles itself.
…aunches without the shared server (stablyai#23933) * fix(terminal): give plain shells and cmd.exe Codex launches --no-daemon Plain bash, zsh and fish tabs were never wrapped, so a typed codex skipped the shell function that adds --no-daemon. Wrap them (bash keeps its prompt and DEBUG trap untouched unless Orca asked for command markers), add --no-daemon host-side where no function can run (cmd.exe, path-named binaries), and move new tabs to a v38 terminal daemon so they get the new wrappers. * fix(terminal): keep plain bash a login shell and give the setup gate the codex function Plain bash and Git Bash tabs launch exactly as before again: the rcfile wrapper would have made every one a non-login shell. Plain tabs on the user's configured shell args stay unwrapped on both transports. The wait-for-setup gate's bash -lc now defines the codex function, so a sequenced Codex launch gets --no-daemon from the binary it actually runs. * fix(terminal): define the setup gate's codex function after setup finishes Setup can be what puts codex on PATH, so defining the function before the marker wait found no binary and skipped --no-daemon. * refactor(terminal): fold the SSH/WSL guard into the Codex launch planner and bound the gate test * fix(terminal): honour the pane's env deletions in the Codex opt-out check Also pin the setup-gate test's fake codex ahead of path_helper's PATH. * revert(terminal): launch plain zsh and fish tabs exactly as on main Drops the always-wrap for plain zsh and fish, the configured-args guard that only served it, and the v38 daemon bump: the daemon's launch configs and generated wrappers are byte-identical to main again. Keeps the host-side --no-daemon for cmd.exe and path-named launches and the setup gate's codex function. (cherry picked from commit 26bb7c2)
…er (stablyai#23929) * feat(settings): add a setting to run Codex terminals on Codex's shared server Off injects ORCA_CODEX_ISOLATE=0 into new terminals on every host (local, daemon, SSH relay, WSL), which the codex shell wrapper from stablyai#23900 reads to skip --no-daemon. On (the default) injects nothing. * feat(terminal): announce per-terminal Codex servers once Shows a one-time toast the first time a Codex terminal starts, with an Open Settings action that lands on the new Codex server setting. The seen flag persists in UI state and is set when the toast is shown. * fix(settings): drop the status warning from the Codex server setting * fix(terminal): simplify the Codex shared-server notice * fix(terminal): say agent status in the Codex notice * fix(settings): hide the Codex server setting from paired web search Gives its search entry an id and gates it with includeCodexTerminalServerIsolation, as the other host-only rows are, so a paired web client cannot find a row it never renders. Its search keywords now use catalogued agents-search keys instead of missing ones; CODEX_ISOLATE_ENV is no longer exported; the toast id comment names the case it guards. * test(settings): assert the Codex server search gate through the metadata builder Calling getAgentsPaneSearchEntries directly stayed green with the web gate deleted; the metadata builder test fails without it. Backport: stablyai#23744 (workspace trust setting) is not on this branch, so its adjacent setting, search entry and test are left out. (cherry picked from commit a0abcb6)
… swipes don't type into Codex (stablyai#23946) * fix(terminal): restore the mouse encoding with mouse tracking in every snapshot Swiping to scroll Codex from the phone on a Windows host typed legacy `ESC [ M` mouse reports into the Codex composer (stablyai#23818). SerializeAddon re-arms mouse tracking (?1000h/?1002h/?1003h) but never the SGR encoding (?1006h/?1016h). Any snapshot taken from a desktop pane's xterm (the runtime seeds its headless model from it after a reattach, and serves it to remote viewers when no model exists) therefore restored "tracking on, legacy encoding", and the phone encoded wheel events as X10 bytes, which ConPTY hands to Codex as keystrokes. serializeWithAbsoluteCursor, the one wrapper every Orca snapshot producer uses, now appends the encoding xterm itself parsed, read from xterm's mouse state service. The daemon/runtime headless model reads tracking and encoding from xterm too, so its regex mirror of the DECSET stream is deleted (one source of truth; one less regex pass per PTY chunk). Mixed versions: no wire field changes. A new host's snapshot carries an extra DECSET that old desktop and phone clients already parse; an old host's snapshot restores exactly as before. With tracking off the encoding alone sends no reports, so the wheel still scrolls scrollback. * test(terminal): pin the mouse-encoding read against the renderer xterm build * fix(terminal): type the xterm mouse-state read behind named shapes (cherry picked from commit ad2e1b5)
…tablyai#23805) * fix(runtime): stop a busy Codex 0.150-0.157 pane reading as tui-idle The startup header box (OpenAI Codex / model: / directory:) stays on screen and in the tail for the whole session, so as tier-1 evidence it settled tui-idle mid-turn. For a codex pane it now counts only in the quiet lane, held to the same quiescence as the composer. * fix(runtime): keep a restored Codex pane's header as tier-1 readiness A restored or reattached pane has no lastOutputAt, so the quiet lane that now holds a Codex header can never fire and the wait sat pending until timeout, where main settled it. Gate the Codex tier-1 veto on the output clock rather than the agent name, and share one settled-prompt helper. * test(runtime): read no screen in the restored Codex pane test * test(runtime): pin the clock in the clockless Codex header cases * test(runtime): name the screen-readiness comparison for what it proves (cherry picked from commit fb67d5d)
… is resized (stablyai#23852) * fix(browser): never resize a browser tab whose page crashed, which segfaulted Orca Chromium's Emulation.setDeviceMetricsOverride and Emulation.setVisibleSize resize the page's view without checking it still exists (WebContentsImpl::SetDeviceEmulationSize). A crashed page renderer takes its view with it until a reload builds a new one, so either command sent in that gap killed Orca's whole main process with SIGSEGV. One gate, sendGuestCdpCommand, now refuses those two commands while the tab's renderer is gone. The viewport preset writer, the agent viewport command, the agent bridge's command sender, the CDP proxy and the screencast device metrics all send through it. The check runs in the same task as the send, so the renderer cannot die in between. The page's own reload reapplies the chosen preset on dom-ready, as it already did. * test(browser): type the CDP gate's target so its test double needs no cast CI's changed-lines gate rejects new type assertions. The gate only uses isDestroyed, isCrashed and debugger.sendCommand, so it now takes exactly that shape; the viewport test keeps the one fixture cast its siblings use, with a line-specific SAFETY note. (cherry picked from commit 4ebec19)
…minified telemetry check
…ai-orca-ru-20261001T1400 v1.4.218 # Conflicts: # config/scripts/skills-cli-package-workflow.test.mjs # config/scripts/verify-dev-channel-packaging.test.mjs # config/scripts/win32-test-lane-registration.test.mjs # src/renderer/src/components/native-chat/native-chat-runtime-image-send.ts # src/renderer/src/components/native-chat/use-native-chat-draft.ts # src/renderer/src/lib/agent-launch-caller-profile-census.test.ts # src/renderer/src/lib/agent-launch-routing-caller-census.test.ts # src/shared/pane-agent-identity-inventory.test.ts
Reset upstream-owned paths to the tag, honored fork deletions, restored fork exceptions and three-way merged the 38 that upstream changed since v1.4.215, and hand-merged 29 seam/feature/quarantine files where the first pass kept the fork's side. Upstream resolved three pending-upstream items (hourly base case, focused Playwright selection, structured preamble settlement) and deleted the junk tests one more fork exception and three seams lived in, so those declarations are removed with their ledger entries. Withdraws the use-native-chat-draft deletion an upstream test now imports, replays four tier-2 copies, repoints three cross-version pins to fork releases, and declares the lockfile and localization-contract seams.
v1.4.218 adds a required inputKind to sendRuntimePtyInput, the verified send, pty.write/writeAccepted and sendTerminalAgentPrompt, and records per-run input facts from it. The fork composer, Heimdall's worker prompt and the omp atomic tests call these without one, so they now pass 'driving' (upstream's kind for every native-chat send). Also advances the composer's tier-2 copy headers.
…apes NativeChatInteractiveCard now takes a resolved prompt card, the caller-profile harness dropped its source-marker fields with the census tests upstream removed, and the trust preset union gained qoder. The dock composer resolves the card the same way the native-chat view does, the sitter's profile keeps only the fields the harness still reads, and the handoff derives its preset type from the agent config instead of copying the union.
i18next-cli 1.74 (bumped in v1.4.218) resolves template-literal keys by type and reported three phantom keys from the attempt-title call, failing verify:localization-extraction. Literal keys per state keep the same strings and are visible to the verifier.
The fork's send-path tests pinned the pre-v1.4.218 argument lists. Calls now carry 'driving' ahead of the optional cancellation predicate, so assertions include it and the predicate is read from the fifth argument.
The OXC-bundle test declares its own writer surface; writeTerminalAgentPrompt now takes the prompt options v1.4.218 requires, so the declared signature does too.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The unresolved composer cache mismatch can discard restored structured-message text, particularly during IME composition.
Review effort: Balanced
Findings: 1
What changed in this PR
Syncs the fork from upstream v1.4.215 to v1.4.218 while preserving fork-owned features and ownership boundaries.
Changes:
- Absorbs 275 upstream commits and reconciles 4,029 files.
- Updates runtime, terminal, agent, mobile, CI, and compatibility contracts.
- Adapts fork features to changed upstream APIs and tests.
Blocking finding: The fork composer does not integrate upstream’s restored-draft/IME append contract, so stopped structured sends can lose user text.
| File | Description |
|---|---|
.github/** |
Updates CI and background-launch workflows. |
config/** |
Updates build, packaging, ownership, and verification tooling. |
src/shared/** |
Expands shared agent, terminal, telemetry, and RPC contracts. |
src/main/** |
Absorbs runtime, SSH, agent, persistence, and daemon changes. |
src/preload/** |
Extends renderer bridge contracts. |
src/relay/** |
Updates remote execution and hook behavior. |
src/cli/** |
Updates orchestration and launch semantics. |
src/renderer/** |
Integrates UI, terminal, native-chat, and state changes. |
mobile/** |
Updates mobile transport, shell, terminal, and task flows. |
tests/** |
Updates E2E coverage for changed upstream behavior. |
native/** |
Adds Windows launcher metadata. |
docs/** |
Refreshes readiness documentation. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
… contract test v1.4.218 trimmed this test to its release-cut checks, and the resolution took the trimmed upstream file whole, dropping the fork's one surviving adaptation: publish-release must not need the disabled Windows/Linux build job. Restores that line and the exception that owns it.
v1.4.218 moved the unit lane's excludes from --exclude flags into the vitest config behind ORCA_BALANCE_UNIT_SHARDS=1 and added two shell contracts. The runner now sets that env for the unit lane instead of carrying its own exclude list, and its shell lane lists the two new contracts.
… ships The v1.4.218 cut synced mobile.yml from main (with stablyai#23732's workflow change) but not its tests, so the tag fails its own suite. Mirrors upstream's e594cb0 for the tests only: the recording-pin checkout test goes (the job it reads no longer exists) and the gated-step assertion skips the new summary step. Declared pending-upstream until a tag carries e594cb0.
Run status: needs attention (left open)First CI run: 3 test shards failed, plus
Still failing, and needs a decision:
|
v1.4.218 gives a Stop-withdrawn structured send back to the composer by appending to the native-chat draft cache, and holds that text while an IME composition owns the field. The fork composer reads its own draft cache and never heard the append, so the withdrawn text was lost. The fork draft cache now mirrors into the native-chat cache, adopts appends that landed while no composer was mounted, and the draft hook ports upstream's append/flush contract: shown immediately, or held mid-composition and flushed when the composition settles.
v1.4.218 added agent-session-death-evidence-downgrade.unit.test.ts but left it out of the cross-version-wire job's explicit file list, upstream and fork alike, so nothing ran it. pr.yml is fork-owned, so the fork lists it.
Run status: green, mergingSecond round of fixes
CI on
|

What this is
This PR brings the fork up to upstream's latest stable release, v1.4.218 (
75ea50273328d9bd5465170d10a098711d61b5a4). The fork was on v1.4.215.It replaces #111, which synced v1.4.217 and was closed unmerged. The v1.4.217 release had a defect: its PR workflow called a
git-pull-request-diff-base.mjsCLI and anrpc-recording-pin-guard.mts reachablesubcommand that only exist from v1.4.218. That is why #111's repository-guard and RPC-pin checks failed. v1.4.218 ships both, so moving straight to it removes those failures.Before / after
Before: upstream v1.4.215 plus the fork's features.
After: the same fork features on top of v1.4.218, which is 275 upstream commits across three releases. No fork feature was removed or reduced.
How it was resolved
Merge and ownership
-X ourshandled the content conflicts.config/fork-ownership.json:pr.yml: rebuilt from sync: absorb upstream v1.4.217 #111's v1.4.217 resolution plus the v1.4.217→v1.4.218 change, which is the Codex trust-contract step. The fork's Windows packaging job stays deleted.package.json:verify:localization-catalogsruns the fork's catalog wrapper and then the runtime catalog check.readme-downloads.svgandclient-hosted-browser-package-coverage.test.mjs: the fork's version is kept.package-electron-runtime-contract.test.mjs: upstream's version is taken. Upstream deleted the source-text tests the fork had adapted (test: remove junk tests that assert source text instead of behavior stablyai/orca#23815), so the exception is dropped.inputKindargument, which is now passed through the fork's code paths.NativeChatResolvedViewtakes upstream's turn-status, delivery-notice and prompt-card wiring.NativeChatConversationnow forwards everyNativeChatMessageListprop instead of copying the list.pnpm-lock.yaml: three-way merged, and the frozen install passes. It is now declared as a seam, because the fork's pnpm 12.5.1 pin otherwise de-syncs it at every sync.Pending-upstream items v1.4.218 resolves
These are removed from the manifest and from
docs/fork-upstreaming.mdtogether:packageVersionoption.Other upstream changes absorbed
use-native-chat-draft.ts, so the fork's deletion of it is withdrawn.death-evidence: pinned tov1.4.208-rc.0.zy01. The module it loads is byte-identical to v1.4.211's.worktree-ps-verdict: pinned tov1.4.216-rc.0.zy01. All three modules it loads are byte-identical to v1.4.212's.resume-marker: pinned tov1.4.216-rc.0.zy03, the newest fork release. No fork release carries v1.4.211's recovery capsule, so this one tests the downgrade fork users would actually do.Fixes on top of the resolution
8722614ffdinputKinda required argument on the runtime PTY send helpers,pty.write/writeAcceptedandsendTerminalAgentPrompt, and records per-run input facts from itwriteInputAccepted) now pass'driving', and main records the input fact for that path too11a8b69fa3qoder8f3a87c6712472bff24b,47695c4187Checklists
agent-composeris possible. Upstream's v1.4.218 adds IME-aware draft appends (useNativeChatDraft(paneKey, isComposing)plusflushDraftAppendson IME settle) to the composer the fork replaces. The fork composer does not get that behaviour. Nothing the fork ships changes, so the fork's side was kept, and this is raised for review. Every other feature: none.Verification
Locally, all of these pass:
pnpm lintThe test files touched by the resolution and fixes were also run on the remote test sandbox: 204 files at first, with every failure addressed and those files re-run green. The full suite runs in this PR's CI.
Backup of the previous
main:backup/main-20261001-160045Zat5aea9542430091c39a652258e015487d71e0d175.Merge with a merge commit only. A squash or rebase breaks the next sync.