Commit Graph
222 Commits
Author SHA1 Message Date
Kelvin Amoaba 255716e31d feat(cli): add orca workspace cleanup preview, run and report (#41831)
* feat(cli): add orca workspace cleanup preview, run and report

* fix(cli): sanitize cleanup output and label unknown host values

* fix(cli): sanitize run triggers in cleanup report

* refactor(cli): share keep-reason wording in cleanup output

* fix(cli): label automation-run and orchestration-worker cleanup reasons
2026-11-13 05:12:49 +00:00
Neil 89bac6f400 fix(plugins): host API 1.7-1.9 release floors are 1.4.259 (#41789) 2026-11-12 20:18:10 -08:00
Kelvin Amoaba c5657bd5a7 feat(computer): type into a named text field without focusing it on Linux and macOS (#41421)
* feat(computer): type into a named text field without focusing it on Linux and macOS

* fix(computer): report unconfirmed Linux text readback and cover element typing

* test(computer): send an element with benchmark text only for targeted typing

* test(computer): pick gedit's editor, not its hidden overview map, in Linux e2e

* docs(computer): confirm focus before the unindexed type-text fallback

* fix(computer): report unreadable element text readback as readback_unsupported
2026-11-13 00:28:06 +00:00
Kelvin Amoaba c794f75e4e fix(computer-use): use UI Automation for Windows scroll, expand and slider actions (#41429)
* fix(computer-use): scroll, expand and set sliders on Windows without raising the window

* fix(computer-use): wait for Windows scroll and slider writes to settle before verifying

* fix(computer-use): reject NaN for Windows slider set-value

* test(computer-use): wait on the Windows fixture state with vi.waitFor and a schema

* test(computer-use): check activation per action against a holder window in the Windows fixture

* test(computer-use): log fixture window events for activation failures

* fix(computer-use): report foreground when a Windows app raises itself for a UI Automation action

WPF activates its own window for Scroll, ExpandCollapse, RangeValue and SelectionItem calls from any UIA client, so the runtime now compares the foreground window before and after a pattern action instead of assuming background. The Windows e2e checks delivery against the fixture's own activation count, with a holder window in another process.

* test(computer-use): skip an unstarted holder when closing the Windows fixture

* fix(computer-use): bound Windows pattern scroll paging and tighten slider read-back

* fix(computer-use): cap Windows slider read-back tolerance and run the UIA e2e only on CI
2026-11-12 23:17:10 +00:00
Kelvin Amoaba 792d4e8028 fix(computer): verify macOS type-text and paste-text by reading the field back (#41402)
* fix(computer): verify macOS type-text and paste-text sent as keys by reading the field back

When text can't be written through AXValue (Chromium/Electron fields, fields
that refuse the write), type-text and paste-text send keys or Cmd+V and always
reported unverified. Now the helper predicts the focused field's value from its
value and selection before sending, then reads it back until it settles:
verified on a match, unverified (text_mismatch) otherwise. Secure fields and
fields without a readable value and selection stay unverified as before, and
the result never repeats the typed text or the field's contents.

* fix(computer): keep the caret put after a refused macOS text write and skip unprovable readbacks

A refused AX value write no longer moves the caret before falling back to keys, so the keys and the prediction both use the user's selection. Text with control characters, a value the field already holds, and a field still filling at the 2 s cap stay unverified rather than verified or text_mismatch. The quiet window starts after the first read answers.

* fix(computer): bound macOS text readback size and say a mismatch can mean keys went elsewhere

* fix(computer): treat a macOS text readback past the cap as undetermined
2026-11-12 22:45:11 +00:00
Kelvin Amoaba 8bb57668ed fix(computer): refuse quit, log out and lock shortcuts unless explicitly allowed (#41412)
* fix(computer): refuse quit, log out and lock shortcuts unless explicitly allowed

* fix(computer): close Linux keysym bypasses in the system shortcut guard

* fix(computer): refuse Linux keycode, L1/L2 and VT-switch keysym bypasses

* fix(computer): catch control characters in Linux keycode tokens and point recovery at the stated effect
2026-11-12 22:25:10 +00:00
Kelvin Amoaba 8ed0d047db feat(computer): show where snapshots were cut and read one element's subtree (#41482)
* feat(computer): show where snapshots were cut and read one element's subtree

* fix(computer): validate subtree targets against the fresh walk and keep scope for focused input

* fix(computer): return whole-window action results after subtree reads

* fix(computer): count kept records toward the macOS limit and index subtree reads against the latest cache

* fix(computer): index Linux/Windows subtree reads against the snapshot they started from
2026-11-12 22:22:18 +00:00
Kelvin Amoaba cd933ae08e feat(computer-use): add orca computer wait for text, enabled controls and window titles (#41433)
* feat(computer-use): add orca computer wait for text, enabled controls and window titles

* fix(computer-use): bound wait reads by the deadline and wait out missing Linux/Windows windows

* fix(computer-use): read disabled traits after role text with parentheses and bound the capability probe
2026-11-12 21:35:26 +00:00
Kelvin Amoaba 3cfdd60d3b fix(computer): check macOS click targets are enabled, in view and uncovered before clicking (#41519)
* fix(computer): check macOS click targets are enabled, in view and on top before sending input

* fix(computer): scope macOS click cover checks to the target window

* fix(computer): scroll before trusting container hits and stop hit walks at the shared container

* refactor(computer): share the one-scroll rule in the macOS click check
2026-11-12 21:23:42 +00:00
Neil 757b1e6167 feat(plugins): project.setHidden — hide and show projects from plugins (#41582)
- project.setHidden({ projectId, hostId?, hidden }) -> { hostId, hidden }: workspace:write,
  worker only, host API 1.9 (unreleased, floor 1.4.258). Calls repo.setHidden by id: only,
  always host-qualified; a twin without hostId is refused naming hostId; an answer without
  hidden (an older host) is a fixed action_failed.
- project.list rows carry hidden.
- repo_not_found maps to 'no project has this id'.
- Audit summary by ids; workspace:write consent copy names hiding projects.
- Mock testing host echoes project.setHidden; regenerated plugin artifacts.
2026-11-12 07:45:08 -08:00
Neil d277381bb3 Hide projects from the sidebar without stopping them (#41529)
* Hide projects from the sidebar without stopping them

Adds Repo.hiddenAt, a per-host, view-only flag. A hidden project's
workspaces, empty header and project-filter entry leave the desktop
sidebar, the paired phone's list, the new-workspace picker and the
palette's project filter. Its terminals, agents and automations keep
running, and repo.list / worktree.ps still list it.

- Hide Project in the project menu (toast with Undo), a collapsed
  "N hidden projects" list under the workspace list with Show buttons,
  and a Hide from sidebar switch in Settings > Projects.
- repo.setHidden RPC ({repo, repoHostId?, hidden} -> {repo, hostId,
  hidden}) and `orca repo hide|unhide [--host]`; `repo list` marks
  hidden rows.
- Opening a hidden project's workspace (notification, CLI, deep link)
  focuses it without unhiding it, lifting sidebar filters, or leaving a
  pending sidebar reveal.
- repo.update echo check: a host that drops hiddenAt reports failure
  instead of reading as hidden.

* Address hidden-projects review: multi-host hide, picker scope, mute, stale filters, shared predicate, restore list styling

* Hidden projects re-review: keep saved filters, Agents filter, composer seed, per-toast Undo, shared default host

* Hidden projects: address review threads (pre-feed, palette search, notices, dialog default, seed remap, row keys, a11y)

* Hidden projects: no implicit dialog default when every project is hidden
2026-11-12 07:02:57 -08:00
Neil 1bd6d7a659 fix(plugins): host API 1.8 and 1.9 floors match the next release (1.4.258) (#41565) 2026-11-12 06:36:48 -08:00
Neil 75ce5be014 feat(plugins): host API 1.9 — agent session history, resume past sessions, task titles (#41542)
* feat(plugins): host API 1.9: agent.listSessions (history:read), resume past sessions, agents.list task titles

* test(plugins): host API 1.9 coverage; regenerate plugin artifacts

* fix(plugins): host API 1.9 review fixes

- agent.resume starts a past session where the desktop's Resume would: the same preparation
  request and answer handling (now shared), and the transcript in the home it pins
- AI Vault list cache keeps four scopes, so plugin reads never evict the panel's list
- list fingerprints ignore scan id and issues, so an unchanged history revalidates
- workspace mapping resolves symlinked workspaces and prefers a project over a folder
- agents.list task only for open dispatches, read at most once a second
- running matches OpenCode versions; history reads reset when the vault list is invalidated
- truncation, consent copy and limitations documented

* fix(plugins): forced history refresh supersedes cached scopes; resume legacy Codex sessions from their recorded transcript

* fix(plugins): address host API 1.9 review threads

- a scan that began before a forced history refresh no longer caches its older result
- list fingerprints count which issues there are (not their wording)
- symlinked workspaces rank by their resolved folder
- a session-only status row is no live pane: resume prepares the session
- a failed task-title read leaves agents.list rows intact
- the symlink test uses a junction on Windows

* test(ai-vault): order the stale scan before the forced refresh
2026-11-12 06:19:16 -08:00
Neil 255b5c22c1 feat(plugins): host API 1.8 — create workspaces, resume agents, automations (#41528)
* feat(plugins): proposed tier for host methods not yet frozen

A method spec may set `proposed: true`: only development plugins may call
it (others get not_permitted), and the minor, frame/worker method lists,
typings and skill references omit it. The reference renders such methods
in a separate Proposed section; dev workers' host.has answers for them.

* feat(plugins): param capabilities, host confirmations, automation provenance

- PluginHostMethodSpec.paramCapabilities: a passed param can require a
  second capability; executePluginHostCall and the mock host refuse it with
  capability_denied before any audit or effect, and the reference shows it.
- confirmPluginAction generalizes the external-open prompt into a host-owned
  confirmation, exposed as PluginHostServices.confirm (desktop only; absent
  in headless serve). It re-checks the plugin's approval after the answer.
- Automations record createdBy { kind: 'plugin', pluginKey, name }, set by
  the runtime from the in-process plugin caller (RpcContext.plugin), never
  from params; the Automations detail shows "Created by <plugin>".

* feat(plugins): workspace:create, automation:read and automation:write capabilities

New closed-enum kinds (older Orcas refuse such manifests with the engines
message), worker-only, with consent copy that names what each allows;
release floor PLUGIN_HOST_API_1_8_SINCE (1.4.259) joins
PLUGIN_SCHEMA_NEWEST_SINCE. agent:launch copy now says it also resumes.

* feat(plugins): host API 1.8 methods: workspace.create, agent.resume, automation.*

- workspace.create (workspace:create; agent also needs agent:launch): a
  worktree in a Git project, as orca worktree create does; with agent, the
  CLI's agent.launch create-worktree path, so the agent starts after setup.
  Setup is skipped or follows the project's settings; never run, an
  approved hash or a startup command.
- agent.resume (agent:launch): terminal.ensureAgentSession by session id;
  started is false when a terminal already ran it. agents.list rows and
  agent.status.changed carry sessionId.
- automation.list/create/update/delete (automation:read/write): create
  forwards only name, prompt, agent, target, schedule, time zone and
  enabled; update/delete of automations another plugin or the person made
  ask the person first and report cancelled or consent-unavailable.

* test(plugins): host API 1.8 coverage; regenerate plugin artifacts

Covers param capabilities (host and mock host), workspace.create payloads
and refusals, agent.resume keys and adoption, sessionId on agents.list,
automation projection, forbidden create fields, confirmation outcomes,
runtime-set provenance and capability access growth. Regenerates the
reference, schemas, typings, declarative runtime and skill references.

* fix(plugins): host API 1.8 review fixes

- Confirmations spend the frame dialog budget, allow one question per
  plugin at a time and pause after a refusal (rate_limited); a worker's
  question shows in the focused window, else the first visible one.
- Changing what an automation with extra agent settings runs (prompt,
  schedule, resuming) asks first even for its creator, showing the prompt.
- Removing, disabling or blocking a plugin pauses its automations and ends
  its ownership (createdBy.endedAt), so neither re-enabling nor a reinstall
  under the key resumes or edits them silently; the remove dialog says so.
- workspace.create and agent.resume record the terminals they return as
  the plugin's own; a launch that fails after its worktree exists names it.
- Setup-decision refusals are told by the runtime's error class (kept as
  the in-process RPC error's cause); generated names see every worktree
  of the project; resume transcripts match the workspace and host.
- Created by shows the plugin id beside its name.

* fix(plugins): end automation ownership only on uninstall, disable or block

- The ownership sweep no longer reads discovery: only an uninstall
  (announced by the removal path), the disabled list, the kill list or
  the plugin-system switch end it, and only once the service is ready,
  so an unreadable plugins folder pauses nothing. An install under the
  same key after a removal keeps what it creates.
- A new time zone on an automation with extra agent settings asks first.
- A failed launch names only a new worktree made from the requested name.
- Settings' plugins-off state and the CLI's plugin system off and plugin
  disable say that plugin-created automations are paused and stay so.

* fix(plugins): address host API 1.8 review threads

- Confirmations close when the worker's call ends, freeing the plugin's
  turn; they name the automation (short id, project, workspace,
  schedule), show any new prompt, and are refused as `changed` when the
  automation was edited while the person was asked.
- automation.create takes hostId (through the project's setup on that
  host) and a creationKey scoped to the plugin; the runtime rechecks the
  plugin's approval right before the write.
- agent.resume records only terminals it started; both it and
  workspace.create recheck approval before recording.
- automation.list never cuts a schedule (null when too long) or fails on
  an id too long to show.
- The Automations detail says when a creator plugin was removed or
  disabled.
2026-11-12 05:28:13 -08:00
Neil e24af39c47 feat(plugins): host API 1.7 — workspace ids, project/terminal list, terminal focus/close (#41508)
* feat(plugins): host API 1.7 — workspace ids, project/terminal list, terminal focus/close

Plugins that track workspaces and terminals across Orca had to read the private runtime
token or shell out to the CLI. Host API 1.7 gives them the same through consented methods:

- workspace.readContext (and workspace.changed) carry `workspaceId`, the id workspace.list
  gives; workspace.created/removed and agent.status.changed add `workspaceListId` beside
  their existing raw `workspaceId`, which keeps its meaning.
- workspace.list rows name their `projectId`; opt-in `includeStatus` joins each row's agent
  state, unread flag, live terminal count and last activity from worktree.ps.
- project.list (workspace:read), terminal.list (workspace:read), terminal.focus
  (workspace:write, desktop only, steers only this window) and terminal.close
  (terminal:send, reports whether the process is known to have stopped).
- Runtime refusals (unknown or ambiguous workspace, stale or exited terminal) reach plugins
  as fixed messages instead of runtime wording.
- Consent copy for workspace:read, workspace:write and terminal:send says what they now
  allow; terminal.focus and terminal.close are audited by terminal id.
- PLUGIN_SCHEMA_NEWEST_SINCE covers the editor typography and theme video floors it missed,
  and the provisional 1.7 floor, so development builds accept plugins requiring them.

* fix(plugins): narrow terminal.close and harden host API 1.7 from review

- terminal.close closes only terminals of the focused workspace (the check terminal.sendText
  uses) or ones this plugin opened with terminal.create or agent.launch, recorded in a bounded
  per-plugin registry that is forgotten when its worker stops or it is disabled or removed.
  terminal.focus stays any-terminal; summaries and terminal:send copy say so.
- Lifecycle events carry the worktree's identity and host: from the new row on create, and read
  host-qualified before the purge on every removal path. agent.status.changed looks up the
  identity on the reporting host only. The global removed-identity map is gone.
- includeStatus shares one in-flight worktree.ps and a 1 s cache across plugins, and reports
  statusTruncated when that listing stopped short.
- Stored remote contexts get their identity host-qualified; panels and editors never get a raw,
  path-bearing workspace id from readContext or workspace.changed.
- Runtime refusals map to fixed messages (tab pinned, no window, tab gone, host disconnected);
  any other runtime error or malformed answer is a fixed action_failed with the detail logged.
- hostId is `local`, `ssh:` or `runtime:` in both workspace.list and project.list; rows past the
  id or path bounds are left out with truncated set instead of failing the list.
- The mock testing host answers terminal.focus and terminal.close by default.

* fix(plugins): keep shipped host API values and codes; honest terminal results

- workspace.list hostId keeps the values 1.3 shipped (recorded host, else null; folder rows
  their executionHostId); project.list always names the host. Both summaries say which.
- Methods that shipped before 1.7 report every runtime refusal as action_failed, as before;
  the unavailable/conflict mapping applies to 1.7 methods only.
- includeStatus shares a pending worktree.ps however long it runs; the 1 s TTL starts when it
  lands.
- The opened-terminal registry records only for a call still approved and not cancelled, and is
  pruned on disable or removal only, so event-driven workers keep close rights across restarts.
- terminal.close answers { closed: true }: a local close cannot tell whether the process exited.
  terminal.focus answers focused: false when the request was superseded or not navigated.
- workspace.list and project.list cut labels to 512 instead of failing the list.
- Removal events from the runtime job and the IPC retry are tested to carry the identity read
  before the purge; folder deletion carries its host.

* fix(plugins): name the status-listing owner type
2026-11-12 04:06:19 -08:00
Jinwoo Hong 2e7e992027 feat(orchestration): let coordinators approve worker permission prompts (opt-in) (#41306)
* feat(orchestration): let coordinators approve worker permission prompts when the user turns it on

One setting on the orchestration page, off by default. When on, the
escalation offers orchestration approve and deny, both with a reason, and
the user still sees Allow/Deny: the first answer wins. A prompt the
worker's agent lets only a person approve is refused and stays with the
user. The machine running the worker enforces its own setting.

* fix(native-chat): a worker approval's receipt shows the command, not its tool input as JSON

* test(orchestration): list every worker-side case in the coordinator approval table

* chore(i18n): ship the coordinator approval setting's search keywords in the runtime catalog

* fix(orchestration): a reasonless allow keeps the person's refusal, and terminal checks no hook may approve are person-only

* fix(orchestration): address review on coordinator approvals

- A person-only chat prompt answered meanwhile reports as closed.
- A terminal allow reads Claude's warning from the screen it checks, so a
  late-painted person-only warning still refuses before the hook is used.
- The receipt keeps a chat worker's whole command.
- orchestration approve prints the reason it sent.

* fix(native-chat): read the receipt's command through a parsed shape, not Reflect

* docs(skills): drop worker permission prompt guidance; the escalation carries it
2026-11-12 00:30:27 -05:00
Jinjing be8f5ace6c docs(orchestration): tell workers to report effort from --effort, not reasoning_effort (#41356)
The numeric reasoning_effort a model sees is not on a 0-100 scale
(claude-opus-5-5: low=5, medium=10, high=15, xhigh=40). Workers launched
with --effort high read 15 as low and misreported their effort.
2026-11-11 19:52:08 -08:00
Brennan Benson 3f84308ec1 Revert orca chat list/read/send/wait (#40836) and its perf repair (#41129) (#41241)
* Revert "Make chat wait check the chat's work state instead of reading its history every second (#41129)"

This reverts commit 9a10464bec.

* Revert "feat(cli): read, message and wait on agent chats with orca chat list/read/send/wait (#40836)"

This reverts commit c2e6ebbf0b.
2026-11-11 19:36:32 -08:00
Kelvin Amoaba ada69cba8c fix(browser): stop agent clicks from opening the system file picker over your work (#41299)
* fix(browser): stop agent clicks from opening the system file picker

An agent click on a file input opened the macOS Open panel, which brought
Orca's window forward over the app the user was in. Page actions now catch
the picker the way upload does and tell the agent to use upload.

* fix(browser): enable Page, cancel the picker, and clean up outside host scope

* fix(browser): limit picker blocking to input delivery and bound its setup

* perf(browser): skip picker blocking for actions without user activation

* fix(browser): bound picker interception cleanup on a hung page

* fix(browser): bound the picker interception setup as a whole
2026-11-12 00:18:39 +00:00
Kelvin Amoaba cab41b4075 fix(browser): tell agents when a page waits on a passkey, and let them cancel it (#41048) 2026-11-11 23:27:38 +00:00
Neil 1f1158f7cb docs(orchestration): replace hardcoded worker-start agent ids with <agent> placeholder (#41279)
The orchestration skill guide and reference examples hardcoded --agent codex, leading coordinators on hosts without Codex installed to fail at agent_readiness. Replace hardcoded worker-start agent ids with <agent>, document how to pick an agent id across shared vs remote/WSL/--on execution hosts, and regenerate bundled skill guides.

Fixes #30495
2026-11-11 15:03:56 -08:00
Jinwoo Hong c6467bbc53 fix(orchestration): tell the coordinator when a worker is lost (#40983)
* fix(orchestration): tell the coordinator when a worker is lost

A worker that could no longer run its task sent no mail: a failed start,
a person closing its pane, tab or chat, or a terminal gone after a restart.
Each now sends one "Worker lost without reporting" alert through the
turn-stop report, with its cause, last output and any leftover workspace.
An unexpected exit and a lost Codex app-server use the same path. An exit
or loss says the Dispatch is closed as failed and gives the retry command.
Failure text in the alert is redacted like terminal output.

The coordinator's own worker-stop stays silent, locally and on a paired
server. A finished turn is not reported when that turn's worker_done was
rejected; later turns still are. worker-read and worker-show say
"never started" for a start that never got a terminal.

* fix(orchestration): a lost worker's restart command names its Task id and suits its Task's state

- The command named the Task's label, not its id.
- Restart recovery puts the Task back to ready, which --retry-of refuses:
  the command is a plain worker-start then.
- worker-show does not call a paired server's failed worker "never
  started": its record carries no terminal details.

* test(orchestration): import the turn-stop report after main's test cleanup
2026-11-11 14:56:05 -05:00
Jinwoo Hong 818055fcbb feat(orchestration): answer workers' permission prompts from the coordinator (#40756)
* feat(orchestration): deny a worker's permission prompt, and say when mail is held

A chat worker that stops at a permission prompt now escalates with the prompt
itself as structured data (approval id, state, worker, summary, allowed
actions). The coordinator can deny it with a reason through
`orchestration deny`; the worker carries on and gets the reason as mail.
Only a person can allow a prompt: the answer method decides "person" from
the transport, never from params. The stop report keys one escalation per
approval and sends one closing line when it is answered, and no longer tells
the coordinator that `orchestration send` answers a prompt.

`orchestration send` now warns when the delivery gate would hold the mail
right now (an open prompt, a blocked status, typed text), and says delivery
state is unknown for a worker on a paired server.

* fix(orchestration): only the desktop app counts as a person for worker approvals

A paired device can carry a remote CLI, so it is treated as an agent: it can deny with a reason but never allow.

* fix(orchestration): approval answers and held receipts follow the real gates

- A same-option answer counts as Orca's only when Orca recorded it; a retry returns the same
  receipt with no second reason mail.
- An unreadable chat is not a closed prompt: the answer refuses, and the closer keeps watching.
- A closing line tells a reason only when it went to the worker as mail.
- The terminal held receipt prints the delivery gate's own refusal; the chat one prints what the
  pointer's admission and queue gate would do (not attached, refused, or behind an open prompt).

* fix(orchestration): read the held receipt only after the mail is stored

An await before the insert let a worker settle meanwhile, so the mail could land on a settled
Dispatch after its follow-up scan. The closer also removes only the approval map it read.

* fix(orchestration): tell the coordinator not to block on a worker's permission prompt

The approval escalation now says the worker is waiting for permission, tells a chat
coordinator the user has been shown Allow/Deny (a terminal coordinator: a person must
answer it in Orca or the worker), asks it to carry on with other work and not message
the worker until the answer arrives, and offers deny only as the way out when the
prompt is holding up the task. The guide and CLI docs say the same.

* fix(orchestration): a paired coordinator without an Orca session id mails a deny reason from its Run

* feat(orchestration): answer a Claude terminal worker's permission prompt

A worker pane's PermissionRequest hook now waits for Orca's answer, so the coordinator can deny
it with a reason (the worker continues) and a person can allow it. One record per waiting hook,
keyed by Claude's prompt and tool call; it is answerable only while the hook waits and the dialog
is on screen, and anything else gets `{}` as before.

* test: annotate the fake screen instead of casting

* test: wait on the hang-up instead of sleeping

* fix(orchestration): claim a terminal answer only from what Claude shows

An answer is written only while a caught-up screen still shows the dialog
in the same process run, and claimed only once Claude shows it applied: the
hook's deny line for a deny, no other close for an allow. A Yes, a No or the
2:00 auto-block that wins the race is refused and named from the screen.

A hook that hangs up is not an answer: with the dialog still up the
coordinator is told a person must answer it in the worker's terminal.

A PermissionRequest entry the user made async stays async: it prints {}
first and never waits for a decision.

* fix(orchestration): name a terminal prompt's close from its tool_result

The screen could show an older prompt's close, so who answered is now read
from the tool_result Claude's transcript records for that tool call: Orca's
own deny text credits Orca, the user's No and the 2:00 safety-check block
name themselves, and a run names an allow. Hook events cannot say this: a
deny or a No fires no PostToolUse. The screen only says whether the dialog
is still up before a write, and a PostToolUse seen mid-answer is kept.

* fix(orchestration): read a prompt's tool_result without blocking main

The transcript read is async, reads only its tail, and skips any path that
is not a regular file, so a FIFO or device cannot stall the main process.
A closed prompt still awaiting its result gets one last read when the lead's
turn stops, so a result written late still names the close.

* feat(native-chat): answer workers' approvals from the coordinator chat

A worker's open permission prompt appears as a card at the end of its coordinator's chat, drawn
from the escalation payload as soon as it is stored. The person allows or denies it there; the
card's buttons answer the worker's own prompt over the desktop app's IPC, so only a person can
allow. Once answered, the card turns into a receipt saying who answered.

* fix(orchestration): read a terminal prompt's countdown when it is first escalated

* refactor(orchestration): give a terminal prompt's hold state its own module

* fix(native-chat): let a worker's approval card answer, and drop it once it lapses

The window's runtime calls never carried the orchestration contract
version, so the card's Allow and Deny were refused as an obsolete client.
The renderer ships with its main process, so desktop IPC states the current
contract. An open card whose agent's own countdown has passed, with no
closing message (the app restarted while it was open), is no longer shown.

* test: say why the desktop fence test's runtime stub is enough

* fix(orchestration): a chat worker's approval asks to allow its tool, like a terminal worker's

* fix(native-chat): pause the approval countdown while the window is hidden

* chore(i18n): protect the approval card's worker line copy

* fix(orchestration): close a terminal prompt's card as soon as Orca can't answer it

When the dialog leaves without an answer through Orca, the closing line is
published at once, so the coordinator's card becomes a receipt; a tool
result that arrives later adds a second line naming how it closed, without
waking the coordinator. On startup, open terminal prompts left by an earlier
run are closed the same way, since their holds lived in memory. A Claude
terminal card's reason is the warning Claude prints under the command.

* fix(orchestration): keep the dialog-warning patterns ASCII for the orcad bundle

* fix(native-chat): say when a deny reason reached the worker as a separate message

A coordinator's deny reason for a chat worker whose prompt takes no message is sent
as mail. The receipt showed it the same as a reason that went with the denial, so it
now labels it 'Reason, sent as a message'.

* chore(native-chat): follow main's moved window-activity and agent-session modules

* fix(orchestration): only Orca's own reports draw approval cards, and every card closes

- Cards and the startup sweep read approvals only from rows whose id is the stop report's own
  stable id for that approval, through one shared parser; a worker's send cannot draw a card.
- A chat worker's card closes as soon as its own chat answers it (a journal watch replaces the
  turn-edge check), when an answer finds the prompt already gone, and after a restart.
- A terminal coordinator is told nobody was shown the prompt and to tell the user; the
  terminal-only close asks the same and goes out as an escalation.
- A chat coordinator's line names only the answers its card offers; a prompt with none is a
  plain prompt with no card.
- A person's Deny on a chat worker mails no extra reason.
- A record a quit or budget end closed stays closed.
- One closed-approval builder; `waitingOn` becomes `awaitsReply`.

* fix(orchestration): a failing read cannot hang an answer, fail a stored send, or fail the database open

* refactor(orchestration): add the held-send line in send-delivery-hold, keeping send-methods under the size cap

* test(orchestration): read the worker's mail with a schema, not a cast

* fix(orchestration): an open approval stays visible and closes even behind many closed ones or a missing database
2026-11-11 04:36:35 -05:00
Neil 45b433671e fix(recipes): show credentials recipe scripts inherit, add opt-in passEnv allowlist (#40757)
* fix(recipes): warn which credentials recipe scripts inherit, add opt-in passEnv allowlist

Recipe lifecycle scripts run locally with Orca's full environment. Keep that
default (provider CLIs and git auth rely on it) but name the credential-like
variables in Settings and let a recipe opt into passEnv so only listed
variables plus a safe base set reach its scripts.

* fix(recipes): fail closed on a malformed passEnv instead of dropping the recipe

Dropping the recipe let a stored snapshot or a same-id plugin recipe run with
the full environment. Keep it with an empty allowlist and a diagnostic, match
base variable names exactly outside Windows, and make the warning copy apply
to any recipe source.

* fix(recipes): import user-agent-platform from its new app-shell location
2026-11-10 17:58:06 -08:00
Jinjing 5f3b2fa4bf feat(artifacts): allow artifact publishing by default for new profiles (#40948)
New profiles default artifactSharingEnabled to true. Existing users are
unchanged: stored settings win over defaults on load, and a stored profile
saved before the key existed loads as false instead of inheriting the new
default. The gate still requires an explicit true, sign-in is still
required, and web clients still mirror the host (their local fallback no
longer inherits the desktop default). showArtifactsButton is unchanged.
2026-11-10 17:28:29 -08:00
Kelvin AmoabaandYangNuoCheng c2e6ebbf0b feat(cli): read, message and wait on agent chats with orca chat list/read/send/wait (#40836)
* feat(cli): read and message agent chats with orca chat list/read/send

Carried over from #33115 (squashed onto current main; conflicts with chat rename resolved).

* feat(cli): wait for a chat to settle, read text from stdin, refuse paired hosts

chat send --wait and chat wait poll the history's working flag until the
chat is idle or waits on a question, keeping a queued message pending until
it runs. chat read is one history fetch and returns a cursor. Unattached
and paired-host refusals say what they mean.

* fix(cli): settle a held queued message, skip subagent rows, resolve chat list --worktree

* fix(cli): show chat errors, keep waiting through queue handoffs, return the whole settled turn

* fix(cli): settle any queued message the host will not send, show grouped questions and only answerable prompts

* test(cli): drive chat tests through a real client and fake timers

* fix(cli): describe chat --session, --wait and --state in command help

* fix(cli): report chat wait in chat list's states, reject unknown --state, flag truncated reads

* docs(cli): say chat wait settles on the chat's own turn; no truncated flag on held

* fix(cli): chat rename help asks for a session id, not a handle

---------

Co-authored-by: YangNuoCheng <42427439+YangNuoCheng@users.noreply.github.com>
2026-11-10 22:37:31 +00:00
Kelvin Amoaba 6dfb4dc60d feat(cli): add orca tab annotations so agents can read a tab's unsent notes (#40873)
Prints the notes the user left on a browser tab and has not sent, the same text the tab's Copy button gives (--json returns them). Reads the saved session, so it works for closed-and-restored tabs; SSH hosts reach it through the desktop browser bridge. A page drawn by a paired desktop reports that its notes stay there.
2026-11-10 22:02:43 +00:00
Neil 9ef5e48f09 Plugins: add editor.readTypography and editor.typography.changed (#40736)
* feat(plugins): add editor.readTypography and editor.typography.changed

Plugins that render code next to Orca's editor had to open the private
profile database and reimplement Orca's font rules to match it. Host API 1.6
adds editor.readTypography (no capability; worker, panel and editor frames):
the font family and CSS stack, size with editor zoom, weight, line height in
px, ligatures, word wrap and minimap that the file editor resolves now.
editor.typography.changed carries the same values after a settings write or
an editor zoom changes them; it is the first event that needs no capability.

The pure resolution (editor typography, editor zoom, monospace font stack)
moves to src/shared so main and the renderer use one implementation.

* fix(plugins): keep editor typography resolution from throwing in main

A hand-edited profile with a non-string font family made the shared resolver
throw, which the main-process watcher would surface at startup and on every
settings write. Font values are now type-checked, the watcher catches and
logs, and it reads live settings so a write without listeners cannot leave the
event payload stale. Over-long font families are cut to the schema bound
instead of failing every read. Regenerates the testing runtime.
2026-11-10 03:38:47 -08:00
Vyacheslav ScherbininandKelvin Amoaba 1bdadc903b fix(skills): load Orca browser guidance for ordinary web tasks (#39916)
* docs: load Orca browser guidance for ordinary web tasks

Extend the Orca CLI skill description to include local and external page opening, reading, testing, and captures while working in Orca. Preserve explicitly chosen browser tools and the Computer Use boundary. Regenerate discovery/install bytes and append the new digest.

Fixes #39880

* fix: route existing Edge windows to desktop browser control

* docs: preserve configured desktop-control tool precedence

* docs(skills): scope orca-cli browser trigger to page work and keep the Computer Use rule

Drop "reading" so doc lookups stay on fetch tools, say plain HTTP/API calls don't need the skill, and restore the original Computer Use sentence and guide body, which the issue didn't ask to change.

* docs(skills): list Edge among existing browser windows in the orca-cli guide

The wider page trigger makes "screenshot my open Edge tab" load orca-cli, and the guide named only Chrome and Safari as windows that go to desktop control.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-11-09 23:27:58 +00:00
Jinwoo Hong bd56be7146 feat(orchestration): mail an agent on a paired server with send --on; its reply comes back by itself (#40106)
* feat(orchestration): mail agents on a paired server with send --on, replies come back by themselves

* fix(orchestration): gate --on on the carrying Orca, ack retried deliveries, refuse payloads and federated workers

* chore(orchestration): annotate peer-mail row casts and drop a wall-clock wait in its test

* chore(orchestration): name mail-between-servers codes server_mail_unsupported and mail_requires_server_pairing

* docs(cli): list --on in the orchestration reply usage

* fix(orchestration): name --environment, the flag on main, in agent mail refusals and the guide

* chore(orchestration): mark the two deliberate agent-kind branches mail between servers needs

* docs(cli): leave --on out of the reply usage; it is accepted only to refuse it

* fix(orchestration): keep peer conversations to peer ids, survive resets and re-pairs, keep pulling on a registry error

- A server takes only peerconv_ conversation ids, so a paired computer cannot name another Orca's dispatch in the relay.
- A replayed reply after a mail reset is acknowledged, not retried forever; reset tasks keeps replies waiting to be pulled.
- A re-paired server starts a new conversation instead of refusing every later send and reply.
- A failed registry read keeps the pull loop retrying.
- Drop the two ast-grep-ignore lines that only #40193's rule needed.

* fix(orchestration): worker-start --on runs on the caller's own Orca, like send --on

An inherited ORCA_ENVIRONMENT sent worker-start --on to that server, so the
--on command the agent refusal suggests did not work. One rule now keeps
send, reply and worker-start with --on on the caller's own Orca.

* fix(orchestration): refuse reply --on on both sides of a conversation between servers

The side that opened the conversation still took --on when it named the right
server; the reply usage says --on is accepted only to refuse it.
2026-11-09 17:00:11 -05:00
Neil f358eb6a7d Plugins: add workspace.rename and project names in workspace.list (#40197)
* feat(plugins): add workspace.rename and project names in workspace.list

Plugins that name workspaces had to read Orca's private runtime token and call
worktree.set over the runtime socket, bypassing capability consent. workspace.rename
(workspace:write, worker only, host API 1.5) does the same update as a sidebar
rename. workspace.list rows gain the project name so plugins can prefix names
without reading the runtime's repo list.

* fix(plugins): harden workspace.rename against twin folders and hidden characters

Folder renames require a unique folder id, so twins on two hosts are not both renamed,
and fail when no folder has the id. Names refuse C1, bidi and zero-width characters,
which could make a label read as another workspace's name.

* fix(plugins): workspace.rename matches a sidebar rename for folders and reports kept names

A folder rename also cancels a pending first-agent-message rename, so the automatic
title cannot replace the plugin's name. A rename Orca does not apply (during a WSL
move) is a conflict instead of a silent success. workspace.list's project is optional,
so mocks written for host API 1.4 still validate. More invisible characters are refused.
2026-11-09 00:48:33 -08:00
Neil 02ad6d9671 feat(cli): add orca vm env doctor to check that an environment can run agents (#40120)
* feat(cli): add orca vm env doctor to check a workspace environment

Checks required CLIs (git plus what the repo manifests imply), agent CLIs
and their sign-in, Git fetch and a dry-run push, the orca.yaml setup script
(optionally re-running it with Orca's runner), and free disk. Pass/warn/fail
with --json; checks live in src/main/environment-doctor for runtime reuse.

* fix(env-doctor): ship the doctor modules in the packaged CLI and share the check formatter

* fix(env-doctor): run Git probes in the C locale so folder detection is locale-independent
2026-11-09 00:09:00 -08:00
Jinwoo Hong 1a60595845 fix(orchestration): record orchestration as the origin of nested workers on connected servers; lead the guide with new-child (#40091)
worker-start --on <server> --worktree new-child now tells the server that
orchestration picked the parent, so the server records the child's lineage as
orchestration, as a local child is, instead of cli. Older coordinators omit the
field and keep cli. The guide now shows new-child first and new-top-level as
the no-parent choice.
2026-11-09 02:48:36 -05:00
Neil f36751f79f Revert "feat(cli): create workspaces on environment recipes (#40108)" (#40184)
This reverts commit 862d315575.
2026-11-08 23:10:35 -08:00
NeilandJustas Brazauskas 862d315575 feat(cli): create workspaces on environment recipes (#40108)
* feat(cli): create workspaces on environment recipes

`orca worktree create --recipe <id>` creates the workspace on a new
environment from one of the repo's environment recipes, and
`orca vm recipe list` shows which recipes it accepts.

The desktop app on the provisioning computer runs the same main-side
provisioning the composer uses (write-ahead record, per-step timeouts,
cancellation), registers the project on the environment's Orca server,
then creates (orca-worktree) or adopts (provisioned-root) the
workspace there. Named progress steps ride on long-poll keepalive
frames, so the CLI prints them to stderr; older CLIs ignore them. A
failure after the VM exists destroys it through the shared cleanup and
returns recipe_workspace_create_failed with the failed step, the
recipe failure code and whether the destroy finished. Ctrl+C aborts
the request and destroys a started environment.

Paired devices cannot start a recipe create. Hosts advertise
worktree.recipe-create.v1 only when the desktop wires the recipe
service, so orcad and older hosts are refused before anything runs.

Based on #39228 by jutaz, a port of #28439.

Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>

* fix(cli): report the VM outcome when connecting fails; record no cross-host parent

* fix(vm-recipes): destroy the VM when recording its environment fails; reset exitCode in CLI tests

* perf(types): keep recipe orchestration out of the runtime's type graph

---------

Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
2026-11-08 22:19:52 -08:00
Brennan Benson bf7dfff664 Keep Session History responsive on large histories: move session search SQLite to worker threads (#38945)
* Move session search SQLite into dedicated workers

* test: spawn the session search test worker with the shared worker helper

* fix: pass only drain promises to the channel's drain wait

* Repair session search failure and lifecycle boundaries

* Stop indexing tool output and reclaim existing rows

* test: say why the session search worker tests need a longer timeout

* Bound search cleanup and preserve failure and digest semantics

* Use the database row type for tool purge batches

* test: drop the same-connection mid-page write case now that each page reads one snapshot

* test: prove a mid-page delete from the writer can't change that page's hits

* Repair transcript cancellation cleanup and search test runtime admission

* fix: cancel active transcript finalization and enrichment waits

* fix: close transcript handles when cancellation wins delivery

* fix: preserve scan cancellation errors across parser waits

* test: prove cold session search bypasses an active writer batch

* fix: preserve search continuation through background tool cleanup

* fix: preserve search pages during orphan reclamation

* fix: bound typo repair posting visibility probes

* fix: preserve exact search terms when visibility is inconclusive

* test: drop orphan-reclaim cursor staleness case superseded by frozen continuation

* Bound session search work before ranking candidates

* Preserve the limit notice for empty search windows

* Bound session eligibility lookups and reuse FTS scoring statistics

* Index session scopes for population and candidate searches

* Derive search status from the live index after clear

* Preserve disabled search status during settings transitions

* Share planned expressions between spelling probes and search

* Keep identifier fragments out of spelling presence checks

* Report search initialization through its pending transition

* Bound spelling vocabulary work with the search posting budget

* Preserve search fallback while bounding distinct vocabulary seeks

* fix(session-search): drain removals before the worker queue fills; keep aborted close waits from failing teardown

* fix(session-search): hold writer commands when the worker queue is full instead of stopping the writer

* chore(ratchets): baseline the session search worker's one-shot entry check
2026-11-08 17:08:24 -08:00
Neil 0b1efd9b90 fix(vm-recipes): record each VM before create runs so a quit or crash can't leak it (#39241)
* fix(vm-recipes): record each VM before create runs so a quit or crash can't leak it

Orca now saves a "provisioning" record for a recipe VM before running its
create command, and updates it when create finishes. If Orca quits or
crashes mid-create, or create fails without returning a result, the VM
stays listed in Settings > Cloud VMs as Failed with its instance id, so the
user can run Cleanup (destroy gets the instance id) or remove it from the
list. On startup, provisioning records with no create running are marked
as interrupted.

Records without a recipe result live in a separate file that older builds
never read, so downgrading keeps working. Records also store the repo path
so Cleanup, Copy command, suspend and resume still work after the repo is
removed or re-added under a new id (#17293).

* fix(vm-recipes): keep no runtime row when create is cancelled or rejected before its script starts

* fix(vm-recipes): harden write-ahead records from review

- Never overwrite a provisioning-records file this build cannot read; refuse new records instead.
- Remove the provisioning-records file when empty instead of rewriting it on every store write.
- Only fall back to the saved repo path while it still defines the same recipe.
- Don't let Cleanup or Attach act on a create that is still running or never returned a result.
- Show Provisioning before Cleanup disabled; stamp running records with the save time.

* fix(vm-recipes): keep new store code off direct sync fs calls and render-path translate

* fix(vm-recipes): detect a missing provisioning-records file without a type assertion
2026-11-08 16:31:49 -08:00
Neil 47b4238cbc feat(vm-recipes): optional per-step timeouts for recipe lifecycle commands (#39238)
* feat(vm-recipes): optional per-step timeouts for recipe lifecycle commands

A recipe in orca.yaml can set timeoutSeconds (one number, or a map of
create/suspend/resume/destroy). When a step runs past its limit, Orca
stops the whole process tree the same way Cancel does and reports a
recipeTimedOut failure naming the step and the limit. Recipes that do not
set timeoutSeconds keep running with no limit, exactly as before.

Saved runtime records keep a recipe snapshot that older builds parse
strictly, so the snapshot leaves timeoutSeconds out; suspend, resume and
destroy read the current limit from the repo's orca.yaml instead.

Suspend and resume exit failures now go through the failure catalog with
the same English text.

* test(vm-recipes): fire the grandchild timeout only after the grandchild exists

* fix(vm-recipes): only reuse orca.yaml timeouts for the same recipe a runtime was created from
2026-11-08 15:48:32 -08:00
Brennan Benson 3fe350eaed Create a worktree per repository from an empty folder workspace (#39575)
A folder workspace with no worktrees now offers Create worktree for each repository, named after the folder workspace. If that branch name is already taken, the host refuses instead of picking another name, and the composer opens so you can choose.
2026-11-08 03:30:10 -08:00
Jinwoo Hong 4fabde28b1 feat(cli): one enclosing-workspace rule, --environment local, copyable addresses, and --parent-environment (#39733)
* feat(cli): one enclosing-workspace rule, --environment local, and copyable workspace addresses

current/active and cwd inference now pick the innermost workspace of either kind (worktree or
folder workspace); at equal depth the caller terminal's own workspace wins, otherwise the choice
is refused as ambiguous. --environment local names this machine's own Orca over an ambient
ORCA_ENVIRONMENT or pairing code. worktree ps/show/current print an environment: line and an
address: line (JSON environment, address, addressUnavailable, parent) that always carries its
--environment, and name a parent's environment only when it is verified.

* test: answer the folder catalog read in agent launch cwd tests

* feat(cli): worktree rm refuses current/active and names the selector to pass

Removal needs an explicit workspace, as git worktree remove needs a path. The refusal runs before
rm decides between a worktree and a folder workspace, and reports what current resolves to now
(one selector, the ambiguous choices, or none) in text and as invalid_argument data.

* fix(cli): keep the remote-environment guidance when rm refuses current

* fix(cli): surface folder-catalog failures for omitted targets; no address for a duplicated folder parent

* fix(cli): surface a worktree-list failure for omitted browser and terminal targets too

* test(cli): folder rm refuses current/active before the folder removal path

* fix(cli): refuse a cwd owner whose folder host can't be derived instead of skipping it

* fix(cli): compare cwd owners by filesystem identity, refuse every equal-path tie, surface worktree-list failures

Paths on the caller's own filesystem compare by realpath (reusing resolveRealPathSync), so /tmp
and /private/tmp aliases find the deeper owner in both the folder prefilter and ranking; other
hosts' paths stay lexical. Equal-depth owners with different repo registrations now refuse without
a caller instead of picking by catalog order. An omitted target no longer swallows worktree.list
method_not_found; only the optional folder reads fall back.

* fix(cli): read the realpath helper from shared so the packaged CLI ships it

* refactor(cli): move the catalog row type and unresolved-owner refusal out of the selection/catalog cycle

* fix(cli): resolve every caller-filesystem workspace path, not only basename matches

A workspace registered through a differently named symlink was skipped by the basename gate.
Containment now realpaths cwd and each row on the caller's own filesystem once per command,
shared by the folder prefilter and ranking; folder hosts are derived first so another host's
paths are never resolved locally.

* test: answer the folder catalog read in the ambiguous orchestration-check caller test

* feat(cli): --parent-environment names where a worktree's parent lives

worktree create and worktree set take --parent-environment <local|saved id|name>
next to --parent-worktree. The parent is resolved in that environment only, and
sent to the child as a verified cross-store ref after the child's cross-machine
capability check. Without the flag, the parent stays in the child's environment;
active/current always mean this machine's own Orca.

Preflight failures happen before any change: environment_not_paired,
environment_unavailable, LINEAGE_PARENT_NOT_FOUND / LINEAGE_PARENT_AMBIGUOUS
naming the searched environment, and incompatible_runtime with data.environment
and data.requires.

* fix(cli): parent lookup errors name and list the environment searched

LINEAGE_PARENT_AMBIGUOUS and LINEAGE_PARENT_NOT_FOUND now always carry
data.environment and a listing command for the environment the parent was
looked up in, for parents in another environment and in the child's own. Steps
inherited from the runtime listed the caller's default route instead.

* docs(cli): a local address names the Orca that printed it
2026-11-08 04:08:07 -05:00
Jinwoo Hong a55de38395 feat(cli): set and rm folder workspaces through the folder workspace RPCs (#39670)
* feat(cli): set and rm folder workspaces through the folder workspace RPCs

worktree set and rm on folder:<id> (or a path:/name: selector that matches a
folder) now call folderWorkspace.update and folderWorkspace.delete after the
runtime confirms the folder id is unique. Flags with no folder meaning are
refused before any change, a missing method reports incompatible_runtime, and
worktree activate refuses folder workspaces as not supported yet.

* test: read mocked method names without a cast

* fix(runtime): refuse shared folder ids inside folder update and delete

The CLI's show preflight could not make the id-only folder RPCs safe: an older
show could select one of two same-id rows, and a twin added during teardown was
deleted too. folderWorkspace.update/delete now take requireUniqueId, which
refuses a shared id before any side effect, and delete removes only the row it
checked. Hosts advertise folder-workspace.unique-id-mutation.v1; the CLI
requires it and reports incompatible_runtime otherwise.

* fix(runtime): refuse a folder delete when a twin appears during teardown

Two rows that share a folder id share every record keyed by it, so delete
can't keep one row's sessions while removing the other. After the awaited
terminal teardown, delete checks the id again before any cleanup or removal
and refuses with the duplicate-id error; only the stopped terminals remain as
an effect. Removal by row identity is no longer needed and is dropped.

* fix(cli): give only the repair step for a duplicated folder id

The generic ambiguity recovery told agents to pass folder:<id>, which can't
name one of two folders sharing that id.
2026-11-08 00:34:44 -05:00
Jinwoo Hong f341558b82 feat(cli): match folder workspaces by path: and name:, keep same-id ps rows apart (#39637)
* feat(cli): match folder workspaces by path: and name:, and keep same-id ps rows apart

Adds one runtime matcher for worktrees and folder workspaces. With the new
matchFolderWorkspaces opt-in (advertised as workspace-selector.folder-match.v1),
path: and name: also match folder workspaces; branch:, issue: and identity:
stay repo-backed. Several matches refuse with each choice's kind, host, path
and selector; a folder id shared by two folder workspaces refuses with the
repair step. The CLI resolves path:/name: through it, so terminal, file and
ports commands reach a folder workspace, and create/set parents record a
folder parent. Explicit ambiguous parents report LINEAGE_PARENT_AMBIGUOUS.

worktree ps now keeps rows that share an id on different hosts apart, with
their own host, identity, metadata and activity; activity whose host can't
be proven attaches to neither.

* test: let the cross-version ps harness pass the host-qualified summary lookup

* fix(cli): read each ps row's own host session; qualify folder selector help

* fix(runtime): refuse unscoped duplicate folder ids; hand lineage the matcher's typed result

Unscoped folder:<id> refuses a duplicated id even when only one copy's host
is derivable; a host-scoped lookup still picks that host's copy. A wsl: hook
stamp counts as local host evidence. The lineage controller receives the
worktree-or-folder candidate directly instead of re-deriving the kind.

* docs(cli): guide the ambiguity fallback through truncated ps and id: selectors

* fix(cli): report an ambiguous parent by its own choices; cover per-host sessions

* fix(cli): send parents to the runtime parent resolver as typed; translate WSL paths for folders too

Parent selectors skip the CLI's show-based folder lookup, so worktree.create
and worktree.set classify them with parent rules: a folder spanning hosts is
a valid parent, and ambiguity reports LINEAGE_PARENT_AMBIGUOUS. Caller-distro
Linux path translation now also matches folder workspaces.

* chore(rpc): import the computer-use recovery data directly instead of through an alias

* fix(runtime): report a missing set parent as LINEAGE_PARENT_NOT_FOUND, as create does

worktree set and worktree create now share one explicit-parent error
conversion: several matches give LINEAGE_PARENT_AMBIGUOUS and none give
LINEAGE_PARENT_NOT_FOUND, so a missing parent is no longer reported as a
bare selector_not_found that could mean the child.
2026-11-07 23:35:33 -05:00
Neil 51f3c956ed feat(plugins): let plugins ship web fonts for the terminal, editor and interface (#39416)
* feat(plugins): let plugins contribute web fonts to the font pickers

Plugins declare font families under contributes.fonts (WOFF/WOFF2 only).
Install checks each file's signature against its extension and caps file
size, family count and plugin total; main never parses a font. Files are
served over the plugin image scheme only while the plugin is enabled,
typed and nosniff. The renderer registers each family under a name that
carries the plugin key, so a plugin font cannot shadow an installed or
built-in font, and it applies only once the user picks it. Disabling or
uninstalling removes the faces; uninstalling also resets font settings
that named them.

Refs #38607

* fix(plugins): harden plugin fonts and re-measure editors when they load

- Refuse WOFF/WOFF2-wrapped font collections by checking the flavor bytes.
- Check dev folders' font files at discovery, not only at install.
- Re-check family, weight and style from the plugin list in the renderer.
- Track loaded families (case-insensitively) from document font loads, so
  the code editor re-measures and terminals, previews, the SSH terminal and
  the dashboard popout re-apply only when their own font changes.
- Register plugin fonts in the dashboard popout window.
- Give dev-folder font URLs their change count so edits reload.
- Keep monospace fallbacks unless the chosen family is exactly that font.

* fix(terminal): keep every fallback only for plugin font families

System font choices keep their existing fallback list unchanged.

* fix(plugins): leave the dashboard popout's plugin list alone; add the font row string

Registering fonts there started the plugin auto-update watcher in a window with no toaster, which could consume update notices. Adds the new contribution-row string to the English catalog and the fonts list to the RPC test manifest.
2026-11-07 02:08:35 -08:00
Brennan Benson f308486115 Show Source Control for folder workspaces (#38831)
* Separate editor tab placement from content ownership

* Show scoped Source Control sections for attached worktrees

* Preserve active diff refresh and validate section catalogs

* Complete folder section test worktree metadata

* Use contextual types for scoped Source Control actions

* Preserve optional scoped action parameters

* Preserve editor ownership through restore, mirroring and workspace removal

* Retire Source Control drafts only after confirmed owner removal

* Limit section work to visible expanded repositories

* Keep editor follow-up actions and bulk closes in their invoking views

* Track the consolidated editor order writer in its owning module

* Use complete typed fixtures for repair contracts

* Preserve live editor placement during layout readback

* Pass projected editor placement directly to serialization

* Read attached worktree lineage from shared graph module

* Retain inferred owner checks and scope placement retirement

* Preserve selection in untouched workspaces during purge

* Exercise editor placements in existing launch and lifecycle fixtures

* Preserve shared buffer prompts and editor strip order

* Pause inactive section context subscriptions

* Keep section recovery and file actions in the folder workspace

* Describe attached Source Control in folder workspace CLI help

* Attribute Git metadata signals once per dispatch

* Watch mounted source control sections outside the warm budget

* Resolve section watches only for served filesystem roots

* Restore restart-stable editor identity across SSH opens

* Apply section terminal routing to explicit Chat choices

* Include cross-store descendants in folder workspace panels

* Keep cross-host recovery on its existing workspace route

* Start cross-host section agents in their workspace without navigation

* Update memoized Source Control labels on language changes

* Remove unused terminal close-to-right implementation

* Suspend inactive Source Control body observers

* Retain base ref query while section observation pauses

* Cover retained base ref search across section visibility

* Resolve note menu ownership from the retained snapshot

* Preserve section agent working directories and background placement

* Keep Source Control sections active while their overlays are open

* Read current settings when Source Control commands execute

* Adapt editor and browser test stores to view subscriptions

* Preserve bound store hooks for ordinary app views

* Trust agent starts outside the placement workspace

* Trust the section worktree through transient launch ownership

* Extract editor follow-up file actions from the panel

* Fail section launches when trust capability lookup fails

Preserve explicit unsupported-host fallback, propagate lookup failures to the existing launch error path, and let the existing transport retry refresh rejected capability probes.

* Follow the moved pane launch test in web configs

* Preserve section file ownership during refresh and close

* Share tab order removal across editor close paths

* Verify companion editor close through the real store

* Close all workspace split copies for legacy mobile file requests

* Keep unmatched mobile close requests within their workspace

* Reuse the agent menu render snapshot

* Keep attached folder roots scoped to their resolved host

* Apply repository trust decisions to the launch trust owner
2026-11-06 18:25:57 -08:00
Jinwoo Hong 555bd481bc Let multi-repo folder workspaces parent and nest workspaces, including on other machines (#38904)
Multi-repo folder workspaces can parent workspaces on this machine and on paired servers, and their children nest under them in the sidebar and on the phone. Task parents are inferred at creation instead of on every lineage refresh.
2026-11-06 19:03:51 -05:00
Brennan Benson e0005f5cbf Attach existing worktrees to folder workspaces from the CLI (#39018)
* feat(cli): attach existing worktrees to folder workspaces

worktree set accepts --parent-worktree folder:<id> (hosts advertise
worktree.set.folder-parent.v1), keeping each worktree to one parent in the
store. --parent-worktree active/current resolves to a folder workspace from
its terminal or enclosing directory, and worktree create without --repo under
a folder workspace lists the folder's Git repositories with a ready command.

* fix(cli): report folder parents and keep typed flags in folder repo choices

worktree show/set report a folder parent; the missing-repo error lists --repo
choices to add to the user's command and names the Attached worktrees panel.
Load and import repairs skip malformed rows and only touch imported worktrees,
an import keeps a worktree's existing parent, a twin-owned folder parent warns,
and folder ambiguity keeps its choices.

* fix(persistence): settle one parent per imported worktree before writing

An Orca server migration import now decides each touched worktree's parent
before any write: an explicit folder parent replaces an inferred worktree
parent, any other disagreement refuses the import. --parent-worktree active
in a folder terminal still lists the folder's repositories.

* fix(persistence): let a folder parent beat hydrate's inferred worktree parent

Load repair and import reconciliation share one rule: an inferred worktree parent loses
to a folder parent when the folder was chosen explicitly or the worktree parent carries
hydrate's orchestration stamp. Import tests now run payloads through the manifest parser
and cover a conflict that appears after staging.

* fix(cli): list folder repos when active resolves to the enclosing folder

worktree create without --repo used only the terminal's env to find the folder, so
--parent-worktree active run outside an Orca terminal fell back to the generic
missing-repo error. Use the parent create already resolved.
2026-11-06 15:13:57 -08:00
Neil b9a4b5fd2f fix(plugins): re-review any plugin whose catalog moves it to another repository (#36643)
* fix(plugins): drop a plugin's approval when its catalog moves it to another repository

* plugins: revokePluginConsent refuses when the plugin service is not running

* cli: orca plugin install/update ask again when a plugin moves to another repository, for every plugin kind
2026-11-06 14:41:29 -08:00
Neil be3b87f3ac cli: add orca plugin install, update, uninstall and catalog list/add/rm (#36647)
* cli: add orca plugin install, update, uninstall and catalog list/add/rm

* plugins: escape the invisible-character regex so the orcad bundle stays ASCII

* plugins: split approval re-run helpers and plugin RPC binding to stay under max-lines
2026-11-06 14:20:27 -08:00
Neil f0bfce8fce fix(automations): accept Antigravity model and effort extra arguments (#39161)
Antigravity automations refused --extra-agent-args, so unattended agy jobs
could only use the model and effort from agy's global settings.json. Allow
--model and --effort through the existing allowlist; permission, mode, and
other flags stay refused.

Part of #35234 (STA-12678).
2026-11-06 12:55:54 -08:00
Kelvin Amoaba 345c326a91 feat(cli): rename a chat with orca chat rename (#38719)
Fixes #38556
2026-11-06 03:44:40 +00:00