Files
orca/src/main/plugins/plugin-host-service-bindings.ts
T
Brennan Benson 39c3c58d55 perf(runtime): gate terminal.list visual layouts (#12450)
* perf(runtime): gate terminal.list visual layouts and stop the false writable claim

visualLayouts is ~31% of a large terminal.list payload (44,208 B of 137,412 B on a live 134-terminal remote runtime) and has exactly one consumer: the human-readable CLI formatter. Gate it behind an includeVisualLayouts request param that defaults to included, so pre-flag clients are unaffected, and have every --json/internal caller opt out.

Also drop the record-backed builder's writable, which was a verbatim copy of connected. terminal.show now states writability explicitly as exactly what terminal.send's PTY gate enforces.

* test(runtime): type the payload-size fixture arrays for tsc

* fix(runtime): preserve terminal list compatibility

* test(runtime): guard terminal list optimization

* fix(cli): preserve agent access to terminal layouts
2026-08-04 17:50:52 -07:00

87 lines
3.3 KiB
TypeScript

import type { PluginEventName } from '../../shared/plugins/plugin-manifest'
import { PLUGIN_WORKSPACE_TERMINAL_LIMIT } from '../../shared/plugins/plugin-host-api'
import type { PluginHostServices } from './plugin-host-methods'
import { PluginSecretsStore } from './plugin-secrets-store'
import { PluginKvStore } from './plugin-storage-store'
/** Structural subset of OrcaRuntimeService exposed to plugin facade bindings. */
export type PluginRuntimeDelegate = {
resolveActiveWorktreeContext(): Promise<{
worktreeId: string
path: string
branch: string
displayName: string
} | null>
listTerminals(
worktreeSelector?: string,
limit?: number,
opts?: { includeVisualLayouts?: boolean }
): Promise<{ terminals: { handle: string; title: string | null }[] }>
sendTerminal(
handle: string,
action: { text?: string; enter?: boolean }
): Promise<{ accepted: boolean }>
dispatchPluginNotification(input: {
pluginId: string
title: string
body?: string
}): Promise<{ delivered: boolean }>
}
export function bindPluginHostServices(input: {
delegate: PluginRuntimeDelegate
pluginsDataDir: string
subscribeEvents: (pluginKey: string, events: PluginEventName[]) => PluginEventName[]
}): PluginHostServices {
const { delegate, pluginsDataDir, subscribeEvents } = input
return {
resolveActiveWorktreeContext: async () => {
const context = await delegate.resolveActiveWorktreeContext()
if (!context) {
return null
}
// Why: retain the internal id only for host-side terminal membership;
// the public handler projects it out because it embeds provider paths.
return {
worktreeId: context.worktreeId,
branch: context.branch,
displayName: context.displayName
}
},
listWorktreeTerminals: async (worktreeId) => {
const result = await delegate.listTerminals(
`id:${worktreeId}`,
PLUGIN_WORKSPACE_TERMINAL_LIMIT,
{ includeVisualLayouts: false }
)
return result.terminals
.slice(0, PLUGIN_WORKSPACE_TERMINAL_LIMIT)
.map((terminal) => ({ id: terminal.handle }))
},
sendTerminalText: async (terminalId, action) => {
const result = await delegate.sendTerminal(terminalId, action)
return { accepted: result.accepted }
},
dispatchPluginNotification: (notification) => delegate.dispatchPluginNotification(notification),
storage: {
get: (key, itemKey) => new PluginKvStore(pluginsDataDir, key, 'storage.json').get(itemKey),
set: (key, itemKey, value) =>
new PluginKvStore(pluginsDataDir, key, 'storage.json').set(itemKey, value),
delete: (key, itemKey) =>
new PluginKvStore(pluginsDataDir, key, 'storage.json').delete(itemKey),
keys: (key) => new PluginKvStore(pluginsDataDir, key, 'storage.json').keys()
},
secrets: {
get: (key, itemKey) => new PluginSecretsStore(pluginsDataDir, key).get(itemKey),
set: (key, itemKey, value) => new PluginSecretsStore(pluginsDataDir, key).set(itemKey, value),
delete: (key, itemKey) => new PluginSecretsStore(pluginsDataDir, key).delete(itemKey)
},
settings: {
getAll: (key) => new PluginKvStore(pluginsDataDir, key, 'settings.json').getAll(),
set: (key, itemKey, value) =>
new PluginKvStore(pluginsDataDir, key, 'settings.json').set(itemKey, value)
},
subscribeEvents
}
}