Skip to content

sync: absorb upstream v1.4.230 - #122

Merged
zpyoung merged 1817 commits into
mainfrom
zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20261018T1400
Oct 19, 2026
Merged

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

Conversation

@zpyoung

@zpyoung zpyoung commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner
Files Added Deleted Net
Test 1120 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​82489 $\color{#cf222e}{\Huge{\mathbf{−}}}$​29597 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​52892
Prod 1880 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​149346 $\color{#cf222e}{\Huge{\mathbf{−}}}$​64912 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​84434

ELI5

This brings the fork up to upstream's newest stable release, v1.4.230. It's built on top of the still-open v1.4.227 sync (#120), so merging this lands both, and #120 then closes as merged.

v1.4.230 is much bigger than a normal sync. It was cut from upstream main after ~1,400 commits, and it deletes the SSH relay the fork's SSH features ran on. As decided by the repo owner, the fork drops its SSH-relay code paths and keeps every feature's local behavior.

What Changed

  • Target: v1.4.230 at b2879bd5aa, merged onto sync: absorb upstream v1.4.227 #120's head (d3dfc479b8, which carries v1.4.227). Resolution: auto-ours+tree (43 delete/modify tree conflicts, resolved by the two mechanical rules, then by the manifest).
  • Fork commits: all 669 are still reachable at their original SHAs.
  • Backup: origin/backup/main-20261019-102904Z at c923f8e30a.
  • Ownership classifier: 13,855 paths reset to the tag, 2,732 removed, 183 exceptions restored, 2,102 merge-review paths. 80 exceptions moved upstream and were three-way merged against v1.4.227.

SSH relay retired (owner decision). Upstream replaced the relay with a managed orcad on every SSH host. The fork deleted src/relay/** and the SSH git/pty providers, and plain ssh: hosts now report "not served".

  • native-chat-relay keeps its renderer half (local paging and live tail) under a narrowed purpose. Its SSH transport is gone; remote chats use upstream's orcad nativeChat.* RPC.
  • hosted-review-sitter, heimdall-objective, project-ledger, terminal-dock, artifact-passwords and session-handoff are now local-only. An SSH target answers "unavailable" or counts as lost contact.
  • Each lost capability is filed as an orca ledger deferred item to re-home onto orcad RPC later.

Module splits re-homed. Upstream dissolved the orca-runtime-*.ts modules, the sidebar grouping files, web-session-tabs-sync, ipc/runtime-environment-* and others. Every fork seam moved to the new home. Stale fork copies of deleted files are gone. Where upstream already did the same thing, the fork seam was dropped.

Native chat. The fork's input-quarantine delta (bug-1) is re-applied on upstream's settings-free send path (stablyai#27279). All 15 tier-2 forked copies now point at v1.4.230. Hidden-pane read gating, which the fork had dropped only for relay reconnects, is restored.

New upstream ratchets adopted in fork code, with no baseline lines added:

  • focus-read and deprecated-runtime-owner: fork code now routes by the resource's owner instead of the "Active Server" setting, copying upstream's own migration. Behavior changes:
    • a workspace two hosts publish now refuses instead of reading as local (ledger panel, session info, sitter panel, handoff);
    • a group created from a worktree takes the worktree's host;
    • a dock's ConPTY verdict and automation model retirement no longer borrow the focused server.
  • layout-writer: the dock mint no longer adds a second layout write in headless-tab-properties.ts.
  • text-[11px] → text-2xs in the plugin-attribution picker seam, and one import() type annotation.

CI.

  • pr.yml, release-cut.yml and release-mac-build.yml are rebuilt as v1.4.230 plus the fork's own delta (fork ownership guard, macOS-only release, no Windows PR lanes, file-based changed-paths).
  • Upstream moved PR CI to Blacksmith runners, which this fork has never used, so those jobs map back to GitHub-hosted runners.
  • The guard stays inside verify.needs. Upstream's aggregate-gate tests learn about it through a new config/scripts/fork-ownership-guard/ module plus two seams.
  • The guard job now skips drafts, like upstream's other entry jobs.

Release-branch workflows. Upstream's 597425845e swapped 9 release-branch workflows for main's without updating the tag's tests, so 8 of the tag's own config tests are red against it. As in #120, the 8 upstream-owned ones take 597425845e^. The next tag resets them.

Retired exceptions:

  • the two relay workflow-inventory tests and bug-2's ssh-remote-commands.test.ts: upstream now passes or matches;
  • the skill release-history files: upstream deleted them;
  • verify-skill-update-roundtrip.mjs and max-lines-baseline.txt: identical to upstream;
  • the git-exec-mutation, relay-test and SSH-provider exceptions: relay retired;
  • relay-windows-process-tree.yml and a stale deleted entry.

Sandbox runner. It now ships src/packages and the native workspace manifests, because upstream moved src/shared/child-process into @orca/process-host.

Why

Taking v1.4.230 means taking the relay deletion. Keeping a fork-owned copy of the whole relay (480 files plus the SSH providers) would be permanent upstream-shaped ownership. Re-homing onto orcad in the same sync would have doubled its size and risk. Retiring the SSH halves keeps every local behavior and stays reviewable. The re-home is tracked in the ledger.

Linked Issue

N/A. This is an upstream sync.

Visual Proof

N/A. This is an upstream merge, and the fork's UI changes are routing-only. Nothing has been checked in a running app yet.

Testing

  • Local gate: all of these pass.

    • pnpm install --frozen-lockfile
    • --verify-seams (1,211 lines / 605 files) and --verify-residuals v1.4.230 (548 files)
    • check-fork-ownership.mjs on the committed head
    • typecheck:node, typecheck:web and typecheck:cli, run one after another
    • full pnpm lint
  • config/scripts + .github tests on the remote sandbox: 4,763 passed and 5 failed.

    • All 5 failures are sandbox-only: the image skips Bun's postinstall (--ignore-scripts), installs a pnpm older than the pin, and ships git 2.43 without reftable. None can fail on GitHub-hosted runners.
  • The full unit suite is left to this PR's CI.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Wire parity: projectGroup.delete and repo.rm stay in the uncatalogued RPC list, because project-ledger extends them with main-side schemas.
  • Untested Heimdall verdict: the "unverifiable host read" verdict lost its only tests with the relay, so a test-gap is filed.
  • Dock state and the layout store: it is declared unwritten in upstream's dark layout-owner store, so shipped builds are unaffected. A deferred item is filed for before that build switch ships.
  • Free-form fork copy: fork-heimdall/orchestration/federation-sync.ts uses a free-form copy header, so tier-2 replay can't see it.
  • Unreleased upstream work not taken: 0 commits on upstream/main past this head as of the fetch.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

nwparker and others added 30 commits October 16, 2026 20:06
…another machine or boot (stablyai#29952)

On a shared home, a peer lock's PID is evidence only on the machine that issued it.
Cache retention judged the instance lock and daemon PID records by PID alone, so a
second machine evicted the slot another machine's live serve or daemon runs from.
…efault flip (stablyai#29949)

* fix(ssh): keep existing hosts' orca CLI control switch off after the on-by-default flip

Builds before the flip saved an explicit off as an absent value, so absent=on
silently turned on hosts the user had turned off. On the first load after this
upgrade, pin every saved host's absent switch to an explicit false and record a
one-shot marker in settings so hosts added later keep the new default.

* test(ssh): check the saved profile without a type assertion

* fix(ssh): say the CLI control switch is on by default for new hosts at the call site too
…ts, not only the desktop (stablyai#29913)

useWorkspaceServer keyed the server's status read on the desktop's connection state, so a server restart or update under a connected desktop never re-read what it supports. It now passes the server's computed state.

Co-authored-by: Claude <noreply@anthropic.com>
…ath twin's shells, tabs and edits (stablyai#29954)

* fix(projects): removing one host's project keeps its same-path twin's shells, tabs and edits

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): close the removed host's browsers, chats and late tabs under a twin id

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): attribute a twin's terminals by every PTY id it keeps, SSH included

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): kill a removed local/SSH twin's shells directly and keep its files out of reopen history

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): prune the removed twin's closed editors from the reopen stack

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): recheck twin survivors after the host call and keep reopen order in step

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): close a removed twin's simulators and prune its closed browsers

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): attribute an unstamped twin browser by its pages' host

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): plan a twin's terminal teardown so PTYs other tabs bind survive

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): treat a null browser host as local and close stale stamped editor tabs

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): a host stamp yields to a PTY naming another host; sweep tabless sleeping records

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): cancel a twin's pending launches, clear its PTY records, prune its local editors

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): an ownerless remote pane blocks a stamp; keep the focused surface on background twin removal

Co-Authored-By: Claude <noreply@anthropic.com>

* chore(projects): leave closeFile's active-surface choice to closeFile

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): keep the selection fields consistent after twin teardown

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(editor): closing a background workspace's file keeps the focused surface

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): a file's own host outranks its tab stamp in twin attribution

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): kill only a twin tab's live PTYs and honor a browser's own host stamp

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): skip twin files the removal refresh already closed

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): kill a batch's live PTYs whichever tab the planner chose; background file close keeps focus

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): resolve a removed SSH copy's paired-runtime alias in twin attribution

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): stop the removed host's pane in a tab another host's pane keeps

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): judge a still-present twin surface on its latest evidence

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): apply the removed copy's runtime alias to launches and history; layout-only hints prove nothing

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): repair a selection naming the removed copy's runtime alias

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(projects): leave single-host selection to the bulk purge; test background file close

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
… as stale (stablyai#29957)

The preparation lock reason named only the owner's pid, so a host sharing the repo's disk
(an NFS home) read another machine's in-progress preparation as abandoned and discarded it.
The reason now carries the writer's machine identity (optional, appended after the fields
older builds read); a different or unknown machine is unverifiable, and a reason without
one is judged by pid only on a local disk.
…pen terminals (stablyai#29958)

* fix(orcad): replace a retired terminal daemon when a client returns during idle shutdown

* fix(daemon): drop idle-retired legacy generations when replacing the daemon

* fix(orcad): treat a lost or late daemon retirement reply as committed

* fix(orcad): settle a lost retirement reply with the daemon itself before replacing it

* fix(orcad): bind the replacement to the retired daemon and honor the router fence

* test(daemon): type the pending census

* fix(daemon): skip the owner check only for a proven-dead endpoint
… still starting (stablyai#29911)

The + agent menu waited 5 s for the new tab's terminal and otherwise showed
"Couldn't launch X — the terminal did not start." Any slow spawn (Windows,
a cold or busy terminal host, a queued spawn) passed through that state and
got the false toast before the agent came up. The pane's own spawn already
reports a real failure in the pane, so the guess is removed.
…er (stablyai#29946)

* fix(sidebar): order sidebar text the same on every device

Sidebar names, project labels, project-group names and folder workspace
names were ordered with localeCompare, whose result depends on the ICU data
bundled with Electron, the phone WebView or Node. Order them with one
comparator in src/shared/sidebar-list/text-order.ts instead: case-folded and
NFC-normalized, digit runs by value, the rest by code point, and equal text
broken by host-qualified id.

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(sidebar): fold each sort label once per sort; reuse the phone row identity helper

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(sidebar): ignore accents when ordering sidebar names

Accents and case now only break exact ties, so "Éclair" sorts beside "eclair".

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#29124)

* fix(native-chat): identify the owner when resume create is refused

* test(native-chat): consolidate transcript refusal cases

* test(native-chat): keep ownership coverage at the launch boundary

* test(native-chat): update adoption fixture for early ownership admission

* test(native-chat): align resume admission assertions with host ownership

* test(native-chat): keep RPC coverage focused on ownership proof

* test(native-chat): assert blank request presence before optional source

* fix(native-chat): admit the actual CLI source during chat creation

* fix(native-chat): satisfy source admission lint checks

* test(native-chat): provide the waiting hook prompt

* test(native-chat): isolate source admission fixtures from host homes

* test(native-chat): canonicalize adoption fixture directories

* test(native-chat): preserve early ownership admission in source stack

* fix(native-chat): preserve resume refusal behavior and honest transcript feedback

* fix(native-chat): retain import read evidence in typed result

* fix(native-chat): preserve admitted source and prepared execution home

* fix(chat): retain source evidence for dispatched adoption

* fix(chat): keep source capture within module limits

* test(chat): allow host evidence in create routing

* fix(native-chat): admit an unsaved transcript under a linked account folder

A missing transcript stayed unresolved while its account root resolved through
symlinks, so containment failed and a not-yet-saved conversation showed a load
error instead of the unsaved notice.

* refactor(native-chat): move the newest-item import window into its own module

Keeps journal-legacy-import.ts under the line limit after the source
identity observer landed on top of the streaming import.

* fix(native-chat): restore the refusal error import lost in the main merge

* fix(native-chat): admit Pi transcripts against the root Session History walks

A PI_CODING_AGENT_DIR that already ends in sessions, or any custom folder,
made admission expect <dir>/sessions while the lookup searched <dir>, so a
found conversation was refused.

* refactor(native-chat): admit and look up CLI transcripts in one store per account

Each agent's import described where an account keeps its conversations twice,
once for the path check and once for the lookup, and the two could disagree
(the linked-folder and Pi custom-root refusals). The import now names one
conversation store per account; the create path resolves it once and both the
hook-path check and the fallback lookup judge that same store. OpenCode's
store is its exact database.
…e like a sidebar delete (stablyai#23593)

* fix(workspace-cleanup): let select-all include the workspace you are in

Deleting the current workspace is allowed like any other, so select-all now
includes it; a live agent stays excluded. Cleanup removal now hands focus to a
surviving sibling after the batch, as the sidebar's batch delete does.

Linear: STA-4686

* test(workspace-cleanup): cover focus handoff after the dialog closes and after Delete anyway

* fix(workspace-cleanup): move focus off a deleted active workspace as soon as its row is gone

* fix(workspace-cleanup): don't reopen a workspace the user left while a cleanup batch runs

The per-row focus handoff fired whenever no workspace was selected, so
closing the successor's last tab mid-batch re-activated it (and spawned a
new terminal) on the next row. Move focus only when the workspace the
batch left the user on is actually gone and nothing else took focus.

* refactor(workspace-cleanup): move focus off the active workspace when a cleanup delete starts

Switch to the successor once, right after the batch rows are marked deleting, instead of
repairing an empty selection after each row settles. The active row is no longer active when
it is removed, so the store never clears the selection and no later handoff is needed.

* fix(workspace-cleanup): never hand focus to a workspace in the same cleanup batch

The scan qualifies local rows as host `local`, so their delete state lives
under a host-qualified key, while a sidebar row with no stored host only
matches an unqualified key. The successor picker therefore saw batch rows as
not deleting and could focus one about to be removed, leaving an empty screen
once it went. Exclude the batch's own ids directly.

* test(workspace-cleanup): use scan-shaped hosts in the active-workspace focus tests

Candidates now carry the `local` host the scan publishes, which is what
exposed the picker gap. The other-host case also stamps the viewed row with
its host so it resolves; before, the lookup missed and the test passed with
the host check removed.

* feat(workspace-cleanup): confirm before a cleanup delete stops a running agent

A cleanup delete (bulk, single row, or "Delete anyway") that includes a
workspace with a running agent now shows a step naming those workspaces
before anything is queued. The check reads live agent state at click time,
attributed like the sidebar so structured chats count too, and re-asks if
another agent starts while the step is open.

The approved candidate records which agents the user agreed to stop; the
per-row preflight that runs right before each delete refuses a row whose
agent started after confirmation. With the step in place, live-agent rows
join select-all like the active workspace.

* refactor(workspace-cleanup): name the agent-stop same-action check

* fix(workspace-cleanup): drop an open agent-stop step when the dialog reopens mid-batch

* style(workspace-cleanup): match the agent-stop step's heading to the delete step

* test(workspace-cleanup): type the cache-hydration mocks in the reopen test

* style(workspace-cleanup): let the agent-stop step's heading use the dialog's own typography

The changed-lines design-system gate rejects restyling DialogTitle and
DialogDescription; the delete step's overrides predate that gate.

* fix(worktree-delete): key delete state by the identity the sidebar card reads

A cleanup delete names local rows with the 'local' host, so their queued and
deleting state landed under 'local|<id>' while a card stored without a host
reads the bare id and never showed it. Every delete-state write now derives
its key from the store's own worktree record.

* refactor(workspace-cleanup): reuse the sidebar delete's focus hand-off

Drops the move-focus-before-delete path. Each confirmed row prepares the same
prepareActiveWorktreeFocusAfterDelete committer the sidebar delete uses and
runs it when that row's own removal succeeds, so the user stays on the
workspace while it is queued, lands on the most recently visited surviving
sibling once it is gone, and stays put if its delete fails.

* refactor(workspace-cleanup): reuse the close-terminal stop-agent wording

The stop step's single-agent title is the existing "Stop this agent?" string,
and its description follows the close-terminal prompt's wording.

* test(worktree-delete): cover a local-qualified removal failure on an unhosted card

* docs(workspace-cleanup): describe the after-delete focus hand-off in the bulk-select note

* fix(workspace-cleanup): name one agent in the stop step's button and keep one agent term per locale

* fix(terminal): keep starting terminals in a workspace that is only queued for deletion

A cleanup batch now marks its local rows with the same delete state the sidebar card reads,
so the terminal spawn guard sees them. The guard exists because removal just killed the
workspace's terminals; a queued row still has them and can fail its own delete and stay, so
a new terminal opened there (often the current workspace) stayed blank.

* refactor(terminal): name the teardown-started check the spawn guards share

* chore(workspace-cleanup): keep one agent term in ko/zh and refresh a spawn-guard comment

* fix(workspace-cleanup): refresh consent and focus per removal

* fix(workspace-cleanup): invalidate detected host evidence

* fix(workspace-cleanup): admit removal at transport send

* test(workspace-cleanup): expect the send-time admission callback and a published chat tab
…ames (stablyai#29966)

Records the post-stablyai#29946 text order for workspace rows (Name, Recent and
project-name sort), project group names and folder workspace names, ungrouped
and grouped by project, so a future ordering change shows up as a golden diff.
…t reported, not the capped status store (stablyai#29905)

* fix(native-chat): decide owed helper work from what the provider reported, not the capped store

Idle cleanup, replacing an outgrown agent, /clear, /compact, rewind,
command handover and the teardown resume marker decided whether a chat
still had helpers running by reading the agent-status store. That store
is a bounded display projection: it refuses records when it is full or
for per-record reasons, and a refused helper is still running.

The host now keeps an uncapped per-session set of the child work its
provider reported running and has not reported over, fed from every
child-work edge before the store sees it. Every owed-work decision reads
that set. An entry leaves on the child's own end (a late end of an
earlier run leaves the current run open, as the store's run verdict
does), on a Stop the store settled, or on the session's end.

The strip's "incomplete" note and Stop all's unlisted route are now
derived: open work that no live current-run record answers to. This
replaces the refused-for-room side list, so every refusal reason is
covered and nothing needs separate bookkeeping.

* test(native-chat): the real-store test sink reads recorded helper handles, as production's does

* fix(native-chat): keep helper run identity through delayed events and Stop

* fix(native-chat): name the host helper lifetime token

* test(native-chat): explain the Stop adapter fixture boundary

* fix(native-chat): derive helper coverage from running store records

* docs(native-chat): clarify running helper coverage

* test(native-chat): use an explicit helper end event

* Scope background Stop to captured child work

* Exercise refused helper Stop race through status store
…#29224)

* fix(mobile): remove the dead space around the chat composer

The Tools toggle floats over the transcript and shows only when the chat
has tool calls; the composer is one row (attach, message, mic, send) until
focused or drafted; Stop takes Send's slot while there is nothing to send;
the bridge lane's working dots move to the transcript's tail.

* fix(mobile): name the composer's content facts for their role

* fix(mobile): preserve composer controls and picker focus

* fix(mobile): typecheck working indicator test lookup

* test(mobile): find the floating Tools pill when checking a chat switch keeps it expanded
…, for Settings and chat (stablyai#29049)

* feat(acp): one install row shows and drives a managed runtime install, for Settings and chat

The row reads the shared host state: Install, byte progress with Cancel, extract and verify lines,
Retry after a failure or cancel, and in Settings Reinstall or Update once installed. A failed status
read says it could not check, never that nothing is installed. Strings in all six locales.

* fix(settings): the install row says when a copy is damaged, when a PATH copy is used, and when the host needs unzip

- A damaged copy reads "This copy of {agent} is damaged." with Install, which repairs it.
- A copy found on this host outside Orca's reads "Uses the copy of {agent} found on this host."
  with no Install, since a launch would never run the download.
- A host without the program to unpack the archive says so, with no Install.

* fix(settings): say why a host running its own copy is offered no download

* fix(settings): the install row says Cancelling only where Cancel was clicked, offers Orca's copy beside one found on the host, and keeps its status line after a failed install

The host no longer publishes a cancelling phase or a missing unzip, so the row drops both: the
row whose Cancel is still out says Cancelling and holds its button until the host's cancel
settles. A copy found on PATH or in an install folder still gets Install of Orca's copy in
Settings (the chat keeps its composer). An older installed release reads Installed. with Update.
A failed first install keeps Not installed. beside the failure and Retry. The status line is a
polite live region.

* fix(settings): the install row says it is retrying a failed status check, and names the step after the download

* fix(settings): a Cancel that fails for no stated reason says the cancel failed, not the install
…ect groups (stablyai#29962)

Relinking projects the server already held still re-imported this desktop's
retained copy of their project groups, so a group renamed on the server while
it was managed failed the reconnect with orcad_migration_project_group_id_conflict.
A relinked move now leaves to the server every group its projects sit in (read
from repo.list's projectGroupId) and those groups' ancestors unless a moving row
needs one, journals those ids, and keeps them out of the exported rows while
still reading them for folder-workspace host ownership. Later delta moves
subtract them as they do moved groups.
…self (stablyai#29964)

* fix(runtime): the host stops a removed project's terminals itself

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): a runtime-stamped project still stops the shells that run here

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): refresh the PTY inventory and sweep again after a project's removal

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): bound the project inventory refresh and recheck the WSL move fence

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): fence a project's removal sweep by its SSH connection and wait out in-flight spawns

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): bound the project stop's lease wait by the removal deadline

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): refuse spawns into a removed project and skip a stop a same-id sibling shares

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): bound each project stop by the removal deadline

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(runtime): pass the removal deadline to the lease so a timed-out waiter is dequeued

Co-Authored-By: Claude <noreply@anthropic.com>

* test(runtime): type the project-removal fixtures instead of casting

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
…s again (stablyai#29984)

Partially reverts stablyai#27540 and the plain-http part of stablyai#27552, which broke web
pairing on upgrade for 1.4.227 users who open Orca at a LAN or Tailscale address:

- The host no longer refuses a first pairing from a plain-http page on another
  machine (insecure_origin, ORCA_ALLOW_INSECURE_WEB_PAIRING).
- Such a page keeps its pairing code in local storage and signs in with it, as
  in 1.4.227, so reloads, new tabs and bookmarks stay paired; no notice.
- Session-only browser keys (pairing.device-key-ephemeral.v1, the idle sweep)
  stay for browsers without Ed25519.
- A web client whose credentials are refused shows the host's reason instead
  of an empty workspace and "Session restore failed".
…-owner build only) (stablyai#29988)

* fix(browser): keep slept workspace browser tabs off the reopen-closed list

Sleeping a workspace closed its browser tabs as if the user had closed them, so
Reopen Closed Tab could bring back a tab that was only slept. Sleep now closes
them with a 'sleep' reason that skips the reopen stack while still releasing
host pages, doc grants and webviews as before.

* feat(layout): send a browser tab's window timestamps with its open (dark)

A layout-owner build's openBrowserTab carried no createdAt, so main stamped the
tab-bar entry and the browser record with its own apply time and the window's
next save diverged on createdAt for both. The window now sends both times, as
createTerminalTab does; only switch-on builds send them.

* Revert "fix(browser): keep slept workspace browser tabs off the reopen-closed list"

This reverts commit 6798c3c.

* test: drop the slept-tab close test that went with the held sleep fix
… (dark, layout-owner build only) (stablyai#29967)

* feat(layout): main-made terminal tabs drawn with main's facts; resume records reach main record-only (dark)

In layout-owner builds only:
- A terminal tab main made itself (drag-out, CLI or host terminal, live-surface
  adoption) is drawn with main's createdAt and creation fields from the frames,
  and the window sends no create for it.
- An editor tab main records takes the time the window drew it.
- Every change of the window's agent resume records (live and quit captures,
  dropped records) reaches main through record-only sleep and wake commands,
  which stop or start nothing.
- A terminal row's remount generation is declared the window's.

* fix(layout): real wake reaches main before the record drop; drag-out keeps a frame-drawn tab (dark)

In layout-owner builds only:
- A resumed pane's wake is sent before the window drops its record, so main's
  wake still finds the pane sleeping.
- A drag-out whose new tab main's frame already drew shows the pane in that
  tab instead of throwing "Terminal tab already exists".
- A main-made tab keeps the window's shell, cwd, host-runtime and launch agent
  where main's copy names none (a runtime create records a shell only when
  its launch named one).
- No record-only wake for a tab the window closed; main dropped its records
  with the tab.
- Tests for the resume-record follower.

* fix(layout): a dragged-out chat pane's new tab opens in chat view in main (dark)

Main's movePaneToNewTab now gives the new tab viewMode 'chat' when the moved
pane is its source tab's chat pane, as the window's own drag-out does. In a
layout-owner build the window adopts the row main's frame drew, so without
this the tab opened in terminal view.

* fix(layout): a bound pane with a resume record starts as a no-op; resume records only for held tabs (dark)

- startPane checks the pane's live terminal before its resume record: a
  running agent's live or quit record does not make its pane asleep. A pane
  with no terminal and a record is still refused.
- The window sends record-only sleeps, like record-only wakes, only for tabs
  it still holds; a capture from a stale agent status no longer names a tab
  main already closed.
…ark, layout-owner build only) (stablyai#29987)

* Agree with main on a workspace's first group and the tab order, and stop writing a preview flag main never stores (dark, layout-owner build only)

Switch-on builds only; switch-off behaviour is unchanged.

Group ids: a window save made before main's frame with a workspace's first
tab carries none of that workspace's tab-bar records, so the Loader rebuilt
the tab in the group it names for the workspace while main had minted a
random one: every workspace's first save replaced main's group. Main now
names a workspace's first group as the window's root group and the Loader
do (`workspaceRootGroupId`), or takes the sender's when the window drew the
tab in a group main lacks (the window keeps its emptied group); the
window's `ensureGroup` names it the same way. The detector reads a lone
group with no stored tree as that group's leaf, as main's own save writes
it. Empty groups: the window never saves a group it holds empty, so a save
cannot bring back one main closed (locked by a test).

Tab order: a reorder the window makes itself (an anchored CLI or agent
create, a reopened tab's old slot) is recorded in main as `moveTab` steps
at the store boundary; callers that already asked main pass
`layoutOwnerHandled`. The reopened-editor record this replaces is deleted.
A paired client's move (`ui:moveSessionTab`) goes to main first through
the tab-bar drop path.

Preview: activating a tab removed its preview flag by writing
`isPreview: false` on every tab; main stores no flag, so every activation
changed the tab in main's model. The window now drops the flag instead.

* Record a reopened tab's place in main every time, leave a move into a tab's own group alone, and keep a preserved preview untouched (dark, layout-owner build only)

Review fixes, switch-on only:
- A reopened tab's place is recorded as one moveTab whenever its old
  position is known, as the deleted editor-only record did, now for
  every kind; the reorder it may make is not recorded twice.
- A move into the tab's own group (a paired client can send one) goes
  to today's no-op instead of a moveTab that reordered the tab.
- Activation that preserves a preview returns the tab unchanged.
Tests: switch-off first group stays minted; tabOrderMoves refuses a
duplicate order.

* Send a paired client's tab reorder to main as its whole order (dark, layout-owner build only)

A client reorder names the group's full order, but it went to main as
one moveTab of the named tab, so [a,b,c] -> [b,a,c] naming c moved
nothing anywhere. It now takes the store's reorder path, whose record
turns the whole order into main's moves (tabOrderMoves), the one rule
for every window-side reorder. Moves and splits still go main-first.
…on suite (stablyai#29991)

Seeds local+ssh, local+runtime and folder twins (one id on two hosts) with live
shells, a dormant tab, dirty docs, drafts, sleeping-agent records and module-level
stores, then runs a hand-declared action table (remove, folder delete, purge,
kill, sleep, select) on one twin and asserts the other twin is untouched.
Today's leaks are listed cell by cell and asserted to still leak, so a fix
turns them red until the entry is removed.
…all in place of its composer (stablyai#29051)

* feat(native-chat): a chat whose host has no program to run shows Install in place of its composer

The chat's one input slot is chosen in one place: a final read refusal, then an owned prompt card,
then Install while the host has nothing runnable (its install included), then the composer. Until
the first status answer the slot stays empty instead of flashing either. Send and slash commands are
refused while Install holds the slot, so nothing hidden reaches the host. The draft stays in its
store and is there when the composer returns. A failed status read leaves the composer; the host
remains the final refusal.

* fix(native-chat): keep the composer slot reserved until the host's agent list says, and say nothing about sending while Install shows

- While the host's capabilities or agent list are still loading for a chat's agent, the slot stays
  quiet instead of flashing the composer.
- While the install row holds the composer's place, a failed start's notice ("Send your message
  to try again", Retry) is left out: nothing starts until the install lands.
- The chat install card's title is semibold like the other cards in that slot.

* fix(native-chat): keep the chat session view within its line limit after the install slot

* fix(native-chat): the composer stays while the host's first install answer is out, its sends held, so no agent's chat loses its input box

* fix(native-chat): the install slot holds Send through the composer's existing held-send reason instead of a flag of its own

* fix(native-chat): the install slot hands the chat its held-Send reason, keeping the chat session view under its line limit
…ainst the window in dev and test (stablyai#29980)

* feat(sidebar): main produces per-workspace activity facts in shadow mode

* perf(sidebar): agent pings keep last-read surfaces; shadow counts comparisons

* fix(sidebar): settle review findings in the activity-facts producer and shadow check

* fix(sidebar): refresh on inventory verdict clears; resync agents only when tabs move

* fix(sidebar): scope the shadow comparison by each row's owner, not the focused host

* refactor(sidebar): name the shadow scope after what it keeps

* fix(sidebar): classify sidebarInputs as host-owned in the operation ownership census
brennanb2025 and others added 9 commits October 18, 2026 11:17
…tablyai#30137)

Two merged changes left lines past the formatter's 100-column width in
structured-session-create-support.ts, structured-agent-session-create-adoption.ts
and transcript-opencode-sqlite-query.ts. Any branch that merges main gets them
reformatted by the pre-commit hook, which pushes two of them past the 300-line
limit and fails CI. Format them, and keep them under the limit by moving the
bounded row readers and the resume adopt payload into the modules that own them.
No behavior change.
…stablyai#30436)

* fix(native-chat): a Claude chat keeps a model its CLI stopped listing

Claude Code 2.1.302 stopped listing opus[1m], which still runs, and chats on
it moved to the list's default on the next send, effort remapped. The picker
no longer derives a replacement from the list: the chat's own model shows as
a selected-only entry, its effort read-only, and every send carries both.

A real model_not_found reply still recovers: the options answer shows what
the reset child runs, so the next send records it. A reopened chat's catalog
read lists its own model so older clients that replace one keep it too.

Tracked in STA-10947.

* test(mobile): drop the send-options capability the options hook no longer reads

* test: an unlisted model's saved effort shows read-only at rest, as live, for every agent

* fix(native-chat): round-1 review fixes; a new chat's unlisted remembered model falls back as on main

- The read-only value predicate keys on the effort row, so the phone's legacy
  host Permissions row opens as before.
- The desktop read-only effort row honours a row kept from the previous model.
- A live child with no listing of its own answers with the saved listing's
  ids, so the read-only effort reads the same live and at rest.
- The read-only effort borrows listed rows' effort label and level names.
- The host seeds a new Claude chat from a remembered default the saved listing
  no longer names on that listing's default, effort nearest, as main did; a
  chat's own saved or running model is never replaced.

Tracked in STA-10947.

* test: pin the new-chat seed fallback on its typed helper, with no casts

* fix(native-chat): round-2: a carried effort moves with a fallen-back model; one guard

- An at-rest create carrying an effort but no model, on a remembered model
  the saved listing no longer names, now moves that effort to the nearest
  level the fallback model offers, as main did.
- A create whose own options name no model, and whose merged options carry
  none, reads no listing.
- The seed fallback keeps one guard and no unreachable branch.
- The read-only effort finds its level's name in any listed model's choices.

Tracked in STA-10947.

* fix(native-chat): a live options read with no record borrows no saved ids and never throws

(cherry picked from commit 0322185)
…ai-orca-ru-20261018T1400

v1.4.230

# Conflicts:
#	config/scripts/electron-builder-mac-channel-config.test.mjs
#	config/scripts/node-pty-windows-pty-teardown-patch.test.mjs
#	config/scripts/win32-test-lane-registration.test.mjs
#	mobile/src/session/MobileNativeChatView.test.ts
#	resources/skills/release-mapping.json
#	resources/skills/snapshot-registry.json
#	src/cli/specs/search.test.ts
#	src/main/ipc/ssh-relay-session-callbacks.ts
#	src/main/ipc/ssh.ts
#	src/main/ipc/worktrees/removal/remove-unregistered-worktree-host-home.test.ts
#	src/main/native-chat/agent-session-journal/journal-row-writer.test.ts
#	src/main/native-chat/agent-session-journal/journal-subagent-liveness.test.ts
#	src/main/native-chat/structured-agent-session-create-support.test.ts
#	src/main/providers/ssh-git-provider-diff.test.ts
#	src/main/providers/ssh-git-read-provider.ts
#	src/main/providers/ssh-git-remote-sync-provider.ts
#	src/main/providers/ssh-pty-provider-rpc-operations.ts
#	src/main/providers/ssh-pty-provider.ts
#	src/main/runtime/rpc/methods/structured-agent-session-optional-model-capability.test.ts
#	src/main/runtime/rpc/rpc-streaming-dispatcher.ts
#	src/main/ssh/ssh-relay-session.ts
#	src/main/ssh/ssh-remote-orca-cli.ts
#	src/main/stats/stats-snapshot-writer.ts
#	src/relay/git-exec-validator.ts
#	src/relay/git-handler-diff-read-coalescing.test.ts
#	src/relay/git-handler-registration.ts
#	src/relay/git-handler-submodule-ops.test.ts
#	src/relay/git-handler-sync-operations.ts
#	src/relay/relay-runtime-services.ts
#	src/relay/remote-artifact-cli-input.ts
#	src/renderer/src/components/native-chat/NativeChatComposerActions.test.tsx
#	src/renderer/src/components/native-chat/native-chat-composer-prompt-recall.test.tsx
#	src/renderer/src/components/native-chat/native-chat-observed-send.ts
#	src/renderer/src/components/native-chat/native-chat-queue-send-confirm.test.tsx
#	src/renderer/src/components/settings/setting-ownership.test.ts
#	src/renderer/src/components/sidebar/SidebarWorkspaceFilterSection.tsx
#	src/renderer/src/components/sidebar/visible-worktree-kinds.ts
#	src/renderer/src/components/sidebar/worktree-list/grouping/build-rows.ts
#	src/renderer/src/components/sidebar/worktree-list/grouping/worktree-grouping.ts
#	src/renderer/src/runtime/web-session-tabs-sync.ts
#	src/shared/git-exec-mutation.test.ts
#	src/shared/git-exec-mutation.ts
#	tests/e2e/structured-attention-relay-settlement.unit.test.ts
Resolve every path to its manifest owner after merging v1.4.230 onto the
v1.4.227 sync (PR #120), re-home fork seams onto upstream's module splits,
retire the fork's SSH-relay halves (upstream replaced the relay with orcad),
and adopt v1.4.230's owner-routing and layout-writer ratchets in fork code.
Copilot AI balanced review requested due to automatic review settings October 19, 2026 11:56

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 was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps Bot 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

…lls check

run-node-server-tests.mjs pinned the bundled CLI skills source to stablyai/orca,
but the fork's skills-repository feature points installs at zpyoung/orca, so the
Headless Node server persistence job failed on every fork PR.
v1.4.230 renamed the changed-code-quality and React Doctor steps, so the
fork's >500-file skip was not replayed onto them. On a sync PR every upstream
line counts as changed, and both scans report upstream code that upstream's
own CI never sees. Baseline lint and typecheck still run.
… fork code

Heimdall fork code built worktree ids by hand; it now uses composeWorktreeId and
getRepoMainWorktreeId. The fork worktree-groups e2e spec now passes the fetch
options and host id that upstream's store actions require.
…lysis

The rebuilt pr.yml took upstream's two localization steps verbatim, which call
verify-localization-extraction.mjs and verify-localization-catalogs.mjs
directly and skip the fork wrapper that overlays fork-*/locales catalogs, so
every fork key read as missing. Both steps now run fork-localization-catalog-check.mjs,
matching package.json's verify:localization-* scripts, and the upstream scope
test that pins the extraction command follows through a one-line seam.
@zpyoung zpyoung added the allow-runtime-launcher-protocol-bump Allows a PR to carry a daemon protocol bump together with runtime launcher changes (upstream syncs) label Oct 19, 2026
…ware

v1.4.230's workspace-attention slice reaches visible-worktree-options-from-state,
whose fork seam imported the activity/review filter hook modules and through
them @/store, so the store was built before that slice finished loading and
every suite constructing the store crashed. The pure context readers now live
in store-free modules that the hooks re-export.

The two advisory benchmark workflows now report 'no baseline' when the
benchmarked script is new in the PR, build the mobile-web bundle before the
orcad smoke arm, run the fork localization wrapper, and give the compilers arm
a timeout it does not pass only by luck.
…ests

Upstream's new censuses (host-operation ownership, WSL-move storage) now
require the fork's RPC namespaces and stores to be classified; fork seams no
longer read state upstream test doubles omit (automation launch settings,
group menu repos, activity option row); fork tests follow upstream's new
shapes (settings-free composer sends, upstream code-fence coloring, owner
routing mocks, store mock shape) and the fork's repository URL and app id.
The sandbox runner now matches CI with an init process and
ORCA_BACKGROUND_LAUNCH=1.
…f upstream's highlighter

v1.4.230 colors native-chat code fences itself, so the fork's hljs path no
longer rendered. Per the owner's decision the fork drops it (CommentMarkdown /
message-row seams, .native-chat-code rules, their tests) and keeps the
tool-glyph coloring. Inline code in chat prose loses the fork's accent chip,
which rode on the same highlightCode prop.
- artifact-passwords: read the safeStorage backend through guardedSafeStorage
  so the store honors the keychain withhold (safe-storage import ratchet)
- terminal-dock: move the remote-ConPTY dataset key into a UI-free module so
  pane-created no longer drags the editor tree into launch-parity tests
- cross-version harness: map a module a pre-v1.4.228 baseline release lacks to
  its earlier location, so upstream's suite runs against the fork's 225-based
  release
- fork tests follow upstream's new device-credential minting, attention
  'viewed' semantics, nested session-info locales and fork fix-checks module
- PR benchmarks: plan the native compiler with heap estimates that fit a 16 GB
  runner and retry the release-JavaScript jobs snapshot
…y mistake

The benchmark run's local output under .build/ was swept into 3e4ed86;
it trips the root-directory guard and the ownership guard's coverage check.
…k-with-upstream-stablyai-orca-ru-20261018T1400
… route

Upstream's release-branch commit 5974258 copied main's pr.yml, adding a
required dependency_isolation job, without the rest of stablyai#30254: the scope
script never emits the selection and the job's test file does not exist in
this release, so verify fails every PR with 'missing or invalid selection'.
@zpyoung
zpyoung merged commit 0316f51 into main Oct 19, 2026
135 of 136 checks passed
@zpyoung
zpyoung deleted the zpyoung/auto-sync-fork-with-upstream-stablyai-orca-ru-20261018T1400 branch October 19, 2026 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

allow-runtime-launcher-protocol-bump Allows a PR to carry a daemon protocol bump together with runtime launcher changes (upstream syncs)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants