import type { TSchema } from "@sinclair/typebox"; export interface ToolResultText { type: "text"; text: string } export interface ToolResultImage { type: "image"; data: string; mimeType: string } export interface ToolResultResource { type: "resource"; uri: string; title?: string } export type ToolResultContent = ToolResultText | ToolResultImage | ToolResultResource; export interface ToolResult { content: ToolResultContent[]; details?: Record; isError?: boolean; } export interface ToolExecuteOptions { signal: AbortSignal; update: (partial: Partial) => void; ctx: ExtensionContext; } export type ToolUpdate = (partial: Partial) => void; export interface ToolDefinition { name: string; description?: string; parameters: TSchema; execute: (toolCallId: string, params: unknown, signal: AbortSignal, update: ToolUpdate, ctx: ExtensionContext) => Promise | ToolResult; } export interface CommandOptions { description?: string; args?: unknown[]; handler: (args: CommandArgs, ctx: ExtensionContext) => Promise | void; } export type CommandArgs = string | { text?: string; args: Record; }; export type LifecycleEvent = | "session_start" | "session_end" | "resources_discover" | "input" | "before_agent_start" | "context" | "tool_call" | "tool_execution_start" | "tool_result" | "turn_start" | "turn_end" | "agent_start" | "agent_end" | "stop"; export interface EventPayload { type: LifecycleEvent; sessionId?: string; toolName?: string; input?: unknown; toolArgs?: unknown; messages?: Array<{ role: string; content: string; hidden?: boolean }>; reason?: string; [key: string]: unknown; } export interface EventResult { block?: boolean; reason?: string; modify?: Partial; injectContext?: Array<{ role: string; content: string; hidden?: boolean }>; } export type EventHandler = (event: EventPayload, ctx: ExtensionContext) => Promise | EventResult | void; export interface SelectOption { label: string; value: string } export interface SelectResult { value: string; label?: string; cancelled?: boolean } export interface InputResult { value: string; cancelled?: boolean } export interface EditorResult { value: string; cancelled?: boolean } export type ThinkingLevel = "off" | "low" | "medium" | "high" | "xhigh"; export interface ModelLike { provider: string; id: string; name?: string; thinking?: boolean | string[]; [key: string]: unknown; } export interface ProviderConfigLike { api?: string; baseUrl?: string; apiKey?: string; headers?: Record; authHeader?: string | boolean; models?: ModelLike[]; oauth?: unknown; [key: string]: unknown; } export interface ModelRegistryLike { getAll?(): ModelLike[] | Promise; getAvailable?(): ModelLike[] | Promise; find?(provider: string, id: string): ModelLike | undefined | Promise; registerProvider?(name: string, config: ProviderConfigLike): void | Promise; unregisterProvider?(name: string): void | Promise; } export interface ExtensionContext { cwd?: string; model?: ModelLike; modelRegistry?: ModelRegistryLike; setModel?(model: ModelLike): boolean | Promise; setThinkingLevel?(level: ThinkingLevel): void; ui: { select(title: string, options: SelectOption[]): Promise; input(title: string, opts?: { default?: string; placeholder?: string }): Promise; editor(title: string, content: string, opts?: { language?: string }): Promise; confirm(title: string, message: string): Promise; notify(message: string, level?: "info" | "warn" | "error"): void; setStatus(key: string, text: string): void; setWidget(key: string, content: string[] | WidgetFactory | undefined, options?: { placement?: "aboveEditor" | "belowEditor" }): void; setTitle(title: string): void; setWorkingIndicator(active: boolean): void; }; session?: { id: string; projectRoot: string; workingDirectory: string; }; settings: { get(key: string): unknown; set(key: string, value: unknown): Promise; }; } export type WidgetFactory = (...args: unknown[]) => unknown; export interface CustomEntry { type: string; data: unknown; timestamp?: string } export interface ExtensionAPI { registerCommand(name: string, opts: CommandOptions): void; registerTool(tool: ToolDefinition): void; registerProvider?(name: string, config: ProviderConfigLike): void | Promise; unregisterProvider?(name: string): void | Promise; on(event: LifecycleEvent, handler: EventHandler): void; appendEntry(type: string, data: unknown): Promise; getEntries(opts?: { type?: string; limit?: number }): Promise; sendUserMessage(message: string, opts?: Record): Promise; setActiveTools(toolNames: string[]): void; getSessionId(): string; } export type ExtensionFactory = (pi: ExtensionAPI) => void | Promise; export function textResult(text: string, details?: Record): ToolResult { return details === undefined ? { content: [{ type: "text", text }] } : { content: [{ type: "text", text }], details }; } export function errorResult(text: string, details?: Record): ToolResult { return details === undefined ? { isError: true, content: [{ type: "text", text }] } : { isError: true, content: [{ type: "text", text }], details }; } export function setTextWidget(ctx: ExtensionContext, key: string, content: string, options?: { placement?: "aboveEditor" | "belowEditor" }): void { ctx.ui.setWidget(key, content.split(/\r?\n/), options); } export function getProjectRoot(ctx: ExtensionContext): string { return ctx.session?.projectRoot ?? ctx.cwd ?? process.cwd(); } export function getWorkingDirectory(ctx: ExtensionContext): string { return ctx.session?.workingDirectory ?? ctx.cwd ?? process.cwd(); } export function getSessionId(ctx: ExtensionContext): string { return ctx.session?.id ?? "unknown-session"; } export function getCommandText(args: CommandArgs): string { return typeof args === "string" ? args : args.text ?? ""; }