@github/copilot-sdk 1.0.13-preview.3 → 1.0.13-preview.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/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 { createRequire } from "node:module";
5
- import { Socket } from "node:net";
6
- import { dirname, isAbsolute, join } from "node:path";
7
- import { fileURLToPath } from "node:url";
4
+ import { isIPv6, Socket } from "node:net";
5
+ import { dirname, isAbsolute, join, resolve } from "node:path";
8
6
  import {
9
7
  createMessageConnection,
10
8
  ErrorCodes,
@@ -20,6 +18,8 @@ import {
20
18
  } from "./generated/rpc.js";
21
19
  import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
22
20
  import { CopilotSession } from "./session.js";
21
+ import { ensureRuntimeBundle } from "./runtimeArtifacts.js";
22
+ import { COPILOT_CLI_VERSION } from "./cliVersion.js";
23
23
  import { createSessionFsAdapter } from "./sessionFsProvider.js";
24
24
  import { createCopilotRequestAdapter } from "./copilotRequestHandler.js";
25
25
  import { getTraceContext } from "./telemetry.js";
@@ -49,7 +49,7 @@ async function waitForChildExit(child, timeoutMs) {
49
49
  if (child.exitCode != null || child.signalCode != null) {
50
50
  return true;
51
51
  }
52
- return new Promise((resolve) => {
52
+ return new Promise((resolve2) => {
53
53
  let timeout;
54
54
  let settled = false;
55
55
  const onExit = () => {
@@ -58,7 +58,7 @@ async function waitForChildExit(child, timeoutMs) {
58
58
  }
59
59
  settled = true;
60
60
  clearTimeout(timeout);
61
- resolve(true);
61
+ resolve2(true);
62
62
  };
63
63
  timeout = setTimeout(() => {
64
64
  if (settled) {
@@ -66,7 +66,7 @@ async function waitForChildExit(child, timeoutMs) {
66
66
  }
67
67
  settled = true;
68
68
  child.off("exit", onExit);
69
- resolve(false);
69
+ resolve2(false);
70
70
  }, timeoutMs);
71
71
  child.once("exit", onExit);
72
72
  if (child.exitCode != null || child.signalCode != null) {
@@ -127,6 +127,15 @@ function toWireCustomAgents(agents) {
127
127
  return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
128
128
  });
129
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
+ }
130
139
  function toWireLargeOutput(config) {
131
140
  if (!config) return void 0;
132
141
  const { outputDirectory, ...rest } = config;
@@ -184,39 +193,8 @@ function getNodeExecPath() {
184
193
  }
185
194
  return process.execPath;
186
195
  }
187
- function getCliPlatformPackageNames() {
188
- const arch = process.arch;
189
- const variants = process.platform === "linux" ? ["linux", "linuxmusl"] : [process.platform];
190
- return variants.map((variant) => `@github/copilot-${variant}-${arch}`);
191
- }
192
- function getBundledCliPath() {
193
- const packageNames = getCliPlatformPackageNames();
194
- if (typeof import.meta.resolve === "function") {
195
- for (const packageName of packageNames) {
196
- try {
197
- const packageEntryUrl = import.meta.resolve(packageName);
198
- const packageEntryPath = fileURLToPath(packageEntryUrl);
199
- return join(dirname(packageEntryPath), "index.js");
200
- } catch {
201
- }
202
- }
203
- throw new Error(
204
- `Could not resolve a @github/copilot platform package (tried ${packageNames.join(", ")}). Ensure @github/copilot is installed, or pass cliPath/cliUrl to CopilotClient.`
205
- );
206
- }
207
- const req = createRequire(__filename);
208
- const searchPaths = req.resolve.paths("@github/copilot") ?? [];
209
- for (const base of searchPaths) {
210
- for (const packageName of packageNames) {
211
- const candidate = join(base, ...packageName.split("/"), "index.js");
212
- if (existsSync(candidate)) {
213
- return candidate;
214
- }
215
- }
216
- }
217
- throw new Error(
218
- `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.`
219
- );
196
+ function getBundledRuntimePath() {
197
+ return ensureRuntimeBundle(COPILOT_CLI_VERSION);
220
198
  }
221
199
  class TeardownResilientStreamMessageWriter extends StreamMessageWriter {
222
200
  suppressWriteErrors = false;
@@ -264,6 +242,7 @@ class CopilotClient {
264
242
  _internalRpc = null;
265
243
  processExitPromise = null;
266
244
  // Rejects when CLI process exits
245
+ processTransportError = null;
267
246
  negotiatedProtocolVersion = null;
268
247
  /** Connection-level session filesystem config, set via constructor option. */
269
248
  sessionFsConfig = null;
@@ -430,7 +409,12 @@ class CopilotClient {
430
409
  const connEnv = conn.kind === "stdio" || conn.kind === "tcp" ? conn.env : void 0;
431
410
  const effectiveEnv = connEnv ?? options.env ?? process.env;
432
411
  this.resolvedEnv = effectiveEnv;
433
- this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0;
412
+ if (conn.kind === "stdio" || conn.kind === "tcp") {
413
+ const explicitCliPath = conn.path ?? effectiveEnv.COPILOT_CLI_PATH;
414
+ if (explicitCliPath) {
415
+ this.resolvedCliPath = explicitCliPath;
416
+ }
417
+ }
434
418
  const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
435
419
  this.connectionExtraArgs = [...connArgs];
436
420
  this.options = {
@@ -443,7 +427,8 @@ class CopilotClient {
443
427
  baseDirectory: options.baseDirectory,
444
428
  sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
445
429
  enableRemoteSessions: options.enableRemoteSessions ?? false,
446
- mode: options.mode ?? "copilot-cli"
430
+ mode: options.mode ?? "copilot-cli",
431
+ clientInfo: options.clientInfo
447
432
  };
448
433
  if (this.options.mode === "empty") {
449
434
  const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
@@ -459,17 +444,29 @@ class CopilotClient {
459
444
  connectionExtraArgs = [];
460
445
  /**
461
446
  * Parse CLI URL into host and port
462
- * Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
447
+ * Supports formats: "host:port", "[ipv6]:port", "http://host:port", "https://host:port", or just "port"
463
448
  */
464
449
  parseCliUrl(url) {
465
- let cleanUrl = url.replace(/^https?:\/\//, "");
450
+ const cleanUrl = url.replace(/^https?:\/\//, "");
466
451
  if (/^\d+$/.test(cleanUrl)) {
467
452
  return { host: "localhost", port: parseInt(cleanUrl, 10) };
468
453
  }
454
+ const ipv6Match = cleanUrl.match(/^\[([^\]]+)\]:(\d+)$/);
455
+ if (ipv6Match) {
456
+ const host2 = ipv6Match[1];
457
+ if (!isIPv6(host2)) {
458
+ throw new Error(`Invalid cliUrl format: ${url}`);
459
+ }
460
+ const port2 = parseInt(ipv6Match[2], 10);
461
+ if (isNaN(port2) || port2 <= 0 || port2 > 65535) {
462
+ throw new Error(`Invalid port in cliUrl: ${url}`);
463
+ }
464
+ return { host: host2, port: port2 };
465
+ }
469
466
  const parts = cleanUrl.split(":");
470
467
  if (parts.length !== 2) {
471
468
  throw new Error(
472
- `Invalid cliUrl format: ${url}. Expected "host:port", "http://host:port", or "port"`
469
+ `Invalid cliUrl format: ${url}. Expected "host:port", "[ipv6]:port", "http://host:port", or "port"`
473
470
  );
474
471
  }
475
472
  const host = parts[0] || "localhost";
@@ -598,6 +595,8 @@ class CopilotClient {
598
595
  if (this.state === "connected") {
599
596
  return;
600
597
  }
598
+ this.forceStopping = false;
599
+ this.processTransportError = null;
601
600
  this.state = "connecting";
602
601
  try {
603
602
  if (this.connectionConfig.kind === "inprocess") {
@@ -630,8 +629,10 @@ class CopilotClient {
630
629
  }
631
630
  this.state = "connected";
632
631
  } catch (error) {
632
+ const startupError = this.processTransportError ?? error;
633
+ await this.forceStop();
633
634
  this.state = "error";
634
- throw error;
635
+ throw startupError;
635
636
  }
636
637
  }
637
638
  /**
@@ -676,7 +677,7 @@ class CopilotClient {
676
677
  lastError = error instanceof Error ? error : new Error(String(error));
677
678
  if (attempt < 3) {
678
679
  const delay = 100 * Math.pow(2, attempt - 1);
679
- await new Promise((resolve) => setTimeout(resolve, delay));
680
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
680
681
  }
681
682
  }
682
683
  }
@@ -743,8 +744,8 @@ class CopilotClient {
743
744
  this.socket = null;
744
745
  try {
745
746
  if (!socket.destroyed) {
746
- await new Promise((resolve) => {
747
- socket.once("close", () => resolve());
747
+ await new Promise((resolve2) => {
748
+ socket.once("close", () => resolve2());
748
749
  socket.end();
749
750
  });
750
751
  }
@@ -1224,6 +1225,7 @@ class CopilotClient {
1224
1225
  gitHubTokenProviderRegistrationId,
1225
1226
  remoteSession: config.remoteSession,
1226
1227
  cloud: config.cloud,
1228
+ featureFlags: config.featureFlags,
1227
1229
  expAssignments: config.expAssignments,
1228
1230
  enableManagedSettings: config.enableManagedSettings,
1229
1231
  managedSettings: config.managedSettings
@@ -1459,6 +1461,7 @@ class CopilotClient {
1459
1461
  gitHubTokenProviderRegistrationId,
1460
1462
  remoteSession: config.remoteSession,
1461
1463
  openCanvases: config.openCanvases,
1464
+ featureFlags: config.featureFlags,
1462
1465
  expAssignments: config.expAssignments,
1463
1466
  enableManagedSettings: config.enableManagedSettings,
1464
1467
  managedSettings: config.managedSettings,
@@ -1550,8 +1553,8 @@ class CopilotClient {
1550
1553
  async listModels() {
1551
1554
  await this.modelsCacheLock;
1552
1555
  let resolveLock;
1553
- this.modelsCacheLock = new Promise((resolve) => {
1554
- resolveLock = resolve;
1556
+ this.modelsCacheLock = new Promise((resolve2) => {
1557
+ resolveLock = resolve2;
1555
1558
  });
1556
1559
  try {
1557
1560
  if (this.modelsCache !== null) {
@@ -1607,6 +1610,10 @@ class CopilotClient {
1607
1610
  if (this.onGitHubTelemetry != null) {
1608
1611
  connectParams.enableGitHubTelemetryForwarding = true;
1609
1612
  }
1613
+ const clientInfo = clientInfoToWire(this.options.clientInfo);
1614
+ if (clientInfo != null) {
1615
+ connectParams.clientInfo = clientInfo;
1616
+ }
1610
1617
  const result = await raceAgainstExit(this.internalRpc.connect(connectParams));
1611
1618
  serverVersion = result.protocolVersion;
1612
1619
  } catch (err) {
@@ -1867,7 +1874,8 @@ class CopilotClient {
1867
1874
  * Start the CLI server process
1868
1875
  */
1869
1876
  async startCLIServer() {
1870
- return new Promise((resolve, reject) => {
1877
+ this.resolvedCliPath ??= await getBundledRuntimePath();
1878
+ return new Promise((resolve2, reject) => {
1871
1879
  this.stderrBuffer = "";
1872
1880
  const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
1873
1881
  if (this.options.logLevel) {
@@ -1904,7 +1912,7 @@ class CopilotClient {
1904
1912
  }
1905
1913
  if (!existsSync(this.resolvedCliPath)) {
1906
1914
  throw new Error(
1907
- `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
1915
+ `Copilot CLI not found at ${this.resolvedCliPath}. Set COPILOT_CLI_PATH to use a custom installation.`
1908
1916
  );
1909
1917
  }
1910
1918
  const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
@@ -1928,7 +1936,7 @@ class CopilotClient {
1928
1936
  let resolved = false;
1929
1937
  if (this.connectionConfig.kind === "stdio") {
1930
1938
  resolved = true;
1931
- resolve();
1939
+ resolve2();
1932
1940
  } else {
1933
1941
  this.cliProcess.stdout?.on("data", (data) => {
1934
1942
  stdout += data.toString();
@@ -1936,7 +1944,7 @@ class CopilotClient {
1936
1944
  if (match && !resolved) {
1937
1945
  this.runtimePort = parseInt(match[1], 10);
1938
1946
  resolved = true;
1939
- resolve();
1947
+ resolve2();
1940
1948
  }
1941
1949
  });
1942
1950
  }
@@ -1968,26 +1976,27 @@ stderr: ${stderrOutput}`
1968
1976
  });
1969
1977
  this.processExitPromise = new Promise((_, rejectProcessExit) => {
1970
1978
  this.cliProcess.on("exit", (code) => {
1971
- setTimeout(() => {
1972
- const stderrOutput = this.stderrBuffer.trim();
1973
- if (stderrOutput) {
1974
- rejectProcessExit(
1975
- new Error(
1976
- `CLI server exited with code ${code}
1979
+ if (this.messageWriter) {
1980
+ this.messageWriter.suppressWriteErrors = true;
1981
+ }
1982
+ const stderrOutput = this.stderrBuffer.trim();
1983
+ if (stderrOutput) {
1984
+ rejectProcessExit(
1985
+ new Error(
1986
+ `CLI server exited with code ${code}
1977
1987
  stderr: ${stderrOutput}`
1978
- )
1979
- );
1980
- } else {
1981
- rejectProcessExit(
1982
- new Error(`CLI server exited unexpectedly with code ${code}`)
1983
- );
1984
- }
1985
- }, 50);
1988
+ )
1989
+ );
1990
+ } else {
1991
+ rejectProcessExit(
1992
+ new Error(`CLI server exited unexpectedly with code ${code}`)
1993
+ );
1994
+ }
1986
1995
  });
1987
1996
  });
1988
1997
  this.processExitPromise.catch(() => {
1989
1998
  });
1990
- this.cliProcess.on("exit", (code) => {
1999
+ this.cliProcess.on("close", (code) => {
1991
2000
  if (!resolved) {
1992
2001
  resolved = true;
1993
2002
  const stderrOutput = this.stderrBuffer.trim();
@@ -2029,7 +2038,20 @@ stderr: ${stderrOutput}`
2029
2038
  }
2030
2039
  /** Starts the in-process FFI runtime with SDK-managed typed options. */
2031
2040
  async startInProcessFfi() {
2032
- const entrypoint = this.resolveCliPathForFfi();
2041
+ const explicitEntrypoint = this.resolvedEnv.COPILOT_CLI_PATH;
2042
+ let runtimeLibrary;
2043
+ if (explicitEntrypoint) {
2044
+ const entrypointDirectory = dirname(resolve(explicitEntrypoint));
2045
+ const adjacentRuntime = join(entrypointDirectory, "runtime.node");
2046
+ runtimeLibrary = existsSync(adjacentRuntime) ? adjacentRuntime : join(
2047
+ entrypointDirectory,
2048
+ "prebuilds",
2049
+ CopilotClient.getNapiPrebuildsFolder(explicitEntrypoint),
2050
+ "runtime.node"
2051
+ );
2052
+ } else {
2053
+ runtimeLibrary = join(dirname(await getBundledRuntimePath()), "runtime.node");
2054
+ }
2033
2055
  const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
2034
2056
  const environment = {};
2035
2057
  if (this.options.gitHubToken) {
@@ -2057,12 +2079,7 @@ stderr: ${stderrOutput}`
2057
2079
  if (this.options.enableRemoteSessions) {
2058
2080
  args.push("--remote");
2059
2081
  }
2060
- const host = FfiRuntimeHost.create(
2061
- entrypoint,
2062
- CopilotClient.getNapiPrebuildsFolder(entrypoint),
2063
- environment,
2064
- args
2065
- );
2082
+ const host = FfiRuntimeHost.create(runtimeLibrary, explicitEntrypoint, environment, args);
2066
2083
  this.ffiHost = host;
2067
2084
  await host.start();
2068
2085
  }
@@ -2082,19 +2099,6 @@ stderr: ${stderrOutput}`
2082
2099
  this.attachConnectionHandlers();
2083
2100
  this.connection.listen();
2084
2101
  }
2085
- /**
2086
- * Resolves the CLI entrypoint used for in-process FFI hosting: `COPILOT_CLI_PATH`
2087
- * when set, otherwise the bundled platform-package entrypoint.
2088
- */
2089
- resolveCliPathForFfi() {
2090
- return this.resolvedEnv.COPILOT_CLI_PATH ?? getBundledCliPath();
2091
- }
2092
- /**
2093
- * Returns the napi prebuilds folder name for the current host — the
2094
- * `<node-platform>-<arch>` convention (e.g. `win32-x64`, `darwin-arm64`,
2095
- * `linux-x64`, `linuxmusl-x64`) under which the runtime ships
2096
- * `prebuilds/<folder>/runtime.node`.
2097
- */
2098
2102
  static getNapiPrebuildsFolder(entrypoint) {
2099
2103
  const arch = process.arch;
2100
2104
  if (arch !== "x64" && arch !== "arm64") {
@@ -2130,6 +2134,11 @@ stderr: ${stderrOutput}`
2130
2134
  }
2131
2135
  this.state = "error";
2132
2136
  const reason = err instanceof Error ? err.stack ?? err.message : String(err);
2137
+ const stderrOutput = this.stderrBuffer.trim();
2138
+ this.processTransportError = new Error(
2139
+ `CLI server connection failed: ${reason}${stderrOutput ? `
2140
+ stderr: ${stderrOutput}` : ""}`
2141
+ );
2133
2142
  this.logDebug(`stdin pipe error: ${reason}`);
2134
2143
  try {
2135
2144
  this.connection?.dispose();
@@ -2166,7 +2175,7 @@ stderr: ${stderrOutput}`
2166
2175
  if (!this.runtimePort) {
2167
2176
  throw new Error("Server port not available");
2168
2177
  }
2169
- return new Promise((resolve, reject) => {
2178
+ return new Promise((resolve2, reject) => {
2170
2179
  this.socket = new Socket();
2171
2180
  const connectionTimeout = setTimeout(() => {
2172
2181
  this.socket?.destroy();
@@ -2181,7 +2190,7 @@ stderr: ${stderrOutput}`
2181
2190
  );
2182
2191
  this.attachConnectionHandlers();
2183
2192
  this.connection.listen();
2184
- resolve();
2193
+ resolve2();
2185
2194
  });
2186
2195
  this.socket.on("error", (error) => {
2187
2196
  clearTimeout(connectionTimeout);
@@ -16,16 +16,10 @@ export declare class FfiRuntimeHost {
16
16
  readonly sendStream: Writable;
17
17
  private constructor();
18
18
  /**
19
- * Resolves the cdylib next to the given CLI entrypoint and prepares the FFI host.
20
- * The cdylib is resolved as `prebuilds/<prebuildsFolder>/runtime.node` relative to
21
- * the entrypoint directory (the napi-rs `<node-platform>-<arch>` layout, e.g.
22
- * `linux-x64`). Throws if it cannot be found.
23
- */
24
- static create(cliEntrypoint: string, prebuildsFolder: string, environment: Record<string, string | undefined> | undefined, args: readonly string[]): FfiRuntimeHost;
25
- /**
26
- * Starts the in-process runtime: spawns the CLI worker via the native host,
27
- * waits for readiness, and opens the FFI JSON-RPC connection.
19
+ * Loads the runtime cdylib at the given path and prepares the FFI host.
28
20
  */
21
+ static create(libraryPath: string, cliEntrypoint: string | undefined, environment: Record<string, string | undefined> | undefined, args: readonly string[]): FfiRuntimeHost;
22
+ /** Starts the in-process Rust runtime and opens the FFI JSON-RPC connection. */
29
23
  start(): Promise<void>;
30
24
  private writeFrame;
31
25
  /**
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import koffi from "koffi";
3
- import { dirname, join, resolve } from "node:path";
3
+ import { resolve } from "node:path";
4
4
  import { PassThrough, Writable } from "node:stream";
5
5
  const SYMBOL_PREFIX = "copilot_runtime_";
6
6
  const KEEP_ALIVE_INTERVAL_MS = 1 << 30;
@@ -52,7 +52,7 @@ function loadLibrary(libraryPath) {
52
52
  return loadedLibrary;
53
53
  }
54
54
  function buildArgvJson(cliEntrypoint, args) {
55
- const argv = cliEntrypoint.toLowerCase().endsWith(".js") ? ["node", cliEntrypoint, "--embedded-host", "--no-auto-update"] : [cliEntrypoint, "--embedded-host", "--no-auto-update"];
55
+ const argv = cliEntrypoint ? cliEntrypoint.toLowerCase().endsWith(".js") ? ["node", cliEntrypoint, "--embedded-host", "--no-auto-update"] : [cliEntrypoint, "--embedded-host", "--no-auto-update"] : [];
56
56
  argv.push(...args);
57
57
  return Buffer.from(JSON.stringify(argv), "utf8");
58
58
  }
@@ -107,24 +107,21 @@ class FfiRuntimeHost {
107
107
  /** The stream JSON-RPC writes client→server frames to. */
108
108
  sendStream;
109
109
  /**
110
- * Resolves the cdylib next to the given CLI entrypoint and prepares the FFI host.
111
- * The cdylib is resolved as `prebuilds/<prebuildsFolder>/runtime.node` relative to
112
- * the entrypoint directory (the napi-rs `<node-platform>-<arch>` layout, e.g.
113
- * `linux-x64`). Throws if it cannot be found.
110
+ * Loads the runtime cdylib at the given path and prepares the FFI host.
114
111
  */
115
- static create(cliEntrypoint, prebuildsFolder, environment, args) {
116
- const fullEntrypoint = resolve(cliEntrypoint);
117
- const distDir = dirname(fullEntrypoint);
118
- const libraryPath = join(distDir, "prebuilds", prebuildsFolder, "runtime.node");
119
- if (!existsSync(libraryPath)) {
120
- throw new Error(`FFI runtime library not found. Looked for '${libraryPath}'.`);
112
+ static create(libraryPath, cliEntrypoint, environment, args) {
113
+ const fullLibraryPath = resolve(libraryPath);
114
+ if (!existsSync(fullLibraryPath)) {
115
+ throw new Error(`FFI runtime library not found at '${fullLibraryPath}'.`);
121
116
  }
122
- return new FfiRuntimeHost(libraryPath, fullEntrypoint, environment, args);
117
+ return new FfiRuntimeHost(
118
+ fullLibraryPath,
119
+ cliEntrypoint ? resolve(cliEntrypoint) : void 0,
120
+ environment,
121
+ args
122
+ );
123
123
  }
124
- /**
125
- * Starts the in-process runtime: spawns the CLI worker via the native host,
126
- * waits for readiness, and opens the FFI JSON-RPC connection.
127
- */
124
+ /** Starts the in-process Rust runtime and opens the FFI JSON-RPC connection. */
128
125
  async start() {
129
126
  const argvJson = buildArgvJson(this.cliEntrypoint, this.args);
130
127
  const envJson = buildEnvJson(this.environment);
@@ -144,9 +141,7 @@ class FfiRuntimeHost {
144
141
  );
145
142
  });
146
143
  if (!this.serverId) {
147
- throw new Error(
148
- `copilot_runtime_host_start failed (library '${this.libraryPath}', entrypoint '${this.cliEntrypoint}').`
149
- );
144
+ throw new Error(`copilot_runtime_host_start failed (library '${this.libraryPath}').`);
150
145
  }
151
146
  this.outboundCallback = koffi.register(
152
147
  (_userData, bytesPtr, bytesLen) => this.feedInbound(bytesPtr, bytesLen),