@github/copilot-sdk 1.0.13-preview.4 → 1.0.13
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 +51 -9
- package/dist/cjs/cliVersion.js +31 -0
- package/dist/cjs/client.js +74 -68
- package/dist/cjs/generated/rpc.js +64 -3
- package/dist/cjs/runtimeArtifacts.js +112 -17
- package/dist/cjs/session.js +108 -10
- package/dist/cliVersion.d.ts +2 -0
- package/dist/cliVersion.js +6 -0
- package/dist/client.d.ts +2 -1
- package/dist/client.js +76 -69
- package/dist/generated/rpc.d.ts +965 -27
- package/dist/generated/rpc.js +64 -3
- package/dist/generated/session-events.d.ts +493 -43
- package/dist/index.d.ts +1 -1
- package/dist/runtimeArtifacts.d.ts +13 -1
- package/dist/runtimeArtifacts.js +103 -16
- package/dist/session.d.ts +52 -1
- package/dist/session.js +108 -10
- package/dist/types.d.ts +60 -2
- package/package.json +103 -88
package/dist/client.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import {
|
|
5
|
-
import { Socket } from "node:net";
|
|
4
|
+
import { isIPv6, Socket } from "node:net";
|
|
6
5
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
6
|
import {
|
|
9
7
|
createMessageConnection,
|
|
10
8
|
ErrorCodes,
|
|
@@ -20,7 +18,8 @@ import {
|
|
|
20
18
|
} from "./generated/rpc.js";
|
|
21
19
|
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
|
|
22
20
|
import { CopilotSession } from "./session.js";
|
|
23
|
-
import {
|
|
21
|
+
import { ensureRuntimeBundle } from "./runtimeArtifacts.js";
|
|
22
|
+
import { COPILOT_CLI_VERSION } from "./cliVersion.js";
|
|
24
23
|
import { createSessionFsAdapter } from "./sessionFsProvider.js";
|
|
25
24
|
import { createCopilotRequestAdapter } from "./copilotRequestHandler.js";
|
|
26
25
|
import { getTraceContext } from "./telemetry.js";
|
|
@@ -128,6 +127,15 @@ function toWireCustomAgents(agents) {
|
|
|
128
127
|
return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
|
|
129
128
|
});
|
|
130
129
|
}
|
|
130
|
+
function clientInfoToWire(info) {
|
|
131
|
+
if (info == null) return void 0;
|
|
132
|
+
const wire = {};
|
|
133
|
+
if (info.applicationName) wire.editorName = info.applicationName;
|
|
134
|
+
if (info.applicationVersion) wire.editorVersion = info.applicationVersion;
|
|
135
|
+
if (info.integrationName) wire.extensionName = info.integrationName;
|
|
136
|
+
if (info.integrationVersion) wire.extensionVersion = info.integrationVersion;
|
|
137
|
+
return Object.keys(wire).length > 0 ? wire : void 0;
|
|
138
|
+
}
|
|
131
139
|
function toWireLargeOutput(config) {
|
|
132
140
|
if (!config) return void 0;
|
|
133
141
|
const { outputDirectory, ...rest } = config;
|
|
@@ -185,53 +193,8 @@ function getNodeExecPath() {
|
|
|
185
193
|
}
|
|
186
194
|
return process.execPath;
|
|
187
195
|
}
|
|
188
|
-
function getCliPlatformPackageNames() {
|
|
189
|
-
const arch = process.arch;
|
|
190
|
-
const variants = process.platform === "linux" ? ["linux", "linuxmusl"] : [process.platform];
|
|
191
|
-
return variants.map((variant) => `@github/copilot-${variant}-${arch}`);
|
|
192
|
-
}
|
|
193
|
-
function getBundledCliPackage() {
|
|
194
|
-
const packageNames = getCliPlatformPackageNames();
|
|
195
|
-
if (typeof import.meta.resolve === "function") {
|
|
196
|
-
for (const packageName of packageNames) {
|
|
197
|
-
try {
|
|
198
|
-
const packageEntryUrl = import.meta.resolve(packageName);
|
|
199
|
-
const packageEntryPath = fileURLToPath(packageEntryUrl);
|
|
200
|
-
return {
|
|
201
|
-
root: dirname(packageEntryPath),
|
|
202
|
-
platform: packageName.slice("@github/copilot-".length)
|
|
203
|
-
};
|
|
204
|
-
} catch {
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
throw new Error(
|
|
208
|
-
`Could not resolve a @github/copilot platform package (tried ${packageNames.join(", ")}). Ensure @github/copilot is installed, or pass cliPath/cliUrl to CopilotClient.`
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
const req = createRequire(__filename);
|
|
212
|
-
const searchPaths = req.resolve.paths("@github/copilot") ?? [];
|
|
213
|
-
for (const base of searchPaths) {
|
|
214
|
-
for (const packageName of packageNames) {
|
|
215
|
-
const root = join(base, ...packageName.split("/"));
|
|
216
|
-
const candidate = join(root, "index.js");
|
|
217
|
-
if (existsSync(candidate)) {
|
|
218
|
-
return {
|
|
219
|
-
root,
|
|
220
|
-
platform: packageName.slice("@github/copilot-".length)
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
throw new Error(
|
|
226
|
-
`Could not find a @github/copilot platform package (tried ${packageNames.join(", ")}). Searched ${searchPaths.length} paths. Ensure @github/copilot is installed, or pass cliPath/cliUrl to CopilotClient.`
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
196
|
function getBundledRuntimePath() {
|
|
230
|
-
|
|
231
|
-
return materializeRuntimeBundle({
|
|
232
|
-
packageRoot: bundled.root,
|
|
233
|
-
platform: bundled.platform
|
|
234
|
-
});
|
|
197
|
+
return ensureRuntimeBundle(COPILOT_CLI_VERSION);
|
|
235
198
|
}
|
|
236
199
|
class TeardownResilientStreamMessageWriter extends StreamMessageWriter {
|
|
237
200
|
suppressWriteErrors = false;
|
|
@@ -251,6 +214,7 @@ class CopilotClient {
|
|
|
251
214
|
ffiHost = null;
|
|
252
215
|
connection = null;
|
|
253
216
|
messageWriter = null;
|
|
217
|
+
connectionClosed = false;
|
|
254
218
|
socket = null;
|
|
255
219
|
runtimePort = null;
|
|
256
220
|
actualHost = "localhost";
|
|
@@ -450,8 +414,6 @@ class CopilotClient {
|
|
|
450
414
|
const explicitCliPath = conn.path ?? effectiveEnv.COPILOT_CLI_PATH;
|
|
451
415
|
if (explicitCliPath) {
|
|
452
416
|
this.resolvedCliPath = explicitCliPath;
|
|
453
|
-
} else {
|
|
454
|
-
this.resolvedCliPath = getBundledRuntimePath();
|
|
455
417
|
}
|
|
456
418
|
}
|
|
457
419
|
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
@@ -466,7 +428,8 @@ class CopilotClient {
|
|
|
466
428
|
baseDirectory: options.baseDirectory,
|
|
467
429
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
468
430
|
enableRemoteSessions: options.enableRemoteSessions ?? false,
|
|
469
|
-
mode: options.mode ?? "copilot-cli"
|
|
431
|
+
mode: options.mode ?? "copilot-cli",
|
|
432
|
+
clientInfo: options.clientInfo
|
|
470
433
|
};
|
|
471
434
|
if (this.options.mode === "empty") {
|
|
472
435
|
const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
|
|
@@ -482,17 +445,29 @@ class CopilotClient {
|
|
|
482
445
|
connectionExtraArgs = [];
|
|
483
446
|
/**
|
|
484
447
|
* Parse CLI URL into host and port
|
|
485
|
-
* Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
|
|
448
|
+
* Supports formats: "host:port", "[ipv6]:port", "http://host:port", "https://host:port", or just "port"
|
|
486
449
|
*/
|
|
487
450
|
parseCliUrl(url) {
|
|
488
|
-
|
|
451
|
+
const cleanUrl = url.replace(/^https?:\/\//, "");
|
|
489
452
|
if (/^\d+$/.test(cleanUrl)) {
|
|
490
453
|
return { host: "localhost", port: parseInt(cleanUrl, 10) };
|
|
491
454
|
}
|
|
455
|
+
const ipv6Match = cleanUrl.match(/^\[([^\]]+)\]:(\d+)$/);
|
|
456
|
+
if (ipv6Match) {
|
|
457
|
+
const host2 = ipv6Match[1];
|
|
458
|
+
if (!isIPv6(host2)) {
|
|
459
|
+
throw new Error(`Invalid cliUrl format: ${url}`);
|
|
460
|
+
}
|
|
461
|
+
const port2 = parseInt(ipv6Match[2], 10);
|
|
462
|
+
if (isNaN(port2) || port2 <= 0 || port2 > 65535) {
|
|
463
|
+
throw new Error(`Invalid port in cliUrl: ${url}`);
|
|
464
|
+
}
|
|
465
|
+
return { host: host2, port: port2 };
|
|
466
|
+
}
|
|
492
467
|
const parts = cleanUrl.split(":");
|
|
493
468
|
if (parts.length !== 2) {
|
|
494
469
|
throw new Error(
|
|
495
|
-
`Invalid cliUrl format: ${url}. Expected "host:port", "http://host:port", or "port"`
|
|
470
|
+
`Invalid cliUrl format: ${url}. Expected "host:port", "[ipv6]:port", "http://host:port", or "port"`
|
|
496
471
|
);
|
|
497
472
|
}
|
|
498
473
|
const host = parts[0] || "localhost";
|
|
@@ -622,6 +597,7 @@ class CopilotClient {
|
|
|
622
597
|
return;
|
|
623
598
|
}
|
|
624
599
|
this.forceStopping = false;
|
|
600
|
+
this.connectionClosed = false;
|
|
625
601
|
this.processTransportError = null;
|
|
626
602
|
this.state = "connecting";
|
|
627
603
|
try {
|
|
@@ -720,7 +696,7 @@ class CopilotClient {
|
|
|
720
696
|
}
|
|
721
697
|
this.sessions.clear();
|
|
722
698
|
this.githubTokenProviders.clear();
|
|
723
|
-
if (this.connection && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
699
|
+
if (this.connection && !this.connectionClosed && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
724
700
|
const runtimeShutdownStart = Date.now();
|
|
725
701
|
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
726
702
|
void shutdownPromise.catch(() => void 0);
|
|
@@ -1251,6 +1227,7 @@ class CopilotClient {
|
|
|
1251
1227
|
gitHubTokenProviderRegistrationId,
|
|
1252
1228
|
remoteSession: config.remoteSession,
|
|
1253
1229
|
cloud: config.cloud,
|
|
1230
|
+
featureFlags: config.featureFlags,
|
|
1254
1231
|
expAssignments: config.expAssignments,
|
|
1255
1232
|
enableManagedSettings: config.enableManagedSettings,
|
|
1256
1233
|
managedSettings: config.managedSettings
|
|
@@ -1284,6 +1261,7 @@ class CopilotClient {
|
|
|
1284
1261
|
await this.updateSessionOptionsForMode(session, config);
|
|
1285
1262
|
this.commitGitHubTokenProvider(returnedSessionId, gitHubTokenProviderRegistrationId);
|
|
1286
1263
|
} catch (e) {
|
|
1264
|
+
session?._markDisconnected();
|
|
1287
1265
|
if (registeredId !== void 0) {
|
|
1288
1266
|
this.sessions.delete(registeredId);
|
|
1289
1267
|
}
|
|
@@ -1486,6 +1464,7 @@ class CopilotClient {
|
|
|
1486
1464
|
gitHubTokenProviderRegistrationId,
|
|
1487
1465
|
remoteSession: config.remoteSession,
|
|
1488
1466
|
openCanvases: config.openCanvases,
|
|
1467
|
+
featureFlags: config.featureFlags,
|
|
1489
1468
|
expAssignments: config.expAssignments,
|
|
1490
1469
|
enableManagedSettings: config.enableManagedSettings,
|
|
1491
1470
|
managedSettings: config.managedSettings,
|
|
@@ -1515,6 +1494,7 @@ class CopilotClient {
|
|
|
1515
1494
|
await this.updateSessionOptionsForMode(session, config);
|
|
1516
1495
|
this.commitGitHubTokenProvider(sessionId, gitHubTokenProviderRegistrationId);
|
|
1517
1496
|
} catch (e) {
|
|
1497
|
+
session._markDisconnected();
|
|
1518
1498
|
this.sessions.delete(sessionId);
|
|
1519
1499
|
if (gitHubTokenProviderRegistrationId !== void 0) {
|
|
1520
1500
|
this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
|
|
@@ -1630,10 +1610,17 @@ class CopilotClient {
|
|
|
1630
1610
|
const raceAgainstExit = (p) => this.processExitPromise ? Promise.race([p, this.processExitPromise]) : p;
|
|
1631
1611
|
let serverVersion;
|
|
1632
1612
|
try {
|
|
1633
|
-
const connectParams = {
|
|
1613
|
+
const connectParams = {
|
|
1614
|
+
token: this.effectiveConnectionToken,
|
|
1615
|
+
supportedTaskKinds: ["agent", "client", "shell"]
|
|
1616
|
+
};
|
|
1634
1617
|
if (this.onGitHubTelemetry != null) {
|
|
1635
1618
|
connectParams.enableGitHubTelemetryForwarding = true;
|
|
1636
1619
|
}
|
|
1620
|
+
const clientInfo = clientInfoToWire(this.options.clientInfo);
|
|
1621
|
+
if (clientInfo != null) {
|
|
1622
|
+
connectParams.clientInfo = clientInfo;
|
|
1623
|
+
}
|
|
1637
1624
|
const result = await raceAgainstExit(this.internalRpc.connect(connectParams));
|
|
1638
1625
|
serverVersion = result.protocolVersion;
|
|
1639
1626
|
} catch (err) {
|
|
@@ -1894,6 +1881,7 @@ class CopilotClient {
|
|
|
1894
1881
|
* Start the CLI server process
|
|
1895
1882
|
*/
|
|
1896
1883
|
async startCLIServer() {
|
|
1884
|
+
this.resolvedCliPath ??= await getBundledRuntimePath();
|
|
1897
1885
|
return new Promise((resolve2, reject) => {
|
|
1898
1886
|
this.stderrBuffer = "";
|
|
1899
1887
|
const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
|
|
@@ -1931,7 +1919,7 @@ class CopilotClient {
|
|
|
1931
1919
|
}
|
|
1932
1920
|
if (!existsSync(this.resolvedCliPath)) {
|
|
1933
1921
|
throw new Error(
|
|
1934
|
-
`Copilot CLI not found at ${this.resolvedCliPath}.
|
|
1922
|
+
`Copilot CLI not found at ${this.resolvedCliPath}. Set COPILOT_CLI_PATH to use a custom installation.`
|
|
1935
1923
|
);
|
|
1936
1924
|
}
|
|
1937
1925
|
const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
|
|
@@ -2058,12 +2046,19 @@ stderr: ${stderrOutput}`
|
|
|
2058
2046
|
/** Starts the in-process FFI runtime with SDK-managed typed options. */
|
|
2059
2047
|
async startInProcessFfi() {
|
|
2060
2048
|
const explicitEntrypoint = this.resolvedEnv.COPILOT_CLI_PATH;
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2049
|
+
let runtimeLibrary;
|
|
2050
|
+
if (explicitEntrypoint) {
|
|
2051
|
+
const entrypointDirectory = dirname(resolve(explicitEntrypoint));
|
|
2052
|
+
const adjacentRuntime = join(entrypointDirectory, "runtime.node");
|
|
2053
|
+
runtimeLibrary = existsSync(adjacentRuntime) ? adjacentRuntime : join(
|
|
2054
|
+
entrypointDirectory,
|
|
2055
|
+
"prebuilds",
|
|
2056
|
+
CopilotClient.getNapiPrebuildsFolder(explicitEntrypoint),
|
|
2057
|
+
"runtime.node"
|
|
2058
|
+
);
|
|
2059
|
+
} else {
|
|
2060
|
+
runtimeLibrary = join(dirname(await getBundledRuntimePath()), "runtime.node");
|
|
2061
|
+
}
|
|
2067
2062
|
const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
|
|
2068
2063
|
const environment = {};
|
|
2069
2064
|
if (this.options.gitHubToken) {
|
|
@@ -2249,12 +2244,24 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2249
2244
|
return await this.handleHooksInvoke(params);
|
|
2250
2245
|
}
|
|
2251
2246
|
);
|
|
2252
|
-
this.connection
|
|
2247
|
+
const connection = this.connection;
|
|
2248
|
+
const markDisconnected = () => {
|
|
2249
|
+
if (this.connection !== connection) {
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
this.connectionClosed = true;
|
|
2253
2253
|
this.state = "disconnected";
|
|
2254
|
+
for (const session of this.sessions.values()) {
|
|
2255
|
+
session._markDisconnected();
|
|
2256
|
+
}
|
|
2257
|
+
this.sessions.clear();
|
|
2254
2258
|
this.githubTokenProviders.clear();
|
|
2255
|
-
}
|
|
2256
|
-
this.connection.
|
|
2257
|
-
|
|
2259
|
+
};
|
|
2260
|
+
this.connection.onClose(markDisconnected);
|
|
2261
|
+
this.connection.onError(() => {
|
|
2262
|
+
if (this.connection === connection) {
|
|
2263
|
+
this.state = "disconnected";
|
|
2264
|
+
}
|
|
2258
2265
|
});
|
|
2259
2266
|
}
|
|
2260
2267
|
handleSessionEventNotification(notification) {
|