@github/copilot-sdk
Advanced tools
+193
-134
@@ -39,7 +39,2 @@ "use strict"; | ||
| const import_meta = {}; | ||
| function toWireProviderConfig(provider) { | ||
| const { maxInputTokens, ...rest } = provider; | ||
| if (maxInputTokens === void 0) return rest; | ||
| return { ...rest, maxPromptTokens: maxInputTokens }; | ||
| } | ||
| const MIN_PROTOCOL_VERSION = 2; | ||
@@ -56,2 +51,22 @@ function isZodSchema(value) { | ||
| } | ||
| function toWireMcpServers(mcpServers) { | ||
| if (!mcpServers) return void 0; | ||
| return Object.fromEntries( | ||
| Object.entries(mcpServers).map(([name, server]) => { | ||
| if ("workingDirectory" in server) { | ||
| const { workingDirectory, ...rest } = server; | ||
| return [name, { ...rest, cwd: workingDirectory }]; | ||
| } | ||
| return [name, server]; | ||
| }) | ||
| ); | ||
| } | ||
| function toWireCustomAgents(agents) { | ||
| if (!agents) return void 0; | ||
| return agents.map((agent) => { | ||
| if (!agent.mcpServers) return agent; | ||
| const { mcpServers, ...rest } = agent; | ||
| return { ...rest, mcpServers: toWireMcpServers(mcpServers) }; | ||
| }); | ||
| } | ||
| function extractTransformCallbacks(systemMessage) { | ||
@@ -110,3 +125,3 @@ if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) { | ||
| socket = null; | ||
| actualPort = null; | ||
| runtimePort = null; | ||
| actualHost = "localhost"; | ||
@@ -117,2 +132,8 @@ state = "disconnected"; | ||
| // Captures CLI stderr for error messages | ||
| /** Resolved connection mode chosen in the constructor. */ | ||
| connectionConfig; | ||
| /** Resolved path to the runtime executable (only used for child-process kinds). */ | ||
| resolvedCliPath; | ||
| /** Resolved environment passed to the spawned runtime. */ | ||
| resolvedEnv; | ||
| options; | ||
@@ -166,56 +187,54 @@ isExternalServer = false; | ||
| * @param options - Configuration options for the client | ||
| * @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Default options - spawns CLI server using stdio | ||
| * // Default: spawns the bundled runtime over stdio | ||
| * const client = new CopilotClient(); | ||
| * | ||
| * // Connect to an existing server | ||
| * const client = new CopilotClient({ cliUrl: "localhost:3000" }); | ||
| * // Connect to an existing runtime | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forUri("localhost:3000"), | ||
| * }); | ||
| * | ||
| * // Custom CLI path with specific log level | ||
| * // Spawn the runtime over TCP on a chosen port | ||
| * const client = new CopilotClient({ | ||
| * cliPath: "/usr/local/bin/copilot", | ||
| * logLevel: "debug" | ||
| * connection: RuntimeConnection.forTcp({ port: 9001 }), | ||
| * }); | ||
| * | ||
| * // Use a custom runtime binary | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }), | ||
| * logLevel: "debug", | ||
| * }); | ||
| * ``` | ||
| */ | ||
| constructor(options = {}) { | ||
| if (options.cliUrl && (options.useStdio === true || options.cliPath)) { | ||
| throw new Error("cliUrl is mutually exclusive with useStdio and cliPath"); | ||
| } | ||
| if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) { | ||
| const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" }; | ||
| if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) { | ||
| throw new Error( | ||
| "isChildProcess must be used in conjunction with useStdio and not with cliUrl" | ||
| "gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)" | ||
| ); | ||
| } | ||
| if (options.cliUrl && (options.gitHubToken || options.useLoggedInUser !== void 0)) { | ||
| throw new Error( | ||
| "gitHubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)" | ||
| ); | ||
| } | ||
| if (options.tcpConnectionToken !== void 0) { | ||
| if (typeof options.tcpConnectionToken !== "string" || options.tcpConnectionToken.length === 0) { | ||
| throw new Error("tcpConnectionToken must be a non-empty string"); | ||
| if (conn.kind === "tcp" && conn.connectionToken !== void 0) { | ||
| if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) { | ||
| throw new Error("connectionToken must be a non-empty string"); | ||
| } | ||
| if (options.useStdio === true) { | ||
| throw new Error("tcpConnectionToken cannot be used with useStdio: true"); | ||
| } | ||
| } | ||
| const willUseStdio = options.cliUrl ? false : options.useStdio ?? true; | ||
| const sdkSpawnsCli = !willUseStdio && !options.cliUrl && !options.isChildProcess; | ||
| this.effectiveConnectionToken = options.tcpConnectionToken ?? (sdkSpawnsCli ? (0, import_node_crypto.randomUUID)() : void 0); | ||
| this.connectionConfig = conn; | ||
| if (options.sessionFs) { | ||
| this.validateSessionFsConfig(options.sessionFs); | ||
| } | ||
| if (options.cliUrl) { | ||
| const { host, port } = this.parseCliUrl(options.cliUrl); | ||
| if (conn.kind === "uri") { | ||
| const { host, port } = this.parseCliUrl(conn.url); | ||
| this.actualHost = host; | ||
| this.actualPort = port; | ||
| this.runtimePort = port; | ||
| this.isExternalServer = true; | ||
| } | ||
| if (options.isChildProcess) { | ||
| } else if (conn.kind === "parent-process") { | ||
| this.isExternalServer = true; | ||
| } | ||
| if (conn.kind === "tcp") { | ||
| this.effectiveConnectionToken = conn.connectionToken ?? (0, import_node_crypto.randomUUID)(); | ||
| } else if (conn.kind === "uri") { | ||
| this.effectiveConnectionToken = conn.connectionToken; | ||
| } | ||
| this.onListModels = options.onListModels; | ||
@@ -225,24 +244,19 @@ this.onGetTraceContext = options.onGetTraceContext; | ||
| const effectiveEnv = options.env ?? process.env; | ||
| this.resolvedEnv = effectiveEnv; | ||
| this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0; | ||
| const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : []; | ||
| this.connectionExtraArgs = [...connArgs]; | ||
| this.options = { | ||
| cliPath: options.cliUrl ? void 0 : options.cliPath || effectiveEnv.COPILOT_CLI_PATH || getBundledCliPath(), | ||
| cliArgs: options.cliArgs ?? [], | ||
| cwd: options.cwd ?? process.cwd(), | ||
| port: options.port || 0, | ||
| useStdio: options.cliUrl ? false : options.useStdio ?? true, | ||
| // Default to stdio unless cliUrl is provided | ||
| isChildProcess: options.isChildProcess ?? false, | ||
| cliUrl: options.cliUrl, | ||
| logLevel: options.logLevel || "debug", | ||
| autoStart: options.autoStart ?? true, | ||
| autoRestart: false, | ||
| env: effectiveEnv, | ||
| workingDirectory: options.workingDirectory ?? process.cwd(), | ||
| logLevel: options.logLevel, | ||
| gitHubToken: options.gitHubToken, | ||
| // Default useLoggedInUser to false when gitHubToken is provided, otherwise true | ||
| // Default useLoggedInUser to false when gitHubToken is provided, otherwise true. | ||
| useLoggedInUser: options.useLoggedInUser ?? (options.gitHubToken ? false : true), | ||
| telemetry: options.telemetry, | ||
| copilotHome: options.copilotHome, | ||
| baseDirectory: options.baseDirectory, | ||
| sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0, | ||
| remote: options.remote ?? false | ||
| enableRemoteSessions: options.enableRemoteSessions ?? false | ||
| }; | ||
| } | ||
| connectionExtraArgs = []; | ||
| /** | ||
@@ -285,8 +299,8 @@ * Parse CLI URL into host and port | ||
| } | ||
| if (!config.createSessionFsHandler) { | ||
| if (!config.createSessionFsProvider) { | ||
| throw new Error( | ||
| "createSessionFsHandler is required in session config when sessionFs is enabled in client options." | ||
| "createSessionFsProvider is required in session config when sessionFs is enabled in client options." | ||
| ); | ||
| } | ||
| const provider = config.createSessionFsHandler(session); | ||
| const provider = config.createSessionFsProvider(session); | ||
| if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) { | ||
@@ -305,3 +319,3 @@ throw new Error( | ||
| * | ||
| * This method is called automatically when creating a session if `autoStart` is true (default). | ||
| * This method is called automatically the first time you create or resume a session. | ||
| * | ||
@@ -313,3 +327,3 @@ * @returns A promise that resolves when the connection is established | ||
| * ```typescript | ||
| * const client = new CopilotClient({ autoStart: false }); | ||
| * const client = new CopilotClient(); | ||
| * await client.start(); | ||
@@ -409,4 +423,11 @@ * // Now ready to create sessions | ||
| if (this.socket) { | ||
| const socket = this.socket; | ||
| this.socket = null; | ||
| try { | ||
| this.socket.end(); | ||
| if (!socket.destroyed) { | ||
| await new Promise((resolve) => { | ||
| socket.once("close", () => resolve()); | ||
| socket.end(); | ||
| }); | ||
| } | ||
| } catch (error) { | ||
@@ -419,7 +440,14 @@ errors.push( | ||
| } | ||
| this.socket = null; | ||
| } | ||
| if (this.cliProcess && !this.isExternalServer) { | ||
| const child = this.cliProcess; | ||
| this.cliProcess = null; | ||
| try { | ||
| this.cliProcess.kill(); | ||
| if (child.exitCode === null && child.signalCode === null) { | ||
| const exited = new Promise((resolve) => { | ||
| child.once("exit", () => resolve()); | ||
| }); | ||
| child.kill(); | ||
| await exited; | ||
| } | ||
| } catch (error) { | ||
@@ -432,3 +460,2 @@ errors.push( | ||
| } | ||
| this.cliProcess = null; | ||
| } | ||
@@ -440,3 +467,3 @@ if (this.cliStartTimeout) { | ||
| this.state = "disconnected"; | ||
| this.actualPort = null; | ||
| this.runtimePort = null; | ||
| this.stderrBuffer = ""; | ||
@@ -447,2 +474,17 @@ this.processExitPromise = null; | ||
| /** | ||
| * Alias for {@link stop} that lets `CopilotClient` participate in `await using` | ||
| * blocks for automatic cleanup. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await using client = new CopilotClient(); | ||
| * const session = await client.createSession({ onPermissionRequest: approveAll }); | ||
| * await session.sendAndWait("Hello"); | ||
| * // client.stop() is called automatically when the block exits. | ||
| * ``` | ||
| */ | ||
| async [Symbol.asyncDispose]() { | ||
| await this.stop(); | ||
| } | ||
| /** | ||
| * Forcefully stops the CLI server without graceful cleanup. | ||
@@ -503,3 +545,3 @@ * | ||
| this.state = "disconnected"; | ||
| this.actualPort = null; | ||
| this.runtimePort = null; | ||
| this.stderrBuffer = ""; | ||
@@ -512,8 +554,7 @@ this.processExitPromise = null; | ||
| * Sessions maintain conversation state, handle events, and manage tool execution. | ||
| * If the client is not connected and `autoStart` is enabled, this will automatically | ||
| * start the connection. | ||
| * If the client is not connected, this method automatically starts the connection. | ||
| * | ||
| * @param config - Optional configuration for the session | ||
| * @returns A promise that resolves with the created session | ||
| * @throws Error if the client is not connected and autoStart is disabled | ||
| * @throws Error if the client fails to start | ||
| * | ||
@@ -540,7 +581,3 @@ * @example | ||
| if (!this.connection) { | ||
| if (this.options.autoStart) { | ||
| await this.start(); | ||
| } else { | ||
| throw new Error("Client not connected. Call start() first."); | ||
| } | ||
| await this.start(); | ||
| } | ||
@@ -563,7 +600,7 @@ const sessionId = config.sessionId ?? (0, import_node_crypto.randomUUID)(); | ||
| } | ||
| if (config.onExitPlanMode) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanMode); | ||
| if (config.onExitPlanModeRequest) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanModeRequest); | ||
| } | ||
| if (config.onAutoModeSwitch) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitch); | ||
| if (config.onAutoModeSwitchRequest) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest); | ||
| } | ||
@@ -605,3 +642,3 @@ if (config.hooks) { | ||
| excludedTools: config.excludedTools, | ||
| provider: config.provider ? toWireProviderConfig(config.provider) : void 0, | ||
| provider: config.provider, | ||
| enableSessionTelemetry: config.enableSessionTelemetry, | ||
@@ -612,4 +649,4 @@ modelCapabilities: config.modelCapabilities, | ||
| requestElicitation: !!config.onElicitationRequest, | ||
| requestExitPlanMode: !!config.onExitPlanMode, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitch, | ||
| requestExitPlanMode: !!config.onExitPlanModeRequest, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitchRequest, | ||
| hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)), | ||
@@ -619,5 +656,5 @@ workingDirectory: config.workingDirectory, | ||
| includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true, | ||
| mcpServers: config.mcpServers, | ||
| mcpServers: toWireMcpServers(config.mcpServers), | ||
| envValueMode: "direct", | ||
| customAgents: config.customAgents, | ||
| customAgents: toWireCustomAgents(config.customAgents), | ||
| defaultAgent: config.defaultAgent, | ||
@@ -670,7 +707,3 @@ agent: config.agent, | ||
| if (!this.connection) { | ||
| if (this.options.autoStart) { | ||
| await this.start(); | ||
| } else { | ||
| throw new Error("Client not connected. Call start() first."); | ||
| } | ||
| await this.start(); | ||
| } | ||
@@ -692,7 +725,7 @@ const session = new import_session.CopilotSession( | ||
| } | ||
| if (config.onExitPlanMode) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanMode); | ||
| if (config.onExitPlanModeRequest) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanModeRequest); | ||
| } | ||
| if (config.onAutoModeSwitch) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitch); | ||
| if (config.onAutoModeSwitchRequest) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest); | ||
| } | ||
@@ -735,3 +768,3 @@ if (config.hooks) { | ||
| })), | ||
| provider: config.provider ? toWireProviderConfig(config.provider) : void 0, | ||
| provider: config.provider, | ||
| modelCapabilities: config.modelCapabilities, | ||
@@ -741,4 +774,4 @@ requestPermission: config.onPermissionRequest !== import_types.defaultJoinSessionPermissionHandler, | ||
| requestElicitation: !!config.onElicitationRequest, | ||
| requestExitPlanMode: !!config.onExitPlanMode, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitch, | ||
| requestExitPlanMode: !!config.onExitPlanModeRequest, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitchRequest, | ||
| hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)), | ||
@@ -750,5 +783,5 @@ workingDirectory: config.workingDirectory, | ||
| includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true, | ||
| mcpServers: config.mcpServers, | ||
| mcpServers: toWireMcpServers(config.mcpServers), | ||
| envValueMode: "direct", | ||
| customAgents: config.customAgents, | ||
| customAgents: toWireCustomAgents(config.customAgents), | ||
| defaultAgent: config.defaultAgent, | ||
@@ -760,3 +793,3 @@ agent: config.agent, | ||
| infiniteSessions: config.infiniteSessions, | ||
| disableResume: config.disableResume, | ||
| suppressResumeEvent: config.suppressResumeEvent, | ||
| continuePendingWork: config.continuePendingWork, | ||
@@ -991,4 +1024,9 @@ gitHubToken: config.gitHubToken, | ||
| } | ||
| let wireFilter; | ||
| if (filter) { | ||
| const { workingDirectory, ...rest } = filter; | ||
| wireFilter = { ...rest, cwd: workingDirectory }; | ||
| } | ||
| const response = await this.connection.sendRequest("session.list", { | ||
| filter | ||
| filter: wireFilter | ||
| }); | ||
@@ -1028,2 +1066,3 @@ const { sessions } = response; | ||
| static toSessionMetadata(raw) { | ||
| const { context } = raw; | ||
| return { | ||
@@ -1035,3 +1074,8 @@ sessionId: raw.sessionId, | ||
| isRemote: raw.isRemote, | ||
| context: raw.context | ||
| context: context ? { | ||
| workingDirectory: context.cwd, | ||
| gitRoot: context.gitRoot, | ||
| repository: context.repository, | ||
| branch: context.branch | ||
| } : void 0 | ||
| }; | ||
@@ -1089,3 +1133,3 @@ } | ||
| } | ||
| on(eventTypeOrHandler, handler) { | ||
| onLifecycle(eventTypeOrHandler, handler) { | ||
| if (typeof eventTypeOrHandler === "string" && handler) { | ||
@@ -1117,13 +1161,13 @@ const eventType = eventTypeOrHandler; | ||
| this.stderrBuffer = ""; | ||
| const args = [ | ||
| ...this.options.cliArgs, | ||
| "--headless", | ||
| "--no-auto-update", | ||
| "--log-level", | ||
| this.options.logLevel | ||
| ]; | ||
| if (this.options.useStdio) { | ||
| const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"]; | ||
| if (this.options.logLevel) { | ||
| args.push("--log-level", this.options.logLevel); | ||
| } | ||
| if (this.connectionConfig.kind === "stdio") { | ||
| args.push("--stdio"); | ||
| } else if (this.options.port > 0) { | ||
| args.push("--port", this.options.port.toString()); | ||
| } else if (this.connectionConfig.kind === "tcp") { | ||
| const requestedPort = this.connectionConfig.port ?? 0; | ||
| if (requestedPort > 0) { | ||
| args.push("--port", requestedPort.toString()); | ||
| } | ||
| } | ||
@@ -1142,6 +1186,6 @@ if (this.options.gitHubToken) { | ||
| } | ||
| if (this.options.remote) { | ||
| if (this.options.enableRemoteSessions) { | ||
| args.push("--remote"); | ||
| } | ||
| const envWithoutNodeDebug = { ...this.options.env }; | ||
| const envWithoutNodeDebug = { ...this.resolvedEnv }; | ||
| delete envWithoutNodeDebug.NODE_DEBUG; | ||
@@ -1154,8 +1198,8 @@ if (this.options.gitHubToken) { | ||
| } | ||
| if (this.options.copilotHome) { | ||
| envWithoutNodeDebug.COPILOT_HOME = this.options.copilotHome; | ||
| if (this.options.baseDirectory) { | ||
| envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory; | ||
| } | ||
| if (!this.options.cliPath) { | ||
| if (!this.resolvedCliPath) { | ||
| throw new Error( | ||
| "Path to Copilot CLI is required. Please provide it via the cliPath option, or use cliUrl to rely on a remote CLI." | ||
| "Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime." | ||
| ); | ||
@@ -1179,13 +1223,13 @@ } | ||
| } | ||
| if (!(0, import_node_fs.existsSync)(this.options.cliPath)) { | ||
| if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) { | ||
| throw new Error( | ||
| `Copilot CLI not found at ${this.options.cliPath}. Ensure @github/copilot is installed.` | ||
| `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.` | ||
| ); | ||
| } | ||
| const stdioConfig = this.options.useStdio ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"]; | ||
| const isJsFile = this.options.cliPath.endsWith(".js"); | ||
| const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"]; | ||
| const isJsFile = this.resolvedCliPath.endsWith(".js"); | ||
| if (isJsFile) { | ||
| this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.options.cliPath, ...args], { | ||
| this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.resolvedCliPath, ...args], { | ||
| stdio: stdioConfig, | ||
| cwd: this.options.cwd, | ||
| cwd: this.options.workingDirectory, | ||
| env: envWithoutNodeDebug, | ||
@@ -1195,5 +1239,5 @@ windowsHide: true | ||
| } else { | ||
| this.cliProcess = (0, import_node_child_process.spawn)(this.options.cliPath, args, { | ||
| this.cliProcess = (0, import_node_child_process.spawn)(this.resolvedCliPath, args, { | ||
| stdio: stdioConfig, | ||
| cwd: this.options.cwd, | ||
| cwd: this.options.workingDirectory, | ||
| env: envWithoutNodeDebug, | ||
@@ -1205,3 +1249,3 @@ windowsHide: true | ||
| let resolved = false; | ||
| if (this.options.useStdio) { | ||
| if (this.connectionConfig.kind === "stdio") { | ||
| resolved = true; | ||
@@ -1214,3 +1258,3 @@ resolve(); | ||
| if (match && !resolved) { | ||
| this.actualPort = parseInt(match[1], 10); | ||
| this.runtimePort = parseInt(match[1], 10); | ||
| resolved = true; | ||
@@ -1289,3 +1333,3 @@ resolve(); | ||
| } | ||
| }, 1e4); | ||
| }, 3e4); | ||
| }); | ||
@@ -1297,8 +1341,10 @@ } | ||
| async connectToServer() { | ||
| if (this.options.isChildProcess) { | ||
| return this.connectToParentProcessViaStdio(); | ||
| } else if (this.options.useStdio) { | ||
| return this.connectToChildProcessViaStdio(); | ||
| } else { | ||
| return this.connectViaTcp(); | ||
| switch (this.connectionConfig.kind) { | ||
| case "parent-process": | ||
| return this.connectToParentProcessViaStdio(); | ||
| case "stdio": | ||
| return this.connectToChildProcessViaStdio(); | ||
| case "tcp": | ||
| case "uri": | ||
| return this.connectViaTcp(); | ||
| } | ||
@@ -1343,3 +1389,3 @@ } | ||
| async connectViaTcp() { | ||
| if (!this.actualPort) { | ||
| if (!this.runtimePort) { | ||
| throw new Error("Server port not available"); | ||
@@ -1353,3 +1399,3 @@ } | ||
| }, 1e4); | ||
| this.socket.connect(this.actualPort, this.actualHost, () => { | ||
| this.socket.connect(this.runtimePort, this.actualHost, () => { | ||
| clearTimeout(connectionTimeout); | ||
@@ -1434,3 +1480,16 @@ this.connection = (0, import_node.createMessageConnection)( | ||
| } | ||
| const event = notification; | ||
| const raw = notification; | ||
| let metadata; | ||
| if (raw.metadata && raw.metadata.startTime && raw.metadata.modifiedTime) { | ||
| metadata = { | ||
| startTime: new Date(raw.metadata.startTime), | ||
| modifiedTime: new Date(raw.metadata.modifiedTime), | ||
| summary: raw.metadata.summary | ||
| }; | ||
| } | ||
| const event = { | ||
| type: raw.type, | ||
| sessionId: raw.sessionId, | ||
| metadata | ||
| }; | ||
| const typedHandlers = this.typedLifecycleHandlers.get(event.type); | ||
@@ -1437,0 +1496,0 @@ if (typedHandlers) { |
@@ -33,7 +33,7 @@ "use strict"; | ||
| } | ||
| const client = new import_client.CopilotClient({ isChildProcess: true }); | ||
| const client = new import_client.CopilotClient({ _internalConnection: { kind: "parent-process" } }); | ||
| return client.resumeSession(sessionId, { | ||
| ...config, | ||
| onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler, | ||
| disableResume: config.disableResume ?? true | ||
| suppressResumeEvent: config.suppressResumeEvent ?? true | ||
| }); | ||
@@ -40,0 +40,0 @@ } |
@@ -23,12 +23,14 @@ "use strict"; | ||
| CopilotSession: () => import_session.CopilotSession, | ||
| SYSTEM_PROMPT_SECTIONS: () => import_types.SYSTEM_PROMPT_SECTIONS, | ||
| approveAll: () => import_types.approveAll, | ||
| convertMcpCallToolResult: () => import_types.convertMcpCallToolResult, | ||
| createSessionFsAdapter: () => import_types.createSessionFsAdapter, | ||
| defineTool: () => import_types.defineTool | ||
| RuntimeConnection: () => import_types.RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS: () => import_types2.SYSTEM_PROMPT_SECTIONS, | ||
| approveAll: () => import_types2.approveAll, | ||
| convertMcpCallToolResult: () => import_types2.convertMcpCallToolResult, | ||
| createSessionFsAdapter: () => import_types2.createSessionFsAdapter, | ||
| defineTool: () => import_types2.defineTool | ||
| }); | ||
| module.exports = __toCommonJS(index_exports); | ||
| var import_client = require("./client.js"); | ||
| var import_types = require("./types.js"); | ||
| var import_session = require("./session.js"); | ||
| var import_types = require("./types.js"); | ||
| var import_types2 = require("./types.js"); | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
@@ -38,2 +40,3 @@ 0 && (module.exports = { | ||
| CopilotSession, | ||
| RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS, | ||
@@ -40,0 +43,0 @@ approveAll, |
+17
-58
@@ -29,2 +29,10 @@ "use strict"; | ||
| const NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server."; | ||
| function deserializeHookInput(raw) { | ||
| if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") { | ||
| return raw; | ||
| } | ||
| const obj = raw; | ||
| const { cwd, ...rest } = obj; | ||
| return { ...rest, timestamp: new Date(obj.timestamp), workingDirectory: cwd }; | ||
| } | ||
| class CopilotSession { | ||
@@ -106,21 +114,4 @@ /** | ||
| } | ||
| /** | ||
| * Sends a message to this session and waits for the response. | ||
| * | ||
| * The message is processed asynchronously. Subscribe to events via {@link on} | ||
| * to receive streaming responses and other session events. | ||
| * | ||
| * @param options - The message options including the prompt and optional attachments | ||
| * @returns A promise that resolves with the message ID of the response | ||
| * @throws Error if the session has been disconnected or the connection fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const messageId = await session.send({ | ||
| * prompt: "Explain this code", | ||
| * attachments: [{ type: "file", path: "./src/index.ts" }] | ||
| * }); | ||
| * ``` | ||
| */ | ||
| async send(options) { | ||
| async send(optionsOrPrompt) { | ||
| const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt; | ||
| const response = await this.connection.sendRequest("session.send", { | ||
@@ -136,26 +127,4 @@ ...await (0, import_telemetry.getTraceContext)(this.traceContextProvider), | ||
| } | ||
| /** | ||
| * Sends a message to this session and waits until the session becomes idle. | ||
| * | ||
| * This is a convenience method that combines {@link send} with waiting for | ||
| * the `session.idle` event. Use this when you want to block until the | ||
| * assistant has finished processing the message. | ||
| * | ||
| * Events are still delivered to handlers registered via {@link on} while waiting. | ||
| * | ||
| * @param options - The message options including the prompt and optional attachments | ||
| * @param timeout - Timeout in milliseconds (default: 60000). Controls how long to wait; does not abort in-flight agent work. | ||
| * @returns A promise that resolves with the final assistant message when the session becomes idle, | ||
| * or undefined if no assistant message was received | ||
| * @throws Error if the timeout is reached before the session becomes idle | ||
| * @throws Error if the session has been disconnected or the connection fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Send and wait for completion with default 60s timeout | ||
| * const response = await session.sendAndWait({ prompt: "What is 2+2?" }); | ||
| * console.log(response?.data.content); // "4" | ||
| * ``` | ||
| */ | ||
| async sendAndWait(options, timeout) { | ||
| async sendAndWait(optionsOrPrompt, timeout) { | ||
| const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt; | ||
| const effectiveTimeout = timeout ?? 6e4; | ||
@@ -724,4 +693,6 @@ let resolveIdle; | ||
| } | ||
| const normalized = deserializeHookInput(input); | ||
| const handlerMap = { | ||
| preToolUse: this.hooks.onPreToolUse, | ||
| preMcpToolCall: this.hooks.onPreMcpToolCall, | ||
| postToolUse: this.hooks.onPostToolUse, | ||
@@ -738,3 +709,3 @@ userPromptSubmitted: this.hooks.onUserPromptSubmitted, | ||
| try { | ||
| const result = await handler(input, { sessionId: this.sessionId }); | ||
| const result = await handler(normalized, { sessionId: this.sessionId }); | ||
| return result; | ||
@@ -756,3 +727,3 @@ } catch (_error) { | ||
| * ```typescript | ||
| * const events = await session.getMessages(); | ||
| * const events = await session.getEvents(); | ||
| * for (const event of events) { | ||
@@ -765,3 +736,3 @@ * if (event.type === "assistant.message") { | ||
| */ | ||
| async getMessages() { | ||
| async getEvents() { | ||
| const response = await this.connection.sendRequest("session.getMessages", { | ||
@@ -806,14 +777,2 @@ sessionId: this.sessionId | ||
| } | ||
| /** | ||
| * @deprecated Use {@link disconnect} instead. This method will be removed in a future release. | ||
| * | ||
| * Disconnects this session and releases all in-memory resources. | ||
| * Session data on disk is preserved for later resumption. | ||
| * | ||
| * @returns A promise that resolves when the session is disconnected | ||
| * @throws Error if the connection fails | ||
| */ | ||
| async destroy() { | ||
| return this.disconnect(); | ||
| } | ||
| /** Enables `await using session = ...` syntax for automatic cleanup. */ | ||
@@ -820,0 +779,0 @@ async [Symbol.asyncDispose]() { |
+30
-0
@@ -21,2 +21,3 @@ "use strict"; | ||
| __export(types_exports, { | ||
| RuntimeConnection: () => RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS: () => SYSTEM_PROMPT_SECTIONS, | ||
@@ -31,2 +32,30 @@ approveAll: () => approveAll, | ||
| var import_sessionFsProvider = require("./sessionFsProvider.js"); | ||
| const RuntimeConnection = { | ||
| /** | ||
| * Spawn a runtime child process and communicate over its stdin/stdout. | ||
| * This is the default if no {@link CopilotClientOptions.connection} is set. | ||
| */ | ||
| forStdio(opts = {}) { | ||
| return { kind: "stdio", path: opts.path, args: opts.args }; | ||
| }, | ||
| /** | ||
| * Spawn a runtime child process that listens on a TCP socket and connect to it. | ||
| */ | ||
| forTcp(opts = {}) { | ||
| return { | ||
| kind: "tcp", | ||
| port: opts.port, | ||
| connectionToken: opts.connectionToken, | ||
| path: opts.path, | ||
| args: opts.args | ||
| }; | ||
| }, | ||
| /** | ||
| * Connect to an already-running runtime at the given URL. The SDK does not | ||
| * spawn a process in this mode. | ||
| */ | ||
| forUri(url, opts = {}) { | ||
| return { kind: "uri", url, connectionToken: opts.connectionToken }; | ||
| } | ||
| }; | ||
| function convertMcpCallToolResult(callResult) { | ||
@@ -97,2 +126,3 @@ const textParts = []; | ||
| 0 && (module.exports = { | ||
| RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS, | ||
@@ -99,0 +129,0 @@ approveAll, |
+43
-23
@@ -19,3 +19,3 @@ import { createServerRpc } from "./generated/rpc.js"; | ||
| * // Or connect to an existing server | ||
| * const client = new CopilotClient({ cliUrl: "localhost:3000" }); | ||
| * const client = new CopilotClient({ connection: RuntimeConnection.forUri("localhost:3000") }); | ||
| * | ||
@@ -43,3 +43,3 @@ * // Create a session | ||
| private socket; | ||
| private actualPort; | ||
| private runtimePort; | ||
| private actualHost; | ||
@@ -49,2 +49,8 @@ private state; | ||
| private stderrBuffer; | ||
| /** Resolved connection mode chosen in the constructor. */ | ||
| private connectionConfig; | ||
| /** Resolved path to the runtime executable (only used for child-process kinds). */ | ||
| private resolvedCliPath; | ||
| /** Resolved environment passed to the spawned runtime. */ | ||
| private resolvedEnv; | ||
| private options; | ||
@@ -73,28 +79,30 @@ private isExternalServer; | ||
| /** | ||
| * Internal RPC surface (e.g. handshake helpers). Not part of the public API. | ||
| * @internal | ||
| */ | ||
| private get internalRpc(); | ||
| /** | ||
| * Creates a new CopilotClient instance. | ||
| * | ||
| * @param options - Configuration options for the client | ||
| * @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Default options - spawns CLI server using stdio | ||
| * // Default: spawns the bundled runtime over stdio | ||
| * const client = new CopilotClient(); | ||
| * | ||
| * // Connect to an existing server | ||
| * const client = new CopilotClient({ cliUrl: "localhost:3000" }); | ||
| * // Connect to an existing runtime | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forUri("localhost:3000"), | ||
| * }); | ||
| * | ||
| * // Custom CLI path with specific log level | ||
| * // Spawn the runtime over TCP on a chosen port | ||
| * const client = new CopilotClient({ | ||
| * cliPath: "/usr/local/bin/copilot", | ||
| * logLevel: "debug" | ||
| * connection: RuntimeConnection.forTcp({ port: 9001 }), | ||
| * }); | ||
| * | ||
| * // Use a custom runtime binary | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }), | ||
| * logLevel: "debug", | ||
| * }); | ||
| * ``` | ||
| */ | ||
| constructor(options?: CopilotClientOptions); | ||
| private connectionExtraArgs; | ||
| /** | ||
@@ -113,3 +121,3 @@ * Parse CLI URL into host and port | ||
| * | ||
| * This method is called automatically when creating a session if `autoStart` is true (default). | ||
| * This method is called automatically the first time you create or resume a session. | ||
| * | ||
@@ -121,3 +129,3 @@ * @returns A promise that resolves when the connection is established | ||
| * ```typescript | ||
| * const client = new CopilotClient({ autoStart: false }); | ||
| * const client = new CopilotClient(); | ||
| * await client.start(); | ||
@@ -153,2 +161,15 @@ * // Now ready to create sessions | ||
| /** | ||
| * Alias for {@link stop} that lets `CopilotClient` participate in `await using` | ||
| * blocks for automatic cleanup. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await using client = new CopilotClient(); | ||
| * const session = await client.createSession({ onPermissionRequest: approveAll }); | ||
| * await session.sendAndWait("Hello"); | ||
| * // client.stop() is called automatically when the block exits. | ||
| * ``` | ||
| */ | ||
| [Symbol.asyncDispose](): Promise<void>; | ||
| /** | ||
| * Forcefully stops the CLI server without graceful cleanup. | ||
@@ -183,8 +204,7 @@ * | ||
| * Sessions maintain conversation state, handle events, and manage tool execution. | ||
| * If the client is not connected and `autoStart` is enabled, this will automatically | ||
| * start the connection. | ||
| * If the client is not connected, this method automatically starts the connection. | ||
| * | ||
| * @param config - Optional configuration for the session | ||
| * @returns A promise that resolves with the created session | ||
| * @throws Error if the client is not connected and autoStart is disabled | ||
| * @throws Error if the client fails to start | ||
| * | ||
@@ -410,3 +430,3 @@ * @example | ||
| * // Listen for when a session becomes foreground in TUI | ||
| * const unsubscribe = client.on("session.foreground", (event) => { | ||
| * const unsubscribe = client.onLifecycle("session.foreground", (event) => { | ||
| * console.log(`Session ${event.sessionId} is now displayed in TUI`); | ||
@@ -419,3 +439,3 @@ * }); | ||
| */ | ||
| on<K extends SessionLifecycleEventType>(eventType: K, handler: TypedSessionLifecycleHandler<K>): () => void; | ||
| onLifecycle<K extends SessionLifecycleEventType>(eventType: K, handler: TypedSessionLifecycleHandler<K>): () => void; | ||
| /** | ||
@@ -429,3 +449,3 @@ * Subscribes to all session lifecycle events. | ||
| * ```typescript | ||
| * const unsubscribe = client.on((event) => { | ||
| * const unsubscribe = client.onLifecycle((event) => { | ||
| * switch (event.type) { | ||
@@ -445,3 +465,3 @@ * case "session.foreground": | ||
| */ | ||
| on(handler: SessionLifecycleHandler): () => void; | ||
| onLifecycle(handler: SessionLifecycleHandler): () => void; | ||
| /** | ||
@@ -448,0 +468,0 @@ * Start the CLI server process |
+193
-134
@@ -25,7 +25,2 @@ import { spawn } from "node:child_process"; | ||
| import { defaultJoinSessionPermissionHandler } from "./types.js"; | ||
| function toWireProviderConfig(provider) { | ||
| const { maxInputTokens, ...rest } = provider; | ||
| if (maxInputTokens === void 0) return rest; | ||
| return { ...rest, maxPromptTokens: maxInputTokens }; | ||
| } | ||
| const MIN_PROTOCOL_VERSION = 2; | ||
@@ -42,2 +37,22 @@ function isZodSchema(value) { | ||
| } | ||
| function toWireMcpServers(mcpServers) { | ||
| if (!mcpServers) return void 0; | ||
| return Object.fromEntries( | ||
| Object.entries(mcpServers).map(([name, server]) => { | ||
| if ("workingDirectory" in server) { | ||
| const { workingDirectory, ...rest } = server; | ||
| return [name, { ...rest, cwd: workingDirectory }]; | ||
| } | ||
| return [name, server]; | ||
| }) | ||
| ); | ||
| } | ||
| function toWireCustomAgents(agents) { | ||
| if (!agents) return void 0; | ||
| return agents.map((agent) => { | ||
| if (!agent.mcpServers) return agent; | ||
| const { mcpServers, ...rest } = agent; | ||
| return { ...rest, mcpServers: toWireMcpServers(mcpServers) }; | ||
| }); | ||
| } | ||
| function extractTransformCallbacks(systemMessage) { | ||
@@ -96,3 +111,3 @@ if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) { | ||
| socket = null; | ||
| actualPort = null; | ||
| runtimePort = null; | ||
| actualHost = "localhost"; | ||
@@ -103,2 +118,8 @@ state = "disconnected"; | ||
| // Captures CLI stderr for error messages | ||
| /** Resolved connection mode chosen in the constructor. */ | ||
| connectionConfig; | ||
| /** Resolved path to the runtime executable (only used for child-process kinds). */ | ||
| resolvedCliPath; | ||
| /** Resolved environment passed to the spawned runtime. */ | ||
| resolvedEnv; | ||
| options; | ||
@@ -152,56 +173,54 @@ isExternalServer = false; | ||
| * @param options - Configuration options for the client | ||
| * @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Default options - spawns CLI server using stdio | ||
| * // Default: spawns the bundled runtime over stdio | ||
| * const client = new CopilotClient(); | ||
| * | ||
| * // Connect to an existing server | ||
| * const client = new CopilotClient({ cliUrl: "localhost:3000" }); | ||
| * // Connect to an existing runtime | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forUri("localhost:3000"), | ||
| * }); | ||
| * | ||
| * // Custom CLI path with specific log level | ||
| * // Spawn the runtime over TCP on a chosen port | ||
| * const client = new CopilotClient({ | ||
| * cliPath: "/usr/local/bin/copilot", | ||
| * logLevel: "debug" | ||
| * connection: RuntimeConnection.forTcp({ port: 9001 }), | ||
| * }); | ||
| * | ||
| * // Use a custom runtime binary | ||
| * const client = new CopilotClient({ | ||
| * connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }), | ||
| * logLevel: "debug", | ||
| * }); | ||
| * ``` | ||
| */ | ||
| constructor(options = {}) { | ||
| if (options.cliUrl && (options.useStdio === true || options.cliPath)) { | ||
| throw new Error("cliUrl is mutually exclusive with useStdio and cliPath"); | ||
| } | ||
| if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) { | ||
| const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" }; | ||
| if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) { | ||
| throw new Error( | ||
| "isChildProcess must be used in conjunction with useStdio and not with cliUrl" | ||
| "gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)" | ||
| ); | ||
| } | ||
| if (options.cliUrl && (options.gitHubToken || options.useLoggedInUser !== void 0)) { | ||
| throw new Error( | ||
| "gitHubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)" | ||
| ); | ||
| } | ||
| if (options.tcpConnectionToken !== void 0) { | ||
| if (typeof options.tcpConnectionToken !== "string" || options.tcpConnectionToken.length === 0) { | ||
| throw new Error("tcpConnectionToken must be a non-empty string"); | ||
| if (conn.kind === "tcp" && conn.connectionToken !== void 0) { | ||
| if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) { | ||
| throw new Error("connectionToken must be a non-empty string"); | ||
| } | ||
| if (options.useStdio === true) { | ||
| throw new Error("tcpConnectionToken cannot be used with useStdio: true"); | ||
| } | ||
| } | ||
| const willUseStdio = options.cliUrl ? false : options.useStdio ?? true; | ||
| const sdkSpawnsCli = !willUseStdio && !options.cliUrl && !options.isChildProcess; | ||
| this.effectiveConnectionToken = options.tcpConnectionToken ?? (sdkSpawnsCli ? randomUUID() : void 0); | ||
| this.connectionConfig = conn; | ||
| if (options.sessionFs) { | ||
| this.validateSessionFsConfig(options.sessionFs); | ||
| } | ||
| if (options.cliUrl) { | ||
| const { host, port } = this.parseCliUrl(options.cliUrl); | ||
| if (conn.kind === "uri") { | ||
| const { host, port } = this.parseCliUrl(conn.url); | ||
| this.actualHost = host; | ||
| this.actualPort = port; | ||
| this.runtimePort = port; | ||
| this.isExternalServer = true; | ||
| } | ||
| if (options.isChildProcess) { | ||
| } else if (conn.kind === "parent-process") { | ||
| this.isExternalServer = true; | ||
| } | ||
| if (conn.kind === "tcp") { | ||
| this.effectiveConnectionToken = conn.connectionToken ?? randomUUID(); | ||
| } else if (conn.kind === "uri") { | ||
| this.effectiveConnectionToken = conn.connectionToken; | ||
| } | ||
| this.onListModels = options.onListModels; | ||
@@ -211,24 +230,19 @@ this.onGetTraceContext = options.onGetTraceContext; | ||
| const effectiveEnv = options.env ?? process.env; | ||
| this.resolvedEnv = effectiveEnv; | ||
| this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0; | ||
| const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : []; | ||
| this.connectionExtraArgs = [...connArgs]; | ||
| this.options = { | ||
| cliPath: options.cliUrl ? void 0 : options.cliPath || effectiveEnv.COPILOT_CLI_PATH || getBundledCliPath(), | ||
| cliArgs: options.cliArgs ?? [], | ||
| cwd: options.cwd ?? process.cwd(), | ||
| port: options.port || 0, | ||
| useStdio: options.cliUrl ? false : options.useStdio ?? true, | ||
| // Default to stdio unless cliUrl is provided | ||
| isChildProcess: options.isChildProcess ?? false, | ||
| cliUrl: options.cliUrl, | ||
| logLevel: options.logLevel || "debug", | ||
| autoStart: options.autoStart ?? true, | ||
| autoRestart: false, | ||
| env: effectiveEnv, | ||
| workingDirectory: options.workingDirectory ?? process.cwd(), | ||
| logLevel: options.logLevel, | ||
| gitHubToken: options.gitHubToken, | ||
| // Default useLoggedInUser to false when gitHubToken is provided, otherwise true | ||
| // Default useLoggedInUser to false when gitHubToken is provided, otherwise true. | ||
| useLoggedInUser: options.useLoggedInUser ?? (options.gitHubToken ? false : true), | ||
| telemetry: options.telemetry, | ||
| copilotHome: options.copilotHome, | ||
| baseDirectory: options.baseDirectory, | ||
| sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0, | ||
| remote: options.remote ?? false | ||
| enableRemoteSessions: options.enableRemoteSessions ?? false | ||
| }; | ||
| } | ||
| connectionExtraArgs = []; | ||
| /** | ||
@@ -271,8 +285,8 @@ * Parse CLI URL into host and port | ||
| } | ||
| if (!config.createSessionFsHandler) { | ||
| if (!config.createSessionFsProvider) { | ||
| throw new Error( | ||
| "createSessionFsHandler is required in session config when sessionFs is enabled in client options." | ||
| "createSessionFsProvider is required in session config when sessionFs is enabled in client options." | ||
| ); | ||
| } | ||
| const provider = config.createSessionFsHandler(session); | ||
| const provider = config.createSessionFsProvider(session); | ||
| if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) { | ||
@@ -291,3 +305,3 @@ throw new Error( | ||
| * | ||
| * This method is called automatically when creating a session if `autoStart` is true (default). | ||
| * This method is called automatically the first time you create or resume a session. | ||
| * | ||
@@ -299,3 +313,3 @@ * @returns A promise that resolves when the connection is established | ||
| * ```typescript | ||
| * const client = new CopilotClient({ autoStart: false }); | ||
| * const client = new CopilotClient(); | ||
| * await client.start(); | ||
@@ -395,4 +409,11 @@ * // Now ready to create sessions | ||
| if (this.socket) { | ||
| const socket = this.socket; | ||
| this.socket = null; | ||
| try { | ||
| this.socket.end(); | ||
| if (!socket.destroyed) { | ||
| await new Promise((resolve) => { | ||
| socket.once("close", () => resolve()); | ||
| socket.end(); | ||
| }); | ||
| } | ||
| } catch (error) { | ||
@@ -405,7 +426,14 @@ errors.push( | ||
| } | ||
| this.socket = null; | ||
| } | ||
| if (this.cliProcess && !this.isExternalServer) { | ||
| const child = this.cliProcess; | ||
| this.cliProcess = null; | ||
| try { | ||
| this.cliProcess.kill(); | ||
| if (child.exitCode === null && child.signalCode === null) { | ||
| const exited = new Promise((resolve) => { | ||
| child.once("exit", () => resolve()); | ||
| }); | ||
| child.kill(); | ||
| await exited; | ||
| } | ||
| } catch (error) { | ||
@@ -418,3 +446,2 @@ errors.push( | ||
| } | ||
| this.cliProcess = null; | ||
| } | ||
@@ -426,3 +453,3 @@ if (this.cliStartTimeout) { | ||
| this.state = "disconnected"; | ||
| this.actualPort = null; | ||
| this.runtimePort = null; | ||
| this.stderrBuffer = ""; | ||
@@ -433,2 +460,17 @@ this.processExitPromise = null; | ||
| /** | ||
| * Alias for {@link stop} that lets `CopilotClient` participate in `await using` | ||
| * blocks for automatic cleanup. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await using client = new CopilotClient(); | ||
| * const session = await client.createSession({ onPermissionRequest: approveAll }); | ||
| * await session.sendAndWait("Hello"); | ||
| * // client.stop() is called automatically when the block exits. | ||
| * ``` | ||
| */ | ||
| async [Symbol.asyncDispose]() { | ||
| await this.stop(); | ||
| } | ||
| /** | ||
| * Forcefully stops the CLI server without graceful cleanup. | ||
@@ -489,3 +531,3 @@ * | ||
| this.state = "disconnected"; | ||
| this.actualPort = null; | ||
| this.runtimePort = null; | ||
| this.stderrBuffer = ""; | ||
@@ -498,8 +540,7 @@ this.processExitPromise = null; | ||
| * Sessions maintain conversation state, handle events, and manage tool execution. | ||
| * If the client is not connected and `autoStart` is enabled, this will automatically | ||
| * start the connection. | ||
| * If the client is not connected, this method automatically starts the connection. | ||
| * | ||
| * @param config - Optional configuration for the session | ||
| * @returns A promise that resolves with the created session | ||
| * @throws Error if the client is not connected and autoStart is disabled | ||
| * @throws Error if the client fails to start | ||
| * | ||
@@ -526,7 +567,3 @@ * @example | ||
| if (!this.connection) { | ||
| if (this.options.autoStart) { | ||
| await this.start(); | ||
| } else { | ||
| throw new Error("Client not connected. Call start() first."); | ||
| } | ||
| await this.start(); | ||
| } | ||
@@ -549,7 +586,7 @@ const sessionId = config.sessionId ?? randomUUID(); | ||
| } | ||
| if (config.onExitPlanMode) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanMode); | ||
| if (config.onExitPlanModeRequest) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanModeRequest); | ||
| } | ||
| if (config.onAutoModeSwitch) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitch); | ||
| if (config.onAutoModeSwitchRequest) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest); | ||
| } | ||
@@ -591,3 +628,3 @@ if (config.hooks) { | ||
| excludedTools: config.excludedTools, | ||
| provider: config.provider ? toWireProviderConfig(config.provider) : void 0, | ||
| provider: config.provider, | ||
| enableSessionTelemetry: config.enableSessionTelemetry, | ||
@@ -598,4 +635,4 @@ modelCapabilities: config.modelCapabilities, | ||
| requestElicitation: !!config.onElicitationRequest, | ||
| requestExitPlanMode: !!config.onExitPlanMode, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitch, | ||
| requestExitPlanMode: !!config.onExitPlanModeRequest, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitchRequest, | ||
| hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)), | ||
@@ -605,5 +642,5 @@ workingDirectory: config.workingDirectory, | ||
| includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true, | ||
| mcpServers: config.mcpServers, | ||
| mcpServers: toWireMcpServers(config.mcpServers), | ||
| envValueMode: "direct", | ||
| customAgents: config.customAgents, | ||
| customAgents: toWireCustomAgents(config.customAgents), | ||
| defaultAgent: config.defaultAgent, | ||
@@ -656,7 +693,3 @@ agent: config.agent, | ||
| if (!this.connection) { | ||
| if (this.options.autoStart) { | ||
| await this.start(); | ||
| } else { | ||
| throw new Error("Client not connected. Call start() first."); | ||
| } | ||
| await this.start(); | ||
| } | ||
@@ -678,7 +711,7 @@ const session = new CopilotSession( | ||
| } | ||
| if (config.onExitPlanMode) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanMode); | ||
| if (config.onExitPlanModeRequest) { | ||
| session.registerExitPlanModeHandler(config.onExitPlanModeRequest); | ||
| } | ||
| if (config.onAutoModeSwitch) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitch); | ||
| if (config.onAutoModeSwitchRequest) { | ||
| session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest); | ||
| } | ||
@@ -721,3 +754,3 @@ if (config.hooks) { | ||
| })), | ||
| provider: config.provider ? toWireProviderConfig(config.provider) : void 0, | ||
| provider: config.provider, | ||
| modelCapabilities: config.modelCapabilities, | ||
@@ -727,4 +760,4 @@ requestPermission: config.onPermissionRequest !== defaultJoinSessionPermissionHandler, | ||
| requestElicitation: !!config.onElicitationRequest, | ||
| requestExitPlanMode: !!config.onExitPlanMode, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitch, | ||
| requestExitPlanMode: !!config.onExitPlanModeRequest, | ||
| requestAutoModeSwitch: !!config.onAutoModeSwitchRequest, | ||
| hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)), | ||
@@ -736,5 +769,5 @@ workingDirectory: config.workingDirectory, | ||
| includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true, | ||
| mcpServers: config.mcpServers, | ||
| mcpServers: toWireMcpServers(config.mcpServers), | ||
| envValueMode: "direct", | ||
| customAgents: config.customAgents, | ||
| customAgents: toWireCustomAgents(config.customAgents), | ||
| defaultAgent: config.defaultAgent, | ||
@@ -746,3 +779,3 @@ agent: config.agent, | ||
| infiniteSessions: config.infiniteSessions, | ||
| disableResume: config.disableResume, | ||
| suppressResumeEvent: config.suppressResumeEvent, | ||
| continuePendingWork: config.continuePendingWork, | ||
@@ -977,4 +1010,9 @@ gitHubToken: config.gitHubToken, | ||
| } | ||
| let wireFilter; | ||
| if (filter) { | ||
| const { workingDirectory, ...rest } = filter; | ||
| wireFilter = { ...rest, cwd: workingDirectory }; | ||
| } | ||
| const response = await this.connection.sendRequest("session.list", { | ||
| filter | ||
| filter: wireFilter | ||
| }); | ||
@@ -1014,2 +1052,3 @@ const { sessions } = response; | ||
| static toSessionMetadata(raw) { | ||
| const { context } = raw; | ||
| return { | ||
@@ -1021,3 +1060,8 @@ sessionId: raw.sessionId, | ||
| isRemote: raw.isRemote, | ||
| context: raw.context | ||
| context: context ? { | ||
| workingDirectory: context.cwd, | ||
| gitRoot: context.gitRoot, | ||
| repository: context.repository, | ||
| branch: context.branch | ||
| } : void 0 | ||
| }; | ||
@@ -1075,3 +1119,3 @@ } | ||
| } | ||
| on(eventTypeOrHandler, handler) { | ||
| onLifecycle(eventTypeOrHandler, handler) { | ||
| if (typeof eventTypeOrHandler === "string" && handler) { | ||
@@ -1103,13 +1147,13 @@ const eventType = eventTypeOrHandler; | ||
| this.stderrBuffer = ""; | ||
| const args = [ | ||
| ...this.options.cliArgs, | ||
| "--headless", | ||
| "--no-auto-update", | ||
| "--log-level", | ||
| this.options.logLevel | ||
| ]; | ||
| if (this.options.useStdio) { | ||
| const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"]; | ||
| if (this.options.logLevel) { | ||
| args.push("--log-level", this.options.logLevel); | ||
| } | ||
| if (this.connectionConfig.kind === "stdio") { | ||
| args.push("--stdio"); | ||
| } else if (this.options.port > 0) { | ||
| args.push("--port", this.options.port.toString()); | ||
| } else if (this.connectionConfig.kind === "tcp") { | ||
| const requestedPort = this.connectionConfig.port ?? 0; | ||
| if (requestedPort > 0) { | ||
| args.push("--port", requestedPort.toString()); | ||
| } | ||
| } | ||
@@ -1128,6 +1172,6 @@ if (this.options.gitHubToken) { | ||
| } | ||
| if (this.options.remote) { | ||
| if (this.options.enableRemoteSessions) { | ||
| args.push("--remote"); | ||
| } | ||
| const envWithoutNodeDebug = { ...this.options.env }; | ||
| const envWithoutNodeDebug = { ...this.resolvedEnv }; | ||
| delete envWithoutNodeDebug.NODE_DEBUG; | ||
@@ -1140,8 +1184,8 @@ if (this.options.gitHubToken) { | ||
| } | ||
| if (this.options.copilotHome) { | ||
| envWithoutNodeDebug.COPILOT_HOME = this.options.copilotHome; | ||
| if (this.options.baseDirectory) { | ||
| envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory; | ||
| } | ||
| if (!this.options.cliPath) { | ||
| if (!this.resolvedCliPath) { | ||
| throw new Error( | ||
| "Path to Copilot CLI is required. Please provide it via the cliPath option, or use cliUrl to rely on a remote CLI." | ||
| "Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime." | ||
| ); | ||
@@ -1165,13 +1209,13 @@ } | ||
| } | ||
| if (!existsSync(this.options.cliPath)) { | ||
| if (!existsSync(this.resolvedCliPath)) { | ||
| throw new Error( | ||
| `Copilot CLI not found at ${this.options.cliPath}. Ensure @github/copilot is installed.` | ||
| `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.` | ||
| ); | ||
| } | ||
| const stdioConfig = this.options.useStdio ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"]; | ||
| const isJsFile = this.options.cliPath.endsWith(".js"); | ||
| const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"]; | ||
| const isJsFile = this.resolvedCliPath.endsWith(".js"); | ||
| if (isJsFile) { | ||
| this.cliProcess = spawn(getNodeExecPath(), [this.options.cliPath, ...args], { | ||
| this.cliProcess = spawn(getNodeExecPath(), [this.resolvedCliPath, ...args], { | ||
| stdio: stdioConfig, | ||
| cwd: this.options.cwd, | ||
| cwd: this.options.workingDirectory, | ||
| env: envWithoutNodeDebug, | ||
@@ -1181,5 +1225,5 @@ windowsHide: true | ||
| } else { | ||
| this.cliProcess = spawn(this.options.cliPath, args, { | ||
| this.cliProcess = spawn(this.resolvedCliPath, args, { | ||
| stdio: stdioConfig, | ||
| cwd: this.options.cwd, | ||
| cwd: this.options.workingDirectory, | ||
| env: envWithoutNodeDebug, | ||
@@ -1191,3 +1235,3 @@ windowsHide: true | ||
| let resolved = false; | ||
| if (this.options.useStdio) { | ||
| if (this.connectionConfig.kind === "stdio") { | ||
| resolved = true; | ||
@@ -1200,3 +1244,3 @@ resolve(); | ||
| if (match && !resolved) { | ||
| this.actualPort = parseInt(match[1], 10); | ||
| this.runtimePort = parseInt(match[1], 10); | ||
| resolved = true; | ||
@@ -1275,3 +1319,3 @@ resolve(); | ||
| } | ||
| }, 1e4); | ||
| }, 3e4); | ||
| }); | ||
@@ -1283,8 +1327,10 @@ } | ||
| async connectToServer() { | ||
| if (this.options.isChildProcess) { | ||
| return this.connectToParentProcessViaStdio(); | ||
| } else if (this.options.useStdio) { | ||
| return this.connectToChildProcessViaStdio(); | ||
| } else { | ||
| return this.connectViaTcp(); | ||
| switch (this.connectionConfig.kind) { | ||
| case "parent-process": | ||
| return this.connectToParentProcessViaStdio(); | ||
| case "stdio": | ||
| return this.connectToChildProcessViaStdio(); | ||
| case "tcp": | ||
| case "uri": | ||
| return this.connectViaTcp(); | ||
| } | ||
@@ -1329,3 +1375,3 @@ } | ||
| async connectViaTcp() { | ||
| if (!this.actualPort) { | ||
| if (!this.runtimePort) { | ||
| throw new Error("Server port not available"); | ||
@@ -1339,3 +1385,3 @@ } | ||
| }, 1e4); | ||
| this.socket.connect(this.actualPort, this.actualHost, () => { | ||
| this.socket.connect(this.runtimePort, this.actualHost, () => { | ||
| clearTimeout(connectionTimeout); | ||
@@ -1420,3 +1466,16 @@ this.connection = createMessageConnection( | ||
| } | ||
| const event = notification; | ||
| const raw = notification; | ||
| let metadata; | ||
| if (raw.metadata && raw.metadata.startTime && raw.metadata.modifiedTime) { | ||
| metadata = { | ||
| startTime: new Date(raw.metadata.startTime), | ||
| modifiedTime: new Date(raw.metadata.modifiedTime), | ||
| summary: raw.metadata.summary | ||
| }; | ||
| } | ||
| const event = { | ||
| type: raw.type, | ||
| sessionId: raw.sessionId, | ||
| metadata | ||
| }; | ||
| const typedHandlers = this.typedLifecycleHandlers.get(event.type); | ||
@@ -1423,0 +1482,0 @@ if (typedHandlers) { |
@@ -12,7 +12,7 @@ import { CopilotClient } from "./client.js"; | ||
| } | ||
| const client = new CopilotClient({ isChildProcess: true }); | ||
| const client = new CopilotClient({ _internalConnection: { kind: "parent-process" } }); | ||
| return client.resumeSession(sessionId, { | ||
| ...config, | ||
| onPermissionRequest: config.onPermissionRequest ?? defaultJoinSessionPermissionHandler, | ||
| disableResume: config.disableResume ?? true | ||
| suppressResumeEvent: config.suppressResumeEvent ?? true | ||
| }); | ||
@@ -19,0 +19,0 @@ } |
+2
-1
@@ -7,5 +7,6 @@ /** | ||
| export { CopilotClient } from "./client.js"; | ||
| export { RuntimeConnection } from "./types.js"; | ||
| export { CopilotSession, type AssistantMessageEvent } from "./session.js"; | ||
| export { defineTool, approveAll, convertMcpCallToolResult, createSessionFsAdapter, SYSTEM_PROMPT_SECTIONS, } from "./types.js"; | ||
| export type * from "./generated/session-events.js"; | ||
| export type { CommandContext, CommandDefinition, CommandHandler, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, ConnectionState, CopilotClientOptions, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, InputOptions, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ProviderConfig, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js"; | ||
| export type { CommandContext, CommandDefinition, CommandHandler, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, ConnectionState, CopilotClientOptions, StdioRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, UiInputOptions, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ProviderConfig, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionConfigBase, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventMetadata, SessionLifecycleEventType, SessionLifecycleHandler, SessionCreatedEvent, SessionDeletedEvent, SessionUpdatedEvent, SessionForegroundEvent, SessionBackgroundEvent, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolTelemetry, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js"; |
+2
-0
| import { CopilotClient } from "./client.js"; | ||
| import { RuntimeConnection } from "./types.js"; | ||
| import { CopilotSession } from "./session.js"; | ||
@@ -13,2 +14,3 @@ import { | ||
| CopilotSession, | ||
| RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS, | ||
@@ -15,0 +17,0 @@ approveAll, |
+5
-212
@@ -1,10 +0,3 @@ | ||
| /** | ||
| * Copilot Session - represents a single conversation session with the Copilot CLI. | ||
| * @module session | ||
| */ | ||
| import type { MessageConnection } from "vscode-jsonrpc/node.js"; | ||
| import { createSessionRpc } from "./generated/rpc.js"; | ||
| import type { ClientSessionApiHandlers } from "./generated/rpc.js"; | ||
| import type { CommandHandler, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, ElicitationHandler, ElicitationContext, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, MessageOptions, PermissionHandler, PermissionRequestResult, ReasoningEffort, ModelCapabilitiesOverride, SectionTransformFn, SessionCapabilities, SessionEvent, SessionEventHandler, SessionEventType, SessionHooks, SessionUiApi, Tool, ToolHandler, TraceContextProvider, TypedSessionEventHandler, UserInputHandler, UserInputResponse } from "./types.js"; | ||
| export declare const NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server."; | ||
| import type { MessageOptions, ReasoningEffort, ModelCapabilitiesOverride, SessionCapabilities, SessionEvent, SessionEventHandler, SessionEventType, SessionUiApi, TypedSessionEventHandler } from "./types.js"; | ||
| /** Assistant message event - the final response from the assistant. */ | ||
@@ -57,15 +50,3 @@ export type AssistantMessageEvent = Extract<SessionEvent, { | ||
| private _capabilities; | ||
| /** @internal Client session API handlers, populated by CopilotClient during create/resume. */ | ||
| clientSessionApis: ClientSessionApiHandlers; | ||
| /** | ||
| * Creates a new CopilotSession instance. | ||
| * | ||
| * @param sessionId - The unique identifier for this session | ||
| * @param connection - The JSON-RPC message connection to the Copilot CLI | ||
| * @param workspacePath - Path to the session workspace directory (when infinite sessions enabled) | ||
| * @param traceContextProvider - Optional callback to get W3C Trace Context for outbound RPCs | ||
| * @internal This constructor is internal. Use {@link CopilotClient.createSession} to create sessions. | ||
| */ | ||
| constructor(sessionId: string, connection: MessageConnection, _workspacePath?: string | undefined, traceContextProvider?: TraceContextProvider); | ||
| /** | ||
| * Typed session-scoped RPC methods. | ||
@@ -116,2 +97,3 @@ */ | ||
| */ | ||
| send(prompt: string): Promise<string>; | ||
| send(options: MessageOptions): Promise<string>; | ||
@@ -141,2 +123,3 @@ /** | ||
| */ | ||
| sendAndWait(prompt: string, timeout?: number): Promise<AssistantMessageEvent | undefined>; | ||
| sendAndWait(options: MessageOptions, timeout?: number): Promise<AssistantMessageEvent | undefined>; | ||
@@ -189,104 +172,2 @@ /** | ||
| on(handler: SessionEventHandler): () => void; | ||
| /** | ||
| * Dispatches an event to all registered handlers. | ||
| * Also handles broadcast request events internally (external tool calls, permissions). | ||
| * | ||
| * @param event - The session event to dispatch | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| _dispatchEvent(event: SessionEvent): void; | ||
| /** | ||
| * Handles broadcast request events by executing local handlers and responding via RPC. | ||
| * Handlers are dispatched as fire-and-forget — rejections propagate as unhandled promise | ||
| * rejections, consistent with standard EventEmitter / event handler semantics. | ||
| * @internal | ||
| */ | ||
| private _handleBroadcastEvent; | ||
| /** | ||
| * Executes a tool handler and sends the result back via RPC. | ||
| * @internal | ||
| */ | ||
| private _executeToolAndRespond; | ||
| /** | ||
| * Executes a permission handler and sends the result back via RPC. | ||
| * @internal | ||
| */ | ||
| private _executePermissionAndRespond; | ||
| /** | ||
| * Executes a command handler and sends the result back via RPC. | ||
| * @internal | ||
| */ | ||
| private _executeCommandAndRespond; | ||
| /** | ||
| * Registers custom tool handlers for this session. | ||
| * | ||
| * Tools with handlers allow the assistant to execute custom functions automatically. | ||
| * Declaration-only tools are surfaced as events and left pending for the consumer. | ||
| * | ||
| * @param tools - An array of tool definitions with their handlers, or undefined to clear all tools | ||
| * @internal This method is typically called internally when creating a session with tools. | ||
| */ | ||
| registerTools(tools?: Tool[]): void; | ||
| /** | ||
| * Retrieves a registered tool handler by name. | ||
| * | ||
| * @param name - The name of the tool to retrieve | ||
| * @returns The tool handler if found, or undefined | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| getToolHandler(name: string): ToolHandler | undefined; | ||
| /** | ||
| * Registers command handlers for this session. | ||
| * | ||
| * @param commands - An array of command definitions with handlers, or undefined to clear | ||
| * @internal This method is typically called internally when creating/resuming a session. | ||
| */ | ||
| registerCommands(commands?: { | ||
| name: string; | ||
| handler: CommandHandler; | ||
| }[]): void; | ||
| /** | ||
| * Registers the elicitation handler for this session. | ||
| * | ||
| * @param handler - The handler to invoke when the server dispatches an elicitation request | ||
| * @internal This method is typically called internally when creating/resuming a session. | ||
| */ | ||
| registerElicitationHandler(handler?: ElicitationHandler): void; | ||
| /** | ||
| * Registers the exit-plan-mode handler for this session. | ||
| * | ||
| * @param handler - The handler to invoke when the server dispatches an exit-plan-mode request | ||
| * @internal This method is typically called internally when creating/resuming a session. | ||
| */ | ||
| registerExitPlanModeHandler(handler?: ExitPlanModeHandler): void; | ||
| /** | ||
| * Registers the auto-mode-switch handler for this session. | ||
| * | ||
| * @param handler - The handler to invoke when the server dispatches an auto-mode-switch request | ||
| * @internal This method is typically called internally when creating/resuming a session. | ||
| */ | ||
| registerAutoModeSwitchHandler(handler?: AutoModeSwitchHandler): void; | ||
| /** | ||
| * Handles an elicitation.requested broadcast event. | ||
| * Invokes the registered handler and responds via handlePendingElicitation RPC. | ||
| * @internal | ||
| */ | ||
| _handleElicitationRequest(context: ElicitationContext, requestId: string): Promise<void>; | ||
| /** | ||
| * Handles an exitPlanMode.request callback from the runtime. | ||
| * @internal | ||
| */ | ||
| _handleExitPlanModeRequest(request: ExitPlanModeRequest): Promise<ExitPlanModeResult>; | ||
| /** | ||
| * Handles an autoModeSwitch.request callback from the runtime. | ||
| * @internal | ||
| */ | ||
| _handleAutoModeSwitchRequest(request: AutoModeSwitchRequest): Promise<AutoModeSwitchResponse>; | ||
| /** | ||
| * Sets the host capabilities for this session. | ||
| * | ||
| * @param capabilities - The capabilities object from the create/resume response | ||
| * @internal This method is typically called internally when creating/resuming a session. | ||
| */ | ||
| setCapabilities(capabilities?: SessionCapabilities): void; | ||
| private assertElicitation; | ||
@@ -298,80 +179,2 @@ private _elicitation; | ||
| /** | ||
| * Registers a handler for permission requests. | ||
| * | ||
| * When the assistant needs permission to perform certain actions (e.g., file operations), | ||
| * this handler is called to approve or deny the request. | ||
| * | ||
| * @param handler - The permission handler function, or undefined to remove the handler | ||
| * @internal This method is typically called internally when creating a session. | ||
| */ | ||
| registerPermissionHandler(handler?: PermissionHandler): void; | ||
| /** | ||
| * Registers a user input handler for ask_user requests. | ||
| * | ||
| * When the agent needs input from the user (via ask_user tool), | ||
| * this handler is called to provide the response. | ||
| * | ||
| * @param handler - The user input handler function, or undefined to remove the handler | ||
| * @internal This method is typically called internally when creating a session. | ||
| */ | ||
| registerUserInputHandler(handler?: UserInputHandler): void; | ||
| /** | ||
| * Registers hook handlers for session lifecycle events. | ||
| * | ||
| * Hooks allow custom logic to be executed at various points during | ||
| * the session lifecycle (before/after tool use, session start/end, etc.). | ||
| * | ||
| * @param hooks - The hook handlers object, or undefined to remove all hooks | ||
| * @internal This method is typically called internally when creating a session. | ||
| */ | ||
| registerHooks(hooks?: SessionHooks): void; | ||
| /** | ||
| * Registers transform callbacks for system message sections. | ||
| * | ||
| * @param callbacks - Map of section ID to transform callback, or undefined to clear | ||
| * @internal This method is typically called internally when creating a session. | ||
| */ | ||
| registerTransformCallbacks(callbacks?: Map<string, SectionTransformFn>): void; | ||
| /** | ||
| * Handles a systemMessage.transform request from the runtime. | ||
| * Dispatches each section to its registered transform callback. | ||
| * | ||
| * @param sections - Map of section IDs to their current rendered content | ||
| * @returns A promise that resolves with the transformed sections | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| _handleSystemMessageTransform(sections: Record<string, { | ||
| content: string; | ||
| }>): Promise<{ | ||
| sections: Record<string, { | ||
| content: string; | ||
| }>; | ||
| }>; | ||
| /** | ||
| * Handles a permission request in the v2 protocol format (synchronous RPC). | ||
| * Used as a back-compat adapter when connected to a v2 server. | ||
| * | ||
| * @param request - The permission request data from the CLI | ||
| * @returns A promise that resolves with the permission decision | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| _handlePermissionRequestV2(request: unknown): Promise<PermissionRequestResult>; | ||
| /** | ||
| * Handles a user input request from the Copilot CLI. | ||
| * | ||
| * @param request - The user input request data from the CLI | ||
| * @returns A promise that resolves with the user's response | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| _handleUserInputRequest(request: unknown): Promise<UserInputResponse>; | ||
| /** | ||
| * Handles a hooks invocation from the Copilot CLI. | ||
| * | ||
| * @param hookType - The type of hook being invoked | ||
| * @param input - The input data for the hook | ||
| * @returns A promise that resolves with the hook output, or undefined | ||
| * @internal This method is for internal use by the SDK. | ||
| */ | ||
| _handleHooksInvoke(hookType: string, input: unknown): Promise<unknown>; | ||
| /** | ||
| * Retrieves all events and messages from this session's history. | ||
@@ -387,3 +190,3 @@ * | ||
| * ```typescript | ||
| * const events = await session.getMessages(); | ||
| * const events = await session.getEvents(); | ||
| * for (const event of events) { | ||
@@ -396,3 +199,3 @@ * if (event.type === "assistant.message") { | ||
| */ | ||
| getMessages(): Promise<SessionEvent[]>; | ||
| getEvents(): Promise<SessionEvent[]>; | ||
| /** | ||
@@ -420,12 +223,2 @@ * Disconnects this session and releases all in-memory resources (event handlers, | ||
| disconnect(): Promise<void>; | ||
| /** | ||
| * @deprecated Use {@link disconnect} instead. This method will be removed in a future release. | ||
| * | ||
| * Disconnects this session and releases all in-memory resources. | ||
| * Session data on disk is preserved for later resumption. | ||
| * | ||
| * @returns A promise that resolves when the session is disconnected | ||
| * @throws Error if the connection fails | ||
| */ | ||
| destroy(): Promise<void>; | ||
| /** Enables `await using session = ...` syntax for automatic cleanup. */ | ||
@@ -432,0 +225,0 @@ [Symbol.asyncDispose](): Promise<void>; |
+17
-58
@@ -5,2 +5,10 @@ import { ConnectionError, ResponseError } from "vscode-jsonrpc/node.js"; | ||
| const NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server."; | ||
| function deserializeHookInput(raw) { | ||
| if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") { | ||
| return raw; | ||
| } | ||
| const obj = raw; | ||
| const { cwd, ...rest } = obj; | ||
| return { ...rest, timestamp: new Date(obj.timestamp), workingDirectory: cwd }; | ||
| } | ||
| class CopilotSession { | ||
@@ -82,21 +90,4 @@ /** | ||
| } | ||
| /** | ||
| * Sends a message to this session and waits for the response. | ||
| * | ||
| * The message is processed asynchronously. Subscribe to events via {@link on} | ||
| * to receive streaming responses and other session events. | ||
| * | ||
| * @param options - The message options including the prompt and optional attachments | ||
| * @returns A promise that resolves with the message ID of the response | ||
| * @throws Error if the session has been disconnected or the connection fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const messageId = await session.send({ | ||
| * prompt: "Explain this code", | ||
| * attachments: [{ type: "file", path: "./src/index.ts" }] | ||
| * }); | ||
| * ``` | ||
| */ | ||
| async send(options) { | ||
| async send(optionsOrPrompt) { | ||
| const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt; | ||
| const response = await this.connection.sendRequest("session.send", { | ||
@@ -112,26 +103,4 @@ ...await getTraceContext(this.traceContextProvider), | ||
| } | ||
| /** | ||
| * Sends a message to this session and waits until the session becomes idle. | ||
| * | ||
| * This is a convenience method that combines {@link send} with waiting for | ||
| * the `session.idle` event. Use this when you want to block until the | ||
| * assistant has finished processing the message. | ||
| * | ||
| * Events are still delivered to handlers registered via {@link on} while waiting. | ||
| * | ||
| * @param options - The message options including the prompt and optional attachments | ||
| * @param timeout - Timeout in milliseconds (default: 60000). Controls how long to wait; does not abort in-flight agent work. | ||
| * @returns A promise that resolves with the final assistant message when the session becomes idle, | ||
| * or undefined if no assistant message was received | ||
| * @throws Error if the timeout is reached before the session becomes idle | ||
| * @throws Error if the session has been disconnected or the connection fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Send and wait for completion with default 60s timeout | ||
| * const response = await session.sendAndWait({ prompt: "What is 2+2?" }); | ||
| * console.log(response?.data.content); // "4" | ||
| * ``` | ||
| */ | ||
| async sendAndWait(options, timeout) { | ||
| async sendAndWait(optionsOrPrompt, timeout) { | ||
| const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt; | ||
| const effectiveTimeout = timeout ?? 6e4; | ||
@@ -700,4 +669,6 @@ let resolveIdle; | ||
| } | ||
| const normalized = deserializeHookInput(input); | ||
| const handlerMap = { | ||
| preToolUse: this.hooks.onPreToolUse, | ||
| preMcpToolCall: this.hooks.onPreMcpToolCall, | ||
| postToolUse: this.hooks.onPostToolUse, | ||
@@ -714,3 +685,3 @@ userPromptSubmitted: this.hooks.onUserPromptSubmitted, | ||
| try { | ||
| const result = await handler(input, { sessionId: this.sessionId }); | ||
| const result = await handler(normalized, { sessionId: this.sessionId }); | ||
| return result; | ||
@@ -732,3 +703,3 @@ } catch (_error) { | ||
| * ```typescript | ||
| * const events = await session.getMessages(); | ||
| * const events = await session.getEvents(); | ||
| * for (const event of events) { | ||
@@ -741,3 +712,3 @@ * if (event.type === "assistant.message") { | ||
| */ | ||
| async getMessages() { | ||
| async getEvents() { | ||
| const response = await this.connection.sendRequest("session.getMessages", { | ||
@@ -782,14 +753,2 @@ sessionId: this.sessionId | ||
| } | ||
| /** | ||
| * @deprecated Use {@link disconnect} instead. This method will be removed in a future release. | ||
| * | ||
| * Disconnects this session and releases all in-memory resources. | ||
| * Session data on disk is preserved for later resumption. | ||
| * | ||
| * @returns A promise that resolves when the session is disconnected | ||
| * @throws Error if the connection fails | ||
| */ | ||
| async destroy() { | ||
| return this.disconnect(); | ||
| } | ||
| /** Enables `await using session = ...` syntax for automatic cleanup. */ | ||
@@ -796,0 +755,0 @@ async [Symbol.asyncDispose]() { |
+239
-112
@@ -51,70 +51,110 @@ /** | ||
| } | ||
| export interface CopilotClientOptions { | ||
| /** | ||
| * Configures how a {@link CopilotClient} connects to the Copilot runtime. | ||
| * Construct via the factory functions on {@link RuntimeConnection}. | ||
| */ | ||
| export type RuntimeConnection = StdioRuntimeConnection | TcpRuntimeConnection | UriRuntimeConnection; | ||
| /** | ||
| * Spawns a runtime child process and communicates over its stdin/stdout. | ||
| * This is the default if no {@link CopilotClientOptions.connection} is set. | ||
| */ | ||
| export interface StdioRuntimeConnection { | ||
| readonly kind: "stdio"; | ||
| /** Path to the runtime executable. When omitted, the bundled runtime is used. */ | ||
| readonly path?: string; | ||
| /** Extra command-line arguments to pass to the runtime process. */ | ||
| readonly args?: readonly string[]; | ||
| } | ||
| /** | ||
| * Spawns a runtime child process that listens on a TCP socket and connects to it. | ||
| */ | ||
| export interface TcpRuntimeConnection { | ||
| readonly kind: "tcp"; | ||
| /** | ||
| * Path to the CLI executable or JavaScript entry point. | ||
| * If not specified, uses the bundled CLI from the @github/copilot package. | ||
| * TCP port to listen on. `0` (the default) auto-allocates a free port. | ||
| * If the chosen port is already in use, startup fails. | ||
| */ | ||
| cliPath?: string; | ||
| readonly port?: number; | ||
| /** | ||
| * Extra arguments to pass to the CLI executable (inserted before SDK-managed args) | ||
| * Optional shared secret the SDK sends to the spawned runtime to authenticate | ||
| * the TCP connection. When omitted, a UUID is generated automatically so the | ||
| * loopback listener is safe by default. | ||
| */ | ||
| cliArgs?: string[]; | ||
| readonly connectionToken?: string; | ||
| /** Path to the runtime executable. When omitted, the bundled runtime is used. */ | ||
| readonly path?: string; | ||
| /** Extra command-line arguments to pass to the runtime process. */ | ||
| readonly args?: readonly string[]; | ||
| } | ||
| /** | ||
| * Connects to an already-running runtime at the specified URL. The SDK does not | ||
| * spawn a process in this mode. | ||
| */ | ||
| export interface UriRuntimeConnection { | ||
| readonly kind: "uri"; | ||
| /** | ||
| * Working directory for the CLI process | ||
| * If not set, inherits the current process's working directory | ||
| * URL of the runtime to connect to. Accepts `"port"`, `"host:port"`, or a | ||
| * full URL (`"http://host:port"`). | ||
| */ | ||
| cwd?: string; | ||
| readonly url: string; | ||
| /** Optional shared secret to authenticate the connection. */ | ||
| readonly connectionToken?: string; | ||
| } | ||
| /** Factory functions for constructing {@link RuntimeConnection} instances. */ | ||
| export declare const RuntimeConnection: { | ||
| /** | ||
| * Base directory for Copilot data (session state, config, etc.). | ||
| * Sets the COPILOT_HOME environment variable on the spawned CLI process. | ||
| * When not set, the CLI defaults to ~/.copilot. | ||
| * This option is only used when the SDK spawns the CLI process; it is ignored | ||
| * when connecting to an external server via {@link cliUrl}. | ||
| * Spawn a runtime child process and communicate over its stdin/stdout. | ||
| * This is the default if no {@link CopilotClientOptions.connection} is set. | ||
| */ | ||
| copilotHome?: string; | ||
| readonly forStdio: (opts?: { | ||
| path?: string; | ||
| args?: readonly string[]; | ||
| }) => StdioRuntimeConnection; | ||
| /** | ||
| * Port for the CLI server (TCP mode only) | ||
| * @default 0 (random available port) | ||
| * Spawn a runtime child process that listens on a TCP socket and connect to it. | ||
| */ | ||
| port?: number; | ||
| readonly forTcp: (opts?: { | ||
| port?: number; | ||
| connectionToken?: string; | ||
| path?: string; | ||
| args?: readonly string[]; | ||
| }) => TcpRuntimeConnection; | ||
| /** | ||
| * Use stdio transport instead of TCP | ||
| * When true, communicates with CLI via stdin/stdout pipes | ||
| * @default true | ||
| * Connect to an already-running runtime at the given URL. The SDK does not | ||
| * spawn a process in this mode. | ||
| */ | ||
| useStdio?: boolean; | ||
| readonly forUri: (url: string, opts?: { | ||
| connectionToken?: string; | ||
| }) => UriRuntimeConnection; | ||
| }; | ||
| export interface CopilotClientOptions { | ||
| /** | ||
| * When true, indicates the SDK is running as a child process of the Copilot CLI server, and should | ||
| * use its own stdio for communicating with the existing parent process. Can only be used in combination | ||
| * with useStdio: true. | ||
| * How to connect to the Copilot runtime. When omitted, defaults to | ||
| * {@link RuntimeConnection.forStdio} with the bundled runtime. | ||
| */ | ||
| isChildProcess?: boolean; | ||
| connection?: RuntimeConnection; | ||
| /** | ||
| * URL of an existing Copilot CLI server to connect to over TCP | ||
| * When provided, the client will not spawn a CLI process | ||
| * Format: "host:port" or "http://host:port" or just "port" (defaults to localhost) | ||
| * Examples: "localhost:8080", "http://127.0.0.1:9000", "8080" | ||
| * Mutually exclusive with cliPath, useStdio | ||
| * Working directory for the runtime process. | ||
| * If not set, inherits the current process's working directory. | ||
| */ | ||
| cliUrl?: string; | ||
| workingDirectory?: string; | ||
| /** | ||
| * Log level for the CLI server | ||
| * Base directory for Copilot data (session state, config, etc.). | ||
| * Sets the COPILOT_HOME environment variable on the spawned runtime. | ||
| * When not set, the runtime defaults to ~/.copilot. | ||
| * Ignored when connecting to an existing runtime via {@link RuntimeConnection.forUri}. | ||
| */ | ||
| logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all"; | ||
| baseDirectory?: string; | ||
| /** | ||
| * Auto-start the CLI server on first use | ||
| * @default true | ||
| * Log level for the Copilot runtime. When omitted, the runtime uses its | ||
| * own default (currently `"info"`). | ||
| */ | ||
| autoStart?: boolean; | ||
| logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all"; | ||
| /** | ||
| * @deprecated This option has no effect and will be removed in a future release. | ||
| * Environment variables to pass to the runtime process. If not set, inherits process.env. | ||
| */ | ||
| autoRestart?: boolean; | ||
| /** | ||
| * Environment variables to pass to the CLI process. If not set, inherits process.env. | ||
| */ | ||
| env?: Record<string, string | undefined>; | ||
| /** | ||
| * GitHub token to use for authentication. | ||
| * When provided, the token is passed to the CLI server via environment variable. | ||
| * When provided, the token is passed to the runtime via environment variable. | ||
| * This takes priority over other authentication methods. | ||
@@ -125,3 +165,3 @@ */ | ||
| * Whether to use the logged-in user for authentication. | ||
| * When true, the CLI server will attempt to use stored OAuth tokens or gh CLI auth. | ||
| * When true, the runtime will attempt to use stored OAuth tokens or gh CLI auth. | ||
| * When false, only explicit tokens (gitHubToken or environment variables) are used. | ||
@@ -134,3 +174,3 @@ * @default true (but defaults to false when gitHubToken is provided) | ||
| * When provided, client.listModels() calls this handler instead of | ||
| * querying the CLI server. Useful in BYOK mode to return models | ||
| * querying the runtime. Useful in BYOK mode to return models | ||
| * available from your custom provider. | ||
@@ -140,5 +180,5 @@ */ | ||
| /** | ||
| * OpenTelemetry configuration for the CLI process. | ||
| * OpenTelemetry configuration for the runtime process. | ||
| * When provided, the corresponding OTel environment variables are set | ||
| * on the spawned CLI server. | ||
| * on the spawned runtime. | ||
| */ | ||
@@ -182,4 +222,3 @@ telemetry?: TelemetryConfig; | ||
| * Set to 0 or omit to disable (sessions live indefinitely). | ||
| * This option is only used when the SDK spawns the CLI process; it is ignored | ||
| * when connecting to an external server via {@link cliUrl}. | ||
| * Ignored when connecting to an existing runtime via {@link RuntimeConnection.forUri}. | ||
| * @default undefined (disabled) | ||
@@ -189,17 +228,9 @@ */ | ||
| /** | ||
| * Connection token for the headless CLI server (TCP only). When the SDK | ||
| * spawns its own CLI in TCP mode and this is omitted, a UUID is generated | ||
| * automatically so the loopback listener is safe by default. Rejected with | ||
| * `useStdio: true` (stdio is pre-authenticated by transport). | ||
| */ | ||
| tcpConnectionToken?: string; | ||
| /** | ||
| * Enable remote session support (Mission Control integration). | ||
| * When true, sessions in a GitHub repository working directory are | ||
| * accessible from GitHub web and mobile. | ||
| * This option is only used when the SDK spawns the CLI process; it is ignored | ||
| * when connecting to an external server via {@link cliUrl}. | ||
| * Ignored when connecting to an existing runtime via {@link RuntimeConnection.forUri}. | ||
| * @default false | ||
| */ | ||
| remote?: boolean; | ||
| enableRemoteSessions?: boolean; | ||
| } | ||
@@ -216,2 +247,3 @@ /** | ||
| }; | ||
| export type ToolTelemetry = Record<string, Record<string, unknown> | undefined>; | ||
| export type ToolResultObject = { | ||
@@ -223,3 +255,3 @@ textResultForLlm: string; | ||
| sessionLog?: string; | ||
| toolTelemetry?: Record<string, unknown>; | ||
| toolTelemetry?: ToolTelemetry; | ||
| }; | ||
@@ -492,3 +524,3 @@ export type ToolResult = string | ToolResultObject; | ||
| */ | ||
| export interface InputOptions { | ||
| export interface UiInputOptions { | ||
| /** Title label for the input field. */ | ||
@@ -534,3 +566,3 @@ title?: string; | ||
| */ | ||
| input(message: string, options?: InputOptions): Promise<string | null>; | ||
| input(message: string, options?: UiInputOptions): Promise<string | null>; | ||
| } | ||
@@ -634,9 +666,16 @@ export interface ToolCallRequestPayload { | ||
| /** | ||
| * Permission request types from the server | ||
| * Permission request types from the server. This is the generated | ||
| * discriminated union from the runtime schema — switch on `kind` to | ||
| * access the variant-specific fields (e.g. shell `commands`, write | ||
| * `fileName`/`diff`, mcp `toolName`/`args`). | ||
| */ | ||
| export interface PermissionRequest { | ||
| kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"; | ||
| toolCallId?: string; | ||
| } | ||
| export type { PermissionRequest } from "./generated/session-events.js"; | ||
| import type { PermissionRequest } from "./generated/session-events.js"; | ||
| import type { PermissionDecisionRequest } from "./generated/rpc.js"; | ||
| /** | ||
| * Permission decision result returned from a {@link PermissionHandler}. | ||
| * The discriminated `kind` field selects the decision. Variant-specific | ||
| * fields (e.g. `feedback` on `{ kind: "reject" }`) come from the generated | ||
| * `PermissionDecisionRequest["result"]` union. | ||
| */ | ||
| export type PermissionRequestResult = PermissionDecisionRequest["result"] | { | ||
@@ -743,4 +782,5 @@ kind: "no-result"; | ||
| sessionId: string; | ||
| timestamp: number; | ||
| cwd: string; | ||
| /** Time at which the hook event was emitted by the runtime. */ | ||
| timestamp: Date; | ||
| workingDirectory: string; | ||
| } | ||
@@ -771,2 +811,30 @@ /** | ||
| /** | ||
| * Input for pre-MCP-tool-call hook | ||
| */ | ||
| export interface PreMcpToolCallHookInput extends BaseHookInput { | ||
| toolCallId?: string; | ||
| serverName: string; | ||
| toolName: string; | ||
| arguments: unknown; | ||
| _meta?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Output for pre-MCP-tool-call hook | ||
| */ | ||
| export interface PreMcpToolCallHookOutput { | ||
| /** | ||
| * Hook-controlled metadata to use for the outgoing MCP request. | ||
| * - undefined/absent: preserve the current request `_meta` | ||
| * - object: use this object as request `_meta` | ||
| * - null: omit `_meta` | ||
| */ | ||
| metaToUse?: Record<string, unknown> | null; | ||
| } | ||
| /** | ||
| * Handler for pre-MCP-tool-call hook | ||
| */ | ||
| export type PreMcpToolCallHandler = (input: PreMcpToolCallHookInput, invocation: { | ||
| sessionId: string; | ||
| }) => Promise<PreMcpToolCallHookOutput | void> | PreMcpToolCallHookOutput | void; | ||
| /** | ||
| * Input for post-tool-use hook | ||
@@ -887,2 +955,6 @@ */ | ||
| /** | ||
| * Called before an MCP tool is called | ||
| */ | ||
| onPreMcpToolCall?: PreMcpToolCallHandler; | ||
| /** | ||
| * Called after a tool is executed | ||
@@ -913,5 +985,7 @@ */ | ||
| /** | ||
| * List of tools to include from this server. [] means none. "*" means all. | ||
| * List of tools to include from this server. | ||
| * `undefined` (the default) or `["*"]` means include all tools. | ||
| * `[]` means include none. | ||
| */ | ||
| tools: string[]; | ||
| tools?: string[]; | ||
| /** | ||
@@ -938,3 +1012,6 @@ * Indicates the server type: "stdio" for local/subprocess servers, "http"/"sse" for remote servers. | ||
| env?: Record<string, string>; | ||
| cwd?: string; | ||
| /** | ||
| * Working directory for the server process. | ||
| */ | ||
| workingDirectory?: string; | ||
| } | ||
@@ -1050,9 +1127,9 @@ /** | ||
| export type ReasoningEffort = "low" | "medium" | "high" | "xhigh"; | ||
| export interface SessionConfig { | ||
| /** | ||
| * Shared configuration fields used by both {@link SessionConfig} (for | ||
| * creating a new session) and {@link ResumeSessionConfig} (for resuming | ||
| * an existing one). | ||
| */ | ||
| export interface SessionConfigBase { | ||
| /** | ||
| * Optional custom session ID | ||
| * If not provided, server will generate one | ||
| */ | ||
| sessionId?: string; | ||
| /** | ||
| * Client name to identify the application using the SDK. | ||
@@ -1152,3 +1229,3 @@ * Included in the User-Agent header for API requests. | ||
| */ | ||
| onExitPlanMode?: ExitPlanModeHandler; | ||
| onExitPlanModeRequest?: ExitPlanModeHandler; | ||
| /** | ||
@@ -1158,3 +1235,3 @@ * Handler for auto-mode-switch requests from the agent. | ||
| */ | ||
| onAutoModeSwitch?: AutoModeSwitchHandler; | ||
| onAutoModeSwitchRequest?: AutoModeSwitchHandler; | ||
| /** | ||
@@ -1170,2 +1247,9 @@ * Hook handlers for intercepting session lifecycle events. | ||
| workingDirectory?: string; | ||
| /** | ||
| * Enable streaming of assistant message and reasoning chunks. | ||
| * When true, ephemeral assistant.message_delta and assistant.reasoning_delta | ||
| * events are sent as the response is generated. Clients should accumulate | ||
| * deltaContent values to build the full response. | ||
| * @default false | ||
| */ | ||
| streaming?: boolean; | ||
@@ -1241,7 +1325,2 @@ /** | ||
| /** | ||
| * Creates a remote session in the cloud instead of a local session. | ||
| * The optional repository is associated with the cloud session. | ||
| */ | ||
| cloud?: CloudSessionOptions; | ||
| /** | ||
| * Optional event handler that is registered on the session before the | ||
@@ -1260,9 +1339,24 @@ * session.create RPC is issued. This guarantees that early events emitted | ||
| */ | ||
| createSessionFsHandler?: (session: CopilotSession) => SessionFsProvider; | ||
| createSessionFsProvider?: (session: CopilotSession) => SessionFsProvider; | ||
| } | ||
| /** | ||
| * Configuration for resuming a session | ||
| * Configuration for creating a new session via {@link CopilotClient.createSession}. | ||
| */ | ||
| export type ResumeSessionConfig = Pick<SessionConfig, "clientName" | "model" | "tools" | "commands" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "enableSessionTelemetry" | "modelCapabilities" | "streaming" | "includeSubAgentStreamingEvents" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "onElicitationRequest" | "onExitPlanMode" | "onAutoModeSwitch" | "hooks" | "workingDirectory" | "configDir" | "enableConfigDiscovery" | "mcpServers" | "customAgents" | "defaultAgent" | "agent" | "skillDirectories" | "instructionDirectories" | "disabledSkills" | "infiniteSessions" | "gitHubToken" | "remoteSession" | "onEvent" | "createSessionFsHandler"> & { | ||
| export interface SessionConfig extends SessionConfigBase { | ||
| /** | ||
| * Optional custom session ID. If not provided, the server generates one. | ||
| */ | ||
| sessionId?: string; | ||
| /** | ||
| * Creates a remote session in the cloud instead of a local session. | ||
| * The optional repository is associated with the cloud session. | ||
| */ | ||
| cloud?: CloudSessionOptions; | ||
| } | ||
| /** | ||
| * Configuration for resuming an existing session via | ||
| * {@link CopilotClient.resumeSession}. | ||
| */ | ||
| export interface ResumeSessionConfig extends SessionConfigBase { | ||
| /** | ||
| * When true, skips emitting the session.resume event. | ||
@@ -1272,3 +1366,3 @@ * Useful for reconnecting to a session without triggering resume-related side effects. | ||
| */ | ||
| disableResume?: boolean; | ||
| suppressResumeEvent?: boolean; | ||
| /** | ||
@@ -1286,3 +1380,3 @@ * When true, the runtime continues any tool calls or permission prompts that were | ||
| continuePendingWork?: boolean; | ||
| }; | ||
| } | ||
| /** | ||
@@ -1347,3 +1441,3 @@ * Configuration for a custom API provider. | ||
| */ | ||
| maxInputTokens?: number; | ||
| maxPromptTokens?: number; | ||
| /** | ||
@@ -1433,3 +1527,3 @@ * Overrides the resolved model's default max output tokens. When hit, the | ||
| /** Working directory where the session was created */ | ||
| cwd: string; | ||
| workingDirectory: string; | ||
| /** Git repository root (if in a git repo) */ | ||
@@ -1477,4 +1571,4 @@ gitRoot?: string; | ||
| export interface SessionListFilter { | ||
| /** Filter by exact cwd match */ | ||
| cwd?: string; | ||
| /** Filter by exact working directory match */ | ||
| workingDirectory?: string; | ||
| /** Filter by git root */ | ||
@@ -1496,3 +1590,3 @@ gitRoot?: string; | ||
| isRemote: boolean; | ||
| /** Working directory context (cwd, git info) from session creation */ | ||
| /** Working directory context (working directory, git info) from session creation */ | ||
| context?: SessionContext; | ||
@@ -1582,31 +1676,64 @@ } | ||
| /** | ||
| * Types of session lifecycle events | ||
| * Types of session lifecycle events. | ||
| */ | ||
| export type SessionLifecycleEventType = "session.created" | "session.deleted" | "session.updated" | "session.foreground" | "session.background"; | ||
| /** | ||
| * Session lifecycle event notification | ||
| * Sent when sessions are created, deleted, updated, or change foreground/background state | ||
| * Metadata payload for session lifecycle events. Not present on | ||
| * `session.deleted` events. | ||
| */ | ||
| export interface SessionLifecycleEvent { | ||
| /** Type of lifecycle event */ | ||
| type: SessionLifecycleEventType; | ||
| /** ID of the session this event relates to */ | ||
| export interface SessionLifecycleEventMetadata { | ||
| /** Time the session was created. */ | ||
| startTime: Date; | ||
| /** Time the session was last modified. */ | ||
| modifiedTime: Date; | ||
| /** Human-readable summary of the session, if available. */ | ||
| summary?: string; | ||
| } | ||
| /** Base shape shared by every lifecycle event variant. */ | ||
| interface SessionLifecycleEventBase { | ||
| /** ID of the session this event relates to. */ | ||
| sessionId: string; | ||
| /** Session metadata (not included for deleted sessions) */ | ||
| metadata?: { | ||
| startTime: string; | ||
| modifiedTime: string; | ||
| summary?: string; | ||
| }; | ||
| /** Session metadata (not included for `session.deleted`). */ | ||
| metadata?: SessionLifecycleEventMetadata; | ||
| } | ||
| /** Emitted when a new session is created. */ | ||
| export interface SessionCreatedEvent extends SessionLifecycleEventBase { | ||
| type: "session.created"; | ||
| metadata: SessionLifecycleEventMetadata; | ||
| } | ||
| /** Emitted when a session is deleted. The metadata field is omitted. */ | ||
| export interface SessionDeletedEvent extends SessionLifecycleEventBase { | ||
| type: "session.deleted"; | ||
| metadata?: undefined; | ||
| } | ||
| /** Emitted when a session's metadata is updated. */ | ||
| export interface SessionUpdatedEvent extends SessionLifecycleEventBase { | ||
| type: "session.updated"; | ||
| metadata: SessionLifecycleEventMetadata; | ||
| } | ||
| /** Emitted when a session is brought to the foreground (TUI+server mode). */ | ||
| export interface SessionForegroundEvent extends SessionLifecycleEventBase { | ||
| type: "session.foreground"; | ||
| metadata: SessionLifecycleEventMetadata; | ||
| } | ||
| /** Emitted when a session is moved to the background (TUI+server mode). */ | ||
| export interface SessionBackgroundEvent extends SessionLifecycleEventBase { | ||
| type: "session.background"; | ||
| metadata: SessionLifecycleEventMetadata; | ||
| } | ||
| /** | ||
| * Handler for session lifecycle events | ||
| * Discriminated union of all session lifecycle events emitted in TUI+server mode. | ||
| * Switch on `type` to access the variant-specific metadata. | ||
| */ | ||
| export type SessionLifecycleEvent = SessionCreatedEvent | SessionDeletedEvent | SessionUpdatedEvent | SessionForegroundEvent | SessionBackgroundEvent; | ||
| /** | ||
| * Handler for session lifecycle events. | ||
| */ | ||
| export type SessionLifecycleHandler = (event: SessionLifecycleEvent) => void; | ||
| /** | ||
| * Typed handler for specific session lifecycle event types | ||
| * Typed handler for specific session lifecycle event types. | ||
| */ | ||
| export type TypedSessionLifecycleHandler<K extends SessionLifecycleEventType> = (event: SessionLifecycleEvent & { | ||
| export type TypedSessionLifecycleHandler<K extends SessionLifecycleEventType> = (event: Extract<SessionLifecycleEvent, { | ||
| type: K; | ||
| }) => void; | ||
| }>) => void; | ||
| /** | ||
@@ -1613,0 +1740,0 @@ * Information about the foreground session in TUI+server mode |
+29
-0
| import { createSessionFsAdapter } from "./sessionFsProvider.js"; | ||
| const RuntimeConnection = { | ||
| /** | ||
| * Spawn a runtime child process and communicate over its stdin/stdout. | ||
| * This is the default if no {@link CopilotClientOptions.connection} is set. | ||
| */ | ||
| forStdio(opts = {}) { | ||
| return { kind: "stdio", path: opts.path, args: opts.args }; | ||
| }, | ||
| /** | ||
| * Spawn a runtime child process that listens on a TCP socket and connect to it. | ||
| */ | ||
| forTcp(opts = {}) { | ||
| return { | ||
| kind: "tcp", | ||
| port: opts.port, | ||
| connectionToken: opts.connectionToken, | ||
| path: opts.path, | ||
| args: opts.args | ||
| }; | ||
| }, | ||
| /** | ||
| * Connect to an already-running runtime at the given URL. The SDK does not | ||
| * spawn a process in this mode. | ||
| */ | ||
| forUri(url, opts = {}) { | ||
| return { kind: "uri", url, connectionToken: opts.connectionToken }; | ||
| } | ||
| }; | ||
| function convertMcpCallToolResult(callResult) { | ||
@@ -66,2 +94,3 @@ const textParts = []; | ||
| export { | ||
| RuntimeConnection, | ||
| SYSTEM_PROMPT_SECTIONS, | ||
@@ -68,0 +97,0 @@ approveAll, |
+2
-2
@@ -7,3 +7,3 @@ { | ||
| }, | ||
| "version": "1.0.0-beta.5", | ||
| "version": "1.0.0-beta.6", | ||
| "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", | ||
@@ -60,3 +60,3 @@ "main": "./dist/cjs/index.js", | ||
| "dependencies": { | ||
| "@github/copilot": "^1.0.51", | ||
| "@github/copilot": "^1.0.52-1", | ||
| "vscode-jsonrpc": "^8.2.1", | ||
@@ -63,0 +63,0 @@ "zod": "^4.3.6" |
+22
-23
@@ -82,14 +82,13 @@ # Copilot SDK for Node.js/TypeScript | ||
| - `cliPath?: string` - Path to CLI executable (default: uses COPILOT_CLI_PATH env var or bundled instance) | ||
| - `cliArgs?: string[]` - Extra arguments prepended before SDK-managed flags (e.g. `["./dist-cli/index.js"]` when using `node`) | ||
| - `cliUrl?: string` - URL of existing CLI server to connect to (e.g., `"localhost:8080"`, `"http://127.0.0.1:9000"`, or just `"8080"`). When provided, the client will not spawn a CLI process. | ||
| - `port?: number` - Server port (default: 0 for random) | ||
| - `useStdio?: boolean` - Use stdio transport instead of TCP (default: true) | ||
| - `logLevel?: string` - Log level (default: "info") | ||
| - `autoStart?: boolean` - Auto-start server (default: true) | ||
| - `connection?: RuntimeConnection` - How to connect to the Copilot runtime. Construct via the factory functions on `RuntimeConnection`: | ||
| - `RuntimeConnection.forStdio({ path?, args? })` (default) — spawn the runtime and communicate over its stdin/stdout. | ||
| - `RuntimeConnection.forTcp({ port?, connectionToken?, path?, args? })` — spawn the runtime as a TCP server. | ||
| - `RuntimeConnection.forUri(url, { connectionToken? })` — connect to an already-running runtime (mutually exclusive with `gitHubToken`/`useLoggedInUser`). | ||
| - `cwd?: string` - Working directory for the runtime process (default: current process cwd). | ||
| - `baseDirectory?: string` - Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned runtime. When not set, the runtime defaults to `~/.copilot`. Ignored when connecting via `RuntimeConnection.forUri`. | ||
| - `logLevel?: string` - Log level. When omitted, the runtime uses its own default (currently `"info"`). | ||
| - `gitHubToken?: string` - GitHub token for authentication. When provided, takes priority over other auth methods. | ||
| - `useLoggedInUser?: boolean` - Whether to use logged-in user for authentication (default: true, but false when `gitHubToken` is provided). Cannot be used with `cliUrl`. | ||
| - `copilotHome?: string` - Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned CLI process. When not set, the CLI defaults to `~/.copilot`. Useful in restricted environments where only specific directories are writable. Ignored when using `cliUrl`. | ||
| - `telemetry?: TelemetryConfig` - OpenTelemetry configuration for the CLI process. Providing this object enables telemetry — no separate flag needed. See [Telemetry](#telemetry) below. | ||
| - `onGetTraceContext?: TraceContextProvider` - Advanced: callback for linking your application's own OpenTelemetry spans into the same distributed trace as the CLI's spans. Not needed for normal telemetry collection. See [Telemetry](#telemetry) below. | ||
| - `useLoggedInUser?: boolean` - Whether to use logged-in user for authentication (default: true, but false when `gitHubToken` is provided). Cannot be used with `RuntimeConnection.forUri`. | ||
| - `telemetry?: TelemetryConfig` - OpenTelemetry configuration for the runtime process. Providing this object enables telemetry — no separate flag needed. See [Telemetry](#telemetry) below. | ||
| - `onGetTraceContext?: TraceContextProvider` - Advanced: callback for linking your application's own OpenTelemetry spans into the same distributed trace as the runtime's spans. Not needed for normal telemetry collection. See [Telemetry](#telemetry) below. | ||
@@ -177,3 +176,3 @@ #### Methods | ||
| ```typescript | ||
| const unsubscribe = client.on("session.foreground", (event) => { | ||
| const unsubscribe = client.onLifecycle("session.foreground", (event) => { | ||
| console.log(`Session ${event.sessionId} is now in foreground`); | ||
@@ -188,3 +187,3 @@ }); | ||
| ```typescript | ||
| const unsubscribe = client.on((event) => { | ||
| const unsubscribe = client.onLifecycle((event) => { | ||
| console.log(`${event.type}: ${event.sessionId}`); | ||
@@ -283,3 +282,3 @@ }); | ||
| ##### `getMessages(): Promise<SessionEvent[]>` | ||
| ##### `getEvents(): Promise<SessionEvent[]>` | ||
@@ -422,3 +421,3 @@ Get all events/messages from this session. | ||
| ```typescript | ||
| const client = new CopilotClient({ autoStart: false }); | ||
| const client = new CopilotClient({}); | ||
@@ -864,11 +863,11 @@ // Start manually | ||
| | Kind | Meaning | Extra fields | | ||
| | ------------------------ | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | ||
| | `"approve-once"` | Allow this single request | — | | ||
| | `"approve-for-session"` | Allow this request and remember the approval for the rest of the session | `approval?` (rule to remember), `domain?` (for URL approvals) | | ||
| | Kind | Meaning | Extra fields | | ||
| | ------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | ||
| | `"approve-once"` | Allow this single request | — | | ||
| | `"approve-for-session"` | Allow this request and remember the approval for the rest of the session | `approval?` (rule to remember), `domain?` (for URL approvals) | | ||
| | `"approve-for-location"` | Allow this request and persist the approval for this project location (git root or cwd) | `approval` (rule to persist), `locationKey` (location to persist under) | | ||
| | `"approve-permanently"` | Allow this request and persist the approval across sessions (currently used for URL domains) | `domain` (URL domain to approve) | | ||
| | `"reject"` | Deny the request | `feedback?` (optional string surfaced to the agent) | | ||
| | `"user-not-available"` | Deny the request because no user is available to confirm it | — | | ||
| | `"no-result"` | Leave the request unanswered (only valid with protocol v1; rejected by protocol v2 servers) | — | | ||
| | `"reject"` | Deny the request | `feedback?` (optional string surfaced to the agent) | | ||
| | `"user-not-available"` | Deny the request because no user is available to confirm it | — | | ||
| | `"no-result"` | Leave the request unanswered (only valid with protocol v1; rejected by protocol v2 servers) | — | | ||
@@ -1035,3 +1034,3 @@ ### Resuming Sessions | ||
| - Node.js >= 18.0.0 | ||
| - GitHub Copilot CLI installed and in PATH (or provide custom `cliPath`) | ||
| - GitHub Copilot CLI installed and in PATH (or provide a custom `connection`) | ||
@@ -1038,0 +1037,0 @@ ## License |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1005213
0.11%27291
0.32%54
-3.57%1033
-0.1%Updated