- Centralize and align auto-merge eligibility logic across web and
mobile clients.
- Use the `enablePullRequestAutoMerge` GraphQL mutation instead of
`gh pr merge --auto` to prevent immediate merges on clean branches.
- Fall back to `gh pr merge --auto` when a merge queue is required on
the base branch.
- Hide the auto-merge control when only optional checks are pending.
Previously, the AI Vault only blocked resume actions for workspaces with
an active SSH connection (checking `connectionId`). This allowed resume
actions to run on runtime-owned workspaces, which are non-local but do
not use SSH.
To resolve this:
- Introduce `getAiVaultResumeWorkspaceTargetStatus` to classify targets
based on both `connectionId` and `executionHostId`.
- Restrict AI Vault panel actions, session resume checks, and drop layers
to local workspaces.
- Preserve the `executionHostId` on project groups during normalization to
ensure runtime-owned groups retain their execution host status across
persistence reloads.
Avoid forcing the active view back to the creation panel when background
worktree preflight completes after the user has already navigated away.
- Add a `revealCreationSurface` option to `continueBackgroundWorktreeCreation` to skip switching views.
- Check both `activeView` and `activePendingCreationId` to determine if the creation UI is actually visible.
- Use this option when kicking off background creation for GitHub work items.
Windows runs managed hooks through a shell, and #6078 wrapped the
launcher in `powershell -EncodedCommand` to survive spaces in profile
paths. Combined with the inner PowerShell Invoke-WebRequest post, every
hook spawned two PowerShell processes (~300ms startup each), so a hook
took ~650ms+ and fired up to 6x per turn. Codex 0.140 renders that as
lingering "Running <event> hook" rows. The earlier RC worked around it
by deleting SessionStart/UserPromptSubmit/Stop, which loses lifecycle
status fidelity.
Keep all six Codex events and make them fast instead:
- Codex runs hooks as `cmd.exe /C <command>` and forwards our string
verbatim when it has no spaces/quotes, so emit the bare .cmd path for
cmd-safe profiles (zero shell startup) and fall back to the encoded
PowerShell launcher only for spaced/metachar paths (#6078 robustness).
- Replace the inner PowerShell post with curl.exe (Windows 10 1803+),
posting the same form fields as the POSIX hook and reading the raw
payload from stdin via `--data-urlencode payload@-` so UTF-8 (e.g. CJK)
survives without code-page translation.
Result: the common Codex case is 0 PowerShell (~70-150ms vs ~650ms);
spaced-path profiles drop to 1.
Claude runs hooks through Git Bash, so its launcher must stay
PowerShell-encoded (a bare path is what breaks it), but its inner post
moves to curl.exe too, cutting Claude from two PowerShell startups to
one.
Validated against the real Codex 0.140 binary (interactive TUI + exec):
all managed hooks fire, render briefly, and clear with no lingering
rows; the listener receives every post in 1-6ms.
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(automations): track exact run terminal targets
Record terminal pane keys and PTY ids on automation dispatches, persist them across run updates, and propagate them through runtime launch results.
Use the recorded pane and PTY for completion detection, session reuse, prompt submission, and View run navigation so split-pane tabs reopen the actual run terminal.
Keep legacy runs compatible by falling back to workspace resume when exact terminal identity is absent.
* chore: address automation targeting review cleanup
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Update the pill and badge styles for GitHub PR statuses and check runs
to use muted background washes with theme-appropriate text colors. This
replaces solid high-contrast backgrounds with soft backgrounds, and
fixes low-contrast text in light mode by using darker foreground colors.
* fix(ports): stop cursor-move redraws corrupting advertised dev-server hosts
The Live Ports panel showed `localhst:5199` (and opened a broken URL with the
missing `o`) for a dev server that printed `http://localhost:5199`.
AdvertisedUrlWatcher cleans raw PTY bytes with stripTerminalControls, which
*deletes* ANSI/cursor sequences instead of emulating them. CLIs that redraw a
line differentially step the cursor forward over characters already on screen
(`ESC[1C`) rather than reprinting them; a real terminal renders the underlying
glyph, but deleting the move splices the two text runs together and drops the
skipped cell — `http://localh` + `ESC[1C` + `st` collapses to `localhst`.
`new URL()` then accepts the corrupted, plausible-looking host verbatim, so it
gets cached, displayed, copied, and opened.
Neutralize horizontal cursor moves (forward/back `C`/`D`, absolute column `G`,
position `H`/`f`) to a space before the CSI delete pass, so the URL candidate
matcher breaks at the seam and can't fuse a corrupted hostname. Worst case we
skip that frame and fall back to the kernel bind, which is the safe default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(ports): document stripTerminalControls
Add a docstring to the exported helper to clear CodeRabbit's docstring
coverage warning and explain why horizontal cursor moves are neutralized.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(ports): invalidate cursor-redrawn URL candidates
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix: handle native Windows skill update flow for Orca setup
- Rewrite npx skills update <skill> --global to the repo reinstall path on native Windows hosts.
- Keep the WSL runtime path unchanged so Linux/WSL setup behavior stays intact.
- Update the affected runtime helper tests to cover the Windows fallback.
- Adjust the orchestration pane test expectation to match the Windows-host command rewrite.
- Scope the change narrowly to the issue path to avoid impacting unrelated skill setup flows.
* fix: cover Windows skill update fallbacks
---------
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
* Fix ReDoS in terminal file-path link detection that froze the app (#5970)
A full-screen TUI such as ngrok, run through Windows ConPTY, emits its
dashboard as a single newline-free logical line that is almost entirely
alignment spaces. xterm accumulates it into one ~150k-char logical line,
and on every hover/redraw Orca's file-path link providers scan that line.
The spaced-path lookaheads (SPACED_PATH_WITH_SEPARATOR_REGEX and
LINE_ENDING_SPACED_PATH_REGEX) began with `[^...]*\s+`, where the negated
character class also matches whitespace. That overlap let the engine split
a long run of spaces in exponentially many ways before failing, so a
~5k-char prefix took ~25s and pegged the renderer main thread, freezing
the whole app. macOS uses a normal PTY and never builds that line, so it
was unaffected; disabling terminal GPU acceleration did not help.
Anchor the first lookahead segment at the first whitespace (add `\s` to
the negated class) so it can no longer overlap the following `\s+`. The
matches are identical; the scan drops from ~25,000ms to ~4ms.
Adds a regression test asserting extraction stays roughly linear on long
space-heavy lines.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix terminal link ReDoS guards
* Trim terminal link padding
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
* Adopt pending terminal tab reveals
* Materialize pending remote terminal tabs
Wait for mobile terminal creates to produce a ready PTY handle before resolving. If the renderer only publishes a pending tab shell, materialize a headless PTY into the same tab/leaf identity so later renderer focus adopts it instead of duplicating the tab.
Add a pane-key spawn reservation shared by runtime materialization and renderer pty:spawn so focus racing fallback reuses the winning PTY, including when SSH env stripping removes ORCA_PANE_KEY. Cover the pending-surface fallback and both overlapping spawn race directions with regression tests.
* Settle pane spawn reservation on any post-spawn failure
The per-paneKey spawn reservation was only settled on spawn error, persist
error, or final resolve. A throw in the post-spawn region (seedHeadlessTerminal,
registerPty, rememberPaneKeyForPty, track) rejected the IPC promise but left the
reservation in paneSpawnReservationsByPaneKey forever, so every later spawn for
that pane awaited a promise that never settled and hung.
Wrap each post-reservation body (both spawn paths) in a catch-all that rejects
the reservation with the real error and rethrows; reject is a no-op once
resolved. Remove the now-redundant inner reject calls. Add regression tests for
both paths.
* Tear down runtime-owned headless tabs on mobile session close
The renderer-attached branch of closeMobileSessionTab closed the renderer's
pane but never pruned mobileSessionTabsByWorktree or dropped the persisted
binding. For runtime-owned headless terminals — serve/SSH materialized, or a
pending shell the renderer never adopted, all introduced by the pending-surface
materialize fallback — syncMobileSessionTabs then re-hydrates the closed tab
from the persisted session, resurrecting it with a live PTY. "Close others" on
a paired client showed closed remote tabs reappearing with their sessions still
running.
Add isRuntimeOwnedHeadlessMobileTab (serve/SSH-owned, or no live PTY and absent
from the renderer graph). When the whole parent of such a tab is closed, route
through closeHeadlessMobileTerminalTab to kill the PTY, remove the persisted
binding, and prune+emit, then best-effort notify the renderer so no adopted
pane is left dead. Genuinely renderer-owned tabs and exact split-leaf closes
keep the existing path. Cover the serve parent close, renderer-published vs
runtime-unadopted pending tabs, and the serve split-leaf case with regressions.
* Tear down only headless tabs the renderer never published on mobile close
The close-others teardown discriminator returned false for any resolved
non-serve/ssh PTY, so headless tabs carrying a daemon session id
(<worktreeId>@@<shortUuid>) that the host materialized but the renderer never
published leaked into the session snapshot and the client mirrored them
(confirmed live: host published 5 tabs for a worktree the renderer showed 1 for).
That id shape is ALSO minted for ordinary renderer-owned daemon-backed local
terminals, so it can't classify ownership by shape — the renderer graph
(this.tabs) does. Classify a tab as runtime-owned when it is serve/ssh (always,
they're preserved + re-hydrated) or when the renderer graph never published it
(a leaked/unadopted shell); delegate everything the renderer graph lists,
including ordinary @@ local terminals and pending tabs.
Regression tests: renderer-owned @@ tab is delegated (not de-persisted); leaked
@@ tab the renderer never published is torn down + de-persisted.