Path: blob/main/src/vs/workbench/api/common/extHostDebugService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type * as vscode from 'vscode';6import { coalesce } from '../../../base/common/arrays.js';7import { asPromise } from '../../../base/common/async.js';8import { CancellationToken } from '../../../base/common/cancellation.js';9import { Emitter, Event } from '../../../base/common/event.js';10import { Disposable as DisposableCls, toDisposable } from '../../../base/common/lifecycle.js';11import { ThemeIcon as ThemeIconUtils } from '../../../base/common/themables.js';12import { URI, UriComponents } from '../../../base/common/uri.js';13import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';14import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';15import { ISignService } from '../../../platform/sign/common/sign.js';16import { IWorkspaceFolder } from '../../../platform/workspace/common/workspace.js';17import { AbstractDebugAdapter } from '../../contrib/debug/common/abstractDebugAdapter.js';18import { DebugVisualizationType, IAdapterDescriptor, IConfig, IDebugAdapter, IDebugAdapterExecutable, IDebugAdapterImpl, IDebugAdapterNamedPipeServer, IDebugAdapterServer, IDebuggerContribution, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from '../../contrib/debug/common/debug.js';19import { convertToDAPaths, convertToVSCPaths, isDebuggerMainContribution } from '../../contrib/debug/common/debugUtils.js';20import { ExtensionDescriptionRegistry } from '../../services/extensions/common/extensionDescriptionRegistry.js';21import { Dto } from '../../services/extensions/common/proxyIdentifier.js';22import { DebugSessionUUID, ExtHostDebugServiceShape, IBreakpointsDeltaDto, IDebugSessionDto, IFunctionBreakpointDto, ISourceMultiBreakpointDto, IStackFrameFocusDto, IThreadFocusDto, MainContext, MainThreadDebugServiceShape, MainThreadTelemetryShape } from './extHost.protocol.js';23import { IExtHostCommands } from './extHostCommands.js';24import { IExtHostConfiguration } from './extHostConfiguration.js';25import { IExtHostEditorTabs } from './extHostEditorTabs.js';26import { IExtHostExtensionService } from './extHostExtensionService.js';27import { IExtHostRpcService } from './extHostRpcService.js';28import { IExtHostTesting } from './extHostTesting.js';29import * as Convert from './extHostTypeConverters.js';30import { Breakpoint, DataBreakpoint, DebugAdapterExecutable, DebugAdapterInlineImplementation, DebugAdapterNamedPipeServer, DebugAdapterServer, DebugConsoleMode, DebugStackFrame, DebugThread, Disposable, FunctionBreakpoint, Location, Position, setBreakpointId, SourceBreakpoint, ThemeIcon } from './extHostTypes.js';31import { IExtHostVariableResolverProvider } from './extHostVariableResolverService.js';32import { IExtHostWorkspace } from './extHostWorkspace.js';3334export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtHostDebugService');3536export interface IExtHostDebugService extends ExtHostDebugServiceShape {3738readonly _serviceBrand: undefined;3940onDidStartDebugSession: Event<vscode.DebugSession>;41onDidTerminateDebugSession: Event<vscode.DebugSession>;42onDidChangeActiveDebugSession: Event<vscode.DebugSession | undefined>;43activeDebugSession: vscode.DebugSession | undefined;44activeDebugConsole: vscode.DebugConsole;45onDidReceiveDebugSessionCustomEvent: Event<vscode.DebugSessionCustomEvent>;46onDidChangeBreakpoints: Event<vscode.BreakpointsChangeEvent>;47breakpoints: vscode.Breakpoint[];48onDidChangeActiveStackItem: Event<vscode.DebugThread | vscode.DebugStackFrame | undefined>;49activeStackItem: vscode.DebugThread | vscode.DebugStackFrame | undefined;5051addBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;52removeBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;53startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean>;54stopDebugging(session?: vscode.DebugSession): Promise<void>;55registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable;56registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable;57registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable;58registerDebugVisualizationProvider<T extends vscode.DebugVisualization>(extension: IExtensionDescription, id: string, provider: vscode.DebugVisualizationProvider<T>): vscode.Disposable;59registerDebugVisualizationTree<T extends vscode.DebugTreeItem>(extension: IExtensionDescription, id: string, provider: vscode.DebugVisualizationTree<T>): vscode.Disposable;60asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri;61}6263export abstract class ExtHostDebugServiceBase extends DisposableCls implements IExtHostDebugService, ExtHostDebugServiceShape {6465declare readonly _serviceBrand: undefined;6667private _configProviderHandleCounter: number;68private _configProviders: ConfigProviderTuple[];6970private _adapterFactoryHandleCounter: number;71private _adapterFactories: DescriptorFactoryTuple[];7273private _trackerFactoryHandleCounter: number;74private _trackerFactories: TrackerFactoryTuple[];7576private _debugServiceProxy: MainThreadDebugServiceShape;77private _debugSessions: Map<DebugSessionUUID, ExtHostDebugSession> = new Map<DebugSessionUUID, ExtHostDebugSession>();7879private readonly _onDidStartDebugSession: Emitter<vscode.DebugSession>;80get onDidStartDebugSession(): Event<vscode.DebugSession> { return this._onDidStartDebugSession.event; }8182private readonly _onDidTerminateDebugSession: Emitter<vscode.DebugSession>;83get onDidTerminateDebugSession(): Event<vscode.DebugSession> { return this._onDidTerminateDebugSession.event; }8485private readonly _onDidChangeActiveDebugSession: Emitter<vscode.DebugSession | undefined>;86get onDidChangeActiveDebugSession(): Event<vscode.DebugSession | undefined> { return this._onDidChangeActiveDebugSession.event; }8788private _activeDebugSession: ExtHostDebugSession | undefined;89get activeDebugSession(): vscode.DebugSession | undefined { return this._activeDebugSession?.api; }9091private readonly _onDidReceiveDebugSessionCustomEvent: Emitter<vscode.DebugSessionCustomEvent>;92get onDidReceiveDebugSessionCustomEvent(): Event<vscode.DebugSessionCustomEvent> { return this._onDidReceiveDebugSessionCustomEvent.event; }9394private _activeDebugConsole: ExtHostDebugConsole;95get activeDebugConsole(): vscode.DebugConsole { return this._activeDebugConsole.value; }9697private _breakpoints: Map<string, vscode.Breakpoint>;9899private readonly _onDidChangeBreakpoints: Emitter<vscode.BreakpointsChangeEvent>;100101private _activeStackItem: vscode.DebugThread | vscode.DebugStackFrame | undefined;102private readonly _onDidChangeActiveStackItem: Emitter<vscode.DebugThread | vscode.DebugStackFrame | undefined>;103104private _debugAdapters: Map<number, IDebugAdapter>;105private _debugAdaptersTrackers: Map<number, vscode.DebugAdapterTracker>;106107private _debugVisualizationTreeItemIdsCounter = 0;108private readonly _debugVisualizationProviders = new Map<string, vscode.DebugVisualizationProvider>();109private readonly _debugVisualizationTrees = new Map<string, vscode.DebugVisualizationTree>();110private readonly _debugVisualizationTreeItemIds = new WeakMap<vscode.DebugTreeItem, number>();111private readonly _debugVisualizationElements = new Map<number, { provider: string; item: vscode.DebugTreeItem; children?: number[] }>();112113private _signService: ISignService | undefined;114115private readonly _visualizers = new Map<number, { v: vscode.DebugVisualization; provider: vscode.DebugVisualizationProvider; extensionId: string }>();116private _visualizerIdCounter = 0;117118private _telemetryProxy: MainThreadTelemetryShape;119120constructor(121@IExtHostRpcService extHostRpcService: IExtHostRpcService,122@IExtHostWorkspace protected readonly _workspaceService: IExtHostWorkspace,123@IExtHostExtensionService private readonly _extensionService: IExtHostExtensionService,124@IExtHostConfiguration protected readonly _configurationService: IExtHostConfiguration,125@IExtHostEditorTabs protected readonly _editorTabs: IExtHostEditorTabs,126@IExtHostVariableResolverProvider private readonly _variableResolver: IExtHostVariableResolverProvider,127@IExtHostCommands private readonly _commands: IExtHostCommands,128@IExtHostTesting private readonly _testing: IExtHostTesting,129) {130super();131132this._configProviderHandleCounter = 0;133this._configProviders = [];134135this._adapterFactoryHandleCounter = 0;136this._adapterFactories = [];137138this._trackerFactoryHandleCounter = 0;139this._trackerFactories = [];140141this._debugAdapters = new Map();142this._debugAdaptersTrackers = new Map();143144this._onDidStartDebugSession = this._register(new Emitter<vscode.DebugSession>());145this._onDidTerminateDebugSession = this._register(new Emitter<vscode.DebugSession>());146this._onDidChangeActiveDebugSession = this._register(new Emitter<vscode.DebugSession | undefined>());147this._onDidReceiveDebugSessionCustomEvent = this._register(new Emitter<vscode.DebugSessionCustomEvent>());148149this._debugServiceProxy = extHostRpcService.getProxy(MainContext.MainThreadDebugService);150151this._onDidChangeBreakpoints = this._register(new Emitter<vscode.BreakpointsChangeEvent>());152153this._onDidChangeActiveStackItem = this._register(new Emitter<vscode.DebugThread | vscode.DebugStackFrame | undefined>());154155this._activeDebugConsole = new ExtHostDebugConsole(this._debugServiceProxy);156157this._breakpoints = new Map<string, vscode.Breakpoint>();158159this._extensionService.getExtensionRegistry().then((extensionRegistry: ExtensionDescriptionRegistry) => {160this._register(extensionRegistry.onDidChange(_ => {161this.registerAllDebugTypes(extensionRegistry);162}));163this.registerAllDebugTypes(extensionRegistry);164});165166this._telemetryProxy = extHostRpcService.getProxy(MainContext.MainThreadTelemetry);167}168169public async $getVisualizerTreeItem(treeId: string, element: IDebugVisualizationContext): Promise<IDebugVisualizationTreeItem | undefined> {170const context = this.hydrateVisualizationContext(element);171if (!context) {172return undefined;173}174175const item = await this._debugVisualizationTrees.get(treeId)?.getTreeItem?.(context);176return item ? this.convertVisualizerTreeItem(treeId, item) : undefined;177}178179public registerDebugVisualizationTree<T extends vscode.DebugTreeItem>(manifest: IExtensionDescription, id: string, provider: vscode.DebugVisualizationTree<T>): vscode.Disposable {180const extensionId = ExtensionIdentifier.toKey(manifest.identifier);181const key = this.extensionVisKey(extensionId, id);182if (this._debugVisualizationProviders.has(key)) {183throw new Error(`A debug visualization provider with id '${id}' is already registered`);184}185186this._debugVisualizationTrees.set(key, provider);187this._debugServiceProxy.$registerDebugVisualizerTree(key, !!provider.editItem);188return toDisposable(() => {189this._debugServiceProxy.$unregisterDebugVisualizerTree(key);190this._debugVisualizationTrees.delete(id);191});192}193194public async $getVisualizerTreeItemChildren(treeId: string, element: number): Promise<IDebugVisualizationTreeItem[]> {195const item = this._debugVisualizationElements.get(element)?.item;196if (!item) {197return [];198}199200const children = await this._debugVisualizationTrees.get(treeId)?.getChildren?.(item);201return children?.map(i => this.convertVisualizerTreeItem(treeId, i)) || [];202}203204public async $editVisualizerTreeItem(element: number, value: string): Promise<IDebugVisualizationTreeItem | undefined> {205const e = this._debugVisualizationElements.get(element);206if (!e) { return undefined; }207208const r = await this._debugVisualizationTrees.get(e.provider)?.editItem?.(e.item, value);209return this.convertVisualizerTreeItem(e.provider, r || e.item);210}211212public $disposeVisualizedTree(element: number): void {213const root = this._debugVisualizationElements.get(element);214if (!root) {215return;216}217218const queue = [root.children];219for (const children of queue) {220if (children) {221for (const child of children) {222queue.push(this._debugVisualizationElements.get(child)?.children);223this._debugVisualizationElements.delete(child);224}225}226}227}228229private convertVisualizerTreeItem(treeId: string, item: vscode.DebugTreeItem): IDebugVisualizationTreeItem {230let id = this._debugVisualizationTreeItemIds.get(item);231if (!id) {232id = this._debugVisualizationTreeItemIdsCounter++;233this._debugVisualizationTreeItemIds.set(item, id);234this._debugVisualizationElements.set(id, { provider: treeId, item });235}236237return Convert.DebugTreeItem.from(item, id);238}239240public asDebugSourceUri(src: vscode.DebugProtocolSource, session?: vscode.DebugSession): URI {241242const source = <any>src;243244if (typeof source.sourceReference === 'number' && source.sourceReference > 0) {245// src can be retrieved via DAP's "source" request246247let debug = `debug:${encodeURIComponent(source.path || '')}`;248let sep = '?';249250if (session) {251debug += `${sep}session=${encodeURIComponent(session.id)}`;252sep = '&';253}254255debug += `${sep}ref=${source.sourceReference}`;256257return URI.parse(debug);258} else if (source.path) {259// src is just a local file path260return URI.file(source.path);261} else {262throw new Error(`cannot create uri from DAP 'source' object; properties 'path' and 'sourceReference' are both missing.`);263}264}265266private registerAllDebugTypes(extensionRegistry: ExtensionDescriptionRegistry) {267268const debugTypes: string[] = [];269270for (const ed of extensionRegistry.getAllExtensionDescriptions()) {271if (ed.contributes) {272const debuggers = <IDebuggerContribution[]>ed.contributes['debuggers'];273if (debuggers && debuggers.length > 0) {274for (const dbg of debuggers) {275if (isDebuggerMainContribution(dbg)) {276debugTypes.push(dbg.type);277}278}279}280}281}282283this._debugServiceProxy.$registerDebugTypes(debugTypes);284}285286// extension debug API287288289get activeStackItem(): vscode.DebugThread | vscode.DebugStackFrame | undefined {290return this._activeStackItem;291}292293get onDidChangeActiveStackItem(): Event<vscode.DebugThread | vscode.DebugStackFrame | undefined> {294return this._onDidChangeActiveStackItem.event;295}296297get onDidChangeBreakpoints(): Event<vscode.BreakpointsChangeEvent> {298return this._onDidChangeBreakpoints.event;299}300301get breakpoints(): vscode.Breakpoint[] {302const result: vscode.Breakpoint[] = [];303this._breakpoints.forEach(bp => result.push(bp));304return result;305}306307public async $resolveDebugVisualizer(id: number, token: CancellationToken): Promise<MainThreadDebugVisualization> {308const visualizer = this._visualizers.get(id);309if (!visualizer) {310throw new Error(`No debug visualizer found with id '${id}'`);311}312313let { v, provider, extensionId } = visualizer;314if (!v.visualization) {315v = await provider.resolveDebugVisualization?.(v, token) || v;316visualizer.v = v;317}318319if (!v.visualization) {320throw new Error(`No visualization returned from resolveDebugVisualization in '${provider}'`);321}322323return this.serializeVisualization(extensionId, v.visualization)!;324}325326public async $executeDebugVisualizerCommand(id: number): Promise<void> {327const visualizer = this._visualizers.get(id);328if (!visualizer) {329throw new Error(`No debug visualizer found with id '${id}'`);330}331332const command = visualizer.v.visualization;333if (command && 'command' in command) {334this._commands.executeCommand(command.command, ...(command.arguments || []));335}336}337338private hydrateVisualizationContext(context: IDebugVisualizationContext): vscode.DebugVisualizationContext | undefined {339const session = this._debugSessions.get(context.sessionId);340return session && {341session: session.api,342variable: context.variable,343containerId: context.containerId,344frameId: context.frameId,345threadId: context.threadId,346};347}348349public async $provideDebugVisualizers(extensionId: string, id: string, context: IDebugVisualizationContext, token: CancellationToken): Promise<IDebugVisualization.Serialized[]> {350const contextHydrated = this.hydrateVisualizationContext(context);351const key = this.extensionVisKey(extensionId, id);352const provider = this._debugVisualizationProviders.get(key);353if (!contextHydrated || !provider) {354return []; // probably ended in the meantime355}356357const visualizations = await provider.provideDebugVisualization(contextHydrated, token);358359if (!visualizations) {360return [];361}362363return visualizations.map(v => {364const id = ++this._visualizerIdCounter;365this._visualizers.set(id, { v, provider, extensionId });366const icon = v.iconPath ? this.getIconPathOrClass(v.iconPath) : undefined;367return {368id,369name: v.name,370iconClass: icon?.iconClass,371iconPath: icon?.iconPath,372visualization: this.serializeVisualization(extensionId, v.visualization),373};374});375}376377public $disposeDebugVisualizers(ids: number[]): void {378for (const id of ids) {379this._visualizers.delete(id);380}381}382383public registerDebugVisualizationProvider<T extends vscode.DebugVisualization>(manifest: IExtensionDescription, id: string, provider: vscode.DebugVisualizationProvider<T>): vscode.Disposable {384if (!manifest.contributes?.debugVisualizers?.some(r => r.id === id)) {385throw new Error(`Extensions may only call registerDebugVisualizationProvider() for renderers they contribute (got ${id})`);386}387388const extensionId = ExtensionIdentifier.toKey(manifest.identifier);389const key = this.extensionVisKey(extensionId, id);390if (this._debugVisualizationProviders.has(key)) {391throw new Error(`A debug visualization provider with id '${id}' is already registered`);392}393394this._debugVisualizationProviders.set(key, provider);395this._debugServiceProxy.$registerDebugVisualizer(extensionId, id);396return toDisposable(() => {397this._debugServiceProxy.$unregisterDebugVisualizer(extensionId, id);398this._debugVisualizationProviders.delete(id);399});400}401402public addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void> {403// filter only new breakpoints404const breakpoints = breakpoints0.filter(bp => {405const id = bp.id;406if (!this._breakpoints.has(id)) {407this._breakpoints.set(id, bp);408return true;409}410return false;411});412413// send notification for added breakpoints414this.fireBreakpointChanges(breakpoints, [], []);415416// convert added breakpoints to DTOs417const dtos: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto> = [];418const map = new Map<string, ISourceMultiBreakpointDto>();419for (const bp of breakpoints) {420if (bp instanceof SourceBreakpoint) {421let dto = map.get(bp.location.uri.toString());422if (!dto) {423dto = {424type: 'sourceMulti',425uri: bp.location.uri,426lines: []427} satisfies ISourceMultiBreakpointDto;428map.set(bp.location.uri.toString(), dto);429dtos.push(dto);430}431dto.lines.push({432id: bp.id,433enabled: bp.enabled,434condition: bp.condition,435hitCondition: bp.hitCondition,436logMessage: bp.logMessage,437line: bp.location.range.start.line,438character: bp.location.range.start.character,439mode: bp.mode,440});441} else if (bp instanceof FunctionBreakpoint) {442dtos.push({443type: 'function',444id: bp.id,445enabled: bp.enabled,446hitCondition: bp.hitCondition,447logMessage: bp.logMessage,448condition: bp.condition,449functionName: bp.functionName,450mode: bp.mode,451});452}453}454455// send DTOs to VS Code456return this._debugServiceProxy.$registerBreakpoints(dtos);457}458459public removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void> {460// remove from array461const breakpoints = breakpoints0.filter(b => this._breakpoints.delete(b.id));462463// send notification464this.fireBreakpointChanges([], breakpoints, []);465466// unregister with VS Code467const ids = breakpoints.filter(bp => bp instanceof SourceBreakpoint).map(bp => bp.id);468const fids = breakpoints.filter(bp => bp instanceof FunctionBreakpoint).map(bp => bp.id);469const dids = breakpoints.filter(bp => bp instanceof DataBreakpoint).map(bp => bp.id);470return this._debugServiceProxy.$unregisterBreakpoints(ids, fids, dids);471}472473public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean> {474const testRunMeta = options.testRun && this._testing.getMetadataForRun(options.testRun);475476return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {477parentSessionID: options.parentSession ? options.parentSession.id : undefined,478lifecycleManagedByParent: options.lifecycleManagedByParent,479repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',480noDebug: options.noDebug,481compact: options.compact,482suppressSaveBeforeStart: options.suppressSaveBeforeStart,483testRun: testRunMeta && {484runId: testRunMeta.runId,485taskId: testRunMeta.taskId,486},487488// Check debugUI for back-compat, #147264489suppressDebugStatusbar: options.suppressDebugStatusbar ?? (options as any).debugUI?.simple,490suppressDebugToolbar: options.suppressDebugToolbar ?? (options as any).debugUI?.simple,491suppressDebugView: options.suppressDebugView ?? (options as any).debugUI?.simple,492});493}494495public stopDebugging(session?: vscode.DebugSession): Promise<void> {496return this._debugServiceProxy.$stopDebugging(session ? session.id : undefined);497}498499public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable {500501if (!provider) {502return new Disposable(() => { });503}504505const handle = this._configProviderHandleCounter++;506this._configProviders.push({ type, handle, provider });507508this._debugServiceProxy.$registerDebugConfigurationProvider(type, trigger,509!!provider.provideDebugConfigurations,510!!provider.resolveDebugConfiguration,511!!provider.resolveDebugConfigurationWithSubstitutedVariables,512handle);513514return new Disposable(() => {515this._configProviders = this._configProviders.filter(p => p.provider !== provider); // remove516this._debugServiceProxy.$unregisterDebugConfigurationProvider(handle);517});518}519520public registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable {521522if (!factory) {523return new Disposable(() => { });524}525526// a DebugAdapterDescriptorFactory can only be registered in the extension that contributes the debugger527if (!this.definesDebugType(extension, type)) {528throw new Error(`a DebugAdapterDescriptorFactory can only be registered from the extension that defines the '${type}' debugger.`);529}530531// make sure that only one factory for this type is registered532if (this.getAdapterDescriptorFactoryByType(type)) {533throw new Error(`a DebugAdapterDescriptorFactory can only be registered once per a type.`);534}535536const handle = this._adapterFactoryHandleCounter++;537this._adapterFactories.push({ type, handle, factory });538539this._debugServiceProxy.$registerDebugAdapterDescriptorFactory(type, handle);540541return new Disposable(() => {542this._adapterFactories = this._adapterFactories.filter(p => p.factory !== factory); // remove543this._debugServiceProxy.$unregisterDebugAdapterDescriptorFactory(handle);544});545}546547public registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable {548549if (!factory) {550return new Disposable(() => { });551}552553const handle = this._trackerFactoryHandleCounter++;554this._trackerFactories.push({ type, handle, factory });555556return new Disposable(() => {557this._trackerFactories = this._trackerFactories.filter(p => p.factory !== factory); // remove558});559}560561// RPC methods (ExtHostDebugServiceShape)562563public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined> {564return Promise.resolve(undefined);565}566567public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise<IConfig> {568let ws: IWorkspaceFolder | undefined;569const folder = await this.getFolder(folderUri);570if (folder) {571ws = {572uri: folder.uri,573name: folder.name,574index: folder.index,575toResource: () => {576throw new Error('Not implemented');577}578};579}580const variableResolver = await this._variableResolver.getResolver();581return variableResolver.resolveAsync(ws, config);582}583584protected createDebugAdapter(adapter: vscode.DebugAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined {585if (adapter instanceof DebugAdapterInlineImplementation) {586return new DirectDebugAdapter(adapter.implementation);587}588return undefined;589}590591protected createSignService(): ISignService | undefined {592return undefined;593}594595public async $startDASession(debugAdapterHandle: number, sessionDto: IDebugSessionDto): Promise<void> {596const mythis = this;597598const session = await this.getSession(sessionDto);599600return this.getAdapterDescriptor(this.getAdapterDescriptorFactoryByType(session.type), session).then(daDescriptor => {601602if (!daDescriptor) {603throw new Error(`Couldn't find a debug adapter descriptor for debug type '${session.type}' (extension might have failed to activate)`);604}605606const da = this.createDebugAdapter(daDescriptor, session);607if (!da) {608throw new Error(`Couldn't create a debug adapter for type '${session.type}'.`);609}610611const debugAdapter = da;612613this._debugAdapters.set(debugAdapterHandle, debugAdapter);614615return this.getDebugAdapterTrackers(session).then(tracker => {616617if (tracker) {618this._debugAdaptersTrackers.set(debugAdapterHandle, tracker);619}620621debugAdapter.onMessage(async message => {622623if (message.type === 'request' && (<DebugProtocol.Request>message).command === 'handshake') {624625const request = <DebugProtocol.Request>message;626627const response: DebugProtocol.Response = {628type: 'response',629seq: 0,630command: request.command,631request_seq: request.seq,632success: true633};634635if (!this._signService) {636this._signService = this.createSignService();637}638639try {640if (this._signService) {641const signature = await this._signService.sign(request.arguments.value);642response.body = {643signature: signature644};645debugAdapter.sendResponse(response);646} else {647throw new Error('no signer');648}649} catch (e) {650response.success = false;651response.message = e.message;652debugAdapter.sendResponse(response);653}654} else {655if (tracker && tracker.onDidSendMessage) {656tracker.onDidSendMessage(message);657}658659// DA -> VS Code660try {661// Try to catch details for #233167662message = convertToVSCPaths(message, true);663} catch (e) {664const type = message.type + '_' + ((message as any).command ?? (message as any).event ?? '');665this._telemetryProxy.$publicLog2<DebugProtocolMessageErrorEvent, DebugProtocolMessageErrorClassification>('debugProtocolMessageError', { type, from: session.type });666throw e;667}668669mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message);670}671});672debugAdapter.onError(err => {673if (tracker && tracker.onError) {674tracker.onError(err);675}676this._debugServiceProxy.$acceptDAError(debugAdapterHandle, err.name, err.message, err.stack);677});678debugAdapter.onExit((code: number | null) => {679if (tracker && tracker.onExit) {680tracker.onExit(code ?? undefined, undefined);681}682this._debugServiceProxy.$acceptDAExit(debugAdapterHandle, code ?? undefined, undefined);683});684685if (tracker && tracker.onWillStartSession) {686tracker.onWillStartSession();687}688689return debugAdapter.startSession();690});691});692}693694public $sendDAMessage(debugAdapterHandle: number, message: DebugProtocol.ProtocolMessage): void {695696// VS Code -> DA697message = convertToDAPaths(message, false);698699const tracker = this._debugAdaptersTrackers.get(debugAdapterHandle); // TODO@AW: same handle?700if (tracker && tracker.onWillReceiveMessage) {701tracker.onWillReceiveMessage(message);702}703704const da = this._debugAdapters.get(debugAdapterHandle);705da?.sendMessage(message);706}707708public $stopDASession(debugAdapterHandle: number): Promise<void> {709710const tracker = this._debugAdaptersTrackers.get(debugAdapterHandle);711this._debugAdaptersTrackers.delete(debugAdapterHandle);712if (tracker && tracker.onWillStopSession) {713tracker.onWillStopSession();714}715716const da = this._debugAdapters.get(debugAdapterHandle);717this._debugAdapters.delete(debugAdapterHandle);718if (da) {719return da.stopSession();720} else {721return Promise.resolve(void 0);722}723}724725public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {726727const a: vscode.Breakpoint[] = [];728const r: vscode.Breakpoint[] = [];729const c: vscode.Breakpoint[] = [];730731if (delta.added) {732for (const bpd of delta.added) {733const id = bpd.id;734if (id && !this._breakpoints.has(id)) {735let bp: Breakpoint;736if (bpd.type === 'function') {737bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);738} else if (bpd.type === 'data') {739bp = new DataBreakpoint(bpd.label, bpd.dataId, bpd.canPersist, bpd.enabled, bpd.hitCondition, bpd.condition, bpd.logMessage, bpd.mode);740} else {741const uri = URI.revive(bpd.uri);742bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);743}744setBreakpointId(bp, id);745this._breakpoints.set(id, bp);746a.push(bp);747}748}749}750751if (delta.removed) {752for (const id of delta.removed) {753const bp = this._breakpoints.get(id);754if (bp) {755this._breakpoints.delete(id);756r.push(bp);757}758}759}760761if (delta.changed) {762for (const bpd of delta.changed) {763if (bpd.id) {764const bp = this._breakpoints.get(bpd.id);765if (bp) {766if (bp instanceof FunctionBreakpoint && bpd.type === 'function') {767const fbp = <any>bp;768fbp.enabled = bpd.enabled;769fbp.condition = bpd.condition;770fbp.hitCondition = bpd.hitCondition;771fbp.logMessage = bpd.logMessage;772fbp.functionName = bpd.functionName;773} else if (bp instanceof SourceBreakpoint && bpd.type === 'source') {774const sbp = <any>bp;775sbp.enabled = bpd.enabled;776sbp.condition = bpd.condition;777sbp.hitCondition = bpd.hitCondition;778sbp.logMessage = bpd.logMessage;779sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character));780}781c.push(bp);782}783}784}785}786787this.fireBreakpointChanges(a, r, c);788}789790public async $acceptStackFrameFocus(focusDto: IThreadFocusDto | IStackFrameFocusDto | undefined): Promise<void> {791let focus: vscode.DebugThread | vscode.DebugStackFrame | undefined;792if (focusDto) {793const session = await this.getSession(focusDto.sessionId);794if (focusDto.kind === 'thread') {795focus = new DebugThread(session.api, focusDto.threadId);796} else {797focus = new DebugStackFrame(session.api, focusDto.threadId, focusDto.frameId);798}799}800801this._activeStackItem = focus;802this._onDidChangeActiveStackItem.fire(this._activeStackItem);803}804805public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined, token: CancellationToken): Promise<vscode.DebugConfiguration[]> {806return asPromise(async () => {807const provider = this.getConfigProviderByHandle(configProviderHandle);808if (!provider) {809throw new Error('no DebugConfigurationProvider found');810}811if (!provider.provideDebugConfigurations) {812throw new Error('DebugConfigurationProvider has no method provideDebugConfigurations');813}814const folder = await this.getFolder(folderUri);815return provider.provideDebugConfigurations(folder, token);816}).then(debugConfigurations => {817if (!debugConfigurations) {818throw new Error('nothing returned from DebugConfigurationProvider.provideDebugConfigurations');819}820return debugConfigurations;821});822}823824public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {825return asPromise(async () => {826const provider = this.getConfigProviderByHandle(configProviderHandle);827if (!provider) {828throw new Error('no DebugConfigurationProvider found');829}830if (!provider.resolveDebugConfiguration) {831throw new Error('DebugConfigurationProvider has no method resolveDebugConfiguration');832}833const folder = await this.getFolder(folderUri);834return provider.resolveDebugConfiguration(folder, debugConfiguration, token);835});836}837838public $resolveDebugConfigurationWithSubstitutedVariables(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {839return asPromise(async () => {840const provider = this.getConfigProviderByHandle(configProviderHandle);841if (!provider) {842throw new Error('no DebugConfigurationProvider found');843}844if (!provider.resolveDebugConfigurationWithSubstitutedVariables) {845throw new Error('DebugConfigurationProvider has no method resolveDebugConfigurationWithSubstitutedVariables');846}847const folder = await this.getFolder(folderUri);848return provider.resolveDebugConfigurationWithSubstitutedVariables(folder, debugConfiguration, token);849});850}851852public async $provideDebugAdapter(adapterFactoryHandle: number, sessionDto: IDebugSessionDto): Promise<Dto<IAdapterDescriptor>> {853const adapterDescriptorFactory = this.getAdapterDescriptorFactoryByHandle(adapterFactoryHandle);854if (!adapterDescriptorFactory) {855return Promise.reject(new Error('no adapter descriptor factory found for handle'));856}857const session = await this.getSession(sessionDto);858return this.getAdapterDescriptor(adapterDescriptorFactory, session).then(adapterDescriptor => {859if (!adapterDescriptor) {860throw new Error(`Couldn't find a debug adapter descriptor for debug type '${session.type}'`);861}862return this.convertToDto(adapterDescriptor);863});864}865866public async $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): Promise<void> {867const session = await this.getSession(sessionDto);868this._onDidStartDebugSession.fire(session.api);869}870871public async $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): Promise<void> {872const session = await this.getSession(sessionDto);873if (session) {874this._onDidTerminateDebugSession.fire(session.api);875this._debugSessions.delete(session.id);876}877}878879public async $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto | undefined): Promise<void> {880this._activeDebugSession = sessionDto ? await this.getSession(sessionDto) : undefined;881this._onDidChangeActiveDebugSession.fire(this._activeDebugSession?.api);882}883884public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise<void> {885const session = await this.getSession(sessionDto);886session?._acceptNameChanged(name);887}888889public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise<void> {890const session = await this.getSession(sessionDto);891const ee: vscode.DebugSessionCustomEvent = {892session: session.api,893event: event.event,894body: event.body895};896this._onDidReceiveDebugSessionCustomEvent.fire(ee);897}898899// private & dto helpers900901private convertToDto(x: vscode.DebugAdapterDescriptor): Dto<IAdapterDescriptor> {902if (x instanceof DebugAdapterExecutable) {903return this.convertExecutableToDto(x);904} else if (x instanceof DebugAdapterServer) {905return this.convertServerToDto(x);906} else if (x instanceof DebugAdapterNamedPipeServer) {907return this.convertPipeServerToDto(x);908} else if (x instanceof DebugAdapterInlineImplementation) {909return this.convertImplementationToDto(x);910} else {911throw new Error('convertToDto unexpected type');912}913}914915protected convertExecutableToDto(x: DebugAdapterExecutable): IDebugAdapterExecutable {916return {917type: 'executable',918command: x.command,919args: x.args,920options: x.options921};922}923924protected convertServerToDto(x: DebugAdapterServer): IDebugAdapterServer {925return {926type: 'server',927port: x.port,928host: x.host929};930}931932protected convertPipeServerToDto(x: DebugAdapterNamedPipeServer): IDebugAdapterNamedPipeServer {933return {934type: 'pipeServer',935path: x.path936};937}938939protected convertImplementationToDto(x: DebugAdapterInlineImplementation): IDebugAdapterImpl {940return {941type: 'implementation',942};943}944945private getAdapterDescriptorFactoryByType(type: string): vscode.DebugAdapterDescriptorFactory | undefined {946const results = this._adapterFactories.filter(p => p.type === type);947if (results.length > 0) {948return results[0].factory;949}950return undefined;951}952953private getAdapterDescriptorFactoryByHandle(handle: number): vscode.DebugAdapterDescriptorFactory | undefined {954const results = this._adapterFactories.filter(p => p.handle === handle);955if (results.length > 0) {956return results[0].factory;957}958return undefined;959}960961private getConfigProviderByHandle(handle: number): vscode.DebugConfigurationProvider | undefined {962const results = this._configProviders.filter(p => p.handle === handle);963if (results.length > 0) {964return results[0].provider;965}966return undefined;967}968969private definesDebugType(ed: IExtensionDescription, type: string) {970if (ed.contributes) {971const debuggers = ed.contributes['debuggers'];972if (debuggers && debuggers.length > 0) {973for (const dbg of debuggers) {974// only debugger contributions with a "label" are considered a "defining" debugger contribution975if (dbg.label && dbg.type) {976if (dbg.type === type) {977return true;978}979}980}981}982}983return false;984}985986private getDebugAdapterTrackers(session: ExtHostDebugSession): Promise<vscode.DebugAdapterTracker | undefined> {987988const config = session.configuration;989const type = config.type;990991const promises = this._trackerFactories992.filter(tuple => tuple.type === type || tuple.type === '*')993.map(tuple => asPromise<vscode.ProviderResult<vscode.DebugAdapterTracker>>(() => tuple.factory.createDebugAdapterTracker(session.api)).then(p => p, err => null));994995return Promise.race([996Promise.all(promises).then(result => {997const trackers = coalesce(result); // filter null998if (trackers.length > 0) {999return new MultiTracker(trackers);1000}1001return undefined;1002}),1003new Promise<undefined>(resolve => setTimeout(() => resolve(undefined), 1000)),1004]).catch(err => {1005// ignore errors1006return undefined;1007});1008}10091010private async getAdapterDescriptor(adapterDescriptorFactory: vscode.DebugAdapterDescriptorFactory | undefined, session: ExtHostDebugSession): Promise<vscode.DebugAdapterDescriptor | undefined> {10111012// a "debugServer" attribute in the launch config takes precedence1013const serverPort = session.configuration.debugServer;1014if (typeof serverPort === 'number') {1015return Promise.resolve(new DebugAdapterServer(serverPort));1016}10171018if (adapterDescriptorFactory) {1019const extensionRegistry = await this._extensionService.getExtensionRegistry();1020return asPromise(() => adapterDescriptorFactory.createDebugAdapterDescriptor(session.api, this.daExecutableFromPackage(session, extensionRegistry))).then(daDescriptor => {1021if (daDescriptor) {1022return daDescriptor;1023}1024return undefined;1025});1026}10271028// fallback: use executable information from package.json1029const extensionRegistry = await this._extensionService.getExtensionRegistry();1030return Promise.resolve(this.daExecutableFromPackage(session, extensionRegistry));1031}10321033protected daExecutableFromPackage(session: ExtHostDebugSession, extensionRegistry: ExtensionDescriptionRegistry): DebugAdapterExecutable | undefined {1034return undefined;1035}10361037private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) {1038if (added.length > 0 || removed.length > 0 || changed.length > 0) {1039this._onDidChangeBreakpoints.fire(Object.freeze({1040added,1041removed,1042changed,1043}));1044}1045}10461047private async getSession(dto: IDebugSessionDto): Promise<ExtHostDebugSession> {1048if (dto) {1049if (typeof dto === 'string') {1050const ds = this._debugSessions.get(dto);1051if (ds) {1052return ds;1053}1054} else {1055let ds = this._debugSessions.get(dto.id);1056if (!ds) {1057const folder = await this.getFolder(dto.folderUri);1058const parent = dto.parent ? this._debugSessions.get(dto.parent) : undefined;1059ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration, parent?.api);1060this._debugSessions.set(ds.id, ds);1061this._debugServiceProxy.$sessionCached(ds.id);1062}1063return ds;1064}1065}1066throw new Error('cannot find session');1067}10681069private getFolder(_folderUri: UriComponents | undefined): Promise<vscode.WorkspaceFolder | undefined> {1070if (_folderUri) {1071const folderURI = URI.revive(_folderUri);1072return this._workspaceService.resolveWorkspaceFolder(folderURI);1073}1074return Promise.resolve(undefined);1075}10761077private extensionVisKey(extensionId: string, id: string) {1078return `${extensionId}\0${id}`;1079}10801081private serializeVisualization(extensionId: string, viz: vscode.DebugVisualization['visualization']): MainThreadDebugVisualization | undefined {1082if (!viz) {1083return undefined;1084}10851086if ('title' in viz && 'command' in viz) {1087return { type: DebugVisualizationType.Command };1088}10891090if ('treeId' in viz) {1091return { type: DebugVisualizationType.Tree, id: `${extensionId}\0${viz.treeId}` };1092}10931094throw new Error('Unsupported debug visualization type');1095}10961097private getIconPathOrClass(icon: vscode.DebugVisualization['iconPath']) {1098const iconPathOrIconClass = this.getIconUris(icon);1099let iconPath: { dark: URI; light?: URI | undefined } | undefined;1100let iconClass: string | undefined;1101if ('id' in iconPathOrIconClass) {1102iconClass = ThemeIconUtils.asClassName(iconPathOrIconClass);1103} else {1104iconPath = iconPathOrIconClass;1105}11061107return {1108iconPath,1109iconClass1110};1111}11121113private getIconUris(iconPath: vscode.DebugVisualization['iconPath']): { dark: URI; light?: URI } | { id: string } {1114if (iconPath instanceof ThemeIcon) {1115return { id: iconPath.id };1116}1117const dark = typeof iconPath === 'object' && 'dark' in iconPath ? iconPath.dark : iconPath;1118const light = typeof iconPath === 'object' && 'light' in iconPath ? iconPath.light : iconPath;1119return {1120dark: (typeof dark === 'string' ? URI.file(dark) : dark) as URI,1121light: (typeof light === 'string' ? URI.file(light) : light) as URI,1122};1123}1124}11251126export class ExtHostDebugSession {1127private apiSession?: vscode.DebugSession;1128constructor(1129private _debugServiceProxy: MainThreadDebugServiceShape,1130private _id: DebugSessionUUID,1131private _type: string,1132private _name: string,1133private _workspaceFolder: vscode.WorkspaceFolder | undefined,1134private _configuration: vscode.DebugConfiguration,1135private _parentSession: vscode.DebugSession | undefined) {1136}11371138public get api(): vscode.DebugSession {1139const that = this;1140return this.apiSession ??= Object.freeze({1141id: that._id,1142type: that._type,1143get name() {1144return that._name;1145},1146set name(name: string) {1147that._name = name;1148that._debugServiceProxy.$setDebugSessionName(that._id, name);1149},1150parentSession: that._parentSession,1151workspaceFolder: that._workspaceFolder,1152configuration: that._configuration,1153customRequest(command: string, args: any): Promise<any> {1154return that._debugServiceProxy.$customDebugAdapterRequest(that._id, command, args);1155},1156getDebugProtocolBreakpoint(breakpoint: vscode.Breakpoint): Promise<vscode.DebugProtocolBreakpoint | undefined> {1157return that._debugServiceProxy.$getDebugProtocolBreakpoint(that._id, breakpoint.id);1158}1159});1160}11611162public get id(): string {1163return this._id;1164}11651166public get type(): string {1167return this._type;1168}11691170_acceptNameChanged(name: string) {1171this._name = name;1172}11731174public get configuration(): vscode.DebugConfiguration {1175return this._configuration;1176}1177}11781179export class ExtHostDebugConsole {11801181readonly value: vscode.DebugConsole;11821183constructor(proxy: MainThreadDebugServiceShape) {11841185this.value = Object.freeze({1186append(value: string): void {1187proxy.$appendDebugConsole(value);1188},1189appendLine(value: string): void {1190this.append(value + '\n');1191}1192});1193}1194}11951196interface ConfigProviderTuple {1197type: string;1198handle: number;1199provider: vscode.DebugConfigurationProvider;1200}12011202interface DescriptorFactoryTuple {1203type: string;1204handle: number;1205factory: vscode.DebugAdapterDescriptorFactory;1206}12071208interface TrackerFactoryTuple {1209type: string;1210handle: number;1211factory: vscode.DebugAdapterTrackerFactory;1212}12131214class MultiTracker implements vscode.DebugAdapterTracker {12151216constructor(private trackers: vscode.DebugAdapterTracker[]) {1217}12181219onWillStartSession(): void {1220this.trackers.forEach(t => t.onWillStartSession ? t.onWillStartSession() : undefined);1221}12221223onWillReceiveMessage(message: any): void {1224this.trackers.forEach(t => t.onWillReceiveMessage ? t.onWillReceiveMessage(message) : undefined);1225}12261227onDidSendMessage(message: any): void {1228this.trackers.forEach(t => t.onDidSendMessage ? t.onDidSendMessage(message) : undefined);1229}12301231onWillStopSession(): void {1232this.trackers.forEach(t => t.onWillStopSession ? t.onWillStopSession() : undefined);1233}12341235onError(error: Error): void {1236this.trackers.forEach(t => t.onError ? t.onError(error) : undefined);1237}12381239onExit(code: number, signal: string): void {1240this.trackers.forEach(t => t.onExit ? t.onExit(code, signal) : undefined);1241}1242}12431244/*1245* Call directly into a debug adapter implementation1246*/1247class DirectDebugAdapter extends AbstractDebugAdapter {12481249constructor(private implementation: vscode.DebugAdapter) {1250super();12511252implementation.onDidSendMessage((message: vscode.DebugProtocolMessage) => {1253this.acceptMessage(message as DebugProtocol.ProtocolMessage);1254});1255}12561257startSession(): Promise<void> {1258return Promise.resolve(undefined);1259}12601261sendMessage(message: DebugProtocol.ProtocolMessage): void {1262this.implementation.handleMessage(message);1263}12641265stopSession(): Promise<void> {1266this.implementation.dispose();1267return Promise.resolve(undefined);1268}1269}127012711272export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {1273constructor(1274@IExtHostRpcService extHostRpcService: IExtHostRpcService,1275@IExtHostWorkspace workspaceService: IExtHostWorkspace,1276@IExtHostExtensionService extensionService: IExtHostExtensionService,1277@IExtHostConfiguration configurationService: IExtHostConfiguration,1278@IExtHostEditorTabs editorTabs: IExtHostEditorTabs,1279@IExtHostVariableResolverProvider variableResolver: IExtHostVariableResolverProvider,1280@IExtHostCommands commands: IExtHostCommands,1281@IExtHostTesting testing: IExtHostTesting,1282) {1283super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands, testing);1284}1285}12861287// Collecting info for #233167 specifically1288type DebugProtocolMessageErrorClassification = {1289from: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The type of the debug adapter that the event is from.' };1290type: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The type of the event that was malformed.' };1291owner: 'roblourens';1292comment: 'Sent to collect details about misbehaving debug extensions.';1293};12941295type DebugProtocolMessageErrorEvent = {1296from: string;1297type: string;1298};129913001301