API 参考
按执行上下文选择接口。下面的声明直接取自当前公共 SDK 类型;使用者仍须匹配目标宿主版本与所需权限。
按对象查询
| 对象 | 用途 | 对应指南 |
|---|---|---|
ExtensionContext | 后台命令、注册、共享数据、通知、调度 | 核心概念 |
ViewContext | 界面、资源、剪贴板、引用、状态与关闭 | 视图 |
ResourceApi / LocalResourceApi | 私有与已授权文件的读取、生成、导出 | 文件 |
DocumentApi / EditableDocument | 内容版本、原件保存和恢复 | 文档 |
AgentToolContext / AgentActionContext | 原任务中的工具或独立动作 | Agent |
ReferenceInput / ReferenceReveal | 材料快照和来源定位 | 引用 |
WorkerApi | 包内 Worker 生命周期 | 计算 |
EventSubscriber / TaskActionEvents | 作用域事件与动作来源 | 状态与事件 |
清单字段
extension.json 必须提供 schemaVersion: 1、稳定 id、name、version、apiVersion 和 engines.lexora。format 区分 source/compiled,entry 在需要后台代码时提供。permissions 和 contributes 按实际能力声明;完整结构示例见第一个插件。
可选 author 是独立署名,icon 指向包内图标。dataVersion 与视图 stateVersion 分别管理数据和实例状态迁移。不要根据其他产品的 manifest 字段推测 Lexora 行为。
完整类型声明
复制声明为插件内 lexora.d.ts,仅通过 import type 使用。独立 SDK 导出同一份类型;声明存在不表示目标安装版已经具备所有增量能力。
展开公共 SDK 类型
ts
export type Json = null | boolean | number | string | Json[] | { [key: string]: Json }
export type ReadonlyJson = string | number | boolean | null | ReadonlyJsonArray | ReadonlyJsonObject
export interface ReadonlyJsonArray extends ReadonlyArray<ReadonlyJson> {}
export interface ReadonlyJsonObject { readonly [key: string]: ReadonlyJson }
export interface Disposable { dispose: () => void | Promise<void> }
export interface EventSubscription { dispose: () => void }
export interface EventSubscriptionOptions { signal?: AbortSignal, once?: boolean }
export type EventName<Events> = Extract<keyof Events, string>
type NamespacePattern<Name extends string> = Name extends `${infer Head}:${infer Tail}` ? `${Head}:*` | `${Head}:**` | `${Head}:${NamespacePattern<Tail>}` : never
export type EventPattern<Events> = EventName<Events> | '*' | '**' | NamespacePattern<EventName<Events>>
type EventMatches<Name extends string, Pattern extends string> = Pattern extends '**' ? true
: Pattern extends `${infer Prefix}:**` ? Name extends Prefix | `${Prefix}:${string}` ? true : false
: Pattern extends `${infer Prefix}:*` ? Name extends `${Prefix}:${infer Tail}` ? Tail extends `${string}:${string}` ? false : true : false
: Pattern extends '*' ? Name extends `${string}:${string}` ? false : true : Name extends Pattern ? true : false
export type EventMessage<Events, Pattern extends string = '**'> = Pattern extends unknown ? {
[Name in EventName<Events>]: EventMatches<Name, Pattern> extends true ? Readonly<{ type: Name, data: Events[Name] }> : never
}[EventName<Events>] : never
export interface EventSubscriber<Events> {
on: <const Pattern extends EventPattern<Events>>(patterns: Pattern | readonly Pattern[], listener: (event: EventMessage<Events, Pattern>) => unknown, options?: EventSubscriptionOptions) => EventSubscription
}
export type EventSnapshot<Value> = Value extends object ? { readonly [Key in keyof Value]: EventSnapshot<Value[Key]> } : Value
export type FileOpeningLocation = 'inline' | 'standalone'
export type FileViewResource = 'selected-file' | 'optional-file' | 'none'
export interface FileHandlerView {
view: string
/** Preselect this mode in the installation dialog. Defaults to true. */
requestDefault?: boolean
}
export interface FileHandlerContribution {
id: string
title: string
extensions: string[]
preview?: FileHandlerView
open?: FileHandlerView
}
/** Legacy declaration. New plugins should use FileHandlerContribution. */
export interface FileOpenerContribution {
id: string
title: string
view: string
extensions: string[]
locations: FileOpeningLocation[]
requestDefault?: boolean
}
export interface LauncherContribution { id: string, title: string, view: string }
export interface NavigationContribution {
title: string
view: string
/** Show the host title bar on this navigation page. Defaults to true; does not affect resource tabs or the app frame. */
showHeader?: boolean
when?: WorkbenchCondition
}
/** API 4: contributes.skills; id is plugin-prefixed and package-wide unique; path points to a packaged Skill directory's SKILL.md. */
export interface SkillContribution { id: string, path: string }
/**
* API 4 increment: contributes.mcpConnectors; see mcp-connectors.md and set engines.lexora to verified supporting hosts.
* Independent declarations need no other contributions, entry or plugin permissions.
* Connection definitions follow the plugin; credentials, enablement and authorization remain host-managed.
*/
export interface McpConnectorContribution {
/** Unprefixed package-local ID matching /^[a-z0-9][a-z0-9_-]{0,63}$/, unique among MCP connectors; not a user connection ID. */
id: string
name: string
transport: 'streamable-http'
/** HTTPS address without userinfo or secrets. */
url: string
/** Required authentication requirement, not credentials or a guarantee of host OAuth support. */
authentication: 'none' | 'bearer' | 'oauth'
}
export type SubagentToolReference = {
source: 'mcp'
/** Local ID declared in this package's contributes.mcpConnectors. */
connector: string
/** Exact remote tool name, not a host-generated or JSON-encoded identity. */
name: string
} | {
source: 'builtin'
name: 'read' | 'find' | 'grep' | 'ls'
}
/**
* API 4 increment: contributes.subagents (NPC); see buddies.md and set engines.lexora to verified supporting hosts.
* Independent declarations need no MCP connectors, Skills, entry or plugin permissions and do not bind themselves to a companion.
* Enablement, model selection and companion bindings are user configuration, not manifest fields.
* Customize a copy; explicitly referenced plugin Skills and connectors remain dependencies of that copy.
*/
export interface SubagentContribution {
/** Unprefixed package-local ID matching /^[a-z0-9][a-z0-9_-]{0,63}$/, unique among NPCs; built-in NPC IDs are reserved. */
id: string
name: string
/** Defaults to ''. */
description?: string
instructions: string
/** Unique full plugin-prefixed contributes.skills IDs from this package. Defaults to []. */
skills?: string[]
/** Unique subset of skills that must be available. Defaults to []. */
requiredSkills?: string[]
/** Unique explicit references; no all-tools selection. Defaults to []. */
tools?: SubagentToolReference[]
/** Required. Inherits the task's limits or restricts file access; read_only forbids MCP references. */
fileAccess: 'inherit' | 'read_only'
}
export interface Resource { readonly id: string, readonly name: string, readonly sourceId?: string }
export interface ResourceTransferOptions { name?: string, signal?: AbortSignal }
export interface ResourceApi {
readText: (resource: Resource) => Promise<string>
listFiles: () => Promise<LocalFile[]>
getUrl: (resource: Pick<LocalFile, 'id'> | { packagePath: string }) => Promise<string>
readBytes: (resource: Pick<LocalFile, 'id'>, options?: { offset?: number, length?: number }) => Promise<{ data: Uint8Array, size: number, eof: boolean }>
importFile: (resource: Resource, options?: ResourceTransferOptions) => Promise<LocalFile>
createFile: (options: { name: string, data: Blob | ArrayBuffer | Uint8Array, mimeType?: string, signal?: AbortSignal }) => Promise<LocalFile>
release: (resource: Pick<LocalFile, 'id'>) => Promise<void>
}
export interface LocalFile extends Resource { readonly mimeType: string, readonly size: number, readonly relativePath?: string }
export interface LocalDirectory extends Resource {}
export interface LocalResourceApi extends ResourceApi {
pickFiles: (options?: { filters?: { name: string, extensions: string[] }[], multiple?: boolean }) => Promise<LocalFile[]>
revokeFile: (resource: Pick<LocalFile, 'id'>) => Promise<void>
pickDirectory: () => Promise<LocalDirectory | null>
listDirectories: () => Promise<LocalDirectory[]>
scanDirectory: (directory: Pick<LocalDirectory, 'id'>, options?: { extensions?: string[], recursive?: boolean }) => Promise<LocalFile[]>
revokeDirectory: (directory: Pick<LocalDirectory, 'id'>) => Promise<void>
saveFile: (options: { name: string, data: Blob | ArrayBuffer | Uint8Array }) => Promise<boolean>
}
export interface NetworkApi {
get: (url: string) => Promise<{ status: number, text: string }>
download: (url: string, options?: ResourceTransferOptions) => Promise<LocalFile>
}
export interface ScheduleInput { id: string, command: string, enabled: boolean, intervalMinutes: number }
export interface Schedule extends ScheduleInput { nextRunAt: number | null }
export interface ScheduleApi {
get: (id: string) => Promise<Schedule | null>
set: (schedule: ScheduleInput) => Promise<Schedule>
remove: (id: string) => Promise<void>
}
export interface CommandInvocation {
readonly target: 'composer.actions' | 'task.actions' | 'resource.actions' | 'message.actions' | 'view' | 'slash'
readonly instanceId: string | null
readonly content?: string
}
export interface Rect { readonly x: number, readonly y: number, readonly width: number, readonly height: number }
export interface PaneSnapshot { readonly id: string, readonly active: boolean, readonly visible: boolean, readonly rect: Rect }
export interface Interaction { readonly id: string, readonly signal: AbortSignal, end: () => Promise<void> }
export interface PlacementOptions { instanceId?: string, interactionId?: string }
export interface HitRegion { id: string, label: string, rect: Rect }
export interface ModelSelection { providerId: string, modelId: string }
export type SettingValue = boolean | string | number | ModelSelection | null
export interface ConfigurationEvents {
'configuration:changed': { readonly configuration: EventSnapshot<Record<string, SettingValue>>, readonly changedKeys: readonly string[] }
}
export interface WorkbenchPaneEvents {
'workbench:panes:changed': { readonly panes: readonly PaneSnapshot[] }
}
export interface ExtensionEvents extends ConfigurationEvents, WorkbenchPaneEvents {}
export interface TaskTitle {
id: string
title: string | null
titleSource: 'legacy' | 'manual' | 'fallback' | 'generated'
}
export interface AgentReferenceSummary { referenceId: string, sourceMessageId: string, title: string, excerpt: string }
export interface AgentReference {
referenceId: string
sourceMessageId: string
title: string
text: string
textLength: number
textDigest: string
offset: number
nextOffset: number | null
locator: ReferenceLocator | null
scope: { taskId: string, branchId: string }
}
export interface AgentPublishedArtifact { id: string, name: string, mimeType: string, size: number }
export interface AgentToolContext {
readonly scope: Readonly<{ taskId: string, branchId: string, runId: string }>
readonly artifacts: {
/** Publish a private file to this task. Requires a write tool. Creates an independent workspace copy and a task output card. */
publish: (input: { resource: Pick<LocalFile, 'id'>, name?: string }) => Promise<AgentPublishedArtifact>
}
readonly results: {
/** Add a private PNG/JPEG/WebP to this tool's native model image result. Await before returning the JSON result. */
addImage: (input: { resource: Pick<LocalFile, 'id'> }) => Promise<void>
}
readonly references: {
list: () => Promise<{ items: AgentReferenceSummary[], truncated: boolean }>
resolve: (referenceId: string, options?: { sourceMessageId?: string, offset?: number, limit?: number }) => Promise<AgentReference>
}
readonly signal: AbortSignal
readonly task: {
get: () => Promise<TaskTitle>
messages: () => Promise<{ role: 'user' | 'assistant', text: string }[]>
rename: (input: { title: string }) => Promise<{ applied: boolean }>
}
readonly models: {
generateText: (input: { prompt: string, system?: string, model?: ModelSelection | null, maxTokens?: number }) => Promise<{ text: string, model: ModelSelection }>
}
}
export interface TaskActionEvents {
'task:created': { readonly conversationId: string, readonly branchId: string, readonly runId: string, readonly messageId: string, readonly commitId: string }
'task:run:before': { readonly conversationId: string, readonly branchId: string, readonly runId: string, readonly messageId: string }
'task:reply:started': { readonly conversationId: string, readonly branchId: string, readonly runId: string, readonly messageId: string }
'task:input:committed': { readonly conversationId: string, readonly branchId: string, readonly runId: string, readonly messageId: string, readonly commitId: string }
'task:turn:completed': { readonly conversationId: string, readonly branchId: string, readonly runId: string, readonly triggeringMessageId: string, readonly completedAt: string }
}
export interface AgentActionContext extends Omit<AgentToolContext, 'references' | 'scope' | 'artifacts' | 'results'> {
readonly cause: EventMessage<TaskActionEvents> | Readonly<{ type: 'user' }>
}
export interface AgentActionResult { status: 'completed' | 'skipped', message?: string }
export type ConditionInput = 'configuration' | 'runtime.models' | 'runtime.task' | 'workbench' | 'form'
export interface ConditionReference { condition: string, params?: ReadonlyJsonObject }
export interface ConditionResult { value: boolean, reason?: string }
export type ConfigurationScope = { kind: 'global' } | { kind: 'space', spaceId: string } | { kind: 'task', taskId: string }
export type ConditionInvocationScope = { kind: 'settings', moduleId: string, groupId: string } | { kind: 'task', taskId: string, runId: string | null }
export type ConditionData<T> = EventSnapshot<{ status: 'available', revision: string } & T> | Readonly<{ status: 'not_requested' | 'no_context' | 'denied' | 'unsupported' | 'loading' | 'invalid' }>
export interface ConditionContext {
readonly version: 1
readonly signal: AbortSignal
readonly scope: EventSnapshot<{ key: string, configuration: ConfigurationScope, invocation: ConditionInvocationScope }>
readonly target: Readonly<{ kind: 'setting' | 'agent' | 'action', id: string }>
readonly configuration: ConditionData<{ values: Record<string, SettingValue>, sources: Record<string, ConfigurationScope> }>
readonly runtime: Readonly<{
models: ConditionData<{ selection: ModelSelection | null, models: { providerId: string, modelId: string, name: string, available: boolean, capabilities: string[] }[] }>
task: ConditionData<{ id: string, spaceId: string | null, branchId: string, title: string | null, titleSource: 'fallback' | 'generated' | 'manual' | 'legacy', activity: 'idle' | 'running' | 'awaiting_approval', modelSelection: ModelSelection | null }>
}>
readonly workbench: ConditionData<{ panes: { id: string, active: boolean, visible: boolean }[] }>
readonly form: ConditionData<{ values: Record<string, SettingValue>, dirtyKeys: string[] }>
}
export interface ConditionApi {
register: (id: string, evaluate: (context: ConditionContext, params: ReadonlyJsonObject) => boolean | ConditionResult | Promise<boolean | ConditionResult>) => Disposable
invalidate: (input?: { condition?: string, scopeKey?: string }) => Promise<void>
}
export type ShellCandidateId = 'bash' | 'git-bash' | 'zsh' | 'sh' | 'powershell7' | 'powershell51' | 'cmd'
export interface ShellCandidate {
id: ShellCandidateId
label: string
dialect: 'bash' | 'zsh' | 'sh' | 'powershell' | 'cmd'
executable: string
version: string
available: boolean
reason?: string
}
export interface WorkerOptions {
type?: 'classic' | 'module'
name?: string
signal?: AbortSignal
}
export interface WorkerApi {
create: (entry: string | URL, options?: WorkerOptions) => Promise<Worker>
}
export interface ExtensionContext {
readonly signal: AbortSignal
readonly workers: WorkerApi
readonly themes: ThemeApi
readonly extension: { readonly id: string, readonly version: string, readonly apiVersion: 1 | 2 | 3 | 4 }
readonly events: EventSubscriber<ExtensionEvents>
readonly configuration: {
get: () => Promise<Record<string, SettingValue>>
onChange: (listener: (configuration: Readonly<Record<string, SettingValue>>) => void | Promise<void>) => Disposable
}
readonly conditions: ConditionApi
readonly shells: { detect: () => Promise<ShellCandidate[]> }
readonly agent: {
registerTool: (id: string, execute: (input: Record<string, Json>, context: AgentToolContext) => Json | void | Promise<Json | void>) => Disposable
registerAction: (id: string, execute: (context: AgentActionContext) => AgentActionResult | Promise<AgentActionResult>) => Disposable
}
readonly subscriptions: { add: <T extends Disposable>(disposable: T) => T }
readonly commands: { register: (id: string, execute: (context: { resource: Resource | null, arguments: Json, invocation: CommandInvocation | null }) => Json | void | Promise<Json | void>) => Disposable }
readonly placements: { show: (id: string, options?: string | PlacementOptions) => Promise<string>, hide: (id: string, options?: string | PlacementOptions) => Promise<string | null> }
readonly window: { readonly styles: { set: (id: string, css: string) => Promise<void>, remove: (id: string) => Promise<void> } }
readonly workbench: { readonly panes: readonly PaneSnapshot[], onPanesChange: (listener: (panes: readonly PaneSnapshot[]) => void) => Disposable }
readonly interactions: { start: (title: string) => Promise<Interaction> }
readonly views: { broadcast: (message: Json) => Promise<void>, open: (type: string, options?: { resource?: Resource | null, state?: Json }) => Promise<string> }
readonly resources: ResourceApi
readonly network: NetworkApi
readonly storage: { get: () => Promise<Json>, set: (value: Json) => Promise<void> }
readonly notifications: { show: (notification: { title: string, body: string }) => Promise<boolean> }
readonly schedules: ScheduleApi
}
export type WorkbenchRegion
= | 'window'
| 'app.sidebar'
| 'workbench.sidebar'
| 'workbench.workspace'
| 'workbench.pane'
| 'task.history'
| 'composer.input'
export interface AnchorGeometry {
readonly kind: WorkbenchRegion
readonly visible: boolean
readonly width: number
readonly height: number
}
export interface ControlSnapshot {
readonly revision: string
readonly value: string | null
readonly options: readonly { readonly value: string, readonly label: string }[]
readonly disabled: boolean
}
export type MountTarget = 'workbench' | 'app.sidebar' | 'workbench.sidebar' | 'workbench.pane'
export type MountLength = number | `${number}%` | null
export interface ViewPresentation {
target?: MountTarget
position?: 'static' | 'absolute'
order?: number
zIndex?: number
width?: MountLength
height?: MountLength
top?: MountLength
right?: MountLength
bottom?: MountLength
left?: MountLength
}
export interface MountGeometry {
readonly instanceId?: string
readonly target: MountTarget
readonly visible: boolean
readonly width: number
readonly height: number
readonly rect: { readonly x: number, readonly y: number, readonly width: number, readonly height: number }
}
export type WorkbenchContextValues = Readonly<Record<string, string | number | boolean>>
export type WorkbenchCondition = Record<string, string | number | boolean | (string | number | boolean)[]>
export interface WorkbenchContextSnapshot {
readonly values: WorkbenchContextValues
readonly pages: readonly { readonly id: string, readonly title: string }[]
}
export interface ReferenceLocator {
readonly version: number
readonly data: ReadonlyJson
}
export type ReferenceChoice = { kind: 'view', id: string } | { kind: 'new-task' | 'clipboard' }
export interface ReferenceCapture {
readonly id: string
readonly targets: readonly { readonly id: string, readonly label: string }[]
readonly defaultId: string | null
readonly clipboard: boolean
}
export interface ReferenceReveal {
readonly referenceId: string
readonly text: string
readonly locator: ReferenceLocator | null
}
export type ReferenceInput
= | { kind: 'content', title: string, text: string, locator?: ReferenceLocator, source?: 'view' }
| { kind: 'resource', resource: { id: string } }
/** Format-independent editable content; it may exist before a file is saved. */
export interface EditableDocument {
readonly id: string
readonly name: string
readonly location: string
readonly version: string | null
readonly revision: string
readonly size: number
readonly writable: boolean
readonly kind: 'file' | 'draft'
readonly recovery: boolean
readonly openedAt: number
}
export interface DocumentBytes { data: Blob | ArrayBuffer | Uint8Array, signal?: AbortSignal }
export interface DocumentApi {
pick: (options?: { filters?: { name: string, extensions: string[] }[] }) => Promise<EditableDocument | null>
open: (resource: Resource) => Promise<EditableDocument | null>
resume: (document: Pick<EditableDocument, 'id'>) => Promise<EditableDocument>
list: () => Promise<EditableDocument[]>
read: (document: Pick<EditableDocument, 'id'>, options?: { recovery?: boolean, signal?: AbortSignal }) => Promise<Uint8Array>
create: (options: DocumentBytes & { name: string }) => Promise<EditableDocument>
save: (document: EditableDocument, options: DocumentBytes) => Promise<EditableDocument>
saveAs: (options: DocumentBytes & { name: string }) => Promise<EditableDocument | null>
backup: (document: EditableDocument, options: DocumentBytes) => Promise<EditableDocument>
status: (document: Pick<EditableDocument, 'id'>) => Promise<{ changed: boolean }>
discardRecovery: (document: Pick<EditableDocument, 'id'>) => Promise<void>
close: (document: Pick<EditableDocument, 'id'>) => Promise<void>
forget: (document: Pick<EditableDocument, 'id'>) => Promise<void>
reveal: (document: Pick<EditableDocument, 'id'>) => Promise<void>
}
export type ExtensionDataSource = 'task.metrics' | 'context.usage'
export interface ExtensionDataQuery<Source extends ExtensionDataSource = ExtensionDataSource> {
readonly source: Source
readonly scope: 'bound'
}
export interface ExtensionDataValues {
'task.metrics': {
taskId: string
branchId: string
turns: number
steps: number
tokens: { inputTokens: number, outputTokens: number, cacheReadTokens: number, cacheWriteTokens: number }
throughput: { samples: number, tokensPerSecond: number | null }
}
'context.usage': {
taskId: string
branchId: string
actorId: string
runId: string | null
tokens: number
window: number
percent: number
}
}
export type ExtensionDataSnapshot<Source extends ExtensionDataSource = ExtensionDataSource> = {
[Key in Source]: {
readonly source: Key
readonly status: 'ready'
readonly value: EventSnapshot<ExtensionDataValues[Key]>
} | {
readonly source: Key
readonly status: 'denied' | 'no_target' | 'unavailable'
readonly value: null
}
}[Source]
export interface ExtensionDataApi {
read: <Source extends ExtensionDataSource>(query: ExtensionDataQuery<Source>) => Promise<ExtensionDataSnapshot<Source>>
observe: <Source extends ExtensionDataSource>(query: ExtensionDataQuery<Source>, listener: (snapshot: ExtensionDataSnapshot<Source>) => unknown) => Disposable
}
export interface ViewContext {
readonly documents: DocumentApi
readonly clipboard: {
read: () => Promise<{ text?: string, html?: string }>
write: (data: { text?: string, html?: string }) => Promise<void>
}
setDocumentInfo: (info: { title: string, dirty: boolean }) => Promise<void>
onBeforeClose: (handler: (signal: AbortSignal) => boolean | Promise<boolean>) => Disposable
readonly workers: WorkerApi
readonly themes: ThemeApi
readonly events: EventSubscriber<ViewEvents>
readonly interaction: {
readonly id: string
setRegions: (regions: readonly HitRegion[]) => Promise<void>
onActivate: (listener: (event: { readonly id: string, readonly x: number, readonly y: number }) => void) => Disposable
} | null
onMessage: (listener: (message: Json) => void) => Disposable
readonly instanceId: string | null
readonly data: ExtensionDataApi
readonly workbench: WorkbenchContextSnapshot
onWorkbenchChange: (listener: (snapshot: WorkbenchContextSnapshot) => void) => Disposable
readonly visible: boolean
onVisibilityChange: (listener: (visible: boolean) => void) => Disposable
readonly mount: MountGeometry | null
onMountChange: (listener: (mount: MountGeometry) => void) => Disposable
readonly anchor: AnchorGeometry | null
onAnchorChange: (listener: (anchor: AnchorGeometry) => void) => Disposable
readonly control: {
readonly snapshot: ControlSnapshot
onChange: (listener: (snapshot: ControlSnapshot) => void) => Disposable
propose: (value: string, revision?: string) => Promise<void>
} | null
readonly environment: ViewEnvironment
onEnvironmentChange: (listener: (environment: ViewContext['environment']) => void) => Disposable
readonly apiVersion: 1 | 2 | 3 | 4
readonly resource: Resource | null
readonly state: Json
readonly stateVersion: number
readonly expectedStateVersion: number
readonly signal: AbortSignal
onActivity: (listener: (event: { readonly type: 'composer-input', readonly caret?: { readonly x: number, readonly y: number, readonly width: number, readonly height: number } | null }) => void) => Disposable
openExternal: (url: string) => Promise<void>
readonly references: {
add: (input: ReferenceInput) => Promise<boolean>
capture: (input: ReferenceInput) => Promise<ReferenceCapture | null>
commit: (id: string, choice: ReferenceChoice) => Promise<boolean>
release: (id: string) => Promise<boolean>
onReveal: (handler: (input: ReferenceReveal, signal: AbortSignal) => boolean | Promise<boolean>) => Disposable
}
readonly resources: LocalResourceApi
readonly network: NetworkApi
readonly commands: { execute: (command: string, args?: Json) => Promise<Json> }
setPresentation: (presentation: ViewPresentation) => Promise<void>
setState: (state: Json) => Promise<void>
setActive: (active: boolean) => Promise<void>
}
export interface ViewEnvironment {
readonly language: string
readonly colorScheme: 'light' | 'dark'
readonly themeRevision?: number
readonly colors: Readonly<Record<string, string>>
}
export interface ExtensionDataEvents {
'data:changed': { readonly id: string, readonly snapshot: ExtensionDataSnapshot | null }
}
export interface ViewStateEvents {
'view:visibility:changed': { readonly visible: boolean }
'view:environment:changed': { readonly environment: ViewEnvironment }
}
export interface ViewGeometryEvents {
'view:mount:changed': { readonly mount: MountGeometry }
'view:anchor:changed': { readonly anchor: AnchorGeometry }
}
export interface ViewMessageEvents {
'view:message:received': { readonly message: ReadonlyJson }
}
export interface WorkbenchContextEvents {
'workbench:context:changed': { readonly context: WorkbenchContextSnapshot }
}
export interface ControlEvents {
'control:changed': { readonly control: ControlSnapshot }
}
export interface InteractionEvents {
'interaction:activated': { readonly regionId: string, readonly x: number, readonly y: number }
}
export interface ComposerEvents {
'composer:input:received': { readonly caret?: Rect | null }
}
export interface ViewEvents extends ExtensionDataEvents, ViewStateEvents, ViewGeometryEvents, ViewMessageEvents, WorkbenchContextEvents, ControlEvents, InteractionEvents, ComposerEvents {}
export interface ExtensionModule {
activate: (context: ExtensionContext) => void | Promise<void>
deactivate?: () => void | Promise<void>
migrate?: (previous: Json, from: number, to: number) => Json | Promise<Json>
}
export interface ViewModule { render: (context: ViewContext, container: HTMLElement) => void | Promise<void> }
export type ThemeColor = 'app-sidebar-fg' | 'workspace-sidebar-fg' | 'reading' | 'reading-fg' | 'composer' | 'composer-fg' | 'hover-fg' | 'selected-fg' | 'pressed-fg' | 'link' | 'quote' | 'quote-border' | 'inline-code' | 'inline-code-fg' | 'code' | 'code-fg' | 'code-header' | 'code-border' | 'code-line-number' | 'table-header' | 'table-border' | 'table-stripe' | 'table-hover' | 'canvas-grid' | 'diff-added' | 'diff-removed' | 'editor' | 'editor-fg' | 'editor-line' | 'editor-gutter' | 'editor-cursor' | 'syntax-comment' | 'syntax-keyword' | 'syntax-string' | 'syntax-number' | 'syntax-function' | 'syntax-type' | 'syntax-variable' | 'syntax-operator' | 'terminal-background' | 'terminal-foreground' | 'terminal-muted' | 'terminal-scrollbar' | 'terminal-mauve' | 'terminal-blue' | 'terminal-green' | 'terminal-yellow' | 'terminal-peach' | 'terminal-maroon' | 'terminal-sky' | 'terminal-rosewater' | 'canvas' | 'app-sidebar' | 'workspace-sidebar' | 'surface' | 'raised' | 'subtle' | 'user-message' | 'hover' | 'pressed' | 'selected' | 'selected-hover' | 'nav-hover' | 'nav-selected' | 'nav-selected-hover' | 'nav-pressed' | 'nav-foreground' | 'border' | 'border-strong' | 'strong' | 'fg' | 'muted' | 'disabled' | 'on-accent' | 'accent' | 'accent-hover' | 'accent-pressed' | 'accent-text' | 'focus' | 'text-selection' | 'text-selection-inactive' | 'text-selection-match' | 'accent-subtle' | 'accent-surface' | 'accent-surface-hover' | 'accent-surface-pressed' | 'accent-border' | 'accent-border-hover' | 'accent-on-surface' | 'success' | 'success-solid' | 'success-surface' | 'success-surface-hover' | 'success-border' | 'warning' | 'warning-solid' | 'warning-surface' | 'warning-surface-hover' | 'warning-border' | 'danger' | 'danger-solid' | 'danger-surface' | 'danger-surface-hover' | 'danger-border' | 'gold' | 'gold-surface' | 'avatar' | 'avatar-foreground' | 'data-violet' | 'data-cyan' | 'data-blue'
export type ThemeAppearance = 'light' | 'dark'
export interface FileIconAssociations {
file?: string
folder?: string
folderExpanded?: string
rootFolder?: string
rootFolderExpanded?: string
fileNames?: Record<string, string>
fileExtensions?: Record<string, string>
languageIds?: Record<string, string>
folderNames?: Record<string, string>
folderNamesExpanded?: Record<string, string>
rootFolderNames?: Record<string, string>
rootFolderNamesExpanded?: Record<string, string>
}
export interface FileIconThemeDocument extends FileIconAssociations {
$schema?: string
iconDefinitions: Record<string, { iconPath: string }>
light?: FileIconAssociations
highContrast?: FileIconAssociations
hidesExplorerArrows?: boolean
}
export interface FileIconThemeContribution { id: string, label: string, path: string }
export interface ThemePreference { id: string }
export interface ThemeDescriptor { id: string, label: string, appearance: ThemeAppearance, source: 'plugin' | 'user' | 'fallback', extensionId: string | null, packageName: string, swatch: string }
export interface ThemeMaterial {
anchor: WorkbenchRegion
image?: string
color?: string
gradient?: { angle: number, stops: { color: string, at: number }[] }
opacity?: number
imageOpacity?: number
scale?: number
blur?: number
position?: [number, number]
size?: 'cover' | 'contain'
}
export interface ThemeDocument {
schemaVersion: 1
colors?: Partial<Record<ThemeColor, string>>
shadows?: Partial<Record<'soft' | 'raised' | 'overlay' | 'window' | 'illustration', { x: number, y: number, blur: number, spread?: number, color: string }[]>>
materials?: ThemeMaterial[]
welcome?: { text?: { 'zh-CN': string, 'en-US': string } | null, image?: string | null }
}
export interface ThemeArchive { schemaVersion: 1, label: string, appearance: ThemeAppearance, document: ThemeDocument, assets?: Record<string, string | { resourceId: string } | { packagePath: string }> }
export interface ResolvedTheme { descriptor: ThemeDescriptor, colors: Record<ThemeColor, string>, variables: Record<string, string>, document: ThemeDocument, assets: Record<string, string> }
export interface ThemeSnapshot { revision: number, preference: ThemePreference, active: ResolvedTheme, themes: ThemeDescriptor[], unavailable: string | null, preview: boolean }
export interface ThemePreview { token: string, revision: number }
export interface ThemeApi {
list: () => Promise<ThemeDescriptor[]>
get: (id: string) => Promise<{ descriptor: ThemeDescriptor, document: ThemeDocument }>
getActive: () => Promise<ThemeSnapshot>
describe: () => Promise<{ schema: Json, colors: ThemeColor[], anchors: ThemeMaterial['anchor'][], precedence: string[] }>
validate: (document: unknown) => Promise<{ valid: boolean, diagnostics: { path: string, message: string }[] }>
resolve: (appearance: ThemeAppearance, document: ThemeDocument, overrides?: Partial<Record<ThemeColor, string>>) => Promise<ResolvedTheme>
save: (archive: ThemeArchive, id?: string) => Promise<ThemeDescriptor>
remove: (id: string) => Promise<void>
setPreference: (preference: ThemePreference) => Promise<ThemeSnapshot>
beginPreview: (archive: ThemeArchive) => Promise<ThemePreview>
updatePreview: (preview: ThemePreview, archive: ThemeArchive) => Promise<ThemePreview>
commitPreview: (preview: ThemePreview) => Promise<ThemeDescriptor>
cancelPreview: (token: string) => Promise<void>
import: (content: string) => Promise<ThemeDescriptor>
export: (id: string) => Promise<string>
onDidChange: (listener: (snapshot: ThemeSnapshot) => void) => Disposable
}错误与兼容
异步 API 通过 Promise 返回结果;取消可能是返回值,也可能拒绝请求,按各接口契约处理。保存冲突、授权撤销和视图失效不能被当成成功。模型截断会报 EXTENSION_MODEL_TRUNCATED,不会返回被截断的完整答案。
升级插件前检查权限与兼容性,并在目标宿主验证关键流程。