* Keep long live session logs stable while updating
* fix(editor): normalize content before append sync
* chore(editor): export e2e probe type and link gate motivator
Post-review cleanup: env.d.ts referenced the probe's method shape as an
inline literal, so a probe rename would only surface in the e2e spec;
the new reliability gate's motivatingLinks pointed at the repo root.
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
- Late child/parent settlements now report individually instead of
being batched into a single combined result, so toasts and
onLateResult callbacks reflect actual per-candidate outcomes.
- Post-batch reconciler retains only unresolved provisional-ancestor
state instead of the full batch arrays, and releases it once no
provisional ancestor remains, avoiding unbounded retention for
long-hung IPC promises.
- Unblocked ancestors retried post-batch now go through the same
timeout/settlement tracking as in-batch removals, including
further late settlement if the retry itself hangs.
- Validate each remote path segment (name, symlink target, directory
entry) via assertSafeRemotePathSegment before it reaches the remote
filesystem, since Windows canonicalizes reserved device names and
NTFS streams in ways POSIX checks miss.
- Extract directory pre-scan/upload logic into
filesystem-import-ssh-directory.ts and add captureLocalUploadRoot to
detect a selected root swapped out from under an in-progress import.
- Add path-safety tests covering traversal, reserved Windows names,
and TOCTOU root replacement.
* fix(terminal): preserve Linux IME candidate digits
* fix(terminal): preserve overlapping Linux IME keys
* docs(terminal): document Linux IME candidate state
* docs(terminal): describe IME candidate event handling
* docs(terminal): clarify Linux IME state callbacks
* fix(terminal): harden Linux IME candidate fallback
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: yuqili03 <yuqili03@deeproute.ai>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* feat(diff): add F7/Shift+F7 keyboard navigation for diff changes
Stacks on the Previous/Next change buttons (#6668) to add keyboard
navigation for single-file diffs, matching VS Code / JetBrains diff review.
- Register editor.nextChange (F7) / editor.previousChange (Shift+F7) in the
keybinding registry (Editors group) so they show in Settings and stay
rebindable.
- Teach the keybinding normalizer function keys (F1-F24) and make them
first-class in the bare-key safety model (safe standalone or with Shift,
opt-in per action) - F7 was previously unbindable.
- Install a capture-phase listener from DiffNavigationProvider so keyboard
and the existing header buttons share one goToDiff path; works on
read-only and editable single-file diffs.
- Translate the Previous/Next change strings for es/ja/ko/zh.
Refs #6215
* test(diff): cover change navigation shortcuts
* fix(diff): use shortcut chips in navigation tooltips
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* feat(diff): add Previous/Next change navigation buttons to Diff View
Add up/down navigation buttons to the single-file Diff View toolbar so
users can jump between change regions (hunks) without scrolling, matching
IntelliJ/Android Studio. The buttons bridge the Monaco diff editor to the
header via an instance-scoped DiffNavigationProvider and call Monaco's
goToDiff('previous'|'next'); they disable when the file has no changes.
Closes#6215
Co-authored-by: Orca <help@stably.ai>
* test(diff): cover stale onDidUpdateDiff guard in fast-swap
Address CodeRabbit nitpick: prove that an update fired from a replaced
editor is ignored after a new editor registers (the subscription is
disposed on re-register). The fake editor's dispose now clears its
callback, matching real Monaco subscription semantics.
Co-authored-by: Orca <help@stably.ai>
* fix(diff): isolate navigation registration updates
* fix(diff): use arrows for change navigation
* fix(editor): tighten header action spacing
---------
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* perf(renderer): sweep suppressedPtyExitIds and pendingCodexPaneRestartIds on bulk worktree purge
Both are ptyId-keyed maps cleared alongside codexRestartNoticeByPtyId on the
normal pty-exit path, but buildWorktreePurgeState (remove-project / external
authoritative-scan / hydration-stale reconcile) runs no terminal teardown and
only swept codexRestartNoticeByPtyId and migrationUnsupportedByPtyId. A
suppression / pending-restart flag planted just before a doomed pty's exit
therefore stranded one entry per removed pty for the renderer session.
Add both to omitByPtyId, matching their two swept siblings; extend the
bulk-purge leak regression test to cover them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(renderer): cover dormant PTYs in bulk purge
* Fix worktree-purge PTY id leaks: proportional alias scan and stricter su
- purgeWorktreeTerminalState now short-circuits the surviving-alias scan
once every doomed remote handle alias is matched, instead of scanning
every surviving tab's terminals on each purge.
- Repo removal (removeRepo) no longer force-marks killed PTY ids as
suppressed/pending-restart; those tabs are gone before async exit
events fire, so retaining the guards just leaked entries.
- Update tests to cover raw remote-handle aliasing against surviving
local PTY ids and to assert the tightened cleanup behavior.
* Fix environment-scoped remote PTY id handling for guards and lifecycle s
- Canonicalize legacy remote PTY ids at attach time so guard/restart/notice
maps stay scoped per runtime environment instead of colliding on raw
aliases shared across environments.
- Migrate suppressedPtyExitIds, pendingCodexPaneRestartIds,
codexRestartNoticeByPtyId, and migrationUnsupportedByPtyId entries when a
tab's PTY id transitions from a legacy alias to its scoped id.
- Narrow shutdown/purge guard sets to renderer-visible PTY ids only, since
raw exact-stop RPC handles never emit pane exit callbacks and previously
caused cross-environment leakage and unnecessary alias scanning.
- Prevent a late PTY exit from resurrecting a ptyIdsByTabId entry for a tab
whose worktree/repo was already purged.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* fix(i18n): use useTranslation hook in SidebarNav for reactive language switching
Replace plain translate() calls with the useTranslation() hook so the
React.memo-wrapped SidebarNav re-renders when the i18n language changes
after async catalog loading, fixing sidebar labels staying in English
on non-English locale startup.
Closes#7530
* fix(i18n): make sidebar language subscription race-safe
* refactor(i18n): use standard sidebar language subscription
---------
Co-authored-by: 文小松 <wenxiaosong@wenxiaosongdeMac-mini.local>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* fix(pr-comments): let users mark comment authors as bots for the Humans/Bots filter
Some review bots post from regular user accounts that defeat both provider
bot metadata and login heuristics, so their comments were misclassified as
human. Adds a persisted prBotAuthorOverrides setting with a "Mark author as
bot" comment action, applied consistently across desktop and mobile.
Fixes#7597
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(pr-comments): address review feedback on bot-author overrides
- Cap sanitized prBotAuthorOverrides at 500 entries so malformed payloads
can't bloat GlobalSettings or slow comment classification
- Reuse the shared normalizePRCommentAuthorLogin in isBotPRComment on
desktop and mobile instead of duplicating the normalization inline
- Pass botAuthorOverrides from CommentRow to CommentMoreMenu instead of
re-subscribing per menu instance
- Re-fetch mobile bot-author overrides alongside each PR refetch so they
don't stay a stale one-shot snapshot for the whole session
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(pr-comments): harden bot author override sync
* fix(pr-comments): bound and recover override updates
* fix(pr-comments): merge overrides from canonical settings
* fix(pr-comments): make bot override updates atomic
* fix(pr-comments): surface rejected bot overrides
* fix(i18n): translate bot override warning
* fix(i18n): translate bot author actions
---------
Co-authored-by: Dzmitry Bachko <dbachko@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* Surface the Pi CLI's real error when branch auto-naming and commit generation fail
Pi failures (missing provider credentials, HTTP 4xx/5xx, connection errors)
previously collapsed to the generic 'Pi CLI command failed with code 1.'
because extractAgentErrorMessage only recognized Error:-prefixed lines.
Add two stderr-only extraction passes for pi's failure formats and narrow
the unix-path redactor so pi's /login remedy token survives redaction.
Fixes the OP variant of STA-1492 (#7808).
* Replace per-CLI failure parsing with sanitized raw output excerpts
Every agent CLI formats errors differently, and the parsing passes only
ever covered the vendors someone had already debugged (the pi passes
fixed pi and nothing else). Show the output itself instead: a positional
excerpt (first two non-empty lines plus the last one) of stderr, falling
back to stdout when stderr is silent, path-redacted and capped as
before. Exit-0 runs with empty stdout now stay 'returned an empty
<result>' instead of misreporting a command failure. The sanitizer also
strips Cf characters (bidi overrides) now that provider-controlled
bodies flow through verbatim, and OSC sequences are stripped alongside
CSI.
* Keep the full CLI output of failed branch-name generation for on-demand viewing
The persisted rename-failed badge carries only a sanitized excerpt (it
syncs to paired clients), so the complete diagnosis was previously
buried in the main-process log. Failed generations now capture their
full stdout/stderr (bounded to 64 KiB per stream, head and tail) into a
main-memory-only store keyed by worktree — never persisted or synced.
The rename-failed dialog fetches it on demand and shows it in place of
the excerpt, ANSI/control/bidi-stripped; after a restart or on paired
web clients it falls back to the excerpt. Renderer-bound generation
results explicitly drop the capture so IPC payload shapes are
unchanged.
* Cover the rename-failed dialog's full-output fetch and excerpt fallback
* Split the folder-workspace title rename flow into its own module
first-work-branch-rename.ts sat at the max-lines ceiling; the folder
title flow is a self-contained concept and main's concurrent additions
to this file pushed the CI merge ref over the limit.
* Harden the failure-output capture and dialog against review findings
- Flatten bounded captures so V8 sliced strings no longer retain the
multi-megabyte parent stream in the capture map (128 MiB -> ~4 MiB in
a 32-entry probe).
- Require an OSC terminator and stop its char class at newlines so an
unterminated/boundary-truncated sequence can no longer swallow the
omission marker and diagnostic tail.
- Exclude stdout from the persisted branch-name failure detail (it can
echo the prompt into synced metadata); the full local-only capture
still keeps it for the dialog.
- Refetch and reset the dialog's full output when the persisted error
changes so an open dialog never shows or copies a stale run.
- Report signal-terminated generators (null exit code) as 'was
terminated before exiting' instead of 'code null'.
* Redact JSON-escaped Windows drive paths without breaking scheme URLs
Provider JSON bodies double backslashes (C:\\Users\\name), which slipped past the drive-letter redaction into the persisted, client-synced failure excerpt. Allow repeated backslashes only — a URL's :// must stay single so remedy links survive.
* Fix branch rename failure IPC re-registration
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* fix(orchestration): complete worker tasks and improve coordinator UX
* Fix orchestration lifecycle sender resolution and peek/check compat hand
- Lifecycle sends (worker_done/heartbeat) now use ORCA_TERMINAL_HANDLE
verbatim, skipping the liveness probe and pane remint that could
block delivery during restarts or mismatch stale-runtime assignee
handles.
- --peek now round-trips as {peek:true, unread:false} so older runtimes
that strip unknown params degrade to non-destructive "all" instead of
mark-read, with client-side filtering to restore peek semantics and a
clear error when --peek --wait can't be honored.
- Reject combined read-mode flags (--unread/--peek/--all) before calling
the runtime.
- Distinguish suppressed (already-consumed) lifecycle messages from
ignored ones so send doesn't wake --wait waiters for stale heartbeats.
- Fix task summary truncation to avoid splitting UTF-16 surrogate pairs
and to not misreport whitespace normalization as truncation.
* Add shared helper to abbreviate orchestration task specs for brief listi
- Normalizes whitespace and caps spec length at 160 chars, flagging
truncation separately from whitespace-only changes
- Truncates on UTF-16 code point boundaries to avoid splitting
surrogate pairs and emitting malformed strings
* Add pane-key identity to worker_done/heartbeat reconciliation and server
- Records the sender's pane key on messages and dispatch contexts so
worker_done/heartbeat ownership can be verified by the remint-stable
pane leaf instead of the terminal handle, which is reissued across
restarts.
- Rejects lifecycle messages from a genuinely foreign pane while still
tolerating handle remints, tab break-outs, and older CLIs that lack
pane identity.
- Moves task-spec abbreviation server-side (orchestration.taskList
--brief) so full specs no longer cross SSH/relay transports, with a
client-side fallback for older runtimes; consolidates the shared
abbreviation helper under src/shared.
- Adds a stderr warning when a pre-peek runtime's --peek response hits
the 100-row cap, since older unread messages may be missing.
* Isolate ORCA_PANE_KEY in CLI test beforeEach to fix leaked senderPaneKey
Co-authored-by: Orca <help@stably.ai>
* Fix pane-key remint bypassing dispatch mutual-exclusion lock
- Dispatch locking only matched on assignee_handle, so a reminted
terminal handle (tab break-out) could open a second concurrent
dispatch on the same pane.
- Add leaf-UUID-based pane key comparison (parsePaneKey) as a
secondary lock, falling back to exact handle match for legacy
rows without pane keys.
* Update orchestration skill docs for lifecycle authority and CLI flag add
- Clarify that dispatch lifecycle is tied to taskId+dispatchId verified against
the dispatched pane, not the terminal handle, since handles can be reminted
after restart
- Document new `check --peek`/`--all` and `task-list --brief` flags, with
fallback guidance for older CLIs that reject them
- Note that a valid worker_done auto-completes the task/dispatch, so workers
shouldn't also call task-update manually
---------
Co-authored-by: Orca <help@stably.ai>
Persist and safely restore the active top-level view on startup. Unknown, removed, legacy, or unavailable views fall back to the terminal, while cross-window UI sync cannot navigate the current window.\n\nCloses #8264
* fix(settings): make WSL skill commands pasteable (#7795)
* Fix WSL skill commands so PowerShell 7 pastes match PowerShell 5.1 argv
- Encode the WSL login-shell script as base64 and decode/eval it inside
the sh -c invocation, avoiding raw nested quotes at the paste boundary
- Scope $PSNativeCommandArgumentPassing = 'Legacy' to the invocation so
PS 5.1 and PS 7 both hand wsl.exe the same escaped argv
- Extract powershell-native-argument.ts as the shared quoting module and
reuse it from ssh-remote-powershell.ts
* test(runtime): stub getRepo in mobile-tab startup cwd test
Main's #7892 made listMobileSessionTabs validate selectors via
this.store?.getRepo; the mock store here only defined
getWorkspaceSession, so the merged CI build threw 'getRepo is not a
function'. Return null (wt-1 is a worktree id, not a repo).
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Automatically resolve and require explicit push targets for linked
GitHub PRs and GitLab MRs before allowing remote actions.
This prevents operations like push or sync from targeting helper
upstreams or falling back to default behaviors when the review target
is unavailable. Also, recover missing push targets during metadata
saves to heal existing linked PRs.
* fix(codex): share global AGENTS.md into managed runtime homes
Orca launches Codex with a managed CODEX_HOME, so host and WSL sessions otherwise lose the user's global instructions. Share AGENTS.md through the existing ownership-aware link-or-copy path, with a narrow WSL launch sync that avoids copying unrelated resource directories.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(codex): copy global AGENTS.md into WSL runtime homes
Symlinking across the \wsl.localhost 9P boundary stores a Windows UNC
target the distro cannot resolve, so the global AGENTS.md silently would
not load inside WSL when the host symlink succeeded. Copy it like the
config mirror already does across the same boundary.
Co-authored-by: Orca <help@stably.ai>
* Fix WSL global-instruction sync to dereference symlinks and skip redunda
- Copy AGENTS.md contents (not the symlink) into WSL runtime homes, since
a host-side symlink is unusable inside the distro
- Skip rewriting the fallback copy when source contents are unchanged,
avoiding needless writes across the UNC boundary on every Codex launch
- Handle non-regular-file sources and malformed/undeletable marker
directories without blocking sync or stranding stale instructions
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* feat(ssh): support file transfers over system ssh
* fix(ssh): harden system file transfers
* test(runtime): stub getRepo in headless mobile tab cwd test
The mobile-session selector validator (getValidatedExplicitWorktreeIdSelector,
from main) calls this.store?.getRepo to reject repo ids passed as worktree ids.
The store stub only implemented getWorkspaceSession, so the guarded call threw
'getRepo is not a function' once main merged into this branch. Add a getRepo
that returns null (wt-1 is a worktree, not a repo).
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
On Linux the CLI installs as orca-ide so it never shadows /usr/bin/orca
(GNOME's screen reader), but agent-facing surfaces (orca-cli skill,
dispatch preambles, CLI hints) all invoke bare `orca` — so on stock
Ubuntu an agent inside an Orca terminal launched the screen reader,
which started speaking (#7904).
Fix: prepend a userData-scoped shim dir (bare `orca` -> bundled
orca-ide launcher, or the stable AppImage) to the PATH of every
packaged-Linux managed PTY, mirroring the existing dev-mode cli/bin
prepend. The user's own shells — and their real screen reader command —
stay untouched. Also flip the orca-cli skill probe to prefer orca-ide
so agents outside Orca terminals never execute the screen reader.
Fixes#7904
Co-authored-by: Orca <help@stably.ai>
* Fix Codex WSL project trust conflating case-distinct Linux paths
normalizeCodexProjectPathForLookup lowercased the entire Windows/UNC
path, including the case-sensitive Linux portion under \\wsl$\<distro>.
Two distinct WSL project dirs (.../Repo vs .../repo) collapsed onto one
trust key, and the mirror dedupe (codex-config-mirror) inherited it.
Preserve case for the Linux path after the case-insensitive
\\wsl$\<distro> / \\wsl.localhost\<distro> share prefix; true Windows
drive letters and normal UNC shares still case-fold as before.
Co-authored-by: Orca <help@stably.ai>
* Apply the same WSL case-fold fix to hook-trust key lookup
normalizeHookTrustKeyForLookup had the identical latent bug: on a win32
host it lowercased the whole Windows-shaped path, folding the
case-sensitive Linux tail of a \\wsl$\<distro> UNC hook path — contrary
to its own comment that WSL sources stay case-sensitive.
Extract foldWindowsCaseInsensitivePath (shared with the project-path
normalizer): fold only the case-insensitive drive/\\wsl$ share prefix,
preserve the Linux tail. Existing suffix (event:group:handler) is already
lowercase, so behavior is unchanged there.
Co-authored-by: Orca <help@stably.ai>
* Fix Codex WSL trust revocation and hook-key case folding
- Case-drifted or share-spelling-varied WSL revocations were being
ignored on merge, letting stale "trusted" entries survive; fold
revocation lookups fully so matching errs toward revoked.
- Hook-trust key folding was gated on process.platform === 'win32',
so WSL/SSH-remote hook sources weren't folded when Orca itself ran
on macOS/Linux; fold by path shape instead, via the new shared
foldWslUncPathCaseInsensitiveParts helper (also covers /mnt drvfs
automounts and wsl$/wsl.localhost share aliasing).
* Fix Codex WSL trust key case-folding regressions
- Don't fold case-variant `/MNT` dirs as if they were the drvfs
automount; only literal lowercase `/mnt/<drive>` folds.
- Preserve an exact-cased trusted project entry in ~/.codex during
runtime merge instead of letting a loosely-matched, case-drifted
revocation clobber a user's re-granted trust on every mirror pass.
- Minor cleanup: inline foldWindowsCaseInsensitivePath and hoist the
repeated normalizeHookTrustKeyForLookup call in findTrustBlockRanges.
* Refactor case-fold WSL trust test to assert real serializer output
Extract path variables and assert against escapeTomlString(incomingPath) instead of a hardcoded escaped string literal, so the fixture can't silently drift from the actual TOML header serialization.
---------
Co-authored-by: Orca <help@stably.ai>
* fix(runtime): explain full worktree id selectors (#7432)
* Fix full worktree id selectors for bare repo ids and doc guidance
- Reject bare repo-id selectors up front via a shared validator instead
of relying on worktree-list scanning, so RPC callers no longer trigger
an unnecessary rescan just to detect the mistake
- Propagate the structured worktree_id_requires_full_path code through
RPC error mapping so callers get a typed error, not just a message
- Update orca-cli, orca-emulator, and orchestration skill docs to show
the full `<repo-id>::<path>` id shape and stop implying a bare repo
id is a valid worktree selector
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* fix: work-item naming, usage % rounding, and terminal/delete copy
Address prod-release-scan P2s:
- #8238: recognize Bitbucket Server (/projects|users/.../repos/.../pull-requests/N)
and Azure DevOps (/_git/REPO/pullrequest/N) PR URL shapes in
work-item-reference, alongside Bitbucket Cloud; graceful fallback preserved.
- #7574: getDisplayedUsagePercentage now rounds the used value before taking the
`remaining` complement, so the compact status bar (raw usedPercent) and tooltip
(pre-rounded clampUsedPercent) can no longer disagree by 1% at a .5 fraction.
clampUsedPercent moves to the shared module as the single rounding source.
- #7459: mixed remote+local batch delete confirm no longer claims the whole
batch is a permanent "remote host" delete — it now states remote items are
permanent while local items move to the Trash/Recycle Bin.
- #8322: right-click-to-paste settings copy is platform-aware — "Control-click"
on macOS, "Ctrl+right-click" on Windows/Linux — matching the ctrlKey gate.
Localization catalog synced (also picks up pre-existing UsagePercentageDisplayChangeNotice drift).
* Fix NaN% usage bar and label for non-finite provider values
Non-finite usedPercent inputs (NaN/Infinity) propagated through Math.round/min/max into the CSS bar width (`NaN%`) and displayed copy. clampUsedPercent now short-circuits to 0 in that case, with a test covering the divergence from getDisplayedUsagePercentage for the 'remaining' case.
* fix(cli): don't recover benign typos into destructive commands
CLI did-you-mean ranked purely by Levenshtein, so `orca worktree move`
sole-suggested `orca worktree remove` (distance 2) — an alias of the
destructive `worktree rm`. Suggestions also flow into --json
error.data.nextSteps, the agent recovery channel, so a blind retry could
delete a clean worktree.
Make destructiveness a declared property of the command instead of a verb
heuristic: add `destructive?: true` to CommandSpec and mark the
irreversible commands (worktree rm, environment rm, automations remove,
project setup-delete, tab profile delete, cookie delete, storage
local/session clear). The suggestion ranker excludes destructive
candidates unless the input token is itself a near-miss (distance <=1) of a
destructive verb, so `worktree remov` still recovers `rm`/`remove` while
`worktree move` no longer does. The guard tracks the registry, so it
also covers destructive verbs outside the delete family (e.g. kill).
Fixes#6303
Co-authored-by: Orca <help@stably.ai>
* fix(cli): use Array.at(-1) to satisfy oxlint prefer-at
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
Pi awaits its extension event handlers, so an awaited loopback status
post that stalls (Orca restarting / receiver unavailable) blocked the
running Pi turn and disconnected it. Make post() fire-and-forget with a
latest-only pending slot drained by a single active request and a 1s
AbortController timeout, so a stalled receiver can never hold the turn.
Also stop treating session_shutdown as turn completion: Pi emits it on
reload/new/resume/fork while the PTY stays alive, so only agent_end
proves done (real exit is cleared by PTY teardown). Split the generated
handler registrations into agent-status-handler-source.ts.
Co-authored-by: Orca <help@stably.ai>
* fix(cleanup): reconcile late removal results
* fix(cleanup): report authoritative late removals
* fix(cleanup): reconcile skipped ancestors on late child settlement
Ancestor rows skipped past the removal deadline were reported as
definitive failures even when the blocking child later succeeded or
was still in flight. Track provisional vs. definitive skips, re-derive
them as child settlements arrive mid-batch, requeue unblocked
ancestors for retry, and add a "still removing" toast state so batch
summaries stop contradicting rows that settle later.
* Fix skipped-parent rows going stale after post-batch child settlement
- Post-batch late child results (settling after the batch loop ends)
previously ignored ancestor skip state, so a parent skipped for a
since-resolved child kept a stale "could not be removed" failure
instead of reclassifying and retrying.
- Extracts reclassification logic into
workspace-cleanup-skipped-ancestor-reclassification.ts, shared by the
mid-batch and new post-batch paths.
- Adds workspace-cleanup-post-batch-late-settlement.ts to reconcile
ancestor skips and retry unblocked parents after late child
settlement, serialized via a reconcile chain to avoid interleaving
concurrent settlements.
* docs: design Grok orchestration group
* docs: plan Grok orchestration group implementation
* fix: add Grok orchestration group
* test(orchestration): accept Windows skill newlines
* Fix @grok orchestration group matching and remove stale planning docs
- Reuse the shared buildAgentNameRe matcher in groups.ts instead of a
divergent local regex, so orchestration groups honor the same
Windows launcher-suffix rule (grok.exe/.cmd/.bat/.ps1) as the rest
of Orca's agent-title detection.
- Add test coverage for real Grok OSC title shapes (spinner-collapsed,
session titles) and Windows launcher-suffix titles.
- Delete the now-completed design and implementation-plan docs for
the Grok orchestration group work.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Prod-release-scan P1+P2 from v1.4.137-rc.1 mobile host-remove.
P1: Host remove could orphan a SecureStore pairing token with no Settings
retry when BOTH the durable pending-queue write failed AND the native delete
rejected/stalled. recordCleanupIntent swallowed the queue-write failure, so
the only recovery handle for the failed keychain delete was silently lost.
Now scheduleHostCredentialCleanup keeps a session-scoped in-memory fallback
handle when the durable write fails, so Settings still surfaces the pending
cleanup and offers a retry; confirmNativeCleanup clears the fallback if the
native delete later lands. removeHost stays non-blocking on the keychain
(freeze fix intact).
P2 (updateLastConnected): the fire-and-forget `void updateLastConnected(...)`
call site threw on unreadable storage, producing an unhandled rejection.
updateLastConnected now swallows unreadable-storage failures internally since
it's a best-effort timestamp.
P2 (soft-read): loadPendingHostCredentialCleanup now reports storageUnreadable
instead of pretending the queue is empty, and Settings surfaces a
"couldn't check cleanup status — retry to be safe" affordance rather than
hiding the section when the durable queue can't be read.
Tests: dual-fault fallback + no-clobber, storageUnreadable reporting,
fallback self-heal on late delete success, and updateLastConnected non-throw.
* fix: host browser popups in an Orca origin-bar window instead of chrome-less child windows
A guest-opened popup previously became a default Electron child window
with no address bar, so users could not verify a popup's origin — a
phishing surface flagged in the prod-release scan of #7392. The reverted
#8332 tried gating on disposition, which is bypassable and breaks
featureless window.open() OAuth flows.
Instead, keep hosting popups in-app (preserving the shared session
partition and live window.opener handle OAuth depends on) but build the
child window ourselves via setWindowOpenHandler's createWindow callback:
a BaseWindow with an Orca-controlled origin-bar WebContentsView on top
and a content WebContentsView that adopts the pre-created popup
WebContents. The bar shows only the destination origin (never path or
query), updates on navigation, and flags plain http to remote hosts.
Also pins secure webPreferences (contextIsolation, no nodeIntegration,
sandbox, no webviewTag) on popup children via
SAFE_POPUP_WINDOW_OPTIONS, attaches guest policies to popup contents
directly (did-create-window does not fire for createWindow children),
emits the existing opened-in-orca renderer notice, and closes popups
with their opener guest.
Co-authored-by: Orca <help@stably.ai>
* fix: show page title in popup title bar instead of doubling the origin
The native title bar and the origin bar both showed the origin, reading
as a doubled header. Match Chrome popup behavior: title bar shows the
page title (reset to origin on navigation so a stale title cannot
outlive its origin); the origin bar below remains the unspoofable trust
surface.
Co-authored-by: Orca <help@stably.ai>
* fix: elide the start of long popup origins so the registrable domain stays visible
Adversarial review findings on the origin bar:
- The bar right-ellipsized long hostnames, hiding exactly the part that
matters: window.open('https://accounts.google.com.<...>.evil.com',
'', 'width=360') rendered as 'https://accounts.google.com.signin.s…'.
Clip from the left instead (rtl container + isolated ltr bdi so host
and port keep normal character order), matching how Chrome elides.
- Re-assert the origin on the popup's did-finish-load so a transiently
dropped executeJavaScript write cannot leave a stale origin up.
- Re-pin view layout on enter/leave-full-screen: verified at runtime
that HTML5 fullscreen keeps the bar visible on macOS (resize fires);
the explicit events make that hold on every platform.
- Test hardening: fake WebContents now flips isDestroyed after
'destroyed' so the double-close guard is actually exercised.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* fix(preflight): reject Windows paths from WSL lookup
WSL agent discovery previously treated path.win32 absolute results as
valid guest paths, so a Windows absolute path like C:\spoof could be
counted as a found agent. Only POSIX absolute paths are valid inside WSL.
* docs(preflight): explain WSL path boundary
* docs(preflight): correct WSL path rejection rationale
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Once quitAndInstall commits, Squirrel's ShipIt (and the Win/Linux
installers) wait for the old app process to exit before replacing the
bundle and relaunching. The quit path defers exit behind unbounded async
teardown (daemon checkpoint RPCs at 30s each per session, SSH
disconnects, watcher/emulator shutdown); if any of it wedges, the app
looks closed but the process survives, ShipIt stalls, and the update
never applies — 'Check for updates closes the app but never relaunches'.
Arm a 20s unref'd exit watchdog at the exact install-commit point (where
recovery is already forbidden) and disarm it on pre-commit recovery, so
the old process is guaranteed to exit and the installer can relaunch.
Fixes#4438
Co-authored-by: Orca <help@stably.ai>
Include fallbackGitHubPR alongside linkedGitHubPR/linkedGitLabMR when
determining whether a hosted review link resolves to a push target.
Worktrees without persisted linkedPR metadata (e.g. child worktrees)
were incorrectly blocked with "target unavailable" despite having a
real matching upstream, since their PR was only known via the queue
fallback. Also splits hasPositiveHostedReviewNumberLink to build on
the resolvable subset so the two helpers can't drift.
- Pass the active `worktreePath` through IPC, RPC, and the GitHub client
to ensure we fetch the correct HEAD OID when resolving merged PRs.
- Validate incoming worktree paths against known repository worktrees in
the main process to prevent forged path usage.
- Escalate Checks Panel PR refresh requests from 'swr' to 'active' when
a cached "no PR" miss predates when the panel became visible.