/** * V2 (opencode2) TUI plugin API — 最小本地类型(实验版)。 * 运行时由 opencode2 提供,此处仅用于本地类型检查; * 结构对应 v2 分支 packages/plugin/src/tui/context.ts。 */ export interface App { readonly version: string; readonly channel: string; } export interface Theme { readonly hue: { /** V1 primary 的 V2 等价(v1-migrate.ts:interactive = hues.byToken.primary)。 * 取 300:更亮(暗背景下 400/500 偏深)。 */ readonly interactive: { readonly 300: string; }; /** 主题强调色别名。 */ readonly accent: { readonly 500: string; }; }; /** 文本色 token 存在两代命名:base/muted 与 default/subdued。宿主按其中一代提供, * 读取时以 base/muted 为准,故全部声明为可选。 */ readonly text: { readonly base?: string; readonly muted?: string; readonly default?: string; readonly subdued?: string; readonly feedback: { readonly success: { readonly base?: string; readonly default?: string; }; readonly error: { readonly base?: string; readonly default?: string; }; readonly warning: { readonly base?: string; readonly default?: string; }; }; }; } /** token 用量:结构与 V1 的 message.tokens 同构,字段以运行时实际数据为准。 */ export interface TokenUsage { input?: number; output?: number; reasoning?: number; cache?: { read?: number; write?: number; }; } export interface MessageInfo { readonly id: string; readonly type: string; readonly agent?: string; readonly model?: string; readonly time: { readonly created: number; readonly completed?: number; }; readonly cost?: unknown; readonly tokens?: TokenUsage; readonly content?: unknown[]; } export interface SessionInfo { readonly id: string; readonly title?: string; readonly time?: { readonly created: number; readonly updated: number; }; readonly model?: string; readonly agent?: string; readonly parentID?: string; } export interface Data { readonly session: { get(sessionID: string): SessionInfo | undefined; list(): SessionInfo[]; cost(sessionID: string): number; status(sessionID: string): string; readonly message: { list(sessionID: string): MessageInfo[]; sync(sessionID: string): Promise; }; }; readonly location: { readonly provider: { list(location?: unknown): unknown[]; }; readonly model: { list(location?: unknown): unknown[]; }; readonly mcp: { readonly server: { list(location?: unknown): unknown[]; }; }; }; readonly on: (type: string, handler: (event: unknown) => void) => () => void; readonly listen: (handler: (event: unknown) => void) => () => void; } export interface Storage { store(key: string, options: { readonly initial: Value; }): readonly [Value, (mutation: (draft: Value) => void) => Promise]; memory(key: string, options: { readonly initial: Value; }): readonly [Value, (mutation: (draft: Value) => void) => void]; } export type SlotClaim = { readonly render: (input: Record) => unknown; } & ({ readonly append: string; readonly prepend?: never; readonly before?: never; readonly after?: never; readonly replace?: never; } | { readonly prepend: string; readonly append?: never; readonly before?: never; readonly after?: never; readonly replace?: never; } | { readonly before: string; readonly append?: never; readonly prepend?: never; readonly after?: never; readonly replace?: never; } | { readonly after: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly replace?: never; } | { readonly replace: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly after?: never; }); export interface KeymapCommand { readonly id?: string; readonly title?: string; readonly description?: string; readonly group?: string; readonly palette?: true; readonly slash?: { readonly name: string; readonly aliases?: string[]; readonly arguments?: true; }; /** 旧字段(opencode-dcp 兼容写法:palette 可见性 + slash 补全依赖它们) */ readonly namespace?: string; readonly name?: string; readonly desc?: string; readonly category?: string; readonly slashName?: string; readonly slashAliases?: string[]; readonly run: (input?: string) => void | false | Promise; } export interface Context { readonly app: App; readonly options: Record; readonly location: { readonly directory?: string; } | undefined; readonly renderer: { readonly terminalWidth: number; }; readonly theme: Theme; readonly data: Data; readonly storage: Storage; readonly ui: { slot(claim: SlotClaim): () => void; readonly toast: { show(options: { readonly message: string; readonly title?: string; readonly variant?: string; }): void; }; readonly dialog: { prompt(options: { readonly title: string; readonly description?: string; readonly placeholder?: string; readonly value?: string; }): Promise; select(options: { readonly title: string; readonly placeholder?: string; readonly options: readonly { readonly title: string; readonly value: Value; readonly description?: string; readonly category?: string; readonly disabled?: boolean; }[]; readonly current?: Value; }): Promise; }; /** 当前路由:命令需要当前会话 ID(V2 Route = { type: "session", sessionID })。 */ readonly router: { current(): { readonly type?: string; readonly sessionID?: string; readonly params?: Record; }; }; }; readonly keymap: { layer(input: () => { readonly commands?: readonly KeymapCommand[]; }): void; shortcuts(id: string): readonly string[]; }; } export type PluginModule = { readonly id: string; readonly setup: (context: Context) => void | (() => void | Promise) | Promise void | Promise)>; };