Files
orca/docs/reference/plugin-host-api.md
T
Neil a9b1041ecc feat(plugins): status bar items plugins can update live (#37291)
* plugins: contributes.statusBarItems with worker updates (statusBar.update)

A plugin declares status bar items { id, text?, icon?, tone?, tooltip?,
command? } (declarative profile, engines >=1.4.247); pressing one runs
its own command. A trusted worker changes them with the new worker-only
host method statusBar.update; main keeps the session's changes and
pushes snapshots to desktop windows over plugins:statusBarChanged.
Regenerates schemas, references, typings and the authoring skill.

* plugins: statusBarItems ship in 1.4.248, beside contributes.hooks

* plugins: clear a plugin's status bar changes when it is disabled, removed or updated

* plugins: list status bar items in the plugin page's Adds section

* plugins: count statusBarItems' since in the host's newest readable version

* i18n: add the plugin page's status bar row label to en.json

* plugins: status bar items respect workspace commands, dev reloads and catalog summaries

- An item whose command needs a workspace is disabled with no open workspace.
- A dev code edit (new devRevision) drops the old worker's status bar changes.
- Catalog summaries list status bar items, and marketplace details show them.

* plugins: authoring skill lists status bar items as buildable; approval lists them

The skill no longer calls status bar items reserved and gains a row for them. The
dev-load/inspect approval already lists them via the contribution summary; a test pins
that and the fingerprint binding.

* chore(plugins): regenerate the testing bundle after rebasing on main
2026-11-02 04:26:55 +00:00

224 lines
13 KiB
Markdown

# Orca plugin host API reference
<!-- Generated by `pnpm generate:plugin-schemas` from src/shared/plugins. Do not edit. -->
Host API 1.2 (`"pluginApi": 1`). Workers call a method with `await orca.host.call(name, params)`; panels and custom editors call the same methods through `window.orca.host.call(name, params)`. Each method lists the surfaces allowed to call it; any other surface gets `not_permitted`. `orca.host.has(name)` answers synchronously whether this Orca offers a method on the current surface, and `orca.api` is `{ major, minor }`. See [Plugin authoring](./plugin-authoring.md) for the frame API.
Every call is checked against the capabilities the user approved, and params are validated before Orca runs anything: params are strict, so a field this Orca does not know is refused with `invalid_params` instead of being dropped. Mutations are recorded in the audit log as `plugin:<publisher>.<id>`.
Methods whose capability is `none` need no capability but still need the plugin enabled and approved. `shell.openExternal` and `files.saveAs` also need transient user activation (a click or key press in the calling frame, within a few seconds), are rate-limited, and run only in the desktop app; frames also reach them as `orca.shell.openExternal(url)` and `orca.files.saveAs({ suggestedName, mimeType, data })`, which resolves with `{ status: "saved" }`, or `{ status: "cancelled" }` when the person cancels the dialog. Saved files carry the OS mark for downloaded files.
## Methods
| Method | Capability | Surfaces | Mutation | Since | Summary |
| --- | --- | --- | --- | --- | --- |
| [`workspace.readContext`](#workspacereadcontext) | `workspace:read` | worker, panel, editor | no | 1.0 | Branch, name and terminal ids of the focused workspace, or null when none is focused. |
| [`terminal.sendText`](#terminalsendtext) | `terminal:send` | worker | yes | 1.0 | Types text into one terminal named by id, optionally pressing Enter. |
| [`notifications.show`](#notificationsshow) | `notifications:show` | worker, panel, editor | yes | 1.0 | Shows a desktop notification. |
| [`storage.get`](#storageget) | `storage:own` | worker, panel, editor | no | 1.0 | Reads a JSON value from the plugin's private store; null when absent. |
| [`storage.set`](#storageset) | `storage:own` | worker, panel, editor | yes | 1.0 | Writes a JSON value to the plugin's private store. |
| [`storage.delete`](#storagedelete) | `storage:own` | worker, panel, editor | yes | 1.0 | Removes a key from the plugin's private store. |
| [`storage.keys`](#storagekeys) | `storage:own` | worker, panel, editor | no | 1.0 | Lists the keys in the plugin's private store. |
| [`secrets.get`](#secretsget) | `secrets:own` | worker, panel, editor | no | 1.0 | Reads a secret from the plugin's encrypted secrets file; null when absent. |
| [`secrets.set`](#secretsset) | `secrets:own` | worker, panel, editor | yes | 1.0 | Stores a secret in the plugin's encrypted secrets file. |
| [`secrets.delete`](#secretsdelete) | `secrets:own` | worker, panel, editor | yes | 1.0 | Removes a secret from the plugin's encrypted secrets file. |
| [`secrets.protection`](#secretsprotection) | `secrets:own` | worker, panel, editor | no | 1.1 | How secrets are protected at rest: `os-keyring`, or `unavailable` (no OS key store, or Linux `basic_text`), where `secrets.set` fails. |
| [`settings.get`](#settingsget) | `settings:own` | worker, panel, editor | no | 1.0 | Reads every setting the plugin owns. |
| [`settings.set`](#settingsset) | `settings:own` | worker, panel, editor | yes | 1.0 | Writes one setting the plugin owns. |
| [`shell.openExternal`](#shellopenexternal) | none | panel, editor | no | 1.1 | Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; `opened` is false if they cancel. |
| [`files.saveAs`](#filessaveas) | none | panel, editor | yes | 1.1 | Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only. |
| [`plugin.request`](#pluginrequest) | none | panel, editor | no | 1.2 | Asks the plugin's own worker to run the handler it registered with `orca.panels.handle(name)`, starting the worker if needed; resolves with what the handler returned. `unknown_method` when no handler has that name. |
| [`agents.list`](#agentslist) | `agent:read` | worker, panel, editor | no | 1.2 | The agents in the focused workspace: their terminal, title, agent kind and status. `agent.status.changed` reports each change after. |
| [`events.subscribe`](#eventssubscribe) | none | panel, editor | no | 1.2 | Delivers a workspace or agent event to this panel as `orca.on(event)`; needs the event's read capability. The frame APIs call it for you. |
| [`statusBar.update`](#statusbarupdate) | none | worker | no | 1.2 | Changes one of the plugin's `contributes.statusBarItems` (named by `id`): fields given replace their current value, `visible: false` hides it. Desktop app only; lasts until Orca restarts, and is hidden while the plugin is disabled. |
### `workspace.readContext`
Branch, name and terminal ids of the focused workspace, or null when none is focused.
```ts
(params?: {}) => { branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null
```
### `terminal.sendText`
Types text into one terminal named by id, optionally pressing Enter.
```ts
(params: { terminalId: string; text: string; enter?: boolean }) => { accepted: boolean }
```
### `notifications.show`
Shows a desktop notification.
```ts
(params: { title: string; body?: string }) => { delivered: boolean }
```
### `storage.get`
Reads a JSON value from the plugin's private store; null when absent.
```ts
(params: { key: string }) => { value: JSON }
```
### `storage.set`
Writes a JSON value to the plugin's private store.
```ts
(params: { key: string; value: JSON }) => { ok: true }
```
### `storage.delete`
Removes a key from the plugin's private store.
```ts
(params: { key: string }) => { ok: true }
```
### `storage.keys`
Lists the keys in the plugin's private store.
```ts
(params?: {}) => { keys: string[] }
```
### `secrets.get`
Reads a secret from the plugin's encrypted secrets file; null when absent.
```ts
(params: { key: string }) => { value: string | null }
```
### `secrets.set`
Stores a secret in the plugin's encrypted secrets file.
```ts
(params: { key: string; value: string }) => { ok: true }
```
### `secrets.delete`
Removes a secret from the plugin's encrypted secrets file.
```ts
(params: { key: string }) => { ok: true }
```
### `secrets.protection`
How secrets are protected at rest: `os-keyring`, or `unavailable` (no OS key store, or Linux `basic_text`), where `secrets.set` fails.
```ts
(params?: {}) => { status: "os-keyring" | "unavailable" }
```
### `settings.get`
Reads every setting the plugin owns.
```ts
(params?: {}) => { settings: Record<string, JSON> }
```
### `settings.set`
Writes one setting the plugin owns.
```ts
(params: { key: string; value: JSON }) => { ok: true }
```
### `shell.openExternal`
Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; `opened` is false if they cancel.
```ts
(params: { url: string }) => { opened: boolean; reason?: "cancelled" | "consent-unavailable" }
```
### `files.saveAs`
Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only.
```ts
(params: { suggestedName?: string; mimeType?: string; data: string | ArrayBuffer }) => { status: "saved" | "cancelled" }
```
### `plugin.request`
Asks the plugin's own worker to run the handler it registered with `orca.panels.handle(name)`, starting the worker if needed; resolves with what the handler returned. `unknown_method` when no handler has that name.
```ts
(params: { name: string; input?: JSON; timeoutMs?: number }) => { output: JSON }
```
### `agents.list`
The agents in the focused workspace: their terminal, title, agent kind and status. `agent.status.changed` reports each change after.
```ts
(params?: {}) => { agents: { terminalId: string | null; title: string | null; agent: string | null; state: "working" | "blocked" | "waiting" | "done"; stateStartedAt: number }[] }
```
### `events.subscribe`
Delivers a workspace or agent event to this panel as `orca.on(event)`; needs the event's read capability. The frame APIs call it for you.
```ts
(params: { event: "workspace.created" | "workspace.removed" | "agent.status.changed" | "workspace.changed" }) => { ok: true }
```
### `statusBar.update`
Changes one of the plugin's `contributes.statusBarItems` (named by `id`): fields given replace their current value, `visible: false` hides it. Desktop app only; lasts until Orca restarts, and is hidden while the plugin is disabled.
```ts
(params: { id: string; text?: string; icon?: "activity" | "bar-chart-3" | "bell" | "blocks" | "book" | "bot" | "bug" | "calendar" | "cloud" | "code" | "database" | "file-text" | "flag" | "folder" | "gauge" | "globe" | "hammer" | "layers" | "lightbulb" | "package" | "plug" | "puzzle" | "rocket" | "star" | "terminal" | "wrench" | "zap" | "add" | "remove" | "delete" | "edit" | "refresh" | "search" | "settings" | "check" | "close" | "info" | "warning" | "error" | "open-external" | "copy" | "download" | "upload" | "play" | "pause" | "stop" | "more" | "expand" | "collapse" | "next" | "filter" | "branch" | "file" | "agent" | "link"; tone?: "neutral" | "accent" | "success" | "warning" | "danger"; tooltip?: string; visible?: boolean }) => { ok: true }
```
## Events
A worker receives the events its manifest lists in `contributes.events` through `orca.events.on(event, handler)`, which returns `{ dispose() }`. Each needs `main`, the `trusted-worker` profile and its domain's capability (`workspace:read` or `agent:read`). `orca plugin types` writes the payloads as `PluginEvents` in `orca/host`.
| Event | Payload | Summary |
| --- | --- | --- |
| `workspace.created` | `{ workspaceId: string; kind: "worktree" \| "folder"; path: string; branch: string }` | A worktree workspace was created. |
| `workspace.removed` | `{ workspaceId: string; kind: "worktree" \| "folder"; path: string }` | A worktree workspace was removed. |
| `agent.status.changed` | `{ workspaceId: string \| null; paneKey: string; terminalId?: string; title?: string; state: "working" \| "blocked" \| "waiting" \| "done"; receivedAt: number; mainAgent?: { state: "working" \| "blocked" \| "waiting" \| "done"; outcome?: "success" \| "failure" \| "cancellation" \| "superseded" \| "interruption" \| "unconfirmed"; stateStartedAt: number } }` | An agent in a terminal pane changed status; `workspaceId` is null when Orca cannot tie the pane to a workspace, and `terminalId` names its terminal when Orca lists it. |
| `workspace.changed` | `{ context: { branch: string; displayName: string; terminals: { id: string; title?: string }[] } \| null }` | The focused workspace changed, or its terminals were opened, closed or renamed; `context` is what `workspace.readContext` now answers. Each new subscriber first gets the current context. |
## Errors
A failed call rejects with an `Error` carrying `code`, `message`, `retryable` and, for `rate_limited`, `retryAfterMs`. Treat a code not listed here as `action_failed`:
- `invalid_request`: the call itself is malformed.
- `invalid_params`: params do not match the method, including a field this Orca does not know; the message names it.
- `unknown_method`: the method does not exist in this Orca.
- `capability_denied`: the manifest does not declare the capability.
- `consent_required`: the plugin is disabled or the user has not approved this version.
- `not_permitted`: the method or document is not available here, e.g. a worker-only method from a panel.
- `rate_limited`: calls arrive faster than the budget; `retryAfterMs` says when to try again.
- `unavailable`: the service behind the method is not running yet.
- `action_failed`: the method ran and failed.
- `cancelled`: the caller aborted the call through its `signal`.
- `timeout`: Orca gave up waiting.
- `conflict`: the call was made against a stale version, e.g. an editor edit after an outside change.
- `too_large`: the message is larger than Orca accepts.
## Stability and deprecation
Plugins are in Alpha: the manifest v2 format and catalog format are stable contracts; items listed as experimental in [Plugin authoring](./plugin-authoring.md#stability) may change.
- **Host API 1 is frozen.** Within `pluginApi` 1, methods, params and results only grow: a new method or a new optional param arrives with a higher `Since` minor, and nothing listed here is removed, renamed or narrowed.
- **Deprecation.** A method to be retired is marked deprecated in this table and keeps working for the rest of the major.
- **New majors.** A breaking change ships as a new `pluginApi` major beside the old one. Orca refuses a manifest whose `pluginApi` names a major it does not implement, with "update Orca", instead of loading it against the wrong API.
- **Detect, do not assume.** Check `orca.host.has(name)` or `orca.api.minor` before calling a method newer than the oldest Orca you support; a call that slips through fails with `unknown_method`.