Commit Graph
11906 Commits
Author SHA1 Message Date
NeilandClaude 5da18e154f fix: preserve newer hosted review lookup ownership (#23126)
* fix: preserve newer hosted review lookup ownership

* refactor: reuse the shared lookup generation sequence

Drops this coordinator's private counter for the identical allocator added on
the pull-request branch, so the "never reuse a generation id" invariant lives in
one place. The file is byte-identical on both branches, so either may merge
first.

* docs(store): describe the lookup generation sequence by its contract, not its callers

The JSDoc claimed the sequence was "shared by the pull-request and hosted-review
request coordinators", but the pull-request call site arrives in a sibling
change, so on this branch alone the comment named a caller that does not exist.

Describe what the module provides instead: one process-lifetime monotonic
allocator for lookup-ownership stamps, safe to share across every cache because
callers compare stamps for equality only, never order or magnitude. That stays
accurate whether one coordinator draws from it or several, so it needs no edit
when the second call site lands.

Applied identically on the sibling branch so the file stays byte-identical and
the two add/add introductions keep merging without conflict.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 23:37:45 -07:00
NeilandClaude 6ccfc1246c fix: preserve newer pull request lookup ownership (#23119)
* fix: preserve newer pull request lookup ownership

* refactor: share one lookup generation sequence between review coordinators

The sibling hosted-review fix needs the same never-reused generation id, so
move the allocator into src/renderer/src/store/lookup-generation-sequence.ts
instead of keeping a second private counter per coordinator.

Also assert in the lifetime test that a stale lookup cannot publish into
prCache and that the live lookup's answer is what lands there.

* docs(store): describe the lookup generation sequence by its contract, not its callers

The JSDoc claimed the sequence was "shared by the pull-request and hosted-review
request coordinators", but the hosted-review call site arrives in a sibling
change, so on this branch alone the comment named a caller that does not exist.

Describe what the module provides instead: one process-lifetime monotonic
allocator for lookup-ownership stamps, safe to share across every cache because
callers compare stamps for equality only, never order or magnitude. That stays
accurate whether one coordinator draws from it or several, so it needs no edit
when the second call site lands.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 23:37:28 -07:00
Neil 172083f304 fix: remove PDF export temp files after setup failures (#23130)
* fix: remove PDF export temp files after setup failures

* fix(export): keep PDF temp cleanup to files this export created, and time out a hung load

Two holes in the temp-document cleanup:

- The write was not an exclusive create, so anything already sitting at the
  generated temp path (a symlink planted in the shared temp dir) would be
  written through, and the cleanup would then unlink an entry this export did
  not create. The write now uses `flag: 'wx'`, and the one failure that means
  "this path is not ours" (EEXIST) skips cleanup entirely.
- The 60s timeout only covered render-and-print, started after the load had
  already finished. An export document whose script never yields fires neither
  `did-finish-load` nor `did-fail-load`, so the load await hung forever and the
  hidden window plus its temp file leaked for the life of the app. The timer now
  starts before `loadFile` and races the whole load-render-print sequence.

Tests cover the preserved foreign file, a never-settling load, a load that
resolves without either event, `did-fail-load`, and that one export's cleanup
cannot touch a concurrent export's in-flight temp file.
2026-09-26 23:19:45 -07:00
OrcaWinandm4air ccd1e87287 Overlap independent CI checks with native Actions background steps (#23351)
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 23:09:40 -07:00
Neil 7ac9c8d675 perf: skip macOS DNS probes for unrelated errors (#23121)
* perf: skip macOS DNS probes for unrelated errors

* review(dns-probe-admission): single-source the probe gate and widen resolution-failure coverage

The admission guard duplicated the hint predicate at a second call site, so a gate
that drifted stricter than the hint test would silently drop the DNS diagnostic for
a real lookup failure. Route both through isMacTailscaleDnsHintCandidate, evaluated
once per call, and add a parity test asserting admission never changes the message
the ungated hint decision produces.

Also: widen the predicate to the resolution-failure wordings it missed (EAI_NONAME /
EAI_FAIL / ENODATA / getaddrinfo / "could not resolve" / "name or service not known" /
ERR_NAME_RESOLUTION_FAILED), gate the probe on process.platform === 'darwin' explicitly
rather than relying on the reader's internal check, make the hint idempotent so a
re-wrapped hinted message neither duplicates copy nor re-probes, and rewrite the
cache-window test to assert the resolver state the next relevant error reports instead
of pinning an exact probe count.
2026-09-26 23:07:24 -07:00
Neil 7505e55447 perf: share pending plugin translation startup requests (#23133)
* perf: share pending plugin translation startup requests

* fix(plugins): retry a wedged language-pack startup request instead of joining it

Sharing the pending startup request removed the duplicate IPC call, but the
suppression was permanent: plugins:listLanguagePacks awaits plugin discovery,
so a request that never settles left ensurePluginLanguagePacksLoaded a no-op
for the session. Every later consumer joined a request that would never
finish, where before each one retried — loaded stayed false, pinning the UI on
built-in translations and suppressing the TCC notices that gate on it.

Bound the join to a window instead of a boolean: a request that is merely slow
is still shared, one past the window is treated as wedged and a later consumer
starts its own. Adds the stalled-request test the change was missing.
2026-09-26 23:07:10 -07:00
Neil dc8f623a3a fix: retire stale review lookups after cache invalidation (#23182)
* fix: retire stale review lookups after cache invalidation

* test: pin the fence a retired review lookup answer has to clear

The extraction widened canAdoptDetachedAnswer: a retired owner is no longer in
the in-flight index, so with no replacement reader the scope generation is the
only thing stopping its pre-invalidation "no review" from being adopted as
current — which would short-circuit the lookup for the review Orca just opened.
Cover that interleaving, and restore the invariant comments the extraction
dropped (token identity, expire idempotency, and that a size-cap eviction
forfeits the wall-clock sweep).
2026-09-26 23:06:57 -07:00
Jinjing f5f537ef14 Revert "Support mouse Back/Forward buttons in shortcuts (#23287)" (#23350)
This reverts commit a86fae0889.
2026-09-26 22:58:01 -07:00
NeilandHarshul Rathod bdb897b735 Respect disabled OpenCode variants and refresh WSL settings safely (#23328)
Respect disabled OpenCode variants, preserve explicit config ownership, and refresh WSL guest settings safely across reconnects.

Based on Harshul Rathod proposal #22805.

Co-authored-by: Harshul Rathod <harshulrathod1640@gmail.com>
2026-09-26 22:48:35 -07:00
OrcaWinandm4air 9f5a8a5b8a Reuse mobile recording compilation and refresh desktop CI timings (#23343)
* ci: reuse recording compilation, split families, and refresh shard timings

* Keep recording suite intact after hosted performance comparison

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 22:44:15 -07:00
459410a63b Preserve Hermes YAML configuration during hook installation (#23324)
Preserve supported Hermes YAML values and comments while installing or removing Orca hooks.

Adapted from manthis and Pr1p proposals #22366 and #20632.

Co-authored-by: Maxime AUBURTIN <m@hellomax.io>
Co-authored-by: Chen <zwq19980411@gmail.com>
2026-09-26 22:13:24 -07:00
NeilandKelvin Amoaba 41607a9ddc fix(sidebar): preserve list focus when selecting workspaces (#23320)
Keep keyboard focus in the workspace list during selection changes, and transfer it to the selected terminal on Enter only when focus actually moves.

Based on Kelvin Amoaba proposal #22911.

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-09-26 22:01:24 -07:00
7438bc80f5 fix(orchestration): deliver dispatch mail and replies to the current lead (#23325)
Deliver Dispatch mail and ordinary replies to the current lead Run, preserving original delivery receipts and pre-bind mail draining.

Based on Seongho Bae proposals #22977 and #22979.

Co-authored-by: Seongho Bae <seonghobae@me.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 21:59:39 -07:00
Neil fddf8c8331 feat(editor): highlight Typst files and diffs (#23323)
Highlight Typst files and diffs through the existing lazy TextMate provider.

Based on contributor proposal #22884.
Co-authored-by: Quan Nguyen <qnguyen.dev2@gmail.com>
2026-09-26 21:58:14 -07:00
Neil f41cecc712 fix(search): keep commas inside grouped file filters (#23319)
Keep grouped commas intact when building search filters for ripgrep and Git.

Based on contributor proposal #22915.
Co-authored-by: KAPUIST <thsxornjs12@gmail.com>
2026-09-26 21:58:10 -07:00
Neilanddrakeo338 c3c53f1d24 fix(sidebar): show unread emphasis in compact agent rows (#23327)
Show unread emphasis in compact workspace rows using the existing pane acknowledgment state.

Based on drakeo338’s bounded PR #22870. pinhaum reported #22857 and proposed the broader #22899 variant; the local candidate preserves the existing acknowledgement policy.

Co-authored-by: drakeo338 <paranoyouz@gmail.com>
2026-09-26 21:47:26 -07:00
1c982ff2d9 fix(packaging): exclude root notes from app files (#23326)
Exclude root notes files from packaging while retaining nested runtime notes assets.

Co-authored-by: lurunzi <lurunzi@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
2026-09-26 21:45:35 -07:00
NeilandYi-111-a fa3642256f fix(terminal): retain Japanese middle dots and tildes in file links (#23322)
Retain Japanese middle dots and tildes in rooted and explicitly relative terminal file paths; preserve existing path routing and suffix handling.

Co-authored-by: Yi-111-a <47240345+Yi-111-a@users.noreply.github.com>
2026-09-26 21:45:32 -07:00
23e5e77637 fix(grok): show zero usage for an explicit zero quota (#23321)
Infer zero weekly Grok usage for a confirmed explicit zero quota while retaining unreported and monthly precedence safeguards.

Adapted from huiq777’s PR #22303 and the payload analysis from deminit02-hue in issue #20657. The accepted exception is limited to explicit zero cap.

Co-authored-by: Hui <a3239737781@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-26 21:45:28 -07:00
NeilandKAPUIST 2ce47d9bc2 fix(browser): accept dotted hostnames with explicit ports (#23318)
Allow dotted browser domains with explicit numeric ports through the existing URL normalizer.

Co-authored-by: KAPUIST <thsxornjs12@gmail.com>
2026-09-26 21:45:25 -07:00
OrcaWinandm4air b5dec85a4e ci: reuse mobile web route analysis and skip unrelated mobile tests (#23329)
* ci: share mobile route analysis and scope mobile test runs

* ci: cover mobile web runner process dependencies

* test: verify mobile web selectors through the new runner

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 21:37:40 -07:00
Neil 1526d416e2 fix(terminal): recognize a Git Bash launcher by its install layout (#23308)
* fix(terminal): recognize a Git Bash launcher by its install layout

* fix(terminal): require git-bash.exe in the launcher install-layout check

* test(terminal): pin each Git Bash launcher install-layout marker as necessary
2026-09-26 21:35:09 -07:00
NeilandClaude 1f00eaeefd perf(history): coalesce tombstone directory rescans (#23031)
* perf(history): coalesce tombstone directory rescans

* perf(history): reuse one tombstone listing instead of re-reading per completion

Refilling the 64-slot tombstone removal window used to list the whole
`.pending-delete` directory again, synchronously, after every removal that
finished. A backlog of 1,024 tombstones cost 1,026 listings of a directory
that starts 1,024 entries long, all on the main process thread.

Each history root now keeps the names from its last listing and takes the
next one from memory when a slot frees, listing the directory again only
once that list runs out. The listing moved to `fs.promises.readdir`, so it
no longer blocks the main thread.

This replaces the previous coalescing-on-setImmediate approach, which left
the directory being re-listed once per completion batch and needed a
deferred-roots set, an event-loop turn of latency, and an unref'd immediate
whose freed slots could go unfilled at exit. Holding the names removes all
three.

Two behaviours are kept deliberately:

- Freed slots are offered across roots, so a root displaced at the shared
  cap is not stranded until the next startup.
- A listing cannot re-submit a removal that was already under way when it
  started, including one that finished before the listing resolved.

Five real-filesystem samples per version, 1,024 tombstone directories each
holding a meta.json, macOS arm64 / Node 24. Medians: directory listings
1,026 to 6, names enumerated 494,348 to 1,077, blocking main-thread time in
this path 820 to 7 ms, total drain 886 to 75 ms. The 886 ms breaks down as
266 ms of `readdirSync`, ~554 ms of per-entry work over those 494k names
and its garbage, and ~70 ms of actual recursive rm, which is the unchanged
floor the remaining 75 ms consists of. Average concurrent removals return
to 62 of 64 from the 46 a deferred refill left idle.

Adds coverage for a listing that fails mid-drain with later completions
still able to recover, and for both roots draining under one shared cap.
The heavy drain tests now run on real timers so real `fs.promises` and
microtask ordering are exercised.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(history): warn when a tombstone root read fails for a reason other than absence

readTombstoneNames swallowed every readdir error, so EACCES or ENOTDIR on the
initial enumeration left tombstones in place with no diagnostic until a later
completion happened to re-read. An absent root stays silent; it is the norm.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 21:22:47 -07:00
NeilandClaude 21170c6e22 perf: avoid repeatedly encoding retained VM recipe output (#23048)
* perf: avoid repeatedly encoding retained VM recipe output

* perf: capture retained VM recipe output as raw bytes in the shared byte buffer

The previous commit added a third byte-retention buffer to the repo. This
replaces it with the one that already existed and removes the remaining
encoding work.

`runRecipeCommand` no longer calls `setEncoding('utf8')` on the child's stdout
and stderr. It keeps the raw `Buffer` chunks and runs one `StringDecoder` per
stream to feed the existing string callbacks, which is exactly how
`setEncoding` is implemented, so callbacks see the same characters at the same
boundaries. With the bytes already in hand the capture encodes nothing: the
4,194,304 bytes the ring still encoded for 4 MiB of output drop to 0, and the
UTF-8 continuation trim collapses from one scan per chunk to a single scan when
the tail is decoded.

Retention is now `GrowingByteBuffer.appendRetainedSuffix`, which had no
production consumer. It gained an O(1) head offset, so `discardPrefix` and
`retainSuffix` mark bytes dead instead of moving the whole tail and `append`
slides or grows only when the head offset runs out of room. Quick Open path
accumulation and the SOCKS handshake buffer get that win too. Without the
offset the per-chunk memmove costs 12.36 ms for 4 MiB; with it, 0.25 ms against
the ring's 0.53 ms and the old per-chunk re-encode's 265.78 ms.

Two behaviour notes. Odd capture limits are clamped once at entry instead of
carrying a per-chunk coercion path no production caller could reach, so an
infinite or NaN cap is now bounded at 1 MiB rather than retaining everything.
And malformed UTF-8 yields a different tail: replacement characters no longer
inflate the byte count, so a malformed tail keeps more of what the recipe
actually wrote.

The encoding-budget assertions no longer spy on `Buffer` itself, where any
unrelated allocation in the same tick could flip them. They count bytes through
the capture's own buffer class and still assert the deterministic oracle: at
most 5 MiB moved for 4 MiB of output, exactly 4 MiB appended, 1 MiB decoded,
and the stored chunks identical to the Buffers the stream delivered.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(vm-recipe): emit Buffers from the doctor stream doubles

Dropping setEncoding('utf8') means stdout and stderr now deliver Buffers, so
the hand-rolled EventEmitter doubles emitting strings threw inside the data
listener — the capture retained nothing and the exit path never settled.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 21:22:13 -07:00
Neil 080c4ad62a fix(ssh): name the missing unzip when Bun archive extraction cannot start (#23298)
* fix(ssh): name the missing unzip when Bun archive extraction cannot start

Extracting the downloaded Bun runtime shells out to `unzip` on POSIX hosts,
which a minimal Debian/Ubuntu install does not ship. runProcess rejects a
missing program with a bare `spawn unzip ENOENT`, which the caller's
non-zero-exit branch never sees, so the operator got an errno instead of a
remedy. Translate that one errno into a message naming the tool and the
ORCA_UNZIP_BIN override.

* fix(ssh): reuse the canonical absence predicate for extractor launch failures

isDefinitiveAbsence is the repo's single errno allowlist for "definitively not
there", and it also covers ENOTDIR — which spawn throws synchronously when a
configured ORCA_UNZIP_BIN has a regular file for a parent. That case previously
escaped as a bare `spawn ENOTDIR` naming no path at all.

Also correct the comment: a deleted working directory is not a second source of
these errnos, because runProcess leaves cwd unset and the child inherits the
parent's without resolving it. Verified on macOS, Linux and Windows.
2026-09-26 21:07:59 -07:00
NeilandClaude 1d2c0e5879 perf(mobile): coalesce stalled connection log persistence (#22973)
* perf(mobile): coalesce stalled connection log persistence

* fix(mobile): bound connection-log writes and flush the log before the app suspends

The coalescing pass counted a pending persistence attempt per append and then
burned that whole budget on unblock. With failing storage, 500 appends during a
stall released ~1000 back-to-back `setItem` calls — and slow storage and failing
storage are the same device condition, so the amplification fired in exactly the
scenario the coalescing was for.

The counter is gone. A single `dirtyHosts` flag replaces it: the host's revision
always holds the newest entries, so counting appends bought nothing but writes.
The loop re-reads the revision after each save, so a stall costs the in-flight
snapshot plus one attempt at the newest one, whatever the append count. That also
retires the compound `finally` condition and its unreachable `(… ?? 1) - 1`.

A failed snapshot no longer gets an immediate second `setItem` against a store
that just rejected. It gets one retry after 200 ms, and none at all once a newer
snapshot is queued, because that snapshot already carries the same entries.

`flush()` closes a data-loss gap that predates the coalescing: a write that
failed was only retried by the next append, so when the disconnect was the last
thing to happen the entries explaining it never reached storage. It drains the
in-flight save and makes one more attempt at the newest snapshot, wired to
AppState `background` the way `subscribeConnectionRevivalTriggers` wires resume.

Two revisions tests asserted the retry budget as intended behaviour (6 writes
for 3 appends; 3 for one failure) and now assert one write per snapshot
generation instead. `connection-log-buffer.test.ts` is untouched, including its
requirement that one transient failure self-heals without another append — that
is what the single delayed retry keeps.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(mobile): type the background-flush test mock so the tests ratchet passes

The new test copied `ReturnType<typeof vi.fn>` from
connection-revival-triggers.test.ts, which is grandfathered in the
tests-typecheck baseline for that exact TS2345. The ratchet only shrinks,
so type the mock instead of adding a baseline entry.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 20:59:10 -07:00
Neil 067844b646 fix(design-system): replace hand-rolled diff draft-card shadow with shadow-xs (#23307)
The inline AI-note draft card in the diff view used a fourth, hand-rolled
box-shadow tier with raw rgba values instead of the documented shadow-xs
token, so it didn't track theme/token updates like the rest of the UI.
Restated the value under `.dark` too, since it shares selector specificity
with `.orca-diff-comment-popover`'s dark shadow later in the file and would
otherwise lose the cascade to that unrelated rule.
2026-09-26 20:56:41 -07:00
Neil 98cfdc809f fix(kimi): don't crash if config.toml is deleted mid-write (#23293)
* fix(kimi): don't crash if config.toml is deleted mid-write

writeConfigToml checked existsSync(configPath) then called statSync(configPath)
to preserve the file's mode, with no error handling in between. If the file
was deleted in that window (e.g. a concurrent uninstall), statSync threw
ENOENT and the exception escaped install()/getStatus() uncaught.

Now a missing-file stat during that race is treated the same as a missing
file at the check: fall back to the default 0o600 mode and continue the
write. Any other stat error still throws, preserving the existing
mode-read-failure behavior.

* fix(kimi): use isDefinitiveAbsence for the config delete-race check

Reuse the repo's canonical absence check instead of a hand-rolled ENOENT
comparison, per review feedback on #23293. isDefinitiveAbsence also covers
ENOTDIR (an ancestor directory replaced by a file), which the inline check
missed but is equally "the config is definitively not there."
2026-09-26 20:56:37 -07:00
NeilandClaude fed613bab7 perf: avoid rescanning partial notebook output frames (#23138)
* perf: avoid rescanning partial notebook output frames

* perf(notebook): stream bridge frames and skip the unused size accounting

The reader buffered every record of a chunk before delivering the first one, and
asked the framer for byte accounting it can never use. An unbounded line limit
cannot reject, so the per-segment `Buffer.byteLength` and the rejection-prefix
retention were pure overhead for the notebook and Codex readers; both are now
skipped once, behind a hoisted check. Frames are handed to the consumer as each
line completes, so the first output of a chunk paints without waiting for the
last.

The dropped buffer only ever preserved a trailing partial record across a
consumer throw, which cannot help: that throw leaves the stdout 'data' listener
and takes main down with it. Rejections are no longer discarded either — the
bridge keeps fd 1 to itself, so an unreadable line means the frame channel is
damaged and now says so.

Tests move into notebook-kernel.test.ts beside the reader's existing coverage,
and add the never-terminated record and a guard that no record bytes are
measured when no limit applies.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 20:48:19 -07:00
OrcaWinandm4air 1882458f44 ci: scope orcad smoke and parallelize Linux packages (#23314)
* ci: scope orcad smoke and parallelize Linux package formats

* ci: validate packaging when its copy dependency changes

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 20:44:15 -07:00
Neil a2325bbb9b fix(worktrees): clear orphan cleanup on BusyBox WSL distros (#23296)
The WSL "is this path gone?" probe decided a path was missing by matching
GNU coreutils' exact wording, `stat: cannot statx ...`. BusyBox writes
`stat: can't stat ...`, so on an Alpine-style distro a successful orphaned
worktree delete was still reported as a permanent failure, on every retry.

Match only the trailing strerror text, which is POSIX and already pinned to
English by the probe's LC_ALL=C. Permission failures still report failure.
2026-09-26 20:43:45 -07:00
NeilandClaude da95225ba7 perf(push): keep retention sweeps from overlapping without slowing the drain (#23001)
* perf(push): keep retention sweeps from overlapping

* perf(push): drain a saturated retention sweep instead of idling out the tick

The overlap guard on the shared prune timer removed a side effect the sweeper had
been relying on: overlap was the only thing that let a backlog exceed the
50-batch-per-call cap inside one 60-second tick. With the guard, a sweep that
spent its whole budget went idle for the rest of the interval, so a large backlog
drained far slower exactly when retention matters most.

The timer is now a chained setTimeout rather than an interval. `deleteInBatches`
reports whether it exhausted its batch budget, `prune()` returns
`{ deleted, saturated }`, and a saturated sweep is rescheduled immediately. The
connection gate hands a freed slot to the longest waiter, so one serial sweeper
looping back to back still parks a single statement ahead of a worker claim: claim
latency keeps the value the guard bought while the maximum drain rate returns to
what it was before. The loop is self-limiting and stops once the backlog clears.

A sweep that has not settled a full interval after it started now logs
`orca_push_prune_overdue` with its target. Admission waits have no timeout, so a
lost slot release could previously wedge retention permanently and silently.

Chaining makes the overlap guard structural, so there is no flag to scope. The two
single-DELETE sweeps state through `unbatchedSweep` that they have no batch budget
to exhaust, which keeps the immediate-resume path readable as delivery-only.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 20:39:57 -07:00
NeilandClaude 375c0279c5 perf: bound wildcard segment work in nested repository scans (#23149)
* perf: bound wildcard segment work in nested repository scans

* perf: bound the ** path walk in nested repository scans, not just one segment

The wildcard-segment fix left the larger blowup in place. A short .gitignore line
made only of `**` segments still costs exponential work in the outer path walk:
`**/**/.../z` at 24 segments and 73 characters, against an eight-segment
candidate, takes about 49 million recursive calls and ~150 ms here — larger than
the 25 ms single-segment case this branch removes. Rules are inherited down the
tree and re-checked for every directory, so that price is per directory, the
runtime's 15s scan timeout fires, and the user silently gets a short repo list.

Two independent bounds, both kept:

- `**` spans zero or more segments, so `**/**` accepts exactly what `**` accepts.
  Parsing now collapses a run of them to one segment, taking the reported shape
  from 49M recursive calls to 26 matcher steps.
- The walk memoizes on (pattern index, candidate index), so no other arrangement
  of `**` can reintroduce the blowup. A rule holding at most one `**` is already
  linear and skips the table, because allocating it costs more than the walk it
  would save on the shapes real ignore files contain.

The budget suite's process-CPU ceiling is replaced by a matcher step counter read
through `readNestedRepoGlobMatchSteps`, so an algorithmic regression fails the
suite rather than passing on a fast machine. Each bound has its own budget case,
and each fails when only the other is applied.

The equivalence oracle now also covers multi-segment and anchored patterns
including `**`, checked against the pre-change per-segment expression walking
uncollapsed segments. Code-unit and metacharacter cases are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 20:39:42 -07:00
OrcaWinandm4air 3eb1adec20 ci: reuse fixture setup and scope localization extraction (#23291)
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 18:46:26 -07:00
OrcaWinandm4air 46907de602 fix(ssh): recover abandoned caches without deleting live dependencies (#23281)
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 18:17:34 -07:00
Neil 5b11834d68 fix(editor): preserve Markdown source across rich edits (#23280)
* fix(editor): preserve Markdown source across rich edits

* perf(editor): remove repeated Markdown suffix scans and block reparses

* fix(markdown): retain case-insensitive editable details parsing
2026-09-26 18:10:21 -07:00
github-actions[bot] cdff2a624e Update README downloads badge 2026-09-27 01:08:35 +00:00
OrcaWinandm4air 6433c3c7a3 fix(ssh): preserve interrupted installation outcomes through retries (#23273)
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 18:03:55 -07:00
Neil a86fae0889 Support mouse Back/Forward buttons in shortcuts (#23287)
* feat: support mouse Back and Forward shortcut bindings

* fix: ignore duplicate mouse shortcut presses until release
2026-09-26 17:53:58 -07:00
OrcaWinandm4air 7a4f83336b ci: shard SSH Docker coverage and warm Windows native caches (#23286)
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 17:47:57 -07:00
OrcaWinandm4air 47ddfbdc0d feat: let users choose JSON or SQLite when profile copies diverge (#23278)
Replace the copy-a-command startup dialog for diverged JSON/SQLite profile
state with Use SQLite / Use JSON buttons. The choice relaunches Orca into the
locked recovery preflight, applies it, then starts normally. Adds a
current-sqlite recovery selector (and --current-sqlite CLI flag) that archives
the diverged JSON and republishes it from SQLite.

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 17:03:05 -07:00
ee6281ff79 fix: dispose OpenCode 2 hooks after prompt setup and cleanup failures (#23209)
* fix: dispose OpenCode 2 hooks after prompt setup and cleanup failures

* test: pin reviewed OpenCode setup cleanup bytes

* fix(i18n): restore diff note draft catalog entries

* test: isolate historical hourly build version inputs

* test: align historical package input with shared CI repair

* test: inject hourly package version without module mocking

* test: share the hourly package input contract across CI repairs

* test(windows): verify NSIS policy with native PowerShell modules

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
Co-authored-by: OrcaWin <alpha-eng@stably.ai>
2026-09-26 15:30:41 -07:00
Neil 34d055c2fa perf(relay): release canceled AI Vault startup requests (#23027)
* perf(relay): release canceled AI Vault startup requests

* test: pin the historical hourly package version fixture

* test: provide the historical package version through build options

* test(ai-vault): cover delayed readiness rejection across restart
2026-09-26 15:27:21 -07:00
Neilandm4air 003b37d6e0 perf: cap shared-path scans and synchronize Windows PTY access (#23194)
* perf: stop scanning shared paths when suggestions are full

* fix(i18n): restore diff note draft catalog entries

* fix(windows): synchronize native terminal table lifetime

* fix: restore catalog entries required by the current CI baseline

* fix(i18n): make AI the recipient of diff notes

* fix(ci): preserve focused Playwright file selection

* test(ci): require focused commands on every platform

Assert each golden platform step and its focused arguments before deduplicating Playwright discovery probes.

* test: pin the historical hourly package version fixture

* test: provide the historical package version through build options

* test(windows): retain PTY stress failure evidence

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 15:15:17 -07:00
OrcaWinandm4air 408499ec58 Keep SSH terminals parked after their own workspace updates (#23193)
* fix(ssh): suppress workspace echoes acknowledged during stale reads

* fix(ssh): preserve newer workspace observations during resync

* fix(ssh): retain newer own acknowledgements during stale reads

* fix(ssh): deliver peer snapshots cached by rejected patches during stale reads

A stale-revision patch reply caches the peer snapshot under a new host
observation token, but the renderer only records a conflict and blocks
uploads. Suppressing an identical stale read then left the peer change
unapplied. Only suppress when the intervening write kept the pre-read
token, which is what a contiguous own acknowledgement does.

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 15:11:34 -07:00
Neilandm4air 8f173581f3 fix: refresh strict Gitea lookups and synchronize Windows PTY access (#23162)
* fix: refresh strict Gitea lookups after creating a review

* fix(i18n): restore diff note draft catalog entries

* fix(windows): synchronize native terminal table lifetime

* fix(ci): preserve focused Playwright file selection

* test: isolate hourly identity inputs from release version changes

* test(windows): retain PTY stress failure evidence

* test(orcad): preserve launcher startup phase evidence on timeout

* test(ci): require focused commands on every platform

Assert each golden platform step and its focused arguments before deduplicating Playwright discovery probes.

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 15:11:23 -07:00
4c38cabb4e fix(windows): synchronize native terminal table lifetime (#23257)
* fix(i18n): restore diff note draft catalog entries

* fix(windows): synchronize native terminal table lifetime

* fix(ci): preserve focused Playwright file selection

* test(windows): retain PTY stress failure evidence

* test: isolate hourly identity inputs from release version changes

* test(ci): require focused commands on every platform

Assert each golden platform step and its focused arguments before deduplicating Playwright discovery probes.

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-26 15:11:17 -07:00
dffb3498e2 fix(ci): preserve focused Playwright file selection (#23270)
* fix(ci): preserve focused Playwright file selection

* test: isolate historical hourly build version inputs

* test: align historical package input with shared CI repair

* test: inject hourly package version without module mocking

* test: share the hourly package input contract across CI repairs

* test(ci): require focused commands on every platform

Assert each golden platform step and its focused arguments before deduplicating Playwright discovery probes.

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-09-26 15:10:35 -07:00
28d617d0d0 fix: close abandoned PDF.js development asset streams (#23054)
* fix: close abandoned PDF.js development asset streams

* test: keep casting safety comments attached after formatting

* fix(i18n): restore diff note draft catalog entries

* fix: guard closed PDF streams and preserve foreign listeners

* fix(i18n): make AI the recipient of diff notes

* test(browser): report the phase of WebRTC probe timeouts

* test: pin the historical hourly package version fixture

* test: provide the historical package version through build options

---------

Co-authored-by: OrcaWin <alpha-eng@stably.ai>
Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 15:08:43 -07:00
OrcaWinandm4air 10cfe9218f test: target writer timeouts and diagnose Bun startup stalls (#23267)
* test(persistence): start the fault timer after the real worker is ready

* test(orcad): preserve launcher startup phase evidence on timeout

* test: isolate historical hourly build version inputs

* test: align historical package input with shared CI repair

* test: inject hourly package version without module mocking

* test: share the hourly package input contract across CI repairs

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-26 15:05:44 -07:00