Skip to content

sync: upstream d4144ce5ed into swaplabs/main - #88

Merged
kiwidream merged 165 commits into
swaplabs/mainfrom
sync/upstream-20261105
Nov 5, 2026
Merged

kiwidream merged 165 commits into
swaplabs/mainfrom
sync/upstream-20261105

Conversation

@kiwidream

@kiwidream kiwidream commented Nov 5, 2026 •

Copy link
Copy Markdown

Daily upstream sync (auto-sync run 44, minidev-alex1). Supersedes #87, whose head main conflicted and takes no commits.

Upstream range: 974bb4a7ca..d4144ce5ed, 164 commits (compare). Upstream's regrouping of config/scripts (stablyai#38130, stablyai#38407), src/main/daemon (stablyai#38462), the relay (stablyai#38374), runtime integration commands (stablyai#38504) and the right sidebar (stablyai#38101) accounts for 2,296 renames.

orca-fork-ops status (integration d0355dab26, mirror d4144ce5ed): 0 merged upstream, 0 pending upstream, 93 local forever (30 unprefixed with no upstream PR); 19 merge carriers, 0 unchecked. Upstream tags v1.4.249 and v1.4.250 were copied to the fork this run.

Conflicts: 14 paths, 15 hunks, no operator decision

Fork PR Path Took
#10, #16 electron.vite.config.ts upstream's moved build-source-commit.mjs import, plus the fork's withSwaplabsUpdateDefines import
#10 src/main/updater/releases/updater-changelog.test.ts upstream's deletion (stablyai#38113). The fork's one case moved unchanged to the fork-owned updater-changelog-release-source.test.ts
#23 .github/workflows/pr.yml upstream's moved check-react-doctor-changed.mjs path, plus the fork's ORCA_SYNC_PR_DIFF_BASE env
#25 daemon-out-of-process-launcher.ts, daemon-legacy-adapters.ts, daemon-main.ts, daemon-server-options.ts, daemon-server.ts, daemon-pty-adapter.ts import lists only: upstream's owner paths (stablyai#38462), plus the fork's drain imports at their new paths
#25 daemon-pty-runtime-state.ts upstream's: DaemonPtyAdapterOptions moved out. The fork's draining option followed it to daemon-pty-adapter-options.ts unchanged
#30 src/main/agent-hooks/ended-process-reconciliation.test.ts the fork's rewritten case (dismissed identity survives a certified PTY exit without being resumable), beside upstream's removal of the neighbouring cases
#30 src/main/agent-hooks/manual-compact-status-cleanup.test.ts upstream's deletion (stablyai#38129). The fork only adapted its expectation; server-terminal-loss-presence.test.ts still covers the retained identity
past sync resolution (#69) src/main/runtime/orchestration-mailbox-delivery-recheck.test.ts upstream's deletion (stablyai#38255). The fork only waited out its own draft hold; orchestration-mailbox-typing-hold.test.ts still covers the hold
past sync resolutions config/flaky-test-pattern-baseline.txt upstream's file, plus the fork's 17 # fork test rows inserted in place (daemon-drain.test.ts at its new path)

Breaks the conflict list did not show

  • Fork build workflow: .github/workflows/swaplabs-build.yml called config/scripts/ensure-native-runtime.mjs, which upstream moved to config/scripts/native-build/node-addons/. Both build legs (Linux, macOS) now use the new path. Nothing but a real build would have caught this; it comes from a scan of path literals on the fork's lines.
  • Fork script imports: config/scripts/swaplabs-build-version.mjs follows release/versioning/release-title-timestamp.mjs and dev-channel-base-version.mjs.
  • Fork files stranded by refactor(daemon): group endpoint, provider, session and transport owners stablyai/orca#38462: git's rename detection moves only upstream's files, so 8 fork-only files stayed in src/main/daemon/. They moved beside the owners upstream chose, with only their relative imports changed:
    • launch/: daemon-drain.ts; test in launch/testing/
    • endpoint/publication/: daemon-endpoint-handover.ts; test in its testing/
    • providers/adapter/: daemon-pty-drain-state.ts
    • providers/routing/: daemon-router-drained-daemon.ts; daemon-pty-router-drain.test.ts in its testing/
    • providers/lifecycle/testing/: daemon-init-drain.test.ts
  • max-lines, two clean auto-merges:

Fork lines dropped

None beyond the two adapted test files above, whose only fork lines were expectations in upstream tests upstream deleted.

Validation

Run on merge 180834d09a (signed with the sync key, verified G BF1DD75F888E96080C2453E2D9E158C5D6874235) against integration head d0355dab26. ORCA_* variables unset for tests.

  • pnpm install and pnpm tc: pass.
  • pnpm lint: all 41 steps pass.
  • pnpm run check:code-quality:changed with ORCA_SYNC_PR_DIFF_BASE=<mirror>: 0 new findings across 371 files. check:flaky-test-pattern-ratchet: pass. ast-grep-gates.mjs with ORCA_SYNC_PR_DIFF_BASE=<integration head>: pass.
  • Every test file differing from upstream (123 files, including the fork's scripts): 1,436 tests pass, 8 skipped.
  • src/main/daemon, src/main/agent-hooks, src/main/updater, src/main/runtime/orchestration-*, terminal-pane: 985 files pass, 2 fail (4 tests). Both are upstream's bash-wrapper tests (bash-prompt-command-composition, shell-ready-bash-wrapper) and the same 4 tests fail on pristine d4144ce5ed on this host.
  • config/scripts: 408 files pass, 11 fail on this host. 10 pass with fixture signing off. The other (windows-native-preparation-benchmark, "Duplicate environment keys") fails the same way on pristine d4144ce5ed.
  • orca-runtime.test.ts (runs orca-runtime-tests/*.spec.ts), fixture signing off: 1,351 pass, 3 skipped.
  • Fork-file scans: every relative and @/ specifier resolves, including vi.mock paths. No path literal on the fork's lines names a moved file.
  • Pre-commit hook ran normally; the tree is identical before and after (356617db51).

Not run: the fork's Playwright e2e specs (paired-emptied-workspace-empty-state, paired-host-agent-resume-after-terminal-loss, update-sources-buttons) and a packaged build. The SwapLabs Fork Build run after the merge is the first real test of the swaplabs-build.yml path change.

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

Files Added Deleted Net
Test 1540 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​9219 $\color{#cf222e}{\Huge{\mathbf{−}}}$​59324 $\color{#cf222e}{\Huge{\mathbf{−}}}$​50105
Prod 1460 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​18662 $\color{#cf222e}{\Huge{\mathbf{−}}}$​14356 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​4306

OrcaWin and others added 30 commits November 4, 2026 03:40
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
… workspace switches (stablyai#38176)

* fix(native-chat): keep loaded chat images cached across scroll and workspace switches

Inline Markdown images and sent-image thumbnails evicted their cache entry
whenever they left the viewport or their chat was hidden, so every return
re-read the file (over RPC on remote workspaces). Drop the eager release and
let the bounded shared cache evict unpinned entries when it needs room.

Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com>

* refactor(editor): remove unused local image release and version tracking

---------

Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…echoes them back (stablyai#38186)

A paired server that serves this desktop's own browser row back without
the host stamp from stablyai#36447 (e.g. a peer on 1.4.245 or older) made
buildMirroredBrowserTabs reuse the row's workspace and page ids, so the
local page was rebound to that server and its webview destroyed.

A mirrored row can no longer claim a page this desktop holds as its own
or a live other runtime's. Pages of a removed runtime stay reclaimable so
a re-paired server still adopts them.
* Use the shared agent picker for Automations

Preserve sparse authored launch settings and full Arguments through the existing Automation owner, copies, and host launch compiler. Keep legacy writers and supported mixed-version launch routes intact.

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Courtenay <1909814+hdsheena@users.noreply.github.com>
Co-authored-by: Andy Zhang <hiandyzhang@gmail.com>

* Align the new launch-settings translations with the catalog

* Preserve automation launch choices through editor changes

* Use supported legacy arguments in the editor regression

* Keep automation edits controlled until Save

* Compose automation launch edits by their authored sources

Preserve controlled raw input, cumulative source retirements and agent reset intent through destination changes and Save. Merge only the authored extent into the latest automation.

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Courtenay <1909814+hdsheena@users.noreply.github.com>
Co-authored-by: Andy Zhang <hiandyzhang@gmail.com>

* Preserve pending automation arguments across agent changes

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Courtenay <1909814+hdsheena@users.noreply.github.com>
Co-authored-by: Andy Zhang <hiandyzhang@gmail.com>

* Preserve automation source order and unchanged picker rows

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Courtenay <1909814+hdsheena@users.noreply.github.com>
Co-authored-by: Andy Zhang <hiandyzhang@gmail.com>

* Keep picker Arguments stable until acceptance

* Preserve Chat import and capability regression inputs

* Exercise explicit picker acceptance in retained form tests

* fix: preserve legacy-only automation copies across host changes

* Use canonical automation validation and one host capability observation

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Courtenay <1909814+hdsheena@users.noreply.github.com>
Co-authored-by: Andy Zhang <hiandyzhang@gmail.com>
…ai#38191)

* fix(pi): show compaction in native chat and hold sends until it ends

* fix(pi): wait out compaction before the dispatch liveness checks

* refactor(pi): separate releasing waiting sends from compaction end

* fix(pi): wait out compaction after option RPCs, right before the prompt write

* fix(pi): reapply a send's options after waiting out compaction
…ablyai#37074)

icon.png shipped its own rounded corners, transparent corners and a bright
bevel. iOS applies its own corner mask on top, so the bevel showed as a sharp
light outline, most visibly on Spotlight's search results.

Replace the bevel and corners with the icon's existing vertical gradient,
extended to a square opaque 1024x1024 RGB image. The logo is unchanged.

Verified by pixel checks (no alpha channel; rows outside the logo are uniform;
no logo-region pixel moved by more than 6/255) and a simulated iOS mask. Not
yet checked on a device.

Fixes stablyai#26834

Co-authored-by: Rongzheng Liu <tianlrz@users.noreply.github.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
…ts screen (stablyai#38187)

* feat(mobile): show every desktop usage provider on Accounts

* refactor(status-bar): import moved usage helpers from shared

* refactor(mobile): reuse shared usage rules for provider names and data checks

* test(mobile): type account-slot fixtures as Claude/Codex limits
…blyai#38194)

Rows named only the workspace, so with several agents in one workspace they didn't say which conversation needed you. The newest live top-level agent in the row's dot state now gives the title, the workspace moves to the subtitle, and tapping the row opens that conversation's tab. Older desktops send no names and keep the workspace title.
…ding (stablyai#38162)

* feat(native-chat): add a setting to keep the scroll position when sending

Own sends from a pane bring the latest into view and follow the reply.
A new Chat > Behavior setting, "Scroll to latest when sending" (on by
default), turns that off: a reader who scrolled up stays in place, one
at the end keeps following the reply, and Jump to latest still works.

The gate sits in the one reveal every send path reports to, so the
explicit Jump to latest button and find navigation are unaffected.

Fixes stablyai#38153

* fix(native-chat): keep following a reader at the end when reveal on send is off

A reader can sit at the end without following (a rail jump that clamps at
the end, a short nudge up). The setting's gate skipped their reveal, so
the sent message and its reply grew below the viewport. The list now
decides: off skips only readers who stopped away from the end, judged by
where they last scrolled so the send's own echo doesn't count.

* refactor(native-chat): read the scroll-on-send setting through one helper

Also drops the redundant 'scroll' search keyword (the title already
matches) and the settings switch call-shape test.

* fix(native-chat): decide the send reveal from where the reader was at the press

The last-scroll distance stayed small after output grew past a reader who
had nudged up, so a later send still jumped them with the setting off.
The list now reads live geometry, and a structured message, which reveals
only once the host admits it, captures that answer at the press, before
its own echo moves the end.

* fix(native-chat): read the reader before Resume waits for the host

Resume reveals only after the host lifts the pause, by which time the
drain may already have added rows below the reader.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
stablyai#38202)

* feat(native-chat): let users change or turn off the idle stop for chat agents

The idle sweep stopped every chat's agent after a hard-coded 30 minutes,
which broke peer messaging, Claude Remote Control and background
subagents. Settings > Chat > Behavior now picks the window, including
Never, and the sweep reads it every tick so a change applies without a
restart. Never only keeps agents running: a chat handle with no agent
still retires on the default window.

* test(native-chat): type the childless sweep fixture's journal parameter
…stablyai#38203)

* fix(ai-vault): list managed Antigravity chats in Agent Session History

Orca's managed Antigravity chat sets GEMINI_HOME under the app's data
directory, so its transcripts land in antigravity-chat/antigravity-acp/brain,
which the history scanner never walked. Scan that root, take each session's
cwd from the server's conversations/<id>.meta so the row shows in its
workspace, and treat rows no chat owns as transcript references, since agy
cannot open the server's conversations.

* fix(ai-vault): scan managed Antigravity chats only for reference-aware clients
* fix(contextual-tours): keep the Split tip until the user splits or closes it

The Split a terminal pane tip was saved as seen the first time it painted,
so any dialog, page change or restart ended it for good and the next tip
never appeared. A step that waits for an action is now done only when the
split succeeds (the saved split record) or the user closes the tour; the
tour resumes at its first unfinished step and keeps its session slot while
paused.

* fix(contextual-tours): a resumed tip never takes focus, at any step

* fix(contextual-tours): keep the pause across an activation that never painted

* fix(contextual-tours): a forced tour can't take a paused Split tip's place

* fix(contextual-tours): type the focus hook's tour ids

* fix(contextual-tours): remember a resumed tour in the store, and stop watching for a sidebar tip while the sidebar is closed

The overlay unmounts between activations, so its pause memory never
survived; the activation itself now says it resumes a tour already
started this session.

* fix(contextual-tours): keep the agent-sessions interaction counted only before a first split

* fix(contextual-tours): a tip that waits for a split never takes keyboard focus

It shows over the terminal the user types into and comes back each
session until they split, so taking focus (first display, after a
restart, or on the next tip after a keyboard split) would send their
keystrokes to its dismiss button. Replaces the in-memory resumed flag.

* fix(contextual-tours): keep focus in the callout when the user navigates inside it

* fix(contextual-tours): let other pages' tips show while the Split tip waits for a split

The Split tip now sits outside the one-tour-per-session limit while it is unfinished: it
neither blocks another page's tips nor is blocked by them, and it resumes afterwards.

* fix(contextual-tours): open the sidebar for a paused Split tip only if it started this session

* fix(contextual-tours): decide the session limit inside the tour effect, as main read its inputs
…is being created (stablyai#38196)

* fix(projects): refuse project removal while a workspace is being created

Removing a project mid-create let the create land a workspace no project
owns, and its armed .orca-preparing checkouts outlived the project: a quit
inside their TTL leaked them locked, since crash reclaim only runs when the
same repo prepares again. Hold each create against its project row so
removal refuses until it settles, and release the repo's armed and
crash-left preparations when the project is removed.

* fix(projects): keep project removal working when its runtime needs repair

Resolving Git options for the dead-owner reclaim threw for a WSL runtime
needing repair, which blocked forgetting the project. Make the reclaim
best effort, and give host-setup deletion the same create fence and
preparation release as project removal.

* fix(projects): skip WSL boot and late prefetch arms on project removal

The removal-time reclaim no longer boots a stopped WSL distro, and a
prefetch that finishes after its project was removed no longer arms a
checkout nothing would reclaim.

* test(projects): assert the removal refusal by code, not copy

* refactor(projects): key the create hold by the shared repo host identity

* refactor(projects): keep workspace creation under the file line cap
stablyai#37895)

Claude Code suggests allow rules with destination localSettings, and Orca
passed them back unchanged, so "Allow for this session" wrote a permanent
rule to the project's .claude/settings.local.json. Scope every suggested
update to the session, as the button says.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…abs (stablyai#38206)

* revert(mobile): drop the details card on session tab taps

Reverts 852391d (stablyai#36395). The card popped up on every tab switch.
Tapping a tab switches tabs again, and the session title card goes back
to its own owner from stablyai#30389. Keeps later changes to these files: tab
press feedback, the compact top bar's + button, and stablyai#36866's keyboard
keep-focus for title taps.

* fix(mobile): hide branch and folder when the setting is off

The phone's workspace row always printed the branch or folder path, so the
Branch name / Branch / folder path toggle under Card display did nothing.
The shared card details now carry that rule, and the row reads it.

* fix(mobile): centre the chevron on Home list rows

* fix(mobile): scroll sheets taller than the screen

Content-sized sheets ride the keyboard by translation, but their height cap ignored that lift, so a tall sheet pushed its top off screen with no way to scroll back to it. The cap now gives back the keyboard lift. Sheets that scroll their own list can now shrink to the cap instead of clipping it, and the GitHub Pages picker no longer nests its list inside the drawer's ScrollView.

* feat(mobile): show each desktop's machine kind and model

The desktop now reports whether it is a laptop, desktop or server, and its
model, on status.get. The phone stores it with the other last-known host
fields and turns it into a line like "MacBook Pro · macOS".

* feat(mobile): edit a host from its screen and align the Automations bar

The host screen's menu gains Edit host and Network diagnostics. Edit host moves
onto the standard bar and gains Remove host. Automations uses the standard bar
with its switcher pinned under it, as Source Control does.

* feat(mobile): arrange Home and bring back stats and account usage

Home drops the Jump back in times, names the repo on every Jump back in row
(stablyai#37642), shows each desktop's machine kind, and adds stats and account usage
at the bottom. A new Arrange button reorders and hides sections, saved on the
phone.

* fix(mobile): keep the page bundle within budget and show the machine on the host screen

The edit route gets a web stub so its native-only removal flow stays out of
the page's chunks, and Automations keeps its own segment style. The host
screen header shows the machine line like Home does.

* fix(mobile): give the edit route's page stub its own module

A bare re-export of the catch-all route compiled to the same asset as
[...page], so the page manifest listed it twice and the desktop template's
inventory check refused the build.

* feat(mobile): turn Home into Feed, Usage, Automations and Settings tabs

Feed keeps agents (needs-you first, five then Show all), desktops with a
needs-you count, and Tasks; New workspace moves to a floating button.
Usage shows stats and per-desktop account usage, Automations a per-desktop
summary with on/off switches that opens the page for editing (new=1 opens
its editor). Settings becomes a tab. Arrange Home is removed: tabs replace
the long scrolling Home it was for.

* style(mobile): darken the accent blue slightly

* style(mobile): give the Home Tasks row the desktop tile icon

* style(mobile): condense the Home Feed

Smaller tiles, type and gaps; a desktop is two lines with its needs-you
count as an amber pill; the Tasks row drops its duplicate heading.

* style(mobile): drop the Last known prefix on Home desktop rows

* chore(mobile): bump to 0.0.63 and Android versionCode 27

* test(mobile): re-record Linear task recordings for the darker accent blue

* test(mobile): check the page Back stack on Tasks now that Edit host is native

* fix(mobile): pass the Usage tab's limit window to the shared usage helpers

* fix(mobile): type the Usage tab test to the account-slot limits and keep the tab under 400 lines
…e accounts (stablyai#38219)

* fix(claude-accounts): keep /model and effort saved in a managed account across launches

Profile settings.json was overwritten from ~/.claude/settings.json on every
launch. Apply only the top-level keys the default home changed since the
last sync, tracked by per-key digests beside the profile marker, and keep
the rest of the profile copy.

* test(claude-accounts): fail hook install through a broken linked settings file

* fix(claude-accounts): leave an unreadable account settings file alone

* fix(claude-accounts): carry Orca hook changes in the default home to account copies

* refactor(claude-accounts): spell out the no-record case in the settings sync
…38223)

Delete 19 whole suites and update coverage metadata and reduced flaky-pattern counts.

Co-authored-by: Codex <codex@openai.com>
OrcaWin and others added 22 commits November 5, 2026 01:03
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* Cache projected worktree rows for faster workspace selection

* Fixed workspace-catalog.ts:171 to key by stable repo/host identity instead of repo object references. Existing revision and scan invalidation remain intact.
* Add refresh action for folder project groups

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refresh nested folder groups and flag incomplete scans

- Import new repos at any scanned depth into the deepest matching folder-scan sub-group
- Warn when the scan stopped early instead of reporting no new projects
- Match imported repos on the owning host only
- Show a loading toast while refreshing and pluralize the success message

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: remove low-value ports and AI Vault tests

* test: drop unused focus callback capture

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…tablyai#38314)

orca account list called accounts.list with refreshUsage:false, so on an
idle headless host the JSON's rateLimits stayed null. JSON output now
asks the host to refresh only stale usage windows (the same
refresh-if-stale an accounts.subscribe stream runs), via a new optional
refreshStaleUsage param. The host waits at most 10s for it, so slow
inactive-account probes can't push the CLI past its request timeout;
they keep running and land on the next call. Older hosts strip the unknown field and keep
their prior no-refresh behavior; human output still skips the refresh.

Fixes stablyai#37256
…frame instead of flashing blank (stablyai#37604)

* fix(terminal): paint a new WebGL canvas inside a synchronized frame instead of leaving it blank

A replaced WebGL renderer's first paint went through terminal.refresh(), which
xterm buffers while DEC 2026 synchronized output is held. The old canvas is
already gone, so the pane showed an empty canvas until the program closed its
frame. Over a remote link Codex's frames often span packets, so revealing a
remote worktree flashed blank/content for under a second, only with WebGL.

Paint a just-attached or just-resized canvas at once. A canvas created while
its renderer is paused (hidden worktree) is remembered until its first paint,
so the reveal present paints it through the open frame instead of waiting.
Also drop the WebGL rebuild after every reattach replay: it worked around an
atlas problem that no longer exists and replaced the renderer on every reveal.

* fix(terminal): limit a never-painted canvas to one mid-frame paint

* test(terminal): prove a swapped WebGL canvas paints through spinner sync frames

* fix(terminal): clear the never-painted mark on any forced paint; drop e2e casts

* test(terminal): keep the spinner repro inside the flaky-pattern ratchet
…ers (stablyai#38462)

* refactor(daemon): group transport, provider, endpoint, and terminal owners

* refactor(daemon): consolidate owner imports and preserve pinned baseline sources

* refactor(daemon): import termination budgets from their defining owner

* fix(ci): retain serve mode coverage for extracted orcad startup

* fix daemon build smoke to load concrete argument owner

* read daemon protocol facts from historical defining paths

* route protocol revision owners through compatibility checks
)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…i#38503)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…cause (stablyai#38508)

* fix(ssh): say what to do when a host's server setup stops on a known cause

A managed SSH host whose server setup deferred always showed "Orca couldn't
start its server on this host. Try connecting again.", even when a retry
can't help (full disk, an interrupted update needing Recover, another Orca
runtime on the host's data). The deferral code was dropped before it reached
the host status.

Carry the code as an optional field on the unserved status, keep the retry
line only for codes a later connect clears, and name the fix for the ones a
user can act on. Older hosts and thrown errors carry no code and keep the
retry line.

Refs stablyai#38347

* fix(ssh): drop the Recover advice a first setup can't act on

Connect already runs activation recovery before deploying, and an unregistered
host has no Recover control, so that code now points at Details. Soften the
live-runtime line, keep waiting causes in the warning tone, and test the
published code and its remedy rather than English copy.

Refs stablyai#38347

* fix(ssh): treat an unreadable server build as needing Details, not a retry

Refs stablyai#38347
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…y why (stablyai#38308)

* fix(ssh): stop restarting a managed orcad that keeps crashing, and say why

orcad now reports, in its health, a previous run that died on this boot
without releasing its instance lock. Graceful stops (idle exit, explicit
stop, update activation, rollback) release the lock, and a reboot changes
the boot id, so none of those count. After 3 such exits in 10 minutes the
desktop stops waking the server until an explicit Connect, and shows the
reason with orcad.log's path and tail instead of timing out.

Refs stablyai#37538

* fix(ssh): count fatal stops and failed starts; brake every automatic wake

- A fatal orcad stop (uncaught exception) keeps its instance lock, so the
  next start reports it.
- A launch that never becomes ready counts once, not again when the next
  orcad reports it.
- The tunnel port-recovery wake goes through the same brake.
- macOS and Windows hosts use OS uptime as boot evidence.
- Connect also drops a cached serving verdict.

Refs stablyai#37538

* fix(ssh): serialize crash-loop brake admission per host

Refs stablyai#37538

* fix(ssh): count reported Windows launch failures toward the crash-loop brake

Refs stablyai#37538

* fix(orcad): read the Windows launch report when the launcher exits nonzero

Refs stablyai#37538

* fix(ssh): ignore brake accounting from wakes begun before a reconnect

Refs stablyai#37538

* fix(ssh): count only launches that failed readiness, not inspection failures

Refs stablyai#37538

* fix(orcad): keep the command error when a Windows launch left no report

Refs stablyai#37538

* fix(ssh): surface the crash-loop reason from tunnel port recovery

Refs stablyai#37538

* fix(ssh): take the brake's reset epoch when a wake is requested

Refs stablyai#37538

* test(ssh): keep the cast on its SAFETY line

Refs stablyai#37538

* fix(ssh): tighten what the crash-loop brake counts and when it lets go

- A Windows host-policy refusal is not counted; its own guidance stays.
- The braked detail names the last failed start.
- A latch set on a run that served is released once that run's lock shows
  it stopped cleanly.
- The update path's already-active wake goes through the brake.
- The fatal-stop test drops its shutdown timer.

Refs stablyai#37538

* fix(ssh): brake only a new launch, and count the wake after an automatic release

Refs stablyai#37538

* fix(ssh): refuse a braked launch at the fenced launch decision itself

Refs stablyai#37538

* fix(ssh): a refused launch also skips fence recovery, which can relaunch

Refs stablyai#37538

* test(ssh): a refused launch leaves fence recovery alone

Refs stablyai#37538

* fix(ssh): count failed recovery launches; dedupe only runs that ran

Refs stablyai#37538

* fix(ssh): explicit Update and Restart re-arm the crash-loop brake; release it after a reboot

- Update and Restart are user actions like Connect: they clear the brake.
- An auto-update that meets the brake on an already-current host is a
  skip, never a recorded update failure that would block retries.
- The brake releases once the latched run's lock comes from an earlier boot.

Refs stablyai#37538

* fix(ssh): every explicit server action re-arms the brake; count failed candidate launches in recovery

Refs stablyai#37538

* fix(ssh): only gated wakes can return launch-refused

Ungated callers (version adoption, stale-lock reclaim, WSL, restart) pass no
launch gate, so their wake type no longer includes a refusal they cannot get.

Refs stablyai#37538

* fix(ssh): reboot evidence also releases a brake raised by failed starts

Refs stablyai#37538

* fix(ssh): release the brake only on a new boot of the machine that answered when it engaged

A leftover lock's boot id cannot tell a reboot from a shared-home lock
written by another login node or one older than the loop.

Refs stablyai#37538

* fix(ssh): a braked host seen serving can be released by that run's clean exit

Refs stablyai#37538

* fix(ssh): identify the rebooted machine by hostname and machine id

Login nodes behind one hostname share it, so the hostname alone cannot tell
them apart. Without a machine id the brake does not auto-release.

Refs stablyai#37538

* fix(ssh): only an answered run counts as served; a reboot must postdate the brake

A clone with the same hostname and machine id that booted earlier is a
different backend, not a reboot. Boot and read times come from the host's
own clock.

Refs stablyai#37538

* fix(ssh): only an answer received after the brake engaged marks its run served

A control-socket pong up to 20 s old may come from a run that has since
exited cleanly; counting it would let failed starts release the brake.

Refs stablyai#37538
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Upstream range 974bb4a..d4144ce, 164 commits. 14 conflicted
paths (11 both modified, 3 modify/delete), 15 hunks.

Conflicts:
- electron.vite.config.ts (#10, #16) and pr.yml (#23): upstream's moved
  script paths beside the fork's lines.
- Daemon import lists (#25; 6 paths): upstream's stablyai#38462 owner paths plus
  the fork's drain imports. daemon-pty-runtime-state.ts takes upstream's;
  the fork's `draining` option follows DaemonPtyAdapterOptions to
  daemon-pty-adapter-options.ts.
- ended-process-reconciliation.test.ts (#30): the fork's rewritten case
  stays beside upstream's removals.
- Upstream's test trims deleted three fork-edited files; each takes the
  deletion: manual-compact-status-cleanup.test.ts (#30),
  orchestration-mailbox-delivery-recheck.test.ts (#69) and
  updater-changelog.test.ts (#10), whose one fork case moves to
  updater-changelog-release-source.test.ts.
- Flaky-test baseline: upstream's file plus the fork's 17 rows.

Breaks the conflict list did not show:
- swaplabs-build.yml follows ensure-native-runtime.mjs to
  native-build/node-addons/; swaplabs-build-version.mjs follows
  release/versioning/.
- Eight fork-only files left in src/main/daemon/ follow upstream's owners
  (launch/, endpoint/publication/, providers/{adapter,routing,lifecycle}/)
  with only their relative imports changed.
- max-lines: daemon-out-of-process-launcher.ts (305) moves
  abandonUnfinishedDrain to daemon-drain-abandon.ts;
  TerminalPaneSurface.tsx (406, upstream alone is 400) mounts the fork's
  TerminalPaneRestorePortals in place of upstream's banner portals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-05T11:24:13.738703Z 180834d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kiwidream

Copy link
Copy Markdown
Author

Merged at 11:22:11Z as c4f9170bb8 onto the validated integration head d0355dab26. Neither CI nor review gated it (§1a step 6). At merge: 0 failing, 51 pending.

Build: run 42018420522 succeeded on all legs, which also proves the swaplabs-build.yml path fix. Published swaplabs-v1.4.251+202611051122 at 11:31Z, with macOS arm64 and x64 and Linux x64 and arm64 assets.

Checks at 11:56Z: 124 pass, 2 fail, 1 pending (WSL2 distro (ubuntu-24.04)), 15 skipped. Neither failure points at a fork file.

  • compatibility-imports: upstream's benchmark reads check-compat-boundary-imports.mjs at its new path from HEAD^1, the old fork head, which predates upstream's move. This is the known "comparison against the old fork head" class.
  • e2e / changed e2e specs (3/3): combined-diff-syntax-colour.spec.ts:77 (upstream fix(diff): colour visible diff lines as soon as a pane is laid out (STA-12770) stablyai/orca#38266) saw 4 of 8 sections laid out within 15 s. It passed on upstream's own PR. The fork changes nothing in combined diff, but the cause is not verified.

Reviews: Codex completed on 180834d with no findings. Tenki did not review (SwapLabs#225). No review threads on this PR or on #86, #82, #80 and #78.

Follow-ups:

Release notes: wiki, 0ccc9ea.

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.