diff --git a/packages/connection/src/node/common-channel-handler.ts b/packages/connection/src/node/common-channel-handler.ts index c4baf378b2..b1b6260f1d 100644 --- a/packages/connection/src/node/common-channel-handler.ts +++ b/packages/connection/src/node/common-channel-handler.ts @@ -121,11 +121,10 @@ export class CommonChannelHandler extends WebSocketHandler { // 心跳消息 if (msgObj.kind === 'heartbeat') { - // console.log(`heartbeat msg ${msgObj.clientId}`) connection.send(stringify(`heartbeat ${msgObj.clientId}`)); } else if (msgObj.kind === 'client') { const clientId = msgObj.clientId; - this.logger.log('new connection clientId', clientId); + this.logger.log(`New connection with id ${clientId}`); connectionId = clientId; this.connectionMap.set(clientId, connection); this.hearbeat(connectionId, connection); @@ -133,7 +132,7 @@ export class CommonChannelHandler extends WebSocketHandler { } else if (msgObj.kind === 'open') { const channelId = msgObj.id; // CommonChannelHandler.channelId ++; const { path } = msgObj; - this.logger.log('new open channelId', channelId, 'channelPath', path); + this.logger.log(`Open a new connection channel ${channelId} with path ${path}`); // 生成 channel 对象 const connectionSend = this.channelConnectionSend(connection); @@ -162,14 +161,12 @@ export class CommonChannelHandler extends WebSocketHandler { channel.ready(); } else { - // console.log('connection message', msgObj.id, msgObj.kind, this.channelMap.get(msgObj.id)); - const { id } = msgObj; const channel = this.channelMap.get(id); if (channel) { channel.handleMessage(msgObj); } else { - this.logger.warn(`channel ${id} not found`); + this.logger.warn(`The channel(${id}) was not found`); } } } catch (e) { @@ -184,7 +181,7 @@ export class CommonChannelHandler extends WebSocketHandler { clearTimeout(this.heartbeatMap.get(connectionId) as NodeJS.Timeout); this.heartbeatMap.delete(connectionId); - this.logger.verbose(`clear heartbeat ${connectionId}`); + this.logger.verbose(`Clear heartbeat from channel ${connectionId}`); } Array.from(this.channelMap.values()) @@ -192,7 +189,7 @@ export class CommonChannelHandler extends WebSocketHandler { .forEach((channel) => { channel.close(1, 'close'); this.channelMap.delete(channel.id); - this.logger.verbose(`remove channel ${channel.id}`); + this.logger.verbose(`Remove connection channel ${channel.id}`); }); }); }); diff --git a/packages/core-node/src/connection.ts b/packages/core-node/src/connection.ts index d19438df26..6bff97f77c 100644 --- a/packages/core-node/src/connection.ts +++ b/packages/core-node/src/connection.ts @@ -37,7 +37,7 @@ export function createServerConnection2( // 事件由 connection 的时机来触发 commonChannelPathHandler.register('RPCService', { handler: (connection: WSChannel, clientId: string) => { - logger.log(`set rpc connection ${clientId}`); + logger.log(`New RPC connection ${clientId}`); const serviceCenter = new RPCServiceCenter(undefined, logger); const serviceChildInjector = bindModuleBackService(injector, modulesInstances, serviceCenter, clientId); @@ -50,10 +50,10 @@ export function createServerConnection2( serviceCenter.removeConnection(serverConnection); serviceChildInjector.disposeAll(); - logger.log(`remove rpc connection ${clientId} `); + logger.log(`Remove RPC connection ${clientId}`); }); }, - dispose: (connection: ws, connectionClientId: string) => {}, + dispose: () => {}, }); socketRoute.registerHandler(channelHandler); @@ -76,15 +76,12 @@ export function createNetServerConnection(server: net.Server, injector, modulesI ); server.on('connection', (connection) => { - logger.log('set net rpc connection'); const serverConnection = createSocketConnection(connection); serviceCenter.setConnection(serverConnection); connection.on('close', () => { serviceCenter.removeConnection(serverConnection); serviceChildInjector.disposeAll(); - - logger.log('remove net rpc connection'); }); }); @@ -97,7 +94,6 @@ export function bindModuleBackService( serviceCenter: RPCServiceCenter, clientId?: string, ) { - const logger = injector.get(INodeLogger); const { createRPCService } = initRPCService(serviceCenter); const childInjector = injector.createChild(); @@ -105,7 +101,6 @@ export function bindModuleBackService( if (module.backServices) { for (const service of module.backServices) { if (service.token) { - logger.log('back service', service.token); const serviceToken = service.token; if (!injector.creatorMap.has(serviceToken)) { diff --git a/packages/extension/src/browser/extension-node.service.ts b/packages/extension/src/browser/extension-node.service.ts index 77afc0d544..5863fe2496 100644 --- a/packages/extension/src/browser/extension-node.service.ts +++ b/packages/extension/src/browser/extension-node.service.ts @@ -20,6 +20,7 @@ import { } from '@opensumi/ide-core-browser'; import { + CONNECTION_HANDLE_BETWEEN_EXTENSION_AND_MAIN_THREAD, ExtensionNodeServiceServerPath, IExtension, IExtensionHostService, @@ -172,7 +173,7 @@ export class NodeExtProcessService implements AbstractNodeExtProcessService; + getAllExtensions( + scan: string[], + extensionCandidate: string[], + localization: string, + extraMetaData: IExtraMetaData, + ): Promise; + createProcess(clientId: string, options?: ICreateProcessOptions): Promise; + ensureProcessReady(clientId: string): Promise; + getElectronMainThreadListenPath(clientId: string): Promise; + getElectronMainThreadListenPath2(clientId: string): Promise; + getExtServerListenOption(clientId: string); + getExtension( + extensionPath: string, + localization: string, + extraMetaData?: IExtraMetaData, + ): Promise; + setConnectionServiceClient(clientId: string, serviceClient: IExtensionNodeClientService); + disposeClientExtProcess(clientId: string, info: boolean): Promise; + disposeAllClientExtProcess(): Promise; + tryEnableInspectPort(clientId: string, delay?: number): Promise; + getProcessInspectPort(clientId: string): Promise; +} + +export const IExtensionNodeClientService = Symbol('IExtensionNodeClientService'); +export interface IExtensionNodeClientService { + getElectronMainThreadListenPath(clientId: string): Promise; + getAllExtensions( + scan: string[], + extensionCandidate: string[], + localization: string, + extraMetaData: IExtraMetaData, + ): Promise; + createProcess(clientId: string, options: ICreateProcessOptions): Promise; + getExtension( + extensionPath: string, + localization: string, + extraMetaData?: IExtraMetaData, + ): Promise; + infoProcessNotExist(): void; + infoProcessCrash(): void; + restartExtProcessByClient(): void; + disposeClientExtProcess(clientId: string, info: boolean): Promise; + updateLanguagePack(languageId: string, languagePackPath: string, storagePath: string): Promise; + getOpenVSXRegistry(): Promise; +} + +export type ExtensionHostType = 'node' | 'worker'; + +export type ExtensionHostTypeUpperCase = 'Node.js' | 'Web Worker'; + +export interface ChangeExtensionOptions { + upgrade: boolean; + extensionPath: string; + oldExtensionPath?: string; + isBuiltin?: boolean; +} + +/** + * 管理不同进程内插件注册的 command 的运行环境及其调用 + */ +export abstract class IExtCommandManagement { + abstract registerProxyCommandExecutor(env: ExtensionHostType, proxyCommandExecutor: IMainThreadCommands): void; + abstract executeExtensionCommand(env: ExtensionHostType, command: string, args: any[]): Promise; + /** + * @param command command id + * @param targetHost 目标插件进程的运行环境,默认 'node' + */ + abstract registerExtensionCommandEnv(command: string, targetHost?: ExtensionHostType): IDisposable; + abstract getExtensionCommandEnv(command: string): ExtensionHostType | undefined; +} + +/** + * 为插件市场面板提供数据/交互 + */ +export abstract class AbstractExtensionManagementService { + /** + * @deprecated 建议直接用 AbstractExtInstanceManagementService#getExtensionInstances 后自行 map#toJSON 即可 + */ + abstract getAllExtensionJson(): IExtensionProps[]; + + /** + * 禁用插件 + */ + abstract postDisableExtension(extensionPath: string): Promise; + + /** + * 启用插件 + */ + abstract postEnableExtension(extensionPath: string): Promise; + + /** + * 安装插件之后开始激活 + */ + abstract postChangedExtension(options: ChangeExtensionOptions): Promise; + abstract postChangedExtension(upgrade: boolean, extensionPath: string, oldExtensionPath?: string): Promise; + abstract postChangedExtension( + upgrade: boolean | ChangeExtensionOptions, + extensionPath?: string, + oldExtensionPath?: string, + ): Promise; + + /** + * 卸载插件 + */ + abstract postUninstallExtension(extensionPath: string): Promise; + + /** + * 通过 extensionPath 获取插件实例 + */ + abstract getExtensionByPath(extensionPath: string): IExtension | undefined; + /** + * 通过 extension id 获取插件实例 + */ + abstract getExtensionByExtId(extensionId: string): IExtension | undefined; + + /** + * 通过 extensionPath 获取插件实例序列化数据及从 node 层获取的 extraMetadata + */ + abstract getExtensionProps( + extensionPath: string, + extraMetaData?: IExtraMetaData, + ): Promise; +} + +export abstract class ExtensionService { + /** + * 激活插件服务 + */ + abstract activate(): Promise; + + /** + * 重启插件进程 + */ + abstract restartExtProcess(): Promise; + + /** + * 激活插件, 给 Extension 实例使用 + */ + abstract activeExtension(extension: IExtension): Promise; + + /** + * 销毁插件 + */ + abstract disposeExtensions(): Promise; + + /** + * 执行插件命令 + */ + abstract executeExtensionCommand(command: string, args: any[]): Promise; + + /** + * @internal 提供获取所有运行中的插件的列表数据 + */ + abstract getActivatedExtensions(): Promise<{ [key in ExtensionHostType]?: ActivatedExtension[] }>; + + abstract runExtensionContributes(): Promise; + + eagerExtensionsActivated: Deferred; +} + +export abstract class ExtensionCapabilityRegistry { + abstract getAllExtensions(): Promise; +} + +export const LANGUAGE_BUNDLE_FIELD = 'languageBundle'; + +export interface JSONType { + [key: string]: any; +} + +export interface IExtension extends IExtensionProps { + readonly contributes: IExtensionContributions & ISumiExtensionContributions; + activate(visited?: Set); + enable(): void; + reset(): void; + toJSON(): IExtensionProps; +} + +const VAR_REGEXP = /^\$\(([a-z.]+\/)?([a-z-]+)(~[a-z]+)?\)$/i; + +export interface ContributesMap { + extensionId: string; + contributes: T; +} + +export abstract class VSCodeContributePoint extends Disposable { + protected contributesMap: Array> = []; + + protected contributedMap: Array> = []; + + static schema: IJSONSchema; + + protected readonly iconService?: IIconService; + + abstract contribute(): void | Promise; + + register(extensionId: string, contributes: T) { + this.contributesMap.push({ extensionId, contributes }); + } + + hasUncontributedPoint() { + return this.contributesMap.length > 0; + } + + afterContribute() { + this.contributedMap = this.contributedMap.concat(this.contributesMap); + this.contributesMap = []; + } + + protected toIconClass( + iconContrib: { [index in ThemeType]: string } | string, + type: IconType = IconType.Mask, + basePath: string, + ): string | undefined { + if (typeof iconContrib === 'string' && VAR_REGEXP.test(iconContrib)) { + return this.iconService?.fromString(iconContrib); + } + return this.iconService?.fromIcon(basePath, iconContrib, type); + } + + protected getLocalizeFromNlsJSON(title: string, scope: string, languageId?: string): string { + return replaceNlsField(title, scope, title, languageId); + } +} + +export abstract class ExtensionContributesService extends WithEventBus { + abstract ContributionPoints: typeof VSCodeContributePoint[]; + + @Autowired(ILogger) + private logger: ILogger; + + @Autowired(AppLifeCycleServiceToken) + private lifecycleService: IAppLifeCycleService; + + @Autowired(IExtensionsSchemaService) + private readonly extensionsSchemaService: IExtensionsSchemaService; + + @Autowired(INJECTOR_TOKEN) + private injector: Injector; + + private contributedSet = new Set(); + + private getContributionCls(contributesName: string): typeof VSCodeContributePoint | undefined { + const Constructor = this.ContributionPoints.find((Constructor) => { + const k = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); + if (k === contributesName) { + return true; + } + return false; + }); + return Constructor; + } + + register(extensionId: string, contrib: JSONType) { + for (const k of Object.keys(contrib)) { + const Constructor = this.getContributionCls(k); + if (Constructor) { + const instance = this.injector.get(Constructor); + instance?.register(extensionId, contrib[k]); + } + } + } + + private async runContributesByPhase(lifeCyclePhase: LifeCyclePhase) { + const Contributes = this.ContributionPoints.filter((Constructor) => { + const phase = Reflect.getMetadata(LIFE_CYCLE_PHASE_KEY, Constructor); + const contributeName = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); + if (phase <= lifeCyclePhase && !this.contributedSet.has(contributeName)) { + this.contributedSet.add(contributeName); + return true; + } + return false; + }); + + await Promise.all( + Contributes.map(async (Constructor: typeof VSCodeContributePoint) => { + try { + const contributePoint: VSCodeContributePoint = this.injector.get(Constructor); + const contributeName = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); + this.addDispose(contributePoint); + + if (contributePoint.hasUncontributedPoint()) { + const now = Date.now(); + await contributePoint.contribute(); + contributePoint.afterContribute(); + + this.extensionsSchemaService.registerExtensionPoint({ + extensionPoint: contributeName, + jsonSchema: Constructor.schema || {}, + frameworkKind: ['vscode', 'opensumi'], + }); + + const end = Date.now() - now; + this.logger.log(`run extension contribute ${contributeName}: ${end} ms`); + } + } catch (e) { + this.logger.error(e); + } + }), + ); + } + + public initialize() { + const runContributes = (phase = this.lifecycleService.phase) => { + if (!phase) { + return; + } + + // 所有 contributionPoint 运行完后清空 + // 确保后续安装/启用插件后可以正常激活 + if (phase === LifeCyclePhase.Ready) { + this.contributedSet.clear(); + } + + this.runContributesByPhase(phase); + }; + + runContributes(); + + this.addDispose( + this.lifecycleService.onDidLifeCyclePhaseChange((newPhase) => { + runContributes(newPhase); + }), + ); + } +} + +export const CONTRIBUTE_NAME_KEY = 'contribute_name'; +export function Contributes(name) { + return (target) => { + Reflect.defineMetadata(CONTRIBUTE_NAME_KEY, name, target); + }; +} + +export const LIFE_CYCLE_PHASE_KEY = 'phase'; +export function LifeCycle(name: LifeCyclePhase) { + return (target) => { + Reflect.defineMetadata(LIFE_CYCLE_PHASE_KEY, name, target); + }; +} + +export const EXTENSION_EXTEND_SERVICE_PREFIX = 'extension_extend_service'; +export const MOCK_EXTENSION_EXTEND_PROXY_IDENTIFIER = createExtHostContextProxyIdentifier( + 'mock_extension_extend_proxy_identifier', +); + +export interface IExtensionHost { + logger: IExtensionLogger; + $activateExtension(id: string): Promise; + /** + * 更新插件进程内的插件相关数据 + */ + $updateExtHostData(): Promise; + $getActivatedExtensions(): Promise; + + getExtensionExports(id: string): any; + getExtensions(): Extension[]; + getExtension(extensionId: string): Extension | undefined; + isActivated(id: string): boolean; + activateExtension(id: string): Promise; + extensionsChangeEmitter: Emitter; + storage: ExtHostStorage; +} + +export interface IExtensionHostService extends IExtensionHost { + $fireChangeEvent(): Promise; + init(): Promise; + close(): Promise; + getExtendExports(id: string): any; + extensionsActivator: ExtensionsActivator; + /** + * 上报插件未捕获异常 + * @param error + */ + reportUnexpectedError(error: Error): void; +} + +export interface IExtensionWorkerHost extends IExtensionHost { + staticServicePath: string; +} + +export interface IExtendProxy { + [key: string]: any; +} + +export const WorkerHostAPIIdentifier = { + ExtWorkerHostExtensionService: createExtHostContextProxyIdentifier('ExtWorkerHostExtensionService'), +}; + +export enum ProcessMessageType { + REPORTER, +} + +export enum EXTENSION_ENABLE { + ENABLE = 1, + DISABLE = 0, +} + +// 广播插件事件 +export const EMIT_EXT_HOST_EVENT = { + id: 'sumi-extension:ext-host-event', +}; + +export function getExtensionId(extensionId: string) { + return extensionId.toLowerCase(); +} + +export enum ExtensionHostKind { + NODE_HOST = 1, + WORKER_HOST = 2, +} + +export const ExtensionHostProfilerServicePath = 'ExtensionHostProfilerService'; + +export const ExtensionHostProfilerServiceToken = Symbol('ExtensionHostProfilerService'); + +export interface IExtensionHostProfilerService { + $startProfile(clientId: string): Promise; + $stopProfile(clientId: string): Promise; + $saveLastProfile(filePath: string): Promise; +} + +export enum OutputType { + STDOUT, + STDERR, +} + +export interface Output { + type: OutputType; + data: string; + format: string[]; +} + +export const IExtensionHostManager = Symbol('IExtensionHostManager'); + +export interface IExtensionHostManager { + init(): MaybePromise; + fork(modulePath: string, ...args: any[]): MaybePromise; + send(pid: number, message: string): MaybePromise; + isRunning(pid: number): MaybePromise; + treeKill(pid: number): MaybePromise; + kill(pid: number, signal?: string): MaybePromise; + isKilled(pid: number): MaybePromise; + findDebugPort(startPort: number, giveUpAfter: number, timeout: number): Promise; + onOutput(pid: number, listener: (output: Output) => void): MaybePromise; + onExit(pid: number, listener: (code: number, signal: string) => void): MaybePromise; + onMessage(pid: number, listener: (msg: any) => void): MaybePromise; + disposeProcess(pid: number): MaybePromise; + dispose(): MaybePromise; +} + +/** + * 以下都是 fork 新的插件子进程的时候,传入的命令行参数的 key + */ +export const KT_PROCESS_SOCK_OPTION_KEY = 'kt-process-sock-option'; +export const KT_PROCESS_PRELOAD_KEY = 'kt-process-preload'; +export const KT_APP_CONFIG_KEY = 'kt-app-config'; + +// #region Semantic Tokens Contribution Point + +export interface SemanticTokenScopes { + scopes?: { [selector: string]: string[] }; + language?: string; +} + +export type SemanticTokenScopesSchema = Array; + +export interface SemanticTokenType { + id: string; + description: string; + superType?: string; +} + +export type SemanticTokenTypeSchema = Array; + +export interface SemanticTokenModifier { + id: string; + description: string; +} + +export type SemanticTokenModifierSchema = Array; + +export function validateTypeOrModifier( + contribution: SemanticTokenType | SemanticTokenModifier, + extensionPoint: string, + logger: ILogger, +): boolean { + if (typeof contribution.id !== 'string' || contribution.id.length === 0) { + logger.error("'configuration.{0}.id' must be defined and can not be empty", extensionPoint); + return false; + } + if (!contribution.id.match(typeAndModifierIdPattern)) { + logger.error("'configuration.{0}.id' must follow the pattern letterOrDigit[-_letterOrDigit]*"); + return false; + } + const superType = (contribution as SemanticTokenType).superType; + if (superType && !superType.match(typeAndModifierIdPattern)) { + logger.error( + "'configuration.{0}.superType' must follow the pattern letterOrDigit[-_letterOrDigit]*", + extensionPoint, + ); + return false; + } + if (typeof contribution.description !== 'string' || contribution.id.length === 0) { + logger.error("'configuration.{0}.description' must be defined and can not be empty", extensionPoint); + return false; + } + return true; +} + +// #endregion Semantic Tokens Contribution Point + +export const enum ExtensionContributePoint { + Terminal = 'terminal', +} + +// #region Walkthroughs +export interface IWalkthrough { + id: string; + title: string; + description: string; + order: number; + source: string; + isFeatured: boolean; + next?: string; + when: ContextKeyExpression; + steps: IWalkthroughStep[]; + icon: { type: 'icon'; icon: ThemeIcon } | { type: 'image'; path: string }; +} + +export type IWalkthroughLoose = Omit & { + steps: (Omit & { description: string })[]; +}; + +export interface IWalkthroughStep { + id: string; + title: string; + description: LinkedText[]; + category: string; + when: ContextKeyExpression; + order: number; + completionEvents: string[]; + media: + | { type: 'image'; path: { hcDark: URI; hcLight: URI; light: URI; dark: URI }; altText: string } + | { type: 'svg'; path: URI; altText: string } + | { type: 'markdown'; path: URI; base: URI; root: URI }; +} + +export interface StepProgress { + done: boolean; +} + +export interface IResolvedWalkthroughStep extends IWalkthroughStep, StepProgress {} + +export namespace CompletionEventsType { + export const onLink = 'onLink'; + export const onEvent = 'onEvent'; + export const onView = 'onView'; + export const onSettingChanged = 'onSettingChanged'; + export const onContext = 'onContext'; + export const onStepSelected = 'onStepSelected'; + export const stepSelected = 'stepSelected'; + export const onCommand = 'onCommand'; + export const onExtensionInstalled = 'onExtensionInstalled'; + export const extensionInstalled = 'extensionInstalled'; +} +// #endregion Walkthroughs diff --git a/packages/extension/src/common/index.ts b/packages/extension/src/common/index.ts index 79ca7f1722..d8818a742e 100644 --- a/packages/extension/src/common/index.ts +++ b/packages/extension/src/common/index.ts @@ -1,649 +1,6 @@ -import { Autowired, INJECTOR_TOKEN, Injector } from '@opensumi/di'; -import { createExtHostContextProxyIdentifier } from '@opensumi/ide-connection'; -import { - LifeCyclePhase, - Disposable, - IJSONSchema, - IDisposable, - Deferred, - Uri, - MaybePromise, - IExtensionLogger, - ExtensionConnectOption, - replaceNlsField, - ILogger, - WithEventBus, - IAppLifeCycleService, - AppLifeCycleServiceToken, - Emitter, - IExtensionProps, - IExtensionsSchemaService, - LinkedText, - URI, -} from '@opensumi/ide-core-common'; -import { typeAndModifierIdPattern } from '@opensumi/ide-theme/lib/common/semantic-tokens-registry'; -import { IconType, IIconService, ThemeType } from '@opensumi/ide-theme/lib/common/theme.service'; -import { ContextKeyExpression } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey'; - -import { ExtHostStorage } from '../hosted/api/vscode/ext.host.storage'; -import { Extension } from '../hosted/vscode.extension'; - -import { ActivatedExtension, ExtensionsActivator, ActivatedExtensionJSON } from './activator'; -import { ISumiExtensionContributions } from './sumi/extension'; -import { IExtensionContributions, IMainThreadCommands } from './vscode'; -import { ThemeIcon } from './vscode/ext-types'; - export { IExtensionProps } from '@opensumi/ide-core-common'; export * from './ext.host.proxy'; export * from './require-interceptor'; - -export interface IExtensionMetaData { - id: string; - extensionId: string; - // 支持使用自定义uri - path: string; - uri?: Uri; - packageJSON: { [key: string]: any }; - defaultPkgNlsJSON: { [key: string]: any } | undefined; - packageNlsJSON: { [key: string]: any } | undefined; - extraMetadata: JSONType; - realPath: string; // 真实路径,用于去除symbolicLink - extendConfig: JSONType; - isBuiltin: boolean; - isDevelopment?: boolean; -} - -/** - * 提供插件扫描时的额外信息读取能力 - * 比如 read/changelog/package.nls.json 等等 - */ -export interface IExtraMetaData { - [key: string]: string; -} - -export const ExtensionNodeServiceServerPath = 'ExtensionNodeServiceServerPath'; - -export type ExtensionDependencies = (string | { [extensionId: string]: string })[]; - -export interface ICreateProcessOptions { - /** - * 启用插件进程的 Debug 模式 - */ - enableDebugExtensionHost?: boolean; - /** - * 插件进程连接时候一些配置选项 - */ - extensionConnectOption?: ExtensionConnectOption; -} - -export const IExtensionNodeService = Symbol('IExtensionNodeService'); -export interface IExtensionNodeService { - initialize(): Promise; - getAllExtensions( - scan: string[], - extensionCandidate: string[], - localization: string, - extraMetaData: IExtraMetaData, - ): Promise; - createProcess(clientId: string, options?: ICreateProcessOptions): Promise; - ensureProcessReady(clientId: string): Promise; - getElectronMainThreadListenPath(clientId: string): Promise; - getElectronMainThreadListenPath2(clientId: string): Promise; - getExtServerListenOption(clientId: string); - getExtension( - extensionPath: string, - localization: string, - extraMetaData?: IExtraMetaData, - ): Promise; - setConnectionServiceClient(clientId: string, serviceClient: IExtensionNodeClientService); - disposeClientExtProcess(clientId: string, info: boolean): Promise; - disposeAllClientExtProcess(): Promise; - tryEnableInspectPort(clientId: string, delay?: number): Promise; - getProcessInspectPort(clientId: string): Promise; -} - -export const IExtensionNodeClientService = Symbol('IExtensionNodeClientService'); -export interface IExtensionNodeClientService { - getElectronMainThreadListenPath(clientId: string): Promise; - getAllExtensions( - scan: string[], - extensionCandidate: string[], - localization: string, - extraMetaData: IExtraMetaData, - ): Promise; - createProcess(clientId: string, options: ICreateProcessOptions): Promise; - getExtension( - extensionPath: string, - localization: string, - extraMetaData?: IExtraMetaData, - ): Promise; - infoProcessNotExist(): void; - infoProcessCrash(): void; - restartExtProcessByClient(): void; - disposeClientExtProcess(clientId: string, info: boolean): Promise; - updateLanguagePack(languageId: string, languagePackPath: string, storagePath: string): Promise; - getOpenVSXRegistry(): Promise; -} - -export type ExtensionHostType = 'node' | 'worker'; - -export type ExtensionHostTypeUpperCase = 'Node.js' | 'Web Worker'; - -export interface ChangeExtensionOptions { - upgrade: boolean; - extensionPath: string; - oldExtensionPath?: string; - isBuiltin?: boolean; -} - -/** - * 管理不同进程内插件注册的 command 的运行环境及其调用 - */ -export abstract class IExtCommandManagement { - abstract registerProxyCommandExecutor(env: ExtensionHostType, proxyCommandExecutor: IMainThreadCommands): void; - abstract executeExtensionCommand(env: ExtensionHostType, command: string, args: any[]): Promise; - /** - * @param command command id - * @param targetHost 目标插件进程的运行环境,默认 'node' - */ - abstract registerExtensionCommandEnv(command: string, targetHost?: ExtensionHostType): IDisposable; - abstract getExtensionCommandEnv(command: string): ExtensionHostType | undefined; -} - -/** - * 为插件市场面板提供数据/交互 - */ -export abstract class AbstractExtensionManagementService { - /** - * @deprecated 建议直接用 AbstractExtInstanceManagementService#getExtensionInstances 后自行 map#toJSON 即可 - */ - abstract getAllExtensionJson(): IExtensionProps[]; - - /** - * 禁用插件 - */ - abstract postDisableExtension(extensionPath: string): Promise; - - /** - * 启用插件 - */ - abstract postEnableExtension(extensionPath: string): Promise; - - /** - * 安装插件之后开始激活 - */ - abstract postChangedExtension(options: ChangeExtensionOptions): Promise; - abstract postChangedExtension(upgrade: boolean, extensionPath: string, oldExtensionPath?: string): Promise; - abstract postChangedExtension( - upgrade: boolean | ChangeExtensionOptions, - extensionPath?: string, - oldExtensionPath?: string, - ): Promise; - - /** - * 卸载插件 - */ - abstract postUninstallExtension(extensionPath: string): Promise; - - /** - * 通过 extensionPath 获取插件实例 - */ - abstract getExtensionByPath(extensionPath: string): IExtension | undefined; - /** - * 通过 extension id 获取插件实例 - */ - abstract getExtensionByExtId(extensionId: string): IExtension | undefined; - - /** - * 通过 extensionPath 获取插件实例序列化数据及从 node 层获取的 extraMetadata - */ - abstract getExtensionProps( - extensionPath: string, - extraMetaData?: IExtraMetaData, - ): Promise; -} - -export abstract class ExtensionService { - /** - * 激活插件服务 - */ - abstract activate(): Promise; - - /** - * 重启插件进程 - */ - abstract restartExtProcess(): Promise; - - /** - * 激活插件, 给 Extension 实例使用 - */ - abstract activeExtension(extension: IExtension): Promise; - - /** - * 销毁插件 - */ - abstract disposeExtensions(): Promise; - - /** - * 执行插件命令 - */ - abstract executeExtensionCommand(command: string, args: any[]): Promise; - - /** - * @internal 提供获取所有运行中的插件的列表数据 - */ - abstract getActivatedExtensions(): Promise<{ [key in ExtensionHostType]?: ActivatedExtension[] }>; - - abstract runExtensionContributes(): Promise; - - eagerExtensionsActivated: Deferred; -} - -export abstract class ExtensionCapabilityRegistry { - abstract getAllExtensions(): Promise; -} - -export const LANGUAGE_BUNDLE_FIELD = 'languageBundle'; - -export interface JSONType { - [key: string]: any; -} - -export interface IExtension extends IExtensionProps { - readonly contributes: IExtensionContributions & ISumiExtensionContributions; - activate(visited?: Set); - enable(): void; - reset(): void; - toJSON(): IExtensionProps; -} - -const VAR_REGEXP = /^\$\(([a-z.]+\/)?([a-z-]+)(~[a-z]+)?\)$/i; - -export interface ContributesMap { - extensionId: string; - contributes: T; -} - -export abstract class VSCodeContributePoint extends Disposable { - protected contributesMap: Array> = []; - - protected contributedMap: Array> = []; - - static schema: IJSONSchema; - - protected readonly iconService?: IIconService; - - abstract contribute(): void | Promise; - - register(extensionId: string, contributes: T) { - this.contributesMap.push({ extensionId, contributes }); - } - - hasUncontributedPoint() { - return this.contributesMap.length > 0; - } - - afterContribute() { - this.contributedMap = this.contributedMap.concat(this.contributesMap); - this.contributesMap = []; - } - - protected toIconClass( - iconContrib: { [index in ThemeType]: string } | string, - type: IconType = IconType.Mask, - basePath: string, - ): string | undefined { - if (typeof iconContrib === 'string' && VAR_REGEXP.test(iconContrib)) { - return this.iconService?.fromString(iconContrib); - } - return this.iconService?.fromIcon(basePath, iconContrib, type); - } - - protected getLocalizeFromNlsJSON(title: string, scope: string, languageId?: string): string { - return replaceNlsField(title, scope, title, languageId); - } -} - -export abstract class ExtensionContributesService extends WithEventBus { - abstract ContributionPoints: typeof VSCodeContributePoint[]; - - @Autowired(ILogger) - private logger: ILogger; - - @Autowired(AppLifeCycleServiceToken) - private lifecycleService: IAppLifeCycleService; - - @Autowired(IExtensionsSchemaService) - private readonly extensionsSchemaService: IExtensionsSchemaService; - - @Autowired(INJECTOR_TOKEN) - private injector: Injector; - - private contributedSet = new Set(); - - private getContributionCls(contributesName: string): typeof VSCodeContributePoint | undefined { - const Constructor = this.ContributionPoints.find((Constructor) => { - const k = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); - if (k === contributesName) { - return true; - } - return false; - }); - return Constructor; - } - - register(extensionId: string, contrib: JSONType) { - for (const k of Object.keys(contrib)) { - const Constructor = this.getContributionCls(k); - if (Constructor) { - const instance = this.injector.get(Constructor); - instance?.register(extensionId, contrib[k]); - } - } - } - - private async runContributesByPhase(lifeCyclePhase: LifeCyclePhase) { - const Contributes = this.ContributionPoints.filter((Constructor) => { - const phase = Reflect.getMetadata(LIFE_CYCLE_PHASE_KEY, Constructor); - const contributeName = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); - if (phase <= lifeCyclePhase && !this.contributedSet.has(contributeName)) { - this.contributedSet.add(contributeName); - return true; - } - return false; - }); - - await Promise.all( - Contributes.map(async (Constructor: typeof VSCodeContributePoint) => { - try { - const contributePoint: VSCodeContributePoint = this.injector.get(Constructor); - const contributeName = Reflect.getMetadata(CONTRIBUTE_NAME_KEY, Constructor); - this.addDispose(contributePoint); - - if (contributePoint.hasUncontributedPoint()) { - const now = Date.now(); - await contributePoint.contribute(); - contributePoint.afterContribute(); - - this.extensionsSchemaService.registerExtensionPoint({ - extensionPoint: contributeName, - jsonSchema: Constructor.schema || {}, - frameworkKind: ['vscode', 'opensumi'], - }); - - const end = Date.now() - now; - this.logger.log(`run extension contribute ${contributeName}: ${end} ms`); - } - } catch (e) { - this.logger.error(e); - } - }), - ); - } - - public initialize() { - const runContributes = (phase = this.lifecycleService.phase) => { - if (!phase) { - return; - } - - // 所有 contributionPoint 运行完后清空 - // 确保后续安装/启用插件后可以正常激活 - if (phase === LifeCyclePhase.Ready) { - this.contributedSet.clear(); - } - - this.runContributesByPhase(phase); - }; - - runContributes(); - - this.addDispose( - this.lifecycleService.onDidLifeCyclePhaseChange((newPhase) => { - runContributes(newPhase); - }), - ); - } -} - -export const CONTRIBUTE_NAME_KEY = 'contribute_name'; -export function Contributes(name) { - return (target) => { - Reflect.defineMetadata(CONTRIBUTE_NAME_KEY, name, target); - }; -} - -export const LIFE_CYCLE_PHASE_KEY = 'phase'; -export function LifeCycle(name: LifeCyclePhase) { - return (target) => { - Reflect.defineMetadata(LIFE_CYCLE_PHASE_KEY, name, target); - }; -} - -export const EXTENSION_EXTEND_SERVICE_PREFIX = 'extension_extend_service'; -export const MOCK_EXTENSION_EXTEND_PROXY_IDENTIFIER = createExtHostContextProxyIdentifier( - 'mock_extension_extend_proxy_identifier', -); - -export interface IExtensionHost { - logger: IExtensionLogger; - $activateExtension(id: string): Promise; - /** - * 更新插件进程内的插件相关数据 - */ - $updateExtHostData(): Promise; - $getActivatedExtensions(): Promise; - - getExtensionExports(id: string): any; - getExtensions(): Extension[]; - getExtension(extensionId: string): Extension | undefined; - isActivated(id: string): boolean; - activateExtension(id: string): Promise; - extensionsChangeEmitter: Emitter; - storage: ExtHostStorage; -} - -export interface IExtensionHostService extends IExtensionHost { - $fireChangeEvent(): Promise; - init(): Promise; - close(): Promise; - getExtendExports(id: string): any; - extensionsActivator: ExtensionsActivator; - /** - * 上报插件未捕获异常 - * @param error - */ - reportUnexpectedError(error: Error): void; -} - -export interface IExtensionWorkerHost extends IExtensionHost { - staticServicePath: string; -} - -export interface IExtendProxy { - [key: string]: any; -} - -export const WorkerHostAPIIdentifier = { - ExtWorkerHostExtensionService: createExtHostContextProxyIdentifier('ExtWorkerHostExtensionService'), -}; - -export enum ProcessMessageType { - REPORTER, -} - -export enum EXTENSION_ENABLE { - ENABLE = 1, - DISABLE = 0, -} - -// 广播插件事件 -export const EMIT_EXT_HOST_EVENT = { - id: 'sumi-extension:ext-host-event', -}; - -export function getExtensionId(extensionId: string) { - return extensionId.toLowerCase(); -} - -export enum ExtensionHostKind { - NODE_HOST = 1, - WORKER_HOST = 2, -} - -export const ExtensionHostProfilerServicePath = 'ExtensionHostProfilerService'; - -export const ExtensionHostProfilerServiceToken = Symbol('ExtensionHostProfilerService'); - -export interface IExtensionHostProfilerService { - $startProfile(clientId: string): Promise; - $stopProfile(clientId: string): Promise; - $saveLastProfile(filePath: string): Promise; -} - -export enum OutputType { - STDOUT, - STDERR, -} - -export interface Output { - type: OutputType; - data: string; - format: string[]; -} - -export const IExtensionHostManager = Symbol('IExtensionHostManager'); - -export interface IExtensionHostManager { - init(): MaybePromise; - fork(modulePath: string, ...args: any[]): MaybePromise; - send(pid: number, message: string): MaybePromise; - isRunning(pid: number): MaybePromise; - treeKill(pid: number): MaybePromise; - kill(pid: number, signal?: string): MaybePromise; - isKilled(pid: number): MaybePromise; - findDebugPort(startPort: number, giveUpAfter: number, timeout: number): Promise; - onOutput(pid: number, listener: (output: Output) => void): MaybePromise; - onExit(pid: number, listener: (code: number, signal: string) => void): MaybePromise; - onMessage(pid: number, listener: (msg: any) => void): MaybePromise; - disposeProcess(pid: number): MaybePromise; - dispose(): MaybePromise; -} - -/** - * 以下都是 fork 新的插件子进程的时候,传入的命令行参数的 key - */ -export const KT_PROCESS_SOCK_OPTION_KEY = 'kt-process-sock-option'; -export const KT_PROCESS_PRELOAD_KEY = 'kt-process-preload'; -export const KT_APP_CONFIG_KEY = 'kt-app-config'; - -// #region Semantic Tokens Contribution Point - -export interface SemanticTokenScopes { - scopes?: { [selector: string]: string[] }; - language?: string; -} - -export type SemanticTokenScopesSchema = Array; - -export interface SemanticTokenType { - id: string; - description: string; - superType?: string; -} - -export type SemanticTokenTypeSchema = Array; - -export interface SemanticTokenModifier { - id: string; - description: string; -} - -export type SemanticTokenModifierSchema = Array; - -export function validateTypeOrModifier( - contribution: SemanticTokenType | SemanticTokenModifier, - extensionPoint: string, - logger: ILogger, -): boolean { - if (typeof contribution.id !== 'string' || contribution.id.length === 0) { - logger.error("'configuration.{0}.id' must be defined and can not be empty", extensionPoint); - return false; - } - if (!contribution.id.match(typeAndModifierIdPattern)) { - logger.error("'configuration.{0}.id' must follow the pattern letterOrDigit[-_letterOrDigit]*"); - return false; - } - const superType = (contribution as SemanticTokenType).superType; - if (superType && !superType.match(typeAndModifierIdPattern)) { - logger.error( - "'configuration.{0}.superType' must follow the pattern letterOrDigit[-_letterOrDigit]*", - extensionPoint, - ); - return false; - } - if (typeof contribution.description !== 'string' || contribution.id.length === 0) { - logger.error("'configuration.{0}.description' must be defined and can not be empty", extensionPoint); - return false; - } - return true; -} - -// #endregion Semantic Tokens Contribution Point - -export const enum ExtensionContributePoint { - Terminal = 'terminal', -} - -// #region Walkthroughs -export interface IWalkthrough { - id: string; - title: string; - description: string; - order: number; - source: string; - isFeatured: boolean; - next?: string; - when: ContextKeyExpression; - steps: IWalkthroughStep[]; - icon: { type: 'icon'; icon: ThemeIcon } | { type: 'image'; path: string }; -} - -export type IWalkthroughLoose = Omit & { - steps: (Omit & { description: string })[]; -}; - -export interface IWalkthroughStep { - id: string; - title: string; - description: LinkedText[]; - category: string; - when: ContextKeyExpression; - order: number; - completionEvents: string[]; - media: - | { type: 'image'; path: { hcDark: URI; hcLight: URI; light: URI; dark: URI }; altText: string } - | { type: 'svg'; path: URI; altText: string } - | { type: 'markdown'; path: URI; base: URI; root: URI }; -} - -export interface StepProgress { - done: boolean; -} - -export interface IResolvedWalkthroughStep extends IWalkthroughStep, StepProgress {} - -export namespace CompletionEventsType { - export const onLink = 'onLink'; - export const onEvent = 'onEvent'; - export const onView = 'onView'; - export const onSettingChanged = 'onSettingChanged'; - export const onContext = 'onContext'; - export const onStepSelected = 'onStepSelected'; - export const stepSelected = 'stepSelected'; - export const onCommand = 'onCommand'; - export const onExtensionInstalled = 'onExtensionInstalled'; - export const extensionInstalled = 'extensionInstalled'; -} -// #endregion Walkthroughs +export * from './extension'; +export * from './const'; diff --git a/packages/extension/src/hosted/ext.host.ts b/packages/extension/src/hosted/ext.host.ts index 8dbeaaccf8..c1ac314ee1 100644 --- a/packages/extension/src/hosted/ext.host.ts +++ b/packages/extension/src/hosted/ext.host.ts @@ -3,7 +3,6 @@ import path from 'path'; import { Injector } from '@opensumi/di'; import { RPCProtocol, ProxyIdentifier } from '@opensumi/ide-connection'; import { - getDebugLogger, Emitter, IReporterService, REPORT_HOST, @@ -375,8 +374,6 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { } public async activateExtension(id: string) { - this.logger.debug('exthost $activateExtension', id); - const extension: IExtensionDescription | undefined = this.extensions.find((ext) => ext.id === id); if (!extension) { @@ -394,7 +391,7 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { const modulePath: string = extension.path; this.logger.debug(`${extension.name} - ${modulePath}`); - this.logger.debug('exthost $activateExtension path', modulePath); + this.logger.debug(`active extension host process by ${modulePath}`); const extendProxy = this.getExtendModuleProxy(extension, isSumiContributes); const context = await this.loadExtensionContext(extension, modulePath, this.storage, this.secret, extendProxy); @@ -411,10 +408,10 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { try { extensionModule = getNodeRequire()(modulePath); reportTimer.timeEnd(extension.id); - } catch (err) { + } catch (error) { activationFailed = true; - activationFailedError = err; - this.logger.error(`[Extension-Host][Activate Exception] ${extension.id}: `, err); + activationFailedError = error; + this.logger.error(`active extension ${extension.id} failure by\n${error}`); } if (extensionModule.activate) { @@ -427,10 +424,10 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { version: extension.packageJSON.version, }); exportsData = extensionExports; - } catch (e) { + } catch (error) { activationFailed = true; - activationFailedError = e; - this.logger.error(`[Extension-Host][Activate Exception] ${extension.id}: `, e); + activationFailedError = error; + this.logger.error(`active extension ${extension.id} failure by\n${error}`); } } } @@ -442,11 +439,11 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { reportTimer.timeEnd(extension.id, { version: extension.packageJSON.version, }); - } catch (err) { + } catch (error) { activationFailed = true; - activationFailedError = err; - this.reportRuntimeError(err, extension, err.stack); - this.logger.error(`[Extension-Host][Activate Exception] ${extension.id}: `, err); + activationFailedError = error; + this.reportRuntimeError(error, extension, error.stack); + this.logger.error(`active extension ${extension.id} failure by\n${error}`); } } else if (extension.extendConfig && extension.extendConfig.node && extension.extendConfig.node.main) { extendModule = getNodeRequire()(path.join(extension.path, extension.extendConfig.node.main)); @@ -459,14 +456,11 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { try { const extendModuleExportsData = await extendModule.activate(context); extendExports = extendModuleExportsData; - } catch (e) { + } catch (error) { activationFailed = true; - activationFailedError = e; - this.reportRuntimeError(e, extension, e.stack); - this.logger.log('activateExtension extension.extendConfig error '); - this.logger.log(e); - getDebugLogger().error(`${extension.id}`); - getDebugLogger().error(e); + activationFailedError = error; + this.reportRuntimeError(error, extension, error.stack); + this.logger.error(`active extension extend module failure by\n${error}`); } } this.extensionsActivator.set( @@ -534,6 +528,7 @@ export default class ExtensionHostServiceImpl implements IExtensionHostService { private registerExtendModuleService(exportsData, extension: IExtensionDescription) { const service = {}; for (const key in exportsData) { + // eslint-disable-next-line no-prototype-builtins if (exportsData.hasOwnProperty(key)) { if (typeof exportsData[key] === 'function') { service[`$${key}`] = exportsData[key]; diff --git a/packages/extension/src/node/extension.host.manager.ts b/packages/extension/src/node/extension.host.manager.ts index e5c0255495..88c6e95b9a 100644 --- a/packages/extension/src/node/extension.host.manager.ts +++ b/packages/extension/src/node/extension.host.manager.ts @@ -1,4 +1,3 @@ -import assert from 'assert'; import cp from 'child_process'; import isRunning from 'is-running'; @@ -18,19 +17,24 @@ export class ExtensionHostManager implements IExtensionHostManager { } init() { - // 这个 debug 插件 https://github.com/microsoft/vscode/blob/1.44.2/extensions/debug-auto-launch/src/extension.ts#L120 - // 依赖了 vscode pid 来查找子进程 + // Debug Auto Launch 插件 https://github.com/microsoft/vscode/blob/1.44.2/extensions/debug-auto-launch/src/extension.ts#L120 + // 依赖了 VSCODE_PID 来查找子进程 process.env['VSCODE_PID'] = String(process.pid); } + fork(modulePath: string, ...args: any[]) { const extProcess = cp.fork(modulePath, ...args); this.processMap.set(extProcess.pid, extProcess); return extProcess.pid; } + send(pid: number, message: string) { return new Promise((resolve, reject) => { const extProcess = this.processMap.get(pid); - assert(extProcess, "[ExtensionHostManager] Can't find process with pid: " + pid); + if (!extProcess) { + reject(new Error(`Can't find process with pid ${pid}`)); + return; + } extProcess.send(message, (err) => { if (err) { reject(err); @@ -40,9 +44,11 @@ export class ExtensionHostManager implements IExtensionHostManager { }); }); } + isRunning(pid: number) { return isRunning(pid); } + treeKill(pid: number) { return new Promise((resolve, reject) => { treeKill(pid, (err) => { @@ -54,11 +60,12 @@ export class ExtensionHostManager implements IExtensionHostManager { }); }); } + kill(pid: number, signal?: NodeJS.Signals) { const extProcess = this.processMap.get(pid); - assert(extProcess); - extProcess!.kill(signal); + extProcess?.kill(signal); } + isKilled(pid: number) { const extProcess = this.processMap.get(pid); if (!extProcess) { @@ -73,11 +80,13 @@ export class ExtensionHostManager implements IExtensionHostManager { onOutput(pid: number, listener: (output: Output) => void) { const extProcess = this.processMap.get(pid); - assert(extProcess); - extProcess!.stdout!.setEncoding('utf8'); - extProcess!.stderr!.setEncoding('utf8'); - const onStdout = Event.fromNodeEventEmitter(extProcess!.stdout!, 'data'); - const onStderr = Event.fromNodeEventEmitter(extProcess!.stderr!, 'data'); + if (!extProcess) { + return; + } + extProcess.stdout.setEncoding('utf8'); + extProcess.stderr.setEncoding('utf8'); + const onStdout = Event.fromNodeEventEmitter(extProcess.stdout, 'data'); + const onStderr = Event.fromNodeEventEmitter(extProcess.stderr, 'data'); const onOutput = Event.any( Event.map(onStdout, (o) => ({ type: OutputType.STDOUT, data: `%c${o}`, format: [''] })), Event.map(onStderr, (o) => ({ type: OutputType.STDERR, data: `%c${o}`, format: ['color: red'] })), @@ -102,14 +111,18 @@ export class ExtensionHostManager implements IExtensionHostManager { onExit(pid: number, listener: (code: number, signal: string) => void) { const extProcess = this.processMap.get(pid); - assert(extProcess); - extProcess!.once('exit', listener); + if (!extProcess) { + return; + } + extProcess.once('exit', listener); } onMessage(pid: number, listener: (msg: any) => void): MaybePromise { const extProcess = this.processMap.get(pid); - assert(extProcess); - extProcess!.on('message', listener); + if (!extProcess) { + return; + } + extProcess.on('message', listener); } disposeProcess(pid: number) { diff --git a/packages/extension/src/node/extension.service.ts b/packages/extension/src/node/extension.service.ts index 0b76ef286e..a2cecd9973 100644 --- a/packages/extension/src/node/extension.service.ts +++ b/packages/extension/src/node/extension.service.ts @@ -49,6 +49,7 @@ import { ICreateProcessOptions, KT_PROCESS_SOCK_OPTION_KEY, IExtensionNodeClientService, + CONNECTION_HANDLE_BETWEEN_EXTENSION_AND_MAIN_THREAD, } from '../common'; import { ExtensionScanner } from './extension.scanner'; @@ -319,7 +320,6 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { forkArgs.push(`--kt-process-preload=${preloadPath}`); if (this.appConfig.extHost) { - this.logger.log(`extension host path ${this.appConfig.extHost}`); extProcessPath = this.appConfig.extHost; } else { extProcessPath = @@ -328,6 +328,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { : path.join(__dirname, '../hosted/ext.process' + path.extname(module.filename)); } } + this.logger.log(`Extension host process path ${extProcessPath}`); // 注意只能传递可以序列化的数据 forkArgs.push( @@ -353,7 +354,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { ...forkOptions, ...this.appConfig.extHostForkOptions, }); - this.logger.log('extProcess.pid', extProcessId); + this.logger.log(`Fork extension host process with id ${extProcessId}`); // 监听进程输出,用于获取调试端口 this.extensionHostManager.onOutput(extProcessId, (output) => { @@ -373,9 +374,8 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { }); this.extensionHostManager.onExit(extProcessId, async (code: number, signal: string) => { - this.logger.log('extProcess.pid exit', extProcessId, 'code', code, 'signal', signal); + this.logger.log(`Extension host process ${extProcessId} exit by code ${code} signal ${signal}`); if (this.clientExtProcessMap.get(clientId) === extProcessId) { - this.logger.error('extProcess crash', extProcessId, 'code', code, 'signal', signal); await this.disposeClientExtProcess(clientId, false, false); this.infoProcessCrash(clientId); this.reporterService.point(REPORT_NAME.EXTENSION_CRASH, clientId, { @@ -383,12 +383,11 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { signal, }); } else { - this.logger.log('extProcess.pid exit by dispose', extProcessId); + this.logger.log(`Extension host process ${extProcessId} exit by dispose`); } }); this.clientExtProcessMap.set(clientId, extProcessId); - this.logger.log('clientExtProcessMap.keys', this.clientExtProcessMap.keys()); const extProcessInitDeferred = new Deferred(); this.clientExtProcessInitDeferredMap.set(clientId, extProcessInitDeferred); @@ -408,7 +407,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { const initHandler = (msg) => { if (msg === 'ready') { const duration = forkTimer.timeEnd(); - this.logger.log(`extension,fork,${clientId},${duration}ms`); + this.logger.log(`Starting extension host with pid ${extProcessId} (fork() took ${duration} ms).`); this.clientExtProcessInitDeferredMap.get(clientId)?.resolve(); this.clientExtProcessFinishDeferredMap.set(clientId, new Deferred()); } else if (msg === 'finish') { @@ -446,7 +445,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { try { (process as ProcessExt)._debugProcess!(extHostProcessId); } catch (err) { - this.logger.error(`enable inspect port error \n ${err.message}`); + this.logger.error(`Enable inspect port error \n ${err.message}`); return false; } @@ -475,10 +474,10 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { const clientId = process.env.CODE_WINDOW_CLIENT_ID as string; const mainThreadServer: net.Server = net.createServer(); const mainThreadListenPath = await this.getElectronMainThreadListenPath2(clientId); - this.logger.log('mainThreadListenPath', mainThreadListenPath); + this.logger.log(`The electron mainThread listen on ${mainThreadListenPath}`); mainThreadServer.on('connection', (connection) => { - this.logger.log(`electron ext main connected ${clientId}`); + this.logger.log(`The electron mainThread ${clientId} connected`); handler({ connection: { @@ -489,19 +488,18 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { }); connection.on('close', () => { - this.logger.log('close disposeClientExtProcess clientId', clientId); + this.logger.log(`Dispose client by clientId ${clientId}`); // electron 只要端口进程就杀死插件进程 this.disposeClientExtProcess(clientId); }); }); mainThreadServer.listen(mainThreadListenPath, () => { - this.logger.log(`electron mainThread listen on ${mainThreadListenPath}`); + this.logger.log(`Electron mainThread listen on ${mainThreadListenPath}`); }); } else { - commonChannelPathHandler.register('ExtMainThreadConnection', { + commonChannelPathHandler.register(CONNECTION_HANDLE_BETWEEN_EXTENSION_AND_MAIN_THREAD, { handler: (connection: WSChannel, connectionClientId: string) => { - this.logger.log(`ext main connected ${connectionClientId}`); const reader = new WebSocketMessageReader(connection); const writer = new WebSocketMessageWriter(connection); handler({ @@ -515,7 +513,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { connection.onClose(() => { reader.dispose(); writer.dispose(); - this.logger.log(`remove ext mainConnection ${connectionClientId} `); + this.logger.log(`The connection client ${connectionClientId} closed`); if (this.clientExtProcessExtConnection.has(connectionClientId)) { const extConnection: any = this.clientExtProcessExtConnection.get(connectionClientId); @@ -530,10 +528,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { this.closeExtProcessWhenConnectionClose(connectionClientId); }); }, - dispose: (connection, connectionClientId) => { - // Web 场景断连后不杀死插件进程 - // https://yuque.antfin.com/ide-framework/topiclist/enpip1 - }, + dispose: () => {}, }); } } @@ -544,9 +539,9 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { private closeExtProcessWhenConnectionClose(connectionClientId: string) { if (this.clientExtProcessMap.has(connectionClientId)) { const timer = global.setTimeout(() => { - this.logger.log('close disposeClientExtProcess clientId', connectionClientId); + this.logger.log(`Dispose client by connectionClientId ${connectionClientId}`); this.disposeClientExtProcess(connectionClientId).catch((e) => { - this.logger.error('close extProcess when connection close throw error', e.message); + this.logger.error(`Close extension host process when connection throw error\n${e.message}`); }); }, this.appConfig.processCloseExitThreshold ?? ExtensionNodeServiceImpl.ProcessCloseExitThreshold); this.clientExtProcessThresholdExitTimerMap.set(connectionClientId, timer); @@ -561,8 +556,8 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { } /** - * 如果插件进程已被销毁(比如ws连接断开超过 ProcessCloseExitThreshold),那么当用户重新连接至服务时 - * 需要通知重启整个插件进程 + * 如果插件进程已被销毁,如 websocket 连接断开超过 `ExtensionNodeServiceImpl.ProcessCloseExitThreshold` 时 + * 那么当用户重新连接至服务时,需要通知重启整个插件进程 */ private restartExtProcessByClient(clientId: string) { if (this.clientServiceMap.has(clientId)) { @@ -591,7 +586,7 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { // extServer 关闭 if (this.clientExtProcessExtConnectionServer.has(clientId)) { - this.clientExtProcessExtConnectionServer.get(clientId)!.close(); + this.clientExtProcessExtConnectionServer.get(clientId)?.close(); } // connect 关闭 if (this.clientExtProcessExtConnection.has(clientId)) { @@ -607,13 +602,12 @@ export class ExtensionNodeServiceImpl implements IExtensionNodeService { this.clientExtProcessMap.delete(clientId); if (killProcess) { - await this.extensionHostManager.treeKill(extProcessId); await this.extensionHostManager.disposeProcess(extProcessId); } if (info) { this.infoProcessNotExist(clientId); } - this.logger.log(`${clientId} extProcess dispose`); + this.logger.log(`Extension host process disposed by clientId ${clientId}`); } } diff --git a/packages/extension/src/node/index.ts b/packages/extension/src/node/index.ts index ae0e672b57..7924b18e51 100644 --- a/packages/extension/src/node/index.ts +++ b/packages/extension/src/node/index.ts @@ -58,11 +58,11 @@ export class ExtensionContribution implements ServerAppContribution { async initialize() { await this.extensionNodeService.initialize(); - this.logger.verbose('extension initialized'); + this.logger.verbose('Extension server initialized'); } async onStop() { await this.extensionNodeService.disposeAllClientExtProcess(); - this.logger.warn('extension exit by server stop'); + this.logger.warn('All extension process exit by server stop'); } } diff --git a/packages/terminal-next/src/node/terminal.profile.service.ts b/packages/terminal-next/src/node/terminal.profile.service.ts index e0b7743459..67703aed60 100644 --- a/packages/terminal-next/src/node/terminal.profile.service.ts +++ b/packages/terminal-next/src/node/terminal.profile.service.ts @@ -279,7 +279,7 @@ export class TerminalProfileServiceNode { validatedProfile.color = profile.color; resultProfiles.push(validatedProfile); } else { - this.logger.log('profile not validated', profileName, originalPaths); + this.logger.log(`Profile \`${profileName}\` not validated with originalPaths ${originalPaths}`); } } return resultProfiles; diff --git a/packages/terminal-next/src/node/terminal.service.ts b/packages/terminal-next/src/node/terminal.service.ts index 108fc99164..69727ccdd9 100644 --- a/packages/terminal-next/src/node/terminal.service.ts +++ b/packages/terminal-next/src/node/terminal.service.ts @@ -62,7 +62,7 @@ export class TerminalServiceImpl implements ITerminalNodeService { const sessionCheckResArray = await Promise.all( sessionIdArray.map((sessionId) => this.ptyServiceManager.checkSession(sessionId)), ); - this.logger.log(`ensureClientTerminal ${clientId} ${terminalIdArr} ${sessionCheckResArray}`); + this.logger.log(`Ensure terminal client ${clientId} ${terminalIdArr} ${sessionCheckResArray}`); // 有一个存活就true,所以为了准确使用,每次调用terminalIdArr只传入一个东西 for (const sessionCheckRes of sessionCheckResArray) { @@ -78,7 +78,7 @@ export class TerminalServiceImpl implements ITerminalNodeService { const closeTimer = global.setTimeout( () => { this.disposeClient(clientId); - this.logger.debug(`删除 clientId ${clientId} 窗口的 pty 进程`); + this.logger.debug(`Remove pty process from ${clientId} client`); }, isDevelopment() ? 0 : this.appConfig.terminalPtyCloseThreshold || TerminalServiceImpl.TerminalPtyCloseThreshold, ); @@ -187,7 +187,7 @@ export class TerminalServiceImpl implements ITerminalNodeService { }); ptyService.onExit(({ exitCode, signal }) => { - this.logger.debug(`Terminal process exit (instanceId: ${sessionId}) with code ${exitCode}`); + this.logger.debug(`Terminal process ${sessionId} exit with code ${exitCode}`); if (this.serviceClientMap.has(clientId)) { this.flushPtyData(clientId, sessionId); const serviceClient = this.serviceClientMap.get(clientId) as ITerminalServiceClient; @@ -196,7 +196,7 @@ export class TerminalServiceImpl implements ITerminalNodeService { signal, }); } else { - this.logger.warn(`terminal: pty ${clientId} on data not found`); + this.logger.warn(`The pty process ${clientId} not found`); } }); @@ -206,13 +206,13 @@ export class TerminalServiceImpl implements ITerminalNodeService { const serviceClient = this.serviceClientMap.get(clientId) as ITerminalServiceClient; serviceClient.processChange(sessionId, processName); } else { - this.logger.warn(`terminal: pty ${clientId} on data not found`); + this.logger.warn(`The pty process ${clientId} not found`); } }); const error = await ptyService.start(); if (error) { - this.logger.error(`Terminal process start error (instanceId: ${sessionId})`, error); + this.logger.error(`Terminal process ${sessionId} start error\n`, error); throw error; } @@ -242,7 +242,7 @@ export class TerminalServiceImpl implements ITerminalNodeService { public onMessage(id: string, msg: string) { const terminal = this.getTerminal(id); if (!terminal) { - this.logger.warn(`terminal ${id} onMessage not found`, terminal); + this.logger.warn(`The terminal ${id} not found`); return; } terminal.onMessage(msg); diff --git a/packages/types/manifest.json b/packages/types/manifest.json index 11d0ebf74e..8458f8c84a 100644 --- a/packages/types/manifest.json +++ b/packages/types/manifest.json @@ -1,296 +1,296 @@ { "meta": { "@opensumi/ide-addons": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-collaboration": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-comments": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-components": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-connection": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-core-browser": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["common"] }, "@opensumi/ide-core-common": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-core-electron-main": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-core-node": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-debug": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-decoration": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-editor": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-electron-basic": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-explorer": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-express-file-server": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-extension": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-extension-manager": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-extension-storage": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-file-scheme": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-file-search": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "common"] }, "@opensumi/ide-file-service": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-file-tree-next": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-i18n": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-keymaps": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-logs": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-main-layout": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-markdown": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-markers": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-menu-bar": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-monaco": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-monaco-enhance": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-opened-editor": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-outline": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-output": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-overlay": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-preferences": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-process": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "common"] }, "@opensumi/ide-quick-open": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/remote-cli": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-remote-opener": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-scm": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-search": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-startup": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-static-resource": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/ide-status-bar": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-storage": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-task": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-terminal-next": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["node", "browser", "common"] }, "@opensumi/ide-testing": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-theme": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-toolbar": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser"] }, "@opensumi/sumi": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-userstorage": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-utils": { - "version": "2.21.11", + "version": "2.21.12", "entry": [] }, "@opensumi/ide-variable": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-webview": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-workspace": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] }, "@opensumi/ide-workspace-edit": { - "version": "2.21.11", + "version": "2.21.12", "entry": ["browser", "common"] } }, "packages": { - "@opensumi/ide-addons": "2.21.11", - "@opensumi/ide-collaboration": "2.21.11", - "@opensumi/ide-comments": "2.21.11", - "@opensumi/ide-components": "2.21.11", - "@opensumi/ide-connection": "2.21.11", - "@opensumi/ide-core-browser": "2.21.11", - "@opensumi/ide-core-common": "2.21.11", - "@opensumi/ide-core-electron-main": "2.21.11", - "@opensumi/ide-core-node": "2.21.11", - "@opensumi/ide-debug": "2.21.11", - "@opensumi/ide-decoration": "2.21.11", - "@opensumi/ide-editor": "2.21.11", - "@opensumi/ide-electron-basic": "2.21.11", - "@opensumi/ide-explorer": "2.21.11", - "@opensumi/ide-express-file-server": "2.21.11", - "@opensumi/ide-extension": "2.21.11", - "@opensumi/ide-extension-manager": "2.21.11", - "@opensumi/ide-extension-storage": "2.21.11", - "@opensumi/ide-file-scheme": "2.21.11", - "@opensumi/ide-file-search": "2.21.11", - "@opensumi/ide-file-service": "2.21.11", - "@opensumi/ide-file-tree-next": "2.21.11", - "@opensumi/ide-i18n": "2.21.11", - "@opensumi/ide-keymaps": "2.21.11", - "@opensumi/ide-logs": "2.21.11", - "@opensumi/ide-main-layout": "2.21.11", - "@opensumi/ide-markdown": "2.21.11", - "@opensumi/ide-markers": "2.21.11", - "@opensumi/ide-menu-bar": "2.21.11", - "@opensumi/ide-monaco": "2.21.11", - "@opensumi/ide-monaco-enhance": "2.21.11", - "@opensumi/ide-opened-editor": "2.21.11", - "@opensumi/ide-outline": "2.21.11", - "@opensumi/ide-output": "2.21.11", - "@opensumi/ide-overlay": "2.21.11", - "@opensumi/ide-preferences": "2.21.11", - "@opensumi/ide-process": "2.21.11", - "@opensumi/ide-quick-open": "2.21.11", - "@opensumi/remote-cli": "2.21.11", - "@opensumi/ide-remote-opener": "2.21.11", - "@opensumi/ide-scm": "2.21.11", - "@opensumi/ide-search": "2.21.11", - "@opensumi/ide-startup": "2.21.11", - "@opensumi/ide-static-resource": "2.21.11", - "@opensumi/ide-status-bar": "2.21.11", - "@opensumi/ide-storage": "2.21.11", - "@opensumi/ide-task": "2.21.11", - "@opensumi/ide-terminal-next": "2.21.11", - "@opensumi/ide-testing": "2.21.11", - "@opensumi/ide-theme": "2.21.11", - "@opensumi/ide-toolbar": "2.21.11", - "@opensumi/sumi": "2.21.11", - "@opensumi/ide-userstorage": "2.21.11", - "@opensumi/ide-utils": "2.21.11", - "@opensumi/ide-variable": "2.21.11", - "@opensumi/ide-webview": "2.21.11", - "@opensumi/ide-workspace": "2.21.11", - "@opensumi/ide-workspace-edit": "2.21.11" + "@opensumi/ide-addons": "2.21.12", + "@opensumi/ide-collaboration": "2.21.12", + "@opensumi/ide-comments": "2.21.12", + "@opensumi/ide-components": "2.21.12", + "@opensumi/ide-connection": "2.21.12", + "@opensumi/ide-core-browser": "2.21.12", + "@opensumi/ide-core-common": "2.21.12", + "@opensumi/ide-core-electron-main": "2.21.12", + "@opensumi/ide-core-node": "2.21.12", + "@opensumi/ide-debug": "2.21.12", + "@opensumi/ide-decoration": "2.21.12", + "@opensumi/ide-editor": "2.21.12", + "@opensumi/ide-electron-basic": "2.21.12", + "@opensumi/ide-explorer": "2.21.12", + "@opensumi/ide-express-file-server": "2.21.12", + "@opensumi/ide-extension": "2.21.12", + "@opensumi/ide-extension-manager": "2.21.12", + "@opensumi/ide-extension-storage": "2.21.12", + "@opensumi/ide-file-scheme": "2.21.12", + "@opensumi/ide-file-search": "2.21.12", + "@opensumi/ide-file-service": "2.21.12", + "@opensumi/ide-file-tree-next": "2.21.12", + "@opensumi/ide-i18n": "2.21.12", + "@opensumi/ide-keymaps": "2.21.12", + "@opensumi/ide-logs": "2.21.12", + "@opensumi/ide-main-layout": "2.21.12", + "@opensumi/ide-markdown": "2.21.12", + "@opensumi/ide-markers": "2.21.12", + "@opensumi/ide-menu-bar": "2.21.12", + "@opensumi/ide-monaco": "2.21.12", + "@opensumi/ide-monaco-enhance": "2.21.12", + "@opensumi/ide-opened-editor": "2.21.12", + "@opensumi/ide-outline": "2.21.12", + "@opensumi/ide-output": "2.21.12", + "@opensumi/ide-overlay": "2.21.12", + "@opensumi/ide-preferences": "2.21.12", + "@opensumi/ide-process": "2.21.12", + "@opensumi/ide-quick-open": "2.21.12", + "@opensumi/remote-cli": "2.21.12", + "@opensumi/ide-remote-opener": "2.21.12", + "@opensumi/ide-scm": "2.21.12", + "@opensumi/ide-search": "2.21.12", + "@opensumi/ide-startup": "2.21.12", + "@opensumi/ide-static-resource": "2.21.12", + "@opensumi/ide-status-bar": "2.21.12", + "@opensumi/ide-storage": "2.21.12", + "@opensumi/ide-task": "2.21.12", + "@opensumi/ide-terminal-next": "2.21.12", + "@opensumi/ide-testing": "2.21.12", + "@opensumi/ide-theme": "2.21.12", + "@opensumi/ide-toolbar": "2.21.12", + "@opensumi/sumi": "2.21.12", + "@opensumi/ide-userstorage": "2.21.12", + "@opensumi/ide-utils": "2.21.12", + "@opensumi/ide-variable": "2.21.12", + "@opensumi/ide-webview": "2.21.12", + "@opensumi/ide-workspace": "2.21.12", + "@opensumi/ide-workspace-edit": "2.21.12" } } diff --git a/tools/dev-tool/src/server.ts b/tools/dev-tool/src/server.ts index fe96b3cf62..26e5be8897 100644 --- a/tools/dev-tool/src/server.ts +++ b/tools/dev-tool/src/server.ts @@ -71,8 +71,8 @@ export async function startServer(arg1: NodeModule[] | Partial) */ extHost: path.join(__dirname, '../../../packages/extension/lib/hosted/ext.process.js') || process.env.EXTENSION_HOST_ENTRY, - onDidCreateExtensionHostProcess: (extProcess) => { - console.log('onDidCreateExtensionHostProcess extProcess.pid', extProcess.pid); + onDidCreateExtensionHostProcess: (extHostProcess) => { + console.log(`Extension host process ${extHostProcess.pid} created`); }, }; if (Array.isArray(arg1)) {