@github/copilot-sdk 1.0.0-beta.5 → 1.0.0-beta.6

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.
@@ -36,11 +36,6 @@ var import_sessionFsProvider = require("./sessionFsProvider.js");
36
36
  var import_telemetry = require("./telemetry.js");
37
37
  var import_types = require("./types.js");
38
38
  const import_meta = {};
39
- function toWireProviderConfig(provider) {
40
- const { maxInputTokens, ...rest } = provider;
41
- if (maxInputTokens === void 0) return rest;
42
- return { ...rest, maxPromptTokens: maxInputTokens };
43
- }
44
39
  const MIN_PROTOCOL_VERSION = 2;
45
40
  function isZodSchema(value) {
46
41
  return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
@@ -52,6 +47,26 @@ function toJsonSchema(parameters) {
52
47
  }
53
48
  return parameters;
54
49
  }
50
+ function toWireMcpServers(mcpServers) {
51
+ if (!mcpServers) return void 0;
52
+ return Object.fromEntries(
53
+ Object.entries(mcpServers).map(([name, server]) => {
54
+ if ("workingDirectory" in server) {
55
+ const { workingDirectory, ...rest } = server;
56
+ return [name, { ...rest, cwd: workingDirectory }];
57
+ }
58
+ return [name, server];
59
+ })
60
+ );
61
+ }
62
+ function toWireCustomAgents(agents) {
63
+ if (!agents) return void 0;
64
+ return agents.map((agent) => {
65
+ if (!agent.mcpServers) return agent;
66
+ const { mcpServers, ...rest } = agent;
67
+ return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
68
+ });
69
+ }
55
70
  function extractTransformCallbacks(systemMessage) {
56
71
  if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
57
72
  return { wirePayload: systemMessage, transformCallbacks: void 0 };
@@ -105,12 +120,18 @@ class CopilotClient {
105
120
  cliProcess = null;
106
121
  connection = null;
107
122
  socket = null;
108
- actualPort = null;
123
+ runtimePort = null;
109
124
  actualHost = "localhost";
110
125
  state = "disconnected";
111
126
  sessions = /* @__PURE__ */ new Map();
112
127
  stderrBuffer = "";
113
128
  // Captures CLI stderr for error messages
129
+ /** Resolved connection mode chosen in the constructor. */
130
+ connectionConfig;
131
+ /** Resolved path to the runtime executable (only used for child-process kinds). */
132
+ resolvedCliPath;
133
+ /** Resolved environment passed to the spawned runtime. */
134
+ resolvedEnv;
114
135
  options;
115
136
  isExternalServer = false;
116
137
  forceStopping = false;
@@ -159,86 +180,79 @@ class CopilotClient {
159
180
  * Creates a new CopilotClient instance.
160
181
  *
161
182
  * @param options - Configuration options for the client
162
- * @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath)
163
183
  *
164
184
  * @example
165
185
  * ```typescript
166
- * // Default options - spawns CLI server using stdio
186
+ * // Default: spawns the bundled runtime over stdio
167
187
  * const client = new CopilotClient();
168
188
  *
169
- * // Connect to an existing server
170
- * const client = new CopilotClient({ cliUrl: "localhost:3000" });
189
+ * // Connect to an existing runtime
190
+ * const client = new CopilotClient({
191
+ * connection: RuntimeConnection.forUri("localhost:3000"),
192
+ * });
193
+ *
194
+ * // Spawn the runtime over TCP on a chosen port
195
+ * const client = new CopilotClient({
196
+ * connection: RuntimeConnection.forTcp({ port: 9001 }),
197
+ * });
171
198
  *
172
- * // Custom CLI path with specific log level
199
+ * // Use a custom runtime binary
173
200
  * const client = new CopilotClient({
174
- * cliPath: "/usr/local/bin/copilot",
175
- * logLevel: "debug"
201
+ * connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }),
202
+ * logLevel: "debug",
176
203
  * });
177
204
  * ```
178
205
  */
179
206
  constructor(options = {}) {
180
- if (options.cliUrl && (options.useStdio === true || options.cliPath)) {
181
- throw new Error("cliUrl is mutually exclusive with useStdio and cliPath");
182
- }
183
- if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) {
207
+ const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" };
208
+ if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
184
209
  throw new Error(
185
- "isChildProcess must be used in conjunction with useStdio and not with cliUrl"
210
+ "gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
186
211
  );
187
212
  }
188
- if (options.cliUrl && (options.gitHubToken || options.useLoggedInUser !== void 0)) {
189
- throw new Error(
190
- "gitHubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)"
191
- );
192
- }
193
- if (options.tcpConnectionToken !== void 0) {
194
- if (typeof options.tcpConnectionToken !== "string" || options.tcpConnectionToken.length === 0) {
195
- throw new Error("tcpConnectionToken must be a non-empty string");
196
- }
197
- if (options.useStdio === true) {
198
- throw new Error("tcpConnectionToken cannot be used with useStdio: true");
213
+ if (conn.kind === "tcp" && conn.connectionToken !== void 0) {
214
+ if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) {
215
+ throw new Error("connectionToken must be a non-empty string");
199
216
  }
200
217
  }
201
- const willUseStdio = options.cliUrl ? false : options.useStdio ?? true;
202
- const sdkSpawnsCli = !willUseStdio && !options.cliUrl && !options.isChildProcess;
203
- this.effectiveConnectionToken = options.tcpConnectionToken ?? (sdkSpawnsCli ? (0, import_node_crypto.randomUUID)() : void 0);
218
+ this.connectionConfig = conn;
204
219
  if (options.sessionFs) {
205
220
  this.validateSessionFsConfig(options.sessionFs);
206
221
  }
207
- if (options.cliUrl) {
208
- const { host, port } = this.parseCliUrl(options.cliUrl);
222
+ if (conn.kind === "uri") {
223
+ const { host, port } = this.parseCliUrl(conn.url);
209
224
  this.actualHost = host;
210
- this.actualPort = port;
225
+ this.runtimePort = port;
211
226
  this.isExternalServer = true;
212
- }
213
- if (options.isChildProcess) {
227
+ } else if (conn.kind === "parent-process") {
214
228
  this.isExternalServer = true;
215
229
  }
230
+ if (conn.kind === "tcp") {
231
+ this.effectiveConnectionToken = conn.connectionToken ?? (0, import_node_crypto.randomUUID)();
232
+ } else if (conn.kind === "uri") {
233
+ this.effectiveConnectionToken = conn.connectionToken;
234
+ }
216
235
  this.onListModels = options.onListModels;
217
236
  this.onGetTraceContext = options.onGetTraceContext;
218
237
  this.sessionFsConfig = options.sessionFs ?? null;
219
238
  const effectiveEnv = options.env ?? process.env;
239
+ this.resolvedEnv = effectiveEnv;
240
+ this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0;
241
+ const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
242
+ this.connectionExtraArgs = [...connArgs];
220
243
  this.options = {
221
- cliPath: options.cliUrl ? void 0 : options.cliPath || effectiveEnv.COPILOT_CLI_PATH || getBundledCliPath(),
222
- cliArgs: options.cliArgs ?? [],
223
- cwd: options.cwd ?? process.cwd(),
224
- port: options.port || 0,
225
- useStdio: options.cliUrl ? false : options.useStdio ?? true,
226
- // Default to stdio unless cliUrl is provided
227
- isChildProcess: options.isChildProcess ?? false,
228
- cliUrl: options.cliUrl,
229
- logLevel: options.logLevel || "debug",
230
- autoStart: options.autoStart ?? true,
231
- autoRestart: false,
232
- env: effectiveEnv,
244
+ workingDirectory: options.workingDirectory ?? process.cwd(),
245
+ logLevel: options.logLevel,
233
246
  gitHubToken: options.gitHubToken,
234
- // Default useLoggedInUser to false when gitHubToken is provided, otherwise true
247
+ // Default useLoggedInUser to false when gitHubToken is provided, otherwise true.
235
248
  useLoggedInUser: options.useLoggedInUser ?? (options.gitHubToken ? false : true),
236
249
  telemetry: options.telemetry,
237
- copilotHome: options.copilotHome,
250
+ baseDirectory: options.baseDirectory,
238
251
  sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
239
- remote: options.remote ?? false
252
+ enableRemoteSessions: options.enableRemoteSessions ?? false
240
253
  };
241
254
  }
255
+ connectionExtraArgs = [];
242
256
  /**
243
257
  * Parse CLI URL into host and port
244
258
  * Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
@@ -276,12 +290,12 @@ class CopilotClient {
276
290
  if (!this.sessionFsConfig) {
277
291
  return;
278
292
  }
279
- if (!config.createSessionFsHandler) {
293
+ if (!config.createSessionFsProvider) {
280
294
  throw new Error(
281
- "createSessionFsHandler is required in session config when sessionFs is enabled in client options."
295
+ "createSessionFsProvider is required in session config when sessionFs is enabled in client options."
282
296
  );
283
297
  }
284
- const provider = config.createSessionFsHandler(session);
298
+ const provider = config.createSessionFsProvider(session);
285
299
  if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) {
286
300
  throw new Error(
287
301
  "SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
@@ -295,14 +309,14 @@ class CopilotClient {
295
309
  * If connecting to an external server (via cliUrl), only establishes the connection.
296
310
  * Otherwise, spawns the CLI server process and then connects.
297
311
  *
298
- * This method is called automatically when creating a session if `autoStart` is true (default).
312
+ * This method is called automatically the first time you create or resume a session.
299
313
  *
300
314
  * @returns A promise that resolves when the connection is established
301
315
  * @throws Error if the server fails to start or the connection fails
302
316
  *
303
317
  * @example
304
318
  * ```typescript
305
- * const client = new CopilotClient({ autoStart: false });
319
+ * const client = new CopilotClient();
306
320
  * await client.start();
307
321
  * // Now ready to create sessions
308
322
  * ```
@@ -397,8 +411,15 @@ class CopilotClient {
397
411
  }
398
412
  this.modelsCache = null;
399
413
  if (this.socket) {
414
+ const socket = this.socket;
415
+ this.socket = null;
400
416
  try {
401
- this.socket.end();
417
+ if (!socket.destroyed) {
418
+ await new Promise((resolve) => {
419
+ socket.once("close", () => resolve());
420
+ socket.end();
421
+ });
422
+ }
402
423
  } catch (error) {
403
424
  errors.push(
404
425
  new Error(
@@ -406,11 +427,18 @@ class CopilotClient {
406
427
  )
407
428
  );
408
429
  }
409
- this.socket = null;
410
430
  }
411
431
  if (this.cliProcess && !this.isExternalServer) {
432
+ const child = this.cliProcess;
433
+ this.cliProcess = null;
412
434
  try {
413
- this.cliProcess.kill();
435
+ if (child.exitCode === null && child.signalCode === null) {
436
+ const exited = new Promise((resolve) => {
437
+ child.once("exit", () => resolve());
438
+ });
439
+ child.kill();
440
+ await exited;
441
+ }
414
442
  } catch (error) {
415
443
  errors.push(
416
444
  new Error(
@@ -418,18 +446,32 @@ class CopilotClient {
418
446
  )
419
447
  );
420
448
  }
421
- this.cliProcess = null;
422
449
  }
423
450
  if (this.cliStartTimeout) {
424
451
  clearTimeout(this.cliStartTimeout);
425
452
  this.cliStartTimeout = null;
426
453
  }
427
454
  this.state = "disconnected";
428
- this.actualPort = null;
455
+ this.runtimePort = null;
429
456
  this.stderrBuffer = "";
430
457
  this.processExitPromise = null;
431
458
  return errors;
432
459
  }
460
+ /**
461
+ * Alias for {@link stop} that lets `CopilotClient` participate in `await using`
462
+ * blocks for automatic cleanup.
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * await using client = new CopilotClient();
467
+ * const session = await client.createSession({ onPermissionRequest: approveAll });
468
+ * await session.sendAndWait("Hello");
469
+ * // client.stop() is called automatically when the block exits.
470
+ * ```
471
+ */
472
+ async [Symbol.asyncDispose]() {
473
+ await this.stop();
474
+ }
433
475
  /**
434
476
  * Forcefully stops the CLI server without graceful cleanup.
435
477
  *
@@ -486,7 +528,7 @@ class CopilotClient {
486
528
  this.cliStartTimeout = null;
487
529
  }
488
530
  this.state = "disconnected";
489
- this.actualPort = null;
531
+ this.runtimePort = null;
490
532
  this.stderrBuffer = "";
491
533
  this.processExitPromise = null;
492
534
  }
@@ -494,12 +536,11 @@ class CopilotClient {
494
536
  * Creates a new conversation session with the Copilot CLI.
495
537
  *
496
538
  * Sessions maintain conversation state, handle events, and manage tool execution.
497
- * If the client is not connected and `autoStart` is enabled, this will automatically
498
- * start the connection.
539
+ * If the client is not connected, this method automatically starts the connection.
499
540
  *
500
541
  * @param config - Optional configuration for the session
501
542
  * @returns A promise that resolves with the created session
502
- * @throws Error if the client is not connected and autoStart is disabled
543
+ * @throws Error if the client fails to start
503
544
  *
504
545
  * @example
505
546
  * ```typescript
@@ -521,11 +562,7 @@ class CopilotClient {
521
562
  */
522
563
  async createSession(config) {
523
564
  if (!this.connection) {
524
- if (this.options.autoStart) {
525
- await this.start();
526
- } else {
527
- throw new Error("Client not connected. Call start() first.");
528
- }
565
+ await this.start();
529
566
  }
530
567
  const sessionId = config.sessionId ?? (0, import_node_crypto.randomUUID)();
531
568
  const session = new import_session.CopilotSession(
@@ -543,11 +580,11 @@ class CopilotClient {
543
580
  if (config.onElicitationRequest) {
544
581
  session.registerElicitationHandler(config.onElicitationRequest);
545
582
  }
546
- if (config.onExitPlanMode) {
547
- session.registerExitPlanModeHandler(config.onExitPlanMode);
583
+ if (config.onExitPlanModeRequest) {
584
+ session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
548
585
  }
549
- if (config.onAutoModeSwitch) {
550
- session.registerAutoModeSwitchHandler(config.onAutoModeSwitch);
586
+ if (config.onAutoModeSwitchRequest) {
587
+ session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
551
588
  }
552
589
  if (config.hooks) {
553
590
  session.registerHooks(config.hooks);
@@ -584,21 +621,21 @@ class CopilotClient {
584
621
  systemMessage: wireSystemMessage,
585
622
  availableTools: config.availableTools,
586
623
  excludedTools: config.excludedTools,
587
- provider: config.provider ? toWireProviderConfig(config.provider) : void 0,
624
+ provider: config.provider,
588
625
  enableSessionTelemetry: config.enableSessionTelemetry,
589
626
  modelCapabilities: config.modelCapabilities,
590
627
  requestPermission: true,
591
628
  requestUserInput: !!config.onUserInputRequest,
592
629
  requestElicitation: !!config.onElicitationRequest,
593
- requestExitPlanMode: !!config.onExitPlanMode,
594
- requestAutoModeSwitch: !!config.onAutoModeSwitch,
630
+ requestExitPlanMode: !!config.onExitPlanModeRequest,
631
+ requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
595
632
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
596
633
  workingDirectory: config.workingDirectory,
597
634
  streaming: config.streaming,
598
635
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
599
- mcpServers: config.mcpServers,
636
+ mcpServers: toWireMcpServers(config.mcpServers),
600
637
  envValueMode: "direct",
601
- customAgents: config.customAgents,
638
+ customAgents: toWireCustomAgents(config.customAgents),
602
639
  defaultAgent: config.defaultAgent,
603
640
  agent: config.agent,
604
641
  configDir: config.configDir,
@@ -646,11 +683,7 @@ class CopilotClient {
646
683
  */
647
684
  async resumeSession(sessionId, config) {
648
685
  if (!this.connection) {
649
- if (this.options.autoStart) {
650
- await this.start();
651
- } else {
652
- throw new Error("Client not connected. Call start() first.");
653
- }
686
+ await this.start();
654
687
  }
655
688
  const session = new import_session.CopilotSession(
656
689
  sessionId,
@@ -667,11 +700,11 @@ class CopilotClient {
667
700
  if (config.onElicitationRequest) {
668
701
  session.registerElicitationHandler(config.onElicitationRequest);
669
702
  }
670
- if (config.onExitPlanMode) {
671
- session.registerExitPlanModeHandler(config.onExitPlanMode);
703
+ if (config.onExitPlanModeRequest) {
704
+ session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
672
705
  }
673
- if (config.onAutoModeSwitch) {
674
- session.registerAutoModeSwitchHandler(config.onAutoModeSwitch);
706
+ if (config.onAutoModeSwitchRequest) {
707
+ session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
675
708
  }
676
709
  if (config.hooks) {
677
710
  session.registerHooks(config.hooks);
@@ -709,29 +742,29 @@ class CopilotClient {
709
742
  name: cmd.name,
710
743
  description: cmd.description
711
744
  })),
712
- provider: config.provider ? toWireProviderConfig(config.provider) : void 0,
745
+ provider: config.provider,
713
746
  modelCapabilities: config.modelCapabilities,
714
747
  requestPermission: config.onPermissionRequest !== import_types.defaultJoinSessionPermissionHandler,
715
748
  requestUserInput: !!config.onUserInputRequest,
716
749
  requestElicitation: !!config.onElicitationRequest,
717
- requestExitPlanMode: !!config.onExitPlanMode,
718
- requestAutoModeSwitch: !!config.onAutoModeSwitch,
750
+ requestExitPlanMode: !!config.onExitPlanModeRequest,
751
+ requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
719
752
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
720
753
  workingDirectory: config.workingDirectory,
721
754
  configDir: config.configDir,
722
755
  enableConfigDiscovery: config.enableConfigDiscovery,
723
756
  streaming: config.streaming,
724
757
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
725
- mcpServers: config.mcpServers,
758
+ mcpServers: toWireMcpServers(config.mcpServers),
726
759
  envValueMode: "direct",
727
- customAgents: config.customAgents,
760
+ customAgents: toWireCustomAgents(config.customAgents),
728
761
  defaultAgent: config.defaultAgent,
729
762
  agent: config.agent,
730
763
  skillDirectories: config.skillDirectories,
731
764
  instructionDirectories: config.instructionDirectories,
732
765
  disabledSkills: config.disabledSkills,
733
766
  infiniteSessions: config.infiniteSessions,
734
- disableResume: config.disableResume,
767
+ suppressResumeEvent: config.suppressResumeEvent,
735
768
  continuePendingWork: config.continuePendingWork,
736
769
  gitHubToken: config.gitHubToken,
737
770
  remoteSession: config.remoteSession
@@ -961,8 +994,13 @@ class CopilotClient {
961
994
  if (!this.connection) {
962
995
  throw new Error("Client not connected");
963
996
  }
997
+ let wireFilter;
998
+ if (filter) {
999
+ const { workingDirectory, ...rest } = filter;
1000
+ wireFilter = { ...rest, cwd: workingDirectory };
1001
+ }
964
1002
  const response = await this.connection.sendRequest("session.list", {
965
- filter
1003
+ filter: wireFilter
966
1004
  });
967
1005
  const { sessions } = response;
968
1006
  return sessions.map(CopilotClient.toSessionMetadata);
@@ -997,13 +1035,19 @@ class CopilotClient {
997
1035
  return CopilotClient.toSessionMetadata(session);
998
1036
  }
999
1037
  static toSessionMetadata(raw) {
1038
+ const { context } = raw;
1000
1039
  return {
1001
1040
  sessionId: raw.sessionId,
1002
1041
  startTime: new Date(raw.startTime),
1003
1042
  modifiedTime: new Date(raw.modifiedTime),
1004
1043
  summary: raw.summary,
1005
1044
  isRemote: raw.isRemote,
1006
- context: raw.context
1045
+ context: context ? {
1046
+ workingDirectory: context.cwd,
1047
+ gitRoot: context.gitRoot,
1048
+ repository: context.repository,
1049
+ branch: context.branch
1050
+ } : void 0
1007
1051
  };
1008
1052
  }
1009
1053
  /**
@@ -1056,7 +1100,7 @@ class CopilotClient {
1056
1100
  throw new Error(result.error || "Failed to set foreground session");
1057
1101
  }
1058
1102
  }
1059
- on(eventTypeOrHandler, handler) {
1103
+ onLifecycle(eventTypeOrHandler, handler) {
1060
1104
  if (typeof eventTypeOrHandler === "string" && handler) {
1061
1105
  const eventType = eventTypeOrHandler;
1062
1106
  if (!this.typedLifecycleHandlers.has(eventType)) {
@@ -1083,17 +1127,17 @@ class CopilotClient {
1083
1127
  async startCLIServer() {
1084
1128
  return new Promise((resolve, reject) => {
1085
1129
  this.stderrBuffer = "";
1086
- const args = [
1087
- ...this.options.cliArgs,
1088
- "--headless",
1089
- "--no-auto-update",
1090
- "--log-level",
1091
- this.options.logLevel
1092
- ];
1093
- if (this.options.useStdio) {
1130
+ const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
1131
+ if (this.options.logLevel) {
1132
+ args.push("--log-level", this.options.logLevel);
1133
+ }
1134
+ if (this.connectionConfig.kind === "stdio") {
1094
1135
  args.push("--stdio");
1095
- } else if (this.options.port > 0) {
1096
- args.push("--port", this.options.port.toString());
1136
+ } else if (this.connectionConfig.kind === "tcp") {
1137
+ const requestedPort = this.connectionConfig.port ?? 0;
1138
+ if (requestedPort > 0) {
1139
+ args.push("--port", requestedPort.toString());
1140
+ }
1097
1141
  }
1098
1142
  if (this.options.gitHubToken) {
1099
1143
  args.push("--auth-token-env", "COPILOT_SDK_AUTH_TOKEN");
@@ -1107,10 +1151,10 @@ class CopilotClient {
1107
1151
  this.options.sessionIdleTimeoutSeconds.toString()
1108
1152
  );
1109
1153
  }
1110
- if (this.options.remote) {
1154
+ if (this.options.enableRemoteSessions) {
1111
1155
  args.push("--remote");
1112
1156
  }
1113
- const envWithoutNodeDebug = { ...this.options.env };
1157
+ const envWithoutNodeDebug = { ...this.resolvedEnv };
1114
1158
  delete envWithoutNodeDebug.NODE_DEBUG;
1115
1159
  if (this.options.gitHubToken) {
1116
1160
  envWithoutNodeDebug.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
@@ -1118,12 +1162,12 @@ class CopilotClient {
1118
1162
  if (this.effectiveConnectionToken) {
1119
1163
  envWithoutNodeDebug.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
1120
1164
  }
1121
- if (this.options.copilotHome) {
1122
- envWithoutNodeDebug.COPILOT_HOME = this.options.copilotHome;
1165
+ if (this.options.baseDirectory) {
1166
+ envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
1123
1167
  }
1124
- if (!this.options.cliPath) {
1168
+ if (!this.resolvedCliPath) {
1125
1169
  throw new Error(
1126
- "Path to Copilot CLI is required. Please provide it via the cliPath option, or use cliUrl to rely on a remote CLI."
1170
+ "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."
1127
1171
  );
1128
1172
  }
1129
1173
  if (this.options.telemetry) {
@@ -1142,31 +1186,31 @@ class CopilotClient {
1142
1186
  t.captureContent
1143
1187
  );
1144
1188
  }
1145
- if (!(0, import_node_fs.existsSync)(this.options.cliPath)) {
1189
+ if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) {
1146
1190
  throw new Error(
1147
- `Copilot CLI not found at ${this.options.cliPath}. Ensure @github/copilot is installed.`
1191
+ `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
1148
1192
  );
1149
1193
  }
1150
- const stdioConfig = this.options.useStdio ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
1151
- const isJsFile = this.options.cliPath.endsWith(".js");
1194
+ const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
1195
+ const isJsFile = this.resolvedCliPath.endsWith(".js");
1152
1196
  if (isJsFile) {
1153
- this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.options.cliPath, ...args], {
1197
+ this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.resolvedCliPath, ...args], {
1154
1198
  stdio: stdioConfig,
1155
- cwd: this.options.cwd,
1199
+ cwd: this.options.workingDirectory,
1156
1200
  env: envWithoutNodeDebug,
1157
1201
  windowsHide: true
1158
1202
  });
1159
1203
  } else {
1160
- this.cliProcess = (0, import_node_child_process.spawn)(this.options.cliPath, args, {
1204
+ this.cliProcess = (0, import_node_child_process.spawn)(this.resolvedCliPath, args, {
1161
1205
  stdio: stdioConfig,
1162
- cwd: this.options.cwd,
1206
+ cwd: this.options.workingDirectory,
1163
1207
  env: envWithoutNodeDebug,
1164
1208
  windowsHide: true
1165
1209
  });
1166
1210
  }
1167
1211
  let stdout = "";
1168
1212
  let resolved = false;
1169
- if (this.options.useStdio) {
1213
+ if (this.connectionConfig.kind === "stdio") {
1170
1214
  resolved = true;
1171
1215
  resolve();
1172
1216
  } else {
@@ -1174,7 +1218,7 @@ class CopilotClient {
1174
1218
  stdout += data.toString();
1175
1219
  const match = stdout.match(/listening on port (\d+)/i);
1176
1220
  if (match && !resolved) {
1177
- this.actualPort = parseInt(match[1], 10);
1221
+ this.runtimePort = parseInt(match[1], 10);
1178
1222
  resolved = true;
1179
1223
  resolve();
1180
1224
  }
@@ -1248,19 +1292,21 @@ stderr: ${stderrOutput}`
1248
1292
  resolved = true;
1249
1293
  reject(new Error("Timeout waiting for CLI server to start"));
1250
1294
  }
1251
- }, 1e4);
1295
+ }, 3e4);
1252
1296
  });
1253
1297
  }
1254
1298
  /**
1255
1299
  * Connect to the CLI server (via socket or stdio)
1256
1300
  */
1257
1301
  async connectToServer() {
1258
- if (this.options.isChildProcess) {
1259
- return this.connectToParentProcessViaStdio();
1260
- } else if (this.options.useStdio) {
1261
- return this.connectToChildProcessViaStdio();
1262
- } else {
1263
- return this.connectViaTcp();
1302
+ switch (this.connectionConfig.kind) {
1303
+ case "parent-process":
1304
+ return this.connectToParentProcessViaStdio();
1305
+ case "stdio":
1306
+ return this.connectToChildProcessViaStdio();
1307
+ case "tcp":
1308
+ case "uri":
1309
+ return this.connectViaTcp();
1264
1310
  }
1265
1311
  }
1266
1312
  /**
@@ -1300,7 +1346,7 @@ stderr: ${stderrOutput}`
1300
1346
  * Connect to the CLI server via TCP socket
1301
1347
  */
1302
1348
  async connectViaTcp() {
1303
- if (!this.actualPort) {
1349
+ if (!this.runtimePort) {
1304
1350
  throw new Error("Server port not available");
1305
1351
  }
1306
1352
  return new Promise((resolve, reject) => {
@@ -1309,7 +1355,7 @@ stderr: ${stderrOutput}`
1309
1355
  this.socket?.destroy();
1310
1356
  reject(new Error("Timeout connecting to CLI server"));
1311
1357
  }, 1e4);
1312
- this.socket.connect(this.actualPort, this.actualHost, () => {
1358
+ this.socket.connect(this.runtimePort, this.actualHost, () => {
1313
1359
  clearTimeout(connectionTimeout);
1314
1360
  this.connection = (0, import_node.createMessageConnection)(
1315
1361
  new import_node.StreamMessageReader(this.socket),
@@ -1389,7 +1435,20 @@ stderr: ${stderrOutput}`
1389
1435
  if (typeof notification !== "object" || !notification || !("type" in notification) || typeof notification.type !== "string" || !("sessionId" in notification) || typeof notification.sessionId !== "string") {
1390
1436
  return;
1391
1437
  }
1392
- const event = notification;
1438
+ const raw = notification;
1439
+ let metadata;
1440
+ if (raw.metadata && raw.metadata.startTime && raw.metadata.modifiedTime) {
1441
+ metadata = {
1442
+ startTime: new Date(raw.metadata.startTime),
1443
+ modifiedTime: new Date(raw.metadata.modifiedTime),
1444
+ summary: raw.metadata.summary
1445
+ };
1446
+ }
1447
+ const event = {
1448
+ type: raw.type,
1449
+ sessionId: raw.sessionId,
1450
+ metadata
1451
+ };
1393
1452
  const typedHandlers = this.typedLifecycleHandlers.get(event.type);
1394
1453
  if (typedHandlers) {
1395
1454
  for (const handler of typedHandlers) {
@@ -30,11 +30,11 @@ async function joinSession(config = {}) {
30
30
  "joinSession() is intended for extensions running as child processes of the Copilot CLI."
31
31
  );
32
32
  }
33
- const client = new import_client.CopilotClient({ isChildProcess: true });
33
+ const client = new import_client.CopilotClient({ _internalConnection: { kind: "parent-process" } });
34
34
  return client.resumeSession(sessionId, {
35
35
  ...config,
36
36
  onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler,
37
- disableResume: config.disableResume ?? true
37
+ suppressResumeEvent: config.suppressResumeEvent ?? true
38
38
  });
39
39
  }
40
40
  // Annotate the CommonJS export names for ESM import in node: