Sign In

@opencode-ai/plugin

Package Overview
Dependencies
Maintainers
2
Versions
10978
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opencode-ai/plugin - npm Package Compare versions

Comparing version
0.0.0-beta-17823
to
0.0.0-beta-17887
+7
-17
package.json
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "0.0.0-beta-17823",
"version": "0.0.0-beta-17887",
"type": "module",

@@ -25,6 +25,2 @@ "license": "MIT",

},
"./v1": {
"import": "./dist/v1/index.js",
"types": "./dist/v1/index.d.ts"
},
"./*": {

@@ -40,7 +36,6 @@ "import": "./dist/*.js",

"@ai-sdk/provider": "3.0.8",
"@opencode-ai/ai": "0.0.0-beta-17823",
"@opencode-ai/client": "0.0.0-beta-17823",
"@opencode-ai/protocol": "0.0.0-beta-17823",
"@opencode-ai/schema": "0.0.0-beta-17823",
"@opencode-ai/sdk": "1.18.5",
"@opencode-ai/ai": "0.0.0-beta-17887",
"@opencode-ai/client": "0.0.0-beta-17887",
"@opencode-ai/protocol": "0.0.0-beta-17887",
"@opencode-ai/schema": "0.0.0-beta-17887",
"@standard-schema/spec": "1.1.0",

@@ -51,5 +46,4 @@ "effect": "4.0.0-rc.110",

"peerDependencies": {
"@opencode-ai/theme": "0.0.0-beta-17823",
"@opencode-ai/theme": "0.0.0-beta-17887",
"@opentui/core": ">=0.5.6",
"@opentui/keymap": ">=0.5.6",
"@opentui/solid": ">=0.5.6",

@@ -65,5 +59,2 @@ "solid-js": ">=1.9.0"

},
"@opentui/keymap": {
"optional": true
},
"@opentui/solid": {

@@ -77,5 +68,4 @@ "optional": true

"devDependencies": {
"@opencode-ai/theme": "0.0.0-beta-17823",
"@opencode-ai/theme": "0.0.0-beta-17887",
"@opentui/core": "0.5.6",
"@opentui/keymap": "0.5.6",
"@opentui/solid": "0.5.6",

@@ -82,0 +72,0 @@ "@tsconfig/bun": "1.0.9",

import type { Event, createOpencodeClient, Project, Model, Provider, Permission, UserMessage, Message, Part, Config as SDKConfig } from "@opencode-ai/sdk";
import type { Provider as ProviderV2, Model as ModelV2, Auth } from "@opencode-ai/sdk/v2";
import type { BunShell } from "./shell.js";
import { type ToolDefinition } from "./tool.js";
export * from "./tool.js";
export type ProviderContext = {
source: "env" | "config" | "custom" | "api";
info: Provider;
options: Record<string, any>;
};
export type WorkspaceInfo = {
id: string;
type: string;
name: string;
branch: string | null;
directory: string | null;
extra: unknown | null;
projectID: string;
};
export type WorkspaceTarget = {
type: "local";
directory: string;
} | {
type: "remote";
url: string | URL;
headers?: HeadersInit;
};
export type WorkspaceAdapter = {
name: string;
description: string;
configure(config: WorkspaceInfo): WorkspaceInfo | Promise<WorkspaceInfo>;
create(config: WorkspaceInfo, env: Record<string, string | undefined>, from?: WorkspaceInfo): Promise<void>;
remove(config: WorkspaceInfo): Promise<void>;
target(config: WorkspaceInfo): WorkspaceTarget | Promise<WorkspaceTarget>;
};
export type PluginInput = {
client: ReturnType<typeof createOpencodeClient>;
project: Project;
directory: string;
worktree: string;
experimental_workspace: {
register(type: string, adapter: WorkspaceAdapter): void;
};
serverUrl: URL;
$: BunShell;
};
export type PluginOptions = Record<string, unknown>;
export type Config = Omit<SDKConfig, "plugin"> & {
plugin?: Array<string | [string, PluginOptions]>;
};
export type Plugin = (input: PluginInput, options?: PluginOptions) => Promise<Hooks>;
export type PluginModule = {
id?: string;
server: Plugin;
tui?: never;
};
type Rule = {
key: string;
op: "eq" | "neq";
value: string;
};
export type AuthHook = {
provider: string;
loader?: (auth: () => Promise<Auth>, provider: Provider) => Promise<Record<string, any>>;
methods: ({
type: "oauth";
label: string;
prompts?: Array<{
type: "text";
key: string;
message: string;
placeholder?: string;
validate?: (value: string) => string | undefined;
/** @deprecated Use `when` instead */
condition?: (inputs: Record<string, string>) => boolean;
when?: Rule;
} | {
type: "select";
key: string;
message: string;
options: Array<{
label: string;
value: string;
hint?: string;
}>;
/** @deprecated Use `when` instead */
condition?: (inputs: Record<string, string>) => boolean;
when?: Rule;
}>;
authorize(inputs?: Record<string, string>): Promise<AuthOAuthResult>;
} | {
type: "api";
label: string;
prompts?: Array<{
type: "text";
key: string;
message: string;
placeholder?: string;
validate?: (value: string) => string | undefined;
/** @deprecated Use `when` instead */
condition?: (inputs: Record<string, string>) => boolean;
when?: Rule;
} | {
type: "select";
key: string;
message: string;
options: Array<{
label: string;
value: string;
hint?: string;
}>;
/** @deprecated Use `when` instead */
condition?: (inputs: Record<string, string>) => boolean;
when?: Rule;
}>;
authorize?(inputs?: Record<string, string>): Promise<{
type: "success";
key: string;
provider?: string;
metadata?: Record<string, string>;
} | {
type: "failed";
}>;
})[];
};
export type AuthOAuthResult = {
url: string;
instructions: string;
} & ({
method: "auto";
callback(): Promise<({
type: "success";
provider?: string;
} & ({
refresh: string;
access: string;
expires: number;
accountId?: string;
enterpriseUrl?: string;
} | {
key: string;
metadata?: Record<string, string>;
})) | {
type: "failed";
}>;
} | {
method: "code";
callback(code: string): Promise<({
type: "success";
provider?: string;
} & ({
refresh: string;
access: string;
expires: number;
accountId?: string;
enterpriseUrl?: string;
} | {
key: string;
metadata?: Record<string, string>;
})) | {
type: "failed";
}>;
});
export type ProviderHookContext = {
auth?: Auth;
};
export type ProviderHook = {
id: string;
models?: (provider: ProviderV2, ctx: ProviderHookContext) => Promise<Record<string, ModelV2>>;
};
/** @deprecated Use AuthOAuthResult instead. */
export type AuthOuathResult = AuthOAuthResult;
export interface Hooks {
dispose?: () => Promise<void>;
event?: (input: {
event: Event;
}) => Promise<void>;
config?: (input: Config) => Promise<void>;
tool?: {
[key: string]: ToolDefinition;
};
auth?: AuthHook;
provider?: ProviderHook;
/**
* Called when a new message is received
*/
"chat.message"?: (input: {
sessionID: string;
agent?: string;
model?: {
providerID: string;
modelID: string;
};
messageID?: string;
variant?: string;
}, output: {
message: UserMessage;
parts: Part[];
}) => Promise<void>;
/**
* Modify parameters sent to LLM
*/
"chat.params"?: (input: {
sessionID: string;
agent: string;
model: Model;
provider: ProviderContext;
message: UserMessage;
}, output: {
temperature: number;
topP: number;
topK: number;
maxOutputTokens: number | undefined;
options: Record<string, any>;
}) => Promise<void>;
"chat.headers"?: (input: {
sessionID: string;
agent: string;
model: Model;
provider: ProviderContext;
message: UserMessage;
}, output: {
headers: Record<string, string>;
}) => Promise<void>;
"permission.ask"?: (input: Permission, output: {
status: "ask" | "deny" | "allow";
}) => Promise<void>;
"command.execute.before"?: (input: {
command: string;
sessionID: string;
arguments: string;
}, output: {
parts: Part[];
}) => Promise<void>;
"tool.execute.before"?: (input: {
tool: string;
sessionID: string;
callID: string;
}, output: {
args: any;
}) => Promise<void>;
"shell.env"?: (input: {
cwd: string;
sessionID?: string;
callID?: string;
}, output: {
env: Record<string, string>;
}) => Promise<void>;
"tool.execute.after"?: (input: {
tool: string;
sessionID: string;
callID: string;
args: any;
}, output: {
title: string;
output: string;
metadata: any;
}) => Promise<void>;
"experimental.chat.messages.transform"?: (input: {}, output: {
messages: {
info: Message;
parts: Part[];
}[];
}) => Promise<void>;
"experimental.chat.system.transform"?: (input: {
sessionID?: string;
model: Model;
}, output: {
system: string[];
}) => Promise<void>;
"experimental.provider.small_model"?: (input: {
provider: ProviderV2;
}, output: {
model?: ModelV2;
}) => Promise<void>;
/**
* Called before session compaction starts. Allows plugins to customize
* the compaction prompt.
*
* - `context`: Additional context strings appended to the default prompt
* - `prompt`: If set, replaces the default compaction prompt entirely
*/
"experimental.session.compacting"?: (input: {
sessionID: string;
}, output: {
context: string[];
prompt?: string;
}) => Promise<void>;
/**
* Called after compaction succeeds and before a synthetic user
* auto-continue message is added.
*
* - `enabled`: Defaults to `true`. Set to `false` to skip the synthetic
* user "continue" turn.
*/
"experimental.compaction.autocontinue"?: (input: {
sessionID: string;
agent: string;
model: Model;
provider: ProviderContext;
message: UserMessage;
overflow: boolean;
}, output: {
enabled: boolean;
}) => Promise<void>;
"experimental.text.complete"?: (input: {
sessionID: string;
messageID: string;
partID: string;
}, output: {
text: string;
}) => Promise<void>;
/**
* Modify tool definitions (description and parameters) sent to LLM
*/
"tool.definition"?: (input: {
toolID: string;
}, output: {
description: string;
parameters: any;
}) => Promise<void>;
}
import {} from "./tool.js";
export * from "./tool.js";
export type ShellFunction = (input: Uint8Array) => Uint8Array;
export type ShellExpression = {
toString(): string;
} | Array<ShellExpression> | string | {
raw: string;
} | ReadableStream;
export interface BunShell {
(strings: TemplateStringsArray, ...expressions: ShellExpression[]): BunShellPromise;
/**
* Perform bash-like brace expansion on the given pattern.
* @param pattern - Brace pattern to expand
*/
braces(pattern: string): string[];
/**
* Escape strings for input into shell commands.
*/
escape(input: string): string;
/**
* Change the default environment variables for shells created by this instance.
*/
env(newEnv?: Record<string, string | undefined>): BunShell;
/**
* Default working directory to use for shells created by this instance.
*/
cwd(newCwd?: string): BunShell;
/**
* Configure the shell to not throw an exception on non-zero exit codes.
*/
nothrow(): BunShell;
/**
* Configure whether or not the shell should throw an exception on non-zero exit codes.
*/
throws(shouldThrow: boolean): BunShell;
}
export interface BunShellPromise extends Promise<BunShellOutput> {
readonly stdin: WritableStream;
/**
* Change the current working directory of the shell.
*/
cwd(newCwd: string): this;
/**
* Set environment variables for the shell.
*/
env(newEnv: Record<string, string> | undefined): this;
/**
* By default, the shell will write to the current process's stdout and stderr, as well as buffering that output.
* This configures the shell to only buffer the output.
*/
quiet(): this;
/**
* Read from stdout as a string, line by line
* Automatically calls quiet() to disable echoing to stdout.
*/
lines(): AsyncIterable<string>;
/**
* Read from stdout as a string.
* Automatically calls quiet() to disable echoing to stdout.
*/
text(encoding?: BufferEncoding): Promise<string>;
/**
* Read from stdout as a JSON object
* Automatically calls quiet()
*/
json(): Promise<any>;
/**
* Read from stdout as an ArrayBuffer
* Automatically calls quiet()
*/
arrayBuffer(): Promise<ArrayBuffer>;
/**
* Read from stdout as a Blob
* Automatically calls quiet()
*/
blob(): Promise<Blob>;
/**
* Configure the shell to not throw an exception on non-zero exit codes.
*/
nothrow(): this;
/**
* Configure whether or not the shell should throw an exception on non-zero exit codes.
*/
throws(shouldThrow: boolean): this;
}
export interface BunShellOutput {
readonly stdout: Buffer;
readonly stderr: Buffer;
readonly exitCode: number;
/**
* Read from stdout as a string
*/
text(encoding?: BufferEncoding): string;
/**
* Read from stdout as a JSON object
*/
json(): any;
/**
* Read from stdout as an ArrayBuffer
*/
arrayBuffer(): ArrayBuffer;
/**
* Read from stdout as an Uint8Array
*/
bytes(): Uint8Array;
/**
* Read from stdout as a Blob
*/
blob(): Blob;
}
export type BunShellError = Error & BunShellOutput;
import { z } from "zod";
export type ToolContext = {
sessionID: string;
messageID: string;
agent: string;
/**
* Current project directory for this session.
* Prefer this over process.cwd() when resolving relative paths.
*/
directory: string;
/**
* Project worktree root for this session.
* Useful for generating stable relative paths (e.g. path.relative(worktree, absPath)).
*/
worktree: string;
abort: AbortSignal;
metadata(input: {
title?: string;
metadata?: {
[key: string]: any;
};
}): void;
ask(input: AskInput): Promise<void>;
};
type AskInput = {
permission: string;
patterns: string[];
always: string[];
metadata: {
[key: string]: any;
};
};
export type ToolAttachment = {
type: "file";
mime: string;
url: string;
filename?: string;
};
export type ToolResult = string | {
title?: string;
output: string;
metadata?: {
[key: string]: any;
};
attachments?: ToolAttachment[];
};
export declare function tool<Args extends z.ZodRawShape>(input: {
description: string;
args: Args;
execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<ToolResult>;
}): {
description: string;
args: Args;
execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<ToolResult>;
};
export declare namespace tool {
var schema: typeof z;
}
export type ToolDefinition = ReturnType<typeof tool>;
export {};
import { z } from "zod";
export function tool(input) {
return input;
}
tool.schema = z;
import type { OpencodeClient, LspStatus, McpStatus, Message, Part, Provider, PermissionRequest, QuestionRequest, Session, SessionStatus, Config as SdkConfig } from "@opencode-ai/sdk/v2";
import type { OpenCodeEvent } from "@opencode-ai/client/promise";
import type { PromptInput } from "@opencode-ai/schema";
import type { Types } from "effect";
import type { CliRenderer, KeyEvent, RGBA, Renderable, SlotMode } from "@opentui/core";
import type { Binding, Keymap } from "@opentui/keymap";
import { type BindingConfig, type CreateBindingLookupOptions, type KeySequenceFormatPart, type SequenceBindingLike } from "@opentui/keymap/extras";
import type { JSX, SolidPlugin } from "@opentui/solid";
import type { Config as PluginConfig, PluginOptions } from "./index.js";
export type { CliRenderer, KeyEvent, Renderable, SlotMode } from "@opentui/core";
export { stringifyKeySequence, stringifyKeyStroke } from "@opentui/keymap";
export type { Binding, KeyLike, KeySequencePart, KeyStringifyInput, StringifyOptions } from "@opentui/keymap";
export { formatCommandBindings, formatKeySequence } from "@opentui/keymap/extras";
export type { BindingConfig, BindingLookup, BindingValue, CreateBindingLookupOptions, FormatCommandBindingsOptions, FormatKeySequenceOptions, KeySequenceFormatPart, SequenceBindingLike, } from "@opentui/keymap/extras";
export declare function createBindingLookup(config: BindingConfig<Renderable, KeyEvent> | undefined, options?: CreateBindingLookupOptions<Renderable, KeyEvent>): import("@opentui/keymap/extras").BindingLookup<Renderable, KeyEvent>;
export type TuiRouteCurrent = {
name: "home";
} | {
name: "session";
params: {
sessionID: string;
prompt?: unknown;
};
} | {
name: string;
params?: Record<string, unknown>;
};
export type TuiRouteDefinition = {
name: string;
render: (input: {
params?: Record<string, unknown>;
}) => JSX.Element;
};
export type TuiKeys = {
formatSequence: (parts: readonly KeySequenceFormatPart[] | undefined) => string;
formatBindings: (bindings: readonly SequenceBindingLike[] | undefined) => string | undefined;
};
export type TuiKeymap = Keymap<Renderable, KeyEvent>;
export type TuiModeApi = {
current: () => string;
push: (mode: string) => () => void;
};
/**
* Legacy `api.command` shape kept so v1 plugins can initialize. Remove in v2.
*
* @deprecated Use `api.keymap.registerLayer({ commands, bindings })` instead.
*/
export type TuiCommand = {
title: string;
value: string;
description?: string;
category?: string;
keybind?: string;
suggested?: boolean;
hidden?: boolean;
enabled?: boolean;
slash?: {
name: string;
aliases?: string[];
};
onSelect?: (dialog?: TuiDialogStack) => void | Promise<void>;
};
/**
* Legacy `api.command` API kept so v1 plugins can initialize. Remove in v2.
*
* @deprecated Use `api.keymap.registerLayer`, `api.keymap.dispatchCommand`, and
* `api.keymap.dispatchCommand("command.palette.show")` instead.
*/
export type TuiCommandApi = {
/** @deprecated Use `api.keymap.registerLayer({ commands, bindings })` instead. */
register: (cb: () => TuiCommand[]) => () => void;
/** @deprecated Use `api.keymap.dispatchCommand(name)` instead. */
trigger: (value: string) => void;
/** @deprecated Use `api.keymap.dispatchCommand("command.palette.show")` instead. */
show: () => void;
};
export type TuiDialogProps = {
size?: "medium" | "large" | "xlarge";
onClose: () => void;
children?: JSX.Element;
};
export type TuiDialogStack = {
replace: (render: () => JSX.Element, onClose?: () => void) => void;
clear: () => void;
setSize: (size: "medium" | "large" | "xlarge") => void;
readonly size: "medium" | "large" | "xlarge";
readonly depth: number;
readonly open: boolean;
};
export type TuiDialogAlertProps = {
title: string;
message: string;
onConfirm?: () => void;
};
export type TuiDialogConfirmProps = {
title: string;
message: string;
onConfirm?: () => void;
onCancel?: () => void;
};
export type TuiDialogPromptProps = {
title: string;
description?: () => JSX.Element;
placeholder?: string;
value?: string;
busy?: boolean;
busyText?: string;
onConfirm?: (value: string) => void;
onCancel?: () => void;
};
export type TuiDialogSelectOption<Value = unknown> = {
title: string;
value: Value;
description?: string;
footer?: JSX.Element | string;
category?: string;
disabled?: boolean;
onSelect?: () => void;
};
export type TuiDialogSelectProps<Value = unknown> = {
title: string;
placeholder?: string;
options: TuiDialogSelectOption<Value>[];
flat?: boolean;
onMove?: (option: TuiDialogSelectOption<Value>) => void;
onFilter?: (query: string) => void;
onSelect?: (option: TuiDialogSelectOption<Value>) => void;
skipFilter?: boolean;
current?: Value;
};
export type TuiPromptInfo = Types.DeepMutable<PromptInput.Prompt> & {
pasted: {
text: string;
source: {
start: number;
end: number;
text: string;
};
}[];
mode?: "normal" | "shell";
};
export type TuiPromptRef = {
focused: boolean;
current: TuiPromptInfo;
set(prompt: TuiPromptInfo): void;
reset(): void;
blur(): void;
focus(): void;
submit(): void;
};
export type TuiPromptProps = {
sessionID?: string;
visible?: boolean;
disabled?: boolean;
onSubmit?: () => void;
ref?: (ref: TuiPromptRef | undefined) => void;
hint?: JSX.Element;
right?: JSX.Element;
showPlaceholder?: boolean;
placeholders?: {
normal?: string[];
shell?: string[];
};
};
export type TuiToast = {
variant?: "info" | "success" | "warning" | "error";
title?: string;
message: string;
duration?: number;
};
export type TuiAttentionWhen = "always" | "focused" | "blurred";
export declare const TuiAttentionSoundNames: readonly ["default", "question", "permission", "error", "done", "subagent_done"];
export type TuiAttentionSoundName = (typeof TuiAttentionSoundNames)[number];
export type TuiAttentionSound = boolean | {
name?: TuiAttentionSoundName;
volume?: number;
when?: TuiAttentionWhen;
};
export type TuiAttentionNotification = boolean | {
when?: TuiAttentionWhen;
};
export type TuiAttentionSoundPack = {
id: string;
name?: string;
sounds: Partial<Record<TuiAttentionSoundName, string>>;
};
export type TuiAttentionSoundPackInfo = {
id: string;
name?: string;
active: boolean;
builtin: boolean;
};
export type TuiAttentionSoundboardActivateOptions = {
persist?: boolean;
};
export type TuiAttentionSoundboard = {
registerPack(pack: TuiAttentionSoundPack): () => void;
activate(id: string, options?: TuiAttentionSoundboardActivateOptions): boolean;
current(): string;
list(): ReadonlyArray<TuiAttentionSoundPackInfo>;
};
export type TuiAttentionNotifyInput = {
title?: string;
message: string;
notification?: TuiAttentionNotification;
sound?: TuiAttentionSound;
};
export type TuiAttentionNotifySkipReason = "attention_disabled" | "empty_message" | "blurred" | "focused" | "focus_unknown" | "renderer_destroyed";
export type TuiAttentionNotifyResult = {
ok: boolean;
notification: boolean;
sound: boolean;
skipped?: TuiAttentionNotifySkipReason;
};
export type TuiAttention = {
notify(input: TuiAttentionNotifyInput): Promise<TuiAttentionNotifyResult>;
soundboard: TuiAttentionSoundboard;
};
export type TuiThemeCurrent = {
readonly primary: RGBA;
readonly secondary: RGBA;
readonly accent: RGBA;
readonly error: RGBA;
readonly warning: RGBA;
readonly success: RGBA;
readonly info: RGBA;
readonly text: RGBA;
readonly textMuted: RGBA;
readonly selectedListItemText: RGBA;
readonly background: RGBA;
readonly backgroundPanel: RGBA;
readonly backgroundElement: RGBA;
readonly backgroundMenu: RGBA;
readonly border: RGBA;
readonly borderActive: RGBA;
readonly borderSubtle: RGBA;
readonly diffAdded: RGBA;
readonly diffRemoved: RGBA;
readonly diffContext: RGBA;
readonly diffHunkHeader: RGBA;
readonly diffHighlightAdded: RGBA;
readonly diffHighlightRemoved: RGBA;
readonly diffAddedBg: RGBA;
readonly diffRemovedBg: RGBA;
readonly diffContextBg: RGBA;
readonly diffLineNumber: RGBA;
readonly diffAddedLineNumberBg: RGBA;
readonly diffRemovedLineNumberBg: RGBA;
readonly markdownText: RGBA;
readonly markdownHeading: RGBA;
readonly markdownLink: RGBA;
readonly markdownLinkText: RGBA;
readonly markdownCode: RGBA;
readonly markdownBlockQuote: RGBA;
readonly markdownEmph: RGBA;
readonly markdownStrong: RGBA;
readonly markdownHorizontalRule: RGBA;
readonly markdownListItem: RGBA;
readonly markdownListEnumeration: RGBA;
readonly markdownImage: RGBA;
readonly markdownImageText: RGBA;
readonly markdownCodeBlock: RGBA;
readonly syntaxComment: RGBA;
readonly syntaxKeyword: RGBA;
readonly syntaxFunction: RGBA;
readonly syntaxVariable: RGBA;
readonly syntaxString: RGBA;
readonly syntaxNumber: RGBA;
readonly syntaxType: RGBA;
readonly syntaxOperator: RGBA;
readonly syntaxPunctuation: RGBA;
readonly thinkingOpacity: number;
};
export type TuiTheme = {
readonly current: TuiThemeCurrent;
readonly selected: string;
has: (name: string) => boolean;
set: (name: string) => boolean;
install: (jsonPath: string) => Promise<void>;
mode: () => "dark" | "light";
readonly ready: boolean;
};
/** @deprecated Persistent TUI KV storage is not supported in V2. */
export type TuiKV = {
get: <Value = unknown>(key: string, fallback?: Value) => Value;
set: (key: string, value: unknown) => void;
readonly ready: boolean;
};
export type TuiState = {
readonly ready: boolean;
readonly config: SdkConfig;
readonly provider: ReadonlyArray<Provider>;
readonly path: {
state: string;
config: string;
worktree: string;
directory: string;
};
readonly vcs: {
branch?: string;
default_branch?: string;
} | undefined;
session: {
count: () => number;
get: (sessionID: string) => Session | undefined;
diff: (sessionID: string) => ReadonlyArray<TuiSidebarFileItem>;
messages: (sessionID: string) => ReadonlyArray<Message>;
status: (sessionID: string) => SessionStatus | undefined;
permission: (sessionID: string) => ReadonlyArray<PermissionRequest>;
question: (sessionID: string) => ReadonlyArray<QuestionRequest>;
};
part: (messageID: string) => ReadonlyArray<Part>;
lsp: () => ReadonlyArray<TuiSidebarLspItem>;
mcp: () => ReadonlyArray<TuiSidebarMcpItem>;
};
type TuiBindingLookupView = {
readonly bindings: ReadonlyArray<Binding<Renderable, KeyEvent>>;
get: (command: string) => ReadonlyArray<Binding<Renderable, KeyEvent>>;
has: (command: string) => boolean;
gather: (name: string, commands: readonly string[]) => ReadonlyArray<Binding<Renderable, KeyEvent>>;
pick: (name: string, commands: readonly string[]) => Binding<Renderable, KeyEvent>[];
omit: (name: string, commands: readonly string[]) => Binding<Renderable, KeyEvent>[];
};
type TuiAttentionConfigView = {
enabled: boolean;
notifications: boolean;
sound: boolean;
volume: number;
sound_pack: string;
sounds: Partial<Record<TuiAttentionSoundName, string>>;
};
type TuiConfigView = {
$schema?: string;
theme?: string | {
name?: string;
mode?: "system" | "dark" | "light";
};
plugin?: PluginConfig["plugin"];
plugins?: ReadonlyArray<string | {
package: string;
options?: Record<string, any>;
}>;
plugin_enabled?: Record<string, boolean>;
leader?: {
timeout: number;
};
leader_timeout?: number;
scroll?: {
speed?: number;
acceleration?: boolean;
};
scroll_speed?: number;
scroll_acceleration?: {
enabled: boolean;
};
attention: TuiAttentionConfigView;
diffs?: {
wrap?: "word" | "none";
tree?: boolean;
single?: boolean;
view?: "auto" | "split" | "unified";
};
diff_style?: "auto" | "stacked";
terminal?: {
title?: boolean;
};
prompt?: {
editor?: boolean;
paste?: "compact" | "full";
} | {
max_height?: number;
max_width?: number | "auto";
};
session?: {
sidebar?: "auto" | "hide";
scrollbar?: boolean;
thinking?: "show" | "hide";
markdown?: "source" | "rendered";
grouping?: "auto" | "none";
};
hints?: {
onboarding?: boolean;
};
animations?: boolean;
mouse: boolean;
keybinds: TuiBindingLookupView;
};
export type TuiApp = {
readonly version: string;
};
type Frozen<Value> = Value extends (...args: never[]) => unknown ? Value : Value extends ReadonlyArray<infer Item> ? ReadonlyArray<Frozen<Item>> : Value extends object ? {
readonly [Key in keyof Value]: Frozen<Value[Key]>;
} : Value;
export type TuiSidebarMcpItem = {
name: string;
status: McpStatus["status"];
error?: string;
};
export type TuiSidebarLspItem = Pick<LspStatus, "id" | "root" | "status">;
export type TuiSidebarFileItem = {
file: string;
additions: number;
deletions: number;
};
export type TuiHostSlotMap = {
app: {};
app_bottom: {};
home_logo: {};
home_prompt: {
ref?: (ref: TuiPromptRef | undefined) => void;
};
home_prompt_right: {};
session_prompt: {
session_id: string;
visible?: boolean;
disabled?: boolean;
on_submit?: () => void;
ref?: (ref: TuiPromptRef | undefined) => void;
};
session_prompt_right: {
session_id: string;
};
home_bottom: {};
home_footer: {};
sidebar_title: {
session_id: string;
title: string;
share_url?: string;
};
sidebar_content: {
session_id: string;
};
sidebar_footer: {
session_id: string;
directory: string;
};
};
export type TuiSlotMap<Slots extends Record<string, object> = {}> = TuiHostSlotMap & Slots;
type TuiSlotShape<Name extends string, Slots extends Record<string, object>> = Name extends keyof TuiHostSlotMap ? TuiHostSlotMap[Name] : Name extends keyof Slots ? Slots[Name] : Record<string, unknown>;
export type TuiSlotProps<Name extends string = string, Slots extends Record<string, object> = {}> = {
name: Name;
mode?: SlotMode;
children?: JSX.Element;
} & TuiSlotShape<Name, Slots>;
export type TuiSlotContext = {
theme: TuiTheme;
};
type SlotCore<Slots extends Record<string, object> = {}> = SolidPlugin<TuiSlotMap<Slots>, TuiSlotContext>;
export type TuiSlotPlugin<Slots extends Record<string, object> = {}> = Omit<SlotCore<Slots>, "id"> & {
id?: never;
};
export type TuiSlots = {
register: {
(plugin: TuiSlotPlugin): string;
<Slots extends Record<string, object>>(plugin: TuiSlotPlugin<Slots>): string;
};
};
export type TuiEventBus = {
on: <Type extends OpenCodeEvent["type"]>(type: Type, handler: (event: Extract<OpenCodeEvent, {
type: Type;
}>) => void) => () => void;
};
export type TuiDispose = () => void | Promise<void>;
export type TuiLifecycle = {
readonly signal: AbortSignal;
onDispose: (fn: TuiDispose) => () => void;
};
export type TuiPluginState = "first" | "updated" | "same";
export type TuiPluginEntry = {
id: string;
source: "file" | "npm" | "internal";
spec: string;
target: string;
requested?: string;
version?: string;
modified?: number;
first_time: number;
last_time: number;
time_changed: number;
load_count: number;
fingerprint: string;
};
export type TuiPluginMeta = TuiPluginEntry & {
state: TuiPluginState;
};
export type TuiPluginStatus = {
id: string;
source: TuiPluginEntry["source"];
spec: string;
target: string;
enabled: boolean;
active: boolean;
};
export type TuiPluginInstallOptions = {
global?: boolean;
};
export type TuiPluginInstallResult = {
ok: true;
dir: string;
tui: boolean;
} | {
ok: false;
message: string;
missing?: boolean;
};
export type TuiWorkspace = {
current: () => string | undefined;
set: (workspaceID?: string) => void;
};
export type TuiPluginApi = {
app: TuiApp;
attention: TuiAttention;
/**
* Legacy `api.command` API kept so v1 plugins can initialize. Remove in v2.
*
* @deprecated Use `api.keymap.registerLayer`, `api.keymap.dispatchCommand`, and
* `api.keymap.dispatchCommand("command.palette.show")` instead.
*/
command?: TuiCommandApi;
keys: TuiKeys;
keymap: TuiKeymap;
mode: TuiModeApi;
route: {
register: (routes: TuiRouteDefinition[]) => () => void;
navigate: (name: string, params?: Record<string, unknown>) => void;
readonly current: TuiRouteCurrent;
};
ui: {
Dialog: (props: TuiDialogProps) => JSX.Element;
DialogAlert: (props: TuiDialogAlertProps) => JSX.Element;
DialogConfirm: (props: TuiDialogConfirmProps) => JSX.Element;
DialogPrompt: (props: TuiDialogPromptProps) => JSX.Element;
DialogSelect: <Value = unknown>(props: TuiDialogSelectProps<Value>) => JSX.Element;
Slot: <Name extends string>(props: TuiSlotProps<Name>) => JSX.Element | null;
Prompt: (props: TuiPromptProps) => JSX.Element;
toast: (input: TuiToast) => void;
dialog: TuiDialogStack;
};
readonly tuiConfig: Frozen<TuiConfigView>;
/** @deprecated Persistent TUI KV storage is not supported in V2. */
kv: TuiKV;
state: TuiState;
theme: TuiTheme;
client: OpencodeClient;
event: TuiEventBus;
renderer: CliRenderer;
slots: TuiSlots;
plugins: {
list: () => ReadonlyArray<TuiPluginStatus>;
activate: (id: string) => Promise<boolean>;
deactivate: (id: string) => Promise<boolean>;
add: (spec: string) => Promise<boolean>;
install: (spec: string, options?: TuiPluginInstallOptions) => Promise<TuiPluginInstallResult>;
};
lifecycle: TuiLifecycle;
};
export type TuiPlugin = (api: TuiPluginApi, options: PluginOptions | undefined, meta: TuiPluginMeta) => Promise<void>;
export type TuiPluginModule = {
id?: string;
tui: TuiPlugin;
server?: never;
};
import { createBindingLookup as createKeymapBindingLookup, } from "@opentui/keymap/extras";
export { stringifyKeySequence, stringifyKeyStroke } from "@opentui/keymap";
export { formatCommandBindings, formatKeySequence } from "@opentui/keymap/extras";
export function createBindingLookup(config, options) {
return createKeymapBindingLookup(config ?? {}, options);
}
export const TuiAttentionSoundNames = ["default", "question", "permission", "error", "done", "subagent_done"];