Skip to content

sync: absorb upstream v1.4.194 - #41

Merged
zpyoung merged 132 commits into
mainfrom
zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20260901T1400
Sep 1, 2026
Merged

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

Conversation

@zpyoung

@zpyoung zpyoung commented Sep 1, 2026 •

Copy link
Copy Markdown
Owner
Files Added Deleted Net
Test 299 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​20944 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1614 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​19330
Prod 794 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​68901 $\color{#cf222e}{\Huge{\mathbf{−}}}$​51964 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​16937

Absorbs upstream stable v1.4.194 (07f4356a1678f6170a439527cd043f59b84343f0) into main.

Resolution

  • Mode: auto-ours+tree. Plain git merge stopped on 20 conflicts; -X ours cleared all but one tree conflict.
  • Tree conflict: src/renderer/src/components/native-chat/NativeChatComposerField.tsx — "deleted by us / modified by them". Honoured the fork's deletion (git rm -f); the manifest declares it deleted: true because fork-agent-composer/AgentComposerField replaces it.
  • Fork commits: 299 recorded before the merge, all 299 confirmed still reachable at their original SHAs. The range is now 300 — the extra is this PR's ownership commit.
  • Backup: origin/backup/main-20260901-140217Z at f9b63fef328c52a4180c295b1992aefb6f1d2aaa.

Ownership lists

List Count Outcome
checkout.txt 1029 reset to the tag; all verified byte-identical to v1.4.194
remove.txt 31 16 declared deleted: true fork exceptions, 15 upstream paths the tag dropped
ours.txt 87 fork exceptions restored, then audited (below)
merge-review.txt 714 235 seams + 479 feature-glob paths, reviewed by hand

ours.txt audit — 14 paths upstream also changed

Each was three-way merged with v1.4.193 as base rather than left at the fork's copy:

  • package.json — took every upstream dependency bump, the pnpm@12.0.0 packageManager, and the removal of the pnpm block (v1.4.194 moves it to pnpm-workspace.yaml). Keeping the fork's copy would have failed pnpm install --frozen-lockfile, because pnpm-lock.yaml is upstream-owned. The fork keeps only its version line, test/test:sandbox/localization scripts, and its reactDoctor rules.
  • src/main/speech/stt-service.ts — v1.4.194 split this 501-line module into a 71-line barrel plus five stt-session-* modules. The -X ours merge kept the fork's monolith and added all five new modules, leaving two live implementations. The exception's whole reason (dropping an inert eslint-disable max-lines) is obsolete: the tag's barrel has no such directive. The exception is removed and the file resolves to upstream.
  • src/main/rate-limits/service.ts (tier-4) — upstream's change is oxfmt reformatting in an unrelated region; merged cleanly with the fork's boolean-return change intact.
  • src/renderer/src/components/terminal-pane/TerminalPane.tsx — merged; upstream's nativeChatLeafOwnsTabWideEvidence / ownsTabWideLaunchDraft / split-cwd hunks landed alongside the fork's dock mount and handoff-dialog import.
  • config/max-lines-baseline.txt — took upstream's baseline (37 entries retired by this release's splits), then check-max-lines-ratchet --prune removed the 2 remaining stale entries.
  • The other 9 (pr.yml, release-cut.yml, release-mac-build.yml, reliability-gates.jsonc, install-electron-package-binary.{mjs,test.mjs}, package-electron-runtime-contract.test.mjs, release-cut-token-permissions.test.mjs, resources/skills/release-mapping.json) describe the fork's own pipeline; upstream's versions cannot describe it, so the fork's copies stand.

merge-review.txt — five seams the release split into barrels

--verify-residuals was the only check that saw this: each recorded budget drifted into the hundreds or thousands while --verify-seams stayed green, because the fork's defended monolith still contained every declared line.

Old seam Lines → Re-homed to
settings/Settings.tsx (1930 → 36) 2 settings/settings-page-renderer.tsx
hooks/useSettingsNavigationMetadata.ts (777 → 178) 2 hooks/settings-navigation-workflow-sections.ts
runtime/web-runtime-session.ts (1793 → 31) 2 runtime/web-runtime-terminal-actions.ts
shared/telemetry-events.ts (1657 → 68) 3 split three ways: telemetry-property-schemas.ts, telemetry-event-registry.ts, and a re-export in the barrel; the dock schemas moved into fork-owned shared/fork-terminal-dock/telemetry-terminal-dock-schemas.ts
native-chat/NativeChatView.tsx (459 → 60) 3 native-chat/NativeChatResolvedView.tsx

Seven further seams drifted from ordinary -X ours hunk damage and were re-merged from the clean pre-merge fork blob rather than the damaged tree. transcript-watch-engine.ts was the dangerous one: the merge kept the fork's usages of emitTranscriptUnavailableSnapshot and transcriptWatcherPathIsInstallable while dropping the imports that declare them, and left a dead duplicate watcher counter beside upstream's new transcript-watcher-count module.

Tier-2 forked-copy replay

All 16 copies checked. Every header recorded 6e4f817101 (v1.4.190); 7 recorded sources had moved since.

  • fork-native-chat-relay/transcript-watch-subscription.ts — replayed v1.4.194's WSL running-observer rework. Mandatory: needsWslHostTranslation no longer exists and toHostReadableTranscriptPath now requires a wslSnapshot.
  • fork-agent-composer/AgentComposerField.tsx — replayed the IME rework (fix(native-chat): preserve IME composition across async updates stablyai/orca#17169, fix(native-chat): replay a draft clear dropped mid-composition stablyai/orca#17392): useImeEnterGestureOwnership, uncontrolled textarea with a layout-effect draft sync, imeComposedSegment for a clear dropped mid-composition, onImeSettled replacing the raw composition handlers. Plumbed through AgentComposer.tsx (which had a clean isComposingRef seam at exactly those points) and NativeChatComposer.tsx.
  • use-native-chat-composer-attachments.ts (seam) — union of both sides: the fork's shared cache, subscription and restore stay; upstream's disabled/isComposing args, pending-path deferral, flushPendingAttachments and the applyResolvedPaths refactor are adopted.
  • native-chat-composer-types.ts (seam) — adopted upstream's NativeChatLaunchSeed (with ownsTabWideLaunchDraft) in place of the flat launch props, and NativeChatComposer now remounts on paneKey.
  • fork-native-chat-relay/native-chat-session-transport.ts, use-native-chat-live-session.ts — the delta (capabilities.transcriptPending, the awaiting phase) was already replayed by an earlier sync; only the headers were stale.
  • fork-agent-composer/AgentComposerActions.tsx — upstream's handleCriticalAction double-click guard is inapplicable: the fork renders Stop and Send as separate buttons, so a second click cannot land on the other control. The pickerRequest half was already present.
  • fork-worktree-groups/WorktreeGroupMenuItems.tsx — upstream's delta to WorktreeContextMenu.tsx (1136 → 34) is purely the split; ui/dropdown-menu is unchanged and the copied group-menu region did not move. Header repointed at WorktreeContextMenuView.tsx,WorktreeContextMenuOverlays.tsx.

All 16 headers advanced to 07f4356a16. Two copies (agent-composer-autogrow.test.tsx, use-agent-composer-keydown.test.tsx) carry a leading // @vitest-environment happy-dom pragma, so their headers sit on lines 2–3.

Two upstream files the fork's deletion broke

Both are upstream-owned and reset to the tag by checkout.txt, then failed to compile against the fork's deleted NativeChatComposerField:

  • native-chat-structured-composer-dispatch.ts — the fork's import repoint was undeclared, so the reset dropped it. Restored and declared as an import-swap seam (it should have been one already).
  • native-chat-composer-composition.test.tsx — new in v1.4.194, exercises the component the fork deletes. Declared as a deleted: true exception.

One upstream test also needed a seam: transcript-watch-engine-wsl-lifecycle.test.ts calls installTranscriptWatcher without the tailReader the fork's engine requires. Added a stub at its 5 call sites, declared passthrough.

Checklists

Verification (local gate)

Step Result
pnpm install --frozen-lockfile pass
--verify-seams pass — 495 lines across 246 files
--verify-residuals pass — 232 files match
.github/scripts/check-fork-ownership.mjs pass — no coverage, staleness, capture, seam or residual findings
pnpm typecheck (node + cli + web) pass
pnpm lint pass

Tests are left to this PR's own CI, per the skill's Step 8.

Known follow-up

TEST-5 in TEST_BACKLOG.md: the replayed IME deferral/remount behaviour has no fork-shaped test. Upstream's new assertions mock modules the fork deletes, so they could not be taken verbatim; the fork's equivalents were updated only far enough to compile.

Toolchain note

v1.4.194 bumps packageManager to pnpm@12.0.0, whose self-install runs with --ignore-scripts and leaves a placeholder where the native binary belongs (spawnSync .../12.0.0/bin/pnpm ENOEXEC). Repaired on the runner by running node install.js in the downloaded tool directory. CI installs pnpm through its own action and is unaffected.

AmethystLiang and others added 30 commits August 29, 2026 13:33
Adds flex-1 to palette open tab titles so they expand to fill
available space, making better use of the palette's horizontal layout.
* perf(markdown): skip closed-search update renders

* test(markdown): stress closed-search updates
…under test (stablyai#17178)

* test(cross-version-wire): derive skew expectations from the baseline under test

The cross-version wire job pairs current code against whichever release tag is
newest, so a hand-written "the old side does not have X" assertion expires by
itself: v1.4.192 was the first tag containing the SnapshotStart `terminalOwner`
field, and cutting it turned the new-client/old-server pairing red on unrelated
pull requests with no code change anywhere.

Read what each build publishes from that build. Each host is now paired against
a client of its own version to produce a reference, and the skewed pairings are
compared against that reference, so the expectation is whatever the release
actually shipped. The same class of assertion in the agent-session suite —
"the old build advertises no structured capability and registers no structured
method" — becomes "each build's advertisement agrees with what it registers",
and the "client too old to know this capability" is derived by removing the
capability from the baseline's own list.

The guard is unchanged in strength: a field the old host still publishes may not
be dropped, skew may not change what a host puts on the wire, and a new pairing
asserts the oracle still stalls when a peer cannot decode an opcode the other
side sends.

* test(cross-version-wire): exercise release structured methods

* test(cross-version-wire): load the registered method manifest

* test(cross-version-wire): assert execution, not registration, on both host gates

The release-shaped checkout gate accepted any reply that was not
method_not_found, so a registered-but-throwing handler passed it. The
capability gate asserted a shared host spy had been called at all, so the
second method mapped to that spy could stop reaching the host unnoticed.

* test(cross-version): make the release-shaped skew cover the whole agent-session manifest

The release-shaped checkout is the only place the "registered means usable"
claim is executable today — the baseline release registers none of these
methods — and it was exercising one of sixteen. A handler registered and
returning an execution error passed the suite.

- Declare each method's result in the manifest, so "answered" is the contract
  rather than "did not say method_not_found".
- Give each build a seam to install a host into its own module slot; a release
  checkout has its own copy, so the working tree's host was never this
  dispatcher's, and every host-backed method answered
  structured_agent_session_unsupported — the capability gate's own words.
- Run one execution contract over both skews instead of two divergent loops.
- Pair the AI Vault never-called spy with a positive control; renaming the
  runtime method it watches left it green.

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* Make worktree palette hint rows keyboard-clickable

Hint entries like "See more" are now CommandItems that can be navigated with arrow keys and activated with Enter, instead of being non-interactive divs. This allows keyboard-only users to access the expand actions without mouse interaction.

* Make worktree palette "See more" keyboard-navigable

Preserve cursor position when expanding via keyboard: auto-select the first
newly revealed item at the previous index and restore input focus.
…tablyai#16511)

Both files describe paths with POSIX literals while their subjects compose
paths through `node:path`, so the assertions only hold where the separator
happens to be `/`.

`node-markdown-document-discovery` keys its fake tree at `/repo/docs` and
`/repo/one`, but `discoverMarkdownRelativePaths` descends with
`join(absoluteDirectoryPath, entry.name)` — `\repo\docs` on win32. The child
lookup misses, `readDirectory` yields nothing, and the walk stops at the root:
`docs/guide.mdx` disappears and the depth-limit case never reaches its limit,
so it resolves `[]` instead of rejecting. Keying the children with `join` walks
the tree the subject actually walks.

`git-fetch-head-lock` expects `cwd: '/tmp/repo'` from a subject that returns
`path.resolve(cwd, 'repo')`, which is `C:\tmp\repo` on win32. Asserting through
`path.resolve` pins the behaviour — that `-C` and `--git-dir` are resolved
against the cwd — rather than the separator of whichever machine runs the suite.

Verified on Windows 11: the two files go from 3 failed / 12 passed to
14 passed / 1 skipped, and the wider `src/shared` run shows no regression.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…stablyai#16699)

Refs stablyai#16646

Unify native, WSL, and direct SSH conflict checks behind the execution host, remove the duplicated SSH classifier, and cover orphan/configured remote behavior across both paths.
…ablyai#17284)

* Clarify automation history unavailability and improve recovery UX

- Improve error message to explain run history is unavailable due to host
  version requirements, not automation failure
- Hide misleading "0 runs" count badge when history is unavailable
- Deep-link "update server" recovery actions to specific runtime environment
  in settings instead of pane root
- Add test coverage for run count hiding and recovery targeting

* Watch for deep-linked settings targets that render asynchronously

Some settings panes (such as Remote Orca Servers) fetch and render their
rows asynchronously. Deep links can name targets that don't exist yet,
but the scroll effect has no way to know when they finally mount. Add a
MutationObserver-based watcher to detect when async rows appear and
trigger scrolling.
* fix(browser): close guest-owned split tab

* fix: check sourceId before toggling floating panel on close

The empty-panel toggle is the ambient fallback only. Guest-initiated
closes (with sourceId) target the main workspace and should not toggle
the panel.

* test(browser-split-shortcuts): remove terminal-mirrors close test and un

Removes test case that verified Cmd+W closes guest-owned browser splits when
active-tab mirrors point to a terminal, along with the helper function and
unused fixture properties that only that test required.
* perf(startup): index persisted pane tabs once

* perf(startup): lazily resolve persisted pane tabs
* Improve markdown rich mode: distinguish HTML tags from placeholders

- Consolidate size limit and unsupported content checks into single function
- Refine HTML/JSX detection to validate against rehype-sanitize's known tag names
- Allow bare placeholders like `<id>` and `<project-id>` in rich mode rendering

* Add decision explainer for markdown rich-mode rendering fix

* rm html explainer
nwparker and others added 19 commits August 30, 2026 01:53
…ow (stablyai#17375)

Pure rename, no behavior change. Callers like isCommandAvailable and
isCommandOnPath wrap this in try { ... return true } catch { return false },
collapsing "distro unreachable" and "command absent" into the same value —
a recurring bug class in this subsystem (see
docs/reference/wsl-probe-failure-semantics.md). The OrThrow suffix makes
that swallow visible at the call site instead of implicit in the function
name, so a reviewer notices when a new caller does the same collapse.
…tablyai#17365)

* ci: gate PRs on a real input method, and prove the lane engaged one

No job on the PR gate has ever run a real input method. pr.yml and e2e.yml are
ubuntu-latest with CDP `Input.imeSetComposition`, which is a synthetic
composition; the only job that drives ibus-hangul through xdotool is
terminal-ime-e2e.yml, and it is schedule + dispatch only. A PR could turn the
real-IME path red and merge green.

Route IME source to that lane from pr.yml through the existing
pr-e2e-source-routing mechanism, so it runs on IME-touching PRs and nothing
else. The lane stays out of verify.needs — advisory, like `e2e` — because its
reliability is known only from nightly main runs. Deliberately no
continue-on-error: that reports green and hides the signal.

The harness fails open in ways that all look like success: Playwright reports a
skipped test as a pass, so an unset ORCA_E2E_NATIVE_IBUS_HANGUL, a renamed test,
or a session with no engine all exit 0 having exercised nothing. The specs now
append an engagement receipt only after observing real composition events, and
the runner requires one per expected test before the lane may report success.

Also drop the native spec from changed-e2e: it was already routed there by its
own filename, where it self-skips for want of an ibus session and reported that
skip as coverage.

* ci: let the real-IME step report even when the synthetic step failed
* docs(ime): codify desktop composition regression checks

* docs(ime): define remote verification verdicts

* docs(ime): narrow placeholder masking invariant

* docs(ime): require final-cell caret containment

* docs(ime): cover async attachment settlement

* docs(ime): correct semantic placeholder contract

* docs(ime): record bounded ownership contracts
* feat(sidebar): open linked reviews in Orca browser

* test(e2e): match paired window reveal assertion

* feat(sidebar): focus linked browser tabs

* ci: retry checks after cancelled rerun
…tablyai#17380)

Sibling of execCommandInWslOrThrow (stablyai#17375) with the identical throwing
contract, sitting in the same `try { ... } catch { return false }`
blocks. After that rename the pair read inconsistently — one announced
that it throws, the other did not, while both collapse to a silent
false at the call site.

Also states the contract in a doc comment: it rejects rather than
reporting "absent", so a caller that swallows the rejection makes "not
installed" and "could not run it" the same answer.
… owner (stablyai#17170)

* fix(terminal): render IME caret without placeholder overlap

* fix(terminal): preserve dim mid-line composition tails

* fix(terminal): keep IME caret visible at row edge

* fix(terminal): harden IME overlay lifecycle and layout

* test(terminal): type final-cell layout mock

* fix(terminal): keep final-cell IME anchor on-screen

* fix(terminal): bind IME masking to composer ownership

* fix(terminal): bound IME placeholder session ownership

* fix(terminal): track latest IME placeholder session

* test(terminal): share IME session event fixture

* fix(terminal): keep both writers of the IME candidate anchor in agreement

`textarea.style.left` has two writers: xterm's patched CompositionHelper and
Orca's terminal-ime-candidate-anchor.ts. The anchor module listens on
terminal.element, so within a composition event it writes after xterm's textarea
listener and reverted the final-column clamp the patch had just applied.

Moving the clamp into the anchor module and dropping the patch hunk does not fix
it, and the rendered e2e caught that: CoreBrowserTerminal.ts:444 drives
updateCompositionElements from onRender as well, so xterm re-asserts the textarea
position on every repaint, with no composition event for that module to hear. The
anchor survived only when no render happened to follow — measured as a flake at the
final column, 1561.28px against a 1557px screen edge, the fully unclamped value.

So both writers now compute the same clamp. The patch keeps it, because it is the
writer on the render path and already holds cursorLeft, maxWidth and the preedit
bounds. The anchor module applies the same one, so its composition-event write no
longer reverts the correction in the window before the next render. Both halves are
individually necessary and both are mutation-tested.

Also restores _getRowRemainderText's expression from main: translateToString(true,
x, line.length) and translateToString(false, x, getTrimmedLength()) are the same
call, since upstream does endCol = min(endCol, getTrimmedLength()) under trimRight.

Adds the two missing tests — one installing both anchor writers in a single rig, one
driving a render under an open composition — plus disposal cleanup and clamp-bound
coverage, and moves the Codex/Claude placeholder mask to a follow-up PR.
…ut (stablyai#17385)

stablyai#17372 dropped the exclusion two days early: pdfjs-dist@6.3.289 was published
2026-08-29T12:48Z and does not clear the 4320-minute gate until 2026-09-01T12:48Z,
so every pnpm install in CI fails lockfile verification.
…edit (stablyai#17377)

Split out of stablyai#17170, which now carries only the xterm composition-overlay work.

Codex and Claude draw an all-dim, full-row ghost placeholder. The opaque preedit
overlay reproduces the committed row tail it covers, so without this the ghost is
repeated to the right of the composing syllable instead of staying masked. The
binding keys off the `.xterm-composition-remainder` class that stablyai#17170 adds and
hides it through CSS while a composition owns a structurally verified placeholder
row — bold prompt glyph plus a dimmed model footer below a blank gap for Codex, a
frame line above the prompt for Claude. Arbitrary dim output, shell lookalikes,
and any row carrying typed text keep their tail visible.

readTerminalCursorLineContext moves from src/main/daemon to src/shared because the
renderer now needs the same reader the daemon uses; the move is import-only.

Depends on stablyai#17170.
…ctions (stablyai#17376)

* fix(linear): stop the filter coverage warning firing on complete selections

stablyai#17342 inferred transport-cap truncation from the bounded filter after the
fact, with `atLimit = selectedIds.length >= max`. A row the cap could not fit
leaves no trace in the surviving ids, so at exactly the cap a complete
selection and a trimmed one are indistinguishable from the value alone, and
the inference biased toward always warning. A workspace with 20 teams x 5
status names expands to exactly 100 ids: picking all 5 rows is provably
untruncated, yet the menu read "100 selected · partial".

Record the trim where it happens instead. `applyPickedFilter` holds both the
pre-cap expansion and the bounded result, so it stores the surviving ids as a
truncation record; the notice, section-menu summary, and pill consume that
flag. Keying the record on the ids it describes is what keeps it fresh — the
moment the facet carries anything else (row toggle, pill clear, Clear all, the
prune effect, a workspace switch) the record no longer matches and the warning
goes away, which matters because the prune effect only ever removes ids.
`intended > applied` stays as the fallback for restored filters that carry no
record, and `boundLinearIssueAttributeFilter` is still the last word on the
cap.

Also moves the section-menu partial marker out of the `max-w-[120px] truncate`
summary span, where "100 selected · partial" could clip.

Refs STA-5996

* test(linear): cover the untouched-facet truncation guard

The guard that keeps a recorded trim alive across an unrelated facet click was
untested — the first attempt sat where intended > applied, so the value-derived
shortfall answered for it and removing the guard left every test green. Move the
scenario onto the cap, where only the record can speak.

Also stop an empty record matching an empty facet: a filter carrying nothing is
never truncated.

* test(linear): pin set equality, not subset, on a truncation record

A facet that grew past its record has refetched underneath it; matching by
subset would keep warning about a trim that no longer describes the filter.
Found by mutation: the subset mutant survived the whole suite.

* test(linear): fuzz that the coverage pill and the section notice agree

They are the same claim rendered twice; a pill reading partial over a silent
section is a lie either way round. 20k random topologies, zero divergence.
…blyai#17389)

A bare package name exempts every future version of pdfjs-dist from the
release-age gate, including one published minutes ago. Scope it to the single
version that needs it.
…yai#17392)

A structured send clears the draft asynchronously, on RPC acceptance. If the
user opens the next IME composition first, the clear lands while the browser
owns the field, the DOM sync skips it, and settlement adopts element.value —
which still holds the message that was already sent.

The field now records a clear dropped mid-composition and applies it at
settlement, keeping only what the IME composed on top of the value the field
held when the composition started. Browser ownership is unchanged for every
other programmatic draft; the clear stays on the acceptance path, so a
rejected send still keeps its draft.

Also advances a frame before the attachment-flush focus assertions, which
were vacuous because the focus they forbid is scheduled in rAF.

Fixes stablyai#17359
* fix(terminal): preserve large agent prompt pastes

* fix(terminal): guard oversized SSH PTY writes

* fix(terminal): avoid timer delay for generic sends

* fix(pty): propagate provider write refusals
…ks (stablyai#17361)

When a remote browser pane opens a link with an explicit placementPreference,
honor that override rather than applying the generic browser client policy.
Links opened from remote panes may require specific host placement to respect
execution boundaries.
…auto-sync-fork-with-upstream-stablyai-orca-ru-20260901T1400

# Conflicts:
#	src/renderer/src/components/native-chat/NativeChatComposerField.tsx
Re-homes five seams the release split into barrels (Settings, the settings
nav metadata, web-runtime-session, telemetry-events, NativeChatView), replays
the composer IME rework into the fork's tier-2 copies, and repoints the
manifest seams, residual budgets and tier-2 headers at the new modules.
Copilot AI lite review requested due to automatic review settings September 1, 2026 14:36

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.

🔵 Needs a closer look

This is a large upstream absorption touching critical runtime/IPC/persistence paths and warrants careful human validation beyond spot-check review.

Pull request overview

Syncs the fork with upstream stable v1.4.194, resolving merge fallout and aligning fork-owned seams/copies with upstream splits/refactors while preserving fork-specific behavior (dock composer, release pipeline, etc.).

Changes:

  • Updates workspace/session persistence to include workspace document history, plus associated schema + field-coverage tests.
  • Improves UX/automation safety by introducing background launches (avoid focus-steal) and widening places that honor it.
  • Refactors/extends runtime + IPC contracts around terminal splitting/focus, browser close intent replay, and repo add routing (including displayName).
File summaries
File Description
src/main/network/electron-proxy-request-guard.ts New request gate that blocks default-session traffic until proxy application settles (reviewed for install/idempotence concerns).
src/shared/workspace-session-state-types.ts Adds workspaceDocHistory to persisted workspace session state.
src/shared/workspace-session-schema.ts Wires workspaceDocHistory into the Zod persistence schema.
src/shared/workspace-session-schema-field-coverage.test.ts Updates persisted-field coverage to include workspaceDocHistory.
src/renderer/src/lib/workspace-session-patch.ts Normalizes and patches workspaceDocHistory when present in a session delta.
src/renderer/src/lib/workspace-session-relevant-fields.test.ts Adds workspaceDocHistory to the “session relevant fields” contract.
src/main/window/main-window-state-lifecycle.ts Switches initial reveal behavior to honor “windowless/background launch” policy.
src/main/window/dashboard-popout-window.ts Prevents focus-steal on popout focus/show when background launch is active.
config/scripts/run-electron-vite-dev.mjs Logs when ORCA_BACKGROUND_LAUNCH=1 is set (visibility in dev automation runs).
tests/tools/win-update-e2e/app-driver.mjs Forces background launch in the Windows update E2E harness to avoid stealing focus.
src/main/ipc/repos/local-repo-registration.ts Accepts an optional displayName when adding a local repo, with trimming/fallback.
src/main/runtime/rpc/methods/repo.ts Extends repo.add RPC params to carry displayName.
src/renderer/src/web/preload-api/web-repositories-api.ts Extends preload repos API add call to forward displayName.
src/main/browser/browser-guest-shortcut-dispatch.ts Includes sourceId payload when sending ui:closeActiveTab from guest shortcut handling.
src/preload/close-active-tab-payload-admission.ts Adds an admission layer for legacy vs. payloaded close-active-tab events.
src/renderer/src/runtime/client-hosted-browser-close-intent-replay.ts Extracts a predicate to detect definitively-gone pages for close-intent replay.
src/renderer/src/components/terminal-pane/terminal-pane-split-with-inherited-cwd.ts Extends split routing with worktree/tab/leaf identity for web-runtime focus behavior.
src/renderer/src/runtime/web-session-focus-intent.ts Allows focus-intent clearing to match on optional leafId.
src/renderer/src/components/editor/useRichMarkdownSearch.ts Avoids editor update subscriptions when search UI is closed.
src/renderer/src/components/editor/rich-markdown-task-list.ts Adds an early-exit to avoid scanning full source on non-list input.
src/renderer/src/components/activity/activity-prototype-page-exports.ts New barrel exports for activity prototype surfaces.
src/main/git/worktree-move.ts Adds a safe git worktree move helper (avoids .git pointer corruption).
config/vitest.config.ts Adds happy-dom setup for offscreen canvas.
.github/actions/install-node-dependencies/action.yml Updates pnpm setup action usage and broadens “no drift” diffs to include workspace YAML.
Review details
  • Files reviewed: 179/1087 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1 to +15
import type { Session } from 'electron'
import { getProxySessionApplicationReadiness } from './proxy-settings'

/** Hold default-session requests until the newest app-wide proxy transition settles. */
export function installElectronProxyRequestGuard(proxySession: Session): void {
proxySession.webRequest.onBeforeRequest((_details, callback) => {
const readiness = getProxySessionApplicationReadiness(proxySession)
const answer = (ready: boolean): void => callback(ready ? {} : { cancel: true })
if (typeof readiness === 'boolean') {
answer(readiness)
} else {
void readiness.then(answer)
}
})
}
Each of these upstream-owned files carried an undeclared fork edit, so
ownership resolution correctly reset it to the tag and broke CI:

- the two cross-version-wire tests pin upstream stable tags that do not
  exist on this remote, which is what the fork's own release refs replace
- the two PR-workflow contract tests must know fork_ownership_guard is
  ungated, like root_directory_guard
- the pane-agent-identity ratchet must count the fork's handoff dialog

All five are now seams with recorded residual budgets, so the next sync
merges them instead of reverting them.
Whole-file exceptions kept the fork's copies and silently dropped the
release's unrelated work in the same files:

- the Electron installer's staging-transaction rework (stablyai#17334), which
  rebuild-native-deps.test.mjs asserts by expecting a partial install to
  survive a retry
- the packaged-runtime contract's move from package.json's pnpm block to
  pnpm-workspace.yaml, which v1.4.194 emptied
- release-cut's new e2e prepare-native-cache permission row

Three-way merged against v1.4.193, so the fork's retry-backoff, macOS-only
job matrix and repository guards are unchanged.
The scan pins the root oxlint config, which the sibling scan directly above
it deliberately does not do — mobile/ is its own workspace with its own
lockfile and .oxlintrc.json. Its deps are absent in the job that runs this
gate, so every React Native and react-test-renderer type resolves as an
'error' type and no-redundant-type-constituents fires on the resolution
failure rather than on the code.

Latent for upstream: it only surfaces on a diff that adds lines to a mobile
test, which v1.4.194 does. At least four other mobile files trip the same
rule the moment their lines are touched. The full-tree audit that owns this
rule set already scopes itself to src/config/tests.

Declared pending-upstream with a ledger entry.
Tests: the fork's own NativeChatComposer test drove the field's
onCompositionStart/onCompositionEnd props, which the v1.4.194 replay replaced
with an imeEnterGesture handle plus onImeSettled. v1.4.194's new
native-chat-structured-send-composition-clear suite covers exactly the
dropped-clear path the replay hand-carried into AgentComposerField, so it is
kept and repointed at the fork's actions bar rather than dropped; without the
remap the real bar renders outside a TooltipProvider and every case fails.

Sandbox image: the release deletes .npmrc and moves the pnpm block into
pnpm-workspace.yaml, so the build failed on a COPY of a file that no longer
exists. pnpm 12 also drops the --prefer-frozen-lockfile=false spelling in
favour of --no-prefer-frozen-lockfile. Both test files above were verified
green on the remote sandbox before this commit.
…k edit

pr.yml: the fork exception kept its own copy and dropped the release's new
real-IME e2e lane, its native_ime_source_changed filter output, and the new
cross-version reported-lossy-initial-snapshot spec — which pr-e2e-gate-contract
asserts. Three-way merged, so the fork_ownership_guard job and the fork's own
gating are unchanged; terminal-ime-e2e.yml and the routing flag it needs both
came in with the merge.

use-native-chat-live-session-pending.test.ts: the seventh and last upstream
file carrying an undeclared fork edit. It mocks the relay transport and hook
the fork copied into fork-native-chat-relay/; the reset repointed it back at
upstream's, which the fork does not use. Declared import-swap.

A sweep of every checkout.txt path whose pre-merge fork blob differed from
v1.4.193 found exactly seven such files; all seven are now declared.
@zpyoung
zpyoung merged commit 7f45b36 into main Sep 1, 2026
37 checks passed
@zpyoung
zpyoung deleted the zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20260901T1400 branch September 1, 2026 15:37
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.

9 participants