Files
orca/resources/plugins/declarative/orca.d.ts
T
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

181 lines
12 KiB
TypeScript

// Author typings for Orca components panels (`"ui": "components"`): the runtime API.
// `orca plugin types` joins this file with orca-components*.d.ts (the catalog) and installs
// types/orca-services.d.ts, which adds `shell`, `files`, `on`, `plugin`, `storage`, `settings` and
// `secrets` to this module. Mirrors src/shared/plugins/declarative/ (checked by
// plugin-declarative-typings.test.ts); host methods are generated from the host API.
declare module 'orca' {
export type OrcaElement = { readonly $$typeof: symbol }
export type OrcaNode =
| OrcaElement
| string
| number
| boolean
| null
| undefined
| readonly OrcaNode[]
/** Catalog tags are JSX-only: write `<Stack>`, never call `Stack()`. */
export type OrcaComponent<P> = (props: P) => OrcaNode
/** Read with `read()`; reading while rendering re-renders when it changes. */
export type ReadonlyAtom<T> = { readonly __orcaAtom: T }
/** Changed with `set()` or `update()`. */
export type Atom<T> = ReadonlyAtom<T> & { readonly __orcaWritable: true }
export type Disposable = { dispose(): void }
export type Theme = { colorScheme: 'light' | 'dark' }
export type JsonValue =
| string
| number
| boolean
| null
| JsonValue[]
| { [key: string]: JsonValue }
export const Fragment: unique symbol
export function h(type: unknown, props: object | null, ...children: OrcaNode[]): OrcaElement
/**
* Where a keyed atom survives: this panel run, every run of the plugin, per workspace, or the
* plugin's own storage under the atom's key (`storage:own`), shared with its worker and other
* panels and kept current when they change it.
*/
export type PersistScope = 'memory' | 'plugin' | 'workspace' | 'storage'
export type AtomOptions<T> = {
/** Persisted values must be plain JSON; they load before the first render. `storage` values
* are stored as they are, so `version` and `migrate` do not apply to them. */
persist?: PersistScope
/** Bump when the stored shape changes; `migrate` then receives the older value. */
version?: number
migrate?: (stored: JsonValue, fromVersion: number) => T
}
/** State for this panel run. */
export function atom<T>(initial: T): Atom<T>
/** Named state, unique per plugin, optionally persisted. */
export function atom<T>(key: string, initial: T, options?: AtomOptions<T>): Atom<T>
/** Computed from other atoms; reading it while rendering subscribes to what it reads. */
export function derived<T>(compute: () => T): ReadonlyAtom<T>
export function read<T>(atom: ReadonlyAtom<T>): T
/** Stores `value` as is (functions included). Batched; throws while rendering. */
export function set<T>(atom: Atom<T>, value: T): void
/** Replaces the value with `updater(previous)`. Batched; throws while rendering. */
export function update<T>(atom: Atom<T>, updater: (previous: T) => T): void
/** Optional: the module's default export is mounted automatically. */
export function mount(component: () => OrcaNode): void
/** Passed to the module's optional `export function setup(ctx)`. */
export type PanelContext = {
/** Disposed when the panel closes or reloads. */
subscriptions: Disposable[]
/** Aborts when the panel closes or reloads. */
signal: AbortSignal
/** True while the person can see the panel. */
visible: ReadonlyAtom<boolean>
panel: { id: string }
}
/** Runs once, after persisted atoms load and before the first render. */
export type PanelSetup = (ctx: PanelContext) => void | (() => void)
export type HostCallOptions = { signal?: AbortSignal; timeoutMs?: number }
/** Rejections carry a `code` (`not_permitted`, `capability_denied`, `timeout`, ...). */
export type HostError = Error & { code: string; retryable: boolean; retryAfterMs?: number }
// <generated: host methods, from plugin-host-api.ts>
export type HostMethods = {
/** Id, branch, name and terminal ids of the focused workspace, or null when none is focused. */
"workspace.readContext": { params: Record<string, never> | undefined; result: { workspaceId?: string; branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null }
/** Shows a desktop notification. */
"notifications.show": { params: { title: string; body?: string }; result: { delivered: boolean } }
/** Reads a JSON value from the plugin's private store; null when absent. */
"storage.get": { params: { key: string }; result: { value: JsonValue } }
/** Writes a JSON value to the plugin's private store. */
"storage.set": { params: { key: string; value: JsonValue }; result: { ok: true } }
/** Removes a key from the plugin's private store. */
"storage.delete": { params: { key: string }; result: { ok: true } }
/** Lists the keys in the plugin's private store. */
"storage.keys": { params: Record<string, never> | undefined; result: { keys: string[] } }
/** Reads a secret from the plugin's encrypted secrets file; null when absent. */
"secrets.get": { params: { key: string }; result: { value: string | null } }
/** Stores a secret in the plugin's encrypted secrets file. */
"secrets.set": { params: { key: string; value: string }; result: { ok: true } }
/** Removes a secret from the plugin's encrypted secrets file. */
"secrets.delete": { params: { key: string }; result: { ok: true } }
/** How secrets are protected at rest: `os-keyring`, or `unavailable` (no OS key store, or Linux `basic_text`), where `secrets.set` fails. */
"secrets.protection": { params: Record<string, never> | undefined; result: { status: "os-keyring" | "unavailable" } }
/** Reads every setting the plugin owns. */
"settings.get": { params: Record<string, never> | undefined; result: { settings: Record<string, JsonValue> } }
/** Writes one setting the plugin owns. */
"settings.set": { params: { key: string; value: JsonValue }; result: { ok: true } }
/** 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. */
"shell.openExternal": { params: { url: string }; result: { opened: boolean; reason?: "cancelled" | "consent-unavailable" } }
/** 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. */
"files.saveAs": { params: { suggestedName?: string; mimeType?: string; data: string | ArrayBuffer }; result: { status: "saved" | "cancelled" } }
/** 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. */
"plugin.request": { params: { name: string; input?: JsonValue; timeoutMs?: number }; result: { output: JsonValue } }
/** The agents in the focused workspace: their terminal, title, agent kind, status, session and dispatched task. `agent.status.changed` reports each change after. */
"agents.list": { params: Record<string, never> | undefined; result: { agents: { terminalId: string | null; title: string | null; agent: string | null; state: "working" | "blocked" | "waiting" | "done"; stateStartedAt: number; sessionId?: string | null; task?: { title: string } | null }[] } }
/** Delivers a workspace, agent or editor event to this panel as `orca.on(event)`; needs the event's read capability, when it has one. The frame APIs call it for you. */
"events.subscribe": { params: { event: "workspace.created" | "workspace.removed" | "agent.status.changed" | "workspace.changed" | "editor.typography.changed" }; result: { ok: true } }
/** The font family, size, weight, line height, ligatures, word wrap and minimap Orca's file editor uses now, editor zoom included. `editor.typography.changed` reports each change after. */
"editor.readTypography": { params: Record<string, never> | undefined; result: { fontFamily: string; cssFontFamily: string; fontSize: number; fontWeight: string; lineHeight: number; fontLigatures: boolean; wordWrap: "on" | "off"; minimap: boolean } }
}
/** Workspace and agent events `on(event)` delivers, with the read capability of their domain. */
export type PluginEvents = {
/** A worktree workspace was created; `workspaceListId` (host API 1.7) is the id `workspace.list` gives it. */
"workspace.created": { workspaceId: string; workspaceListId?: string; kind: "worktree" | "folder"; path: string; branch: string }
/** A worktree workspace was removed; `workspaceListId` (host API 1.7) is the id `workspace.list` gave it. */
"workspace.removed": { workspaceId: string; workspaceListId?: string; kind: "worktree" | "folder"; path: string }
/** An agent in a terminal pane changed status; `workspaceId` is null when Orca cannot tie the pane to a workspace, `workspaceListId` (host API 1.7) is the id `workspace.list` gives that workspace, `terminalId` names its terminal when Orca lists it, and `sessionId` (host API 1.8) is what `agent.resume` takes. */
"agent.status.changed": { workspaceId: string | null; workspaceListId?: string; 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 }; sessionId?: string }
/** The focused workspace changed, or its terminals were opened, closed or renamed; `context` is what `workspace.readContext` now answers, its `workspaceId` included. Each new subscriber first gets the current context. */
"workspace.changed": { context: { workspaceId?: string; branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null }
/** What Orca's file editor uses changed (a setting or the editor zoom); the payload is what `editor.readTypography` now answers. Needs no capability. */
"editor.typography.changed": { fontFamily: string; cssFontFamily: string; fontSize: number; fontWeight: string; lineHeight: number; fontLigatures: boolean; wordWrap: "on" | "off"; minimap: boolean }
}
// </generated>
export type HostMethod = keyof HostMethods
export const host: {
call<K extends HostMethod>(
method: K,
...args: Record<string, never> extends HostMethods[K]['params']
? [params?: HostMethods[K]['params'], options?: HostCallOptions]
: [params: HostMethods[K]['params'], options?: HostCallOptions]
): Promise<HostMethods[K]['result']>
/** Whether this Orca offers `method` to this panel. */
has(method: string): boolean
}
/** The host API this Orca implements. */
export const api: { readonly major: number; readonly minor: number }
export const env: {
/** Orca's UI language (BCP-47). */
readonly locale: string
/** Reading it while rendering re-renders on light/dark switches. */
readonly theme: Theme
readonly client: 'desktop'
}
export const ui: {
/** Grows with the component catalog. */
readonly catalog: number
/** Whether this Orca draws `component` (and accepts `prop` on it, when given). */
has(component: string, prop?: string): boolean
}
}
declare module 'orca/jsx-runtime' {
import type { OrcaElement, OrcaNode } from 'orca'
export { Fragment } from 'orca'
export function jsx(type: unknown, props: object, key?: string | number): OrcaElement
export function jsxs(type: unknown, props: object, key?: string | number): OrcaElement
export namespace JSX {
type Element = OrcaElement
type ElementType = (props: never) => OrcaNode
type ElementChildrenAttribute = { children: unknown }
type IntrinsicAttributes = { key?: string | number }
// No lowercase tags: panels never render DOM.
type IntrinsicElements = {}
}
}
declare module 'orca/jsx-dev-runtime' {
import type { OrcaElement } from 'orca'
export { Fragment, JSX } from 'orca/jsx-runtime'
export function jsxDEV(type: unknown, props: object, key?: string | number): OrcaElement
}