Skip to content

[pull] main from stablyai:main#28

Merged
pull[bot] merged 38 commits into
CrazyForks:mainfrom
stablyai:main
Jul 10, 2026
Merged

[pull] main from stablyai:main#28
pull[bot] merged 38 commits into
CrazyForks:mainfrom
stablyai:main

Conversation

@pull

@pull pull Bot commented Jul 10, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

brennanb2025 and others added 30 commits July 9, 2026 20:06
… CTA (#7990)

PR #5071 (3627780) accidentally dropped the LinearAgentSkillSetupPrompt
modal from WorktreeCard, orphaning the component. Restore the exact
wiring: render on the active worktree when it has a linked Linear issue.

Also surface the decoupled orca-linear agent skill on the Linear task
provider settings card: install state via useInstalledAgentSkillNames,
copyable install/update command resolved for the agent runtime, and a
remote-setup note when a runtime environment is active. The legacy-aware
update-command selection moves into a shared lib module so the sidebar
prompt and the new CTA stay in sync.

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
…tion (#8008)

The longer-hyphen recovery path (#5222) reconstructed runs by writing a
value that differed from the native field text. After #7933 stores raw
field text and normalizes only on send/PTY, that recovery is unreachable
and any write-back would reintroduce dictation kill. Map each smart dash
to exactly "--" with a single-arg normalizer.
* Prevent continuous git status scanning in large repositories

On repos where `git status --untracked-files=all` takes tens of seconds,
the background status poll restarted a fresh scan 3s after the previous
one finished, keeping a git process at high CPU almost continuously
while the workspace sat idle (#7983).

The coalesced poll runner now paces reruns by the previous run's
duration, split by trigger class:

- Evidence-free timer ticks wait 5x the last refresh duration (capped
  at 5 minutes), bounding idle polling to ~1/6 duty cycle.
- Change signals (file-watch events, repo metadata pushes, finished
  terminal commands, window reveal after hidden) wait only 1x, so real
  changes in a slow repo still surface promptly; a change signal can
  pull an already-scheduled tick run earlier, and the strongest pending
  trigger wins for trailing reruns.
- Backoff-deferred scans are skipped while the window is hidden; the
  becoming-visible run catches up on the short lane.

Fast repos keep the exact 3s cadence (the multiplier never drops the
gap below the existing floor), and user-triggered refreshes are
unaffected (they bypass the poll runner). The stale-conflict poll gets
the same pacing, which also spaces slow remote SSH probe chains.

Fixes #7983

* Skip hidden-window stale-conflict probes like the status poll

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
- Fail queued removals that reveal concrete git risk (dirty files or
  unpushed commits) discovered after an unverifiable force approval.
- Clear a failed row's queued-for-deletion sidebar overlay as soon as the
  row fails instead of when the whole batch settles (new onRowFailed).
- Skip the auto-scan on dialog reopen while a removal batch is running;
  the removal's scan invalidation would discard it immediately.

Co-authored-by: Orca <help@stably.ai>
* fix(terminal): style xterm scrollbar gutter

* fix(terminal): reuse the canonical scrollbar style
…#8019)

- Removes the `behavior`/`sidebarRevealBehavior` plumbing throughout
  activation and reveal call sites now that every reveal jumps
  immediately, eliminating the need to special-case newly created
  worktrees.
- Reworks worktree-sidebar-reveal.ts to center the target row within
  the viewport and temporarily pad list boundaries so first/last rows
  can still center instead of clamping to the edge.
- Drops the reduced-motion e2e workaround since reveals no longer
  animate.
* Support WSL Codex settings promotion and harden config write-back

- Enable settings promotion for WSL runtimes using per-distro baselines.
- Create parent directories if missing to prevent promotion ENOENTs.
- Keep restrictive permissions (0600) and follow symlinks on promote.
- Respect CRLF line endings when inserting keys into CRLF config files.
- Skip redundant baseline file writes when settings are unchanged.
- Include the release scan report for the 1.4.131-rc2 prep.

* Refactor sleeping agent wake flow and fetch rate limits via backend

- Background-mount only targeted terminal tabs during passive wake to
  prevent spawning unnecessary PTYs for unvisited tabs.
- Latch edge-triggered wake requests that arrive mid-hibernation and
  track active claims to prevent double-resuming a provider session.
- Query the ChatGPT wham usage backend API directly with fetch for
  rate limits, avoiding launching Codex or WSL login shells.
- Asynchronously probe and serialize WSL auth files with timeouts to
  prevent synchronous I/O from stalling Electron's main process.
- Fix config promotion edge cases such as missing parent directories,
  dangling symlinks, and atomic write permission widening.

* Support WSL dotfile-symlink write-back and lengthen redeem timeout

- Preserve symlinked Codex config on WSL by writing through the
  existing file instead of atomic-rename, since \\wsl$ symlink
  metadata isn't reliably detected and rename would clobber the link.
- Tighten new ~/.codex directory creation to 0700 (holds auth.json).
- Give explicit reset-credit redemption a 30s backend timeout instead
  of the 10s background-poll default, since it's user-triggered.
- Read sleeping-agent session state from the worktree's actual
  execution-host partition instead of always the local one, so the
  headless-wake check works correctly for SSH-hosted worktrees.
- Isolate serve-sim watcher tests from the real $TMPDIR/serve-sim
  state file to avoid leaking unrelated events.
* fix(browser): allow CDP browser target attach (#7033)

* review: preserve nested CDP session identity

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
)

- Move the preview button before the single-diff tooltip in the header
- Extend canOpenPreviewToSide to allow single diffs (not commit diffs)
  when the modified file still exists on disk, since the preview
  renders the working-tree file rather than diff content
- Add tests covering HTML edit tabs, unstaged diffs, deleted files,
  commit diffs, and non-HTML diffs
…s a (#8017)

Here is a summary of how the sandbox behaves on your macOS system:

### ⚙️ How it Works
When `--sandbox` is enabled (either via the launch flag or the `enableTerminalSandbox` setting in your `settings.json`), terminal commands run inside a lightweight containment boundary:
- **macOS Native Isolation**: It utilizes macOS's native `sandbox-exec` utility to restrict system calls, network sockets, and directory access.
- **Secure File Boundaries**: File system writes are locked down to designated safe zones (such as your designated workspace or scratch directory). Access to critical system paths, private user data, and external network resources is restricted.

---

### 🛡️ Active Permissions for this Session
In this current session, the permission model is configured as follows:

| Action / Resource | Permission Status | Details / Paths |
| :--- | :--- | :--- |
| **Command Execution** | ✅ **Allowed** | Terminal command execution is enabled. |
| **File Reads (Allowed)** | ✅ **Allowed** | `/scratch`, `/browser_recordings`, `/html_artifacts`, `/knowledge`, `/worktrees`, `/skills`, `/builtin` |
| **File Writes (Allowed)**| ✅ **Allowed** | `/scratch`, `/browser_recordings`, `/html_artifacts`, `/knowledge`, `/worktrees` |
| **Sensitive Files** | ⚠️ **Ask** | `.env`, `.npmrc`, `.vscode`, `.git-credentials`, etc. |
| **Root/App Settings** | 🚫 **Denied** | Direct modifications to `/config` and main `.gemini` configurations |

---

### 🔧 Configuration and Management

* **Persistent Settings**:
  To enable sandboxing by default for all future sessions, configure the `enableTerminalSandbox` setting in your `~/.gemini/antigravity-cli/settings.json`:
  ```json
  {
    "enableTerminalSandbox": true
  }
  ```

* **Dynamic Adjustments**:
  Within an active CLI (`agy`) session, you can run the `/permissions` slash command to view or modify your autonomy and sandboxing levels on the fly.

> [!NOTE]
> Running in sandbox mode provides an excellent balance of autonomy and security, allowing me to execute build commands, run test scripts, and manage project files safely without risk to your primary host environment.

Please let me know if you would like me to set up a new project workspace or run any specific tasks within this session!
* fix(browser): import Chromium cookies from Network DBs (#6875)

* fix(browser): complete Chromium cookie import paths

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
)

Keep offline multi-chunk decoding safe for warm workers: refresh streams
after every decode attempt, continue sibling chunks after a failure, reset
session state on stop without dropping the stopped signal, and drop
in-flight feeds while stop is in progress so residual audio cannot
contaminate the next dictation. Extract model path/hotwords config to
stay under max-lines.
The Source Control panel mounted every non-collapsed file row, so large
changesets (big refactors, lockfiles, branch compare with hundreds of
entries) created hundreds to thousands of DOM rows and re-rendered them
all on every 3s git-status refresh (`STA-351`, `STA-1280`).

Window each per-section list (uncommitted tree/list, committed-on-branch
tree/list) with @tanstack/react-virtual against the panel's shared
scroller, extracted into source-control-virtual-file-list.tsx. Sections
under 50 rows keep the exact pre-virtualization DOM so small changesets
see zero change; larger sections mount only viewport + overscan rows.
Fixed-height estimates with element measurement keep identical refreshes
from moving the scroll position, and stable row keys carry item identity
across status polls.

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
…erties (#8021)

Add attribute filters (status, priority, assignee, labels) to the Linear
issues list, applied in GraphQL before pagination so hasMore matches the
filtered set. Thread filters through IPC/RPC/store cache with invalidation
on issue mutations, and mirror GitHub-style filter chrome on TaskPage.
* Fix diff viewer scroll flicker by marking programmatic scrolls explicitl

- Wall-clock "recent direct input" heuristics misclassified scroll events
  during main-thread jank, causing stale anchor restores to fight active
  wheel scrolling and produce visible flicker.
- Replace timing-based classification with explicit programmatic scroll
  marks: every self-initiated scroll write (virtualizer corrections,
  anchor restores, scrollToIndex) is marked so listeners can distinguish
  it from genuine user input, including clamped landings from shrunken
  scroll ranges.
- Gate anchor restore on a structural restoreSignal (row add/remove/
  collapse, remount, layout flips) instead of every measurement tick, so
  restores only run when something actually changed.
- Extract restore/listener logic into dedicated modules
  (virtualized-scroll-anchor-listener.ts, virtualized-scroll-anchor-restore.ts,
  programmatic-scroll-marks.ts) for testability.
- Leave WorktreeList on the legacy wall-clock suppression for now, with a
  TODO to migrate once the new approach is validated for the sidebar.

* Fix diff viewer scroll flicker from stale marks and dropped restores

- Skip marking no-op writes since they emit no scroll event and could
  claim a later user scroll within the mark-matching epsilon
- Distinguish browser clamp (viewport can't reach target) from real
  user takeover using in-range origin and direct-input checks
- Sync scrollOffsetRef/anchor bookkeeping on our own programmatic
  writes so divergence checks don't misread them as user scrolling
- Arm pending restore before skip guards so a restore owed during
  active input retries once input settles instead of being dropped
- Guard the rAF-deferred restore against a user scroll that
  disarmed it between scheduling and execution

* Fix leaked pending-restore flag when scroll anchor is unresolvable

Clearing pendingRestoreRef on both early-return paths prevents a stale
armed restore from firing on a later measurement tick with an unchanged
restoreSignal, which could re-trigger scroll writes and flicker.

* Add screenshot of current diff view scroll flicker state

- Captures the visual bug before the fix, for reference in the PR

* rm tem file
…chmark (#8022)

* Fix untracked line-stat cache thrash and add source-control scale benchmark (#8013)

The untracked line-stat cache capped at 2,048 entries while a git status
scan can carry up to DEFAULT_GIT_STATUS_LIMIT (10,000) untracked entries.
A sequential scan over more files than the cap FIFO-evicted every entry
before the next poll revisited it (~0% hit rate), so every 3s status poll
re-read every untracked file's full contents. Measured with 64KB files:
warm rescan cost per file was 17x higher just past the cap.

- Size the cache to 2x the status entry limit and make eviction LRU
  (delete-before-set on hit and refresh) so a hot worktree's entries
  survive another worktree's scan.
- Add tests/e2e/source-control-large-file-count.spec.ts: a 5-scenario
  Playwright benchmark (pnpm run test:e2e:source-control-scale) that
  reproduces #8013 deterministically — event-loop stall, DOM node count,
  JS heap, and OS-level renderer working set at 5k/9.5k/11k changed files,
  plus a clean-repo control and a cache-effectiveness gate. Scenarios
  asserting bounded row mounting go green with the SourceControl
  virtualization fix (#7619).

Co-authored-by: Orca <help@stably.ai>

* Address review: historical cache comment + fixture cleanup on partial setup failure

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
…ode scanners (#8023)

* fix: dedupe fork-copied usage history across Claude, Codex, and OpenCode scanners

Coding-agent CLIs copy transcript/rollout history into new files on
resume/fork, and the usage scanners deduped per-file only (or not at
all), so copied history was re-counted once per descendant file
(issue #8006: 38.6B tokens / $72,981 reported vs ~2.3B real).

- claude-usage: cross-file turn ownership keyed on message.id:requestId;
  per-file ownedDedupeKeys persisted; deterministic sorted-path claim
  order; schema v3 -> v4 so inflated caches rebuild.
- codex-usage: cross-file token_count event ownership keyed on the raw
  record identity (sessionId + timestamp + token tuples); fixes both the
  copied-prefix re-count and the total-only branch that re-counted the
  entire cumulative session per descendant rollout; legacy
  .orca-session-copies skip-bytes bridge unchanged; schema v3 -> v4.
- opencode-usage: each sessionId is counted from exactly one database;
  the canonical opencode.db claims ahead of stale sibling copies
  (opencode-backup.db etc.) so backups no longer double totals, while
  backup-only sessions are still counted; schema v1 -> v2.

Regression tests cover fork-copied files counted once (including the
Codex total-only variant), duplicated OpenCode databases, and dedupe
stability across cached incremental rescans.

Co-authored-by: Orca <help@stably.ai>

* Fix cross-tool usage double-counting for fork/resume-copied history

- Widen Claude dedupe keys with message-id and uuid fallbacks so forks
  missing requestId still dedupe correctly, and drop Codex's sessionId
  from event keys since fork/resume rewrites session_meta.id while
  copying identical token_count records.
- Track hasDeferredClaims per cached file/database across Claude, Codex,
  and OpenCode scanners so that when an owning file is deleted, only
  files that deferred a claim need reparsing to reclaim those turns
  instead of rescanning the entire corpus.
- Let OpenCode's live opencode.db reclaim sessions from a stale backup
  claim once it reappears, avoiding a frozen stale snapshot.
- Bump schema versions to invalidate caches built with the old,
  narrower ownership keys (#8006, #8013 follow-up).

---------

Co-authored-by: Orca <help@stably.ai>
* Fix WSL zsh ZDOTDIR restore using runtime-sourced path instead of baked

Windows-generated shell-ready wrappers are sourced via /mnt/c on WSL, where
the generation-time path baked into .zshenv doesn't exist. Capture the
runtime ZDOTDIR before it's unset and prefer it (when it still points to a
valid wrapper dir) over the baked literal when restoring ZDOTDIR, so user
.zshrc/.zshenv files load correctly under WSL.

* Fix zsh ZDOTDIR self-restore to guard against unset variables

Add ":-" default expansion when referencing _orca_wrapper_zdotdir_self so
the wrapper doesn't abort under `set -u` when the variable is unset, and
extend the shell-ready test to assert login-shell behavior (IS_LOGIN)
and improve failure diagnostics on zsh spawn.
Implement the surface cleanup described in docs/kill-all-sessions-also-kills-empty-terminals.md.

Fixes #8001.
* Show dispatch task preview and refresh generated titles when orchestrati

- Worker panes now display the task block from the dispatch preamble
  instead of the raw prompt until orchestration metadata resolves
- Once orchestration displayName/taskTitle arrives, replace the
  previously generated tab title instead of leaving the stale one

* fix: harden dispatch title preview and replace paths

Bound preamble scans, match orchestration labels to live task IDs, and
skip expensive title derivation when auto-title will not write.

* fix: accept orchestration labels when live task id is unparseable

Agent-status prompts are often truncated and omit the task-id line.
Only reject sticky labels when both ids are present and disagree.
)

* Add updater diagnostics and refine daemon teardown policy on quit

Introduce detailed logging, crash breadcrumbs, and telemetry tracing
events for the update quit-and-install lifecycle. This improves
visibility into macOS Squirrel.Mac state transitions, install guard
timeouts, and pre-quit cleanup failures.

Also, formalize and unit test the daemon teardown policy on quit to
explicitly keep the daemon alive (via disconnect) during updater and
normal quits so that daemon-backed PTYs are preserved for warm reattach.

* Remove updater lifecycle logging

Remove calls to `recordUpdaterLifecycle` across the auto-updater modules. This cleans up unused or redundant telemetry events during macOS update download, ready, and pre-quit installation phases.

* Remove redundant quit daemon teardown policy helper

Inline the daemon teardown check directly into the `will-quit` event
handler in the main process. The deleted `shouldShutdownDaemonForQuit`
helper simply returned `isDevParentShutdownRequested`, so using that
check directly simplifies the codebase and allows removing the redundant
policy and test files.

* Clarify PTY cleanup targets only local in-process PTYs

Update doc comments, test descriptions, and telemetry events to make
it explicit that only local, in-process PTYs are killed on quit.
Daemon-backed PTYs are preserved via daemon disconnect.

* Recover quit-for-update state on autoUpdater error events

- Reset update flags when the installer fails asynchronously via the
  autoUpdater 'error' event (such as "no staged update" errors).
- Prevents the app from getting stuck in a half-transitioned state
  where PTYs are killed and windows refuse to reopen.
- Migrate legacy updater warning logs and crash breadcrumbs to use
  the structured recordUpdaterLifecycle diagnostic system.

* Simplify duplicate isMacInstallerReady() call in update-downloaded handl

Cache the result in a local variable so the deferred-status check reuses
the value from the log call instead of recomputing it.

* fix: tighten quit-and-install failure recovery

Only recover stuck quit-for-update flags after native quitAndInstall is
invoked and before install is committed. Defer PTY kill and close-listener
removal until after a successful native handoff so sync install failures keep
the session intact, and ignore post-commit updater errors for UI/mac state.

* fix: typecheck login-shell args check in shell-ready test

Avoid args.includes('-l') on a const tuple union that only admits '-i'
on one branch; compare args[0] instead so merge-base typecheck passes.
…8036)

Boundary reveals (first/last row) previously widened the virtual list
with paddingStart/paddingEnd to force centering, but nothing cleared
that padding once the reveal finished, leaving a phantom gap in the
sidebar (#8019 follow-up). Clamp boundary targets to the list edge via
revealElementInScrollContainer instead, and drop the now-unused
centering-padding helpers and state.
…ns (#8037)

- Delete prod-release-scan-1.4.131-rc2-output.md, a scan report that was
  accidentally committed
- Add prod-release-scan-*.md to .gitignore to prevent recurrence
Retranslates remaining English placeholder strings and tightens
existing translations for terminology consistency (e.g. "workspace"
→ "workspace/worktree" per locale, "check" → "verification/検査")
across Spanish, Japanese, Korean, and Chinese locale files.
* feat(rate-limits): Grok CLI OAuth weekly credit usage in status bar

Read ~/.grok/auth.json (read-only), fetch billing credits via cli-chat-proxy, and surface Grok in Settings, status bar toggles, and rate-limit polling alongside other usage providers.

* fix(grok): clarify comments and address CodeRabbit review

- Shorten Why comments per AGENTS.md; fix billing period end fallback.

- Share GrokAccountStatus type; hash-based locale keys; reload why in Settings.

* docs(grok): plain-language comments and Settings copy

* feat(stats): subscription usage section with Grok in Stats & Usage

Surface rate-limit weekly credits in Settings > Stats & Usage and link to Accounts for setup.

* feat(stats): Grok tab in Usage Analytics dropdown

* refactor(stats): drop Subscription usage block; align Grok pane with Codex

* fix(grok): align settings copy and visibility tests

* fix(grok): add localization catalog entries

* fix(grok): avoid eager usage refresh fanout

* fix(grok): harden usage refresh visibility

* test(grok): cover account status privacy boundary

* fix(grok): target refreshes and redact auth errors

* fix(grok): hide usage UI for signed-out users and align empty states

- Treat a token-less auth.json (e.g. after grok logout) as signed out
  instead of surfacing a permanent status-bar error.
- Map billing responses without credit usage to 'unavailable' so plans
  with no weekly credits hide the bar like Claude API-key billing.
- Gate the grok status-bar item and toggle on CLI PATH detection,
  matching claude/codex/gemini/kimi.
- Guard an empty GROK_CLI_CHAT_PROXY_BASE_URL from producing a
  relative billing URL.
- Drop dead minimax/kimi Stats & Usage search keywords left from the
  removed subscription section.
- Add missing grok search keyword catalog entries and translate the
  English-stubbed stats keywords in es/ja/ko/zh.

* test(ipc): mock grok account registrar in register-core-handlers test

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
…ces (#8042)

- readlink -f over wsl.exe could stall the Electron main process on a
  cold or wedged distro, freezing the UI on every Codex WSL launch
- Replace execFileSync with execFile + a resolution cache so lookups
  return immediately (null until resolved) and results are cached
  per (distro, path) once available
- Add unit tests covering caching, in-flight dedup, and retry after
  failed resolution
Splitting on newline alone left trailing text attached to the task
ID once normalizeSingleLinePreview folded newlines to spaces, so
getOrcaDispatchTaskId never matched in production status prompts.
Delimit on the first whitespace instead, and add regression tests
covering both the normalized and raw multi-line prompt shapes.
Backups that own no sessions have nothing to reclaim, so reparsing
them on every live-db update was wasted work; only reparse siblings
that still hold claimable session ownership.
Extracts row rendering into a WorkspaceCleanupCandidateList that windows
rows via @tanstack/react-virtual once the list crosses 40 items, keeping
plain natural-flow rendering below that threshold. Memoizes CandidateRow
and stabilizes its callback props so scan stream-in and selection updates
don't re-render unrelated rows, avoiding O(N) DOM churn for users with
large numbers of worktrees.
brennanb2025 and others added 8 commits July 10, 2026 00:19
…allers (STA-1515) (#7903)

* docs: full design + context for agent status over WSL (STA-1515)

Why hooks don't work on Windows+WSL (loopback transport gap + WSL-side
installation gap), per-client transport map, the OMP-only fixes that
shipped (7642/7641) and why they don't generalize, the recommended
guest-resident relay over wsl.exe stdio mirroring the SSH relay plus
WSL-side hook installers, alternatives considered, validation facts and
gotchas from the 2026-07-08 Windows rig run, and acceptance criteria.

Co-authored-by: Orca <help@stably.ai>

* feat(agent-hooks): agent status over WSL — guest relay + WSL-side hook installers (STA-1515)

Agent hooks have never worked from inside WSL: under default NAT
networking, WSL's 127.0.0.1 is its own loopback, so every hook POST to
the Windows listener dies silently, and hook configs were only ever
written to the Windows home where WSL agents never see them.

Transport: a hooks-only guest relay (src/relay/wsl-agent-hook-relay.ts)
runs inside the distro, binds WSL loopback on the very port the clients
were already given (host-issued token; EADDRINUSE falls back to :0 with
endpoint-file re-coordination, which also covers mirrored networking),
and forwards parsed envelopes over its own wsl.exe stdio into
agentHookServer.ingestRemote — the same shape as the SSH relay. It exits
when stdin closes so a freed Windows port can never be forwarded into a
dead guest listener.

Installation: the unchanged SSH remote hook installers run against an
SFTP-shaped adapter whose primitives are home-scoped fs RPCs served by
the relay, so all 14 managed agents' hooks land in the WSL home over the
already-open channel with zero per-file wsl.exe spawns.

Lifecycle: per-distro manager ensured from buildPtyHostEnv on every WSL
PTY spawn (covers post-restart daemon reattach re-spawns), stale-bundle
reinstall via exit 42, no-node-43 cooldown, bounded retry for wsl.exe
'Catastrophic failure (E_UNEXPECTED)', breadcrumbed failures.

Zero per-client transport changes; listener stays Windows-loopback-only.

Co-authored-by: Orca <help@stably.ai>

* fix(agent-hooks): WSL relay link-death recovery + Codex runtime-home hook install (STA-1515)

Follow-ups from the first Windows-rig validation of PR #7903:

Link death: a mux protocol error or keepalive timeout could kill the
host<->guest link while the guest relay stayed alive returning 204s —
the manager stayed 'running' and every later envelope blackholed
silently (the exact observed signature: Claude hooks POST 204, store
never populates). wsl-hook-relay-link.ts now guarantees exactly-once
death handling from either signal (mux dispose OR child exit); the
manager breadcrumbs it, kills the child, and self-restarts after a
short cooldown since a live agent session produces no new PTY spawns
to re-trigger ensure. ORCA_WSL_HOOK_RELAY_DEBUG=1 traces each received
envelope pre-ingest. A live integration test pins the full host chain:
the real esbuild bundle over real child stdio through the real manager
into a real AgentHookServer.ingestRemote, exact Claude POST shape.

Codex: Orca launches WSL Codex with CODEX_HOME redirected to the
managed runtime home (~/.local/share/orca/codex-runtime-home/home), so
hooks installed to ~/.codex were never read. installRemote now accepts
an explicit codex home (flat layout), threaded from the relay manager;
the config.toml trust write is deferred while the file doesn't exist
(the launch path seeds it only-if-absent — creating it first would
cancel the seed), and the manager re-runs the byte-equality-idempotent
installers on later ensures (30s throttle) to upsert trust once the
seed lands.

Also: WSL test suites now run on Windows dev hosts (fs-backed suites
skip with rig coverage noted; manager suite uses a fixed POSIX home).

Co-authored-by: Orca <help@stably.ai>

* fix(agent-hooks): renderer ownership gate treats wsl:* connection ids as local (STA-1515)

Round-2 rig finding: with the link fixed, WSL hook envelopes reached
ingestRemote and the durable cache, but useIpcEvents.applyAgentStatus
drops any status whose stamped connectionId differs from the owning
repo's — 'wsl:<distro>' !== null for a local repo, so every WSL-relayed
status died before setAgentStatus and notifications.

wsl:* ids are transport provenance, not ownership: the gate now
normalizes them to local via isWslHookRelayConnectionId (shared
contract, also used by the relay link when stamping), while still
rejecting WSL-stamped events against SSH-owned repos. Provenance stays
stamped — it is what made this drop diagnosable.

Co-authored-by: Orca <help@stably.ai>

* fix(agent-hooks): adversarial-review hardening for the WSL hook relay (STA-1515)

Four independent review lenses over the branch; all confirmed findings
fixed before the next rig round:

Endpoint identity (4/4 reviewers): the guest endpoint dir was keyed by
the EPHEMERAL Windows hook port, so a daemon-surviving agent kept
sourcing the dead port-P1 file after an Orca restart — breaking the
restart-resume acceptance criterion and regressing shipped OMP
recovery. Now keyed by a restart-stable instance key (hash of the
Windows endpoint file path, crossed via ORCA_WSL_HOOK_INSTANCE): the
restarted instance's relay rewrites the SAME file, which is exactly
what re-coordinates survivors.

Restart policy: every failure arms the restart timer (one failed
relaunch no longer ends self-recovery), and the timer probes
wsl --list --running first — wsl -d BOOTS a stopped distro, so
recovery must never resurrect a VM the user shut down; stopped-distro
state is dropped instead. Failure counters reset only after 2min of
stable uptime, so connect-then-die loops escalate to the 10-min cap
instead of cycling every 10s. Timer policy extracted to
wsl-hook-relay-recovery.ts with direct tests.

Also: version-namespaced guest install dir (dev+prod instances no
longer reinstall over each other; PID-suffixed tmp files), 30s install
timeout (a wedged wsl.exe could pin the state machine at 'starting'
forever), per-candidate node version probing (apt node 12 on PATH no
longer masks nvm node 20 into a false no-node cooldown), WSL_UTF8=1 +
NUL-stripped stderr (catastrophic-failure matcher survives UTF-16LE),
ordered post-sentinel chunk handoff, port-fallback breadcrumb via the
home handshake, bad home reply now fails the connect, missing-bundle
warn-once, case-normalized distro keys, disposeAll wired to will-quit,
one-shot 60s reinstall timer for single-spawn Codex trust catch-up,
escaped + contract-derived spawn command.

Co-authored-by: Orca <help@stably.ai>

* docs: record round-3 rig validation status for agent status over WSL (STA-1515)

Co-authored-by: Orca <help@stably.ai>

* fix(agent-hooks): round-4 adversarial-review fixes for the WSL hook relay (STA-1515)

- dropState identity race: recovery re-checks state identity after the
  distro-running probe await, and the manager's dropState only deletes the
  exact state it was armed for — an ensure() landing mid-probe can no longer
  have its fresh relay orphaned outside the map.
- Distro-running probe fails CLOSED: a probe error no longer reports
  'running', so recovery can never wsl-d-boot a distro the user shut down.
- Relay spawns use --exec: bypasses the distro's default login shell
  (fish/nushell chsh) and passes argv verbatim, dropping the $-escape shim;
  same form as the Codex WSL login spawn.
- Post-sentinel chunk handoff rides a microtask so an envelope in the
  trailing bytes can no longer dispatch before the link's notification
  handler is registered.
- Guest relay mirrors the SSH relay's uncaughtException/unhandledRejection
  posture.
- Replay cache capped at 256 panes with recency eviction (the WSL relay has
  no per-pane teardown signal); meta map kept in lockstep.
- Launch script derives the stale-exit code from the shared contract
  constant; one-shot reinstall timer refuses to arm after dispose.
- New oracles: sentinel unit suite, fs-bridge scoping suite, fixed-token
  403/204, EADDRINUSE endpoint-file rewrite, cache-cap eviction, and the
  recovery/manager race regressions (verified to fail with fixes reverted).
- Doc: round-4 review section + revised curl.exe stance (kept as the
  no-node fallback — Codex is a native binary; fresh distros ship no node).

* docs: record round-4 pinned rig validation for agent status over WSL (STA-1515)

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* Fix automatic branch rename for non-English git locales

A gettext-enabled git (Homebrew git, most Linux distro gits) under a
non-English locale translates every diagnostic, including the `fatal:`
prefix, so Orca's stderr phrase parsers stop matching. The first-message
branch auto-rename was the headline casualty: isNoUpstreamError missed
the translated no-upstream error, branchHasUpstream failed closed to
"has upstream", and the rename settled silently and permanently.

- Force LC_ALL=C on all Orca-spawned machine-parsed git: the local
  prompt-guard env chokepoint, the three relay git spawn sites, and both
  local clone spawns (progress + failure-message parsing). User
  terminals are untouched.
- Replace the boolean upstream check with a tri-state probe: rename
  proceeds only on a proven missing upstream; an unreadable probe now
  raises the rename-failed badge and retries instead of settling.

Fixes #7808

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>

* Consolidate untranslated-git-locale into runner and relay primitives

Replace the five per-site LC_ALL=C patches with one shared
UNTRANSLATED_GIT_OUTPUT_ENV (LANGUAGE=en LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8) injected inside the git runner primitives
(promptGuardGitEnv, gitSpawn, gitExecFileSync, gitExecFileAsyncBuffer)
and a relay buildRelayGitEnv() helper, so every current and future
machine-parsed git spawn is covered by construction — including the
fs-handler-git-fallback sites the per-site approach missed. The UTF-8
English locale keeps a UTF-8 LC_CTYPE for hooks git spawns; LANGUAGE is
pinned because gettext consults it before LC_ALL.

WSL-routed git gets the same values as a shell assignment prefix built
in resolveCommand, since spawn env cannot cross the wsl.exe boundary —
closing the WSL gap the first pass accepted.

Also scrub credential-bearing remote URLs from the probe-failed message
surfaced on the worktree card.

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>

* Scrub credential-bearing URLs from clone failure messages

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
* Improve voice dictation reliability

* Move voice-dictation-reliability doc out of tracked tree

Co-authored-by: Orca <help@stably.ai>

* fix: address review findings (stop-flag exception safety, reuse guard, remove dead dictation-hold-release module)

Co-authored-by: Orca <help@stably.ai>

* fix: remove unnecessary max-lines suppression from stt-service test

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: hmrserver <>
Co-authored-by: brennanb2025 <brennankbenson@gmail.com>
…ty rebuilds (#7762)

* fix(build): skip spawn-helper check on Linux to avoid spurious node-pty rebuilds

getPatchedNodePtyRebuildReason() unconditionally checked for
build/Release/spawn-helper, but spawn-helper is a macOS-only node-pty
build target. On Linux, node-gyp never generates it, so missingArtifact
was always non-null, causing unnecessary source rebuilds every time.

Fixes #7760

* test(build): cover platform-specific node-pty artifacts

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
@pull pull Bot locked and limited conversation to collaborators Jul 10, 2026
@pull pull Bot added the ⤵️ pull label Jul 10, 2026
@pull pull Bot merged commit e4c7aab into CrazyForks:main Jul 10, 2026
1 of 5 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants