* perf(git): bound git subprocess execution with an atomic admission scheduler
Field traces (#16038, #11363) show Windows freeze storms driven by unbounded
concurrent git children (12+ at once, 50-65s status convoys for 25+ minutes).
Admit every main-process git child against atomic per-budget base+headroom
counters (general / network / per-route), with reserved interactive capacity,
ordering-only aging, close-bound permit release, a 120s fail-safe read timeout
that feeds scheduler backoff, tier plumbing through every option carrier, and
coalesced+jittered visibility pollers. Killswitch: ORCA_GIT_ADMISSION_DISABLED=1.
Storm harness A/B: max concurrent children 65 -> 6, interactive p95 791ms -> 88ms;
output-parity battery byte-identical with admission on vs off.
* test(git): run the admission output-parity battery on every platform
Parity needs real git, not the storm harness's PATH stub, so it must not share
that file's POSIX gate - Windows is the platform where parity evidence matters.
* fix(git): preserve interactive admission invariants
* perf(git): keep admission queue drains linear
* fix(git): close final admission gaps
* perf(git): bound eligible route selection
* fix(merge): remove unrelated stale snapshot changes
* fix(git): preserve refresh lifecycle authority
* test(git): align admission lifetime contracts
* fix(git): harden admission across runtime paths
* fix(git): restore freshness for bulk status reads
* test(git): repoint delete-dialog source pins after admission plumbing
The hydration effect now orders its targets through
orderDeleteWorktreeStatusHydrationTargets and passes includeLineStats
alongside the abort signal, so both literal anchors stopped matching.
The invariants are unchanged and still pinned: dropping the signal, the
main-worktree/folder filter, or getState-instead-of-subscribe each
still reddens this test.
* Fix git admission tier propagation and lock ordering
Decode optional Git status tiers permissively and default runtime RPC status reads to the status lane while preserving renderer caller intent.
Acquire the FETCH_HEAD mutex before atomic admission so same-repository fetch waiters hold no global or route permits.
Preserve automatic pull-request refresh reasons, keep explicit hosted-review refreshes interactive, remove the dead candidate tier, and keep relay scheduling unchanged.
Use tier-aware status lease keys because a shared lease cannot be safely promoted after its admission request is queued or granted.
* test: align expectations with admission plumbing
* refactor(child-process): move the process contract types to process-spec
run-process.ts crossed its line cap after gaining the termination observer;
the public types and defaults move out with re-exports so no caller changes.
* chore: restore pnpm-lock.yaml to main (unintended local drift)
---------
Co-authored-by: Merge Sim <sim@local>
* fix(relay): reap PTY jobs on fatal exit (STA-5697)
* test(relay): cover the POSIX fatal reap and make a failed reap observable
The fatal reap had no POSIX coverage at all -- every case forced win32 -- and
the daemon discarded the rethrown reap error in an empty catch, so a reap that
failed on a remote host left no trace in the only log a crash produces.
Collapse the job-terminated branch onto the forceKillSent flag it already sets:
the flag is what suppresses the redundant signal, so the separate "continue"
was a second expression of one intent, and the two could only be caught
together -- reverting either one alone left the suite green.
* fix: make PR unlink hide auto-detected reviews
* Type the empty-content test double against the real model
The literal narrowed suppressedGitHubPR to number and typed the callback
as Mock, so neither direction was comparable and tsconfig.tc.web.json
failed on TS2352. Keeping the 'as' cast preserves checking of the fields
the double does supply.
* Add localization keys for the unlinked checks-panel state
The unlinked title, relink action, and the remote-runtime upgrade notice
introduced untranslated keys that static analysis requires in en.json.
* Advertise PR suppression capability in the transport test
The client capability list is pinned by websocket-transport.test.ts, and
adding WORKTREE_GITHUB_PR_SUPPRESSION left the expected list stale.
* Fix stale PR suppression in Checks
* fix: harden PR unlink suppression state
* refactor: extract PR unlink state handling
* fix: show PR relink recovery in source control
* fix: add unlinked PR localization
* Clarify workspace-scoped PR unlinking
---------
Co-authored-by: Merge Sim <sim@local>
A structured send clears the draft asynchronously, on RPC acceptance. If the
user opens the next IME composition first, the clear lands while the browser
owns the field, the DOM sync skips it, and settlement adopts element.value —
which still holds the message that was already sent.
The field now records a clear dropped mid-composition and applies it at
settlement, keeping only what the IME composed on top of the value the field
held when the composition started. Browser ownership is unchanged for every
other programmatic draft; the clear stays on the acceptance path, so a
rejected send still keeps its draft.
Also advances a frame before the attachment-flush focus assertions, which
were vacuous because the focus they forbid is scheduled in rAF.
Fixes#17359
A bare package name exempts every future version of pdfjs-dist from the
release-age gate, including one published minutes ago. Scope it to the single
version that needs it.
* fix(linear): stop the filter coverage warning firing on complete selections
#17342 inferred transport-cap truncation from the bounded filter after the
fact, with `atLimit = selectedIds.length >= max`. A row the cap could not fit
leaves no trace in the surviving ids, so at exactly the cap a complete
selection and a trimmed one are indistinguishable from the value alone, and
the inference biased toward always warning. A workspace with 20 teams x 5
status names expands to exactly 100 ids: picking all 5 rows is provably
untruncated, yet the menu read "100 selected · partial".
Record the trim where it happens instead. `applyPickedFilter` holds both the
pre-cap expansion and the bounded result, so it stores the surviving ids as a
truncation record; the notice, section-menu summary, and pill consume that
flag. Keying the record on the ids it describes is what keeps it fresh — the
moment the facet carries anything else (row toggle, pill clear, Clear all, the
prune effect, a workspace switch) the record no longer matches and the warning
goes away, which matters because the prune effect only ever removes ids.
`intended > applied` stays as the fallback for restored filters that carry no
record, and `boundLinearIssueAttributeFilter` is still the last word on the
cap.
Also moves the section-menu partial marker out of the `max-w-[120px] truncate`
summary span, where "100 selected · partial" could clip.
Refs STA-5996
* test(linear): cover the untouched-facet truncation guard
The guard that keeps a recorded trim alive across an unrelated facet click was
untested — the first attempt sat where intended > applied, so the value-derived
shortfall answered for it and removing the guard left every test green. Move the
scenario onto the cap, where only the record can speak.
Also stop an empty record matching an empty facet: a filter carrying nothing is
never truncated.
* test(linear): pin set equality, not subset, on a truncation record
A facet that grew past its record has refetched underneath it; matching by
subset would keep warning about a trim that no longer describes the filter.
Found by mutation: the subset mutant survived the whole suite.
* test(linear): fuzz that the coverage pill and the section notice agree
They are the same claim rendered twice; a pill reading partial over a silent
section is a lie either way round. 20k random topologies, zero divergence.
Split out of #17170, which now carries only the xterm composition-overlay work.
Codex and Claude draw an all-dim, full-row ghost placeholder. The opaque preedit
overlay reproduces the committed row tail it covers, so without this the ghost is
repeated to the right of the composing syllable instead of staying masked. The
binding keys off the `.xterm-composition-remainder` class that #17170 adds and
hides it through CSS while a composition owns a structurally verified placeholder
row — bold prompt glyph plus a dimmed model footer below a blank gap for Codex, a
frame line above the prompt for Claude. Arbitrary dim output, shell lookalikes,
and any row carrying typed text keep their tail visible.
readTerminalCursorLineContext moves from src/main/daemon to src/shared because the
renderer now needs the same reader the daemon uses; the move is import-only.
Depends on #17170.
#17372 dropped the exclusion two days early: pdfjs-dist@6.3.289 was published
2026-08-29T12:48Z and does not clear the 4320-minute gate until 2026-09-01T12:48Z,
so every pnpm install in CI fails lockfile verification.
* fix(terminal): render IME caret without placeholder overlap
* fix(terminal): preserve dim mid-line composition tails
* fix(terminal): keep IME caret visible at row edge
* fix(terminal): harden IME overlay lifecycle and layout
* test(terminal): type final-cell layout mock
* fix(terminal): keep final-cell IME anchor on-screen
* fix(terminal): bind IME masking to composer ownership
* fix(terminal): bound IME placeholder session ownership
* fix(terminal): track latest IME placeholder session
* test(terminal): share IME session event fixture
* fix(terminal): keep both writers of the IME candidate anchor in agreement
`textarea.style.left` has two writers: xterm's patched CompositionHelper and
Orca's terminal-ime-candidate-anchor.ts. The anchor module listens on
terminal.element, so within a composition event it writes after xterm's textarea
listener and reverted the final-column clamp the patch had just applied.
Moving the clamp into the anchor module and dropping the patch hunk does not fix
it, and the rendered e2e caught that: CoreBrowserTerminal.ts:444 drives
updateCompositionElements from onRender as well, so xterm re-asserts the textarea
position on every repaint, with no composition event for that module to hear. The
anchor survived only when no render happened to follow — measured as a flake at the
final column, 1561.28px against a 1557px screen edge, the fully unclamped value.
So both writers now compute the same clamp. The patch keeps it, because it is the
writer on the render path and already holds cursorLeft, maxWidth and the preedit
bounds. The anchor module applies the same one, so its composition-event write no
longer reverts the correction in the window before the next render. Both halves are
individually necessary and both are mutation-tested.
Also restores _getRowRemainderText's expression from main: translateToString(true,
x, line.length) and translateToString(false, x, getTrimmedLength()) are the same
call, since upstream does endCol = min(endCol, getTrimmedLength()) under trimRight.
Adds the two missing tests — one installing both anchor writers in a single rig, one
driving a render under an open composition — plus disposal cleanup and clamp-bound
coverage, and moves the Codex/Claude placeholder mask to a follow-up PR.
Sibling of execCommandInWslOrThrow (#17375) with the identical throwing
contract, sitting in the same `try { ... } catch { return false }`
blocks. After that rename the pair read inconsistently — one announced
that it throws, the other did not, while both collapse to a silent
false at the call site.
Also states the contract in a doc comment: it rejects rather than
reporting "absent", so a caller that swallows the rejection makes "not
installed" and "could not run it" the same answer.
* ci: gate PRs on a real input method, and prove the lane engaged one
No job on the PR gate has ever run a real input method. pr.yml and e2e.yml are
ubuntu-latest with CDP `Input.imeSetComposition`, which is a synthetic
composition; the only job that drives ibus-hangul through xdotool is
terminal-ime-e2e.yml, and it is schedule + dispatch only. A PR could turn the
real-IME path red and merge green.
Route IME source to that lane from pr.yml through the existing
pr-e2e-source-routing mechanism, so it runs on IME-touching PRs and nothing
else. The lane stays out of verify.needs — advisory, like `e2e` — because its
reliability is known only from nightly main runs. Deliberately no
continue-on-error: that reports green and hides the signal.
The harness fails open in ways that all look like success: Playwright reports a
skipped test as a pass, so an unset ORCA_E2E_NATIVE_IBUS_HANGUL, a renamed test,
or a session with no engine all exit 0 having exercised nothing. The specs now
append an engagement receipt only after observing real composition events, and
the runner requires one per expected test before the lane may report success.
Also drop the native spec from changed-e2e: it was already routed there by its
own filename, where it self-skips for want of an ibus session and reported that
skip as coverage.
* ci: let the real-IME step report even when the synthetic step failed
Pure rename, no behavior change. Callers like isCommandAvailable and
isCommandOnPath wrap this in try { ... return true } catch { return false },
collapsing "distro unreachable" and "command absent" into the same value —
a recurring bug class in this subsystem (see
docs/reference/wsl-probe-failure-semantics.md). The OrThrow suffix makes
that swallow visible at the call site instead of implicit in the function
name, so a reviewer notices when a new caller does the same collapse.
* fix(browser): apply the app-wide HTTP proxy to embedded browser sessions
The proxy setting was only ever written to `session.defaultSession`, but browser
guests run on their own `persist:orca-*` partitions. Any host reachable only via
the configured proxy failed to load in an embedded tab, landing on
`chrome-error://chromewebdata/`, while the same setting worked everywhere else.
Adds a per-session applier alongside the existing defaultSession path, keyed by a
WeakMap so one session's applied config can't suppress another's, and applies it
to every browser partition through the single installer they all pass through.
Startup awaits an explicit sweep so the first guest navigation can't race the
installer's fire-and-forget write, and a settings change re-sweeps so toggling
the proxy takes effect without a restart.
Env-var fallback and the system-proxy probe mirror the defaultSession behaviour,
so a browser partition resolves the proxy the same way the rest of the app does.
Fixes STA-4779
* fix(browser): await per-session proxy readiness
* fix(proxy): preserve loopback and authenticate
* fix(proxy): settle browser partition update races
* fix(proxy): close partition policy races
* fix(proxy): order settings and release removed sessions
* test(browser): await partition proxy readiness
* fix(proxy): cancel removed partition retries
* refactor(proxy): keep OpenCode rate limits out of scope
* fix(proxy): preserve sessionless host policy
* fix(proxy): gate requests on policy readiness
* fix(proxy): retire deleted browser sessions
* fix(proxy): close retired browser guests
* fix(proxy): retain retired session guards
* fix(proxy): retain retired partition policies
* fix(browser): retry transient proxy application failures
* fix(browser): release deleted partition installer state
* fix(proxy): retry delayed transient failures
* fix(proxy): preserve route session authority after rebase
* fix(proxy): clear retired session credentials
* fix(proxy): retire failed browser profiles
* fix(proxy): harden failed session cleanup
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
* fix(wsl): scan sessions only in running distros
* test(ai-vault): pin WSL discovery platform
* fix(wsl): suspend transcript watchers for stopped distros
* test(wsl): pin transcript scan gate platform
* fix(wsl): settle stopped transcript loading
* fix(wsl): add last-known-good fallback and backoff to running-distro discovery
listRunningWslDistrosAsync failed closed on any probe error (timeout, ENOENT,
wsl.exe hiccup), indistinguishable from "no distros running". A 2s poll
(wsl-transcript-running-observer.ts) calls it indefinitely while any WSL
transcript tab is open, so a persistently broken wsl.exe silently made every
WSL session vanish app-wide with no way to tell "discovery broken" from
"distro stopped", and re-spawned wsl.exe every 2s forever.
Extract a dedicated cache/backoff module (wsl-running-distro-cache.ts,
mirroring the sibling machinery already in wsl.ts for the full distro list)
so a probe failure falls back to the last-known-good running-distro list and
backs off further probes, while a genuine empty result (no distros running)
stays authoritative. Add a consumer-level test simulating a sustained wsl.exe
outage across a live transcript-watcher polling session, asserting the
observer keeps reporting "running" and that real wsl.exe spawns stay bounded.
* fix(build): list the new WSL cache module in the web typecheck project
config/tsconfig.tc.web.json enumerates its files explicitly, so a new
module imported by wsl.ts fails the full typecheck with TS6307 until it
is listed. pnpm tc:node passes without it, which is how this got missed.
src/main/wsl.ts(13,8): error TS6307: File 'src/main/wsl-running-distro-cache.ts'
is not listed within the file list of project 'config/tsconfig.tc.web.json'.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* test(wsl): guard probes that report failure as a negative answer
A WSL probe that cannot reach its distro returns the same value as one
that asked and got "no". Downstream nothing can tell them apart, so a
distro that was busy for a second reports no git, or no agent sessions,
until relaunch — sticky, silent, and identical to the real thing.
That has shipped three times: preflight CLI probes, the glab auth
fallback (#8941), and listRunningWslDistrosAsync failing closed with no
last-known-good while polled every 2s (PR #17072).
Scan the WSL and preflight probe modules for the shape and hold the
current set in an allowlist that only shrinks. Scoped deliberately: the
same shape appears ~850 times across src/ and is usually correct,
because for most callers a failure really does mean absent. It is only
dangerous where the answer describes a distro.
The guard cannot see the dangerous part — whether the value is later
cached or gates discovery is dataflow, not syntax. It stops a new
swallow site appearing here without someone saying why it is safe to
pin, which is the review that was missing all three times.
* test(wsl): make ratchet failures actionable
A red build must say what to do. Name the offending files, say the
allowlist is where a safe case goes, and — for a stale entry — say the
change is fine and the list just needs to shrink.
* docs(wsl): track the probe failure-semantics reference
docs/** is gitignored with an explicit allowlist, so the reference the
ratchet points contributors to was silently left out of the branch. A
guard whose error message cites a doc that is not in the repo is worse
than no doc.
* test(wsl): catch a swallow whose reason trails the return
The guard only tolerated comments before `return`, so
`return false // ...` slipped past — including the exact snippet the
doc and the test's own docstring use as the canonical example. The doc
asks authors to write down why a swallow is safe, and the natural place
for that sentence is trailing the return, so following the guidance
defeated the guard.
Verified against both shapes: trailing comment and comment on the line
after.
* fix(cli): name PowerShell when it strips quotes from JSON flags
Windows PowerShell 5.1 does not escape inner quotes when building a native
command line, so `--options '["a","b"]'` reaches orca.exe as `--options [a,b]`.
The value is correct when printed and damaged by the time argv is parsed, so the
resulting "invalid JSON" error blamed the user's input rather than the shell.
#16743 recovered this for `--deps`, which is safe only because generated task IDs
have a fixed 12-hex grammar. The same mangling hits `--options`, `--payload` and
`--result`, and those are NOT safely recoverable: `["1","2"]` and `[1,2]` arrive
at argv identically, so a general repair would silently turn strings into numbers.
Detect instead. `getOptionalJsonFlag` rejects the damaged shape up front with an
error that names the shell and shows the workaround. It fires only when the value
is bracketed, quote-free, fails JSON.parse, AND consists entirely of bare tokens
that quoting would rescue, so valid JSON is untouched.
Also share the generated-id contract: `task-deps-flag` hardcoded
/^task_[0-9a-f]{12}$/i, which silently diverges if `generateId`'s byte count
changes. It now calls `isGeneratedId`, with a test pinning the two together.
Verified on a Windows host. Measured argv, which the new test pins as a fixture:
PS_VALUE=["task_b2a580db74d8","task_c3b691ec85e9"]
ARGV=["--deps","[task_b2a580db74d8,task_c3b691ec85e9]"]
Before: Invalid --options: must be a JSON array of strings
After: --options arrived as [a,b], which is not valid JSON.
Windows PowerShell 5.1 strips the inner quotes ...
* fix(cli): scope JSON-flag detection to genuinely JSON flags
Review found the detector wired to two flags that are not JSON:
- `orchestration ask --options` is documented `<csv>` and the runtime splits it
on commas, so `--options [a,b]` was a legitimate value being rejected.
- `task-update --result` is stored verbatim and reused as dispatch failure text;
existing tests pass free text, so a bracketed `[ok]` was being rejected.
Both revert to `getOptionalStringFlag`. Only `gate-create --options`
(`<json_array>`) and `send --payload` (`<json>`) are JSON-parsed and keep it.
Three further review fixes:
- Objects now require a `key:value` pair per entry. `{a,b}` and `{a:b,c}` were
reported as quote-stripped although quoting them cannot produce valid JSON.
- The raw value is no longer echoed. A `--payload` can carry secrets and this
message reaches `--json` output; the flag name and guidance are enough.
- The message hedges the shell attribution. Detection inspects only the value's
shape, so it also fires when a macOS/Linux user forgets to quote, where
PowerShell is not involved.
Verified against a Windows host, all six cases: both JSON flags fire on the
mangled shape and pass valid JSON through to the runtime; both non-JSON flags
now reach the runtime again; and the secret in `{token:hunter2}` appears zero
times in the error output.
* fix(linear): flag partially applied status and label filters (STA-5983)
Since #16879 one status/label row expands to an id per team, and the renderer
bounds that list to the 100-id transport cap. Any surviving id kept the row
fully checked, so the picker claimed coverage the filter never had; show how
many of the row's per-team ids are actually applied.
* fix(linear): keep every picked status row inside the transport cap
The cap sliced a lexicographically sorted id list, so a whole picked row could lose
every id — reverting to unchecked with no notice, and dropping out of the coverage
denominator that was supposed to explain it. Spread the cap across the picked rows,
and carry the partial-coverage signal to the section menu and the pill, which are
what the user reads once the detail panel is closed.
* fix(linear): stop the status filter claiming coverage it cannot apply
More picked rows than the transport id cap cannot all be represented, and
MultiSelectList.toggle appends the clicked key last — so the starved row was
always the row the user had just clicked: it stayed unchecked, no notice fired,
and coverage still reported a full 100 of 100. Coverage now takes the cap and
reports a spent id budget as its own shortfall, so the picker says how much it
is really carrying instead of claiming teams it never covered.
Capping also bucketed by the click order the picker hands it, so the same
visible selection could resolve to different ids between renders; it now buckets
in metadata order, with ids from unloaded teams sorted after. boundLinear-
IssueAttributeFilter stays the last word on the transport bound.
The pill's `partial` marker moves from a bare title attribute to the Tooltip
primitive, which keyboard and screen-reader users can actually reach.
Pill labels and facet clearing move to their own module so sections stays under
the max-lines cap.
* test(linear): assert coverage at the cap it actually caps to
The exactly-on-the-cap test capped at max=4 but asserted non-partial at
max=5, so it never covered its own subject. Pin both: at the cap coverage
warns (a starved row leaves no trace in the ids), below it stays quiet.
* Consolidate the renderer now-clock and drop the epoch setState round-trip
Follow-up cleanup to #17337.
`src/renderer/src/hooks/use-now.ts` duplicated the shared clock that already
lived at `components/dashboard/useNow.ts`, with a per-instance `setInterval`
and no visibility gating — the exact pattern that file's own comment warns
against. Keep the shared `useSyncExternalStore` implementation, move it to the
`hooks/` home the duplicate had taken, and give it the `enabled` flag that was
the duplicate's only real addition. A disabled caller no longer holds the
shared interval open or re-renders on its ticks.
Gate the two 1 Hz callers on the state that can actually consume them: the
checks-panel empty content only reads the clock for a GitHub auto-retry or
retry-disabled window, and the diff notes menu only for an open request already
addressed to its worktree. Both previously ticked for their whole lifetime —
the empty content re-rendered the create composer once a second while the user
typed in it.
Replace the `setState`-in-`useEffect` epoch clocks with a sample keyed on
`agentStatusEpoch`. The effect ran a render late, so the freshness-scheduler
bump — whose whole purpose is to expire an entry on the stale boundary — first
painted a frame that still read the pre-expiry timestamp, then corrected it.
Sampling during render keeps the value deterministic per epoch and every
consumer of one epoch agreeing on the boundary.
Also: `isPanelVisible` never gates the checks-panel clock (ChecksPanel is
unmounted, not hidden), `setPrRefreshStateNow` was returned but never read,
`panelContextKey` was an unused dep on the expiry effect already keyed by
`prCacheKey`, `useResetCountdownClock` kept a dead alias, and `ProviderPanel`
derived its window sections twice per render.
* Fix the open-request TTL and the epoch clock's captured Date.now
Review findings on the previous commit.
The diff notes menu's 5s TTL stopped working. The shared clock's snapshot is
frozen while nobody at that cadence is subscribed, and `useSyncExternalStore`
subscribes in a passive effect — which flushes child-first, so NotesSendMenu's
open effect ran before the clock could catch up. With both 1 Hz callers now
narrowly gated, nothing holds that cadence, so an open request that was never
consumed could reopen the menu arbitrarily later.
The TTL is a deadline, not a drifting label, so enforce it on the commit that
acts on the request: DiffNotesSendMenu passes `openRequestExpiresAt` and
NotesSendMenu checks it against `Date.now()` in the effect that opens the menu.
Exact, and it removes the 1 Hz clock from that path entirely.
`createAgentStatusEpochClock`'s `readNow = Date.now` default bound the native
function when the module-load singleton was created, so a suite's fake timers
never applied to it. Call through instead. Also add a reset seam: store resets
rewind `agentStatusEpoch` to 0, and without rewinding the sample the next render
at epoch 0 reuses the previous test's timestamp.
Both regressions have tests that fail without the fix. Also corrects the
disabled-caller contract on `useNow` — the snapshot is frozen, not merely
bounded by an enabled caller — and notes on the three memos that they stay keyed
on the epoch because two bumps in one millisecond share a sample.
* perf(preflight): cache WSL CLI probes per distro
A preflight check against a WSL target skipped the cache entirely
(`cacheable = !wslTarget`), so every caller re-spawned up to five
`wsl.exe` probes — git/gh/glab detection plus gh/glab auth, two of them
through login shells — and woke an idle distro each time. Repeated
Landing mounts, pane switches and per-worktree restore each paid the
full set.
Cache per distro so one distro's toolchain never answers for another,
and join concurrent callers onto one probe set instead of letting each
run its own.
The entry expires rather than living for the session like the local
cache does: `isCommandAvailable` collapses every failure into
`installed: false`, so an unreachable distro is indistinguishable from
one with no tooling. Pinning that would report "git not installed"
until relaunch, where the uncached code self-healed. Expiring keeps the
burst collapsed and still lets a transient failure recover.
Propagating unreachable-vs-absent out of the probe layer would allow a
longer-lived entry, but that reaches well past WSL and belongs in its
own change.
* fix(preflight): stop a superseded probe caching its stale result
Review caught two races the first version had.
A forced refresh runs alongside a slower probe already in flight. Both
wrote the cache unconditionally on settle, so the older one landing last
replaced the newer answer — a Re-check could silently return the status
it was asked to replace, for the whole TTL.
The same write also repopulated a cache that `_resetPreflightCache` had
just cleared, which jira/linear call on credential changes: the probe
already out would settle afterwards and restore what was invalidated.
Tag each run and only let it write while it is still the newest for its
key, with an epoch doing the same across a reset. A superseded run still
returns its own answer to its own caller; it just stops becoming the
cached one.
Both tests fail without the guard.
#17347 switched the reveal path to `window.showInactive()` and updated the
thrown message, but the unit test still asserted `show()`, so this suite is red
on main and blocks unrelated PRs.
Updates the assertion and the test title to the call the helper actually makes.
PR #17347 switched the reveal helper from window.show() to
window.showInactive() and updated the thrown message, but left the
unit test's regex/title matching the old show() wording — failing
deterministically in CI (which builds against current main) while
passing on any stale checkout that predates #17347.
* fix(remote): focus host-delegated split panes
Return the authoritative leaf identity from terminal.split, record viewer-local focus intent behind the captured pairing revision, and replay the mirrored layout before focusing the exact pane. Preserve old-host fallback and prevent delayed split responses from stealing focus after the viewer moves away.
Add deterministic runtime, renderer, concurrency, compatibility, and headed paired-Electron coverage for Cmd+D, header splits, and immediate PTY input routing.
Fixes#16510
* fix(remote): preserve split focus across tab groups
Resolve the initiating source tab and leaf from the remote PTY, while keeping the viewer's current focus as a separate anti-steal baseline. This lets context-menu/header splits from non-focused group tabs focus their result without allowing delayed responses to override a later navigation.
* test(remote): drive split focus with key events
* test(remote): use the platform split shortcut
* fix(remote): fence concurrent split focus intent
* fix(remote): harden split focus ordering
* fix(remote): preserve split focus after runtime refactor
* fix(remote): fence stale split focus gestures
* test(remote): keep split focus regression within line budget
* Enable React purity and static component lints
* fix lint follow-up clock activation and eligibility expiry
* test render status bar provider panel with hooks
* fix checks clock activation before paint
* fix React type import in git history files
Reuse direct SSH browser-route eligibility and route owner-pinned terminal links through the workspace createBrowserTab path. Keep the popover and modifier hints aligned with the eligible destination.
Preserve printed 0.0.0.0 and localhost URLs; the existing SSH SOCKS boundary normalizes wildcard listeners to remote loopback immediately before connect.
* fix(build): preserve Electron during binary repair
* refactor(build): split native dependency fixtures
* fix(build): resolve one Electron install target for child and check
runElectronPackageBinaryInstall forced ELECTRON_INSTALL_PLATFORM/ARCH to the
host-derived rebuild target, clobbering inherited installer env, while the
parent usability check still honored the inherited value. A bare
`node config/scripts/rebuild-native-deps.mjs` under ELECTRON_INSTALL_PLATFORM=win32
on Linux therefore installed the Linux binary and then rejected it as
unavailable. Resolve the target once (CLI, ELECTRON_INSTALL_*, npm config, host)
and use it for both the child env and getElectronPlatformPath.
* fix(build): keep Electron install transaction cleanup best-effort
The finally-block rmSync could throw after a fully successful publish (Windows
EPERM when another process still holds the discarded old electron.exe open),
turning a correct install into exit 1. On the rollback path it could also
replace the in-flight publishError with an unrelated temp-dir error. Retry the
removal and downgrade a persistent failure to a warning.