Orca's remote-server feature pairs a desktop client to a remote Orca runtime,
and users update the two independently, so mixed versions are the normal state.
Until now nothing ran an old client against a new server or the reverse. Every
cross-version claim rested on code reading plus unit tests built from
hand-written old and new shapes, which cannot catch a real skew regression.
This adds a two-point compatibility matrix that loads the REAL host RPC methods,
the real RpcDispatcher, and the real renderer terminal multiplexer from two
builds — the working tree and the newest release tag — and drives them against
each other over an in-process transport that reproduces production frame
routing, including the host-side decode that drops unknown opcodes without an
error. One scripted journey runs per pairing: subscribe, input reaching the
process, live output, hide/reveal buffer snapshot, transport drop, resubscribe,
and input landing again.
The oracle asserts the journey actually executed rather than that nothing threw:
the recorded step list, the exact named frame sequence, both subscribed events
with their negotiated capabilities, the exact input texts the host wrote to the
PTY, the rendered snapshot and output content, and an empty set of frames
refused by either decoder. A host runtime method the harness does not stub is
reported by name, so a harness gap can never be misread as a wire break.
Detection is proven per rule by injecting each violation and reverting it.
Adding an optional snapshot field kept every pairing green; making the client
require that field turned only new-client/old-server red. Adding opcode 17 and
sending it ungated turned new-client/old-server red with the rejected opcode
named, while old-client/new-server stayed green. Making the host stop publishing
the snapshot `source` field turned both new-server pairings red and left the
old-server pairing green.
docs/reference/remote-wire-compatibility.md writes the three rules down, and a
dedicated CI job runs the harness with fetch-depth 0 because the sharded test
lane's shallow clone has no tags; that lane now excludes the harness explicitly.
Refs STA-3469.
* fix(worktrees): stop silently switching existing Windows setup scripts to Git Bash
#6967 derived the Windows setup-runner shell from `terminalWindowsShell`. On
upgrade, any Windows user whose terminal preference resolved to Git Bash had
their existing `orca.yaml` setup script (and issue command) handed to bash
instead of cmd.exe. Scripts authored against the cmd runner — `copy`, `xcopy`,
`set VAR=value`, `if errorlevel 1`, `%VAR%`, backslash paths — broke with no
migration and no warning, and the failure looked like Orca broke the project.
The conflation is also wrong in the steady state: a terminal preference is
per-user, so two people on the same repo got different interpreters for the
same orca.yaml and no project could write a setup script that worked for all
of its Windows contributors.
The interpreter is now a property of the script, declared the standard way:
a leading `#!` line. Native Windows keeps the historical `.cmd` runner unless
the script declares a POSIX shell, so no existing script changes behavior.
`resolveSetupRunnerShell` keeps its role as the feasibility gate — a bash
runner still requires the terminal to resolve to Git Bash, since the launch
command is typed into that shell and uses MSYS `/c/...` paths.
`buildWindowsRunnerScript` now drops a leading `#!` line rather than `call`ing
it, so a declared-bash script that falls back to cmd (Git Bash missing) fails
on a real setup line instead of aborting on errorlevel at line one.
WSL worktrees, POSIX platforms, and SSH hosts are untouched.
* fix(worktrees): keep the cmd setup runner launchable from a Git Bash pane
Adversarial review of this PR found that pinning the runner format per script
reopened issue #6896 one layer down.
- `WorktreeSetupLaunch.shell` had been redefined to mean "the format the runner
file was written in". `resolveSetupRunnerCommand` consumes it as "the shell
that types the launch command", so a Git Bash terminal with a batch setup
script produced `cmd.exe /c "C:\...\setup-runner.cmd"` typed into a bash pane,
where MSYS rewrites the `/c` switch into a drive path: cmd opens interactively
and setup never runs. `shell` is the terminal's family again; the runner file's
.cmd/.sh extension carries the format, and a batch runner launched from a POSIX
pane reuses the existing PowerShell ProcessStartInfo launcher.
- The cmd runner dropped a leading `#!` line and ran the rest as batch, so a bash
script reaching cmd (PowerShell/cmd terminal, or any SSH-to-Windows host) got
its interpreter-agnostic prefix executed before failing mid-way. It now prints
why and exits 1 without running anything.
- A `#!` line's option flags were discarded: `#!/usr/bin/env -S bash -euo
pipefail` lost pipefail because the runner is launched as `bash <path>`. The
generated posix runner now replays declared flags via `set` and drops the
duplicate interpreter line.
- Docs cover the per-user setup command in repository hook settings, which goes
through the same `#!` rule, and describe what the `#!` line does and does not
select.
Tests: composed launch command for a POSIX pane + cmd runner (hooks, shared
runner command, setup sequencing gate, observed-setup signal), the cmd runner's
shebang refusal, and shebang flag replay. Each fails with the source reverted.
* fix(worktrees): replay only real `set` flags and keep the gate in the pane's shell
Two round-2 review findings:
- `#!/bin/bash -l` replayed `set -l`, which exits 2 and aborted the runner under
its own `set -e` before a single setup line ran (all platforms). Only the flags
`set` documents are replayed now; a bare `-o` with no option name is dropped
instead of dumping the shell-option table.
- The wait-for-setup gate picked its language from the runner file, so a batch
runner launched from a Git Bash pane got the PowerShell gate while the agent
startup command was already POSIX-quoted — `Invoke-Expression` cannot parse
`'\''`. The gate now follows the pane; the runner still launches through the
ProcessStartInfo launcher, never through bash.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(linux): restore Ubuntu 20.04 launch by pinning node-pty glibc symbols (#9902)
The bundled node-pty pty.node is compiled from source in release CI on
ubuntu-latest (glibc 2.39). glibc's 2.32-2.34 libpthread/libutil merge
relocated openpty/forkpty (GLIBC_2.34) and pthread_sigmask (GLIBC_2.32)
into libc under new symbol versions, so the from-source build bound to
versions absent on Ubuntu 20.04 (glibc 2.31). The main process imports
node-pty at startup, so the app crashed on launch. pty.node is the sole
blocker (Electron needs GLIBC_2.25; other native modules <= 2.17).
- Patch node-pty: a .symver shim pins the 3 symbols to their pre-merge
version (GLIBC_2.2.5 x64 / GLIBC_2.17 arm64), and Linux-only ldflags
force libutil.so.1/libpthread.so.0 back into DT_NEEDED. Guarded to
Linux; macOS/Windows untouched.
- Add a packaging gate (verify-linux-glibc-floor.cjs, afterPack): reads
each bundled native binary's objdump -p version needs and fails the
Linux build if any strong GLIBC_/GLIBCXX_/CXXABI_ node exceeds stock
Ubuntu 20.04 (glibc 2.31 / GLIBCXX_3.4.28 / CXXABI_1.3.12). Catches
GLIBC_ABI_DT_RELR, rejects GLIBC_PRIVATE, skips weak needs, fail-closed.
- Docs + tests; the lazy sherpa-onnx speech prebuilt (GLIBCXX_3.4.29,
never loaded at launch) is a documented libstdc++-floor exemption.
* fix(linux): assert DT_NEEDED provider deps in the glibc-floor gate
Harden the packaging gate (flagged in adversarial re-eval): the version-floor
check alone can false-pass if the patch's forced `-l:libutil.so.1` ever silently
drops — the pinned openpty@GLIBC_2.2.5 still resolves from libc's compat alias at
build time, but fails to load on Ubuntu 20.04 where openpty/forkpty live only in
libutil. The gate now also asserts that any binary importing openpty/forkpty
keeps libutil.so.1 in DT_NEEDED. Validated on a real symver-pinned .so with
libutil dropped (now fails) vs. present (passes). Documents the recommended
real-host smoke-test follow-up.
* fix(sidebar): guard every worktree sort against undefined displayName (crash 99657ab1)
Worktree.displayName is typed non-optional but arrives undefined at runtime for
persisted/discovered worktrees (crash 99657ab1). PR #8683 fixed the kanban board;
this extends the same guard to the five other sort sites that share those worktree
objects — including the Cmd+J switcher (order-empty-query-worktrees) — via one
shared compareWorktreeDisplayName helper in lib/. Behavior-neutral when names are
present; a missing name now sorts as '' instead of throwing.
Co-authored-by: Orca <help@stably.ai>
* docs(agents): add over-commenting anti-pattern example to the comment rule
Anchors the existing 'document the why, briefly' rule with a concrete
before/after (the worktree-displayName guard) so agents stop dumping the
crash id, mechanism, file location, and every call site into a comment.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
oxlint already fails any file over max-lines that is not suppressed, so the
only way to grow past the budget is to add an eslint/oxlint-disable max-lines
comment or a per-file max-lines bump in mobile/.oxlintrc.json. This adds a CI
gate that freezes the current set of suppressions (config/max-lines-baseline.txt,
355 grandfathered entries) and fails the build when a NEW one appears — with a
loud, actionable message pointing at 'split the file'. Existing oversized files
are untouched; the baseline may only shrink (pnpm check:max-lines-ratchet --prune).
Wired into the root lint script and as a dedicated pr.yml step. Unit-tested
(15 cases) and verified against all three failure paths + clean-tree pass.
Co-authored-by: Orca <help@stably.ai>
- Use fallback PR numbers after branch lookup misses, including detached HEAD
- Preserve review cards for forked or deleted-head PRs across manual refreshes
- Clear stale GitHub PR cache entries when unlinking worktree review metadata
* Strip Grok user query wrapper from status prompts
* Document PR evidence image handling
* Surface Grok final responses in agent status
* Harden Grok status result extraction
* Squashed commits
- refactor
- commit design doc
* docs: add why-comments to conflict resolution code and track conflicts on open
- Add explanatory comments throughout conflict resolution code covering
safety constraints, architectural boundaries, and compatibility choices
- Track unresolved conflicts in openConflictFile so Resolved locally
state works for conflict-safe entry point
- Add CLAUDE.md/AGENTS.md guideline for documenting the "why"
- Add test for conflict tracking through openConflictFile
* feat: make keyboard shortcuts work with Ctrl on Linux/Windows
All Cmd+X shortcuts now also respond to Ctrl+X on non-Mac platforms.
Tooltip hints show platform-appropriate modifier symbols.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add cross-platform guidelines to AGENTS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>