@github/copilot-language-server 1.528.0 → 1.529.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var client_exports = {};
20
30
  __export(client_exports, {
@@ -246,6 +256,7 @@ class TeardownResilientStreamMessageWriter extends import_node.StreamMessageWrit
246
256
  class CopilotClient {
247
257
  cliStartTimeout = null;
248
258
  cliProcess = null;
259
+ ffiHost = null;
249
260
  connection = null;
250
261
  messageWriter = null;
251
262
  socket = null;
@@ -322,6 +333,29 @@ class CopilotClient {
322
333
  `);
323
334
  }
324
335
  }
336
+ /**
337
+ * Environment variable that overrides the transport when the caller does not set
338
+ * {@link CopilotClientOptions.connection}. Accepts `"inprocess"` or `"stdio"`
339
+ * (case-insensitive); unset preserves the default stdio transport. Any other value
340
+ * is an error.
341
+ */
342
+ static DEFAULT_CONNECTION_ENV_VAR = "COPILOT_SDK_DEFAULT_CONNECTION";
343
+ /**
344
+ * Resolves the default {@link RuntimeConnection} for the no-connection case,
345
+ * honoring {@link CopilotClient.DEFAULT_CONNECTION_ENV_VAR}.
346
+ */
347
+ static resolveDefaultConnection() {
348
+ const value = process.env[CopilotClient.DEFAULT_CONNECTION_ENV_VAR];
349
+ if (!value || value.toLowerCase() === "stdio") {
350
+ return { kind: "stdio" };
351
+ }
352
+ if (value.toLowerCase() === "inprocess") {
353
+ return { kind: "inprocess" };
354
+ }
355
+ throw new Error(
356
+ `Invalid ${CopilotClient.DEFAULT_CONNECTION_ENV_VAR} value '${value}'. Expected 'inprocess', 'stdio', or unset.`
357
+ );
358
+ }
325
359
  /**
326
360
  * Creates a new CopilotClient instance.
327
361
  *
@@ -350,12 +384,32 @@ class CopilotClient {
350
384
  * ```
351
385
  */
352
386
  constructor(options = {}) {
353
- const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" };
387
+ const conn = options._internalConnection ?? options.connection ?? CopilotClient.resolveDefaultConnection();
354
388
  if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
355
389
  throw new Error(
356
390
  "gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
357
391
  );
358
392
  }
393
+ if (conn.kind === "inprocess" && options.workingDirectory !== void 0) {
394
+ throw new Error(
395
+ "workingDirectory is not supported with RuntimeConnection.forInProcess(): the in-process transport hosts the runtime in this process, so honoring it would require mutating the shared process-global cwd. Change the host process's working directory before constructing the client instead."
396
+ );
397
+ }
398
+ if (conn.kind === "inprocess" && options.env !== void 0) {
399
+ throw new Error(
400
+ "env is not supported with RuntimeConnection.forInProcess(): the in-process transport loads the native runtime into the shared host process, whose single environment block cannot carry per-client values. Set the variables on the host process environment instead."
401
+ );
402
+ }
403
+ if (conn.kind === "inprocess" && options.telemetry !== void 0) {
404
+ throw new Error(
405
+ "telemetry is not supported with RuntimeConnection.forInProcess(): telemetry configuration is lowered to environment variables read by native runtime code running in the shared host process, so per-client telemetry cannot be honored in-process. Configure telemetry via the host process environment, or use a child-process transport."
406
+ );
407
+ }
408
+ if ((conn.kind === "stdio" || conn.kind === "tcp") && conn.env !== void 0 && options.env !== void 0) {
409
+ throw new Error(
410
+ "Set environment variables via either the client-level env option or the connection's env (RuntimeConnection.forStdio/forTcp), not both. Prefer the connection-level env for child-process transports."
411
+ );
412
+ }
359
413
  if (conn.kind === "tcp" && conn.connectionToken !== void 0) {
360
414
  if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) {
361
415
  throw new Error("connectionToken must be a non-empty string");
@@ -384,7 +438,8 @@ class CopilotClient {
384
438
  this.requestHandler = options.requestHandler ?? null;
385
439
  this.onGitHubTelemetry = options.onGitHubTelemetry;
386
440
  this.setupClientGlobalHandlers();
387
- const effectiveEnv = options.env ?? process.env;
441
+ const connEnv = conn.kind === "stdio" || conn.kind === "tcp" ? conn.env : void 0;
442
+ const effectiveEnv = connEnv ?? options.env ?? process.env;
388
443
  this.resolvedEnv = effectiveEnv;
389
444
  this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0;
390
445
  const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
@@ -511,7 +566,9 @@ class CopilotClient {
511
566
  }
512
567
  this.state = "connecting";
513
568
  try {
514
- if (!this.isExternalServer) {
569
+ if (this.connectionConfig.kind === "inprocess") {
570
+ await this.startInProcessFfi();
571
+ } else if (!this.isExternalServer) {
515
572
  await this.startCLIServer();
516
573
  }
517
574
  await this.connectToServer();
@@ -560,6 +617,9 @@ class CopilotClient {
560
617
  async stop() {
561
618
  const errors = [];
562
619
  const activeSessions = [...this.sessions.values()];
620
+ if (this.connectionConfig.kind === "inprocess") {
621
+ await Promise.allSettled(activeSessions.map((session) => session.abort()));
622
+ }
563
623
  for (const session of activeSessions) {
564
624
  const sessionId = session.sessionId;
565
625
  let lastError = null;
@@ -588,7 +648,7 @@ class CopilotClient {
588
648
  session._markDisconnected();
589
649
  }
590
650
  this.sessions.clear();
591
- if (this.connection && this.cliProcess && !this.isExternalServer) {
651
+ if (this.connection && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
592
652
  const runtimeShutdownStart = Date.now();
593
653
  const shutdownPromise = this.rpc.runtime.shutdown();
594
654
  void shutdownPromise.catch(() => void 0);
@@ -673,6 +733,19 @@ class CopilotClient {
673
733
  );
674
734
  }
675
735
  }
736
+ if (this.ffiHost) {
737
+ const host = this.ffiHost;
738
+ this.ffiHost = null;
739
+ try {
740
+ host.dispose();
741
+ } catch (error) {
742
+ errors.push(
743
+ new Error(
744
+ `Failed to dispose in-process runtime host: ${error instanceof Error ? error.message : String(error)}`
745
+ )
746
+ );
747
+ }
748
+ }
676
749
  if (this.cliStartTimeout) {
677
750
  clearTimeout(this.cliStartTimeout);
678
751
  this.cliStartTimeout = null;
@@ -757,6 +830,13 @@ class CopilotClient {
757
830
  }
758
831
  this.cliProcess = null;
759
832
  }
833
+ if (this.ffiHost) {
834
+ try {
835
+ this.ffiHost.dispose();
836
+ } catch {
837
+ }
838
+ this.ffiHost = null;
839
+ }
760
840
  if (this.cliStartTimeout) {
761
841
  clearTimeout(this.cliStartTimeout);
762
842
  this.cliStartTimeout = null;
@@ -834,11 +914,16 @@ class CopilotClient {
834
914
  enableHostGitOperations: false,
835
915
  enableSessionStore: false,
836
916
  enableSkills: false,
837
- memory: { enabled: false }
917
+ memory: { enabled: false },
918
+ customAgentsLocalOnly: true
838
919
  };
839
920
  }
840
921
  return {};
841
922
  }
923
+ /** Mode-specific default for enableExperimentalMode. */
924
+ experimentalModeForMode(supplied) {
925
+ return this.options.mode === "empty" ? supplied ?? false : supplied;
926
+ }
842
927
  /**
843
928
  * Returns the systemMessage config to use, adjusted for the current mode.
844
929
  * In empty mode we ensure the environment_context section is removed
@@ -919,7 +1004,9 @@ class CopilotClient {
919
1004
  if (!this.connection) {
920
1005
  await this.start();
921
1006
  }
922
- config = { ...this.configDefaultsForMode(), ...config };
1007
+ const modeDefaults = this.configDefaultsForMode();
1008
+ config = { ...modeDefaults, ...config };
1009
+ config.customAgentsLocalOnly ??= modeDefaults.customAgentsLocalOnly;
923
1010
  config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
924
1011
  const callerSessionId = config.sessionId;
925
1012
  const useServerGeneratedId = config.cloud != null && callerSessionId == null;
@@ -938,7 +1025,10 @@ class CopilotClient {
938
1025
  this.connection,
939
1026
  void 0,
940
1027
  this.onGetTraceContext,
941
- { mcpAuthHandler: config.onMcpAuthRequest }
1028
+ {
1029
+ mcpAuthHandler: config.onMcpAuthRequest,
1030
+ managedSettingsEnabled: config.enableManagedSettings
1031
+ }
942
1032
  );
943
1033
  s.registerTools(config.tools);
944
1034
  s.registerCanvases(config.canvases);
@@ -987,6 +1077,7 @@ class CopilotClient {
987
1077
  clientName: config.clientName,
988
1078
  reasoningEffort: config.reasoningEffort,
989
1079
  reasoningSummary: config.reasoningSummary,
1080
+ isExperimentalMode: this.experimentalModeForMode(config.enableExperimentalMode),
990
1081
  contextTier: config.contextTier,
991
1082
  tools: config.tools?.map((tool) => ({
992
1083
  name: tool.name,
@@ -994,13 +1085,16 @@ class CopilotClient {
994
1085
  parameters: toJsonSchema(tool.parameters),
995
1086
  overridesBuiltInTool: tool.overridesBuiltInTool,
996
1087
  skipPermission: tool.skipPermission,
997
- defer: tool.defer
1088
+ defer: tool.defer,
1089
+ metadata: tool.metadata
998
1090
  })),
1091
+ toolSearch: config.toolSearch,
999
1092
  canvases: config.canvases?.map((canvas) => canvas.declaration),
1000
1093
  requestCanvasRenderer: config.requestCanvasRenderer,
1001
1094
  requestExtensions: config.requestExtensions,
1002
1095
  extensionSdkPath: config.extensionSdkPath,
1003
1096
  extensionInfo: config.extensionInfo,
1097
+ canvasProvider: config.canvasProvider,
1004
1098
  commands: config.commands?.map((cmd) => ({
1005
1099
  name: cmd.name,
1006
1100
  description: cmd.description
@@ -1023,10 +1117,12 @@ class CopilotClient {
1023
1117
  requestUserInput: !!config.onUserInputRequest,
1024
1118
  requestElicitation: !!config.onElicitationRequest,
1025
1119
  ...config.enableMcpApps ? { requestMcpApps: true } : {},
1120
+ ...config.githubMcpToolConfig != null ? { githubMcpToolConfig: config.githubMcpToolConfig } : {},
1026
1121
  requestExitPlanMode: !!config.onExitPlanModeRequest,
1027
1122
  requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
1028
1123
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
1029
1124
  workingDirectory: config.workingDirectory,
1125
+ additionalDirectories: config.additionalDirectories,
1030
1126
  streaming: config.streaming,
1031
1127
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
1032
1128
  ...this.onGitHubTelemetry != null ? { enableGitHubTelemetryForwarding: true } : {},
@@ -1034,6 +1130,7 @@ class CopilotClient {
1034
1130
  mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
1035
1131
  envValueMode: "direct",
1036
1132
  customAgents: toWireCustomAgents(config.customAgents),
1133
+ customAgentsLocalOnly: config.customAgentsLocalOnly,
1037
1134
  defaultAgent: config.defaultAgent,
1038
1135
  agent: config.agent,
1039
1136
  configDir: config.configDirectory,
@@ -1050,12 +1147,14 @@ class CopilotClient {
1050
1147
  pluginDirectories: config.pluginDirectories,
1051
1148
  instructionDirectories: config.instructionDirectories,
1052
1149
  disabledSkills: config.disabledSkills,
1150
+ disabledMcpServers: config.disabledMcpServers,
1053
1151
  infiniteSessions: config.infiniteSessions,
1054
1152
  memory: config.memory,
1055
1153
  gitHubToken: config.gitHubToken,
1056
1154
  remoteSession: config.remoteSession,
1057
1155
  cloud: config.cloud,
1058
- expAssignments: config.expAssignments
1156
+ expAssignments: config.expAssignments,
1157
+ enableManagedSettings: config.enableManagedSettings
1059
1158
  });
1060
1159
  const {
1061
1160
  sessionId: returnedSessionId,
@@ -1116,6 +1215,13 @@ class CopilotClient {
1116
1215
  * ```
1117
1216
  */
1118
1217
  async resumeSession(sessionId, config) {
1218
+ return this.resumeSessionInternal(sessionId, config);
1219
+ }
1220
+ /** @internal */
1221
+ async resumeSessionForExtension(sessionId, config, factories) {
1222
+ return this.resumeSessionInternal(sessionId, config, factories);
1223
+ }
1224
+ async resumeSessionInternal(sessionId, config, factories) {
1119
1225
  if (!this.connection) {
1120
1226
  await this.start();
1121
1227
  }
@@ -1124,11 +1230,15 @@ class CopilotClient {
1124
1230
  this.connection,
1125
1231
  void 0,
1126
1232
  this.onGetTraceContext,
1127
- { mcpAuthHandler: config.onMcpAuthRequest }
1233
+ {
1234
+ mcpAuthHandler: config.onMcpAuthRequest,
1235
+ managedSettingsEnabled: config.enableManagedSettings
1236
+ }
1128
1237
  );
1129
1238
  session.registerTools(config.tools);
1130
1239
  session.registerCanvases(config.canvases);
1131
1240
  session.registerCommands(config.commands);
1241
+ session.registerFactories(factories);
1132
1242
  const {
1133
1243
  wireProvider: bearerWireProvider,
1134
1244
  wireProviders: bearerWireProviders,
@@ -1153,7 +1263,9 @@ class CopilotClient {
1153
1263
  if (config.hooks) {
1154
1264
  session.registerHooks(config.hooks);
1155
1265
  }
1156
- config = { ...this.configDefaultsForMode(), ...config };
1266
+ const modeDefaults = this.configDefaultsForMode();
1267
+ config = { ...modeDefaults, ...config };
1268
+ config.customAgentsLocalOnly ??= modeDefaults.customAgentsLocalOnly;
1157
1269
  config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
1158
1270
  const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
1159
1271
  config.systemMessage
@@ -1175,6 +1287,7 @@ class CopilotClient {
1175
1287
  model: config.model,
1176
1288
  reasoningEffort: config.reasoningEffort,
1177
1289
  reasoningSummary: config.reasoningSummary,
1290
+ isExperimentalMode: this.experimentalModeForMode(config.enableExperimentalMode),
1178
1291
  contextTier: config.contextTier,
1179
1292
  systemMessage: wireSystemMessage,
1180
1293
  availableTools: toolFilterOptions.availableTools,
@@ -1190,13 +1303,17 @@ class CopilotClient {
1190
1303
  parameters: toJsonSchema(tool.parameters),
1191
1304
  overridesBuiltInTool: tool.overridesBuiltInTool,
1192
1305
  skipPermission: tool.skipPermission,
1193
- defer: tool.defer
1306
+ defer: tool.defer,
1307
+ metadata: tool.metadata
1194
1308
  })),
1309
+ toolSearch: config.toolSearch,
1195
1310
  canvases: config.canvases?.map((canvas) => canvas.declaration),
1311
+ factories: factories?.map((factory) => factory.meta),
1196
1312
  requestCanvasRenderer: config.requestCanvasRenderer,
1197
1313
  requestExtensions: config.requestExtensions,
1198
1314
  extensionSdkPath: config.extensionSdkPath,
1199
1315
  extensionInfo: config.extensionInfo,
1316
+ canvasProvider: config.canvasProvider,
1200
1317
  commands: config.commands?.map((cmd) => ({
1201
1318
  name: cmd.name,
1202
1319
  description: cmd.description
@@ -1211,10 +1328,12 @@ class CopilotClient {
1211
1328
  requestUserInput: !!config.onUserInputRequest,
1212
1329
  requestElicitation: !!config.onElicitationRequest,
1213
1330
  ...config.enableMcpApps ? { requestMcpApps: true } : {},
1331
+ ...config.githubMcpToolConfig != null ? { githubMcpToolConfig: config.githubMcpToolConfig } : {},
1214
1332
  requestExitPlanMode: !!config.onExitPlanModeRequest,
1215
1333
  requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
1216
1334
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
1217
1335
  workingDirectory: config.workingDirectory,
1336
+ additionalDirectories: config.additionalDirectories,
1218
1337
  configDir: config.configDirectory,
1219
1338
  enableConfigDiscovery: config.enableConfigDiscovery,
1220
1339
  skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
@@ -1232,12 +1351,14 @@ class CopilotClient {
1232
1351
  mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
1233
1352
  envValueMode: "direct",
1234
1353
  customAgents: toWireCustomAgents(config.customAgents),
1354
+ customAgentsLocalOnly: config.customAgentsLocalOnly,
1235
1355
  defaultAgent: config.defaultAgent,
1236
1356
  agent: config.agent,
1237
1357
  skillDirectories: config.skillDirectories,
1238
1358
  pluginDirectories: config.pluginDirectories,
1239
1359
  instructionDirectories: config.instructionDirectories,
1240
1360
  disabledSkills: config.disabledSkills,
1361
+ disabledMcpServers: config.disabledMcpServers,
1241
1362
  infiniteSessions: config.infiniteSessions,
1242
1363
  memory: config.memory,
1243
1364
  disableResume: config.suppressResumeEvent,
@@ -1245,7 +1366,8 @@ class CopilotClient {
1245
1366
  gitHubToken: config.gitHubToken,
1246
1367
  remoteSession: config.remoteSession,
1247
1368
  openCanvases: config.openCanvases,
1248
- expAssignments: config.expAssignments
1369
+ expAssignments: config.expAssignments,
1370
+ enableManagedSettings: config.enableManagedSettings
1249
1371
  });
1250
1372
  const { workspacePath, capabilities, openCanvases } = response;
1251
1373
  session["_workspacePath"] = workspacePath;
@@ -1371,9 +1493,11 @@ class CopilotClient {
1371
1493
  const raceAgainstExit = (p) => this.processExitPromise ? Promise.race([p, this.processExitPromise]) : p;
1372
1494
  let serverVersion;
1373
1495
  try {
1374
- const result = await raceAgainstExit(
1375
- this.internalRpc.connect({ token: this.effectiveConnectionToken })
1376
- );
1496
+ const connectParams = { token: this.effectiveConnectionToken };
1497
+ if (this.onGitHubTelemetry != null) {
1498
+ connectParams.enableGitHubTelemetryForwarding = true;
1499
+ }
1500
+ const result = await raceAgainstExit(this.internalRpc.connect(connectParams));
1377
1501
  serverVersion = result.protocolVersion;
1378
1502
  } catch (err) {
1379
1503
  if (err instanceof import_node.ResponseError && (err.code === import_node.ErrorCodes.MethodNotFound || err.message === "Unhandled method connect")) {
@@ -1592,6 +1716,41 @@ class CopilotClient {
1592
1716
  this.sessionLifecycleHandlers.delete(wildcardHandler);
1593
1717
  };
1594
1718
  }
1719
+ /**
1720
+ * Builds the environment for the spawned runtime child process (stdio/TCP): applies
1721
+ * the auth token, connection token, `COPILOT_HOME`, keychain setting, and telemetry
1722
+ * variables on top of the effective env. Not used by the in-process (FFI) transport,
1723
+ * whose worker inherits the host process's ambient environment
1724
+ * (see {@link CopilotClient.startInProcessFfi}).
1725
+ */
1726
+ buildRuntimeEnv() {
1727
+ const env = { ...this.resolvedEnv };
1728
+ delete env.NODE_DEBUG;
1729
+ if (this.options.gitHubToken) {
1730
+ env.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
1731
+ }
1732
+ if (this.effectiveConnectionToken) {
1733
+ env.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
1734
+ }
1735
+ if (this.options.baseDirectory) {
1736
+ env.COPILOT_HOME = this.options.baseDirectory;
1737
+ }
1738
+ if (this.options.mode === "empty") {
1739
+ env.COPILOT_DISABLE_KEYTAR = "1";
1740
+ }
1741
+ if (this.options.telemetry) {
1742
+ const t = this.options.telemetry;
1743
+ env.COPILOT_OTEL_ENABLED = "true";
1744
+ if (t.otlpEndpoint !== void 0) env.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
1745
+ if (t.otlpProtocol !== void 0) env.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
1746
+ if (t.filePath !== void 0) env.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
1747
+ if (t.exporterType !== void 0) env.COPILOT_OTEL_EXPORTER_TYPE = t.exporterType;
1748
+ if (t.sourceName !== void 0) env.COPILOT_OTEL_SOURCE_NAME = t.sourceName;
1749
+ if (t.captureContent !== void 0)
1750
+ env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = String(t.captureContent);
1751
+ }
1752
+ return env;
1753
+ }
1595
1754
  /**
1596
1755
  * Start the CLI server process
1597
1756
  */
@@ -1625,43 +1784,12 @@ class CopilotClient {
1625
1784
  if (this.options.enableRemoteSessions) {
1626
1785
  args.push("--remote");
1627
1786
  }
1628
- const envWithoutNodeDebug = { ...this.resolvedEnv };
1629
- delete envWithoutNodeDebug.NODE_DEBUG;
1630
- if (this.options.gitHubToken) {
1631
- envWithoutNodeDebug.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
1632
- }
1633
- if (this.effectiveConnectionToken) {
1634
- envWithoutNodeDebug.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
1635
- }
1636
- if (this.options.baseDirectory) {
1637
- envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
1638
- }
1639
- if (this.options.mode === "empty") {
1640
- envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
1641
- }
1787
+ const envWithoutNodeDebug = this.buildRuntimeEnv();
1642
1788
  if (!this.resolvedCliPath) {
1643
1789
  throw new Error(
1644
1790
  "Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime."
1645
1791
  );
1646
1792
  }
1647
- if (this.options.telemetry) {
1648
- const t = this.options.telemetry;
1649
- envWithoutNodeDebug.COPILOT_OTEL_ENABLED = "true";
1650
- if (t.otlpEndpoint !== void 0)
1651
- envWithoutNodeDebug.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
1652
- if (t.otlpProtocol !== void 0)
1653
- envWithoutNodeDebug.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
1654
- if (t.filePath !== void 0)
1655
- envWithoutNodeDebug.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
1656
- if (t.exporterType !== void 0)
1657
- envWithoutNodeDebug.COPILOT_OTEL_EXPORTER_TYPE = t.exporterType;
1658
- if (t.sourceName !== void 0)
1659
- envWithoutNodeDebug.COPILOT_OTEL_SOURCE_NAME = t.sourceName;
1660
- if (t.captureContent !== void 0)
1661
- envWithoutNodeDebug.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = String(
1662
- t.captureContent
1663
- );
1664
- }
1665
1793
  if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) {
1666
1794
  throw new Error(
1667
1795
  `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
@@ -1780,11 +1908,103 @@ stderr: ${stderrOutput}`
1780
1908
  return this.connectToParentProcessViaStdio();
1781
1909
  case "stdio":
1782
1910
  return this.connectToChildProcessViaStdio();
1911
+ case "inprocess":
1912
+ return this.connectViaFfi();
1783
1913
  case "tcp":
1784
1914
  case "uri":
1785
1915
  return this.connectViaTcp();
1786
1916
  }
1787
1917
  }
1918
+ /** Starts the in-process FFI runtime with SDK-managed typed options. */
1919
+ async startInProcessFfi() {
1920
+ const entrypoint = this.resolveCliPathForFfi();
1921
+ const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
1922
+ const environment = {};
1923
+ if (this.options.gitHubToken) {
1924
+ environment.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
1925
+ }
1926
+ if (this.options.baseDirectory) {
1927
+ environment.COPILOT_HOME = this.options.baseDirectory;
1928
+ }
1929
+ if (this.options.mode === "empty") {
1930
+ environment.COPILOT_DISABLE_KEYTAR = "1";
1931
+ }
1932
+ const args = [];
1933
+ if (this.options.logLevel) {
1934
+ args.push("--log-level", this.options.logLevel);
1935
+ }
1936
+ if (this.options.gitHubToken) {
1937
+ args.push("--auth-token-env", "COPILOT_SDK_AUTH_TOKEN");
1938
+ }
1939
+ if (!this.options.useLoggedInUser) {
1940
+ args.push("--no-auto-login");
1941
+ }
1942
+ if (this.options.sessionIdleTimeoutSeconds > 0) {
1943
+ args.push("--session-idle-timeout", this.options.sessionIdleTimeoutSeconds.toString());
1944
+ }
1945
+ if (this.options.enableRemoteSessions) {
1946
+ args.push("--remote");
1947
+ }
1948
+ const host = FfiRuntimeHost.create(
1949
+ entrypoint,
1950
+ CopilotClient.getNapiPrebuildsFolder(entrypoint),
1951
+ environment,
1952
+ args
1953
+ );
1954
+ this.ffiHost = host;
1955
+ await host.start();
1956
+ }
1957
+ /**
1958
+ * Connect to the in-process FFI runtime host over its receive/send streams,
1959
+ * reusing the same `vscode-jsonrpc` framing as the stdio transport.
1960
+ */
1961
+ async connectViaFfi() {
1962
+ if (!this.ffiHost) {
1963
+ throw new Error("In-process FFI runtime host not started");
1964
+ }
1965
+ this.messageWriter = new TeardownResilientStreamMessageWriter(this.ffiHost.sendStream);
1966
+ this.connection = (0, import_node.createMessageConnection)(
1967
+ new import_node.StreamMessageReader(this.ffiHost.receiveStream),
1968
+ this.messageWriter
1969
+ );
1970
+ this.attachConnectionHandlers();
1971
+ this.connection.listen();
1972
+ }
1973
+ /**
1974
+ * Resolves the CLI entrypoint used for in-process FFI hosting: `COPILOT_CLI_PATH`
1975
+ * when set, otherwise the bundled platform-package entrypoint.
1976
+ */
1977
+ resolveCliPathForFfi() {
1978
+ return this.resolvedEnv.COPILOT_CLI_PATH ?? getBundledCliPath();
1979
+ }
1980
+ /**
1981
+ * Returns the napi prebuilds folder name for the current host — the
1982
+ * `<node-platform>-<arch>` convention (e.g. `win32-x64`, `darwin-arm64`,
1983
+ * `linux-x64`, `linuxmusl-x64`) under which the runtime ships
1984
+ * `prebuilds/<folder>/runtime.node`.
1985
+ */
1986
+ static getNapiPrebuildsFolder(entrypoint) {
1987
+ const arch = process.arch;
1988
+ if (arch !== "x64" && arch !== "arm64") {
1989
+ throw new Error(`Unsupported architecture '${arch}' for in-process FFI hosting.`);
1990
+ }
1991
+ let platform = process.platform;
1992
+ if (platform === "linux" && CopilotClient.isMusl(entrypoint)) {
1993
+ platform = "linuxmusl";
1994
+ }
1995
+ return `${platform}-${arch}`;
1996
+ }
1997
+ static isMusl(entrypoint) {
1998
+ if (entrypoint.includes(`copilot-linuxmusl-${process.arch}`)) {
1999
+ return true;
2000
+ }
2001
+ if (entrypoint.includes(`copilot-linux-${process.arch}`)) {
2002
+ return false;
2003
+ }
2004
+ const report = process.report?.getReport();
2005
+ const header = report && "header" in report ? report.header : void 0;
2006
+ return header !== void 0 && header.glibcVersionRuntime === void 0;
2007
+ }
1788
2008
  /**
1789
2009
  * Connect to child via stdio pipes
1790
2010
  */
@@ -1879,10 +2099,6 @@ stderr: ${stderrOutput}`
1879
2099
  "autoModeSwitch.request",
1880
2100
  async (params) => await this.handleAutoModeSwitchRequest(params)
1881
2101
  );
1882
- this.connection.onRequest(
1883
- "hooks.invoke",
1884
- async (params) => await this.handleHooksInvoke(params)
1885
- );
1886
2102
  this.connection.onRequest(
1887
2103
  "systemMessage.transform",
1888
2104
  async (params) => await this.handleSystemMessageTransform(params)
@@ -1894,6 +2110,12 @@ stderr: ${stderrOutput}`
1894
2110
  return session.clientSessionApis;
1895
2111
  });
1896
2112
  (0, import_rpc.registerClientGlobalApiHandlers)(this.connection, this.clientGlobalHandlers);
2113
+ this.connection.onRequest(
2114
+ "hooks.invoke",
2115
+ async (params) => {
2116
+ return await this.handleHooksInvoke(params);
2117
+ }
2118
+ );
1897
2119
  this.connection.onClose(() => {
1898
2120
  this.state = "disconnected";
1899
2121
  });
@@ -1906,8 +2128,9 @@ stderr: ${stderrOutput}`
1906
2128
  return;
1907
2129
  }
1908
2130
  const session = this.sessions.get(notification.sessionId);
2131
+ const event = notification.event;
1909
2132
  if (session) {
1910
- session._dispatchEvent(notification.event);
2133
+ session._dispatchEvent(event);
1911
2134
  }
1912
2135
  }
1913
2136
  handleSessionLifecycleNotification(notification) {
@@ -180,6 +180,9 @@ class CopilotRequestHandler {
180
180
  const ctx = {
181
181
  requestId: exchange.requestId,
182
182
  sessionId: exchange.sessionId,
183
+ agentId: exchange.agentId,
184
+ parentAgentId: exchange.parentAgentId,
185
+ interactionType: exchange.interactionType,
183
186
  transport: exchange.transport,
184
187
  url: exchange.url,
185
188
  headers: exchange.headers,
@@ -305,6 +308,9 @@ function routeChunk(exchange, params) {
305
308
  class CopilotRequestExchange {
306
309
  requestId;
307
310
  sessionId;
311
+ agentId;
312
+ parentAgentId;
313
+ interactionType;
308
314
  method = "GET";
309
315
  url = "";
310
316
  headers = {};
@@ -324,6 +330,9 @@ class CopilotRequestExchange {
324
330
  /** Fill in the request context once the matching start frame arrives. */
325
331
  setContext(params) {
326
332
  this.sessionId = params.sessionId;
333
+ this.agentId = params.agentId;
334
+ this.parentAgentId = params.parentAgentId;
335
+ this.interactionType = params.interactionType;
327
336
  this.method = params.method;
328
337
  this.url = params.url;
329
338
  this.headers = params.headers;