Commit Graph
16717 Commits
Author SHA1 Message Date
Jinwoo Hong b7fb07c379 fix(ci): unblock main: split over-long files and pin scanner test file times (#34072) 2026-10-26 17:14:54 -04:00
OrcaWinandBrennan Benson 82ab53ba61 fix(updater): pin stable fallback before downloading (#34076)
## ELI5

Orca can remember one release's ZIP filename and later follow “latest” into a newer release where that file does not exist. Resolve “latest” once, then keep the manifest and download on that concrete release.

## What Changed

- Replace the default-channel moving-feed fallback with a validated stable tag resolved from GitHub's `/releases/latest` redirect.
- Reuse the existing Electron `net.request` HEAD handling and platform manifest/asset readiness probes. `net.fetch` cancels manual redirects in real Electron, so it is not used for redirect discovery.
- Return a retryable check failure when a ready concrete fallback cannot be resolved, and reject fallback results belonging to an expired check.
- Update existing feed expectations and installer fixtures; cover stable fallback, Atom outages, unavailable fallback, late completions, redirect validation, and platform manifest selection.

## Why

The normal path already pins a tag, but Atom outages and no-newer results still installed a `/releases/latest/download` provider. That provider retains relative filenames while GitHub's redirect can move between checking and downloading. Correct release manifests alone cannot prevent the mismatch.

Credit to @brennanb2025 for the original tag-pinning fix in #1797, and @nwparker for the attempt-ownership guard in #23160, which this change extends across the fallback lookup. Also reviewed @sechan-netizen's #30952 and its review thread: its release-manifest validation is a complementary safeguard and remains separate because this race reproduces with correct manifests. No commits from that PR are copied here.

This PR adopts @brennanb2025's audited #34075 lint fix (splitting three files that already exceeded main's line limits), with Brennan retained as a co-author. Independent byte-level audits preserve the moved runtime bodies and test groups; the follow-up replaces five test-only assertions with typed calls and emits identical JavaScript. The standalone older PR remains unmerged after repeated daemon-test CI/order sensitivity; the combined tree here passed all CI, including that exact daemon test file (16 tests) in run 40398604134, job 121839803430.

## Linked Issue

Fixes #34034

Related reports: #15921 and #22621. The controlled race matches their URL signature and retry behavior; the reporter's original feed selection cannot be established without its logs.

## Visual Proof

N/A — updater feed selection only; no presentation change. Verified the HTTP behavior using the production fallback resolver and electron-updater 6.8.10 with unmodified v1.4.240/v1.4.241 manifests and a controlled local release server:

| Scenario | Result |
| --- | --- |
| Old moving provider: read 240 manifest, advance latest to 241, download | `v1.4.241/Orca-1.4.240-arm64-mac.zip`: 404 |
| Retry the old download without a new check | Same 404 |
| Fresh check | Correct 241 ZIP: 200 |
| Fixed fallback: resolve 240 tag, advance latest to 241, download | Correct 240 ZIP under tag 240: 200 |

No installer was executed and no app window was opened.

## Testing

- [x] I manually tested these changes locally
- [x] Automated tests added/updated

`ORCA_BACKGROUND_LAUNCH=1 pnpm check:changed --maxWorkers=2`: all 26 checks pass on the combined branch, including formatting, lint, typechecks, affected tests, and ratchets. The earlier updater-only run also passed all 20 selected checks.

The controller regression run against the original implementation produces five failures with passing controls. The fixed implementation passes. Resolver tests exercise macOS arm64, Windows x64, Linux x64/arm64 manifest selection, invalid redirects, missing assets, and recovery after network failure; these platform variants use mocked transport.

A separate background Electron 43.8.1 smoke on macOS arm64 uses the production resolver and real Electron networking against GitHub, resolving the ready `v1.4.241` tag. The controlled before/after reproduction also exercises the production resolver and actual GenericProvider. Neither proof exercises native installation.

All non-skipped GitHub CI checks pass for combined head `c04a6ca95604e064fb4f91adb1a57ea3dcf9adf0`: all five full unit shards, relay integration, Linux/Windows package checks, macOS updater regression tests, static analysis/typechecks, and the required aggregate check. Final independent review recommends merging that exact head as low risk with no code blockers.

## AI Disclosure

## Review

Independent sub-agent review found no actionable issues and rated the updater change low risk; 57 relevant tests passed independently. The prerequisite received two independent refactor audits, with identical moved runtime/test bodies and a merge-preservation gate reporting zero unexplained deletions and zero unrelated files. The five typed mock changes produce identical JavaScript. Also self-reviewed the feed-selection paths, timeout ownership, transport cleanup, and release-channel filtering. The added lookup runs only on the existing fallback path, uses HEAD for redirect discovery, retains five-second request deadlines, and reuses manifest/asset probes. No new polling, subprocess, persistent cache, or per-workspace work is introduced. Native Windows/Linux networking and installer execution were not exercised locally.

Review disposition for [the DMG-only manifest comment](https://github.com/stablyai/orca/pull/34076#discussion_r4382275117): an independent executable comparison of the original and fixed implementations returned the same `ready` Atom result for a DMG-only manifest; the old fallback already handed that manifest directly to MacUpdater, which cannot select its required ZIP. This is an existing release-integrity limitation, not introduced or worsened by tag pinning. It remains outside this race fix; a complete integrity change must validate the native files list and architecture selection rather than merely finding any ZIP-like name.

## Agent skill upstream boundary

- [x] Not applicable; no upstream skill source or fixtures copied.

## Notes

Desktop updater implementation is shared with headless serve. No IPC/RPC contract, remote version requirement, mobile client code, filesystem path, or workspace-kind assumption changes. Existing RC/perf selection remains in place. If fallback discovery also fails, checks use the existing retry/error flow instead of launching a moving feed.

## Checklist

- [x] This PR is focused on consistent release selection
- [x] Problem, behavior, and mechanism explained
- [x] Visual proof N/A with network verification recorded
- [x] Self-reviewed for correctness, security, and performance
- [x] Cross-platform, remote, mobile, and folder-workspace impact considered
- [x] Required changed-code checks pass


Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 14:09:01 -07:00
Brennan Benson ffc2b3fba1 fix(orchestration): preserve task reset lineage per Run (#28823)
* fix(orchestration): preserve task reset lineage per Run

STA-10382

* fix(orchestration): record removed Tasks, Dispatches and workers per entity

Replace the per-Run capped JSON snapshot with one row per removed entity in
removed_orchestration_work, written by AFTER DELETE triggers on tasks,
dispatch_contexts, worker_dispatches, worker_terminal_resources,
remote_dispatch_attachments and federated_dispatches. The triggers are
rebuilt on every open after migrate and dropped at migrate start; a
recorded_since coverage marker moves forward whenever any trigger was
missing, so a Run created before recording reads partial, never
complete-and-empty.

reset --tasks keeps its delete list and order; its reply gains optional
removed counts computed after commit (a failed summary only drops the
field). run-show gains an optional constant-size removedWork summary and
--removed/--cursor paging. reset --all clears the record; deleting a Run
deletes its rows.

Removes the snapshot modules, the run_reset_lineage table, the in-transaction
receipt completion and alwaysRequestId from the first version of this PR.

* chore: drop accidental pnpm-lock.yaml churn

* refactor(orchestration): decode removed work entries through unknown before the checked cast

* fix(orchestration): count settled workers with open terminals and name affected Runs

- A worker may still be running when its state was possibly live or its
  Orca-owned terminal was never released; the reset reply, run-show line and
  listing share one derivation from the removed records.
- The reset reply names the affected Runs (optional runIds); the CLI prints
  the exact run-show command for one Run and the list for several.
- The watermark read is no longer swallowed inside the reset transaction.
- run-show's removed-work read is guarded; a failure omits the field.
- Coverage compares created_at strictly after recorded_since.
- --removed lists a federated worker once, shows a user-taken-over terminal
  as such, and says when a cursor is past the end.

* fix(orchestration): count removed workers by held process minus durable exit proof

- A removed worker may still be running when Orca held its process (live
  state, federated dispatch pending or dispatched, or an Orca-owned terminal)
  and no durable exit proof exists (stopped, released, released terminal, or
  a certified termination reason on its Dispatch).
- The exit proof is one DURABLE_EXIT_PROOF constant shared by the fleet
  liveness projection (no behavior change) and the removed-work reader.
- Dispatch records keep terminationReason.
- Coverage is complete when a Run was created at or after recorded_since; a
  moved marker is stamped one second past the newest existing non-legacy Run,
  and the capture installs after the stub home Run backfill.

* docs(orchestration): correct the terminationReason and coverage marker comments

* fix(orchestration): decode removed work entries through a checked schema

The stored record is parsed once with a discriminated zod schema per kind,
so the listed entry keeps its precise type without an assertion. The same
lineage field table drives the capture triggers' key set and integer casts.

* fix(orchestration): exhaustive removed-work listing switch; keep valid ids in id lists

List worker and remote worker entries with explicit cases so the switch is
exhaustive over the entry kinds. An id list drops non-string elements and
keeps the rest, as before the schema decoder.

* test(orchestration): build removed-work CLI fixtures without type assertions

Use a real RuntimeClient with a spied call and decode listing fixtures through
the entry schema, so the tests carry checked types instead of casts.

* fix(orchestration): name only the removed kinds in run-show and word the no-record message truthfully

The run-show line lists the kinds a Run actually lost, terminals included,
and the --removed message for a missing record no longer claims the host
keeps none, since a new host omits it when its read fails.

* fix(wsl-move): classify the removed-work tables with the other orchestration tables

removed_orchestration_work and its coverage marker live in the orchestration
database and go with its Runs, so the WSL mover rewrites them in place like
every other orchestration table.

* fix(orchestration): keep the removed-work hint when a reset removes only terminal records
2026-10-26 14:05:33 -07:00
c2ceb5204f fix(windows): stop recursive deletes from retry-storming when a file is held open (#33722)
* fix(windows): stop recursive deletes from retry-storming when a file is held open

Node's async recursive rm retries every nested entry separately and orphans
sibling walkers when it rejects, so deleting a workspace holding a live
browser profile multiplied filesystem work per directory level until the
main process hung. Delete Windows host trees with a walker that retries
whole passes from one shared budget and leaves nothing running on failure.

Also bound and log detached worktree removal, and fail a file transaction
whose proper-lockfile lock is compromised instead of throwing from its timer.

* fix(windows): retry a locked delete as whole passes instead of a custom walker

Replace the hand-rolled tree walker with Node's own recursive rm and no
per-entry retries. Async rm gives each nested entry its own retry counter and
never stops siblings, which is what multiplied the work; with retries off each
pass is one bounded walk, and a transient Windows lock repeats the whole pass
from the existing 250/500/1000/2000 ms budget, checking the job's signal
between passes.

A failed delete now names the file another program holds open instead of
Node's EBUSY/EPERM text. Drop the 30-minute background deadline. The lost-lock
error no longer embeds the library's message and says the write may or may not
have been saved.

* test: cover bounded deletion failure and recovery contracts

* test: prune unchanged cleanup coverage

* fix(worktrees): give truthful failed-delete cleanup advice

* test: document fake-clock retry adapter

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 13:50:11 -07:00
Brennan Benson 5709037f4c Continue a chat after the terminal agent exits (#33759)
* fix(native-chat): a chat sends again once the terminal's agent exits on macOS

The terminal-writer check required the pane's root process to be a shell,
but macOS panes spawn under login(1), which stays as the shell's parent,
so the check refused every send until the terminal closed. Census the
shell login started instead.

* Reconcile current terminal writer evidence before continuation

* Share fresh foreground confirmation and prove hosted login census

* Restore shell process identity import in foreground tracker

* Correct process fixture identity and polling callback contracts

* Align decisive Windows inspection fixture expectations

* Complete foreground inspection Session fixture
2026-10-26 13:47:20 -07:00
Naveen ChatlapalliandNeil 1df8501246 fix(claude): keep a user-set async flag on Orca-managed hooks (#26736)
applyManagedHooks rebuilt each managed Claude hook from scratch, so an
explicit "async" a user added to an Orca hook in settings.json was wiped
on every install. Carry the boolean over from the managed hook being
replaced for the same event; fresh installs stay synchronous and
user-owned hooks never donate their value.

Fixes #26718

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 13:34:39 -07:00
OrcaWinandm4air d58ab9762c perf(memory): read macOS footprints with a bundled proc_pid_rusage helper instead of top (#34053)
top costs ~263 ms of CPU per sample, so the memory panel only refreshed
footprints every 10 s. The new orca-process-footprint helper reads
phys_footprint for every same-user process in ~3 ms, so footprints now
refresh on the panel's 2 s poll. top stays as the fallback when the helper
is missing or fails.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 13:32:55 -07:00
Neilandoutof-place 568131056d fix(i18n): translate crash report, notification settings and tour copy (#34066)
Route the remaining hardcoded English in the crash report dialog, the
macOS/Windows notification failure hint, the feature tour reopen hint and
the CLI install fallback through translate(), with keys in all locales.

Fixes #27074

Co-authored-by: outof-place <contact@outofplace.space>
2026-10-26 13:27:48 -07:00
NeilandClaude e63b8f4c7e fix(wsl-host): a runtime-call reconnect never boots a distro that stopped meanwhile (E9 follow-up) (#34050)
* fix(wsl-host): a runtime-call reconnect never boots a distro that stopped meanwhile (E9)

ensureForRuntimeCall reconnects only to a distro confirmed running, but the distro
could stop between that read and the reconnect, which would then boot it. A runtime
call now asks for a no-boot connect: the connector supplies a running-list check that
the connection manager runs right before anything spawns in the distro, refusing
with WslDistroNotRunningError (and starting nothing) when the distro isn't confirmed
running. The generation is read before that await, so a close during it still
supersedes the connect.

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

* test(wsl-host): import the no-boot error alongside the other connection errors

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

* fix(wsl-host): no-boot connects don't swallow a focus boot, report no failure, re-verify (E9 review)

Review of #34050:
- A connect that may boot (focus, Connect) joined an in-flight no-boot connect and so
  inherited its refusal. It now waits for that one and runs its own.
- A no-boot refusal published 'failed'. It now publishes nothing from the manager;
  the supervisor, whose connect had already disarmed the entry, re-verifies instead of
  arming the incumbent (which would dial into the distro), so liveness gives the
  verdict and parks a stopped distro.
- The generation is checked right after the running-list read, so a close during it
  supersedes the connect before anything deploys.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 13:27:33 -07:00
Kelvin Amoaba cf6c70bfce fix(mobile): keep chat-agent create when the capability check spans a lan-to-relay switch (#33697) 2026-10-26 20:25:58 +00:00
Kelvin Amoaba b590977919 fix(notifications): workspace mark as read clears the chat alert on the phone (#33713) 2026-10-26 20:21:37 +00:00
Neil f8a0b0f60c refactor(store): colocate agent-status action composition (#34045) 2026-10-26 13:20:11 -07:00
Neil 9185d1021e fix(runtime): share one lazy load of the session-tabs apply modules across refreshes (#33939)
Concurrent refreshes each re-imported the same four modules. Under vitest,
overlapping imports of a vi.mock'd module share one importer callstack and
fall through to the real module, so the second and third of three rapid
browser creates loaded and transformed the real session-tabs graph inside the
test (about 20-28s) instead of using the mocks.
2026-10-26 13:18:14 -07:00
Jinwoo Hong f0cc235427 fix(orchestration): let a sleeping chat's background commands send as it (#34049)
* fix(orchestration): let a sleeping chat's background commands send as it

* fix(orchestration): keep unreconciled sleeping sessions and ask refused

* test(orchestration): cover ask refusal for a sleeping session
2026-10-26 16:18:03 -04:00
Neil b7ad8be42e refactor(agent-hooks): launch the WSL hook relay through the process host (#34051)
Build the wsl.exe argv with buildWslExecArgs and start it with spawnProcess
from @orca/process-host instead of a hand-built node:child_process spawn.
2026-10-26 13:17:06 -07:00
Brennan Benson 9ae33a96f9 fix(native-chat): keep damaged chats readable without granting agent actions (#31931)
* fix(native-chat): validate saved next-fence floors before use

* WIP: separate saved conversation observations from runtime proof

* Consolidate duplicate imports for WIP compiler checkpoint

* Preserve saved conversation observations with strict runtime authority

* Consolidate session admission and catalog imports

* fix: align conversation observation contracts and fixtures

* test: update conversation observation and writer fixtures

* test: use checked host fixtures for structured workers

* fix(native-chat): bound conversation projection work per request

* test(native-chat): consolidate scale fixture imports

* test(native-chat): use checked scale fixture types

* test(native-chat): bound unreadable inventory traversal

* Test native CLI admission and durable reference reads

* test: bound cold conversation name subscription work

* test: distinguish native receipt probes from terminal identity

* test: retain exact mutation refusal recovery identity

* fix: explain agent conversation preparation refusals

* test: adapt remaining conversation readers and document CLI timeout

* fix: register preparation refusal English message

* test: align conversation fixtures with checked read APIs

* test(native-chat): use checked conversation in Codex fixture
2026-10-26 13:16:41 -07:00
Kelvin Amoaba d6567867e5 fix(mobile): ask before closing other tabs, sharing desktop's confirm (#33704) 2026-10-26 20:15:24 +00:00
Brennan Benson 9608420517 Keep workspace labels independent of automatic branch names (#32919)
* Fix automatic branch naming for workspace labels in every language

* Use creature branch seeds for typed workspace labels

* Keep first-work generator mocks in creator test suites

* Type the created worktree test mock from its production signature

* Assert created worktree results before exercising first work

* Match the missing-folder update contract in first-work fixtures
2026-10-26 13:14:16 -07:00
Pr1pandBrennan Benson fdcf193cd4 fix(worktree): track explicit remote-only branch (#31645)
* fix(worktree): track explicit remote branch

* test(worktree): cover remote branch path retry

* fix(worktree): resolve cached remote branches canonically

* fix(git): retain commit validation in bounded ref probes

* fix(worktree): preserve selected remote identity during creation

* test(worktree): count cached resolver Git work during path retries

* Fix branch intent state in composer source fixture

* Make Git and daemon regression fixtures portable

* Use the selected base for existing branch creation

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 13:13:56 -07:00
Samuel VilaandBrennan Benson 161927f562 fix(native-chat): make the Chat UI ⇄ terminal shortcut a remappable keybinding (#31679)
* fix(native-chat): make the chat view toggle a remappable keybinding

The terminal and Chat UI toggle was hardcoded to Mod+Shift+J, so users
could not rebind or disable it, Settings did not list it, and it
overrode user bindings on that chord. Declare it as
terminal.toggleNativeChat in the keybinding registry, match it through
the user's keybindings, and render its menu labels from the registry.

* fix(keybindings): align native chat toggle admission and execution

* fix(keybindings): preserve runtime input and defer closed menu hints

* test(keybindings): use typed alias read instrumentation

* Fix keybinding dependency direction and physical modifier inputs

* Preserve typed input facts in floating shortcut arbitration

* Clarify native chat shortcut precedence on Windows and Linux

* Simplify native chat shortcut resolution and nominal labels

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 13:13:34 -07:00
Brennan Benson 9665316b16 Prevent macOS port scans from accumulating stuck processes (#32045)
* fix(ports): bound macOS scans by the lifetime of each operation

* refactor(ports): keep Darwin metadata acquisition together

* fix(ports): preserve valid Darwin observations and source host routing

* fix(ports): retain scan admission outside aged temporary cleanup

* perf(ports): skip unused listener acquisition for ownership actions

* test(ports): make child fixture streams portable across runtimes

* fix(ports): share source host derivation across scan rows

* test(ports): initialize scan projection without a type assertion

* fix(ports): restore existing browser open routing

* fix(ports): preserve scanner compatibility on degraded hosts

* test(ports): explain real process lifetime timing
2026-10-26 13:13:17 -07:00
Brennan Benson 0266b5f95f fix(opencode): allow model picks when discovery is unavailable (#31985)
* fix(opencode): allow picked models across CLI updates

* test(opencode): prune obsolete timeout ratchet allowance

* fix(opencode): use resolved agents and refuse unsafe workers upfront

* fix(i18n): include OpenCode refusal messages in runtime catalog
2026-10-26 13:12:53 -07:00
Kelvin Amoaba 67851c0f51 fix(cli): resolve folder workspace terminals to their own workspace (#33703) 2026-10-26 20:12:36 +00:00
lvxindaandBrennan Benson 5381113900 fix(native-chat): render math and center standalone equations (#31546)
* fix(native-chat): render math and center standalone equations

* fix(native-chat): parse math without rewriting message source

* fix(native-chat): accept element roots for math selections

* fix(native-chat): preserve math boundaries and selected source

* fix(native-chat): derive math fence closure from accepted parser events

* fix(native-chat): reuse exhausted math searches per tokenizer

* fix(native-chat): load math typesetting after parsed formulas

* Use declaration references for chat math augmentations

* Declare chat math metadata and register equation label

* Preserve i18n exports in selection quote test mock

* test: expect cached legacy failure display reuse

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-26 13:12:33 -07:00
Kelvin Amoaba 33a86f3352 fix(mobile): open page sheets above an already-open keyboard (#33760) 2026-10-26 20:12:07 +00:00
Chen ShiandNeil 44d2fcb637 fix(i18n): correct wrong-sense Simplified Chinese UI strings (#29321)
Several zh.json strings used a translation with the wrong meaning for the
UI context (e.g. git base ref, dividers, host, browser profile, search
keywords). Align them with the intended sense and consistent terminology.

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 13:03:11 -07:00
4509092118 fix(packaging): ship agent-browser skill catalog with desktop builds (#17714)
The packaged agent-browser binary resolves its version-matched skills from the
nearest skills/ directory above it (Resources/). Only the binary shipped, so
`agent-browser skills get core` answered "Skill not found" and `skills list`
"No skills found". Ship node_modules/agent-browser/skills/agent-browser and
skill-data beside it on mac, linux and win, and cover it with a test that stages
the host's extraResources slice and runs the real binary.

Refs #17705

Co-authored-by: zerone0x <zerone0x@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 13:02:09 -07:00
Neil ec42b433ca fix(ssh): make Move anyway the next step when saved items refuse a host's move (#34041)
* fix(ssh): show Move anyway on a host card whose move saved state refuses

A host whose move to its Orca server was refused over saved state (an
enabled SSH automation and its runs, stale workspace details, unsupported
saved tabs) stayed in error on every Connect. Move anyway, which connects
it and leaves those items on this computer, was only in the card's
overflow menu, so the host looked stuck. The card now offers Move anyway
next to its refusal, as it already does for Recover server.

Refs #29083.

* fix(ssh): make Move anyway the next step when saved items refuse a host's move

When a host's move to its Orca server is refused only over saved items
that Move anyway can leave on this computer (#29083's enabled
automation and its runs, for example), every surface now leads with it:
- the host card says which items can't move and that Move anyway
  connects the host and keeps them here, with Move anyway as its
  primary button;
- the refusal toast says the same and offers Move anyway, opening SSH
  Hosts where the move is confirmed;
- the terminal pane's Move anyway is primary too;
- the host picker and connect toast read the same line.

Refs #29083.
2026-10-26 13:01:30 -07:00
OrcaWinandm4air faaa59049f fix(perf): preserve TS worker idle deadlines and boot guard diagnostics (#34055)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-26 13:00:29 -07:00
Kelvin AmoabaandRadu Toader c4f8fe5f3c feat(mobile): copy button on each code block in chat (#34039)
Co-authored-by: Radu Toader <radu.m.toader@gmail.com>
2026-10-26 20:00:10 +00:00
NeilandClaude 2dd8207369 fix(wsl-host): boot only the focused WSL host, and keep a stopped one down (E9 A) (#33838)
* fix(wsl-host): boot only the focused WSL host, and keep a stopped one down

E9 connect policy, part 1. A stopped distro now boots only for an explicit user action
or when its host becomes focused:
- Visible work is the active workspace plus workspaces focused earlier in this window
  that still have tabs. Saved tabs alone no longer count, so a launch with two hosts
  boots only the focused one.
- After a confirmed stop (wsl --shutdown, WSL update) the host is parked. Liveness no
  longer reboots it even when it is visible, and polls get "<distro> was stopped"
  instead of a boot. Re-focusing the host, Connect, or the distro running again lifts it.
- Liveness recovery always needs a confirmed-running distro, so a distro that stops
  mid-recovery is never booted again.

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

* test(wsl-host): launch boots one of two hosts; polls never boot; lost contact never parks

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

* fix(wsl-host): only a focus entry or a user action boots a WSL host (E9 review)

Review of #33838:
- Re-focus never lifted a park: a host focused earlier stayed in the visible set, and
  the renderer skips unchanged reports. The renderer now sends a separate focus entry
  (focusHost) each time the user switches to a workspace on a WSL host, including the
  launch restore; only that, or Connect, lifts a park and may boot.
- Runtime calls could boot: ensureForRuntimeCall connected any visible, unparked host.
  It now reads the host's reachability first: a confirmed-stopped distro parks at once,
  an unreadable running list refuses, and only a distro confirmed running is
  reconnected (for visible work). Visible work itself never connects anything.
- Turning WSL hosts on no longer boots every visible host, and focus isn't recorded
  while they're off; the window re-reports its focused host instead.
- Each window's visible work is kept apart and unioned, so one window can't drop
  another's.
- wakeForAutomation/isConnected move to the automation PR, which uses them.

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

* fix(wsl-host): a poll waits for liveness's verdict right after an exit (E9 re-review)

Right after `wsl --shutdown` WSL can still list the stopping distro as running (the
supervisor waits and re-reads for exactly this). A poll's cold probe then read
'unreachable', reconnected, superseded the pending distro-stopped verdict and booted
the distro again. The supervisor now reports when it is settling (a verdict in
progress, or a watch/holder exit within the last few seconds), and a runtime call
refuses instead of reconnecting then; the verdict parks the host as before.

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

* test(wsl-host): a new supervised entry starts with no recorded exit

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 12:52:16 -07:00
Neil 0283880bb1 fix(native-chat): pass session-reported slash commands through to the session (#34048)
OMP's ACP session advertises commands it handles itself (e.g. /fast), but
native chat claimed them as host-only TUI commands and refused them as
unavailable. Commands the running session reports in its slash menu are now
left unclaimed so they send through, on desktop and mobile. Mobile reads the
session command list once in the native-chat lane and shares it between the
send path and the composer menu.
2026-10-26 12:48:34 -07:00
NeilandClaude f551e0addb fix(forge): skip PR refreshes for a WSL host that is off, and say so (E9 C) (#33840)
* fix(forge): skip PR refreshes for a WSL host that is off, and say so

E9 connect policy, part 3. PR status for a workspace on a WSL host is fetched through
the host, and a poll never boots it. While the host isn't ready, the visible-row
refresh skips it (the row keeps its last badge and the existing "host disconnected"
mark), a direct PR refresh keeps the last answer and records a 'host-off' skip, and
the Checks panel says the host is off and to reconnect it. The cached-field half of the
refresh candidate moves to its own helper to keep the lookup file in bounds.

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

* test(forge): a WSL host that goes off keeps its last PR badge and records host-off

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

* fix(forge): only a stopped or closed WSL host is "off"; mark row badges as last known (E9 review)

Review of #33840:
- Connecting, reconnecting and unverifiable hosts were treated as off. Only a
  confirmed-stopped (or parked) host, or one closed with WSL hosts turned off, is off
  now; anything else lets the call proceed or fail as usual. A status change re-runs
  the visible refresh, so rows refresh as soon as the host turns ready.
- Row badges now carry the stale mark too: the card's review status gets the hover
  card's last-known treatment and "Last known status" in its label, and the hover
  card's reference rows are stale and not fetched while the host is off.

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

* test(forge): build the host-off PR refresh test on the shared GitHub slice harness

Drops the copied store and seed casts.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 12:48:32 -07:00
OrcaWinandOrcaWin f34c13ca1e test: remove low-value main-process suites and browser probes (#33889)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 12:48:28 -07:00
Kelvin Amoaba 2451037176 fix(mobile): send terminal controls in key order with live typing (#33724) 2026-10-26 19:38:23 +00:00
Jinwoo Hong fa3bd28995 Let Resource Manager End stop orphaned terminals that main is attached to (#34040) 2026-10-26 15:29:06 -04:00
hjkwonandNeil 5e907783fd fix(linear): make new-project dialog popovers wheel-scrollable (#16413)
The Team, Lead, Members and Labels popovers in the Linear new-project
dialog are portaled outside the dialog, so its scroll-lock cancelled
native wheel input over their inner max-h-64 lists. Opt their
PopoverContent into the shared wheel shim via wheelScroll, and move the
p-1 padding onto the children so the layout is unchanged.

Fixes #16412

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 12:23:23 -07:00
apeppppandNeil 8f4b64cf27 fix(i18n): correct native-chat subagent and tool-run summary strings in zh/ja/ko/fr (#33561)
Replace mistranslated subagent summaries ("kicked off" rendered as "fired"/
"kicked out", untranslated "Ran") and add missing measure words to the zh
tool-run clauses. Leading tool-run clauses are now joined with a translated
runListSeparator so CJK locales use 、 instead of an English comma.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-26 12:17:04 -07:00
Neil b67429c03f fix(ssh): lead an SSH connect failure with what to do about it (#33990)
* fix(ssh): say why SSH failed when Connect never reaches the host

When the SSH session itself could not open (key rejected, port refused,
host not answering, host key not trusted), Connect on a host Orca had not
set up yet said "Orca couldn't start its server on this host" and offered
a plain SSH terminal that could not work either. Errors from opening the
SSH session are now marked where they are dialed, and a setup that fails
on one ends the connect with SSH's own reason. A held move keeps its
status. The connect-failure toast also drops Electron's IPC prefix.

* fix(ssh): lead an SSH connect failure with what to do about it

#33928 shows SSH's own reason when Connect never reaches the host. Raw
reasons like "connect ECONNREFUSED 10.0.0.1:22" or "Timed out while
waiting for SSH authentication" still leave users guessing. A failure
from opening the SSH session is now published with a next step for the
kinds users can act on (host key mismatch, rejected sign-in, refused
port, unknown host name, no route, timeout), and SSH's words follow in
parentheses. The connect-failure toast reads the same published text.
2026-10-26 12:16:04 -07:00
Jinwoo Hong 98690db2ab feat(connector): the desktop holds the Orca Cloud connector poll (#33852)
With the experimentalConnectors setting on and the desktop signed in to Orca, the desktop keeps one long-poll request open to the Orca Cloud connector and hands each delivery to the existing connector code that starts or talks to an agent. Each delivery is confirmed twice (received, then its result), and the agent's turn and prompt events are reported back. The desktop authenticates with a 5-minute connector token from the Orca sign-in service, follows the relay's start/stop lifecycle, and stops on sign-out. Its hello lists Slack as the one source it accepts. Off by default with no settings UI.
2026-10-26 15:08:31 -04:00
Neil ae55694d27 fix(ssh): show Move anyway on a host card whose move saved state refuses (#33961)
A host whose move to its Orca server was refused over saved state (an
enabled SSH automation and its runs, stale workspace details, unsupported
saved tabs) stayed in error on every Connect. Move anyway, which connects
it and leaves those items on this computer, was only in the card's
overflow menu, so the host looked stuck. The card now offers Move anyway
next to its refusal, as it already does for Recover server.

Refs #29083.
2026-10-26 12:02:02 -07:00
Jinwoo Hong 22fd6f505f feat(connector-contract): conversations from Slack, Discord or Linear; machines list the sources they accept (#33862)
A connector conversation now names its source (slack, discord or linear), and a posted reply reports a neutral messageId. Each machine's hello lists the sources it accepts, and the cloud only routes a Slack conversation to machines that list Slack. Machine events from other sources are filtered out where they arrive, and a reply for a non-Slack conversation is refused, so a Discord or Linear conversation can never post into a Slack thread with the same id. The unused turn-bound cancel fields are removed (they return with Stop). Inert: no shipped desktop uses the contract, and Slack is off unless configured.
2026-10-26 14:53:48 -04:00
Neil 7b1bb970b6 fix(board): truncate workspace status labels without splitting emoji (#34035)
sanitizeWorkspaceStatusLabel cut labels with slice(0, 32), which could keep
only the high surrogate of an emoji straddling the limit and render U+FFFD.
Use the existing surrogate-safe sliceAtCodeUnitLimit helper instead.
2026-10-26 11:53:36 -07:00
Neil caa49c8d52 fix(agent-dashboard): keep the drawer's dismissal Escape out of the focused terminal (#34037)
Closing the Agent Dashboard drawer or workspace board with Escape still
forwarded the key to a focused xterm, because xterm ignores
defaultPrevented. Stop propagation only when the target is the xterm
helper textarea so other fields keep their own Escape handling.
2026-10-26 11:48:08 -07:00
Neil c979079fa6 fix(linux): declare ALSA and GBM runtime dependencies in deb/rpm packages (#34036) 2026-10-26 11:47:51 -07:00
shahidbeig-a11yandNeil 5ad7df46e3 fix(project): name the folder's project id when setup-existing-folder identity mismatches (#23551)
When an imported or cloned folder's derived project id does not match the
selected project, the error now names the id the folder resolves to (for
example github:owner/repo) instead of a generic mismatch message. Host-local
ids and identical ids keep the generic message. The setup-existing-folder
help notes which ids --project accepts.

Fixes #23528

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 11:47:32 -07:00
Jinwoo Hong e33400845c feat(connector): Slack answer buttons: the owner answers the agent's approvals and questions from the thread (#33856)
When a Slack-started agent asks for approval or asks one pick-one question, the thread gets a card with one button per option. Only the person who asked for the work can answer; anyone else is told so privately. The answer travels through the existing inbox and delivery path, and the card closes once answered or no longer pending. Other question formats (grouped, pick-several, typed answers) still point to Orca; a follow-up adds them. Connector service only; Slack is off unless configured.
2026-10-26 14:45:25 -04:00
Kelvin Amoaba f195099ccc fix(mobile): unmount history rows once the web chat returns to its live tail (#33664) 2026-10-26 18:41:45 +00:00
Yunqian FanandNeil bc4e66c799 fix(workspace): keep the active workspace key in sync with the active worktree (#14475)
setActiveWorktree's no-op guard now compares activeWorkspaceKey with the key
derived from the target worktree, so reselecting the current worktree repairs
a stale key instead of returning early.

Session hydration always derives activeWorkspaceKey from the restored
activeWorktreeId instead of trusting a persisted key that may name another
workspace, which kept the wrong sidebar row highlighted after restart.

Fixes #14474

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 11:41:28 -07:00
Kelvin Amoaba 8a1213920e fix(terminal): answer terminal queries while a phone watches at desktop size (#33674) 2026-10-26 18:38:27 +00:00