@github/copilot-sdk 0.1.30 → 0.1.31

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.
@@ -2,7 +2,7 @@
2
2
  * The SDK protocol version.
3
3
  * This must match the version expected by the copilot-agent-runtime server.
4
4
  */
5
- export declare const SDK_PROTOCOL_VERSION = 2;
5
+ export declare const SDK_PROTOCOL_VERSION = 3;
6
6
  /**
7
7
  * Gets the SDK protocol version.
8
8
  * @returns The protocol version number
@@ -1,4 +1,4 @@
1
- const SDK_PROTOCOL_VERSION = 2;
1
+ const SDK_PROTOCOL_VERSION = 3;
2
2
  function getSdkProtocolVersion() {
3
3
  return SDK_PROTOCOL_VERSION;
4
4
  }
package/dist/session.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import type { MessageConnection } from "vscode-jsonrpc/node";
6
6
  import { createSessionRpc } from "./generated/rpc.js";
7
- import type { MessageOptions, PermissionHandler, PermissionRequestResult, SessionEvent, SessionEventHandler, SessionEventType, SessionHooks, Tool, ToolHandler, TypedSessionEventHandler, UserInputHandler, UserInputResponse } from "./types.js";
7
+ import type { MessageOptions, PermissionHandler, SessionEvent, SessionEventHandler, SessionEventType, SessionHooks, Tool, ToolHandler, TypedSessionEventHandler, UserInputHandler, UserInputResponse } from "./types.js";
8
8
  /** Assistant message event - the final response from the assistant. */
9
9
  export type AssistantMessageEvent = Extract<SessionEvent, {
10
10
  type: "assistant.message";
@@ -31,7 +31,7 @@ export type AssistantMessageEvent = Extract<SessionEvent, {
31
31
  * await session.sendAndWait({ prompt: "Hello, world!" });
32
32
  *
33
33
  * // Clean up
34
- * await session.destroy();
34
+ * await session.disconnect();
35
35
  * ```
36
36
  */
37
37
  export declare class CopilotSession {
@@ -72,7 +72,7 @@ export declare class CopilotSession {
72
72
  *
73
73
  * @param options - The message options including the prompt and optional attachments
74
74
  * @returns A promise that resolves with the message ID of the response
75
- * @throws Error if the session has been destroyed or the connection fails
75
+ * @throws Error if the session has been disconnected or the connection fails
76
76
  *
77
77
  * @example
78
78
  * ```typescript
@@ -97,7 +97,7 @@ export declare class CopilotSession {
97
97
  * @returns A promise that resolves with the final assistant message when the session becomes idle,
98
98
  * or undefined if no assistant message was received
99
99
  * @throws Error if the timeout is reached before the session becomes idle
100
- * @throws Error if the session has been destroyed or the connection fails
100
+ * @throws Error if the session has been disconnected or the connection fails
101
101
  *
102
102
  * @example
103
103
  * ```typescript
@@ -155,11 +155,29 @@ export declare class CopilotSession {
155
155
  on(handler: SessionEventHandler): () => void;
156
156
  /**
157
157
  * Dispatches an event to all registered handlers.
158
+ * Also handles broadcast request events internally (external tool calls, permissions).
158
159
  *
159
160
  * @param event - The session event to dispatch
160
161
  * @internal This method is for internal use by the SDK.
161
162
  */
162
163
  _dispatchEvent(event: SessionEvent): void;
164
+ /**
165
+ * Handles broadcast request events by executing local handlers and responding via RPC.
166
+ * Handlers are dispatched as fire-and-forget — rejections propagate as unhandled promise
167
+ * rejections, consistent with standard EventEmitter / event handler semantics.
168
+ * @internal
169
+ */
170
+ private _handleBroadcastEvent;
171
+ /**
172
+ * Executes a tool handler and sends the result back via RPC.
173
+ * @internal
174
+ */
175
+ private _executeToolAndRespond;
176
+ /**
177
+ * Executes a permission handler and sends the result back via RPC.
178
+ * @internal
179
+ */
180
+ private _executePermissionAndRespond;
163
181
  /**
164
182
  * Registers custom tool handlers for this session.
165
183
  *
@@ -208,14 +226,6 @@ export declare class CopilotSession {
208
226
  * @internal This method is typically called internally when creating a session.
209
227
  */
210
228
  registerHooks(hooks?: SessionHooks): void;
211
- /**
212
- * Handles a permission request from the Copilot CLI.
213
- *
214
- * @param request - The permission request data from the CLI
215
- * @returns A promise that resolves with the permission decision
216
- * @internal This method is for internal use by the SDK.
217
- */
218
- _handlePermissionRequest(request: unknown): Promise<PermissionRequestResult>;
219
229
  /**
220
230
  * Handles a user input request from the Copilot CLI.
221
231
  *
@@ -240,7 +250,7 @@ export declare class CopilotSession {
240
250
  * assistant responses, tool executions, and other session events.
241
251
  *
242
252
  * @returns A promise that resolves with an array of all session events
243
- * @throws Error if the session has been destroyed or the connection fails
253
+ * @throws Error if the session has been disconnected or the connection fails
244
254
  *
245
255
  * @example
246
256
  * ```typescript
@@ -254,22 +264,39 @@ export declare class CopilotSession {
254
264
  */
255
265
  getMessages(): Promise<SessionEvent[]>;
256
266
  /**
257
- * Destroys this session and releases all associated resources.
267
+ * Disconnects this session and releases all in-memory resources (event handlers,
268
+ * tool handlers, permission handlers).
258
269
  *
259
- * After calling this method, the session can no longer be used. All event
260
- * handlers and tool handlers are cleared. To continue the conversation,
261
- * use {@link CopilotClient.resumeSession} with the session ID.
270
+ * Session state on disk (conversation history, planning state, artifacts) is
271
+ * preserved, so the conversation can be resumed later by calling
272
+ * {@link CopilotClient.resumeSession} with the session ID. To permanently
273
+ * remove all session data including files on disk, use
274
+ * {@link CopilotClient.deleteSession} instead.
262
275
  *
263
- * @returns A promise that resolves when the session is destroyed
276
+ * After calling this method, the session object can no longer be used.
277
+ *
278
+ * @returns A promise that resolves when the session is disconnected
264
279
  * @throws Error if the connection fails
265
280
  *
266
281
  * @example
267
282
  * ```typescript
268
- * // Clean up when done
269
- * await session.destroy();
283
+ * // Clean up when done — session can still be resumed later
284
+ * await session.disconnect();
270
285
  * ```
271
286
  */
287
+ disconnect(): Promise<void>;
288
+ /**
289
+ * @deprecated Use {@link disconnect} instead. This method will be removed in a future release.
290
+ *
291
+ * Disconnects this session and releases all in-memory resources.
292
+ * Session data on disk is preserved for later resumption.
293
+ *
294
+ * @returns A promise that resolves when the session is disconnected
295
+ * @throws Error if the connection fails
296
+ */
272
297
  destroy(): Promise<void>;
298
+ /** Enables `await using session = ...` syntax for automatic cleanup. */
299
+ [Symbol.asyncDispose](): Promise<void>;
273
300
  /**
274
301
  * Aborts the currently processing message in this session.
275
302
  *
@@ -277,7 +304,7 @@ export declare class CopilotSession {
277
304
  * and can continue to be used for new messages.
278
305
  *
279
306
  * @returns A promise that resolves when the abort request is acknowledged
280
- * @throws Error if the session has been destroyed or the connection fails
307
+ * @throws Error if the session has been disconnected or the connection fails
281
308
  *
282
309
  * @example
283
310
  * ```typescript
package/dist/session.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ConnectionError, ResponseError } from "vscode-jsonrpc/node";
1
2
  import { createSessionRpc } from "./generated/rpc.js";
2
3
  class CopilotSession {
3
4
  /**
@@ -45,7 +46,7 @@ class CopilotSession {
45
46
  *
46
47
  * @param options - The message options including the prompt and optional attachments
47
48
  * @returns A promise that resolves with the message ID of the response
48
- * @throws Error if the session has been destroyed or the connection fails
49
+ * @throws Error if the session has been disconnected or the connection fails
49
50
  *
50
51
  * @example
51
52
  * ```typescript
@@ -78,7 +79,7 @@ class CopilotSession {
78
79
  * @returns A promise that resolves with the final assistant message when the session becomes idle,
79
80
  * or undefined if no assistant message was received
80
81
  * @throws Error if the timeout is reached before the session becomes idle
81
- * @throws Error if the session has been destroyed or the connection fails
82
+ * @throws Error if the session has been disconnected or the connection fails
82
83
  *
83
84
  * @example
84
85
  * ```typescript
@@ -152,11 +153,13 @@ class CopilotSession {
152
153
  }
153
154
  /**
154
155
  * Dispatches an event to all registered handlers.
156
+ * Also handles broadcast request events internally (external tool calls, permissions).
155
157
  *
156
158
  * @param event - The session event to dispatch
157
159
  * @internal This method is for internal use by the SDK.
158
160
  */
159
161
  _dispatchEvent(event) {
162
+ this._handleBroadcastEvent(event);
160
163
  const typedHandlers = this.typedEventHandlers.get(event.type);
161
164
  if (typedHandlers) {
162
165
  for (const handler of typedHandlers) {
@@ -173,6 +176,85 @@ class CopilotSession {
173
176
  }
174
177
  }
175
178
  }
179
+ /**
180
+ * Handles broadcast request events by executing local handlers and responding via RPC.
181
+ * Handlers are dispatched as fire-and-forget — rejections propagate as unhandled promise
182
+ * rejections, consistent with standard EventEmitter / event handler semantics.
183
+ * @internal
184
+ */
185
+ _handleBroadcastEvent(event) {
186
+ if (event.type === "external_tool.requested") {
187
+ const { requestId, toolName } = event.data;
188
+ const args = event.data.arguments;
189
+ const toolCallId = event.data.toolCallId;
190
+ const handler = this.toolHandlers.get(toolName);
191
+ if (handler) {
192
+ void this._executeToolAndRespond(requestId, toolName, toolCallId, args, handler);
193
+ }
194
+ } else if (event.type === "permission.requested") {
195
+ const { requestId, permissionRequest } = event.data;
196
+ if (this.permissionHandler) {
197
+ void this._executePermissionAndRespond(requestId, permissionRequest);
198
+ }
199
+ }
200
+ }
201
+ /**
202
+ * Executes a tool handler and sends the result back via RPC.
203
+ * @internal
204
+ */
205
+ async _executeToolAndRespond(requestId, toolName, toolCallId, args, handler) {
206
+ try {
207
+ const rawResult = await handler(args, {
208
+ sessionId: this.sessionId,
209
+ toolCallId,
210
+ toolName,
211
+ arguments: args
212
+ });
213
+ let result;
214
+ if (rawResult == null) {
215
+ result = "";
216
+ } else if (typeof rawResult === "string") {
217
+ result = rawResult;
218
+ } else {
219
+ result = JSON.stringify(rawResult);
220
+ }
221
+ await this.rpc.tools.handlePendingToolCall({ requestId, result });
222
+ } catch (error) {
223
+ const message = error instanceof Error ? error.message : String(error);
224
+ try {
225
+ await this.rpc.tools.handlePendingToolCall({ requestId, error: message });
226
+ } catch (rpcError) {
227
+ if (!(rpcError instanceof ConnectionError || rpcError instanceof ResponseError)) {
228
+ throw rpcError;
229
+ }
230
+ }
231
+ }
232
+ }
233
+ /**
234
+ * Executes a permission handler and sends the result back via RPC.
235
+ * @internal
236
+ */
237
+ async _executePermissionAndRespond(requestId, permissionRequest) {
238
+ try {
239
+ const result = await this.permissionHandler(permissionRequest, {
240
+ sessionId: this.sessionId
241
+ });
242
+ await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
243
+ } catch (_error) {
244
+ try {
245
+ await this.rpc.permissions.handlePendingPermissionRequest({
246
+ requestId,
247
+ result: {
248
+ kind: "denied-no-approval-rule-and-could-not-request-from-user"
249
+ }
250
+ });
251
+ } catch (rpcError) {
252
+ if (!(rpcError instanceof ConnectionError || rpcError instanceof ResponseError)) {
253
+ throw rpcError;
254
+ }
255
+ }
256
+ }
257
+ }
176
258
  /**
177
259
  * Registers custom tool handlers for this session.
178
260
  *
@@ -237,26 +319,6 @@ class CopilotSession {
237
319
  registerHooks(hooks) {
238
320
  this.hooks = hooks;
239
321
  }
240
- /**
241
- * Handles a permission request from the Copilot CLI.
242
- *
243
- * @param request - The permission request data from the CLI
244
- * @returns A promise that resolves with the permission decision
245
- * @internal This method is for internal use by the SDK.
246
- */
247
- async _handlePermissionRequest(request) {
248
- if (!this.permissionHandler) {
249
- return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
250
- }
251
- try {
252
- const result = await this.permissionHandler(request, {
253
- sessionId: this.sessionId
254
- });
255
- return result;
256
- } catch (_error) {
257
- return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
258
- }
259
- }
260
322
  /**
261
323
  * Handles a user input request from the Copilot CLI.
262
324
  *
@@ -315,7 +377,7 @@ class CopilotSession {
315
377
  * assistant responses, tool executions, and other session events.
316
378
  *
317
379
  * @returns A promise that resolves with an array of all session events
318
- * @throws Error if the session has been destroyed or the connection fails
380
+ * @throws Error if the session has been disconnected or the connection fails
319
381
  *
320
382
  * @example
321
383
  * ```typescript
@@ -334,22 +396,27 @@ class CopilotSession {
334
396
  return response.events;
335
397
  }
336
398
  /**
337
- * Destroys this session and releases all associated resources.
399
+ * Disconnects this session and releases all in-memory resources (event handlers,
400
+ * tool handlers, permission handlers).
401
+ *
402
+ * Session state on disk (conversation history, planning state, artifacts) is
403
+ * preserved, so the conversation can be resumed later by calling
404
+ * {@link CopilotClient.resumeSession} with the session ID. To permanently
405
+ * remove all session data including files on disk, use
406
+ * {@link CopilotClient.deleteSession} instead.
338
407
  *
339
- * After calling this method, the session can no longer be used. All event
340
- * handlers and tool handlers are cleared. To continue the conversation,
341
- * use {@link CopilotClient.resumeSession} with the session ID.
408
+ * After calling this method, the session object can no longer be used.
342
409
  *
343
- * @returns A promise that resolves when the session is destroyed
410
+ * @returns A promise that resolves when the session is disconnected
344
411
  * @throws Error if the connection fails
345
412
  *
346
413
  * @example
347
414
  * ```typescript
348
- * // Clean up when done
349
- * await session.destroy();
415
+ * // Clean up when done — session can still be resumed later
416
+ * await session.disconnect();
350
417
  * ```
351
418
  */
352
- async destroy() {
419
+ async disconnect() {
353
420
  await this.connection.sendRequest("session.destroy", {
354
421
  sessionId: this.sessionId
355
422
  });
@@ -358,6 +425,22 @@ class CopilotSession {
358
425
  this.toolHandlers.clear();
359
426
  this.permissionHandler = void 0;
360
427
  }
428
+ /**
429
+ * @deprecated Use {@link disconnect} instead. This method will be removed in a future release.
430
+ *
431
+ * Disconnects this session and releases all in-memory resources.
432
+ * Session data on disk is preserved for later resumption.
433
+ *
434
+ * @returns A promise that resolves when the session is disconnected
435
+ * @throws Error if the connection fails
436
+ */
437
+ async destroy() {
438
+ return this.disconnect();
439
+ }
440
+ /** Enables `await using session = ...` syntax for automatic cleanup. */
441
+ async [Symbol.asyncDispose]() {
442
+ return this.disconnect();
443
+ }
361
444
  /**
362
445
  * Aborts the currently processing message in this session.
363
446
  *
@@ -365,7 +448,7 @@ class CopilotSession {
365
448
  * and can continue to be used for new messages.
366
449
  *
367
450
  * @returns A promise that resolves when the abort request is acknowledged
368
- * @throws Error if the session has been destroyed or the connection fails
451
+ * @throws Error if the session has been disconnected or the connection fails
369
452
  *
370
453
  * @example
371
454
  * ```typescript
package/dist/types.d.ts CHANGED
@@ -32,6 +32,12 @@ export interface CopilotClientOptions {
32
32
  * @default true
33
33
  */
34
34
  useStdio?: boolean;
35
+ /**
36
+ * When true, indicates the SDK is running as a child process of the Copilot CLI server, and should
37
+ * use its own stdio for communicating with the existing parent process. Can only be used in combination
38
+ * with useStdio: true.
39
+ */
40
+ isChildProcess?: boolean;
35
41
  /**
36
42
  * URL of an existing Copilot CLI server to connect to over TCP
37
43
  * When provided, the client will not spawn a CLI process
@@ -179,10 +185,8 @@ export interface PermissionRequest {
179
185
  toolCallId?: string;
180
186
  [key: string]: unknown;
181
187
  }
182
- export interface PermissionRequestResult {
183
- kind: "approved" | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user";
184
- rules?: unknown[];
185
- }
188
+ import type { SessionPermissionsHandlePendingPermissionRequestParams } from "./generated/rpc.js";
189
+ export type PermissionRequestResult = SessionPermissionsHandlePendingPermissionRequestParams["result"];
186
190
  export type PermissionHandler = (request: PermissionRequest, invocation: {
187
191
  sessionId: string;
188
192
  }) => Promise<PermissionRequestResult> | PermissionRequestResult;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/github/copilot-sdk.git"
6
6
  },
7
- "version": "0.1.30",
7
+ "version": "0.1.31",
8
8
  "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -12,6 +12,10 @@
12
12
  ".": {
13
13
  "import": "./dist/index.js",
14
14
  "types": "./dist/index.d.ts"
15
+ },
16
+ "./extension": {
17
+ "import": "./dist/extension.js",
18
+ "types": "./dist/extension.d.ts"
15
19
  }
16
20
  },
17
21
  "type": "module",
@@ -40,7 +44,7 @@
40
44
  "author": "GitHub",
41
45
  "license": "MIT",
42
46
  "dependencies": {
43
- "@github/copilot": "^0.0.420",
47
+ "@github/copilot": "^1.0.2",
44
48
  "vscode-jsonrpc": "^8.2.1",
45
49
  "zod": "^4.3.6"
46
50
  },