@github/copilot-sdk 1.0.0-beta.4 → 1.0.0-beta.5

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.
@@ -397,8 +397,8 @@ class CopilotSession {
397
397
  /**
398
398
  * Registers custom tool handlers for this session.
399
399
  *
400
- * Tools allow the assistant to execute custom functions. When the assistant
401
- * invokes a tool, the corresponding handler is called with the tool arguments.
400
+ * Tools with handlers allow the assistant to execute custom functions automatically.
401
+ * Declaration-only tools are surfaced as events and left pending for the consumer.
402
402
  *
403
403
  * @param tools - An array of tool definitions with their handlers, or undefined to clear all tools
404
404
  * @internal This method is typically called internally when creating a session with tools.
@@ -409,7 +409,9 @@ class CopilotSession {
409
409
  return;
410
410
  }
411
411
  for (const tool of tools) {
412
- this.toolHandlers.set(tool.name, tool.handler);
412
+ if (tool.handler) {
413
+ this.toolHandlers.set(tool.name, tool.handler);
414
+ }
413
415
  }
414
416
  }
415
417
  /**
@@ -21,6 +21,18 @@ __export(sessionFsProvider_exports, {
21
21
  createSessionFsAdapter: () => createSessionFsAdapter
22
22
  });
23
23
  module.exports = __toCommonJS(sessionFsProvider_exports);
24
+ function normalizeSqliteParams(params) {
25
+ if (!params) {
26
+ return void 0;
27
+ }
28
+ const normalized = {};
29
+ for (const [key, value] of Object.entries(params)) {
30
+ if (value !== void 0) {
31
+ normalized[key] = value;
32
+ }
33
+ }
34
+ return normalized;
35
+ }
24
36
  function createSessionFsAdapter(provider) {
25
37
  return {
26
38
  readFile: async ({ path }) => {
@@ -107,6 +119,28 @@ function createSessionFsAdapter(provider) {
107
119
  } catch (err) {
108
120
  return toSessionFsError(err);
109
121
  }
122
+ },
123
+ // Unlike the FS methods above, SQLite methods let errors propagate to the JSON-RPC layer
124
+ // rather than catching and mapping via toSessionFsError. The FS error mapping is specifically
125
+ // for translating Node.js errno codes (e.g., ENOENT) into SessionFsError, which isn't
126
+ // meaningful for SQL errors. Letting exceptions propagate preserves the original error
127
+ // message in the JSON-RPC error response.
128
+ sqliteQuery: async ({ queryType, query, params: bindParams }) => {
129
+ if (!provider.sqlite) {
130
+ throw new Error("SQLite is not supported by this provider");
131
+ }
132
+ const result = await provider.sqlite.query(
133
+ queryType,
134
+ query,
135
+ normalizeSqliteParams(bindParams)
136
+ );
137
+ return result ?? { rows: [], columns: [], rowsAffected: 0 };
138
+ },
139
+ sqliteExists: async () => {
140
+ if (!provider.sqlite) {
141
+ throw new Error("SQLite is not supported by this provider");
142
+ }
143
+ return { exists: await provider.sqlite.exists() };
110
144
  }
111
145
  };
112
146
  }
package/dist/client.d.ts CHANGED
@@ -99,6 +99,7 @@ export declare class CopilotClient {
99
99
  */
100
100
  private parseCliUrl;
101
101
  private validateSessionFsConfig;
102
+ private setupSessionFs;
102
103
  /**
103
104
  * Starts the CLI server and establishes a connection.
104
105
  *
@@ -251,7 +252,7 @@ export declare class CopilotClient {
251
252
  */
252
253
  ping(message?: string): Promise<{
253
254
  message: string;
254
- timestamp: number;
255
+ timestamp: string;
255
256
  protocolVersion?: number;
256
257
  }>;
257
258
  /**
package/dist/client.js CHANGED
@@ -258,6 +258,23 @@ class CopilotClient {
258
258
  throw new Error("sessionFs.conventions must be either 'windows' or 'posix'");
259
259
  }
260
260
  }
261
+ setupSessionFs(session, config) {
262
+ if (!this.sessionFsConfig) {
263
+ return;
264
+ }
265
+ if (!config.createSessionFsHandler) {
266
+ throw new Error(
267
+ "createSessionFsHandler is required in session config when sessionFs is enabled in client options."
268
+ );
269
+ }
270
+ const provider = config.createSessionFsHandler(session);
271
+ if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) {
272
+ throw new Error(
273
+ "SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
274
+ );
275
+ }
276
+ session.clientSessionApis.sessionFs = createSessionFsAdapter(provider);
277
+ }
261
278
  /**
262
279
  * Starts the CLI server and establishes a connection.
263
280
  *
@@ -291,7 +308,8 @@ class CopilotClient {
291
308
  await this.connection.sendRequest("sessionFs.setProvider", {
292
309
  initialCwd: this.sessionFsConfig.initialCwd,
293
310
  sessionStatePath: this.sessionFsConfig.sessionStatePath,
294
- conventions: this.sessionFsConfig.conventions
311
+ conventions: this.sessionFsConfig.conventions,
312
+ capabilities: this.sessionFsConfig.capabilities
295
313
  });
296
314
  }
297
315
  this.state = "connected";
@@ -488,11 +506,6 @@ class CopilotClient {
488
506
  * ```
489
507
  */
490
508
  async createSession(config) {
491
- if (!config?.onPermissionRequest) {
492
- throw new Error(
493
- "An onPermissionRequest handler is required when creating a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }."
494
- );
495
- }
496
509
  if (!this.connection) {
497
510
  if (this.options.autoStart) {
498
511
  await this.start();
@@ -535,17 +548,7 @@ class CopilotClient {
535
548
  session.on(config.onEvent);
536
549
  }
537
550
  this.sessions.set(sessionId, session);
538
- if (this.sessionFsConfig) {
539
- if (config.createSessionFsHandler) {
540
- session.clientSessionApis.sessionFs = createSessionFsAdapter(
541
- config.createSessionFsHandler(session)
542
- );
543
- } else {
544
- throw new Error(
545
- "createSessionFsHandler is required in session config when sessionFs is enabled in client options."
546
- );
547
- }
548
- }
551
+ this.setupSessionFs(session, config);
549
552
  try {
550
553
  const response = await this.connection.sendRequest("session.create", {
551
554
  ...await getTraceContext(this.onGetTraceContext),
@@ -590,7 +593,9 @@ class CopilotClient {
590
593
  instructionDirectories: config.instructionDirectories,
591
594
  disabledSkills: config.disabledSkills,
592
595
  infiniteSessions: config.infiniteSessions,
593
- gitHubToken: config.gitHubToken
596
+ gitHubToken: config.gitHubToken,
597
+ remoteSession: config.remoteSession,
598
+ cloud: config.cloud
594
599
  });
595
600
  const { workspacePath, capabilities } = response;
596
601
  session["_workspacePath"] = workspacePath;
@@ -626,11 +631,6 @@ class CopilotClient {
626
631
  * ```
627
632
  */
628
633
  async resumeSession(sessionId, config) {
629
- if (!config?.onPermissionRequest) {
630
- throw new Error(
631
- "An onPermissionRequest handler is required when resuming a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }."
632
- );
633
- }
634
634
  if (!this.connection) {
635
635
  if (this.options.autoStart) {
636
636
  await this.start();
@@ -672,17 +672,7 @@ class CopilotClient {
672
672
  session.on(config.onEvent);
673
673
  }
674
674
  this.sessions.set(sessionId, session);
675
- if (this.sessionFsConfig) {
676
- if (config.createSessionFsHandler) {
677
- session.clientSessionApis.sessionFs = createSessionFsAdapter(
678
- config.createSessionFsHandler(session)
679
- );
680
- } else {
681
- throw new Error(
682
- "createSessionFsHandler is required in session config when sessionFs is enabled in client options."
683
- );
684
- }
685
- }
675
+ this.setupSessionFs(session, config);
686
676
  try {
687
677
  const response = await this.connection.sendRequest("session.resume", {
688
678
  ...await getTraceContext(this.onGetTraceContext),
@@ -729,7 +719,8 @@ class CopilotClient {
729
719
  infiniteSessions: config.infiniteSessions,
730
720
  disableResume: config.disableResume,
731
721
  continuePendingWork: config.continuePendingWork,
732
- gitHubToken: config.gitHubToken
722
+ gitHubToken: config.gitHubToken,
723
+ remoteSession: config.remoteSession
733
724
  });
734
725
  const { workspacePath, capabilities } = response;
735
726
  session["_workspacePath"] = workspacePath;
@@ -1300,7 +1291,12 @@ stderr: ${stderrOutput}`
1300
1291
  }
1301
1292
  return new Promise((resolve, reject) => {
1302
1293
  this.socket = new Socket();
1294
+ const connectionTimeout = setTimeout(() => {
1295
+ this.socket?.destroy();
1296
+ reject(new Error("Timeout connecting to CLI server"));
1297
+ }, 1e4);
1303
1298
  this.socket.connect(this.actualPort, this.actualHost, () => {
1299
+ clearTimeout(connectionTimeout);
1304
1300
  this.connection = createMessageConnection(
1305
1301
  new StreamMessageReader(this.socket),
1306
1302
  new StreamMessageWriter(this.socket)
@@ -1310,6 +1306,7 @@ stderr: ${stderrOutput}`
1310
1306
  resolve();
1311
1307
  });
1312
1308
  this.socket.on("error", (error) => {
1309
+ clearTimeout(connectionTimeout);
1313
1310
  reject(new Error(`Failed to connect to CLI server: ${error.message}`));
1314
1311
  });
1315
1312
  });