Each local terminal spawn with a Pi agent home rewrote three Orca-owned
extension files (~54 KB) synchronously on the main thread even when their
contents were already current. Compare the read we already do for the
ownership check and write only when the content differs.
Co-authored-by: m4air <m4air@Mac.localdomain>
The first agent-availability derive forced a second interactive login shell
moments after the Claude profile router's capture; settings changes did the
same per update. Recapture now accepts a capture started within the 10s
shell-environment TTL, and startedAfter lookups answer from a finished run
that started after the request.
Co-authored-by: m4air <m4air@Mac.localdomain>
The saved-password detector re-scanned every credential form on each
mutating page twice a second (forcing layout per input and walking the
page's buttons), but main only reads those snapshots for 2.5 s after a
login navigates. Main now tells each document at enable whether it wants
them.
Co-authored-by: m4air <m4air@Mac.localdomain>
* fix(ssh): stop restarting a managed orcad that keeps crashing, and say why
orcad now reports, in its health, a previous run that died on this boot
without releasing its instance lock. Graceful stops (idle exit, explicit
stop, update activation, rollback) release the lock, and a reboot changes
the boot id, so none of those count. After 3 such exits in 10 minutes the
desktop stops waking the server until an explicit Connect, and shows the
reason with orcad.log's path and tail instead of timing out.
Refs #37538
* fix(ssh): count fatal stops and failed starts; brake every automatic wake
- A fatal orcad stop (uncaught exception) keeps its instance lock, so the
next start reports it.
- A launch that never becomes ready counts once, not again when the next
orcad reports it.
- The tunnel port-recovery wake goes through the same brake.
- macOS and Windows hosts use OS uptime as boot evidence.
- Connect also drops a cached serving verdict.
Refs #37538
* fix(ssh): serialize crash-loop brake admission per host
Refs #37538
* fix(ssh): count reported Windows launch failures toward the crash-loop brake
Refs #37538
* fix(orcad): read the Windows launch report when the launcher exits nonzero
Refs #37538
* fix(ssh): ignore brake accounting from wakes begun before a reconnect
Refs #37538
* fix(ssh): count only launches that failed readiness, not inspection failures
Refs #37538
* fix(orcad): keep the command error when a Windows launch left no report
Refs #37538
* fix(ssh): surface the crash-loop reason from tunnel port recovery
Refs #37538
* fix(ssh): take the brake's reset epoch when a wake is requested
Refs #37538
* test(ssh): keep the cast on its SAFETY line
Refs #37538
* fix(ssh): tighten what the crash-loop brake counts and when it lets go
- A Windows host-policy refusal is not counted; its own guidance stays.
- The braked detail names the last failed start.
- A latch set on a run that served is released once that run's lock shows
it stopped cleanly.
- The update path's already-active wake goes through the brake.
- The fatal-stop test drops its shutdown timer.
Refs #37538
* fix(ssh): brake only a new launch, and count the wake after an automatic release
Refs #37538
* fix(ssh): refuse a braked launch at the fenced launch decision itself
Refs #37538
* fix(ssh): a refused launch also skips fence recovery, which can relaunch
Refs #37538
* test(ssh): a refused launch leaves fence recovery alone
Refs #37538
* fix(ssh): count failed recovery launches; dedupe only runs that ran
Refs #37538
* fix(ssh): explicit Update and Restart re-arm the crash-loop brake; release it after a reboot
- Update and Restart are user actions like Connect: they clear the brake.
- An auto-update that meets the brake on an already-current host is a
skip, never a recorded update failure that would block retries.
- The brake releases once the latched run's lock comes from an earlier boot.
Refs #37538
* fix(ssh): every explicit server action re-arms the brake; count failed candidate launches in recovery
Refs #37538
* fix(ssh): only gated wakes can return launch-refused
Ungated callers (version adoption, stale-lock reclaim, WSL, restart) pass no
launch gate, so their wake type no longer includes a refusal they cannot get.
Refs #37538
* fix(ssh): reboot evidence also releases a brake raised by failed starts
Refs #37538
* fix(ssh): release the brake only on a new boot of the machine that answered when it engaged
A leftover lock's boot id cannot tell a reboot from a shared-home lock
written by another login node or one older than the loop.
Refs #37538
* fix(ssh): a braked host seen serving can be released by that run's clean exit
Refs #37538
* fix(ssh): identify the rebooted machine by hostname and machine id
Login nodes behind one hostname share it, so the hostname alone cannot tell
them apart. Without a machine id the brake does not auto-release.
Refs #37538
* fix(ssh): only an answered run counts as served; a reboot must postdate the brake
A clone with the same hostname and machine id that booted earlier is a
different backend, not a reboot. Boot and read times come from the host's
own clock.
Refs #37538
* fix(ssh): only an answer received after the brake engaged marks its run served
A control-socket pong up to 20 s old may come from a run that has since
exited cleanly; counting it would let failed starts release the brake.
Refs #37538
* fix(ssh): say what to do when a host's server setup stops on a known cause
A managed SSH host whose server setup deferred always showed "Orca couldn't
start its server on this host. Try connecting again.", even when a retry
can't help (full disk, an interrupted update needing Recover, another Orca
runtime on the host's data). The deferral code was dropped before it reached
the host status.
Carry the code as an optional field on the unserved status, keep the retry
line only for codes a later connect clears, and name the fix for the ones a
user can act on. Older hosts and thrown errors carry no code and keep the
retry line.
Refs #38347
* fix(ssh): drop the Recover advice a first setup can't act on
Connect already runs activation recovery before deploying, and an unregistered
host has no Recover control, so that code now points at Details. Soften the
live-runtime line, keep waiting causes in the warning tone, and test the
published code and its remedy rather than English copy.
Refs #38347
* fix(ssh): treat an unreadable server build as needing Details, not a retry
Refs #38347
* fix(terminal): paint a new WebGL canvas inside a synchronized frame instead of leaving it blank
A replaced WebGL renderer's first paint went through terminal.refresh(), which
xterm buffers while DEC 2026 synchronized output is held. The old canvas is
already gone, so the pane showed an empty canvas until the program closed its
frame. Over a remote link Codex's frames often span packets, so revealing a
remote worktree flashed blank/content for under a second, only with WebGL.
Paint a just-attached or just-resized canvas at once. A canvas created while
its renderer is paused (hidden worktree) is remembered until its first paint,
so the reveal present paints it through the open frame instead of waiting.
Also drop the WebGL rebuild after every reattach replay: it worked around an
atlas problem that no longer exists and replaced the renderer on every reveal.
* fix(terminal): limit a never-painted canvas to one mid-frame paint
* test(terminal): prove a swapped WebGL canvas paints through spinner sync frames
* fix(terminal): clear the never-painted mark on any forced paint; drop e2e casts
* test(terminal): keep the spinner repro inside the flaky-pattern ratchet
orca account list called accounts.list with refreshUsage:false, so on an
idle headless host the JSON's rateLimits stayed null. JSON output now
asks the host to refresh only stale usage windows (the same
refresh-if-stale an accounts.subscribe stream runs), via a new optional
refreshStaleUsage param. The host waits at most 10s for it, so slow
inactive-account probes can't push the CLI past its request timeout;
they keep running and land on the next call. Older hosts strip the unknown field and keep
their prior no-refresh behavior; human output still skips the refresh.
Fixes#37256
* Add refresh action for folder project groups
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refresh nested folder groups and flag incomplete scans
- Import new repos at any scanned depth into the deepest matching folder-scan sub-group
- Warn when the scan stopped early instead of reporting no new projects
- Match imported repos on the owning host only
- Show a loading toast while refreshing and pluralize the success message
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Claude in the Chat UI gets the same Artifact tools as Claude in a terminal: Orca sets CLAUDE_CODE_ARTIFACT=1 for chat launches unless the user already set a value.
Co-authored-by: Luke Ellison <lukeellison4@gmail.com>
* fix(native-chat): keep a Claude chat's effort changeable after its first turn
After its first turn a Claude chat saves the model id Claude reports it ran
(claude-opus-5-5), while the model list names that model only by its alias
(opus). Every capability lookup matched on the row id, so the chat's model
had no effort choices and effort turned into display-only text on desktop
and phone.
A listed row now describes a model id by its own id or by the model it
resolves to. The match supplies capabilities only; the chat keeps showing and
sending the exact model it ran, so it never drifts when the alias moves. The
host applies the same rule to the row it adds for the chat's model, for
clients that read the answer's models.
* test(native-chat): cover exact-row precedence for a described model id
* fix(native-chat): remember an after-reply effort without changing the new-chat model
An effort pick in a chat on the resolved id it ran is remembered under the
listed row that runs that model and leaves the new-chat model untouched, as
the common pattern keeps the sticky model and updates only its options. The
resolved id is never stored as a default.
* refactor(native-chat): move the remembered-pick model choice into its own module
* fix(native-chat): keep a held effort pick from adopting a new-chat model
* test(native-chat): run the held-effort case as a Claude launch
* revert(native-chat): drop the host-side capability copy no live answer can use
Claude's live session listing carries no resolvedModel, so the host never matched there, and phones draw the host-served chat bundle, so every client already runs the shared lookup.
* Key Claude's model rows by the model each one runs
Claude's listing named rows by alias (opus), while a chat saves the model
it ran (claude-opus-5-5) after its first turn, so equivalent chats held two
kinds of model value and a chat's effort could go read-only. Rows are now
keyed by the versioned model they run, the common pattern: a pick saves the
same id the CLI reports. Aliases stay as their own rows with their own
effort levels; the picker lists one only while the chat is on it or a
search matches it, and the phone list leaves them out. A saved alias is
kept as the user picked it. A configured alias default marks the versioned
row it runs, and an effort picked in an existing or resumed chat no longer
changes the model new chats start on, whatever ids the chat and listing use.
* test: give the delayed-report alias test's timeout its reason
* Remember a new chat's picks by its first turn, and keep aliases reachable everywhere
- A chat counts as existing once it has a turn or a send, or when it was
opened rather than launched here, not once its launch published: an empty
new chat's effort pick adopts its model for new chats again, and every
agent's existing chat keeps the remembered new-chat model.
- Only a row that names itself as the model it runs covers an alias, so an
older host's alias rows stay listed beside a chat's stand-in row.
- The phone lists an alias of a listed model behind a More models toggle.
- The terminal-chat and commit-message model lists carry each row's
resolvedModel, so they list aliases the same way; an older remote that
omits it keeps its full list.
* fix(mobile): keep the More models toggle's state without an effect reset
* Keep commit-message aliases selectable and their resolved model out of saved settings
The Source Control model Select has no search, so it lists alias rows after
the versioned ones instead of hiding them. Discovered models are saved
without an alias row's resolvedModel, and the refresh compares that same
saved shape, so the settings cache gains no field.
* Drop an unrelated audit-tools lockfile change; reset the phone's More models toggle when its drawer closes
* test: build the saved-models test's settings without a cast
* fix(claude): display native resolved effort consistently
* fix(claude): retain native effort report confirmation
* fix(claude): derive effort confirmation from current held input
* test(claude): assert empty effort confirmation after model report
* test(claude): reject late effort confirmation across a new pick
* Add a file, markdown preview or terminal selection to the chat
Right-click Add to chat in the file editor and terminal, and the chat's
floating Add to chat button in the markdown preview, quote the selection
under its path and lines (or terminal title) into the composer of the
workspace's most recently used chat, then switch to that chat.
Tracked in #16640.
* Repair Add to chat review findings
- Add selections as independent additions, so a repeated add lands.
- Markdown preview: source lines without review tools, text-edge endpoints,
folder workspaces, and no selection reading in previews that don't own it.
- Editor: keep every multi-cursor and column range.
- Fence long backtick runs without spreading them into Math.max.
- Terminal chat beside a shell: reveal the chat leaf so its composer takes focus.
- Count a pointer press in an already-active chat or terminal pane as use of its
tab, so the chat in use is the one that receives the selection.
Tracked in #16640.
* Use a type guard instead of a cast for markdown block source lines
* Add to chat: typed-input draft writes and session-local chat use
- Write the quote like typed input (immediate, hydration-safe append): a
lone /compact or /clear stays and a repeated quote is added again.
- Remember clicks and typing in chat and terminal panes for the session,
and target the chat with the later of that and its last activation;
no change to saved tab state.
- Markdown code blocks carry source lines without review tools.
- Reveal a terminal chat hidden by an expanded shell pane, and target the
workspace on screen from the floating terminal.
Tracked in #16640.
* Add to chat: collapse the expanded pane by its leaf, callout source lines, O(1) use recording
- Collapse the actual expanded shell (by saved leaf) when revealing a terminal
chat, also after a parked pane remounts.
- Callouts keep their source lines in the preview without review tools.
- Record pane use in O(1); drop closed tabs' records when a selection is added.
- The agent-reply Add to chat appends after the draft like the others.
Tracked in #16640.
* Keep a covering chat's focus after a pane collapses; type the focus-event test
- refreshPaneSizes focuses the active pane through focusPanePreservingOverlays,
so collapsing an expanded shell never hands keys to the xterm under a chat.
- Use branded leaf ids in the focus-event test (CI typecheck).
* Bound session pane-use records by the tabs still open
Prune records of closed tabs when the record count doubles, so they stay
within twice the open tabs without waiting for an Add to chat.
* Retire pane-use records when a workspace's tab list changes
* Count tab reads in the pane-use test with a getter
* Don't record a key an app shortcut handled as pane use
* Describe appendText as an independent append
* Add to chat: pick the target from the notes Send-to list instead of guessing the last-used chat
* Add to chat: plain terminal agents get the notes guarded paste without Enter
* Add to chat menu: Escape returns focus to the selection's editor
* Add to chat failures name the selection, without the internal code
* Keep notes sends' arguments unchanged; open the point menu without loading its components
* fix(agents): paired-host agent tabs use the host's launch settings
Agent tabs opened on a paired host were replacing that host's permissions and Arguments with the desktop's settings. Let the host plan fresh launches, carry the user's choices separately, and preserve existing prepared launches when an older host cannot express them. Action Arguments replace configured Arguments while inheriting the host's permission settings; resumed sessions keep their recorded recipe.
* fix(agents): paired-host agent tabs use the host's launch settings
Preserve per-launch permissions on older paired hosts by compiling picks they cannot apply from their own settings. Keep authored Arguments separate from saved model defaults so a command's pinned model wins. Use the host's reported shell and execution platform for argument quoting, and remove unused prompt-delivery wrappers.
* fix(agents): paired-host agent tabs use the host's launch settings
Replace recognized permission flags from older paired hosts when a launch picks another permission, while preserving unrelated Arguments and ambiguous prepared launches. Keep multiline drafts working on Command Prompt hosts and omit chat-only permissions from terminal requests.
* fix(agents): paired-host agent tabs use the host's launch settings
Preserve per-launch permission choices that suppress the paired host's Full access flag even when the choice emits no flag itself. Compile these choices from the host snapshot when older launch preferences cannot carry them, while keeping unsupported OpenCode terminal permissions filtered out.
* test: merge duplicate imports in paired launch options test
* test: drop type assertions in paired launch options test
* chore: lower focus-read ratchet baseline after removing creation wrappers
* fix(agents): paired-host agent tabs use the host's launch settings
Keep accepted inline fork drafts delivered when their mirrored tab is unavailable, and cancel launches whose pairing changes during negotiation. Keep action Arguments metadata on the tab route so injected workspace launch callbacks retain their contract. Update consumer fixtures to run lazy compatibility preparation and verify the final launch inputs and cancellation boundary.
* fix(agents): paired-host agent tabs use the host's launch settings
Keep pairing changes during legacy launch preparation silent and preserve the prompt for retry. Make picker tests exercise structured model picks on modern hosts while retaining prepared-command coverage for older hosts.
* fix(agents): paired-host agent tabs use the host's launch settings
A permission pick on an older paired host could turn desktop-configured Arguments into a launch override, including the desktop's model. Keep settings-seeded text out of the paired picker request so the host snapshot supplies defaults, while preserving explicitly edited launch Arguments.
* fix(agents): paired-host agent tabs use the host's launch settings
Keep permission-control choices separate from Arguments the user edited.
Fresh paired terminal launches now share that ownership projection in the
new-tab picker and continuation dialog, so a control change preserves the
host's executable and environment settings. Explicit Arguments edits,
including clearing the field, keep their existing launch behavior.
Cover old-host and modern requests, explicit terminal/chat edits, and the
continuation Start handler. Workspace creation keeps its existing path.
* fix(agents): paired-host agent tabs use the host's launch settings
Older paired hosts could inherit the desktop's model and permission defaults when the launch picker was configured or reopened. Read picker defaults and prepared launch recipes from the executing host, and compile edited Arguments using its settings. Preserve explicit empty edits, narrower permissions and draft prompts.
Keep inherited choices neutral while host settings are unavailable, retaining the existing compatibility launch when no usable host recipe exists.
* chore: merge duplicate type import and drop dead test branch
* fix(agents): paired-host agent tabs use the host's launch settings
Actions with explicit permission choices could unnecessarily read host settings and fall back to desktop preparation when those reads failed. Keep representable action Arguments on the host's authoritative launch path, and read inherited permissions only when the action needs them.
Cover an explicit empty Arguments override and Ask with unavailable settings, preserving the host executable and environment without a permission bypass.
* fix(agents): paired-host agent tabs use the host's launch settings
Supply the paired host's default agent in the shortcut test instead of
assuming the desktop's default applies. Keep a conflicting desktop default
so the shortcut continues to verify the paired host owns its selection.
* fix(ci): run the release skill-sharing Electron install step in bash
#38130 turned this step into a POSIX path fallback, but the skill sharing
release gate also runs on windows-2022, where the default shell is
PowerShell. The step failed with a ParserError, so release-preflight
skipped every build for the v1.4.250 cut.
* test(e2e): keep the one-time Codex notice out of golden runs
The v1.4.250 golden e2e on Linux timed out clicking New Terminal: the
'Orca now runs Codex without its shared server' toast fires once when the
golden stub (a Codex terminal) appears, and here it landed while the +
menu was open and closed it. Mark it seen in the completed-user fixture
like the other one-time notices, and restore that fixture from the
workflow ref in the release golden job so a recovered tag uses it.
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
* Let a finished worker keep messaging its coordinator
* Tell a finished remote worker why its coordinator is out of reach
* Let a finished worker's ask wait for its answer instead of starting a follow-up
* Share the assignee check, keep the finished lookup in dispatch-lookup, and fix review findings
* Match a finished terminal worker by its process too; cover resume after a follow-up
Claude Code shows its next-prompt suggestion as dim text in the empty
composer. The orchestration draft hold read it as the user's unsent draft
and held wakes for up to 10 minutes after the user last typed. The hold
now asks the typed-only composer reader (the one native chat already uses
for a terminal's unsent input), so dim suggestions and placeholders no
longer count, while real typed drafts still hold delivery.
Fixes#38015. Based on the diagnosis in #38015 and the approach explored
in #38077.
* fix(orchestration): let the task spec decide whether a worker pushes or opens a PR
The worker brief said "Don't post to Slack, GitHub, or other channels during the run." Codex read that as forbidding pushes and pull requests even when the task asked for them. The rule began as a reporting rule (reach the coordinator through the CLI, not Slack or GitHub comments), so fold it back into that sentence.
Fixes#38111
* fix(orchestration): drop the Slack and GitHub clause from the worker brief
* fix(contextual-tours): don't restart the agent sessions tour for existing users
v1.4.249 prepended a "New agents start here" step to the workspace agent
sessions tour. No earlier action completes it, so long-time users who never
closed the old tour (usually because they had already split panes) now see
it from step 1. Mark it seen at startup for profiles that finished
onboarding before that release; new users still get the full tour.
* test(contextual-tours): cover which profiles skip the agent sessions tour
Profiles still in onboarding, or onboarded at or after the v1.4.249 release,
keep the tour; earlier profiles get it marked seen without losing other seen tours.
* fix(contextual-tours): don't reopen the agent sessions tour for users who already split
Replace the startup cutoff backfill with a rule derived from what the user did:
a tour never auto-starts after one of its actions is already done (unless it is
already running this session or replayed), and a start never lands before the
latest done step, so steps added ahead of the user's progress can't rewind it.
* perf(contextual-tours): stop watching the page for a tour progress already blocks
* fix(contextual-tours): decide the progress block inside the tour effect
Selecting the derived flag ran it against partial test stores during render; read
the raw fields and decide in the effect, like the session-consumed check.
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
On a host whose temp directory is full or unwritable, every worker_done
failed and the task never settled (#38123). The settlement runs inside
savepoints, and SQLite keeps savepoint journals in a temp file by default.
When that file cannot be written, SQLite rolls back the whole transaction
itself, so our own rollback then failed with 'cannot rollback - no
transaction is active' and hid the real error. Heartbeats and questions
use no savepoints, which is why they kept working.
The orchestration database now keeps temp storage in memory, and the
lifecycle rollback skips when SQLite already ended the transaction so any
remaining failure of this kind reports its own error.