Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/node/nodeAgentHostStarter.ts
13394 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter } from '../../../base/common/event.js';
7
import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js';
8
import { FileAccess, Schemas } from '../../../base/common/network.js';
9
import { Client, IIPCOptions } from '../../../base/parts/ipc/node/ipc.cp.js';
10
import { IConfigurationService } from '../../configuration/common/configuration.js';
11
import { IEnvironmentService, INativeEnvironmentService } from '../../environment/common/environment.js';
12
import { parseAgentHostDebugPort } from '../../environment/node/environmentService.js';
13
import { ILogService } from '../../log/common/log.js';
14
import { getResolvedShellEnv } from '../../shell/node/shellEnv.js';
15
import { IAgentHostConnection, IAgentHostStarter } from '../common/agent.js';
16
17
/**
18
* Options for configuring the agent host WebSocket server in the child process.
19
* When set, the agent host exposes a WebSocket endpoint for external clients.
20
*/
21
export interface IAgentHostWebSocketConfig {
22
/** TCP port to listen on. Mutually exclusive with `socketPath`. */
23
readonly port?: string;
24
/** Unix domain socket / named pipe path. Takes precedence over `port`. */
25
readonly socketPath?: string;
26
/** Host/IP to bind to. */
27
readonly host?: string;
28
/** Connection token value. When set, WebSocket clients must present this token. */
29
readonly connectionToken?: string;
30
}
31
32
/**
33
* Spawns the agent host as a Node child process (fallback when
34
* Electron utility process is unavailable, e.g. dev/test).
35
*/
36
export class NodeAgentHostStarter extends Disposable implements IAgentHostStarter {
37
38
private _wsConfig: IAgentHostWebSocketConfig | undefined;
39
40
private readonly _onRequestConnection = this._register(new Emitter<void>());
41
readonly onRequestConnection = this._onRequestConnection.event;
42
43
constructor(
44
@IConfigurationService private readonly _configurationService: IConfigurationService,
45
@IEnvironmentService private readonly _environmentService: INativeEnvironmentService,
46
@ILogService private readonly _logService: ILogService,
47
) {
48
super();
49
}
50
51
/**
52
* Configures the child process to also start a WebSocket server.
53
* Must be called before {@link start}. Triggers eager process start
54
* via {@link onRequestConnection}.
55
*/
56
setWebSocketConfig(config: IAgentHostWebSocketConfig): void {
57
this._wsConfig = config;
58
// Signal the process manager to start immediately rather than
59
// waiting for a renderer window to connect.
60
this._onRequestConnection.fire();
61
}
62
63
async start(): Promise<IAgentHostConnection> {
64
// Resolve user shell environment so spawned tools/terminals inherit
65
// PATH and other vars from the user's login shell (macOS/Linux).
66
const shellEnv = await this._resolveShellEnv();
67
68
const env: Record<string, string> = {
69
...shellEnv as Record<string, string>,
70
VSCODE_ESM_ENTRYPOINT: 'vs/platform/agentHost/node/agentHostMain',
71
VSCODE_PIPE_LOGGING: 'true',
72
VSCODE_VERBOSE_LOGGING: 'true',
73
};
74
75
// Forward WebSocket server configuration to the child process via env vars
76
if (this._wsConfig) {
77
if (this._wsConfig.port) {
78
env['VSCODE_AGENT_HOST_PORT'] = this._wsConfig.port;
79
}
80
if (this._wsConfig.socketPath) {
81
env['VSCODE_AGENT_HOST_SOCKET_PATH'] = this._wsConfig.socketPath;
82
}
83
if (this._wsConfig.host) {
84
env['VSCODE_AGENT_HOST_HOST'] = this._wsConfig.host;
85
}
86
if (this._wsConfig.connectionToken) {
87
env['VSCODE_AGENT_HOST_CONNECTION_TOKEN'] = this._wsConfig.connectionToken;
88
}
89
}
90
91
const opts: IIPCOptions = {
92
serverName: 'Agent Host',
93
args: ['--type=agentHost', '--logsPath', this._environmentService.logsHome.with({ scheme: Schemas.file }).fsPath],
94
env,
95
};
96
97
const agentHostDebug = parseAgentHostDebugPort(this._environmentService.args, this._environmentService.isBuilt);
98
if (agentHostDebug) {
99
if (agentHostDebug.break && agentHostDebug.port) {
100
opts.debugBrk = agentHostDebug.port;
101
} else if (!agentHostDebug.break && agentHostDebug.port) {
102
opts.debug = agentHostDebug.port;
103
}
104
}
105
106
const client = new Client(FileAccess.asFileUri('bootstrap-fork').fsPath, opts);
107
108
const store = new DisposableStore();
109
store.add(client);
110
111
return {
112
client,
113
store,
114
onDidProcessExit: client.onDidProcessExit
115
};
116
}
117
118
private async _resolveShellEnv(): Promise<typeof process.env> {
119
try {
120
return await getResolvedShellEnv(this._configurationService, this._logService, this._environmentService.args, process.env);
121
} catch (error) {
122
this._logService.error('AgentHostStarter was unable to resolve shell environment', error);
123
return {};
124
}
125
}
126
}
127
128