- Route git.status through an abortable subscription per requestToken so
cancelStatus can actually abort the remote scan instead of being a
no-op, preventing wasted work and stale responses overwriting fresher
state.
- Bump the git status polling generation on push-target changes so an
in-flight refresh against the old remote/branch can't apply stale
upstream data to the new one.
- Guard the stale-conflict poller against writes after unmount.
- Retire pre-purge line-stat scans in the cache so an older in-flight
scan can't repopulate a key after a token-scoped purge.
Cancelled scans could still resolve with partial or stale data instead of
rejecting, letting callers treat an aborted refresh as a valid status. Also
stop counting aborted scan duration toward catch-up refresh pacing, which
was stretching the next refresh interval by the full length of a cancelled
(often slow) scan.
- An aborted scan/numstat pass now always rejects instead of silently
resolving, so a cancelled request can't look like a valid empty status.
- Stop clearing the line-stats cache key on abort, since an aborted pass
never wrote to it — clearing was evicting a concurrent scan's healthy
snapshot and forcing a redundant numstat recompute.
- Add a single duty-cycled refresh scheduler (activity debounce + 60s
safety timer) replacing multiple overlapping intervals, so status
polling no longer runs near-continuously on large repos (#7983).
- Let safety refreshes reuse cached numstat line counts instead of
re-running diff --numstat every cycle, invalidated by head change,
known mutations, and a bounded TTL.
- Thread AbortSignal/request-token cancellation through IPC, RPC, and
relay layers so a superseded or backgrounded git:status call is
killed instead of finishing wastefully.
- Fix automatic upstream/status apply ordering so a slow, older
refresh can no longer clobber a newer result, and so an earlier
refresh still applies when a later one fails.
* fix(sidebar): map header drags to the nearest boundary slot instead of a dead zone
Fixes#8879
* fix(sidebar): bound header edge drops to measured content
The native-smoke job ran bare `pnpm vitest run <files>` with no --config.
There is no root-level vitest/vite config, so vitest fell back to its
built-in defaults: a 5000ms testTimeout and no Windows worker cap. The
real csc.exe launcher-compile tests (build-windows-cli-launcher and
ssh-remote-cli-launcher) cold-start in 1.4-7.4s on hosted Windows and
tipped over the 5s default, failing the PR check.
Pass --config config/vitest.config.ts like every other vitest invocation
in the repo (pnpm test, pr.yml) so the job gets the shared 30s timeout and
Windows maxWorkers:4 cap (less CPU contention -> lower compile variance).
Positional file args still filter to just the listed files.
* feat(mobile): edit saved host endpoints
* fix(mobile): reject ambiguous numeric host addresses
* fix(mobile): label edit host inputs
* fix(mobile): make host edit save atomic and remove superseded mutators
Two independent review rounds found the same class of foot-gun: a
superseded mutator (updateHostEndpoint, then renameHost) left in
host-store.ts after the atomic updateHostNameAndEndpoint refactor, with
zero remaining callers. Either could be reintroduced by a future caller
and silently regress the non-atomic name/endpoint race the atomic
function was written to close, so both are removed.
Also covers reconnect-rejection and endpoint-only save paths that were
missing test coverage, and merges origin/main (#8789) so this lands
without reverting the mobile terminal restore fix.
Co-authored-by: Orca <help@stably.ai>
* Simplify save-race comment and reword host-removed error message
- Trims the redundant comment explaining the savingRef race guard down
to one line.
- Changes the "no longer saved" load-error copy to "was removed" for
clearer phrasing, updating the matching test expectation.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* fix: address pr-bug-scan validated finding from #6335
Replaced unguarded crypto.randomUUID() with the established createBrowserUuid() fallback in both markup shape-id call sites.
* fix(review): cover markup crypto fallback call sites with regression tests
PR #8804 replaced two unguarded crypto.randomUUID() calls with
createBrowserUuid(), matching the convention established in #5471, but
shipped without extending that PR's regression-test pattern to the new
call sites. Add hook-level tests for useMarkupPointerHandlers.onPointerDown
and useMarkupEditor.commitPendingText under a simulated non-secure-context
crypto global.
Co-authored-by: Orca <help@stably.ai>
* fix(review): consolidate annotation bridge token onto createBrowserUuid
BrowserPane had its own inline crypto.randomUUID guard with a
Date.now()+Math.random() fallback, duplicating the getRandomValues-based
fallback already centralized in createBrowserUuid() and used at every
other call site in the renderer.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* docs(readme): fix Korean translation issues
* docs(readme): align agent list with English README across translations
Replace OpenClaude with Pi in Spanish, Japanese, and Chinese READMEs
to match the English README's agent list (Codex, ClaudeCode, OpenCode, Pi).
Portuguese already had the correct list.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* Reopen closed tabs with Cmd+Shift+T, including terminals
Cmd/Ctrl+Shift+T now reopens the most recently closed tab of any kind
(terminal, browser, or editor) in true recency order, walking back
through close history on repeated presses — Chrome/Ghostty semantics.
Terminal tabs previously had no reopen at all, and the shortcut picked
browser-vs-editor by focused surface instead of recency.
Terminal closes capture a snapshot (startupCwd, shellOverride,
customTitle, color) on explicit user closes only; PTY exits, launch
cleanup, onboarding, and floating-panel closes are excluded. Reopen
spawns a fresh shell through the same createTab path as the "+" button.
A per-worktree cross-type kind list (new recently-closed-tabs slice)
orders the three existing per-type stacks; both new maps are purged on
worktree removal and re-keyed on rename with startupCwd prefix remap.
createNewTerminalTab moved to terminal-tab-create.ts to keep
terminal-tab-actions.ts under the max-lines budget.
Requested via Discord feedback; STA-1287.
Co-authored-by: Orca <help@stably.ai>
* Update close-tab assertions for captureRecentlyClosed flag
Floating-panel, launch-failure, and stale-agent-tab closes now thread
{ captureRecentlyClosed: false } so system-initiated closes don't pollute
the reopen stack. Update the affected test expectations to match the new
call shape.
Co-authored-by: Orca <help@stably.ai>
* fix(reopen): skip local terminal reopen on remote-runtime worktrees
reopenClosedTerminalTab recreated terminals via a raw local createTab
without the isWebRuntimeSessionActive guard every sibling terminal-create
path uses, so Cmd+Shift+T on a remote-runtime-owned worktree (paired-web
or desktop-attached headless-serve) spawned an unbacked local phantom tab
not tied to the host session. Guard at reopen time via the cycle-free
getRuntimeEnvironmentIdForWorktree — importing web-runtime-session into a
store slice creates a store-index init cycle. Remote terminal reopen stays
deferred; the cross-type dispatcher falls through to browser/editor.
Adds a regression test and corrects an inaccurate removal-path comment.
* fix(test): seed runtime host id for remote-reopen guard test
The prior test set settings.activeRuntimeEnvironmentId by spreading the
store's settings, which widened workspaceDir to string|undefined and broke
`pnpm typecheck` (GlobalSettings requires string). Seed the worktree with a
`runtime:` hostId instead — getRuntimeEnvironmentIdForWorktree reads it
directly, so no settings spread is needed.
* Remove unrelated formatter changes
---------
Co-authored-by: Orca <help@stably.ai>
* Fix PR checks sticking to a stale linked PR after a terminal branch switch
A worktree's linked PR is a branch-scoped hint, but two refresh paths race
when a terminal switches branches: the git-status identity path clears
branch-scoped review links, while the worktree-listing path rehydrates the
new branch together with the stale persisted link and clears nothing. When
the listing lands first (the common case — worktree listing is much faster
than git status), the identity path sees no branch change and the stale
link survives. Every subsequent refresh then re-fetches the linked PR by
exact number, which ignores the branch, so Checks stays pinned to the old
branch's PR and the Refresh button cannot recover.
Two-part fix:
- Prevention: listing refreshes now route observed branch switches through
updateWorktreeGitIdentity before merging, so the existing link clear and
tombstone machinery runs no matter which refresh path wins. Gated on the
entry still carrying branch-scoped review context so a stale listing row
cannot roll back a newer branch identity.
- Recovery: PRInfo now carries headRefName, and a fetch that returns the
linked OPEN PR whose head branch matches neither the current branch, the
worktree push target, nor the worktree HEAD clears the durable link and
re-resolves by branch. Wired into both fetchPRForBranch and the
background refresh coordinator, mirroring the merged-PR divergence clear.
This also heals wedged workspaces persisted by earlier builds.
* Harden stale PR recovery across refresh races
* Avoid duplicate PR recovery refresh work
* Index linked PR refresh aliases once
* fix(worktrees): stop surfacing prunable git worktrees as live workspaces
A worktree still registered in git but whose directory was deleted
(git's `prunable` state) was enumerated as a normal workspace,
producing repeated pty:spawn DaemonProtocolError / fs:readDir ENOENT
loops and a blank pane.
- Parse the `prunable` porcelain field (Git >= 2.36) in both the main
and relay worktree-list parsers.
- For Git < 2.36 (no `prunable` field), probe each linked worktree
path for existence on the fallback line-block path, skipping locked
registrations to mirror git's own prunable rules.
- Omit prunable worktrees from the detected-workspace enumeration only;
removal/cleanup flows keep seeing them.
- Extend the real-binary compatibility contract with the 2.36
`prunable` boundary.
Fixes#8389
Claude-Session: https://claude.ai/code/session_018Rg1Bpq4GGwmz613hq6RSD
* fix(worktrees): pin the prunable/locked porcelain annotations to their real Git 2.31 boundary
The prunable and locked annotations landed in Git 2.31, five releases
before `worktree list -z` (2.36); only -z defines the capability
fallback boundary. Correct the compatibility contract so a future
matrix entry in the 2.31-2.35 range passes, and reword the fallback
comments: on 2.31-2.35 the annotations still parse and the existence
probe is a backstop; only Git <2.31 relies on it outright.
* fix(worktrees): omit prunable registrations from the Space scan
A prunable registration has no directory to size or reclaim, so Space
rendered it as a dead "Missing" row whose checkbox stayed disabled with
no prune/remove affordance (reported on macOS after a reboot cleared
/private/tmp under 16 registrations). Skip prunable entries in the scan,
matching the workspace enumeration; removal flows list worktrees
separately and still see them.
---------
Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(runtime): retain watcher and PTY teardown ownership
* fix(runtime): restore watchers after interrupted cleanup
* fix(runtime): prevent stale watcher revival
* test(runtime): cover watcher shutdown ownership
* test(daemon): model physical PTY exit
* fix(daemon): keep shutdown terminating when disposal cannot prove exit
A rejecting host.dispose() (unreapable child past its exit deadline) left
the shutdown RPC without its process.nextTick(shutdown) and skipped socket
cleanup in shutdown(), stranding the daemon as an unreachable orphan after
the stale-daemon replacement flow unlinks its socket. Log and continue:
daemon exit reparents the child to init instead of blocking on it.
* fix(runtime): keep local watching alive after an idle-kill deadline miss
An idle child that outlived the exit deadline set shutdownRequested on the
shared desktop supervisor, which has no retire-and-replace path — every
later subscribe rejected supervisor_disposed and the roots were cached
unwatchable, silently ending local file watching for the session. The idle
path owns zero records, so there is no double-watch hazard; the zombie
keeps its capacity reservation until physical exit and the next subscribe
gets a fresh child.
* fix(renderer): resync replayed paired-web file watches
Transparent replay removed the implicit resync the old close-and-rebuild
path provided: a replayed files.watch only reports changes from its own
native setup, so changes during the reconnect gap were silently lost.
Deliver a conservative overflow to consumers once the replayed watch is
ready, matching the overflow-after-interruption contract everywhere else.
* fix(runtime): address teardown review findings
* fix(runtime): retry watches after teardown deadlines
* Fix PTY descendant leaks on forced teardown
* Fix jitter-sensitive terminal lifecycle test
* fix(crash-reporting): coalesce repeated renderer error breadcrumbs
The crash-breadcrumb ring holds only 30 entries, and renderer breadcrumbs
arrived via the plain uncoalesced path. A repeating renderer error — like the
ResizeObserver and SSH-rejection storms in #8260 (50+ identical events) —
flushes the entire ring in seconds, erasing the pre-crash trail exactly when a
crash report is about to snapshot it.
Route renderer_error and renderer_unhandled_rejection breadcrumbs through the
existing recordCoalescedCrashBreadcrumb, keyed by name plus message prefix
with a 30s window. Repeats collapse into one entry carrying
suppressedSinceLast, so a storm shows up as "error X fired N times" alongside
29 slots of surrounding context instead of 30 identical copies.
Other breadcrumb names keep the plain path; telemetry trace spans are
unchanged. Renderer breadcrumb routing tests move to a focused
crash-reporting-renderer-breadcrumbs.test.ts (the main suite is at the
max-lines ceiling).
* fix(crash-reporting): coalesce durable renderer traces
* fix: harden renderer crash guards
* fix(crash-reporting): preserve distinct error sources
* fix(ssh): AND lsof selectors so relay reset can't kill unrelated processes
`forceStopRelayForTarget` resolved PIDs with `lsof -t -U "$sock"`.
lsof ORs its selectors by default, so this selects every process holding
ANY unix socket in addition to the socket's owner. On hosts where lsof
cannot match AF_UNIX sockets by path, the path term matches nothing and
the sweep degrades to all unix-socket holders — including systemd --user
— which the TERM+KILL loop then takes down (#8762).
Add `-a` to AND the unix-socket and path selectors: where lsof supports
path matching the result is exactly the socket's holders (verified: 1
PID with -a vs 97 without on macOS); where it doesn't, the result is
empty and the existing pgrep fallback — scoped to command lines that
reference the relay's per-instance socket name — takes over.
Fixes#8762
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* review: add relay reset process-safety coverage
Exercise the generated POSIX reset script with controlled lsof and pgrep commands plus a mocked kill, and keep the selector rationale concise.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix(native-chat): deliver AskUserQuestion answer by option number, not label
Claude Code's AskUserQuestion is an arrow-navigate selector: a bare Enter
commits the HIGHLIGHTED default (the first option), and pasted label text
does not move the highlight. Native chat delivered the answer as the option
LABEL text + Enter, so every non-first pick was silently committed as the
first option (STA-1860 Bug A).
Deliver the answer by each option's stable 1-based number instead (the marker
the selector commits on), paced so each keystroke lands after the selector
step renders. Covers single/multi-select, multi-question, and free-text
('Type something') answers. Verified live against Claude Code 2.1.210.
- native-chat-interactive-prompt.ts: buildAskAnswerKeys / AskAnswerSelection /
AskAnswerKeyGroup / hasAskAnswer; formatAskAnswer kept (index-based) for the
non-Claude label path
- native-chat-runtime-send.ts: sendNativeChatAskAnswer (paced keystroke groups)
replaces the old label-line sender
- card + interactive hook thread structured { indices, other } selections
STA-1860
* fix(native-chat): harden AskUserQuestion answer lifecycle
* fix(native-chat): stop stale paced answer writes
* fix(native-chat): cancel paced answers during commit
Cancel stale AskUserQuestion timers before replacement UI can commit, and localize the multi-step sending state in every shipped locale.
* fix(gitea): share and cache the /pulls scan so card refreshes can't hammer a self-hosted forge
Each worktree card resolved its branch by paginating the repo's full
/pulls listing (state=all, up to 5 pages) independently, with a 5s
timeout. Gitea/Forgejo have no head-branch filter, self-hosted Forgejo
takes ~5s per page (it loads reviewer data per PR), and a push event
refreshes every card at once — so one repo turned into hundreds of
near-simultaneous requests whose responses were aborted right as they
completed, and the burst OOM-killed a 512Mi Forgejo pod (#8807).
- Share one in-flight /pulls scan per repo across concurrent branch
lookups and cache the result for 30s, so a burst costs a single page
walk instead of one per worktree.
- Raise the list-scan timeout to 15s so slow-but-successful pages are
used instead of discarded and retried.
- Invalidate the cached scan after Orca itself creates a PR (and before
the post-create fallback lookup) so the new PR is seen immediately.
Fixes#8807
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(gitea): don't let an in-flight scan re-cache a listing from before an invalidation
Review feedback: if a PR is created while a card-refresh scan is in
flight, the invalidation cleared the cache but the scan then finished
and re-cached the pre-create listing, hiding the new PR for a full TTL.
Track a per-repo generation: invalidation bumps it (and drops the
in-flight promise), and a scan only writes the cache when its generation
is still current.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(gitea): bound PR scan cache and retry failures
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Preserve original markdown style when editing in the rich editor
The rich markdown editor re-serialized the whole document into a canonical
style on the first edit, so a one-character change rewrote every non-canonical
construct (`_x_`->`*x*`, `__x__`->`**x**`, `* item`->`- item`, dropped trailing
newline) and produced a large, unexpected diff.
Reconcile the canonical getMarkdown() output back toward the original source
bytes at every disk-bound serialize site (debounced autosave, flush, Cmd/Ctrl+S)
so untouched regions keep their markup and only the edited region changes. A
divergent-base fuzzy patch (diff-match-patch) carries the user's edit onto the
original style; a safety re-parse requires the result to render-equal what the
editor shows, else it falls back to today's canonical output — so content
semantics can never change. The rich editor stays the default for markdown.
Fixes#6080
* Bound markdown reconciliation diff work
* fix(terminal): kill agent descendant processes on session teardown (STA-1800)
Agent CLIs spawn tool children in detached process groups that PTY
SIGHUP can never reach. Killing an agent session (tab close, retire,
sleep) left those children running as orphans — eight orphaned git
processes burned ~8 cores for up to 11.5h under the agents-running
keep-awake and drained a battery to 8%.
New pty-descendant-termination module: snapshot the ppid tree BEFORE
signalling (a dead root's descendants reparent to pid 1 and become
unfindable), SIGTERM the root group and every descendant, then after a
2s grace SIGKILL survivors gated on a pid+start-time identity re-check
so a recycled pid is never signalled. Snapshot is bounded and never
rejects; failures degrade to today's shell-only kill.
Wired for agent sessions only (plain terminals keep nohup semantics) at
all three POSIX kill sites: local provider shutdown, daemon
TerminalHost immediate kill (the pty:kill path — force-kill bypassed
Session.kill entirely), and daemon Session graceful kill.
Verified live in the built app: an agent pane with a detached-pgid
child; the child survived on the unwired build (three control runs) and
dies within ~5s with the fix. Windows ConPTY and SSH-hosted PTYs keep
the previous foreground-tree contract (documented follow-ups).
* fix(terminal): harden descendant teardown
* fix(terminal): require fresh process snapshots
* fix(terminal): close descendant teardown races
* refactor(terminal): preserve teardown line budget
* fix(terminal): keep descendant teardown fresh and identity-safe
* docs(reliability): record integrated descendant E2E
* fix(terminal): bound descendant teardown work
* fix(terminal): share descendant snapshot indexes
* docs(reliability): record descendant review evidence
* revert: remove speculative descendant hardening
* fix: close Add Project host selector when an SSH credential prompt appears
The SSH password/passphrase dialog (z-50) renders below popovers (z-60),
so a host selector left open during a connect attempt covered the
credential prompt and its input field. Close the selector as soon as a
credential request is queued so the modal prompt is visible and usable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: raise SSH credential prompt above popovers instead of closing the host selector
The credential prompt is a preemptive global modal, but DialogContent's
default z-50 sits below popovers (z-60) and menus (z-70), so any surface
left open while a prompt fires covers the focused password input — the
Add Project host selector was one reproducible case (#8490).
Raise the prompt's overlay/content to the frontmost tier (!z-[140] /
!z-[150], matching link-routing-preference-dialog) so it renders above
every popover/menu, and drop the host-selector close effect: the picker
can stay open and is available again after cancel for an immediate retry.
---------
Co-authored-by: jonghoonlee <jonghoonlee@inocras.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(agent-status): reap finished Claude named agents/teammates from the sidebar roster
#8522 stopped one-shot subagents from squatting as idle rows, but named
background agents (Workflow/orchestration/ultracode lanes and agent-teams
teammates) still piled up permanent "Idle - <type>" child rows for the rest
of the session — the reported regression (11 idle rows under an
"Orchestration Messages" pane, all idle 3-6h after finishing).
Root cause, confirmed against live hook captures (claude 2.1.210): named
agents get teammate-shaped ids (a<name>-<hex>) AND now appear in Stop's
`background_tasks` as `type: "teammate"` entries whose status stays "running"
forever — even after the agent finished. The old code read that shape as a
"resumable teammate", so SubagentStop only marked it idle and the fold never
reaped it (a present teammate task kept hasTeammateTypedTask true). The rows
never left.
Fix: the roster now tracks only WORKING children.
- SubagentStop removes the child outright (teammate-shaped or not) — it is
the reliable finish signal; the teammate task's "running" status is not.
- TeammateIdle removes by name as the fallback when a SubagentStop is lost.
- A lead Stop's background_tasks still reaps unlisted children: hyphen-free
one-shots always, and teammate-shaped rows once a complete inventory shows
no teammate-typed task at all. A live named agent whose id never appears is
kept only while a teammate-typed task is still present (the done-gate).
- Hydration drops persisted idle snapshots so a restart can't re-pile them.
Verified live in a dev Electron instance driving a real Claude TUI that spawns
four named background agents: pre-fix the pane resolves to done with four
persistent "Idle - <probe>" rows; post-fix each row disappears the instant its
agent finishes and the roster drains to empty (done, zero child rows).
Tests: roster + row-lifecycle + hook-listener suites rewritten to the
working-only semantics, grounded in the captured 2.1.210 hook stream
(126 passing). Typecheck + oxlint clean.
* fix(agent-status): prune persisted idle Claude children
* fix(agent-status): persist Claude idle-row hydration cleanup
* fix(agent-status): avoid ambiguous teammate idle cleanup
* fix(agent-status): reconcile replacement children at roster cap
Reconstruct remote POSIX commands with bounded printf arguments so non-POSIX SSH login shells can forward them without requiring remote base64. Preserve relay and system-SSH stdin, and centralize login-shell flag selection for csh/tcsh compatibility.\n\nValidated against real csh and tcsh OpenSSH targets with built-in and system SSH, including cold relay deployment, stdin upload, PTY I/O, file mutation, and reconnect.
Re-pairing a desktop that was already paired created a duplicate host card (STA-1840). Pairing now resolves the durable host identity by the desktop's pinned publicKeyB64 and reuses the existing id/name, collapses any already-stored duplicates for that key, clears stale relay overlays on a direct-only re-pair, fails closed on unreadable storage, and closes the host's client on pairing success so a reused id reconnects on the newly-paired endpoint. Mobile only. Full mobile suite (1,719 tests) + typecheck/lint/format pass.
* feat(ssh): support Kerberos/GSSAPI hosts via the system OpenSSH transport
ssh2 has no gssapi-with-mic support, and adding it would mean forking its
protocol layer plus packaging the kerberos native module for three
platforms. Instead, route GSSAPI hosts through the existing system-OpenSSH
transport, which delegates Kerberos (tickets, SSPI on Windows) to the
platform ssh binary.
Two tiers, because RHEL-family distros enable GSSAPIAuthentication
globally in /etc/ssh/ssh_config and ssh -G therefore reports it for every
host:
- Targets whose ~/.ssh/config Host block explicitly sets
GSSAPIAuthentication yes (imported as target.gssapiAuthentication) try
system ssh first, falling through to ssh2 so key auth and credential
prompts still work when no ticket is available.
- When ssh2 exhausts key/agent auth and the ssh -G-resolved config
enables GSSAPI, retry over system ssh before prompting for credentials,
so Kerberos-only hosts on distro-default configs connect without a
password prompt. Hosts where keys work never leave the ssh2 path.
Manual targets flagged for GSSAPI pass -o GSSAPIAuthentication=yes
explicitly since they bypass ssh_config. Both tiers work headless (no
credential callbacks required).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(ssh): harden GSSAPI transport selection (review fixes for PR #7507)
Review fixes on top of the Kerberos/GSSAPI feature branch (s546126/kerberos-ssh):
- HIGH: reset useSystemSshTransport on the ssh2 fall-through. doSystemSshProbe
sets the flag before spawnSystemSshCommand, which throws synchronously when no
system ssh binary is on PATH (outside the probe try/catch). The proactive
fall-through previously reset only 2 of 3 transport fields, so exec/sftp kept
routing through the failed transport - breaking GSSAPI on Windows-with-Git-ssh
and headless Linux.
- MEDIUM: throw a cancellation error (not the stale ssh2 authError) when a
disconnect supersedes the reactive probe mid-flight, and guard connect()'s
catch on disposed, so a deliberate disconnect is not overwritten with
auth-failed.
- MEDIUM: skip the encrypted-key passphrase prompt when the GSSAPI fallback
applies, so a Kerberos ticket is tried before prompting; the general prompt
still fires if the probe fails.
Adds 3 mutation-verified regression tests and hardens two existing tests to
assert the probe actually ran. Not connected to any PR remote.
Co-authored-by: Orca <help@stably.ai>
* fix(ssh): isolate GSSAPI system transport
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: s546126 <268420947+s546126@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix(mobile): detect and repair overriding Windows Firewall Block rules for pairing
Firewall inspection now reports an overriding inbound Block rule as
blocked instead of false success, the UAC repair removes only
conflicting rules for the current Orca executable, TCP pairing port,
and Private profile before recreating the scoped allow rule, and the
notice re-inspects Windows policy after repair instead of optimistically
reporting success. Stale focus-triggered inspections can no longer
overwrite a newer result during UAC elevation.
Fixes#8371
* fix(mobile): inspect the ActiveStore so GPO firewall rules are visible
Without -PolicyStore ActiveStore the NetSecurity queries read only the
local persistent store, so a GPO-applied Block rule was invisible and
the post-repair re-inspection could report a false success on managed
hosts.
- Replace the force-open Tooltip discovery hint with a Popover (title,
body, Try it/Got it actions) that can be dismissed via outside
click, Escape, or window blur — Radix's tooltip couldn't handle
Electron webview clicks, which never reach the renderer document.
- Gate the hint on a new `surfaceActive` prop so it only opens for the
visible pane, preventing a portaled layer from anchoring against a
hidden/zero-size trigger at the viewport origin.
- Add locale strings for the new badge/try/dismiss copy across all
supported languages and cover the hook's eligibility/dismiss
behavior with unit tests.
Two renderer paths let Promise rejections escape unhandled, where the
crash-breadcrumb system retains them and grows the heap until the renderer
white-screens (#8260):
- The terminal file-link provider fires a `void Promise.all(...)` whose async
mappers probe path existence over SSH. On disconnect these reject with
"Remote connection dropped/reconnecting"; add a `.catch` that resolves the
callback with no links so the rejection is handled.
- "ResizeObserver loop completed" is a benign Chromium quirk; suppress it in
crash-diagnostics so it stops filling the breadcrumb buffer and inflating
the renderer error count.
Scope note: the original fix for #8260 also proposed Windows pty:kill signal
handling (killPtyProcess / isPtyAlreadyGoneError) and a ResizeObserver
double-rAF. Those landed on main independently (Windows kill handling by
v1.4.135; the pane-title-overlay rect-equality guard from #2756 already breaks
the loop at the source), so this change carries only the two guards still
missing upstream.
Co-authored-by: Yixian HU <yixian@YixiandeMacBook-Air.local>
Co-authored-by: Claude <noreply@anthropic.com>