Skip to content

sync: upstream 36d295628e into swaplabs/main - #64

Merged
kiwidream merged 336 commits into
swaplabs/mainfrom
sync/upstream-20261028
Oct 28, 2026
Merged

kiwidream merged 336 commits into
swaplabs/mainfrom
sync/upstream-20261028

Conversation

@kiwidream

@kiwidream kiwidream commented Oct 28, 2026 •

Copy link
Copy Markdown
Files Added Deleted Net
Test 1103 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​65799 $\color{#cf222e}{\Huge{\mathbf{−}}}$​18598 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​47201
Prod 1897 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​68544 $\color{#cf222e}{\Huge{\mathbf{−}}}$​19807 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​48737

ELI5

Upstream Orca moved forward 335 commits since yesterday's sync (#62). This PR merges them into swaplabs/main. 12 files conflicted with fork changes, all resolved by keeping both sides. Two more things broke without a conflict and are fixed here. Nothing needed an operator decision. This PR replaces #63 (head main), which could not merge.

What Changed

Upstream range df95be4090..36d295628e, 335 commits (compare). One signed merge commit, dd8ce6ed87 (Merge upstream main (36d295628e) into swaplabs/main), on sync/upstream-20261028, cut at the integration head 7d5ebba0c2.

Conflicts, by fork PR (orca-fork-ops conflicts)

Fork PR File Upstream change Resolution
#26 (sync review rule) AGENTS.md stablyai#34507 rewords the test line ("negative value") upstream's line; the fork's section stays unchanged
#6, #7, #9, #10, #13, #14, #17, #31 src/renderer/src/i18n/locales/{en,es,ja,ko,zh}.json stablyai#22056 retires unreferenced keys (here "idle"); new terminalPane.hostFile upstream's catalogs plus the fork's keys: en.json keeps the fork's 14 update-source keys without the retired key; es/ja/ko/zh keep hostFile beside the fork's AgentResumeChooser. The fork's delta in each catalog is unchanged
#30 (host resume) src/main/agent-hooks/server/server-ingest-remote.ts stablyai#34724 types the event as IncomingAgentHookEvent and adds codexRosterAuthority upstream's type and field beside the fork's reportsUserEndedSessions (then moved, see below)
#25 (daemon drain) src/main/ipc/pty/pty-management.ts stablyai#32153 (Quit and Stop All Sessions) tracks the generations whose listing failed (listSessionsOfEveryAdapter, listingIncomplete, confirmNoDaemonSessionsRemain) upstream's code, with the fork's rule kept: each listed session carries the adapter that listed it, and kill/killOne route to it. The kill poll keys a failed listing by that adapter rather than by protocol version, because a drained daemon shares the current one's version. With distinct versions (every non-drain host) this is upstream's behaviour exactly
#16 (mac self-update) src/main/startup/main-process-ready-runtime.ts stablyai#34059 runs the WSL-move rewrite pass after the first window both: upstream's pass, then the fork's launch-outcome report
#14 (update sources) src/renderer/src/components/settings/GeneralUpdateSettingsSection.test.tsx (modify/delete) stablyai#34370 deletes the file as low-value upstream's deletion. The fork's two cases test fork behaviour (single-source markup, the manualInstallUrl download link), so they move unchanged, with the setup they use, to the fork-owned GeneralUpdateSettingsSection.single-source.test.tsx, as the table does for a deleted doc
#6 (auto-resume) src/renderer/src/lib/pane-agent-evidence.test.ts stablyai#34612 removes cases and their imports upstream's removals; the fork's resolvePaneScopedLaunchTuiAgent cases and import stay
#11 (keystroke gate) src/shared/terminal-mode-reset-profiles.test.ts stablyai#34520 removes cases and imports upstream's removals; the fork's PROCESS_BOUNDARY_GROUND/POST_REPLAY_MODE_RESET case stays, with its POST_REPLAY_MODE_RESET import

Breaks the conflict list did not show

Fork PR File Cause Fix
#30 server-ingest-remote.ts: 305 counted lines, max 300 upstream's own copy is now at exactly 300 (stablyai#34724), so the file has no room for fork lines the fork's 5 lines leave the file. The relay's user-ended notice is read where payload validation drops it: its payload state user-ended-session is one no host admits, by the notice's design, and it carries none of the fields checked in between. reportsUserEndedSessions is stamped by the fork-owned withRelayUserEndedSessionReports in server-terminal-loss-resume.ts, beside retireRelayUserEndedSession. Now 299
#7, #13, #31 (titlebar) src/renderer/src/i18n/locales/{ru,tr,zh-Hant}.json stablyai#34717, stablyai#34718 and stablyai#29795 add three catalogs, carrying upstream's "Orca" for the titlebar key the fork changes in every catalog they take the fork's Forca{{value0}} (SwapLabs{{value1}}), so the titlebar keeps the fork name, version and revision in those languages

Fork delta check: each of the 336 files the fork changes, before or after, was compared against upstream on both sides of the merge. 326 keep exactly the same fork lines. The other 10 are the changes listed above.

Some notable upstream changes in the range

Why

Daily upstream sync.

Linked Issue

N/A: daily upstream sync. Supersedes #63. Follow-ups: #65 (fork strings untranslated in pt, ru, tr and zh-Hant), and comments on #45 (the server-ingest-remote.ts move) and #44 (the drain's kill poll).

Visual Proof

N/A. The only user-visible fork change is the titlebar name in the three new languages, which now matches every other language.

Testing

All checks ran on the merge result in the sync worktree, before the commit:

  • Install: pnpm install --frozen-lockfile.
  • Typecheck: pnpm tc passes. A deliberate type error in a scratch edit made it fail, so the gate is live.
  • Lint: pnpm lint, all 36 steps pass. The first run failed on server-ingest-remote.ts max-lines (305), fixed above.
  • Changed-code gate: check:code-quality:changed with ORCA_SYNC_PR_DIFF_BASE=36d295628e: 0 findings across 313 fork files.
  • Tests: every fork unit test file (109), plus src/main/agent-hooks, src/main/ipc/pty, src/main/startup, src/renderer/src/components/settings, src/renderer/src/i18n and src/renderer/src/app-shell whole, pane-agent-evidence.test.ts and terminal-mode-reset-profiles.test.ts: 687 files and 6,332 tests passed, 73 skipped, none failed. This run unset the host's ORCA_* environment, which this agent's terminal exports. orca-runtime.test.ts, which runs the fork's orca-runtime-tests specs, passed with fixture signing off: 1,498 passed, 3 skipped. The fork's three Playwright e2e specs were not run.
  • Resume relay, specifically: wsl-relay-user-ended-session.test.ts and server-terminal-loss-presence.test.ts run a real relay and host end to end, and all 18 tests pass. Each moved piece was also removed in turn: without the notice's retirement 3 tests fail, and without the stamping 7 fail, so both are covered.
  • Daemon drain: pty-management.test.ts passes, including the fork's "routes to a drained daemon that shares the current protocol version" and upstream's failed-listing cases. No test covers a drained and a current daemon of the same version where only one listing fails, the one case where keying by adapter differs from keying by version.
  • Pre-commit hook: oxfmt --check reports all 4,309 staged files formatted (after pty-management.ts was formatted). oxlint, its JS-plugin and React Doctor configs, and ast-grep scan --min-severity warning pass over the 4,148 staged code files. The hook then ran normally, and the tree before the commit (3355fbea76) equals HEAD^{tree} after it.
  • Signature: dd8ce6ed87 is G from the sync key BF1DD75F888E96080C2453E2D9E158C5D6874235.

AI Disclosure

Prepared by the "Orca upstream sync" automation (Claude Code, Claude Opus 5.5).

Agent skill upstream boundary

  • Not applicable: this PR merges upstream's history; it adds no agent skill.

Notes

orca-fork-ops status for swaplabs/main (7d5ebba0c2) against upstream 36d295628e, before this merge:

Upstream release tag v1.4.243 was copied to the fork.

🤖 Generated with Claude Code


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

brennanb2025 and others added 30 commits October 27, 2026 12:32
* fix(chat): confirm before closing active native chats

* Repair native chat close settings and consent coverage

* Cover native close consent in workspace and floating tests

* Require consent before closing active native chats

* Fix close-warning typed values in deferred actions and tests

* Preserve admission ownership and reconcile relevant send evidence

* Separate chat read lifetime from send settlement and activation effects

* Fix required read activation typing
…34355)

* Keep unacknowledged Claude prompts single after reopening

* test: bound local prompt recovery indexing at scale
…blyai#34510)

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

* fix: finish admitted terminal prompts after sender disconnects

* test: consolidate prompt input contract assertions

* Keep first-submit ownership independent of sender observation

* Recheck prompt ownership after awaited guards

* Cover abandoned prompt admission during restored pane startup

* Use typed provider write spy in prompt socket regression
…ith the selected line range (stablyai#33597)

* fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range

The gutter menu's Copy Remote URL always built the link on the default
branch and dropped any multi-line selection. Prefer the HEAD commit when
origin already has it, then the origin branch the current branch tracks,
then the default branch; carry an optional end line through IPC, RPC and
the git provider so a selection becomes a line range.

* fix: pair remote file links with published repository refs

* fix: prepare exact remote file fallback before publication scan

* test: consolidate remote file URL integration coverage

* test: document real-clock cancellation deadline proof

* test: handle optional cancellation signal in assertion

* test: reuse spawned child fixture across runtimes

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Removes 134 redundant test registrations across native-chat projection, sidebar ordering, and palette matching. Deletes two entire suites: notice appearance mapping and ordering scenarios whose test-owned Host supplies the behavior being asserted.

Retains 154 registrations covering state transitions, competing inputs, FIFO tool pairing, sidebar feed application, and search ranking. Production code is unchanged. Removes the two deleted suites’ timing entries and lowers the wall-clock baseline only for the deleted Date.now assertion.

Validation: isolated static registration/body preservation, formatting, lint, discovery, runtime routing, and metadata checks. Full PR CI must verify 275 expanded cases across 17 owning test roots, including the transcript-contract aggregator; 185 cases belong to retained selected sources and required counterparts. No local runtime tests were run.
…33730)

* fix(ports): attribute listeners through workspace symlinks

* fix(ports): bound workspace realpath resolution during scans

* Preserve port URLs through incomplete workspace alias observations

* Bound workspace alias lookups with expiring FIFO admission

* Bound alias admission per workspace scan phase

* Document fake-clock lookup timers for the test policy

* Keep fake-clock recovery coverage on the alias under test

* Wait only on existing workspace alias observations

* Assert advertised port URLs within the node test boundary

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* refactor(terminal): separate startup commands from live input

* fix(terminal): run POSIX startup commands from shell prompt hooks

* fix(terminal): preserve staged commands in shell-owned startup

* fix(terminal): correct startup types and release spawn environment

* fix: keep startup prompts usable during agent restore

* test: run startup prompt regression in the native runtime

* fix(zsh): retire deferred startup callback safely

* test: make shell readiness fixtures satisfy timing checks
…blyai#33632)

* test(native-chat): preserve mixed drops through question submission

* test(native-chat): complete send harness setup

* test: remove duplicate delayed mixed-drop case
stablyai#33621)

* fix(codex): keep the Codex app's bundled plugins in Orca-managed homes

Codex only loads the openai-bundled marketplace when its source sits under
the active CODEX_HOME. The config mirror copied ~/.codex's source verbatim,
so managed homes silently dropped bundled plugins such as visualize.
Link ~/.codex/.tmp/bundled-marketplaces into managed homes and rebase the
mirrored source onto it.

* fix(codex): rebase bundled marketplace onto the canonical managed home

Codex canonicalizes CODEX_HOME before comparing the bundled marketplace
source, so a managed home reached through a symlink (symlinked userData,
/tmp on macOS) was still rejected.
… hosts without ps (stablyai#34519)

* fix(ssh): prove a recycled server PID exited on hosts without ps

On slim Linux images that ship no ps, the managed server's liveness probe
could not read the recorded PID's argv, so after a reboot a PID that now
named another process read as LIVE (same user) or UNKNOWN (root). The wake
then refused to start the stopped server, the update deferred on the
terminal census, and the host stayed unreachable. Read argv and the
zombie state from /proc when ps is missing.

Fixes stablyai#34149

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ssh): name argv-less PIDs from /proc stat; annotate e2e timeout

Kernel threads and zombies have an empty cmdline, so a recycled PID owned
by one stayed UNKNOWN on hosts without ps. Quote the stat pattern so the
probe also parses inside command substitution on older bash.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ssh): fall back to the stat line only after cmdline was read

A failed tr must stay unproven rather than make a live server's PID look
recycled.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#34171)

* fix(gitlab): keep paging merge requests when GitLab omits the totals

When total headers are absent, a full response advertises another page to probe and a short response ends pagination. Keep the existing header precedence and unknown total count.

Tracked in stablyai#33800

* test(gitlab): cover MR pagination exhaustion and header precedence

* test(gitlab): verify unknown-total metadata across list consumers

* test(gitlab): cover remaining screen consumers of list metadata

* test: use checked GitLab RPC runtime fixtures

---------

Co-authored-by: Hotragn <103170876+Hotragn@users.noreply.github.com>
…34173)

* fix(tasks): make Linear list section headers collapsible

* test(tasks): cover Linear section collapse and keyboard activation

* test(tasks): bound Linear section toggle work at scale

* fix(tasks): compose Linear section surface with standard button

* fix(tasks): keep section keyboard focus inside the row

---------

Co-authored-by: Isaac Mello <dzordinetwork@gmail.com>
)

* Correct GitLab MR check status for failed and manual pipelines

Use the same single-MR read for linked and branch-discovered reviews so a
list summary cannot hide a failed pipeline. Preserve lookup failures for
strict callers and keep detail reads within the existing branch cache.

Set mergeable manual pipelines to neutral without claiming an unrun stage
passed; keep blocking manual pipelines pending.

Co-authored-by: Son of Odin <2700975-son-of-odin@users.noreply.gitlab.com>
Co-authored-by: Emily <hadikcze@gmail.com>

* test: cover GitLab MR check status consumers

* test: type GitLab MR fixtures from mapper input

* chore: document GitLab MR boundary assertion exceptions

* test: share GitLab MR producer and consumer fixtures

---------

Co-authored-by: Son of Odin <2700975-son-of-odin@users.noreply.gitlab.com>
Co-authored-by: Emily <hadikcze@gmail.com>
* fix(gitlab): retain successful hosts from partial auth failures

Read rejected auth-status output without treating failed host headings or
API error advice as successful logins. Publish positive results through
the existing context-owned cache; keep backoff when no login succeeds.

Co-authored-by: David Anderson <cantspamdave@gmail.com>

* fix(gitlab): preserve discovery retries with partial host evidence

* fix(gitlab): escape auth marker for ASCII server bundle

---------

Co-authored-by: David Anderson <cantspamdave@gmail.com>
…#34185)

* fix(github-project): render linked PR and sub-issue progress values

* fix(github-project): probe schema support for project column values

* fix(github-project): preserve independently supported project fields

* Preserve nullable project values and unsupported fetch concurrency

* Exercise project relation payloads through unchanged consumers

* Combine project coordination test cache imports

* Use checked project payload types in consumer tests

* Place project provider column contract in cross-layer tests

---------

Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
* fix(tasks): derive preset highlights from the applied query

Reuse the parsed query and already loaded viewer login for personal preset matching. Keep the stored preset field for resume and task-kind behavior.

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>

* fix(tasks): limit preset identity matching to known sources

* fix(tasks): wait for source identity before matching viewer aliases

* fix(tasks): match preset highlights to query tokens

Require the effective open state and recognize personal presets by their @me query tokens. Remove viewer identity matching while preserving existing preset persistence and task-kind behavior.

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>

---------

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ntime host's create (stablyai#34525)

A desktop-scheduled automation whose project lives on a managed Orca server
sent its dispatch token to the server, which never minted it and rejected every
run with "Invalid automation provenance request". The token now goes only to
this desktop's own create.

Fixes stablyai#34433
…yai#34504)

* Add native chat hand-off menu on main

* Fix saved chat hand-off observations and RPC exports

* Reuse indexed chat tabs for hand-off subscriptions

* Match saved-chat clear fixture to current journal API
…tablyai#34500)

* Stop unrelated host status publications rebuilding sidebar workspace state

* Follow sidebar selector lint conventions

* Scope sidebar status reads to mounted consumers

* Cover each unrelated sidebar status publication

* Fix sidebar isolation lint and formatting

* Type the composed sidebar header fixture without assertions

* Remove unused React imports from sidebar contract tests

* Reuse folder record selector and prune stale focus allowance
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(chat): link naming failures to chat name settings

* fix(chat): hide naming settings link when controls are unavailable
…ablyai#34177)

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

* feat(wsl): note why an idle distro stays held, and fail the holder's scan closed

When user work keeps the holder from releasing, it writes the first few process names (at
most 5) to ~/.orca/wsl-holder-blocked, replaced whole and cleared on release, for the desktop
to read later. A /proc without the holder's own entry, or a status file it cannot parse, now
keeps the hold instead of reading as idle.

* fix(wsl): count an unreadable /proc entry only when it is the user's own

Review of stablyai#34534: under hidepid=noaccess root's status files are unreadable, so each read as
this user's work and the distro never released. An unreadable entry now counts only when its
directory belongs to this user. The holder also clears a half-written note on start and
rewrites the note only when it changed.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…urce mode (stablyai#34537)

* feat(editor): VS Code markdown highlighting and sticky headings in source mode

* fix(editor): address review on markdown TextMate highlighting

- resolve fence grammars from the first word of the info string
- give fence grammars the cold-compile retry budget
- fall back to Monarch markdown when TextMate fails to load
- bound heading-scan line length
ejunker and others added 19 commits October 28, 2026 01:57
…s and Gitea detection (stablyai#30808)

Fold every forge SSH host alias (ssh.github.com, altssh.gitlab.com,
ssh.bitbucket.org) through one shared normalizeForgeWebHost so main-process
provider detection and renderer manual review links agree. Remotes on
ssh.bitbucket.org now open bitbucket.org pull request forms instead of
ssh.bitbucket.org URLs, and Gitea no longer claims the host.

Co-authored-by: Eric Junker <4758+ejunker@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
…ane terminal (stablyai#31815)

The terminal context menu only showed a close item when the tab had split
panes. A single-pane terminal now offers "Close tab", which sends the same
close request as Cmd/Ctrl+W. Pinned tabs and one-off command terminals keep
hiding it, matching the pane header's close button via a shared
canCloseTerminalPane/terminalPaneCloseLabel.

Fixes stablyai#20598

Co-authored-by: Neil <neil@stably.ai>
… hosts (stablyai#34865)

* perf(renderer): release reconnect observers for removed hosts

* fix(renderer): forget model-catalog lists of a removed host

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…and measure a 100 MB read on WSL (stablyai#34882)

Follow-ups from the large-file audit (E7):

- files.search had no byte budget: a result past the remote reply cap failed outright with
  reply_too_large. It now keeps the whole files that fit and marks the result truncated, as
  files.listAll and searchPaths already do. Local callers stay uncapped.
- A diff side past the 10 MiB read cap came back as binary, so the diff said "Binary file
  changed" for a large text file. Blob reads mark it `tooLarge`, the binary diff result carries an
  optional `tooLarge`, and both diff views say "File too large to diff". Older clients ignore the
  field and keep the binary view. buildDiffResult builds its binary sides without a cast.
- The real-WSL lane pages a 100 MB file over the plain distro's shared control socket in the
  editor's 384 KiB chunks and records the time, chunk count and orcad's VmHWM. Record-only: it
  asserts nothing, and a failure is recorded in the receipt.
…#34773)

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

* fix(native-chat): a refused queued message still blocks the queue when its card write fails

Every reader of a queued card goes through one derived view of the journal's dispatch facts,
so a card whose message was refused reads as returned even when its card-table update and heal
both failed. One decision and one writer store the derived state for every action.

* refactor(native-chat): keep each queued message in the chat's journal, not a second table

A queued message lived in its own SQL table, and a hook that may be skipped copied
each refusal from the journal into it. When that write failed, a refused card
vanished: the cards behind it sent, and its Send and Delete did nothing.

Each queued message is now a `queue` row in the chat's journal beside the
submission that hands it off and the dispatch row that answers it. The reducer
folds the card from those rows, so a refusal returns the card and holds the
cards behind it with nothing written, and replay reads the same. Every action
writes its own rows in one transaction. Cards an earlier build stored are read
through the same classification until they move: each action moves its own
card, and a bulk import runs once per open. A new epoch restates every card
still owed an answer in the transaction that deletes the old rows.

The settlement hook and its savepoint, the open-time heal, the drain's heal and
the derived-card view are gone. The published card list is unchanged.

* test(native-chat): adapt the queue tests to cards kept in the journal

Cards are written through the journal, so tests queue them with their body
alone and hand them off under their real fingerprint. Tests of the removed
settlement hook, heal and SQL store are deleted; the text-update spec now
covers the edit decision alone, and a test of an earlier build's stored holds
seeds the legacy table and reads the imported cards. Rolling over an epoch now
keeps a card whose hand-off was never handed over, so that test checks the
retried id never sends rather than that nothing sends.

* test(native-chat): a refused card holds the queue through rewind, a new epoch and a restart

One whole-flow test through the host: the refusal writes no card row, a rewind
that retires the refused hand-off and a rolled-over epoch keep the card
returned, a restart and Resume send nothing behind it, its own Send refused
again still holds the queue, and its Delete releases the next card in order.

* test(native-chat): an earlier build's queued cards move into the journal once, each read the same

One mixed-import test through the host. The first open's import fails and
moves nothing, yet every card reads as it will; Delete and Send each move only
their own card. The next open moves the rest in one transaction, writing a
refusal only where its hand-off is gone, nothing for answered cards, and leaving
an unreadable row on disk. A later command turn spends a moved command card, a
third open writes nothing, an old Delete replays from its receipt, and a chat
with only answered legacy rows clears them in a delete-only transaction.

* test(native-chat): adapt typechecked tests to cards kept in the journal

The row-kind table lists a queue row, the clear and legacy-import tests
match the current signatures, and the downgrade test keeps only the
leftover-send case: a queued card is now a newer-version journal row an
older build keeps read-only, and users don't downgrade.

* refactor(native-chat): drop the journal row writer's unused transaction hook

No caller passes one since the queue's savepoint bookkeeping left.

* test(native-chat): downgrade probes write rows at the version older builds read

The highest version this build reads is now 4, the queue row's. A newer
build's row in these probes is written at version 3 so the older build
meets its kind, not a newer version, and the Stop-event probe hands the
older build the rows as stored, since a read raises each row's version.

* test(native-chat): unit tests follow the queue row's version 4

The legacy-import test opens real SQLite, so it runs in the Node runtime
project. The newest version this build reads is now 4, and a read raises a
row's version to it, so the turn-lifecycle test no longer pins the
in-memory version (the written one stays pinned by journalRowSchemaVersion).

* fix(native-chat): one batch echoing two refused queued messages spends both

The per-row delivery check returned only the first waiting card an echo
proved delivered, so when one settlement carried echoes for two cards the
second stayed waiting and was sent again. It now returns every card the
row proves delivered, and the fold withdraws each; replay folds the same.

* fix(native-chat): a rewind moves an earlier build's cards into the journal first

While the open's import had failed, an earlier build's card that read as
refused through its hand-off lost that reading when an in-place rewind
retired the hand-off: it disappeared and the card behind it sent. The
rewind now adopts every legacy card ahead of its tombstones and deletes
their rows in its own transaction, as an epoch replacement already does,
so the fold latches each card's reading before its hand-off is gone.

* fix(native-chat): keep an earlier build's card whose hand-off is still unconfirmed

The import dropped a legacy card handed off as a send whose delivery was
unknown, though the fold keeps such a card linked and a later refusal
returns it. The import now keeps every card whose hand-off a later row can
still answer, through the same check the reducer folds dispatch rows by.

* fix(native-chat): one delivery echo withdraws at most one queued card

One provider echo proves one delivery, yet it withdrew every waiting card
with the same text whose hand-off was refused, so a second identical card
was lost. The fold now pairs each echo with one card: on its own row the
earliest-positioned match no other echo of that row took, and for a card
that waits again the earliest applied echo no card has taken. Paired echoes
live in the fold's state, so live and replay pair the same; readers of
cards not yet imported work on a copy.

* fix(native-chat): a queued message handed to the agent is sent again only on proof it never got it

Pressing Stop after Orca handed a queued or steered message to the agent,
before the agent confirmed it, put the card back in the queue, and Resume
or the next send sent it again. A check matching the agent's echo of the
text was the only guard against a double send, and it kept trading a
resend for a lost card. Whether the card waited again was decided by the
rejection's category, not by proof the agent never got the message.

A refused hand-off now waits again only where Orca proves the agent never
received it: the host still held it, or whoever settled it recorded that.
A failure still returns the card and holds the cards behind it. Anything
else may have reached the agent, so the card is spent and its message
reads as sent, derived on every fold from the stored rejection: with the
turn it was answered into, as that turn's unconfirmed message where it was
handed over; withdrawn before any turn opened, as a person's own send a
Stop took back. The reopen mark ignores a recovered doubt, and the restart
reconciler no longer judges a queued hand-off unsent from what history
lacks. The echo text matching and its pairing are deleted.

A close or quit while the agent starts settles sends with the unrun hold.
The host hands nothing to a child before its start answers
(structured-agent-session-delivery-loop.ts: a handover needs phase
ready), so such a send went to an earlier child and may have run: it now
reads as sent instead of waiting again.

* fix(native-chat): Claude's report that it removed a queued message unrun lets the card wait again

Claude says when it removed a send without running it: the interrupt
receipt's cancelled list, or a command_lifecycle cancelled, discarded or
refused frame for a command that never started. Every one settles through
rejectClaudeDispatchWaiters, which now marks the settlement unrun. For a
queued card's hand-off the host records that as proof the agent never got
it, so the card waits again under the queue's pause. A direct send keeps
the plain refusal: there the proof would owe it as stopped history.

* fix(native-chat): an earlier build's card stopped after hand-over follows the same rule on upgrade

Earlier builds put a card back to waiting after any refusal without a
verdict and cleared its link, so a card the agent may already have would
be sent again after the upgrade. The card's own hand-offs in the journal
decide now: unchanged and last sent as one that may have reached the
agent, it is spent on that hand-off and its message reads as sent; edited
or sent again since, it is held for its own Send under a host-only marker
that publishes as a plain hold; with no hand-off in doubt, including one
that never left Orca, it waits as before. The import writes a card spent
on a hand-off in doubt, so its message shows.

* fix(native-chat): read a queued row's hand-off before the lookup that uses it

The lookup's callback lost the narrowing of the row's change, which the
mobile test typecheck rejects.

* test(native-chat): a card steered into a turn a Stop ends stays sent in the Stop tests

Three tests pinned the old rule, that a card handed into a running turn
comes back to waiting when a Stop ends it. Under the new rule nothing
proves the agent never got it, so the card is spent: with the turn named,
its message reads as that turn's unconfirmed one; without, as a send the
Stop took back. Neither is ever sent again.

* fix(native-chat): a queued message stopped before Orca handed it to the agent waits again

A Stop that aborts a hand-off after its row is written but before the agent call now records
the withdrawal as never reaching the agent, for queued hand-offs only, so plan D's rule returns
the card to waiting under the Stop's pause instead of spending it. Direct sends keep the plain
withdrawal (the flag would owe them as stopped history). The agent's own refusal while aborted
is kept rather than overwritten, and an abort thrown during the call stays in doubt.

* fix(native-chat): a queued message stopped while the agent prepares it waits again

The abort signal reaches only an adapter's preparation (its options, the previous turn opening),
never its write, so the signal's own reason thrown back is the adapter saying nothing was
written. The handover now reads that, for queued hand-offs only, as never reaching the agent,
so the card waits again under the Stop's pause. Claude no longer wraps that abort as an option
refusal, which had returned a stopped card as a refused one blocking the queue. A real refusal
keeps its cause and its barrier; any other throw stays in doubt and is never resent.

* test(native-chat): the usage-limit Continue backlog case writes its card through the journal queue

Main's stablyai#30396 wrote its backlog card with the stored fingerprint and host-instance stamp the
journal queue derives instead; the card the Continue must yield to is the same waiting card.

* test(claude): the real-CLI queued Stop expects the unrun mark Claude's cancelled-unrun receipt carries

* feat(mobile): edit a queued message's images on the phone: remove or attach

* fix(mobile): gate queued image edits on the host reader verdict

* test(mobile): declare the upload fixture chat mode

* fix(native-chat): retain spent legacy messages when import fails

* fix(mobile): reveal the full queued image editor on open

* fix(mobile): invalidate queued editor geometry without a render ref write

* refactor(chat): prepare composer drafts and measured queue dragging

* feat(native-chat): add conditional queue removal and authoritative reordering

* feat(native-chat): move queued edits into the normal composer on desktop and phone

* fix(native-chat): own complete phone drafts before authoring

* fix: preserve submitted composer drafts across storage replacement

* fix composer validation and mobile CI diagnostics

* fix mobile composer test contracts and diagnostic output

* Capture mobile test compiler diagnostics in CI

* Fix queued message contract typing and English strings

* test: complete queued extraction transport fixtures

* refactor: separate composer skill binding from send mutations

* fix(mobile): grant draft storage within route limits

* fix(native-chat): settle each draft save on its own and publish complete composer drafts

Phone: a queued Edit copy no longer consumes the save that later typing
owns. Each ordinary save and the exact copy settle only their own result;
an explicit save waits for its own pending write, and a failed or retired
write never schedules another or revives the copy.

Desktop: a pasted-text leaf no longer shifts which selected file binds
where, and a hand-back held during an IME composition reaches the store
only merged with the visible editor document, including writes the editor
admits without an update and the composition settle.

* fix(native-chat): import the draft type once in the draft cache

* test(mobile): type the held-write state without an assertion

* test(native-chat): assert the handed-back file on Send without reading a typed transport as a mock

* test(mobile): pass main's agent-confirmed flag to the submitted-files harness

* fix: reveal queued reorder grip on touch screens

* fix: save reopened phone drafts and batch reorder measurements

* test: use an explicit React module type

* Preserve queued message sortable identities on unchanged renders

* Prevent stale queued drag completion after unmount

* fix(mobile): hand off navigation across session workspaces

* test(mobile): use resolved session identity in dictation fixture

* feat: edit queued messages inline with the chat composer

* fix: normalize queued edit skill ownership

* fix: retire phone skill selections with the sent draft

* fix: consolidate queued edit module imports

* fix: separate edit save action and stabilize image callbacks

* fix: complete phone inline composer integration

* fix: retain same-name queued skill selections

* fix: complete desktop queued composer integration

* test: use typed phone composer host lookups

* fix: include queued edit localization keys

* Preserve inline edit input across save and attachment completion

* Preserve complete queued edits across delayed saves

* Preserve queued edit input across delayed completion

* Complete queued edit lease loss and pending cancellation

* Use recognized queued edit test fixtures

* Consolidate queued edit imports and type host test spy

* Print mobile test compiler diagnostics on ratchet failure

* Correct queued edit integration fixture types

* fix: keep queued edit placeholder independent of readiness

* Fix queued edit compiler fixture boundaries

* Align upload completion test with ordinary insertion

* Combine mobile composer draft imports

* Load queued edit host fixture during test collection

* Size inline phone queue editor to available space

* Use typed scroll components in phone presentation contract

* Save typed text in a queued edit as written

The inline editor is the chat composer, so it keeps the composer's own identity model and no longer refuses Save for text that looks like a command. Command rows picked from the menu are still refused, Enter still means Save, and Edit never sends or runs anything.

Regression tests cover Undo after deleting an accepted command or skill pill, a scanned skill named like a command, two saved files behind one token, and typed command text saving literally. Also fixes two merge leftovers in tests: a missing import and a fixture that stored the whole menu row as a skill.

* Keep ordinary sends on the main composer contract

* Fix mobile composer imports and fixture loading

* Consolidate queued edit imports and duplicate regression

* Restore ordinary send catalog short circuit and repair test boundaries

* Preserve returned rich drafts through send acceptance

* Remove obsolete queued editor strings from new locales
…e host's server update during a move (stablyai#34823)

* fix(wsl-mover): settle an interrupted move automatically, and hold the host's server update during a move

An app update or crash between sending a move's copy and the host's commit leaves a
`blobs-transferred` record. Startup recovery has no host to ask, so the projects stay fenced, and
the automatic mover only previewed, which refuses an in-flight move, retrying forever. The
projects stayed read-only until the user started the move from the dialog. The automatic mover's
preview now settles that record first (through the host: back to zero, or forward when the host
committed), holding the distro's run while it does so it never races a move the user starts. The
dialog's preview stays read-only. The preview moves to its own module.

A Settings Update or Force, or any reconnect, could also redeploy the host's server in the middle
of a move, cutting it off (safe, but the move is lost). Once a running move has journaled, a
version-changing redeploy now keeps the running server and reports the update as waiting for the
move, mirroring the SSH path's skip while migrating. The move's own first connect, before it
journals, can still update an outdated server.

* fix(wsl-mover): an automatic settle never reloads the window, and never holds its own host update

Review of stablyai#34823:
- A settle that finds the host committed ran the desktop rewrite, which reloads the window past
  its unload veto. From the automatic mover it now records the commit only (the projects stay
  fenced), and the next start's rewrite pass finishes it before any window opens. A move the user
  starts still finishes at once.
- The server hold counted any unfinished record of the distro, so an automatic settle of an old
  record with an outdated server was held, refused for an update, and retried the same way. The
  hold now counts only the cutover the running move journaled itself.

* fix(wsl-mover): let the user finish a committed move in-session; park the automatic mover meanwhile

After an automatic settle records a commit for the next start, nothing could finish it in-session:
the user's Move refused as already in flight and the orchestrator retried for nothing.

- A settle that finds the head committed but not yet rewritten on this desktop finishes it now when
  the user asked (their Move, or the status line's Retry), returning the existing "finished an
  earlier move" answer; the automatic mover still leaves it for the next start.
- The automatic refusal carries detail `finish-pending`, which parks the distro (new reason
  `finish-pending`) instead of retrying; the next start, whose rewrite pass finishes the move before
  any window opens, puts it back to pending.
- The park rules move to wsl-move-orchestrator-park.ts.

* fix(wsl-mover): give the finish-pending park its own status line

Main's move status line (stablyai#34676) names every park reason; the finish-pending reason this PR adds
needs one: the earlier move is done on the host, and finishes here at restart or with Check again.
…open on the chat's host (stablyai#31781)

* fix(native-chat): open sandbox: images and files on the chat's host

Agents sometimes cite files they wrote as sandbox:/abs/path. Markdown
sanitizing dropped those addresses, so the chat showed only alt text and
an inert link. Chat Markdown now rewrites sandbox: links and sandbox:/file:
images to the chat's own file hrefs before sanitizing, and the shared href
router reads sandbox:/abs as the absolute path on the chat's host.

A paired host now grants a chat client a read-only exact-path grant for
any host file the chat links, instead of searching the chat transcript for
the path. The search missed structured chats, Markdown link targets and
older replies, and guarded nothing: a paired client can already run
commands on that host. The grant still refuses network shares, device
paths, hardlinks, pipes and sockets.

Desktop chat links and images now send their chat to the host, so files
outside every workspace on a paired host open and render. A chat link the
host does not have is reported missing there and never read from this
computer.

* Fix chat file reference and granted file actions

* Keep granted chat files on existing read-only tab route

* Remove accidental package manager lock metadata

* Match WSL artifact descriptor fixture to regular file stats

* Fix canonical host image grant acquisition

* Fix host image test transport request typing

* Drop sandbox: address handling from native chat links

sandbox:/mnt/data placeholders belong to a hosted code tool that swaps them
for its own download links; they never name a file on the chat's host.
…ai#34776)

* perf(browser): throttle idle guests between active operations

* perf(browser): lease only the guest for non-capture agent commands

Keep the renderer paint hold, host unthrottle, and host re-hide readback on
capture paths only, and never let the one-way paint-hint send fail the capture.

* style: format bridge paint-hold test

---------

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

* feat(wsl): admit no new WSL host or move in serve-only

Main refuses wslHosts:add while the internal gate is closed and reports
acceptsNewWork in the WSL host capability; moves already need the open gate.
The renderer hides Add WSL distro and every Move entry point once main says
serve-only, while saved hosts keep their Connect and Remove.

* fix(wsl): offer no new WSL host or move until main answers the capability

The renderer's acceptsNewWork now starts false, so Add WSL distro and the Move
entries never flash in serve-only before the capability reply.

* fix(wsl): point the WSL-bridge chat refusal at Add WSL distro only when it is offered

In serve-only Add WSL distro is hidden, so the refusal keeps its terminal-only
words there.

* test(wsl): give the move status-line test's hosts mock the new-work hook

stablyai#34676's test mocks use-wsl-hosts-enabled; WslHostsSection now also reads
useWslHostsAcceptNewWork, which follows the same gate there.
…removed (stablyai#34914)

stablyai#34650 removed dashboardPopout.terminal.closed from en.json, but ru.json,
tr.json and zh-Hant.json kept it, so verify:localization-catalogs fails on
main ("extra: dashboardPopout.terminal.closed"). Drop it from those three. No
other locale has extra keys; ru's _few/_many plural forms are expected.
…#34675)

* fix(terminal): allow automation during phone control

* test(terminal): specify driving input in IPC admission fixture

* test(terminal): delegate preview input through host admission
…tablyai#34774)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(terminal): preserve Codex exit queries across snapshot restore

* fix(terminal): replay owed queries from discarded output and superseded replays

- Mark yielded queries discarded when ACK overflow trimming, the recovery
  cutoff, or snapshot-buffer overflow drops their output unsent, and replay
  them after the covering snapshot (including the ACK recovery snapshot).
- Purge snapshot query replays and escape-tail frames still queued behind the
  ACK window when a newer snapshot is published, and put new replays at the
  head of the ACK queue so they follow their snapshot.
- Share isPrimaryDeviceAttributesQuerySequence across DA1 call sites.
- Move replayed-query settlement into settleReplayedYieldedQuery.

* fix(terminal): replay DA1 still batched when an ACK recovery snapshot covers it

* test(terminal): type the overflowed initial-snapshot stream fixture

* test(terminal): give the host-chain recovery stream fixture its required query and batcher state
…lyai#34775)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
… under max-lines (stablyai#34929)

* fix(i18n): drop queued-message keys stablyai#31180 removed from en

stablyai#31180 removed components.native-chat.queuedMessages.cancelEditing, .pasteOrDropImages and
.saveNeedsContent from en.json; tr.json, added since, still carried them, so the locale catalog
check failed on main. They are the only stray keys in any locale.

* fix(lint): split runtime-file-read-client under the max-lines cap

Move the remote chunked-download helpers into runtime-remote-file-download.ts so
runtime-file-read-client.ts is back under the 300-line lint cap. No behaviour change.
…ai#34907)

* fix(export): cancel PDF work when requesting document retires

* test(export): assert success on non-retired repeated export cycles

---------

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

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Upstream range df95be4..36d2956, 335 commits. 12 conflicted
paths, 13 hunks: 11 both modified and 1 modify/delete.

Conflicts:
- AGENTS.md (#26): upstream's reworded test line (stablyai#34507); the fork's
  section stays.
- Locale catalogs (#6 #7 #9 #10 #13 #14 #17 #31): upstream's catalogs
  plus the fork's keys. en.json drops the "idle" key upstream retired
  (stablyai#22056) and keeps the fork's 14 update-source keys; es, ja, ko and
  zh keep upstream's new terminalPane.hostFile beside the fork's
  AgentResumeChooser.
- server-ingest-remote.ts (#30): upstream stablyai#34724's
  IncomingAgentHookEvent and codexRosterAuthority beside the fork's
  reportsUserEndedSessions.
- pty-management.ts (#25): upstream stablyai#32153 tracks the generations whose
  listing failed. Each listed session still carries the adapter that
  listed it, and the kill poll keys a failed listing by that adapter,
  not by protocol version: a drained daemon shares the current one's
  version.
- main-process-ready-runtime.ts (#16): upstream stablyai#34059's WSL-move
  rewrite pass and the fork's mac self-update launch report both run
  after the first window.
- GeneralUpdateSettingsSection.test.tsx (#14): upstream deleted it as
  low-value (stablyai#34370); the fork's two cases move unchanged, with the
  setup they use, to GeneralUpdateSettingsSection.single-source.test.tsx.
- pane-agent-evidence.test.ts (#6) and terminal-mode-reset-profiles.test.ts
  (#11): upstream's test removals (stablyai#34612, stablyai#34520); the fork's cases
  stay, with the imports they use.

Breaks the conflict list did not show:
- server-ingest-remote.ts reached 305 counted lines (max 300); upstream's
  copy is at exactly 300. The fork's lines leave it: the relay's
  user-ended notice is read where payload validation drops it, which is
  where the notice was designed to stop, and the fork-owned
  withRelayUserEndedSessionReports in server-terminal-loss-resume.ts
  stamps reportsUserEndedSessions. Now 299.
- Upstream's new ru, tr and zh-Hant catalogs (stablyai#34717, stablyai#34718, stablyai#29795)
  carried "Orca" for the titlebar key the fork changes in every
  catalog (#7 #13 #31); they take the fork's value.

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

chatgpt-codex-connector Bot commented Oct 28, 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-10-28T10:23:51.657097Z dd8ce6e 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

CI after the merge (advisory for syncs): 108 passed, 6 failed, 1 cancelled, 2 pending. None of the failures is in a file the fork changes:

The fork build for 34f36fd477 published swaplabs-v1.4.214+202610281022 with all platforms.

kiwidream added a commit that referenced this pull request Oct 28, 2026
Resolve the en.json conflict by keeping both the leaderboard keys and the keys from sync #64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.