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
* 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
* fix(automations): accept Pi model and thinking extra arguments
* fix(automations): keep Pi provider pins and refuse unpinned inline keys
* fix(automations): match Pi value options to its argument parser
* fix(automations): refuse Pi model overrides beside unscoped inline keys
* test(automations): cover Pi's last-provider-wins key pin
* fix(automations): refuse any Pi custom Command text with --api-key
* fix(automations): drop the Pi inline-key pin guard
Pi already sends an unpinned inline key to the chosen model's provider and warns;
the user typed both the key and the model, so Orca does not refuse it.
* fix(automations): say the run's worktree was deleted; document plain run-use recovery
* revert(automations): drop the deleted-worktree wording change (not reproducible)
* docs(orchestration): list Tasks on recovery and note run-use drops other Runs
* docs(orchestration): delete the legacy takeover guide; keep orchestration docs to the normal flow
* fix(browser): a split tab create joins a browser pane already beside the caller
* fix(browser): the joined page is the pane's visible tab
* fix(browser): a split with an unknown caller still splits beside the active pane
Forward OpenCode login methods and form answers into private account enrollment. Reject missing repeated values before login and preserve literal arguments through the common Windows process launcher, with terminal input, JSON output and cancellation retained.
Thanks to Alonso Almeida (@Alonsojrr14) for the original implementation and follow-up fixes. Tracked in #37621.
Co-authored-by: Alonso Almeida <alonsojr1269@gmail.com>
A plugin with a worker and status bar items is now started when enabled and kept warm,
like a plugin with hooks, through one shared resident-worker predicate and warmer.
* feat(browser): guard page commands with an expected URL
* fix(browser): refuse an empty --expect-url and check it on dialogs and the forwarding desktop
* fix(browser): recheck the expected URL right before keys go out
* refactor(browser): drop duplicate session type, dialog alias and per-capability sidecar fields
* chore(browser): satisfy the changed-code gates for the expected URL guard
* fix(dsh): report hooks as partial when a DSH profile cannot load the executor package
* fix(dsh): name only the broken profiles and print hook detail for failing states
* refactor(dsh): fold the profile package check into the installed branch
* fix(orchestration): reach a terminal that still coordinates another Run through its worker Dispatch
A terminal can stay bound to an older Run while it works a Dispatch in another.
send --to <terminal> --run <its Dispatch's Run> was refused with
recipient_run_mismatch, and run-current never mentioned the Dispatch.
* fix(orchestration): say which terminal can safely take an older Run
`worktree set` read --comment through getOptionalStringFlag, which turns
an empty value into undefined, so `--comment ""` and `--comment=` sent no
comment field and the stored comment survived while the command reported
ok:true. Keep an explicit empty value for this flag only; the shared
helper and the RPC schema are unchanged.
Fixes#37464
* fix(orchestration): steer mail notices into a busy native chat's running turn
A native-chat coordinator's mail notice always queued as a card until the whole turn ended, so a
coordinator busy in a long command never saw its workers' reports. Agents that take a message
mid-turn (Claude, Codex, Pi) now get the notice at once; agents that would cancel their turn for
it (ACP) still queue it.
* fix(orchestration): drain mail that arrives while a notice is pending
* fix(orchestration): native chats get each orchestration message whole instead of a check pointer
Each mail message is sent to a native-chat agent as its own chat message,
with the sender, type, subject, body, payload and exact reply command, and
is marked read once the chat accepts it. Heartbeats are marked read, never
sent. Mail an unacknowledged check batch holds stays with that batch.
* fix(orchestration): keep the at-most-once gate's mail-lane assertions, exhaustive sender switch
* Preserve native mail compatibility and drain delivery backlogs
* Drain native mail with a finite ordered pass and scoped operation ownership
* Bound mail formatting and honor accepted queue handoffs
* Run the native mail tests that open SQLite in the Node runtime project
* Preserve live mailbox ownership and recover full reports by id
* Use a typed runtime client in inbox compatibility test
* Preserve historical mail evidence and scope the test clock
* Map historical structured-send evidence to the current test command
* fix(orchestration): settle mail handoffs per message and recover interrupted consumers
* Hold native chat mail until the chat is idle, as terminal mail waits
A mail send admitted into a running turn cancels that turn for agents that
cannot take a message mid-turn (ACP: Grok, OpenCode, OMP, Antigravity): the
second of two reports cancelled the first before the agent saw it, and the
first report cut off the turn carrying the person's answer. Mail now waits
while the chat is working or a prompt waits on the person, for every agent,
and goes out at the idle edge, one message per turn, oldest first.
* test: cover idle orchestration report turns
* fix: preserve independent mail authorization through grouped delivery
* fix: preserve routed mail identity and private inbox state
* test: bound mailbox query work on repeated delivery
* fix(orchestration): consolidate terminal mail imports
* Validate mailbox query rows and type delivery fixtures
* Keep host forwarders typed and inline single-use mail evidence reader
* Declare the mail handoff store method boundary
* Preserve mailbox contracts across typed boundaries
* Retain existing main cleanup row boundaries
* Fix mailbox handoff fixtures and helper mail transfer
* Name the mailbox fixture constructor type
* test: complete mailbox dialog pane identity
* Keep structured mail ordering and ownership current at claim
* Bound mailbox preparation and immutable cohort selection
* Consolidate structured mail contract fixtures
* Consolidate duplicate mailbox imports
* Fix mail handoff type contracts and deterministic test fixtures
* Repair journal forwarding and align mail contract fixtures
* Fix mailbox corpus message type inference
* Correct personal provenance in ACP backlog fixtures
* Correct ACP mail contract measurement and epoch wake fixtures
* Retain full ACP contract diagnostic arguments
* Restore reliability gate coverage and consolidate mail fixtures
* Preserve unknown alias release coverage
* Route native reports through the durable chat queue
* Preserve exact legacy mail holds in queue lineage proof
* Use ordinary queued messages for worker reports
* Use semantic queue and check completion for report delivery
* Record bounded queue recovery work and request cleanup proofs
* Preserve report creation evidence and bounded source wakes
* Preserve report source work and check ownership
* Use ordinary report acceptance and incremental original history
* Retire completed mail opportunities with their current owner
* Retire routed source debt and complete joined mail contracts
* Exercise Run typed peek through the command transport
* Require the queued report submission in creator coverage
* Restore database callback API and align queue contract fixtures
* Fix empty legacy tab selection in restart fixtures
* Keep relation heading assertions scoped to each report
* Native chats receive each orchestration message whole, through the chat's own queue
Each orchestration message to a chat session becomes one ordinary chat message carrying the whole
message, sent with the chat's queue like a person's message: it waits behind running work or a
question and the agent is handed one per turn. A per-message record keeps the send's operation id,
so a restart finds the card instead of sending twice; the message is marked read once the agent is
handed it, and a check that takes it first deletes the waiting card. A message too large for one
chat message keeps today's pointer to check. Terminals are unchanged.
* Test that chats get each message whole, queued like a person's message
* Repeat a report the agent may not have taken only after a later turn or /clear
A send the agent rejected or left unanswered stays unread for check and is handed over again only once
a later turn ran or a /clear replaced its context, so edges alone never restart an agent that fails on
every start. A send whose record a rewind dropped is sent again, and a send that throws is retried on
the session's next journal edge. Tests follow chats getting each message whole.
* Hand a chat orchestration mail only while it is still owed
A queued mail card now runs only while its message is unread in its mailbox and that mailbox still belongs to
the chat: the queue asks at handover and drops a stale card without a turn (abandoned or settled Dispatch,
Run taken over by another chat, mail a check or reset took). Cleanup after check, moves, run-use, abandon,
reset and worker release deletes those cards visibly and never holds the action up; mail still owed goes to
the mailbox's current owner, and Orca's own deletion is never read as the person's.
A send that may have reached the agent is never sent again; check keeps it. A send the agent proved it never
got is sent once more, under a new id, only after a later turn or /clear ordered after that failure. A send
recorded but never admitted is admitted under its own id. Each outstanding send is read by key, never by
scanning the chat's history.
A refusal no longer loses its retry when an edge arrives mid-send, and a coordinator refused for queue room
gets its mail when the queue frees room. A chat worker's follow-up now takes its short Task first and then
each moved message whole, with no check needed. The guide says a working worker gets mail when its turn ends.
* Let the chat's host answer what became of each mail send, and let the person's cards pass mail Orca cannot decide on
The chat's host now answers for each send by its id: the card first, then the send itself, then a gone card's handoff found by key, and only then the admission receipt, which alone can prove nothing was admitted. A receipt whose journal detail is gone is in doubt however old its id, so a renewed id can no longer send the same message twice. A rejected send is repeated once only after a different turn was actually handed over and accepted, or a /clear was made, after the rejection; the queue's admission cursor no longer stands in for that. No answer walks the conversation's history.
The mailbox reserves each send and stamps the message delivered in one write before the host call, so a crash after admission never leaves it selectable again. A refusal before admission releases that exact reservation; every retirement and release is checked against the current attempt, and a record an older build saved without a stamp is repaired as it retires. A person's Delete consumes an oversized pointer's mail too.
Who holds a mailbox is read from durable facts: a Run moved to a terminal, a released worker, another host or an ended chat makes a waiting card stale, so it is withdrawn without a turn and its mail released for the real owner. Only a fact that cannot be read holds a card; the person's own cards behind it go on, later mail stays behind it, and selection and the handover check use the same rule. When the owner can be read again the queue is woken. A Task or a person's edited card never opens the mail database. An explicit Send of such a card now says what happened.
Parked mail is indexed by chat, wakes only that chat's mail, ignores streamed tokens, and drops the chat's journal watch with its last mailbox. Canonical session identity is reused per session store revision instead of rebuilt from every record on each check. Main's account-switch worker test now reads "unread and still owed".
* Let the queue alone decide which card goes next, and wake a terminal given back its mail
The queue now owns one rule for what can be handed over next, installed once on each chat's queue and read by the drain, the final handover check, queue publication and scheduling alike. Mail whose owner cannot be read keeps its place; the first of the person's own cards behind it goes instead. Held cards stay held, a returned, paused or edited card behind it still stops the queue, and later mail, from any mailbox, stays behind it. The rule walks only the queue's live cards, never its history. When nothing can be handed over nothing is published as next, so the chat reads as idle and /clear works; when the owner becomes readable again the queue is published and looked at again. Choosing and publishing the next card only reads custody; settling a stale card stays with the handover.
Mail a chat gives back after its Run or worker moved goes through the runtime's own delivery, so a terminal owner is pointed at it. A chat's journal watch now lasts as long as it has mail parked, through its own redrives, so a publication that changes nothing the mail waits on starts no pass. Session identity is cached until a record joins, leaves or is cleared, not rebuilt after every admission. An explicit Send of mail whose owner cannot be read says Orca couldn't read the chat's saved state rather than that it restarted.
* Find the person's next card past undecidable mail by walking only as far as it must, and ask mail authority only once nothing else stops a send
* Say plainly when Orca can't confirm queued mail is still this chat's, and that the person can try again
* Let parked mail's own watch be the only journal subscription for mail, and stop saving a send fence nothing reads
* Count the queue's order reads with plain index getters instead of a reflected proxy
* Read saved mail sends column by column, and build test fixtures as the types they stand for
* Keep main's words for every other refused queued Send; only undecidable mail says its message wasn't sent
* Let replay read the queue's handoff links, keep the host's last mail answer where the type can see it, and drop the removed test from the send gate
* Keep the queue's possible next cards in order as each one changes, reuse the last pick until the queue moves, and look up a send by its id
* Ask whether one chat's tab closed instead of listing every open tab to find it
* Settle a mailbox's earlier mail only when something it waits on moved, republish a chat once per pass, clean up only the mail a check, abandon or move touched, and act on a chat's status only when it changes
* Date the scaling test's extra tabs by the coordinator's recorded lease instead of the wall clock
* Keep nothing in memory for a mailbox a cleanup finds with no owner and no send left, unless a pass on it is still running
* Ask about a report whose send threw before handing over newer mail, under the id it was reserved with
* Allow profile repair to replace damaged automation history metadata
* Keep verified automation history when repairing its placeholder
* Test structural profile open and repair output for kept automation history
Schema verification no longer reads automation history metadata, so the
read-concurrency tests now assert that open succeeds without reading it and
that ordinary reads still keep snapshots consistent and refuse corrupt
metadata. Add output coverage for the recovery-required message, the
startup failure text (English and a translation) and the bundled CLI
recovery route printing kept and backup-restored sections.
- Box (ui.catalog 4, since 1.4.248): direction, gap/padding/paddingX/
paddingY/margin on the gap scale, align, justify, wrap, grow, shrink,
width/height/min/max (px up to 4096 or whole percents), columns,
scroll, border (true or a tone), radius, background (theme surfaces or
tone tints). Strict props: hex colours, CSS lengths and unknown props
are dropped with a warning like other components.
- Renderer maps props to theme tokens through data attributes; sizes
reach inline style only as validated px or percents.
- Typings, docs, skill references, gallery Layout tab; orca/testing
finds Boxes and summarizes danger or warning Boxes.
The terminal error banner and a paired host's held pane showed
terminal_held_wsl_distro_*:<distro> as is; the banner now swaps either
the code (older hosts) or the English sentence (newer hosts) for the
localized copy, and drops the issue link for it. A held start that
arrives as the sentence now gets the Start card too. The CLI names the
distro for an older server's raw hold code and for an unavailable WSL
folder. The banner's footer reports the shell whose spawn failed
(wsl.exe, say) instead of the client's default shell.
* fix(plugins): merge disk writes into a custom editor's unsaved edits
A write to the file on disk while a custom editor tab had unsaved edits
never reached the editor: the buffer kept the edits, Orca showed its
Reload/Overwrite banner, and the session's merge never ran. Now a frame
whose document session has merge announces it (editor.merges), and Orca
sends it the new disk text with the text the edits started from
(editor.document with ancestor). The session merges, posts the result,
and the tab stays unsaved with it; the banner is skipped. Without merge
the banner decides as before.
* test(editor): an explicit save under the changed-on-disk banner keeps the edits
* fix(plugins): make the outside merge exact, and narrow it to where it is
- The host settles a merge only on the session's edit made against the
merge's own document version, and always commits that result to the
buffer (even when it equals the disk text); silence past the 1 s flush
deadline, a remount or a throwing merge leave the banner and the
suspended autosave in place.
- Orca stamps exactly the disk snapshot the acknowledged merge used and
records it as the next ancestor; a write that landed meanwhile puts the
conflict back for its own merge.
- The ancestor is the tab's disk text recorded while clean and advanced on
acknowledged merges, and must match the tab's disk baseline.
- Only a local file in one merging editor view, with no other tab on its
buffer, takes this path; anything else gets the banner.
- Frame events keep reaching their handlers after the merge capability.
* fix(plugins): move nothing on a failed disk merge; advance the saved text on success
A merge that throws now leaves the session's document, baseline and
version untouched, so the user's next edit goes out against the old
version: Orca refuses it and keeps the banner instead of taking it as the
merge's acknowledgement. After an acknowledged merge the tab's saved text
moves to the disk text it used, so typing back to the old ancestor no
longer looks clean.
* chore(plugins): regenerate the testing bundle on main
* plugins: editor.save.before hook (format on save, or refuse the save)
Explicit saves of text files from an editor tab run plugins' editor.save.before
in main before the write (local, SSH, WSL and folder workspaces all save through
that one renderer path). A plugin can return changed text or deny with a reason,
shown in the save error. The buffer takes the hook's text only if it is unchanged
since the hook started; edits made meanwhile stay dirty. Autosave, restart saves
and bytes documents are not hooked, and with no live plugin listing the hook the
save path adds no await.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(plugins): editor.save.before text reaches the visible Monaco model
The hook writes its text into the tab's draft, which reaches the model through
the same content-sync bridge as Reload from disk. A model-level test covers the
formatted text showing, the next keystroke editing it, and edits typed during the
hook staying in the model.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: editor.save.before review fixes: flush held typing, update the surviving view, keep the denial
- After the hook answers, pending view text (rich Markdown's serialize timer) is
flushed before deciding whether the buffer still holds the hook's input.
- The hook's text goes to whichever view of the buffer record is still open, so
closing the saving view keeps a sibling view in step with disk.
- The save-request bridge passes Errors through whole, so the toast shows the
plugin and its reason instead of a generic failure.
Co-Authored-By: Claude <noreply@anthropic.com>
* chore(plugins): regenerate after rebasing the save hook on main
---------
Co-authored-by: Claude <noreply@anthropic.com>
orca plugin create --template editor wrote an inline-script HTML editor
whose extension came from the folder name squashed to 12 letters. It now
writes the recipe: editor/main.ts (the view), editor/sync.ts (the
document session with a stand-in text merge), editor/sync.test.ts (a
mockEditorHost test of an outside write merged during a save), a
tsconfig on the generated typings, frame isolated, engines.orca
>=1.4.248, and extension .<id>. It passes plugin check and plugin test
as generated.
* plugins: commands[].replaces lets a worker command take over a built-in action
A worker command with replaces: <action> (the declarative action list,
engines >=1.4.248, needs main) runs in place of that built-in from its
shortcut, plugin aliases and the sidebar menus; a failed or silent (2 s)
worker falls back to Orca's own. The install screen names each replacement,
the plugin page has a per-action switch (settings.pluginReplacementsOff), and
when two plugins replace one action the one installed first wins and the
other's log says so. Update review counts replaces as new access.
* fix(plugins): narrow replaced action ids before looking up their titles
* plugins: harden command replaces after review
- Consent includes the replaced actions, so adding replaces to a dev folder
needs a new approval; CLI approval and update review name each takeover.
- Shortcuts main intercepts (Tasks, Workspace Board, history), search with a
selection and floating maximize now go through the replacement too.
- A worker that only starts after the 2 s fallback no longer runs the
command as well: main refuses to start it past the deadline.
- A workspace-only command does not replace an action without a workspace.
- An update keeps the plugin's first install time, so it keeps its takeover.
- Drop the commands.run promise until Orca offers it.
* plugins: commands.run always runs the built-in, never a replacement
A5b's commands.run dispatches with the 'plugin-host' source; the app
dispatcher now builds handlers that run Orca's own action for it, so a
plugin that replaces an action and calls commands.run cannot loop. Docs and
schema describe wrapping the built-in with commands.run; regenerated.