@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.
- package/README.md +22 -23
- package/dist/cjs/client.js +193 -134
- package/dist/cjs/extension.js +2 -2
- package/dist/cjs/generated/rpc.js +13 -1
- package/dist/cjs/index.js +9 -6
- package/dist/cjs/session.js +17 -58
- package/dist/cjs/types.js +30 -0
- package/dist/client.d.ts +43 -23
- package/dist/client.js +193 -134
- package/dist/extension.js +2 -2
- package/dist/generated/rpc.d.ts +67 -57
- package/dist/generated/rpc.js +13 -1
- package/dist/generated/session-events.d.ts +25 -9
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/session.d.ts +5 -212
- package/dist/session.js +17 -58
- package/dist/types.d.ts +239 -112
- package/dist/types.js +29 -0
- package/package.json +2 -2
package/dist/cjs/client.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
186
|
+
* // Default: spawns the bundled runtime over stdio
|
|
167
187
|
* const client = new CopilotClient();
|
|
168
188
|
*
|
|
169
|
-
* // Connect to an existing
|
|
170
|
-
* const client = new CopilotClient({
|
|
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
|
-
* //
|
|
199
|
+
* // Use a custom runtime binary
|
|
173
200
|
* const client = new CopilotClient({
|
|
174
|
-
*
|
|
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
|
-
|
|
181
|
-
|
|
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
|
-
"
|
|
210
|
+
"gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
|
|
186
211
|
);
|
|
187
212
|
}
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
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 (
|
|
208
|
-
const { host, port } = this.parseCliUrl(
|
|
222
|
+
if (conn.kind === "uri") {
|
|
223
|
+
const { host, port } = this.parseCliUrl(conn.url);
|
|
209
224
|
this.actualHost = host;
|
|
210
|
-
this.
|
|
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
|
-
|
|
222
|
-
|
|
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
|
-
|
|
250
|
+
baseDirectory: options.baseDirectory,
|
|
238
251
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
239
|
-
|
|
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.
|
|
293
|
+
if (!config.createSessionFsProvider) {
|
|
280
294
|
throw new Error(
|
|
281
|
-
"
|
|
295
|
+
"createSessionFsProvider is required in session config when sessionFs is enabled in client options."
|
|
282
296
|
);
|
|
283
297
|
}
|
|
284
|
-
const provider = config.
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
547
|
-
session.registerExitPlanModeHandler(config.
|
|
583
|
+
if (config.onExitPlanModeRequest) {
|
|
584
|
+
session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
548
585
|
}
|
|
549
|
-
if (config.
|
|
550
|
-
session.registerAutoModeSwitchHandler(config.
|
|
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
|
|
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.
|
|
594
|
-
requestAutoModeSwitch: !!config.
|
|
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
|
-
|
|
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.
|
|
671
|
-
session.registerExitPlanModeHandler(config.
|
|
703
|
+
if (config.onExitPlanModeRequest) {
|
|
704
|
+
session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
672
705
|
}
|
|
673
|
-
if (config.
|
|
674
|
-
session.registerAutoModeSwitchHandler(config.
|
|
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
|
|
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.
|
|
718
|
-
requestAutoModeSwitch: !!config.
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
1088
|
-
"--
|
|
1089
|
-
|
|
1090
|
-
|
|
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.
|
|
1096
|
-
|
|
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.
|
|
1154
|
+
if (this.options.enableRemoteSessions) {
|
|
1111
1155
|
args.push("--remote");
|
|
1112
1156
|
}
|
|
1113
|
-
const envWithoutNodeDebug = { ...this.
|
|
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.
|
|
1122
|
-
envWithoutNodeDebug.COPILOT_HOME = this.options.
|
|
1165
|
+
if (this.options.baseDirectory) {
|
|
1166
|
+
envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
|
|
1123
1167
|
}
|
|
1124
|
-
if (!this.
|
|
1168
|
+
if (!this.resolvedCliPath) {
|
|
1125
1169
|
throw new Error(
|
|
1126
|
-
"Path to Copilot CLI is required. Please
|
|
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.
|
|
1189
|
+
if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) {
|
|
1146
1190
|
throw new Error(
|
|
1147
|
-
`Copilot CLI not found at ${this.
|
|
1191
|
+
`Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
|
|
1148
1192
|
);
|
|
1149
1193
|
}
|
|
1150
|
-
const stdioConfig = this.
|
|
1151
|
-
const isJsFile = this.
|
|
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.
|
|
1197
|
+
this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.resolvedCliPath, ...args], {
|
|
1154
1198
|
stdio: stdioConfig,
|
|
1155
|
-
cwd: this.options.
|
|
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.
|
|
1204
|
+
this.cliProcess = (0, import_node_child_process.spawn)(this.resolvedCliPath, args, {
|
|
1161
1205
|
stdio: stdioConfig,
|
|
1162
|
-
cwd: this.options.
|
|
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.
|
|
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.
|
|
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
|
-
},
|
|
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
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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) {
|
package/dist/cjs/extension.js
CHANGED
|
@@ -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({
|
|
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
|
-
|
|
37
|
+
suppressResumeEvent: config.suppressResumeEvent ?? true
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
// Annotate the CommonJS export names for ESM import in node:
|