Commit Graph

6796 Commits

Author SHA1 Message Date
Brennan Benson d1532956fd
fix(keybindings): AltGr-safe default for Add Review Note (#9257)
* fix(keybindings): use AltGr-safe default for Add Review Note

The editor.addReviewNote default was Mod+Alt+N, which resolves to
Ctrl+Alt+N (AltGr) on Windows/Linux. On diacritic layouts AltGr+N
types a real character (e.g. Polish n-acute), so the editor-scope
chord hijacked normal typing. Switch the default to Mod+Shift+A,
which is AltGr-safe and keeps a mnemonic (A for annotate).

* test(keybindings): cover Add Review Note chord end to end
2026-07-17 18:57:26 -07:00
Brennan Benson 3e276d78ba
fix(ssh): probe npm via prepended PATH, not colocated with node (#9165) (#9255)
* fix(ssh): probe npm via prepended PATH, not colocated with node (#9165)

The remote Node/npm toolchain gate invoked npm by its absolute path
<nodeBinDir>/npm (POSIX) / npm.cmd (Windows, behind a Test-Path
colocation check). But deploy (commandWithNodePath) runs bare `npm`
with nodeBinDir merely prepended to PATH, so npm can resolve from
anywhere on PATH.

A host whose only resolvable node has npm elsewhere on PATH (e.g. node
symlinked into a dir without npm) deployed fine on v1.4.144, but after
upgrade the candidate is rejected with no fallback → SSH/relay
connection fails to establish.

Make the probe resolve npm exactly the way deploy does — bare
`npm --version` under the same prepended PATH — so it still confirms npm
is runnable (the #8450 concern) without requiring colocation. Windows
now prepends the backslash-form dir (matching deploy) so bare-command
PATH lookup resolves reliably.

* test(ssh): cover split Node npm PATH resolution
2026-07-17 18:51:10 -07:00
Neil c436df0551
feat(tray): mark dev-instance tray icons with a DEV indicator (#9253)
Co-authored-by: Orca <help@stably.ai>
2026-07-17 18:50:21 -07:00
Brennan Benson 64c7f14c3b
fix(codex): clarify account-switch restart card actions (#9254)
The account-switched restart card had two near-synonymous dismissive
buttons (Dismiss / Collapse) whose distinct behaviors weren't legible,
and body copy that attributed "keep working with the current account"
to Collapse — which only minimizes the notice.

Remap to intent-named actions:
- Dismiss  -> "Keep old account" (clears the notice; pane stays on the
  old account)
- Collapse -> "Not now" (minimize to the pill; decision deferred)
- Body no longer claims the minimize action commits you to an account.

Restart, the title, and the heading are unchanged. New English strings
get fresh auto keys so stale es/ja/ko/zh translations don't persist;
catalog re-synced.
2026-07-17 18:42:59 -07:00
slashdevcorpse ad206027b8
fix(terminal): replay cold restores at recovered grid (#9043) 2026-07-17 18:42:31 -07:00
Neil 3a27fb59cd
fix(settings): stop shortcut filter rail overlapping the list below xl (#9252)
Co-authored-by: Orca <help@stably.ai>
2026-07-17 18:37:55 -07:00
Neil ed28dec592
feat(new-workspace): always offer "Add a new project" in Create worktree picker (#9251)
Co-authored-by: Orca <help@stably.ai>
2026-07-17 18:37:20 -07:00
Jinwoo Hong 360b2423ea
Fix duplicate and lost IME terminal commits (#9235)
Co-authored-by: Orca <help@stably.ai>
2026-07-17 18:29:44 -07:00
Brennan Benson 2f5fc65ba4
fix(terminal): don't report agent exit on a degraded foreground scan (#9244)
* fix(terminal): don't report agent exit on a degraded foreground scan

On Windows/ConPTY the foreground scan (a Get-CimInstance Win32_Process
PowerShell fork) can exceed its 3s budget under load, and there is no
wmic fallback on Win11 24H2+. A timed-out scan returned the shell name,
which the completion coordinator reads as "agent exited" and fires a
false "agent done" notification while the agent is still working.

Prefer the last positively-recognized agent across a degraded
(available:false) scan so a transient failure no longer looks like an
exit. An authoritative (available:true) scan still refreshes/clears the
memory, so a genuine exit or crash is still detected. No-op on macOS,
where the scan is always available.

* fix(terminal): drop stale foreground scan results
2026-07-17 18:09:39 -07:00
Jinwoo Hong cbdd750f73
fix(terminal): keep redraw transcript cursors stable (#9081)
Co-authored-by: Orca <help@stably.ai>
2026-07-17 18:07:24 -07:00
Brennan Benson 24ac5a556e
fix(updater): humanize update-error card and hide raw error behind Show details (#9248)
* fix(updater): humanize update-error card and hide raw error behind Show details

Windows auto-update failures surfaced the raw electron-updater message as the
card headline — most visibly the PowerShell "Command failed: … Get-Authenticode
Signature …" dump when antivirus/EDR blocks the post-download signature check.
That reads as a crash, not an actionable state.

Classify each failure and lead with one plain-language sentence + the right
action, keeping the raw error one click away:

- New shared classifier (updater-windows-signature-check): distinguishes an
  AV/EDR-blocked signature check (environment) from a genuine wrong-publisher
  mismatch (security). The two are mutually exclusive so a real integrity
  failure is never softened into "try again".
- UpdateCard: raw error moves behind a collapsed "Show details" toggle; adds a
  security-stop variant (wrong publisher → no retry, "Open official releases")
  and the AV-blocked variant ("Update Verification Blocked"). HTTP/2 and generic
  paths keep their existing actions, now with the same details disclosure.
- Main process records a windows_signature_check_blocked lifecycle event so we
  can size the affected Windows cohort in the field.

Verified each error scenario in a running Electron build (signature-check
blocked, wrong-publisher security stop, HTTP/2, generic, and the expanded
details view).

* fix(updater): make Show details a caret disclosure above the action row

Move the raw-error toggle directly above the Retry/Download buttons and give it
a rotating chevron; the Last error block now expands in place beneath the caret
instead of appearing above the summary, with the action buttons pinned below.

* fix(updater): prevent signature-check bypass

* fix(updater): surface retry start immediately
2026-07-17 18:00:06 -07:00
github-actions[bot] 2668af035c Update README downloads badge 2026-07-18 00:50:48 +00:00
github-actions[bot] 212b79a03a release: v1.4.145-rc.3 2026-07-18 00:30:55 +00:00
eisen0419 3f335efdb9
feat(agents): pi session resume support (#8876)
* feat(agents): pi session resume support

* fix(pi): require persisted session files for resume

* test(sleeping-agent): use non-resumable sentinel in malformed-record fixture

The 'drops malformed sleeping agent resume records' test used agent:'pi' as
its example of an unknown/non-resumable agent, expecting the record to be
dropped. This PR added 'pi' to RESUMABLE_TUI_AGENTS, making that fixture
valid and retained, so the toBeUndefined assertion broke. Switch the
malformed-case fixture to a genuinely non-resumable sentinel
('definitely-not-an-agent') so the drop-malformed path is still exercised;
no other assertions changed.

* Add durable resume identity for Pi sessions without fabricating turn sta

Pi's `session_start` hook now carries the session file needed to resume
a sleeping pane, but until now Orca either discarded it or treated it
as a fake status transition. Thread a `providerSessionOnly` envelope
through the hook listener, relay, main-process server, and renderer
store so resume identity (and its session-file-scoped equality/claim
key) can be persisted and replayed without emitting prompt telemetry
or a visible working/done row.

* Add durable resume identity for completed Pi sessions

Pi's agent_end hook marks a turn done, but the underlying TUI session
stays alive and resumable. Previously a `done` status wiped sleeping
records and launch config as if the session ended, so hibernation,
manual worktree sleep, and quit-capture all lost Pi's resume identity.

- Track a "live recovery" record for done-but-still-resumable Pi
  sessions, exempting it from the usual done-state cleanup paths in
  agent-status.ts and agent-hibernation-planner.ts
- Gate providerSessionOnly rows and sleeping-agent schema records on
  actual resumability (getAgentResumeArgv) instead of trusting the
  presence of a provider session
- Wait for Pi to persist its session file before advertising resume
  metadata, and treat `/reload` as a non-terminal event so it doesn't
  clobber visible status
- Extend SSH relay envelopes to carry providerSessionOnly so remote
  hosts get the same behavior

* Add explicit periodic/quit mode to sleeping-agent session capture

Split captureAllSleepingAgentSessions into 'periodic' and 'quit' modes
so a background checkpoint can no longer downgrade a confirmed-quit
record or promote a completed Pi session without an authoritative
transcript path. Updates all call sites and tests accordingly.

* Use normalizeAgentStatusPayload for default pi status

Remove unnecessary JSON.stringify wrapper and call the appropriate normalization function directly.

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-17 17:29:04 -07:00
Asurada 7c7bf259a2
fix(i18n): correct Chinese UI terminology (#9154) 2026-07-17 17:27:18 -07:00
韦编三绝 1bd757ad2f
fix(i18n): correct zh translation of "Pin Tab" to 固定标签 (#9157)
Co-authored-by: weixin <weixin@thunisoft.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 17:25:55 -07:00
hanjoonchoe 2a22dd0f2a
fix(i18n): translate untranslated Korean catalog strings (#9019)
Translate 105 ko.json entries that were still identical to their English
source after the machine bootstrap — dialog bodies, settings descriptions,
shortcut recorder labels, Windows firewall notices, Jira connection copy,
crash-report notices, and source-control panel text.

Intentionally left in English: brand/product names, command and config
examples, CSS/selector strings used by animated visuals, and lowercase
concatenation fragments whose word order cannot be reordered safely.
2026-07-17 17:23:44 -07:00
slashdevcorpse 803a442868
test(e2e): harden terminal restart regressions on Windows (#9064)
* test(e2e): harden Windows terminal restart regressions

* test(e2e): cover renderer replacement rejection

* test(e2e): tolerate ESRCH when force-killing the daemon on POSIX

* fix(ci): preserve Windows restart test selection

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-17 17:18:36 -07:00
Jinjing 546cc8237f
Improve native chat ui (#9246)
* refactor(native-chat): extract option appliers and improve toggle UI

- Extract setOption apply logic to native-chat-session-option-apply.ts
- Add invokeAction method for toggle-only options without tracked baseline
- Replace checkbox UI with On/Off radio groups for boolean options
- Display option values only in pills (remove redundant label prefixes)
- Serialize concurrent applies so later dispatches win in order

* Remove focus-visible border from composer container

The container uses a steady hairline border (no focus/click flash), with focus-visible styling delegated to the inner textarea. The container is a layout wrapper, not a focus target.

* Prevent option commits on model switch during dispatch

When a user changes an option and the model switches before dispatch
completes, committing the stale option would overwrite state under
the new model. Guard by capturing the baseline option state before
dispatch and validating it hasn't changed post-dispatch.

* Use invokeAction for model option in NativeChatComposer test

Codex model is an agent picker mid-session, so setOption rejects.
Update test to use invokeAction to match the actual UI behavior.
2026-07-17 17:18:27 -07:00
Brennan Benson 49e625d41a
fix(mobile): harden WebSocket accept path against socket overload (#9247)
* fix(mobile): make the :6768 WebSocket accept loop leak-proof and self-healing

The desktop runtime's mobile WebSocket server on :6768 could wedge with the
socket in LISTEN but the TCP accept loop stalled — new connections piling up in
SYN_RCVD with zero ESTABLISHED, even from localhost, with no self-heal. Since
Orca mobile has no APNs (the persistent WS doubles as the push channel), a
wedged accept loop silently drops every notification while the app still shows
cached UI.

Root cause: connections were only capped at the WebSocket-upgrade layer
(MAX_WS_CONNECTIONS), after the socket is already accepted. TCP-level sockets
were unbounded, so leaked/half-open sockets (backgrounded phones, flaky relay,
reconnect storms) could grow until the process ran out of file descriptors and
accept() started failing with EMFILE.

- Bound TCP sockets via httpServer.maxConnections (2x the WS cap). At the cap
  Node accepts-then-closes, so the accept loop always keeps draining and the
  EMFILE/SYN_RCVD wedge is structurally impossible on this listener.
- Handle accept-level errors: ws forwards httpServer 'error' onto the
  WebSocketServer; with no listener Node rethrows it as an uncaught exception.
  Swallow + log and keep listening.
- Force-terminate over-capacity sockets: a bare ws.close(1013) left half-open
  phones lingering at >cap forever, rejecting everyone after them. Add an error
  handler + a 1s terminate fallback so the descriptor is always freed.
- Log heartbeat reaping / near-cap live counts so the leak is observable.

* fix(mobile): avoid masking fatal accept failures
2026-07-17 17:12:27 -07:00
Rod Boev 72a5c6f199
fix(terminal): paint paired remote terminals on first subscribe (#8954)
* fix(terminal): paint paired remote terminals on first subscribe

* test(terminal): cover desktop legacy subscriber PTY wait

The widened terminal.subscribe gate (isMobile -> params.client) had no
regression test: reverting it to the mobile-only gate left the suite
green. Add a desktop legacy-subscriber case asserting the mount request
and late-PTY wait fire before the scrollback-only fallback.

* fix(terminal): cancel abandoned multiplex PTY waits

Desktop subscribers can close while the new late-PTY wait is pending. Register provisional slot cancellation and abort all pending waits on unsubscribe, connection abort, or multiplex teardown so a late PTY cannot resurrect a ghost output stream.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-17 17:08:53 -07:00
Brennan Benson 5907816457
feat(keybindings): swap tab-switch chords to the common convention for new users (#9240)
* feat(keybindings): swap tab-switch chords to the common convention for new users

New installs now get the widespread mapping — Mod+Shift+[ / ] cycles across
all tabs, Mod+Alt+[ / ] cycles within the active tab type. Pre-existing installs
keep today's mapping: a one-time cohort seed (frozen on first launch via the
fileExistedOnLoad signal, mirroring the telemetry migration) pins the legacy
chords into keybindings.json, skipping any action the user already customized.

- shared registry: swap the four tab.*SameType / tab.*AllTypes defaults; export
  LEGACY_TAB_SWITCH_BINDINGS for the seed
- persistence: migrateTabSwitchKeybindings freezes the existing-vs-fresh cohort
  (tabSwitchKeybindingSeed = pending | done)
- keybinding-file: seedLegacyTabSwitchBindings writes the legacy pins into the
  active-platform section so Settings reset still works
- refresh stale default-chord comments
- tests for the swapped defaults, the seed (fresh/existing/customized/idempotent),
  and the cohort migration

* test(keybindings): prove existing-user parity + make the seed strictly per-action

seedLegacyTabSwitchBindings now pins each un-customized action individually
instead of skipping all four when any one is customized. A partially-customized
existing user keeps their rebound action AND the pre-swap default on the rest;
no existing user's behavior changes. The skip check keys on this platform's
effective overrides so a foreign-platform-only override can't leave the active
platform on a new default.

Adds keybinding-service.test.ts: constructs a real KeybindingService and asserts
effective bindings + real keystroke matching for both cohorts across darwin/
linux/win32, plus partial-customization, idempotency, and seed-failure retry.

* fix(keybindings): preserve legacy files during tab shortcut seed

* fix(keybindings): preserve valid pre-swap overrides
2026-07-17 16:58:04 -07:00
Trevin Chow 613dcd8c9b
fix(pr-comments): make the review sidebar legible for structured bot markdown (#9209)
Restore readable block flow, typography, nested spacing, and heading semantics for structured review Markdown in the PR sidebar. Preserve the compact renderer's existing remote-image trust boundary.
2026-07-17 16:39:02 -07:00
Brennan Benson 7c0b84f2b6
fix(terminal): invalidate cached glyphs when WebGL atlas changes (#8899)
* feat(terminal): add flag-gated render-desync sentinel for WebGL panes

Detects the buffer-clean/render-stale glyph garble class in the field: per
visible WebGL pane, compare the cells the xterm buffer says hold glyphs
against the ink actually present on the canvas, sampled in the same task as
a forced synchronous redraw so a divergence proves the render model/atlas is
wrong rather than a missed present. A trip requires the same screen cells to
stay divergent across three samples (real desync is pinned; scroll lag moves),
then records a webgl-render-desync breadcrumb, stashes evidence (canvas PNG +
buffer text) for bug reports, and runs the same shared-atlas recovery a tab
reveal performs, so a stuck-garbled pane self-heals within seconds.

Off by default; arm on any build via
localStorage.setItem('orca:render-desync-sentinel', '1') and reload.

* fix(terminal): invalidate glyph cache on atlas replacement

Reproduce the WebGL atlas identity mismatch with two live terminals and force cached geometry to rebuild whenever a different shared atlas is attached. Persist flag-gated render-desync evidence and retain the investigation tooling used to validate the field signature.

* fix(terminal): harden render desync diagnostics

* docs(reliability): clarify Linux WebGL evidence gap
2026-07-17 16:16:17 -07:00
Brennan Benson 14116e3573
feat(settings): unify skill card status and add Linear agent-skill section (#9218)
* feat(settings): unify skill card status and add Linear agent-skill section

Show the freshness-aware status pill ("Up to date" / "Update available")
on the Orchestration skill card, matching the Computer Use card — it was
the only installed-skill card still limited to a presence-only "Installed"
pill because it omitted the freshnessSkillName prop.

Add a Linear capability section under Settings → Agents that only appears
once the Linear provider is connected. It mirrors the other skill panes:
an orca-linear skill card (Update / Re-check + freshness pill) and a "How
to use it" grid of copyable /orca-linear prompts.

The Orchestration and Linear "How to use it" surfaces now share extracted
SkillUsageExamplesSection / SkillUsageExampleDialog components (the old
orchestration-only dialog is renamed/generalized with a slashCommand prop).

The nav registry and Settings page gate the Linear section on one shared
useLinearProviderConnected() selector so the sidebar entry and the section
appear and disappear together.

* fix(settings): tighten Linear skill section behavior

* fix(settings): preserve Linear freshness and dialog translations

* fix(linear): migrate legacy skill installs

* Revert "fix(linear): migrate legacy skill installs"

This reverts commit 3ff45f9245eda5c283988f9e6d21f8ce1386d548.

* fix(settings): show Linear freshness in sidebar

* fix(settings): type Linear navigation target
2026-07-17 16:15:58 -07:00
Jinjing ba25e4306c
Replace assistant-prose heuristic with explicit turn lifecycle markers (#9121)
* Replace assistant-prose heuristic with explicit turn lifecycle markers

Extract provider-authored turn boundaries (completion, interruption) directly
from Claude/Codex transcripts so the chat view knows when work ends without
guessing from message presence. Reconciles live hook state with transcript
lifecycle: when a terminal boundary lands, it settles a dropped Stop hook
instead of letting prose mislead the UI into showing 'working' after done.

* fix(review): cover Claude terminal stop_reasons and RPC lifecycle frames

Treat max_tokens/stop_sequence/refusal as completed markers so capable hosts
do not stay working after a dropped Stop, and assert lifecycle payloads on
runtime subscribe/read frames plus mid-turn non-terminal stop_reason cases.

* test(native-chat): clarify that lifecycle field is optional

Add type assertion and comment documenting that lifecycle field is optional and can be omitted in truncation-gating test fixtures.

* fix(native-chat): settle status on interruption despite working subagent

When Claude's turn is explicitly interrupted, the session should show ready
immediately — even if background subagents are still running. Add an
interruption check before consulting the hook's working-subagents flag so
interruptions take precedence. Also normalize omitted lifecycle timestamps
to null instead of leaving them undefined, and add test coverage for both
cases.

* fix(native-chat): settle loading spinner on explicit turn boundaries

Explicit transcript turn-lifecycle markers now fully replace the prose-fallback
settlement path. Remove the now-unused `turnLifecycleCapable` flag and wire
lifecycle to suppress spinner even when hook status lingers. Refine Claude
lifecycle detection to distinguish terminal stops from mid-turn tool_use rows,
exclude harness noise from new-generation detection, and apply clock-skew slack
over SSH/relay. Serialize PTY sends per line to prevent rapid prompts from gluing
before Enter, clearing unsubmitted input on cancel. Update working suppression to
detect epoch rollovers so interrupt+next-turn without a ready gap resets the
spinner correctly.
2026-07-17 15:59:38 -07:00
Brennan Benson e719ef1a57
fix(mobile): survive connection-migration cutovers during worktree create (#9234)
* fix(mobile): survive connection-migration cutovers during worktree create

A worktree.create in flight when the mobile transport migrates (relay/direct
hand-off on shoddy cellular, relay lease rotation, relay recovery) rejects with
"RPC interrupted by connection migration" even though the host completed it —
leaving the Create Workspace modal stuck while the worktree exists on desktop.
A naive retry hits a name collision and spawns a duplicate.

Mirror the existing mobile terminal-create idempotency: worktree.create now
accepts an optional clientMutationId that the host dedupes (in-flight + brief
post-success TTL), and mobile mints one key per candidate name and re-issues
the create on a cutover so the retry reconciles instead of duplicating.

* fix(mobile): gate worktree cutover replay by capability

* fix(mobile): await worktree replay capability
2026-07-17 15:56:43 -07:00
Rod Boev b259300032
perf(worktrees): bound runtime discovery scans (#8915)
* perf(worktrees): bound repeated runtime discovery scans (#8882)

* fix(worktrees): invalidate scans on SSH state changes (#8882)

* fix(worktrees): key scan reuse by execution runtime (#8882)

* test(worktrees): prove cached lineage variants (#8882)

* test(worktrees): exercise lineage through the shared scan cache (#8882)

* fix(worktrees): prevent stale runtime scans from repopulating cache (#8882)

* test(worktrees): prove stale generations stay out of cache (#8882)

* fix(worktrees): invalidate hidden SSH scans on relay state (#8882)

* fix(worktrees): scope SSH scan invalidation to provider changes (#8882)

* fix(worktrees): preserve enriched hidden SSH state notifications (#8882)

* test(worktrees): pin SSH provider generation monotonicity (#8882)

* test(worktrees): drain cached scan mock responses (#8882)

* fix(worktrees): scope resolved SSH invalidation to affected repos (#8882)

* fix(worktrees): separate SSH scan invalidation from client events (#8882)

* perf(worktrees): preserve raw scan reuse across metadata updates

# Conflicts:
#	src/main/runtime/orca-runtime.ts

* perf(worktrees): scope repo-local scan invalidation

# Conflicts:
#	src/main/runtime/orca-runtime.ts

* perf(worktrees): scope all repository scan invalidations

* fix(worktrees): drop scan cache on orphan-cleanup removal (#8882)

The orphan-cleanup fallback in removeManagedWorktree (git worktree remove
fails with 'not a working tree', Orca deletes the directory and prunes)
invalidated only the resolved cache, so the removed worktree kept being
served from the bounded raw scan cache for up to its 30s TTL.

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

* Simplify SSH deploy-success handling to use broadcastSshState

Route the post-deploy "connected" notification through the shared
broadcastSshState helper instead of manually reimplementing window
broadcast and runtime cache invalidation inline, keeping SSH state
propagation consistent with other call sites.

* perf(worktrees): defer SSH enrichment, consolidate cache invalidation

- Skip enriching ephemeral-VM SSH state since it's not broadcast to the
  renderer, avoiding unnecessary withSshRemotePlatform() calls.
- Move invalidateResolvedWorktreeCache() outside the conditional branch
  to eliminate redundant calls (previously called in both if and else).

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-17 15:34:30 -07:00
Brennan Benson 3fd73ee848
fix(crash-reporting): disambiguate renderer recovery from app relaunches (#9223)
* fix(crash-reporting): disambiguate main process relaunches

* fix(crash-reporting): trace all app relaunch causes
2026-07-17 15:27:39 -07:00
Brennan Benson ef03a50b1d
fix(github): attribute GitHub API outages instead of blank/"failed" states (#9106)
* fix(github): attribute GitHub API outages instead of blank/"failed" states

When GitHub's API is unreachable (5xx outage, network, or rate limit), Orca
showed no PR data with no explanation, so it read as an Orca bug rather than a
GitHub-side problem.

- Add a shared classifier (classifyGitHubUnavailable) reused by the main
  process and the renderer so every surface attributes an outage identically.
  A live outage returns HTTP 5xx, which the PR-refresh classifier previously
  had no branch for (fell through to the un-attributed "refresh failed").
- Right-sidebar Checks panel: show GitHub-attributed copy in the error
  empty-state, plus an inline banner over stale cached PR data so an outage
  doesn't look like a normal (silently out-of-date) panel.
- Tasks/PR-list page: replace the vague "N of M projects failed to load" with
  a GitHub-attributed banner when the failure is a reachability problem.

Copy names GitHub as the source and reassures it isn't an Orca problem, with no
status-page link. Stays GitHub-scoped so GitLab/other providers aren't
mislabeled.

* fix(github): keep outage attribution accurate

* fix(github): preserve outage attribution edge cases

* fix(github): preserve Tasks outage attribution

* fix(github): avoid false outage attribution

* fix(runtime): tolerate absent browser certificate state

* fix(ui): preserve exhaustive optional state handling

* fix(github): preserve outage attribution for combined queries

* fix(github): preserve runtime failure attribution

* chore: restore unrelated UI files to main (out of scope)

native-chat-session-option-labels.ts and skill-freshness-group.tsx switch
tweaks were unrelated to GitHub API outage attribution — they fix pre-existing
switch-exhaustiveness lint on main, which this PR's CI (oxlint) doesn't gate on.
Restore them to origin/main so this PR's diff stays focused; the exhaustiveness
cleanup belongs in its own change. (sync-runtime-graph.ts is already identical
to main, so no diff there to revert.)

* fix(github): drop Orca self-reference from outage copy

* fix(github): drop em-dashes from outage copy
2026-07-17 15:16:07 -07:00
Brennan Benson e70842fe2c
fix(terminal): recover floating input after app refocus (#9233)
* fix(terminal): recover floating input after app refocus

* fix(terminal): preserve newer focus ownership
2026-07-17 15:10:08 -07:00
Brennan Benson e6933fed84
fix(grok): honor zero-usage weekly reset (#9219)
* fix(grok): honor zero-usage weekly reset

* fix(grok): preserve ambiguous monthly billing fallback
2026-07-17 15:09:22 -07:00
Brennan Benson f544820552
fix(ssh): require a coherent colocated Node/npm toolchain for the relay (#9165) 2026-07-17 14:27:31 -07:00
Brennan Benson 5b6cefa5ab
fix(orchestration): emit message timestamps as RFC3339 UTC (#9167) 2026-07-17 14:25:38 -07:00
Brennan Benson 2cb5d4e149
fix(agent-status): clear answered Claude question waits at answer time (#9074)
* fix(agent-status): clear answered Claude question waits at answer time

An answered AskUserQuestion left the amber "waiting" indicator on sidebar
rows and tabs until the agent's next tool hook or turn end — unbounded
linger while the model thinks or streams after the answer (measured 17s
for a 1000-word reply, 44s for 3000 words).

Root cause is an event-shape change: newer Claude reports the
AskUserQuestion wait as PermissionRequest (not the PreToolUse shape #7852
special-cased), so the wait inherited real-permission stickiness and
shouldKeepClaudePermissionVisible swallowed the answer-time
PostToolUse(AskUserQuestion) working event — the identity match can never
succeed because the question's PermissionRequest carries no inheritable
tool_use_id. That silently undid #8311 for questions.

Two scoped changes, both keyed on the tool name rather than the hook
event name:

- Sticky permission hold now exempts AskUserQuestion waits, so the real
  answer-time hook (when Claude sends one) clears the wait as #8311
  intended.
- New guarded inference for the hook Claude may never send: the submit
  keystroke (Enter or digit quick-select) into a pane whose fresh status
  is a waiting AskUserQuestion synthesizes the post-answer state, exactly
  mirroring the existing interrupt inference (renderer baseline capture,
  main-process re-validation, listener lead-state sync so child-driven
  refreshes cannot resurrect the dismissed question).

Real permission waits (other tools) keep their sticky semantics; batched
input and pastes never match the submit classifier.

Verified live against a real claude CLI: waiting -> working within ~50ms
of both Enter and digit answers, question card dropped, unanswered
questions still hold amber, permission stickiness covered by tests.

* fix(agent-status): guard question answer inference

Keep multi-question, multi-select, and free-text selector interactions waiting until the full prompt is submitted. Wire native-chat answers into the same guarded inference only after every paced runtime write succeeds, with cancellation and delivery-failure coverage.

* chore(skills): refresh manifest for rc.2

* fix(agent-status): verify native chat answer delivery

* fix(agent-status): await verified question delivery

* fix(agent-status): pin native-chat answer baseline before delivery

The native-chat question-answered inference read the live pane status at
settle time (after the paced send + remote acceptance, which can span
seconds on SSH). If a replacement AskUserQuestion became current in that
window, the settle callback minted a fresh baseline from the new question
and the server cleared *its* wait — dismissing a question the user never
answered.

Capture the answered question's baseline before delivery and have the
inference getter return it, so the server re-validates against the pinned
baseline and rejects a changed status — the same capture-then-revalidate
contract the terminal keystroke path already uses. Also hoist the
shouldStepNativeChatAskAnswer predicate to a single evaluation.

Regression test swaps the live status between sendAnswer and settle and
asserts the answered question's baseline is used (fails against the prior
live-read getter).
2026-07-17 12:47:04 -07:00
Brennan Benson b67106805f
fix(runtime): eliminate agent-send TOCTOU that rejects live agents during startup (#9166)
* fix(runtime): avoid false no-agent send rejection during agent startup

* fix(renderer): let guarded note sends resolve agent status races
2026-07-17 12:34:19 -07:00
github-actions[bot] 1c54171c55 Update README downloads badge 2026-07-17 12:42:11 +00:00
Brennan Benson 44686f324c
feat(native-chat): add mobile default-view toggle for native chat (#9084)
* feat(native-chat): add mobile default-view toggle for native chat

Adds a per-device "Native chat" setting on mobile (Settings → Native chat)
that controls whether supported agent sessions open in the native chat view
or the raw terminal. Default stays terminal; flipping it on makes eligible
sessions render as native chat, mirroring the desktop default-view control.

- New orca:defaultSessionView preference (loadDefaultSessionView/save).
- Per-tab chat set refactored into a tri-state override map so a session can
  be pinned to terminal or chat regardless of the default; the legacy array
  format migrates to chat overrides on load.
- useMobileSessionViewMode resolves each tab as override ?? default and
  reloads the default on focus so a Settings change applies without remount.
- Toggle/action-sheet builders take an isTabChatView predicate.

* chore(skills): refresh skill bundle manifest for v1.4.144-rc.2

The v1.4.144-rc.2 release bump left resources/skills/current-manifest.json
pointing at rc.1, so verify:skill-bundle-manifest fails on any branch that
reaches it. Regenerated (appVersion only; no skill content changed) to
unblock CI. Unrelated to the native-chat toggle in this PR.

* fix(native-chat): harden mobile view preferences

* fix(native-chat): harden default view persistence

* fix(native-chat): serialize mobile view persistence

* fix(native-chat): reconcile failed mobile view saves

* fix(native-chat): fail closed on unreadable view overrides

* fix(native-chat): honor fail-closed view races
2026-07-17 00:34:46 -07:00
Brennan Benson c5d2275c35
Add preference to show pinned worktrees in original lists (#6216)
* Add setting for pinned worktree group display

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

* Fix pinned worktree host metadata

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

* Polish pinned worktree setting copy

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

* Clarify pinned worktree setting copy

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

* Use original lists in pinned setting copy

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

* Fix pinned sidebar order and render churn

* Fix pinned host and inbox placement

* Fix worktree host ownership consistency

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-17 00:21:42 -07:00
Jinwoo Hong d0b090b0ff
fix(main): cancel unread fetch response bodies so a peer socket close cannot crash the app (#9142)
Co-authored-by: Orca <help@stably.ai>
2026-07-16 23:10:40 -07:00
Neil 23368ee9da
fix(shortcuts): preserve native input-source switching (#9108)
* fix(shortcuts): preserve native input-source switching

* fix(shortcuts): harden native input-source switch companions

Build on #8305 (@gatsby74): normalize Space key identities so Chromium
keypress without code still cancels companions, clear stale pending on
blur/next keydown, and block insertText beforeinput while a native-only
chord is live. Add #8299 regression coverage.

Co-authored-by: gatsby74 <166927047+gatsby74@users.noreply.github.com>

* fix(shortcuts): harden native-only event tracking

---------

Co-authored-by: gatsby74 <166927047+gatsby74@users.noreply.github.com>
2026-07-16 22:49:28 -07:00
Neil 0cd50eecdb
fix(pet): key sprite keyframes on the resolved track; cap render durations (#9140)
Follow-up polish to #8730: key @keyframes on the resolved row/frames (so a same-row fallback like hover on a jumping-less pet doesn't restart idle), mirror the importer's 60s per-frame cap at render, and trim comments to the 1-2 line convention.
2026-07-16 22:21:58 -07:00
Jinho Choi 13c690b05a
fix(pet): match Codex's per-frame pacing and pointer interactions for imported pets (#8730)
Imported .codex-pet bundles played every animation at a flat 8 fps (~9x too
fast). Mirror Codex's exact per-frame duration tables, render uneven holds as
step-end keyframes, upgrade legacy-persisted pets at render, and add the Codex
mascot's pointer interactions (hover, grab-and-hold on frame 0, horizontal-drag
running). Hardened over several adversarial review rounds: honor explicit fps,
start each row/pet from frame 0, scope drag to its pointer, and guard untrusted
persisted data.

Fixes #8729

Co-authored-by: nasagong <zinho2000@gachon.ac.kr>
2026-07-16 21:59:44 -07:00
fsdwen 8ec050a875
fix(i18n): 修复 zh.json 分页翻译错误和 9 处未翻译文案 (#8990)
- 分页按钮文字修正:Next→下一页, Next page→前往下一页, Previous page→前往上一页
- 翻译 4 处 Jira 连接对话框未翻译描述文案
- 翻译 2 处 Jira 集成卡片描述(远程存储/本地存储)
- 翻译 2 处文件删除确认混合场景文案
- 翻译 Grok 统一计费账户月度已用额度说明

Closes #8988

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-16 21:39:13 -07:00
Glen Maddern fa85536f3a
fix(ssh): repair unbuilt relay native deps (#8686)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
2026-07-16 21:32:13 -07:00
Brennan Benson 1284a00e93
fix(native-chat): don't force a default model/effort on agent spawn (#9134)
#9085 made resolveNativeChatSessionOptionDefaults fall back to the catalog
default model (sonnet) and effort (high) whenever the user had not explicitly
picked one, injecting `--model sonnet --effort high` (and codex `-m`/`-c`
equivalents) onto every agent spawn: composer, worktree activation,
source-control agents, onboarding, work-item launch, floating terminal, and
new-tab launch. That silently overrode each user's own CLI-configured default
model.

Return undefined (spawn the agent exactly as its own CLI would) unless the user
has explicitly selected a model, and carry only explicitly stored option
values. An explicit model selection still applies that model and its catalog
option defaults via resolveAgentSessionOptionLaunch.
2026-07-16 21:29:17 -07:00
Guillermo Avelar 1b331f282c
feat(editor): bindable keyboard shortcut to add a markdown review note (Mod+Alt+N) (#8250)
* feat(editor): bindable shortcut to add a markdown review note

Adds editor.addReviewNote (default Mod+Alt+N) to the shared keybinding
registry and wires it into all three markdown surfaces: the rich editor
key handler invokes the annotation popover opener, the Monaco editor
installs a keydown listener that opens the composer for the tracked
selection target, and the preview maps the DOM selection to its
annotation block. openAnnotationPopover now prefers the live selection
target over synced state so the shortcut works even before the sync
render lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia

* fix(editor): cover list items and Monaco path for add-review-note shortcut

Tag the preview's list-item annotation blocks with data-annotation-block-key
so the shortcut resolves selections inside li blocks (review feedback), and
extend the e2e spec to drive the Monaco source-editor wiring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia

* docs(e2e): explain store-driven view-mode switch in add-review-note spec

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia

* refactor(editor): extract add-review-note + selection-flush modules to satisfy max-lines after rebase

* refactor(editor): spread key-handler params and extract TOC hook to satisfy max-lines

* test(editor): move add-review-note installer test into its own describe

* fix(editor): pass add-review-note chord through when Monaco cannot act; cover preview surface e2e

* fix(editor): unify add-review-note chord consumption — consume only when a composer opens

* fix(editor): gate list-item annotation block key on composer availability

* fix(editor): require live selection for keyboard add-review-note

* chore: retrigger CI against current main (merge ref built during transient main breakage at 6e91ca6c0)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-16 21:10:15 -07:00
Brennan Benson cc1ad064d7
fix(skills): decouple bundled skill artifacts from the release train (#9119)
The current manifest stamped package.json's version into itself (9 lines),
so every RC/stable version bump made the committed artifact stale on every
open branch: lint failed until authors committed content-free regeneration
diffs, which also dragged the resources/skills-filtered update-roundtrip
matrix onto unrelated PRs. Cutting a release tag whose skills tree changed
had the same effect through release-mapping.json.

- current-manifest.json is now schema 2 and content-only; the generator no
  longer reads package.json. Registry and mapping stay schema 1 so the
  append-only released-history guard keeps its schema gate.
- The running build's version enters at the IPC boundary
  (skills:freshnessInventory passes app.getVersion()) and threads through
  the inventory to placement observation; current-revision placements are
  labeled with it while historical revisions keep resolving through the
  release mapping. The artifact loader and its cache stay content-only.
- verify tolerates a committed release mapping that is a byte-exact prefix
  of the derived one when every missing trailing row's revisions equal the
  current manifest (a just-cut tag over unchanged-since bytes); such rows
  are provably redundant until the next real regeneration adds them.

Artifacts now change only when skills/ content changes.
2026-07-16 20:02:01 -07:00
Neil 5ee90c8d59
fix(agents): recognize OpenCode native OC | tab titles (#9102)
* fix(agents): recognize OpenCode native OC | tab titles

OpenCode's native OSC titles use `OC | <task>` without an `opencode`
token, so title classifiers left tabs as Claude/unknown. Map the native
marker (optional mux prefix) to OpenCode identity in both title
classifiers, exclude it from isClaudeAgent, and cover lookalikes plus
stale Claude launch reclaim.

Builds on and supersedes #8590 (credit @gatsby74). Fixes #8478.

* fix(agents): drop renderer import from #8478 shared repro

tsconfig.node includes src/shared tests; importing agent-status pulled
renderer modules outside the node project and failed typecheck. Assert
opencode identity via shared title classifiers only (OpenCode TUI sets
"OpenCode" and `OC | ${title}`).

* fix(runtime): fill browser cert failure map in mobile snapshot fixtures

Main's #9104 reads browserCertificateFailuresByPageId in buildMobileBrowserTab
but left partial AppState test helpers without the field, breaking PR Checks
merge commits. Default the map in fixtures and use optional chaining so partial
state cannot throw.
2026-07-16 19:53:18 -07:00
Neil e01f3f474c
fix(sidebar): preserve Project Group members under Hide sleeping (#9101)
* fix(sidebar): preserve grouped projects under sleep filter

* test(sidebar): harden #8865 project-group sleep-filter coverage

Add adversarial cases for explicit project filters, multi-member groups,
ungrouped neighbors, and buildRows membership/count preservation.

Co-authored-by: bbingz <zzb@gxsmjx.com>

---------

Co-authored-by: bbingz <zzb@gxsmjx.com>
2026-07-16 19:38:13 -07:00