Commit Graph

5700 Commits

Author SHA1 Message Date
Brennan Benson 7df09f2f4c
Restore agent terminal screen on hibernation wake (#6833)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 01:02:11 -07:00
Brennan Benson 5b7611ddcb
fix(win): release PR-refresh aliases when a worktree is removed (#6861)
The OOM reports (F0BDMD16LJ2 and the taifunk many-worktree sessions)
show memory creeping over long sessions with churning worktrees. One
contributor: in pr-refresh-coordinator, many local worktrees that track
the same linked PR coalesce into a single queue entry whose 'aliases'
map keeps one entry per worktree. Aliases were only pruned when a
candidate was re-enqueued as invalid — never when a worktree was simply
removed/closed — so the maps grew unbounded across a session.

Add pruneWorktreePRRefreshAliases(worktreeId) and call it from
removeWorktreeMetadataAndTransientState (the existing central
worktree-removal cleanup, alongside removeWorktreeMeta /
forgetWorktree / deleteWorktreeHistoryDir). It drops the removed
worktree's aliases, deletes the queue entry when none remain, and
rebinds the representative candidate if the removed worktree owned it.

Covered by 3 new coordinator tests (accumulate-then-prune, keep-entry-
on-remaining-aliases with candidate rebind, no-op for unknown worktree)
plus two test-only inspection helpers.

Co-authored-by: Neil <neil@stably.ai>
2026-06-30 00:55:54 -07:00
Brennan Benson 9078ecaef5
fix(win): record a redacted breadcrumb when fs:readDir throws (#6862)
The user report F0BDXH978GJ surfaced 'Error invoking remote method
fs:readDir' — Electron's opaque message when the main-process handler
throws. On Windows this is typically a WSL \wsl$ / \wsl.localhostUNC path or network drive failing realpath/readdir after the distro or
share goes away, or a dropped SSH provider. Nothing recorded which throw
site fired or what kind of path was involved, so the crash report
carried no actionable cause.

Wrap the fs:readDir handler to record an 'fs_readdir_error' breadcrumb
on throw, tagging the throw site (ssh-provider | authorize | readdir),
the error name/code, and a REDACTED path shape (isUNC, isWsl,
driveLetter, hasConnectionId) — never the raw path. The error is
re-thrown unchanged, so renderer behavior is identical; only crash
reports gain structured context.

Pure classification lives in readdir-error-diagnostics.ts (8 unit tests
covering WSL UNC, \wsl$, network share, drive letter, SSH, and
no-path-leak); 4 handler tests assert the breadcrumb fires per throw
site and not on success.

Co-authored-by: Neil <neil@stably.ai>
2026-06-30 00:28:07 -07:00
Brennan Benson 60412362a1
fix(win): stop renderer crash-loop with an auto-recovery circuit breaker (#6856)
A deterministic per-load renderer fault (bad GPU driver, corrupt chunk,
AV interference) crashes on every load. Orca auto-reloads recoverable
renderer deaths after 250ms, so without a limit it reloads every
~0.25-1.3s forever — the Windows clusters F0BDRAZN55L (launch-failed
exit 18, bootstrap loop ~1.3s) and F0BDPCL93UM (ACCESS_VIOLATION on
Win10 1909, ~0.8s loop). shouldRecoverRendererAfterProcessGone only
gated integrity-failure/launch-failed, never 'crashed'/'killed'.

Add a rolling-window circuit breaker (3 recoveries / 60s) consulted at
the reload point in createMainWindow. When it opens, Orca stops
auto-reloading, records a renderer_recovery_circuit_breaker_open
breadcrumb, and shows a native Reload/Quit prompt (the renderer is dead,
so a main-process dialog is the only available surface). The window is
NOT reset on did-finish-load: a crash loop renders on every cycle before
dying, so stale attempts must age out by time instead.

Covered by renderer-recovery-circuit-breaker.test.ts (pure helper) and a
createMainWindow.test.ts integration test that drives the loop and
asserts reloads stop after the limit.

Co-authored-by: Neil <neil@stably.ai>
2026-06-30 00:26:29 -07:00
Brennan Benson e08df5f98a
fix(win): guard xterm link providers so a RangeError can't kill the renderer (#6855)
A synchronous throw inside any terminal link provider's provideLinks
escapes to window.onerror and gets the renderer killed (reason=killed,
exit 1). The reported crash (F0BDKBHDAUE) is xterm web-links'
LinkComputer._getWindowedLineStrings raising 'RangeError: Invalid array
length' while scanning a pathological wrapped line during agent CLI
output (opencode).

Patch terminal.registerLinkProvider at construction so every provider
registered afterward — the web-links addon's internal provider plus
Orca's file-path and terminal-handle providers — has its provideLinks
wrapped in a try/catch that records a crash breadcrumb and degrades to
'no links this hover' instead of throwing.

Covered by terminal-link-provider-guard.test.ts (reproduces the
RangeError and asserts it no longer escapes).

Co-authored-by: Neil <neil@stably.ai>
2026-06-30 00:24:30 -07:00
Dhilip Subramanian 9694830764
Document headless Linux server setup (#6802)
* docs: add headless Linux server guide

* docs: add ldd/appimage-extract tip for diagnosing missing libraries

Salvaged from #6817 before closing it as a duplicate.

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

---------

Co-authored-by: Jinwoo-H <jinwoo@stably.ai>
Co-authored-by: Orca <help@stably.ai>
2026-06-30 00:04:47 -07:00
Jinwoo Hong b44606f023
Fix floating workspace editor ownership (#6859) 2026-06-30 02:59:19 -04:00
Neil f9e18910ae
chore(lint): adopt unicorn/prefer-import-meta-properties (error) (#6847)
Migrate fileURLToPath(import.meta.url) / dirname(...) boilerplate to the
native import.meta.dirname / import.meta.filename, then enable the rule
at error so new code stays on the native form.

The oxlint autofix rewrites the expression but leaves the now-unused
node:url / node:path imports behind (which the already-enabled
no-unused-vars=error would then flag), so this commit also removes those
34 orphaned imports — trimming the named import where other names are
still used, deleting the line where it was the sole import.

Scope is build scripts + Node-env tests only (config/scripts, tools/
benchmarks, *.test.{ts,mjs}, vitest configs); zero shipped runtime code.
The native properties are exact equivalents (Node >= 20.11; repo is on
24), so behavior is unchanged.

Verified: oxlint 0 errors tree-wide (root + mobile), oxfmt clean,
typecheck (node+cli+web) + mobile tsc pass, root vitest 22825 passed /
0 failed, mobile vitest 1018 passed. Exercised the rewritten scripts
directly: build:relay (6 targets), ensure-native-runtime,
verify-macos-entitlements all run correctly with import.meta.dirname.
2026-06-29 23:37:30 -07:00
Neil 2f5f7daa03
fix: recover corrupt lazy-chunk parse errors instead of crashing the boundary (#6850)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 23:34:06 -07:00
Neil f8d52f72e5
fix(browser): mount floating-workspace browser webview via a slot viewport root (#6854)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 23:29:54 -07:00
Neil 3b5390acd9
fix(mobile): bump session max-lines ratchet to match file size (#6851)
mobile/app/h/[hostId]/session/[worktreeId].tsx grew past its 4988
counted-line ratchet (now 5015) in #6659 ("Show the git primary action
on mobile Source Control") without the override being bumped. That PR's
mobile CI passed because it branched off stale main where the file was
smaller; once merged, main went red for mobile lint — but mobile.yml
only runs on PRs touching mobile/, so no main-push build caught it.

Bump the per-file override 4988 -> 5015 to match the file's actual size
(what #6659 should have done), restoring green on every mobile-touching
PR. Per AGENTS.md the file should not carry a max-lines disable; this
keeps the tight per-file ratchet. The file is a candidate for a future
split, but that's a separate, owner-driven refactor.

Verified: mobile oxlint 0 errors, root oxlint 0 errors.
2026-06-29 23:24:35 -07:00
Brennan Benson 8e06ee113c
Prevent regressions in Windows local project adds (#6815)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:39:32 -07:00
Neil 46646d7ff1
chore(lint): upgrade oxlint to 1.71 + enable 7 new rules (autofixed backlog) (#6841)
* chore(lint): upgrade oxlint to 1.71 and enable 7 new rules

Upgrade oxlint 1.67.0 -> 1.71.0 (1.72 was blocked by the repo's 3-day
minimum-release-age supply-chain guard; nothing here needs it). The
bump is a no-op on the existing config.

Enable 3 error rules (backlog autofixed to zero in this commit) and
4 warn rules (surface signal without gating CI):

error (autofixed, behavior-preserving):
- unicorn/prefer-node-protocol        (~1531 sites: bare builtin -> node:)
- typescript/no-import-type-side-effects (~36: all-inline-type -> import type)
- unicorn/no-array-reverse            (19: copy-then-reverse -> toReversed)

warn (real signal, current fires are test-only/correct):
- unicorn/no-array-fill-with-reference-type  (aliasing footgun guard)
- typescript/no-unsafe-function-type         (bans bare Function type)
- unicorn/prefer-array-flat-map              (map().flat() -> flatMap())
- unicorn/prefer-regexp-test                 (.match() in bool ctx -> .test())

mobile/.oxlintrc.json extends root, so it inherits all 7; the autofix
ran from root and covered mobile/ too.

Verification (all green): oxlint 0 errors (root+mobile+aux configs),
oxfmt clean, typecheck (node+cli+web), vitest 22795 passed / 0 failed,
builds (electron-vite + web + cli) succeed. node: rewrites confirmed to
skip embedded SSH/CLI string payloads (AST-only); all toReversed sites
verified to operate on fresh copies or write-once locals.

* chore(lint): bump mobile oxlint to 1.71 so inherited rules parse

mobile/ is a standalone pnpm project pinning its own oxlint@1.67, which
lacks unicorn/no-array-fill-with-reference-type (needs >=1.70). Since
mobile/.oxlintrc.json extends the root config, mobile CI's 'cd mobile &&
oxlint' failed to parse the new rule. Bump mobile to match root (1.71).

Verified in mobile/: oxlint 0 errors, oxfmt --check clean, tsc --noEmit
pass, vitest 978 passed / 0 failed.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:38:29 -07:00
Neil 0476109e2c
fix: keep a worktree's sole newborn terminal mounted when its PTY dies on startup (#6842)
A worktree created from a PR whose branch ships an .envrc with a failing
direnv command bounced the user straight back to the Landing screen. The
worktree's only terminal spawns in the worktree cwd, direnv runs on shell
startup, fails, and the login shell exits non-zero immediately. The
single-pane PTY-exit branch routed that through onPtyExitRef ->
handlePtyExit -> closeTerminalTab, which deactivated the just-created
worktree (setActiveWorktree(null)) and rendered Landing.

The existing newborn-death guard only protected freshly-split panes, never
the first/sole terminal. Track the freshly-spawned ptyId (onPtySpawn fires
only for fresh spawns, never reattach/coldRestore) and, in the sole-pane
branch, keep the dead pane mounted when a never-interacted fresh spawn
exits. A typed 'exit' or a reattached-dead session still tears down as
before. Not gated on hasReceivedPtyOutput on purpose: a failing direnv
prints its error first, so output is received.

Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:36:42 -07:00
Brennan Benson a6f12f6120
Show the git primary action on mobile Source Control (#6659)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:30:46 -07:00
Neil 6130340229
fix: answer startup terminal color queries (#6824) 2026-06-29 21:37:49 -07:00
Neil bf274fd8a9
Fix startup routing test for diagnostic wrappers 2026-06-29 21:37:27 -07:00
Vladislav Meshkorudnyj e82dce4382
Fix/remote skill install floating terminal (#6816)
* fix(terminal): scope skill-install terminals to the floating runtime selector (#6789)

Inline setup/onboarding terminals (skill installers, feature tips) create a
PTY under a synthetic per-panel worktree id. On a remote runtime the remote
PTY transport sent that id as `id:<panel>` to `terminal.create`, which the
runtime cannot resolve, so installing a skill via Settings failed with
selector_not_found. Locally it worked because the IPC spawn uses cwd directly
and never resolves the selector.

These terminals are ephemeral floating terminals with no backing worktree, so
brand their id and resolve it to the floating-terminal selector
(global-floating-terminal), which every runtime already maps to the home dir.
Local tab isolation keeps the distinct per-panel id; only the runtime terminal
selector changes. The server is unchanged.

* docs(terminal): add JSDoc for functions touched by the skill-install terminal fix

Document the new ephemeral setup-terminal id helpers, the runtime terminal
selector, and the onboarding/remote-transport entry points so the changed
functions carry contract-level docstrings.

---------

Co-authored-by: vladmesh <vladmesh@gmail.com>
2026-06-29 20:38:11 -07:00
Neil 380db44d77
Measure and batch restored terminal startup (#6836) 2026-06-29 20:37:26 -07:00
Neil 220d5cb7fe
Prevent and recover from degraded terminal daemon spawns
Adds daemon PTY-spawn health classification, POSIX daemon cwd repair before terminal spawn, and degraded-daemon fallback routing so fresh terminals keep opening without killing preserved sessions.
2026-06-29 20:17:46 -07:00
Neil 16ce1aa73d
perf(startup): lazy-load locale catalogs + mermaid (−5.40MB / −31% eager cold-start JS) (#6804)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 20:02:28 -07:00
Neil 30fc4859e2
fix: reject mobile-scope web pairing and surface forbidden runtime errors (#6581)
Fixes #5508.

Rejects mobile-scope phone-QR pairing in the full web client, keeps runtime browser access links on the instant startup path via advisory pairing scope metadata, and surfaces forbidden runtime scope errors instead of rendering empty workspaces or retry-looping setup checks.

Security note: pairing offer scope is UI metadata only. Runtime RPC authorization remains based on the server-side device token registry and mobile allowlist.
2026-06-29 19:06:59 -07:00
Neil 4776ac1fe5
fix: include legacy commit statuses in PR checks (#6556)
Co-authored-by: Alexander Kirilin <github@alexanderkirilin.com>
2026-06-29 19:04:09 -07:00
Neil 499b900f1b
Remove unused dead-code exports (#6821) 2026-06-29 18:32:56 -07:00
Neil 24fa9860a6
Polish terminal context menu shortcuts (#6809)
* Polish terminal context menu shortcuts

* Polish terminal split menu shortcuts
2026-06-29 18:30:57 -07:00
github-actions[bot] 88d42acf64 Update README downloads badge 2026-06-30 01:19:26 +00:00
Neil 61503b7666
refactor(command-code): split managed hook script (#6807)
* refactor(command-code): split managed hook script

* fix(command-code): include split script in cli typecheck
2026-06-29 18:13:45 -07:00
Neil e2b1386544
refactor(telemetry): split client lifecycle tests (#6813) 2026-06-29 18:09:33 -07:00
Brennan Benson 3eb8d152e0
Prevent false mobile reconnects during active runtime traffic (#6805) 2026-06-29 18:08:16 -07:00
Neil 846d5749b7
refactor(mobile-markdown): split bridge save guard tests (#6811) 2026-06-29 18:04:58 -07:00
Neil bdc8b2a1ca
refactor(pr-context): split guard tests (#6810) 2026-06-29 18:04:36 -07:00
Neil cd9744d43f
refactor(quick-open): split ripgrep guidance (#6808) 2026-06-29 18:04:28 -07:00
Neil 669ff13467
fix: allow duplicate review worktrees (#6812) 2026-06-29 18:02:10 -07:00
github-actions[bot] 8c49426224 release: v1.4.109-rc.0 2026-06-30 00:18:10 +00:00
Brennan Benson f9701a73a9
Stop new terminal tabs from closing right after they open (#6801)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 17:06:01 -07:00
Jinwoo Hong 34c9c117e5
feat(native-chat): per-leaf toggle eligibility + composer UX (paste, draft, scrollbar, focus) (#6783)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 17:03:10 -07:00
Kaylee a06a17b6ee
Improve toast layout and dev tools (#6782)
Restyle shared Sonner toasts (wrapping, bottom-chrome clearance with mobileOffset, custom delete-failure footer) and add a dev-only Dev Tools settings pane gated behind import.meta.env.DEV. Removes dead devToolsSearch locale keys, aligns toast description opacity/width with sibling toasts, and uses a distinct nav icon for Dev Tools.
2026-06-29 17:02:44 -07:00
Brennan Benson a27278dbea
Prevent sleeping agents from getting stranded in stale terminals (#6800)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 16:49:18 -07:00
Brennan Benson 63df8e23cf
Follow the active terminal's worktree in the Checks panel (#6799)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 16:38:18 -07:00
Jinjing 7caa582841
Show coding agent icons on mobile terminal tabs (#6792)
* Show coding agent icons on mobile terminal tabs

Move agent title decoration and terminal title parsing utilities
from the desktop renderer to shared code for reuse on mobile.

* Extract agent title stripping and terminal agent resolution to shared
* Implement mobile agent identity resolution and title-cleaning helpers
* Render agent icons on mobile terminal tabs when an agent is active
* Strip leading status glyphs from tab titles when showing an icon

* Suppress PTY resize on resume for mobile-driven terminals

Avoid reasserting the PTY size on resume if desktop resizing is
suppressed. This prevents overriding the intentional drift from
desktop dimensions for parked or mobile-driven terminals.
2026-06-29 16:06:27 -07:00
Brennan Benson 53e2582cbe
Keep new terminal tabs open during startup (#6796)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 16:04:31 -07:00
Brennan Benson 08e824dda9
Hide Jump to Worktree for sessions in the current worktree (#6791)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 16:03:24 -07:00
github-actions[bot] ab1aac2bda release: v1.4.108-rc.1 [rc-slot:2026-06-29-15] 2026-06-29 22:27:49 +00:00
Brennan Benson 90d3d7a0e5
Reduce CPU from source-control git polling on Windows (#6736)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 15:25:13 -07:00
Brennan Benson 52d51fe828
Keep mobile-fit terminals at phone size during post-spawn size sync (#6794) 2026-06-29 15:24:50 -07:00
Jinjing a978222184
Clarify auto-merge UI and errors when direct merge is available (#6777)
GitHub rejects enabling auto-merge on a PR that is already mergeable
with a "Pull request is in clean status" error.

* Suppress "Enable auto-merge" option in the UI when direct merge
  is available, while retaining "Disable auto-merge".
* Translate the GitHub "clean status" GraphQL error into an actionable
  message recommending direct merge.
2026-06-29 14:40:53 -07:00
Brennan Benson 584cec78c3
fix(mobile): fail fast when iOS App Store train is closed (#6633)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 14:08:23 -07:00
s546126 3f39d7548b
Recommend Tailscale when the remote Orca runtime is unreachable (#6637)
* Recommend Tailscale when the remote Orca runtime is unreachable

When a remote-runtime connection fails (RemoteRuntimeClientError "Could not
connect to the remote Orca runtime."), append an actionable Tailscale hint to
the user-facing error, branched on whether the endpoint is already on a tailnet:

- Non-Tailscale endpoint: recommend connecting both devices over Tailscale and
  pairing with its Tailscale address, with a download link.
- Tailscale endpoint (*.ts.net or 100.64.0.0/10): point at the real causes —
  server offline on the tailnet, or Funnel reverted to tailnet-only — and note
  that already-paired devices reconnect without re-pairing.

Applied at the desktop transport chokepoint (status probe, in-use calls, and
subscriptions — connection failures reject, so the hint is applied to the thrown
error, not just ok:false responses) and at the web client's connect/timeout
sites. New pure shared helper mirrors withMacTailscaleDnsHint.

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

* Address review: scope CGNAT hint to IPv4 literals, track re-paired endpoint

- isTailscaleEndpoint: gate the 100.64.0.0/10 check on a full IPv4 literal so
  DNS names like 100.64.0.1.example.com no longer get tailnet-specific advice.
- callRuntimeEnvironment: capture the endpoint the queued closure actually used,
  so a re-pair between enqueue and dispatch can't append the wrong hint.

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

* Recognize Tailscale IPv6 endpoints and trailing-dot FQDNs in hint

The remote-runtime Tailscale hint classified IPv6 Tailscale nodes
(fd7a:115c:a1e0::/48) and trailing-dot FQDNs as non-Tailscale, so a
user already reaching their server over Tailscale by IPv6 literal was
wrongly told to 'connect both devices to Tailscale'. Pairing endpoints
can carry bracketed IPv6 literals (resolvePairingEndpoint), so this is
a reachable path. Normalize the extracted host (strip brackets and the
trailing FQDN dot) and add an IPv6 ULA-range check.

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

---------

Co-authored-by: s546126 <268420947+s546126@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-06-29 13:41:13 -07:00
github-actions[bot] 004b4d2991 release: v1.4.108-rc.0 2026-06-29 20:39:08 +00:00
Jinwoo Hong 22b00a7cd2
fix(terminal): report PTY's applied size so dropped resizes self-heal (split-mount desync) (#6785)
Co-authored-by: Orca <help@stably.ai>
2026-06-29 13:35:43 -07:00