@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.
@@ -18,32 +18,50 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var runtimeArtifacts_exports = {};
20
20
  __export(runtimeArtifacts_exports, {
21
+ RUNTIME_PLATFORMS: () => RUNTIME_PLATFORMS,
21
22
  defaultRuntimeCacheRoot: () => defaultRuntimeCacheRoot,
22
- materializeRuntimeBundle: () => materializeRuntimeBundle
23
+ ensureRuntimeBundle: () => ensureRuntimeBundle,
24
+ getRuntimePackageName: () => getRuntimePackageName,
25
+ getRuntimePlatform: () => getRuntimePlatform,
26
+ getRuntimeReleaseAssetName: () => getRuntimeReleaseAssetName,
27
+ materializeRuntimeBundle: () => materializeRuntimeBundle,
28
+ resolvePackageRoot: () => resolvePackageRoot,
29
+ validateFile: () => validateFile
23
30
  });
24
31
  module.exports = __toCommonJS(runtimeArtifacts_exports);
25
- var import_node_crypto = require("node:crypto");
26
32
  var import_node_fs = require("node:fs");
33
+ var import_node_crypto = require("node:crypto");
34
+ var import_node_module = require("node:module");
27
35
  var import_node_os = require("node:os");
28
36
  var import_node_path = require("node:path");
37
+ var import_cliVersion = require("./cliVersion.js");
38
+ const import_meta = {};
39
+ const require2 = (0, import_node_module.createRequire)(typeof __filename === "string" ? __filename : import_meta.url);
40
+ const RUNTIME_PLATFORMS = [
41
+ "darwin-arm64",
42
+ "darwin-x64",
43
+ "linux-arm64",
44
+ "linux-x64",
45
+ "linuxmusl-arm64",
46
+ "linuxmusl-x64",
47
+ "win32-arm64",
48
+ "win32-x64"
49
+ ];
29
50
  const EXCLUDED_TOP_LEVEL = /* @__PURE__ */ new Set([
30
51
  "app.js",
31
52
  "assets",
32
53
  "changelog.json",
33
54
  "copilot",
34
55
  "copilot.exe",
35
- "copilot-sdk",
36
56
  "foundry-local-sdk",
37
57
  "index.js",
38
58
  "LICENSE.md",
39
59
  "napi-oop-runtime",
40
60
  "npm-loader.js",
41
61
  "package.json",
42
- "preloads",
43
62
  "pvrecorder",
44
63
  "queries",
45
64
  "README.md",
46
- "sdk",
47
65
  "sea-loader.js",
48
66
  "webview"
49
67
  ]);
@@ -82,14 +100,12 @@ function collectRuntimeAssets(sources) {
82
100
  continue;
83
101
  }
84
102
  const parts = sourceRelative.split(import_node_path.sep);
85
- let relativePath = sourceRelative;
86
103
  if (parts[0] === "prebuilds") {
87
104
  if (parts[1] !== sources.platform || parts.length < 3) {
88
105
  continue;
89
106
  }
90
- relativePath = parts.slice(2).join(import_node_path.sep);
91
107
  }
92
- assets.push({ source, relativePath });
108
+ assets.push({ source, relativePath: sourceRelative });
93
109
  }
94
110
  };
95
111
  visit(sources.packageRoot);
@@ -117,15 +133,20 @@ function defaultRuntimeCacheRoot(platform = process.platform, home = (0, import_
117
133
  const cacheDirectory = platform === "win32" ? environment.LOCALAPPDATA ?? (0, import_node_path.join)(home, "AppData", "Local") : platform === "darwin" ? (0, import_node_path.join)(home, "Library", "Caches") : environment.XDG_CACHE_HOME ?? (0, import_node_path.join)(home, ".cache");
118
134
  return (0, import_node_path.join)(cacheDirectory, "github-copilot-sdk", "runtime");
119
135
  }
120
- function materializeRuntimeBundle(sources, cacheRoot = defaultRuntimeCacheRoot()) {
136
+ function materializeRuntimeBundle(sources, cacheRoot = defaultRuntimeCacheRoot(), cacheKey = `${sources.platform}-${sourceFingerprint(collectRuntimeAssets(sources))}`) {
121
137
  const assets = collectRuntimeAssets(sources);
122
- const wrapperName = process.platform === "win32" ? "copilot-runtime.exe" : "copilot-runtime";
123
- const sourceWrapper = assets.find((asset) => asset.relativePath === wrapperName)?.source;
124
- const sourceRuntimeNode = assets.find((asset) => asset.relativePath === "runtime.node")?.source;
138
+ const wrapperName = sources.platform.startsWith("win32") ? "copilot-runtime.exe" : "copilot-runtime";
139
+ const prebuildDir = (0, import_node_path.join)("prebuilds", sources.platform);
140
+ const wrapperRelative = (0, import_node_path.join)(prebuildDir, wrapperName);
141
+ const runtimeNodeRelative = (0, import_node_path.join)(prebuildDir, "runtime.node");
142
+ const sourceWrapper = assets.find((asset) => asset.relativePath === wrapperRelative)?.source;
143
+ const sourceRuntimeNode = assets.find(
144
+ (asset) => asset.relativePath === runtimeNodeRelative
145
+ )?.source;
125
146
  validateRuntimeBundle(sourceWrapper ?? "", sourceRuntimeNode ?? "");
126
- const installDir = (0, import_node_path.join)(cacheRoot, `${sources.platform}-${sourceFingerprint(assets)}`);
127
- const installedWrapper = (0, import_node_path.join)(installDir, wrapperName);
128
- const installedRuntimeNode = (0, import_node_path.join)(installDir, "runtime.node");
147
+ const installDir = (0, import_node_path.join)(cacheRoot, cacheKey);
148
+ const installedWrapper = (0, import_node_path.join)(installDir, wrapperRelative);
149
+ const installedRuntimeNode = (0, import_node_path.join)(installDir, runtimeNodeRelative);
129
150
  if ((0, import_node_fs.existsSync)(installDir)) {
130
151
  validateRuntimeBundle(installedWrapper, installedRuntimeNode);
131
152
  makeExecutable(installedWrapper);
@@ -139,7 +160,7 @@ function materializeRuntimeBundle(sources, cacheRoot = defaultRuntimeCacheRoot()
139
160
  (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(destination), { recursive: true });
140
161
  (0, import_node_fs.copyFileSync)(asset.source, destination);
141
162
  }
142
- const stagedWrapper = (0, import_node_path.join)(stagingDir, wrapperName);
163
+ const stagedWrapper = (0, import_node_path.join)(stagingDir, wrapperRelative);
143
164
  makeExecutable(stagedWrapper);
144
165
  (0, import_node_fs.renameSync)(stagingDir, installDir);
145
166
  } catch (error) {
@@ -152,8 +173,82 @@ function materializeRuntimeBundle(sources, cacheRoot = defaultRuntimeCacheRoot()
152
173
  }
153
174
  return installedWrapper;
154
175
  }
176
+ function isMusl() {
177
+ if (process.platform !== "linux") {
178
+ return false;
179
+ }
180
+ const report = process.report?.getReport();
181
+ return report?.header?.glibcVersionRuntime === void 0;
182
+ }
183
+ function getRuntimePlatform(platform = process.platform, arch = process.arch, musl = isMusl()) {
184
+ if (arch !== "x64" && arch !== "arm64") {
185
+ throw new Error(`Unsupported Copilot CLI architecture: ${arch}.`);
186
+ }
187
+ if (platform === "linux") {
188
+ return `${musl ? "linuxmusl" : "linux"}-${arch}`;
189
+ }
190
+ if (platform === "darwin" || platform === "win32") {
191
+ return `${platform}-${arch}`;
192
+ }
193
+ throw new Error(`Unsupported Copilot CLI platform: ${platform}-${arch}.`);
194
+ }
195
+ function getRuntimeReleaseAssetName(version, platform) {
196
+ return `github-copilot-${version}-${platform}.tgz`;
197
+ }
198
+ function getRuntimePackageName(platform) {
199
+ return `@github/copilot-sdk-${platform}`;
200
+ }
201
+ function resolvePackageRoot(packageName, searchPaths = require2.resolve.paths(packageName) ?? []) {
202
+ return searchPaths.map((base) => (0, import_node_path.join)(base, ...packageName.split("/"))).find((candidate) => (0, import_node_fs.existsSync)((0, import_node_path.join)(candidate, "package.json")));
203
+ }
204
+ async function ensureRuntimeBundle(version, options = {}) {
205
+ const platform = options.platform ?? getRuntimePlatform();
206
+ if (import_cliVersion.COPILOT_CLI_USE_NPM_PACKAGE) {
207
+ const packageName2 = `@github/copilot-${platform}`;
208
+ const packageRoot2 = resolvePackageRoot(packageName2, options.packageSearchPaths);
209
+ if (!packageRoot2) {
210
+ throw new Error(`Could not resolve ${packageName2} for Copilot CLI ${version}.`);
211
+ }
212
+ validateFile(
213
+ (0, import_node_path.join)(packageRoot2, "prebuilds", platform, "runtime.node"),
214
+ "Copilot runtime.node"
215
+ );
216
+ return materializeRuntimeBundle(
217
+ { packageRoot: packageRoot2, platform },
218
+ options.cacheRoot,
219
+ `${version}-${platform}`
220
+ );
221
+ }
222
+ const packageName = getRuntimePackageName(platform);
223
+ const packageRoot = resolvePackageRoot(packageName, options.packageSearchPaths);
224
+ if (!packageRoot) {
225
+ throw new Error(
226
+ `Could not resolve ${packageName}. Reinstall @github/copilot-sdk so its platform package is installed.`
227
+ );
228
+ }
229
+ const wrapperName = platform.startsWith("win32") ? "copilot-runtime.exe" : "copilot-runtime";
230
+ const prebuildDir = (0, import_node_path.join)(packageRoot, "prebuilds", platform);
231
+ const wrapper = (0, import_node_path.join)(prebuildDir, wrapperName);
232
+ try {
233
+ validateRuntimeBundle(wrapper, (0, import_node_path.join)(prebuildDir, "runtime.node"));
234
+ } catch (error) {
235
+ throw new Error(
236
+ `${packageName} is missing required Copilot CLI runtime files. Reinstall @github/copilot-sdk.`,
237
+ { cause: error }
238
+ );
239
+ }
240
+ makeExecutable(wrapper);
241
+ return wrapper;
242
+ }
155
243
  // Annotate the CommonJS export names for ESM import in node:
156
244
  0 && (module.exports = {
245
+ RUNTIME_PLATFORMS,
157
246
  defaultRuntimeCacheRoot,
158
- materializeRuntimeBundle
247
+ ensureRuntimeBundle,
248
+ getRuntimePackageName,
249
+ getRuntimePlatform,
250
+ getRuntimeReleaseAssetName,
251
+ materializeRuntimeBundle,
252
+ resolvePackageRoot,
253
+ validateFile
159
254
  });
@@ -249,6 +249,7 @@ class CopilotSession {
249
249
  eventHandlers = /* @__PURE__ */ new Set();
250
250
  typedEventHandlers = /* @__PURE__ */ new Map();
251
251
  toolHandlers = /* @__PURE__ */ new Map();
252
+ pendingExternalTools = /* @__PURE__ */ new Map();
252
253
  canvases = /* @__PURE__ */ new Map();
253
254
  bearerTokenProviders = /* @__PURE__ */ new Map();
254
255
  commandHandlers = /* @__PURE__ */ new Map();
@@ -268,6 +269,7 @@ class CopilotSession {
268
269
  _capabilities = {};
269
270
  openCanvasInstances = [];
270
271
  disconnected = false;
272
+ disconnecting = false;
271
273
  onDisconnected;
272
274
  /** @internal Client session API handlers, populated by CopilotClient during create/resume. */
273
275
  clientSessionApis = {};
@@ -525,6 +527,10 @@ class CopilotSession {
525
527
  return;
526
528
  }
527
529
  this.disconnected = true;
530
+ for (const controller of this.pendingExternalTools.values()) {
531
+ controller.abort();
532
+ }
533
+ this.pendingExternalTools.clear();
528
534
  this._runOnDisconnected();
529
535
  this.eventHandlers.clear();
530
536
  this.typedEventHandlers.clear();
@@ -628,6 +634,15 @@ class CopilotSession {
628
634
  tracestate
629
635
  );
630
636
  }
637
+ } else if (event.type === "external_tool.completed") {
638
+ const { requestId } = event.data;
639
+ if (requestId) {
640
+ const controller = this.pendingExternalTools.get(requestId);
641
+ if (controller) {
642
+ this.pendingExternalTools.delete(requestId);
643
+ controller.abort();
644
+ }
645
+ }
631
646
  } else if (event.type === "permission.requested") {
632
647
  const { requestId, permissionRequest, resolvedByHook } = event.data;
633
648
  if (resolvedByHook) {
@@ -708,16 +723,35 @@ class CopilotSession {
708
723
  * @internal
709
724
  */
710
725
  async _executeToolAndRespond(requestId, toolName, toolCallId, args, handler, traceparent, tracestate) {
726
+ const controller = new AbortController();
727
+ if (this.disconnected || this.pendingExternalTools.has(requestId)) {
728
+ return;
729
+ }
730
+ this.pendingExternalTools.set(requestId, controller);
711
731
  try {
712
732
  let availableTools;
713
733
  if (toolName === TOOL_SEARCH_TOOL_NAME) {
734
+ if (controller.signal.aborted) {
735
+ return;
736
+ }
737
+ const aborted = new Promise((resolve) => {
738
+ controller.signal.addEventListener("abort", () => resolve(void 0), {
739
+ once: true
740
+ });
741
+ });
714
742
  try {
715
- const metadata = await this.rpc.tools.getCurrentMetadata();
716
- availableTools = metadata.tools ?? void 0;
743
+ const metadata = await Promise.race([
744
+ this.rpc.tools.getCurrentMetadata(),
745
+ aborted
746
+ ]);
747
+ availableTools = metadata?.tools ?? void 0;
717
748
  } catch {
718
749
  availableTools = void 0;
719
750
  }
720
751
  }
752
+ if (controller.signal.aborted) {
753
+ return;
754
+ }
721
755
  const rawResult = await handler(args, {
722
756
  sessionId: this.sessionId,
723
757
  toolCallId,
@@ -725,7 +759,8 @@ class CopilotSession {
725
759
  arguments: args,
726
760
  availableTools,
727
761
  traceparent,
728
- tracestate
762
+ tracestate,
763
+ signal: controller.signal
729
764
  });
730
765
  let result;
731
766
  if (rawResult == null) {
@@ -737,12 +772,12 @@ class CopilotSession {
737
772
  } else {
738
773
  result = JSON.stringify(rawResult);
739
774
  }
740
- if (this.disconnected) {
775
+ if (!this._claimExternalTool(requestId, controller)) {
741
776
  return;
742
777
  }
743
778
  await this.rpc.tools.handlePendingToolCall({ requestId, result });
744
779
  } catch (error) {
745
- if (this.disconnected) {
780
+ if (!this._claimExternalTool(requestId, controller)) {
746
781
  return;
747
782
  }
748
783
  const message = error instanceof Error ? error.message : String(error);
@@ -753,7 +788,19 @@ class CopilotSession {
753
788
  throw rpcError;
754
789
  }
755
790
  }
791
+ } finally {
792
+ if (this.pendingExternalTools.get(requestId) === controller) {
793
+ this.pendingExternalTools.delete(requestId);
794
+ }
795
+ controller.abort();
796
+ }
797
+ }
798
+ _claimExternalTool(requestId, controller) {
799
+ if (this.disconnected || this.pendingExternalTools.get(requestId) !== controller) {
800
+ return false;
756
801
  }
802
+ this.pendingExternalTools.delete(requestId);
803
+ return true;
757
804
  }
758
805
  /**
759
806
  * Executes a permission handler and sends the result back via RPC.
@@ -1507,13 +1554,27 @@ class CopilotSession {
1507
1554
  * ```
1508
1555
  */
1509
1556
  async disconnect() {
1510
- if (this.disconnected) {
1557
+ if (this.disconnected || this.disconnecting) {
1511
1558
  return;
1512
1559
  }
1513
- await this.connection.sendRequest("session.destroy", {
1514
- sessionId: this.sessionId
1515
- });
1516
- this._markDisconnected();
1560
+ this.disconnecting = true;
1561
+ try {
1562
+ let response = { success: false };
1563
+ for (let attempt = 0; attempt < 2 && !response.success; attempt++) {
1564
+ response = await this.connection.sendRequest("session.detach", {
1565
+ sessionId: this.sessionId
1566
+ });
1567
+ }
1568
+ if (!response.success) {
1569
+ throw new Error(
1570
+ `Failed to disconnect session ${this.sessionId}: ${response.error || "Unknown error"}`
1571
+ );
1572
+ }
1573
+ this._markDisconnected();
1574
+ } catch (error) {
1575
+ this.disconnecting = false;
1576
+ throw error;
1577
+ }
1517
1578
  }
1518
1579
  /** Enables `await using session = ...` syntax for automatic cleanup. */
1519
1580
  async [Symbol.asyncDispose]() {
@@ -1555,11 +1616,48 @@ class CopilotSession {
1555
1616
  * ```typescript
1556
1617
  * await session.setModel("gpt-5.4");
1557
1618
  * await session.setModel("claude-sonnet-4.6", { reasoningEffort: "high" });
1619
+ *
1620
+ * // Select the Auto model and its routing preference in one call.
1621
+ * await session.setModel("auto", { autoTier: "intelligence" });
1558
1622
  * ```
1559
1623
  */
1560
1624
  async setModel(model, options) {
1561
1625
  await this.rpc.model.switchTo({ modelId: model, ...options });
1562
1626
  }
1627
+ /**
1628
+ * Change the Auto routing preference without changing the selected model.
1629
+ *
1630
+ * The runtime does not apply the preference immediately. It records the
1631
+ * request and commits it only when a later user turn using the `auto` model
1632
+ * successfully obtains a usable model from the provider. A `pending` status
1633
+ * therefore confirms that the request was accepted, not that it took effect.
1634
+ *
1635
+ * Watch for the outcome through the `session.model_change` event on success,
1636
+ * or the ephemeral `session.auto_tier_switch_failed` event on failure. You
1637
+ * can also read the current committed and in-flight state at any time with
1638
+ * `session.rpc.model.getCurrent()`.
1639
+ *
1640
+ * Only the most recent request survives: issuing a new request replaces any
1641
+ * earlier one that has not yet been claimed by a turn.
1642
+ *
1643
+ * @param autoTier - Routing preference to activate, or `null` to return to
1644
+ * the provider's default Auto routing
1645
+ * @returns The runtime's immediate acknowledgement and Auto preference snapshot
1646
+ *
1647
+ * @experimental Part of an experimental Auto routing surface and may change
1648
+ * or be removed in a future release.
1649
+ *
1650
+ * @example
1651
+ * ```typescript
1652
+ * const result = await session.setAutoTier("intelligence");
1653
+ * if (result.status === "pending") {
1654
+ * // Takes effect on a later turn that uses the `auto` model.
1655
+ * }
1656
+ * ```
1657
+ */
1658
+ async setAutoTier(autoTier) {
1659
+ return await this.rpc.model.switchAutoTier({ autoTier });
1660
+ }
1563
1661
  /**
1564
1662
  * Log a message to the session timeline.
1565
1663
  * The message appears in the session event stream and is visible to SDK consumers
@@ -0,0 +1,2 @@
1
+ export declare const COPILOT_CLI_VERSION = "1.0.83";
2
+ export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
@@ -0,0 +1,6 @@
1
+ const COPILOT_CLI_VERSION = "1.0.83";
2
+ const COPILOT_CLI_USE_NPM_PACKAGE = false;
3
+ export {
4
+ COPILOT_CLI_USE_NPM_PACKAGE,
5
+ COPILOT_CLI_VERSION
6
+ };
package/dist/client.d.ts CHANGED
@@ -7,6 +7,7 @@ export declare class CopilotClient {
7
7
  private ffiHost;
8
8
  private connection;
9
9
  private messageWriter;
10
+ private connectionClosed;
10
11
  private socket;
11
12
  private runtimePort;
12
13
  private actualHost;
@@ -92,7 +93,7 @@ export declare class CopilotClient {
92
93
  private connectionExtraArgs;
93
94
  /**
94
95
  * Parse CLI URL into host and port
95
- * Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
96
+ * Supports formats: "host:port", "[ipv6]:port", "http://host:port", "https://host:port", or just "port"
96
97
  */
97
98
  private parseCliUrl;
98
99
  private validateSessionFsConfig;