@github/copilot-sdk 1.0.29-preview.1 → 1.0.29-preview.2

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.
@@ -2174,6 +2174,49 @@ function createInternalServerRpc(connection) {
2174
2174
  }
2175
2175
  function createSessionRpc(connection, sessionId) {
2176
2176
  return {
2177
+ /** @experimental */
2178
+ management: {
2179
+ /**
2180
+ * Updates opt-in session management policy live. Enabling the master enables all tools before applying individual overrides. Opt-in is scoped to the session's configuration directory.
2181
+ *
2182
+ * @param params Updates the session's live policy without changing persistent host settings.
2183
+ *
2184
+ * @returns Opt-in policy for local session management.
2185
+ */
2186
+ configure: async (params) => connection.sendRequest("session.management.configure", { ...params, sessionId }),
2187
+ /**
2188
+ * Lists other live, opted-in sessions in the same configuration directory. Requires the list tool to be enabled.
2189
+ *
2190
+ * @param params Lists opted-in local peers. The caller is omitted.
2191
+ *
2192
+ * @returns Eligible live peers reported by their owning runtimes.
2193
+ */
2194
+ list: async (params) => connection.sendRequest("session.management.list", { ...params, sessionId }),
2195
+ /**
2196
+ * Injects peer text into an opted-in session. Wakes an idle agent and safely queues delivery to a busy agent. Acceptance does not imply an answer or completed task.
2197
+ *
2198
+ * @param params Sends peer text, never human approval, to another opted-in session.
2199
+ *
2200
+ * @returns Acceptance is not a completed turn or a reply.
2201
+ */
2202
+ message: async (params) => connection.sendRequest("session.management.message", { ...params, sessionId }),
2203
+ /**
2204
+ * Asks the owning host to create and supervise a separate session, preserving permissions and model restrictions. Omitted model, reasoning effort, context tier and cwd inherit the caller's current values; explicit overrides use normal model validation and workspace trust. Records durable creation lineage before delivering the initial task as peer text. Returns the new session ID, not task completion. Requires the create tool and a host creation handler.
2205
+ *
2206
+ * @param params Requests a separate session. Omitted launch options inherit the caller's current configuration.
2207
+ *
2208
+ * @returns Identifies a session owned and supervised by the creating host.
2209
+ */
2210
+ create: async (params) => connection.sendRequest("session.management.create", { ...params, sessionId }),
2211
+ /**
2212
+ * Closes a live opted-in session created by the caller or one of its descendants, preserving saved history and leaving descendants open. Requires the close capability to be enabled. Self, ancestors, siblings and unrelated sessions cannot be closed.
2213
+ *
2214
+ * @param params Closes one live opted-in descendant without deleting its saved history or closing its children.
2215
+ *
2216
+ * @returns Completion of the existing non-deleting close lifecycle.
2217
+ */
2218
+ close: async (params) => connection.sendRequest("session.management.close", { ...params, sessionId })
2219
+ },
2177
2220
  /** @experimental */
2178
2221
  providers: {
2179
2222
  /**
@@ -2811,7 +2854,13 @@ function createSessionRpc(connection, sessionId) {
2811
2854
  *
2812
2855
  * @returns Canonical runtime state for the session's current autopilot objective.
2813
2856
  */
2814
- getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId })
2857
+ getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId }),
2858
+ /**
2859
+ * Sets whether completing or pausing this session's objective preserves autopilot mode. This in-memory preference defaults to false and must be reapplied when attaching a client.
2860
+ *
2861
+ * @param params Client-resolved preference for retaining autopilot mode after objective completion or pause.
2862
+ */
2863
+ setStayInAutopilot: async (params) => connection.sendRequest("session.autopilotObjective.setStayInAutopilot", { ...params, sessionId })
2815
2864
  },
2816
2865
  /** @experimental */
2817
2866
  completions: {
@@ -3551,6 +3600,12 @@ function createSessionRpc(connection, sessionId) {
3551
3600
  * @returns The selectable model entries and selection ids synthesized for the synchronized BYOK models.
3552
3601
  */
3553
3602
  sync: async (params) => connection.sendRequest("session.provider.sync", { ...params, sessionId }),
3603
+ /**
3604
+ * Returns credential-free provider configuration status for the selected model. This does not validate provider credentials or contact the provider.
3605
+ *
3606
+ * @returns Credential-free provider configuration status for the selected model.
3607
+ */
3608
+ getStatus: async () => connection.sendRequest("session.provider.getStatus", { sessionId }),
3554
3609
  /**
3555
3610
  * Withdraws named host-managed models from the session's BYOK registry, leaving every other entry untouched. The scoped counterpart to `provider.sync`: a snapshot can only describe entries the caller knows about, so using it to remove one model silently withdraws rows registered by another source, such as a plugin calling `provider.add` at runtime. Naming what to remove leaves unrelated entries alone. Selection ids that are not registered are ignored, so withdrawal is idempotent. A provider is removed only when one of the withdrawn models was the last entry referencing it; a provider that simply has no models, which is the normal state while its rows are supplied by catalog discovery, is left in place.
3556
3611
  *
@@ -3891,6 +3946,12 @@ function createSessionRpc(connection, sessionId) {
3891
3946
  * @returns Current permission mode.
3892
3947
  */
3893
3948
  getMode: async () => connection.sendRequest("session.permissions.getMode", { sessionId }),
3949
+ /**
3950
+ * Returns the approval modes currently available under the session's feature and managed permission policy. This read does not change permissions; mutations must still check their authoritative result because policy may change.
3951
+ *
3952
+ * @returns Available permission modes, derived from current session policy.
3953
+ */
3954
+ getCapabilities: async () => connection.sendRequest("session.permissions.getCapabilities", { sessionId }),
3894
3955
  /**
3895
3956
  * Adds or removes session-scoped or location-scoped permission rules.
3896
3957
  *
@@ -170,6 +170,11 @@ class WorkflowProgressBuffer {
170
170
  if (this.closed) {
171
171
  throw new Error("Cannot log after the workflow run has settled");
172
172
  }
173
+ if (typeof text !== "string") {
174
+ throw new TypeError(
175
+ `${kind}() expects a string; got ${text === null ? "null" : typeof text}.`
176
+ );
177
+ }
173
178
  this.pending.push({ seq: this.nextSeq++, kind, text });
174
179
  this.scheduleFlush();
175
180
  }
@@ -297,6 +302,7 @@ class CopilotSession {
297
302
  /** Settles once every earlier `setTools` call has finished. */
298
303
  setToolsQueue = Promise.resolve();
299
304
  pendingExternalTools = /* @__PURE__ */ new Map();
305
+ pendingSessionCreations = /* @__PURE__ */ new Set();
300
306
  canvases = /* @__PURE__ */ new Map();
301
307
  bearerTokenProviders = /* @__PURE__ */ new Map();
302
308
  commandHandlers = /* @__PURE__ */ new Map();
@@ -309,6 +315,7 @@ class CopilotSession {
309
315
  exitPlanModeHandler;
310
316
  autoModeSwitchHandler;
311
317
  skillProvider;
318
+ sessionCreationHandler;
312
319
  hooks;
313
320
  transformCallbacks;
314
321
  _rpc = null;
@@ -896,6 +903,10 @@ class CopilotSession {
896
903
  controller.abort();
897
904
  }
898
905
  this.pendingExternalTools.clear();
906
+ for (const controller of this.pendingSessionCreations) {
907
+ controller.abort();
908
+ }
909
+ this.pendingSessionCreations.clear();
899
910
  this.eventHandlers.clear();
900
911
  this.typedEventHandlers.clear();
901
912
  this.toolHandlers.clear();
@@ -906,6 +917,7 @@ class CopilotSession {
906
917
  this.exitPlanModeHandler = void 0;
907
918
  this.autoModeSwitchHandler = void 0;
908
919
  this.skillProvider = void 0;
920
+ this.sessionCreationHandler = void 0;
909
921
  this.hooks = void 0;
910
922
  this.traceContextProvider = void 0;
911
923
  this.bearerTokenProviders.clear();
@@ -1869,6 +1881,41 @@ class CopilotSession {
1869
1881
  this.assertConnected();
1870
1882
  this.skillProvider = provider;
1871
1883
  }
1884
+ /**
1885
+ * Registers the host's creation callback without enabling the tool group.
1886
+ * Enable it separately with `session.rpc.management.configure({ enabled: true })`.
1887
+ */
1888
+ async setSessionCreationHandler(handler) {
1889
+ this.assertConnected();
1890
+ const previous = this.sessionCreationHandler;
1891
+ this.sessionCreationHandler = handler;
1892
+ try {
1893
+ return await this.rpc.management.configure({ hasCreateHandler: handler !== void 0 });
1894
+ } catch (error) {
1895
+ if (this.sessionCreationHandler === handler) this.sessionCreationHandler = previous;
1896
+ throw error;
1897
+ }
1898
+ }
1899
+ /** @internal */
1900
+ async _handleSessionManagementCreate(request, token) {
1901
+ this.assertConnected();
1902
+ const handler = this.sessionCreationHandler;
1903
+ if (!handler || request.parentSessionId !== this.sessionId || request.sessionId !== this.sessionId) {
1904
+ throw new Error("Session creation handler is unavailable");
1905
+ }
1906
+ const controller = new AbortController();
1907
+ this.pendingSessionCreations.add(controller);
1908
+ const subscription = token.onCancellationRequested(() => controller.abort());
1909
+ if (token.isCancellationRequested) controller.abort();
1910
+ try {
1911
+ return await handler(request, { signal: controller.signal });
1912
+ } catch {
1913
+ throw new Error("Session creation callback failed");
1914
+ } finally {
1915
+ subscription.dispose();
1916
+ this.pendingSessionCreations.delete(controller);
1917
+ }
1918
+ }
1872
1919
  /**
1873
1920
  * Handles a `skillProvider.list` request from the runtime.
1874
1921
  *
@@ -1,2 +1,2 @@
1
- export declare const COPILOT_CLI_VERSION = "1.0.106-2";
1
+ export declare const COPILOT_CLI_VERSION = "1.0.106-3";
2
2
  export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
@@ -1,4 +1,4 @@
1
- const COPILOT_CLI_VERSION = "1.0.106-2";
1
+ const COPILOT_CLI_VERSION = "1.0.106-3";
2
2
  const COPILOT_CLI_USE_NPM_PACKAGE = false;
3
3
  export {
4
4
  COPILOT_CLI_USE_NPM_PACKAGE,
package/dist/client.d.ts CHANGED
@@ -38,7 +38,6 @@ export declare class CopilotClient {
38
38
  private onListModels?;
39
39
  private onGetTraceContext?;
40
40
  private modelsCache;
41
- private modelsCacheLock;
42
41
  private sessionLifecycleHandlers;
43
42
  private typedLifecycleHandlers;
44
43
  private _rpc;
package/dist/client.js CHANGED
@@ -318,8 +318,10 @@ class CopilotClient {
318
318
  effectiveConnectionToken;
319
319
  onListModels;
320
320
  onGetTraceContext;
321
- modelsCache = null;
322
- modelsCacheLock = Promise.resolve();
321
+ modelsCache = {
322
+ models: null,
323
+ lock: Promise.resolve()
324
+ };
323
325
  sessionLifecycleHandlers = /* @__PURE__ */ new Set();
324
326
  typedLifecycleHandlers = /* @__PURE__ */ new Map();
325
327
  _rpc = null;
@@ -888,7 +890,7 @@ class CopilotClient {
888
890
  this._rpc = null;
889
891
  this._internalRpc = null;
890
892
  }
891
- this.modelsCache = null;
893
+ this.modelsCache = { models: null, lock: Promise.resolve() };
892
894
  if (this.socket) {
893
895
  const socket = this.socket;
894
896
  this.socket = null;
@@ -1050,7 +1052,7 @@ class CopilotClient {
1050
1052
  this._rpc = null;
1051
1053
  this._internalRpc = null;
1052
1054
  }
1053
- this.modelsCache = null;
1055
+ this.modelsCache = { models: null, lock: Promise.resolve() };
1054
1056
  if (this.socket) {
1055
1057
  try {
1056
1058
  this.socket.destroy();
@@ -2069,14 +2071,16 @@ class CopilotClient {
2069
2071
  * @throws Error if not connected (when no custom handler is set)
2070
2072
  */
2071
2073
  async listModels() {
2072
- await this.modelsCacheLock;
2074
+ const cache = this.modelsCache;
2075
+ const previousLock = cache.lock;
2073
2076
  let resolveLock;
2074
- this.modelsCacheLock = new Promise((resolve2) => {
2077
+ cache.lock = new Promise((resolve2) => {
2075
2078
  resolveLock = resolve2;
2076
2079
  });
2080
+ await previousLock;
2077
2081
  try {
2078
- if (this.modelsCache !== null) {
2079
- return [...this.modelsCache];
2082
+ if (cache.models !== null) {
2083
+ return [...cache.models];
2080
2084
  }
2081
2085
  let models;
2082
2086
  if (this.onListModels) {
@@ -2105,7 +2109,7 @@ class CopilotClient {
2105
2109
  }
2106
2110
  }
2107
2111
  }
2108
- this.modelsCache = [...models];
2112
+ cache.models = [...models];
2109
2113
  return [...models];
2110
2114
  } finally {
2111
2115
  resolveLock();
@@ -2870,6 +2874,14 @@ stderr: ${stderrOutput}` : ""}`
2870
2874
  "skillProvider.list",
2871
2875
  async (params, token) => await this.resolveSkillProviderSession(params)._handleSkillProviderList(token)
2872
2876
  );
2877
+ this.connection.onRequest(
2878
+ "sessionManagement.create",
2879
+ async (params, token) => {
2880
+ const session = this.sessions.get(params.sessionId);
2881
+ if (!session) throw new Error("Session creation owner is unavailable");
2882
+ return await session._handleSessionManagementCreate(params, token);
2883
+ }
2884
+ );
2873
2885
  this.connection.onRequest(
2874
2886
  "skillProvider.read",
2875
2887
  async (params, token) => {
@@ -2907,7 +2919,7 @@ stderr: ${stderrOutput}` : ""}`
2907
2919
  this.messageWriter = null;
2908
2920
  this._rpc = null;
2909
2921
  this._internalRpc = null;
2910
- this.modelsCache = null;
2922
+ this.modelsCache = { models: null, lock: Promise.resolve() };
2911
2923
  };
2912
2924
  const disconnectAfterDrain = () => {
2913
2925
  if (exitFallback !== void 0) {
@@ -82,7 +82,9 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
82
82
  if (this.#upstream) {
83
83
  return;
84
84
  }
85
- const upstream = new WebSocket(this.context.url);
85
+ const upstream = new WebSocket(this.context.url, {
86
+ headers: forwardedRequestHeaders(this.context.headers)
87
+ });
86
88
  upstream.binaryType = "arraybuffer";
87
89
  this.#upstream = upstream;
88
90
  upstream.addEventListener("message", (event) => {
@@ -467,19 +469,24 @@ const FORBIDDEN_REQUEST_HEADERS = /* @__PURE__ */ new Set([
467
469
  "te",
468
470
  "trailer"
469
471
  ]);
470
- async function buildFetchRequest(exchange) {
472
+ function forwardedRequestHeaders(source) {
471
473
  const headers = new Headers();
472
- for (const [name, values] of Object.entries(exchange.headers)) {
474
+ for (const [name, values] of Object.entries(source)) {
473
475
  if (!values) {
474
476
  continue;
475
477
  }
476
- if (FORBIDDEN_REQUEST_HEADERS.has(name.toLowerCase())) {
478
+ const lower = name.toLowerCase();
479
+ if (FORBIDDEN_REQUEST_HEADERS.has(lower) || lower.startsWith("sec-websocket-")) {
477
480
  continue;
478
481
  }
479
482
  for (const value of values) {
480
483
  headers.append(name, value);
481
484
  }
482
485
  }
486
+ return headers;
487
+ }
488
+ async function buildFetchRequest(exchange) {
489
+ const headers = forwardedRequestHeaders(exchange.headers);
483
490
  const method = exchange.method.toUpperCase();
484
491
  const hasBody = method !== "GET" && method !== "HEAD";
485
492
  let body;