Files
orca/src/main/plugins/plugin-host-service-bindings.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

100 lines
3.9 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'
import {
describeAgentSessionPtyWriteRefusal,
isAgentSessionPtyWriteRefusedError
} from '../../shared/agent-session-pty-write-admission'
/** 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) => {
try {
const result = await delegate.sendTerminal(terminalId, action)
return { accepted: result.accepted }
} catch (error) {
// Why: the plugin API carries only `accepted`, so a lease refusal would read as a silent
// drop; restate it as the message idiom plugin methods already surface to callers.
if (isAgentSessionPtyWriteRefusedError(error)) {
throw new Error(describeAgentSessionPtyWriteRefusal(error.refusal))
}
throw error
}
},
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
}
}