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
100 lines
3.9 KiB
TypeScript
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
|
|
}
|
|
}
|