Commit Graph
4813 Commits
Author SHA1 Message Date
Brennan BensonandBrennan Benson e1de59aaa8 fix(quick-open): keep primary results when the git ignored pass fails (#8049)
The no-ripgrep git fallback ran both ls-files passes under Promise.all
with killSurvivors on first rejection, so any ignored-pass failure
(timeout, kill, non-zero exit) discarded the successful primary listing
and Quick Open showed an error with zero files — the all-or-nothing
failure called out in #7719.

Directory collapse (#7842) bounds the enumeration so timeouts are far
less likely, but a single-pass failure still nuked every result. Now,
in the local main process and the SSH relay alike, only a primary-pass
failure is fatal: an ignored-pass failure logs a warning and the
listing resolves with the primary results plus any ignored entries
streamed before the failure. Cancellation semantics are unchanged —
an aborted scan still rejects via the primary pass or the expansion's
cancellation check.

Fixes #7719

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 17:22:47 -07:00
Brennan BensonandOrca 1ee5babc8c Fix mobile duplicate-PTY-handle crash after agent sleep + wake (#8016)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 17:07:57 -07:00
8976bd969c Fix SSH worktree delete routing after host reconnect (#7997)
* Fix SSH worktree delete routing

* Harden host-scoped worktree deletion

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 16:55:06 -07:00
c633a634ba fix: handle headless file download version skew (#7738)
* fix: handle headless file download version skew

- Issue: remote downloads could open the local save dialog before discovering an older headless server lacks files.readChunk.

- Fix: preflight the first remote chunk before starting the local download transaction.

- Coverage: add regression coverage for method_not_found and preserve cleanup for mid-transfer failures.

* fix: fall back for headless downloads without chunks

- Issue: older headless servers can lack files.readChunk but still expose preview-sized file reads.

- Fix: fall back to files.readPreview and save the file when the preview payload is usable.

- Coverage: verify preview fallback success, unsupported preview update messaging, and modern chunk cleanup.

* fix: reduce remote download support probe

- Issue: the chunk-support probe downloaded a full chunk before the real save flow started.

- Fix: probe chunk support with a one-byte read and keep the actual download starting from offset zero.

- Coverage: add a transport-failure probe test and name the remote download args type.

* fix: preserve empty binary preview downloads

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 16:32:24 -07:00
Neil 402274a35c perf(renderer): scope editor Git subscriptions by worktree (#8107) 2026-07-10 16:26:26 -07:00
Brennan BensonandBrennan Benson fe714211ba Restore original agent working-spinner size in AgentStateDot (#8172)
PR #7423 resized the working spinner ring from the dot size to the
icon size (sm: 6px -> 10px, md: 8px -> 12px) as a side effect of the
AI Vault subagent display work. The size change was unintentional in
the sidebar agent rows, so restore the original dot sizing.

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 15:50:39 -07:00
Brennan BensonandBrennan Benson ce1a9d4cdf Extract web-host agent launch path to fix max-lines lint break on main (#8174)
launch-agent-in-new-tab.ts crossed the 300-line oxlint max-lines limit
(303 counted lines) after #5510 and #7944 both grew it; verify only runs
on PRs, so the over-limit state landed on main via a merge race and now
fails lint for every open PR.

Move the web-runtime host launch branch (stale-local-tab pruning plus
createWebRuntimeSessionTerminal call) into launch-agent-web-host-tab.ts.
No behavior change; the i18n key is kept so locale catalogs are
untouched.

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 15:49:41 -07:00
Brennan BensonandOrca cb92b69746 fix(i18n): unbreak main lint — locale parity for uploadingAttachments (#8056)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 15:47:52 -07:00
Jinjing b9ccc0d17f Flip usage bars from percent-remaining to percent-used (#8167)
Aligns status bar, tooltip, popover mocks, and mobile usage bars with the
Claude/Codex harness convention (consumption meters) so a fresh account
reads empty/green and a depleted one reads full/red, instead of the
inverted "left" framing that misread as "full = exhausted".
2026-07-10 15:39:38 -07:00
OrcaWin b93a7eece1 fix(watcher): preserve isolation in electron-vite builds (#8162) 2026-07-10 15:10:15 -07:00
7d216de486 fix(ports): stop live-port indicator flickering (scan debounce + re-init loop) (#5510)
* fix(ports): stop live-port indicator flickering on transient scan failures

A worktree's plug icon renders only when it has ports. The scanner polls
each execution host every 30s and, on a transient failure (SSH/IPC latency),
substituted an empty "unavailable" scan — dropping that host's ports for the
cycle and blinking the affected row's live-port indicator off, then on again
next poll.

Debounce per-host failures: reuse the host's last good scan until failures
reach a tolerance, so a single dropped poll no longer zeroes the row. A
reachable host reporting no ports has no unavailableReason, so a genuine port
close still clears immediately. Logic extracted to a pure helper with tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ports): stop port scan re-init loop that flickered live-port icons

The scan poll effect depended on the `refresh` callback identity, which gets a
fresh reference whenever repos/settings are replaced (frequent in a busy
workspace). Each change re-ran the effect, which reset the scan to null and
kicked an immediate re-scan — a tight ~600ms loop that blinked the plug icon
off/on even though the scanned ports never changed.

Drive the poll and advertised-url effects off the latest refresh via a ref and
key them on stable value-signatures (enable state, active scan key, host-set
signature, runtime kind) instead of the callback identity. Incidental store
churn no longer re-inits the scanner; it still polls every 30s, reacts to
advertised-url events, and rescans on a real host-set or runtime change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address PR review feedback (#5510)

- Prune the per-host failure counter for failed-only hosts that disappear,
  not just hosts present in lastGood — avoids an unbounded failures map and a
  stale failure streak if the host reappears
- Canonicalize scanTargetsSignature by sorting so a reordered-but-unchanged
  host set does not re-init the scan and reintroduce flicker

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ports): keep host scans targeted and stable

* test(ports): cover scan debounce state

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-10 14:41:09 -07:00
Jinwoo Hong 03a6737089 Fix Windows terminal daemon death after workspace close (#8140) 2026-07-10 13:50:38 -07:00
Jinwoo HongandOrca dc468f0ded Fix Linux Parcel watcher crawl restart loop (#8155)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 13:48:35 -07:00
8f6e44ed53 Show agent session history on mobile (#6786)
* Show agent session history on mobile

Bring the desktop "Agent Session History" panel to Orca Mobile as a
per-worktree screen: browse past agent transcript sessions across the
host with scope tabs (Workspace/Project/All), search, grouping, session
cards, and tap-to-read message previews.

The transcript scan previously ran only over Electron IPC, so mobile
could not reach it. Expose it over the runtime RPC protocol mobile
already speaks (aiVault.listSessions) so the scan runs on whichever host
owns the transcripts — correct for local and SSH/remote hosts. Both the
desktop IPC handler and the new RPC method share one cache, so opening
the desktop panel and the mobile screen never double-scan.

The pure filter/group/display logic is lifted into /shared (the renderer
re-exports it) so the standalone mobile package can reuse it. Mobile
narrows scoped tabs client-side by cwd path-prefix because the host scan
treats scope paths as a widening union.

Resume-from-mobile is intentionally a follow-up.

* Fix mobile agent history list rendering and RPC authorization

- Authorize aiVault.listSessions in the mobile RPC allowlist so the
  mobile client's call is not rejected before dispatch (without this the
  screen could never load sessions at runtime).
- Name each SectionList section's rows `data` (the field React Native
  reads) instead of `cards`, fixing a type error and silent empty-section
  rendering.

* Address review feedback on agent session history

- Match quoted repo:/path: search operator values so labels and paths
  with spaces match (e.g. path:"/Users/ada/My Project").
- Hold a scoped tab in loading until the worktree list resolves instead
  of firing an unscoped fetch that briefly shows unrelated host history;
  proceed once loaded even if the worktree is absent (no stuck spinner).
- Clear cached host capabilities on disconnect/host-switch and failed
  status.get so a capability-gated action can't linger for a host that
  doesn't support it.
- Cover the real OrcaRuntimeService codex-home forwarding path and the
  quoted-operator parser with tests.

* Hide redundant mobile current worktree badges

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

* Resume agent sessions from mobile history (#6969)

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

* Adapt merged seams to main's lint and reply-sender hardening

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

* Cap mobile project-scope paths to the aiVault RPC bound

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

* Share the aiVault scopePaths bound between the RPC schema and mobile

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

* Guard shared AI Vault inflight cleanup against concurrent key replacement

The extracted cache module's .finally() cleared inflight tracking
unconditionally, dropping the if (inflightKey === key) guard its sibling
outer cache kept: an older scan resolving after a different-key scan
replaced the tracking would null the newer scan's dedup slot, so a
re-request started a duplicate transcript rescan. Mirrors the sibling
guard; the regression test flushes a macrotask so a reverted guard fails
fast on the call count instead of hanging.

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

* Harden aiVault.listSessions contract and gate mobile header entry on capability

- Clamp scopePaths (64) instead of rejecting, cap limit at 2000, and make
  executionHostId optional so mobile can omit it; restamp per caller.
- Retain successful mobile terminal-create mutation ids for 60s so resume
  retries dedupe after transient socket drops.
- Gate the session-header Agent History action on the aiVault.v1 capability
  (mirrors the host-list action) so old hosts never show a dead-end entry.
- Fix stale contract comments (scopePaths clamp semantics; filters move
  includes quoted repo:/path: operator parsing).

* Add subagent field to session test fixtures after #7423 merge

AiVaultSession.subagent became required on main; the five fixtures added on
this branch predate it. Top-level scanned sessions carry null.

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 13:48:10 -07:00
Brennan BensonandBrennan Benson da2c692d31 fix(terminal): forward Option hotkeys to kitty-keyboard TUIs on compose layouts (#8031)
* fix(terminal): forward Option hotkeys to kitty-keyboard TUIs on compose layouts

On macOS layouts where Option composes characters (ABC and all non-US, the
effective default), pressing Option+P in a TUI that negotiated the kitty
keyboard protocol made xterm's kitty encoder report the composed codepoint
(alt+pi, CSI 960;3u) instead of the physical key (alt+p, CSI 112;3u). No TUI
binds the composed form, so agent hotkeys like OMP's Alt+P / Alt+M neither
fired nor typed anything.

Fix: mirror each pane's application-negotiated kitty flags with a scan-based
tracker fed only from PTY output (immune to Orca's defensive renderer-side
kitty resets on Ctrl+C interrupts and reattach), and have the terminal
shortcut policy encode Option chords as kitty CSI-u from the physical key
when the pane's app opted in. Dead keys stay exempt so Option composition
still works, and panes without kitty negotiation (shells) are unchanged.
Alt+Arrow / Alt+Backspace now defer to xterm's native kitty encoding in
kitty panes instead of the legacy readline translations.

The daemon's headless emulator tracks the same flags and re-arms them via
the snapshot rehydrate preamble (CSI = flags ; 1 u), so the behavior
survives window reloads and reattaches; PTY exit and cold restore reset the
mirror.

Validated byte-for-byte against a real omp 16.3.15 in a pty: the policy's
emitted CSI-u opens the temporary-model selector (Alt+P) and agent hub
(Alt+A), identical to the legacy ESC-prefixed forms it parses.

* fix(terminal): harden kitty Option-chord mirror for soft resets, replay redelivery, and non-QWERTY layouts

Three review findings on the kitty keyboard mirror, each verified against a
live omp 16.3.15 pty session using the real production modules:

- DECSTR: xterm's soft reset (CSI ! p) clears its kitty flags and stacks for
  both screens without switching buffers; the tracker now mirrors that, so a
  soft-resetting TUI stops receiving kitty-encoded Option chords.

- Replay redelivery: relay reconnects can redeliver the retained replay
  window, and each scan of the app's one-time CSI > u push grew the mirrored
  stack while the renderer's post-replay reset drained xterm's copy. The
  TUI's single exit pop (omp emits a bare CSI < u on quit) then landed on a
  stale frame, leaving Option+B/F/D kitty-encoded in a plain shell. Replay
  paths now scan with scanReplay(), which applies pushes as idempotent sets
  so redelivery cannot grow the stack; the live-output funnel and the
  daemon's once-per-byte emulator keep full stack semantics.

- Layout-correct base keys: kitty CSI-u reports must carry the key's
  unshifted codepoint in the active layout, but the encoder resolved it from
  a US-QWERTY physical-code table — on Dvorak/Colemak/AZERTY-class layouts
  (exactly the population whose effective Option-as-Alt default activates
  this path) the wrong key's chord fired, e.g. Colemak Option+P sent alt+r.
  A new keyboard-layout module caches Chromium's KeyboardLayoutMap (fetched
  at terminal setup and on focus-in, like the option-as-alt probe) and the
  policy resolves through it before the US fallback. Verified live: the
  layout-resolved bytes open omp's model selector; the US-table bytes do not.

* fix(terminal): reset kitty mirror on fresh spawn to cover replaced-PTY late exits

The exit handler resets the per-pane kitty keyboard mirror, but a late exit
from a replaced PTY takes the stale-transport early return and skips it —
so a restart-in-place could leak the old TUI's kitty flags into the fresh
shell, kitty-encoding Option chords the shell cannot parse. A fresh spawn
is by definition a new process with kitty state at zero, so startFreshSpawn
now resets the reused tracker itself, alongside the other per-pane mode
state it already clears. Reattach paths are untouched, so a live TUI's
mirrored flags still survive reconnects.

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 13:45:33 -07:00
Neil d9b1fbbc07 Fix Markdown URL actions behind Explorer (#8137) 2026-07-10 13:34:50 -07:00
BingZandJinwoo Hong 96d1fa1d62 fix(grok): clipboard, native chat, hooks, sessions, ConPTY KKP (#7944)
* fix(grok): restore clipboard and native-chat parity

Grok CLI already supports argv prompts, OSC 52 copy, and image paste chips.
Orca was blocking those paths: stdin-after-start keystroke injection, OSC 52
writes default-off, image-attachment denylist, and native-chat allowlist.

- Launch Grok with positional argv prompts
- Default OSC 52 TUI clipboard writes on (still user-toggleable)
- Treat Grok as image-attachment capable
- Parse ~/.grok/.../chat_history.jsonl for native chat

OSC 52 clipboard *query* remains ignored by design (host clipboard exfil risk);
xAI docs only require OSC 52 write for remote copy.

* fix(grok): sync OSC 52 docs and locale catalog with default-on

Update terminalAllowOsc52Clipboard type docs for the true default, and
refresh locale strings so settings UI mentions Grok alongside other TUIs.

* fix(grok): tool hook matcher, StopFailure, previews, AskUser waiting

Grok tool-event matchers are real regexes; bare `*` failed as match-all.
Install `.*` for Pre/Post tool hooks, add StopFailure for API-error ends,
recognize Grok-native tool input keys, and map ask_user_question PreToolUse
to waiting with interactivePrompt (Kimi-style live card path).

* fix(grok): resolve chat_history under GROK_HOME and long-cwd layouts

Centralize Grok session path helpers so hooks and native-chat honor
GROK_HOME and find chat_history.jsonl by session id when the cwd group
is slug-encoded (encoded name > 255 bytes) instead of only
encodeURIComponent(cwd).

* fix(terminal): keep Kitty keyboard for Grok on Windows ConPTY

Local Windows ConPTY withholds KKP so CSI-u-blind CLIs (e.g. Antigravity)
keep Enter/nav working (#2434). Grok needs KKP for Ctrl+Enter interject and
modified-Enter newline chords; blanking the advertisement for Orca-launched
Grok left those actions broken.

- Prefer KKP when tuiAgent is grok despite ConPTY withhold
- Wire launchAgent from tab/startup into keyboard protocol options

* fix(grok): restore OSC52 default-off, split decoders, honor GROK_HOME hooks

- Keep terminalAllowOsc52Clipboard default false (clipboard exfil risk)
- Split transcript-line-decoders under max-lines without suppressions
- Install local Grok hooks under resolveGrokHomeDir() / GROK_HOME

* refactor(grok): share CLI home resolution

* fix(grok): harden terminal and native chat integration

* test(grok): align CI coverage with native chat support

---------

Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
2026-07-10 13:16:55 -07:00
BingZandBrennan Benson 4209889f60 feat(status-bar): Antigravity usage status (#7996)
* fix(status-bar): keep antigravity usage visible

* feat(rate-limits): add Grok usage status

* feat(grok): add managed usage accounts

* test(rate-limits): isolate Codex PTY fallback fetches

* fix(grok): address CodeRabbit review on usage status PR

- Guard auth.json read/parse so missing files return null
- Thread AbortSignal through Grok rate-limit fetch and ACP auth
- Pass isRemote:false for floating-terminal agent launch env

* fix(grok): wire ACP abort after child listeners to avoid TDZ

* fix(status-bar): address CodeRabbit on combined Grok/Antigravity usage

- Pin WSL shell distro when resolving managed GROK_HOME (parity with Codex)
- Refresh only Grok on account change via fetchGrokOnly
- Consolidate usage status-bar toggle catalogs; add Grok locale keys
- Fix Grok aria-label, feature-interaction tracking, and test fixture

* fix(settings): drop duplicate usage status-bar toggle catalog

Remove the leftover re-export path so Appearance search has a single
source of truth for usage provider toggles (including Antigravity + Grok).

* fix(settings): restore AccountsPane and locale UTF-8 after merge

Re-do AccountsPane three-way merge with binary-safe git objects and keep
both Grok accounts + remote provider client imports. Rebuild locale JSON
merges so em dash/ellipsis/middle-dot strings are no longer mojibake.

* fix(i18n): add missing comma after merged status-bar locale keys

* test: add antigravity to GrokUsagePane rate-limit fixture

RateLimitState gained a required antigravity field; the pane fixture must
carry it to typecheck.

* fix(status-bar): gate Antigravity durable visibility on Gemini OAuth opt-in

The Antigravity snapshot mirrors the Gemini fetch, which is permanently
'unavailable' until the user opts into Gemini CLI OAuth. Without this gate
the default-on checked item plus a detected agy CLI pinned a dead 'A --'
bar (Gemini itself hides in that state) and suppressed the usage setup CTA
for users who configured nothing.

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 13:11:24 -07:00
143c36e566 feat(jira): group Jira issues by status (#7958)
* fix(jira): group Jira issues by status in task page

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* feat(jira): order grouped statuses by agile board columns configuration

* test(jira): add comprehensive tests for Jira issue grouping functionality

Add test coverage for the new Jira issue grouping features including:
- Grouping issues by status name
- Sorting sections by agile board column configuration
- Falling back to alphabetical sorting when no board config exists
- Collapsed groups state management
- Filtering issues based on collapsed state
- Backend tests for getProjectStatuses API with various scenarios

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(jira): add backend tests for getProjectStatuses and RPC routing

Add test coverage for the new getProjectStatuses backend functionality:
- Returns empty array when no clients are available
- Returns statuses from project statuses API when no board configuration exists
- Orders statuses by agile board column configuration when available
- Handles missing status IDs gracefully by falling back to unordered list
- Clears token on auth errors
- Returns empty array on operational errors
- RPC routing for jira.getProjectStatuses method

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(jira): harden status grouping

---------

Co-authored-by: Andres Van Reepingen <andres.vanreepingen@datacamp.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-10 12:57:09 -07:00
Jinwoo HongandOrca c9919e57b3 fix(remote): harden terminal, relay, and SSH reliability (#8141)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 12:56:17 -07:00
Jinwoo Hong 629b57549f STA-1598: Prevent duplicate TOML project keys from breaking Codex startup (#8138) 2026-07-10 15:32:06 -04:00
Brennan Benson 2f62292944 fix(terminal): reset PTY delivery accounting across renderer lifecycle resets (permanent frozen panes) (#8034)
* fix(terminal): reset PTY delivery accounting across renderer lifecycle resets (frozen panes)

Panes froze permanently because main's PTY->renderer flow control leaked
its unacked in-flight byte counters and pending backlog across renderer
reloads/crashes: the lifecycle reset cleared only visibility hints, daemon
PTYs outlive the page, and the new page never acks the dead page's bytes,
so any pty with >=512KB unacked at reload time was delivery-gated forever
(proven by dev repro: counter pinned at exactly 524288; one manual ackData
of the leaked bytes instantly unfroze the pane).

Fix: (1) zero in-flight counters + pending backlog on every main-frame
renderer lifecycle reset (panes rebuild losslessly from main's
authoritative snapshot on reattach); (2) hold PTY sends until the new
page's pty:data listener signals ready (pty:rendererDispatcherReady), so
boot-window output accrues in the capped backlog instead of being
counted-but-dropped; (3) 10s self-heal watchdog + reconcile-on-handshake
backstop so a missed reset (subframe-overlapped reload emits no
did-start-loading) or lost handshake can never itself freeze delivery;
(4) derive the active-renderer-pty report reactively so in-place rebinds
keep the interactive reserve; (5) expose reset/gate state in the delivery
debug snapshot for future diagnosis.

Adds an experimental reliability gate
(pty-delivery.renderer-lifecycle-accounting-reset) with red/green-proven
regression tests for each branch of the fix.

* chore(reliability-gates): link PR #8034 as the gate's motivating fix

* fix(terminal): sender-guard the dispatcher-ready handshake; fix WSL gate wording

CodeRabbit: the reconcile backstop destructively clears delivery
accounting, so a straggler pty:rendererDispatcherReady from a dying
window's webContents must not reset the new window — reuse the pty:write
main-window sender check (+ regression test). Also resolve the
contradictory WSL coverage claim in the reliability gate notes (WSL rides
the same local/daemon pipeline; mobile/relay and SSH are separate paths).
2026-07-10 12:12:51 -07:00
1afec6cbf9 fix(browser): allow trusted embedded popup windows (#7392)
* fix(browser): allow trusted embedded popup windows

* fix(browser): harden embedded popup windows

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 11:52:48 -07:00
970d446d50 fix(browser): auto-grant pointerLock permission (#7697)
* fix(browser): auto-grant pointerLock permission

Orca's browser deny-by-defaults Chromium permission requests unless the
permission is in AUTO_GRANTED_BROWSER_PERMISSIONS. pointerLock is not in
that set, so immersive web apps (3D editors, FPS-style games) that call
requestPointerLock() get a confusing toast:

  "<url> asked for pointer lock, and Orca denied it."

with no in-app toggle to allow it.

Add 'pointerLock' to the auto-grant set. This mirrors the resolution of
the identical persistent-storage denial in #4801 / #4849. Chromium still
requires a user gesture before requestPointerLock() can engage, so this
only lifts Orca's application-level gate — it does not bypass the spec's
user-activation requirement.

* test(browser): cover pointer lock permission paths

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 09:42:10 -07:00
Jinwoo HongandOrca fa4e081362 Fix hard-wrapped terminal file links (#8100)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 08:26:06 -07:00
Neil 0f0e32952e Fix layout-aware find in the source editor (#8088)
* fix(editor): make find shortcut layout-aware

* fix(editor): cover layout-aware find surfaces
2026-07-10 03:56:55 -07:00
c5669cceb5 fix(quick-open): prune generated dirs in git fallback (#7842)
* fix(quick-open): prune generated dirs in git fallback

* fix(source-control): narrow manual review provider switch

* fix(quick-open): collapse git fallback directories

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

* fix(quick-open): harden collapsed git directory expansion

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

* fix(quick-open): close directory expansion races

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

* perf(quick-open): collapse placeholders efficiently

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

* fix(quick-open): preserve root and cancellation semantics

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 03:06:44 -07:00
mehmet turacandOrca 506f6ffbb9 Fix remote host branch diff routing (#6747)
* fix(editor): route remote diff reads through ssh

* Address folder workspace diff routing review

* test(editor): regression-lock combined diff section SSH routing

Extract getCombinedDiffSectionConnectionId so the per-section diff-read
host resolution (joinPath + getConnectionIdForFile) is unit-covered,
including the Windows separator composition for mixed folder workspaces (#6688).

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 03:02:34 -07:00
Jinjing 70ff47ea90 Revert centered sidebar jump behavior (#8019)
Reverts #8019 to restore the sidebar reveal behavior from before the jumpiness regression.
2026-07-10 03:00:51 -07:00
Jinjing db9bae81bd Revert sidebar virtualization boundary changes (#8036)
Reverts #8036 to remove the sidebar jumpiness regression.
2026-07-10 03:00:21 -07:00
Neil 8c50aaddf6 Keep speech model dropdown open during downloads (#8087) 2026-07-10 02:47:23 -07:00
Neil 26224196f5 perf(worktrees): avoid auto-maintenance in create fetches (#8039)
* perf(worktrees): avoid auto-maintenance in create fetches

Git's opportunistic maintenance can keep an already-complete exact-base fetch open for seconds. Disable it per command for create-base refreshes only, leaving ordinary fetch maintenance and exact-ref freshness unchanged.

* docs(worktrees): explain create fetch maintenance scope

* test(worktrees): account for fetch config prefixes

* fix(worktrees): cover Git 2.29 auto maintenance
2026-07-10 02:31:47 -07:00
Neil e4c7aab4a2 Normalize invalid terminal line height before xterm (#8050) 2026-07-10 01:28:22 -07:00
67447fe64f Add AI Vault subagent display (#7423)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: hmrserver <>
Co-authored-by: brennanb2025 <brennankbenson@gmail.com>
2026-07-10 01:13:16 -07:00
JinjingandOrca f5ba5162e4 Improve voice dictation reliability (#3922)
* 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>
2026-07-10 01:07:18 -07:00
b7e84aea3c Fix automatic branch rename for non-English git locales (#8012)
* 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>
2026-07-10 01:03:16 -07:00
f238952be2 Agent status over WSL: guest-resident hook relay + WSL-side hook installers (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>
2026-07-10 00:19:45 -07:00
Jinjing 1383ba85cf Virtualize workspace cleanup candidate rows for large lists (#8044)
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.
2026-07-10 00:18:07 -07:00
Jinjing bcd16e56fd Skip reparsing zero-owner backup databases on live db change (#8043)
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.
2026-07-10 00:14:01 -07:00
Jinjing e75343b1c5 Fix task ID parsing for normalized single-line dispatch prompts (#8041)
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.
2026-07-10 00:13:53 -07:00
Jinjing 445eaaf2bd Make WSL Codex path canonicalization async to avoid blocking main proces (#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
2026-07-10 00:13:08 -07:00
Doan Bac TamandBrennan Benson fa2b228ad3 feat(rate-limits): Grok CLI OAuth weekly credit usage (#7869)
* 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>
2026-07-10 00:11:27 -07:00
Jinjing 770a9d5dc3 Improve translation quality across es/ja/ko/zh locale files (#8040)
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.
2026-07-10 00:10:56 -07:00
Jinjing 830024dc2e Remove temporary scroll-padding centering for boundary sidebar rows (#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.
2026-07-09 23:52:36 -07:00
Jinjing 5d5e2c4b95 Add updater diagnostics and refine daemon teardown policy on quit (#7544)
* 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.
2026-07-09 23:00:01 -07:00
Jinjing 1392981cd7 Show dispatch task preview and refresh worker tab titles (#8024)
* 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.
2026-07-09 22:45:05 -07:00
Jinjing bab126fb2c fix: close terminal tabs when killing all sessions (#8027)
Implement the surface cleanup described in docs/kill-all-sessions-also-kills-empty-terminals.md.

Fixes #8001.
2026-07-09 22:44:12 -07:00
Jinjing 620b475acd Bug wsl terminal zsh shell ready wrapper exports (#8025)
* 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.
2026-07-09 22:41:58 -07:00
JinjingandOrca 4908a03671 fix: dedupe fork-copied usage history across Claude, Codex, and OpenCode 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>
2026-07-09 22:36:53 -07:00
JinjingandOrca f495b39a6a Fix untracked line-stat cache thrash and add source-control scale benchmark (#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>
2026-07-09 22:33:55 -07:00