Skip to content

sync: absorb upstream v1.4.218 - #112

Merged
zpyoung merged 287 commits into
mainfrom
zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20261001T1400
Oct 1, 2026
Merged

zpyoung merged 287 commits into
mainfrom
zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20261001T1400

Conversation

@zpyoung

@zpyoung zpyoung commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner
Files Added Deleted Net
Test 1065 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​72008 $\color{#cf222e}{\Huge{\mathbf{−}}}$​19643 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​52365
Prod 1935 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​49952 $\color{#cf222e}{\Huge{\mathbf{−}}}$​24794 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​25158

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.mjs CLI and an rpc-recording-pin-guard.mts reachable subcommand 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

  • How the tag was taken. The upstream tag was merged, not rebased. All 524 fork commits are still reachable at their original SHAs.
  • First pass.
    • -X ours handled the content conflicts.
    • Five files the fork deletes kept their deletion.
    • Three files upstream deleted kept the fork's copy for now; the ownership step below then removed them.
  • Ownership lists, from config/fork-ownership.json:
    • 3,719 paths reset to the tag. Most already matched it.
    • 153 paths removed.
    • 188 exception files restored to the fork's version. Upstream had changed 38 of them since v1.4.215. Each was three-way merged against v1.4.215 so upstream's unrelated work is kept:
      • 20 merged cleanly.
      • 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:
        • The fork's version and pnpm 12.5.1 are kept.
        • Upstream's new verify:localization-catalogs runs the fork's catalog wrapper and then the runtime catalog check.
        • Upstream's combined script calls its own catalog checker directly. That checker rejects fork translation keys.
      • readme-downloads.svg and client-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.
      • Claude terminal readiness, three files: upstream's import changes are kept and the fork's visible-screen probe imports are re-added.
      • Input quarantine (bug-1), five files: the fork's side is kept.
        • Upstream's only change in these files was the new inputKind argument, which is now passed through the fork's code paths.
        • NativeChatResolvedView takes upstream's turn-status, delivery-notice and prompt-card wiring.
        • NativeChatConversation now forwards every NativeChatMessageList prop instead of copying the list.
    • 2,105 seam and feature paths took a real merge. Upstream touched 101 of them.
      • Each was re-merged cleanly (base v1.4.215).
      • 81 matched the tree exactly.
      • 20 had lost upstream's side in the first pass and were merged by hand, keeping every declared fork line.
      • The terminal-subscription rework moved cleanup to a registration object, so the ask-surface tracking now hangs off that registration's abort signal. It is one seam instead of three.
  • Fork edits to upstream-owned files, two found:
    • 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.
    • The generated RPC catalog: regenerated.

Pending-upstream items v1.4.218 resolves

These are removed from the manifest and from docs/fork-upstreaming.md together:

Other upstream changes absorbed

  • Removed tests. Upstream deleted three test files the fork had seams in (two caller censuses and a pane-identity inventory). The fork follows, and those seams are removed.
  • Restored module. An upstream test now imports use-native-chat-draft.ts, so the fork's deletion of it is withdrawn.
  • Tier-2 copies.
    • Four copies replayed upstream's changes: live status (omp turn end, waiting-for-input), live session, the fix-checks import path, and the view state.
    • The view-state copy already had upstream's "messages beat errors" behaviour, so it only needed its header updated.
    • All 17 copy headers now point at v1.4.218.
  • Cross-version wire tests, three new upstream pins.
    • Why they needed repointing. The pins name v1.4.211 and v1.4.212, and this repo has no such tags, so each was repointed to a fork release.
    • death-evidence: pinned to v1.4.208-rc.0.zy01. The module it loads is byte-identical to v1.4.211's.
    • worktree-ps-verdict: pinned to v1.4.216-rc.0.zy01. All three modules it loads are byte-identical to v1.4.212's.
    • resume-marker: pinned to v1.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.
    • All three are declared as seams.

Fixes on top of the resolution

Commit What broke Fix
8722614ffd v1.4.218 makes inputKind a required argument on the runtime PTY send helpers, pty.write/writeAccepted and sendTerminalAgentPrompt, and records per-run input facts from it The fork composer, Heimdall's worker prompt and the fork's acceptance path (writeInputAccepted) now pass 'driving', and main records the input fact for that path too
11a8b69fa3 The interactive card now takes a resolved prompt card. The caller-profile harness dropped its census fields. Trust presets gained qoder The dock composer, the sitter's profile and the handoff's preset type follow the new shapes
8f3a87c671 i18next-cli 1.74 (bumped in v1.4.218) resolves template-literal keys by type and reported three phantom sitter keys Literal keys per state, with the same strings
2472bff24b, 47695c4187 Fork tests pinned the old argument lists Assertions include the input kind, and the cancellation predicate is read from the fifth argument

Checklists

  • Forked copies (17): 4 replayed, 13 had no upstream change, and all headers were updated together.
  • Pending-upstream items (114 exception paths): 3 were resolved upstream and removed. The rest are still needed. Where upstream changed a path, it was three-way merged.
  • Feature collisions: agent-composer is possible. Upstream's v1.4.218 adds IME-aware draft appends (useNativeChatDraft(paneKey, isComposing) plus flushDraftAppends on 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.
  • Sweeps:
    • Deleted modules: one withdrawn (above).
    • Locales: 22 fork bundles × 6 locales, clean.
    • Release-workflow toolchain: no pnpm or node pin changes.

Verification

Locally, all of these pass:

  • frozen install
  • seam check: 1,238 lines across 623 files
  • residual budgets: 567 files
  • the fork ownership guard
  • typecheck for node, web and cli (the mobile-web project is retired upstream)
  • full pnpm lint
  • the remaining static-analysis steps: Zustand fan-out, feature-wall assets, macOS entitlements

The 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-160045Z at 5aea9542430091c39a652258e015487d71e0d175.

Merge with a merge commit only. A squash or rebase breaks the next sync.

nwparker and others added 30 commits September 26, 2026 20:39
…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>
…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.
* 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.
brennanb2025 and others added 17 commits September 29, 2026 11:30
…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)
…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.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 16:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Medium severity

Open (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.

Comment thread src/renderer/src/components/native-chat/NativeChatComposer.test.tsx
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High risk] Absorbs upstream release with CI/build configuration changes.

The PR is not safe to merge until withdrawn structured-chat messages return to the visible composer.

Summary

This PR merges upstream v1.4.218 into the fork, updates fork integrations and compatibility tests, and revises CI and release workflows. The new structured-chat Stop restoration writes message text to a cache the visible composer does not read; one new downgrade test is also absent from CI execution.

Reviews (1) · Last reviewed commit: "test(sync): type the bundled omp writer'..."

… 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.
@zpyoung

zpyoung commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Run status: needs attention (left open)

First CI run: 3 test shards failed, plus verify, which aggregates them. Four of the causes are fixed in a19c0bbd3f, 259eeac093 and bf07e4bf9b, and verified on the test sandbox:

  • package-electron-runtime-contract.test.mjs
    • What went wrong: the resolution took upstream's trimmed file whole and dropped the fork's one surviving assertion (publish-release must not need the disabled build job).
    • Fix: the assertion and its exception are restored.
  • run-sandboxed-test-shards.test.mjs (the fork's own sandbox runner)
    • What changed upstream: v1.4.218 moved the unit-lane test exclusions into the vitest config, behind ORCA_BALANCE_UNIT_SHARDS=1, and added two shell contract tests.
    • Fix: the runner now sets that variable for its unit lane instead of keeping its own exclusion list, and its shell lane lists the two new tests.
  • mobile-recording-pin-checkout.test.mjs and mobile-release-check-scope.test.mjs

Still failing, and needs a decision: agent-composer feature collision.

  • Which tests fail: the three "withdrawn message put back during an IME composition" tests in native-chat-structured-send-composition-clear.test.tsx. They fail the same way every time.

  • What upstream added: fix(native-chat): Stop is there from the moment a message is sent stablyai/orca#23026 makes Stop return a withdrawn structured message to the composer. It writes the text into upstream's draft cache (appendNativeChatDraftCache). Upstream's useNativeChatDraft subscribes to that cache and holds the appended text back until any IME composition finishes.

  • Why the fork misses it: the fork's composer reads its own cache (useAgentComposerDraft), so withdrawn text never comes back to it.

  • The choice:

    1. Bring upstream's append-and-wait-for-IME behaviour into useAgentComposerDraft. This adds behaviour and removes nothing the fork ships.
    2. Or decide otherwise.

    The run is unattended, and the skill sends feature collisions to a human, so it stopped here.

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.
@zpyoung

zpyoung commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Run status: green, merging

Second round of fixes

  • 664b948c6f, the IME collision flagged in the review and left open last time. v1.4.218 gives the text of a structured send back to the composer when Stop withdraws it, by appending it to upstream's native-chat draft cache. The fork composer reads its own draft cache and never saw that text, so it was lost. It also failed native-chat-structured-send-composition-clear.test.tsx (shard 1/5).
    • The fork's cache now mirrors every write into the native-chat cache.
    • It picks up text that was put back while no composer was open.
    • useAgentComposerDraft adopts upstream's handling: the text appears right away, or, during an IME composition, is held and added once the composition settles.
    • No fork behavior is lost; the fork composer now restores a stopped message, as upstream does. Added 4 hook-level tests.
  • dfd7f3e462, the test Greptile flagged as never run. v1.4.218 added agent-session-death-evidence-downgrade.unit.test.ts but left it out of the cross-version-wire job's file list, in upstream's pr.yml as well as the fork's. The fork's pr.yml now lists it, and the test passed in CI.

CI on dfd7f3e462: 68 passed, 6 skipped, 0 failed.

  • The earlier real IME / Linux Wayland Hangul failure was a job timeout during apt install, before any test ran. That job is not in verify.needs, and it passed on this run.

@zpyoung
zpyoung merged commit 5586e16 into main Oct 1, 2026
74 checks passed
@zpyoung
zpyoung deleted the zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20261001T1400 branch October 1, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.