Copilot SDK for Node.js/TypeScript
TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
Note: This SDK is in public preview and may change in breaking ways.
Installation
npm install @github/copilot-sdk
Run the Sample
Try the interactive chat sample (from the repo root):
cd nodejs
npm ci
npm run build
cd samples
npm install
npm start
Quick Start
import { CopilotClient, approveAll } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
});
const done = new Promise<void>((resolve) => {
session.on("assistant.message", (event) => {
console.log(event.data.content);
});
session.on("session.idle", () => {
resolve();
});
});
await session.send({ prompt: "What is 2+2?" });
await done;
await session.disconnect();
await client.stop();
Sessions also support Symbol.asyncDispose for use with await using (TypeScript 5.2+/Node.js 18.0+):
await using session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
});
API Reference
CopilotClient
Constructor
new CopilotClient(options?: CopilotClientOptions)
Options:
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)
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.
telemetry?: TelemetryConfig - OpenTelemetry configuration for the CLI process. Providing this object enables telemetry — no separate flag needed. See 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 below.
Methods
start(): Promise<void>
Start the CLI server and establish connection.
stop(): Promise<Error[]>
Stop the server and close all sessions. Returns a list of any errors encountered during cleanup.
forceStop(): Promise<void>
Force stop the CLI server without graceful cleanup. Use when stop() takes too long.
createSession(config?: SessionConfig): Promise<CopilotSession>
Create a new conversation session.
Config:
sessionId?: string - Custom session ID.
model?: string - Model to use ("gpt-5", "claude-sonnet-4.5", etc.). Required when using custom provider.
reasoningEffort?: "low" | "medium" | "high" | "xhigh" - Reasoning effort level for models that support it. Use listModels() to check which models support this option.
tools?: Tool[] - Custom tools exposed to the CLI
systemMessage?: SystemMessageConfig - System message customization (see below)
infiniteSessions?: InfiniteSessionConfig - Configure automatic context compaction (see below)
provider?: ProviderConfig - Custom API provider configuration (BYOK - Bring Your Own Key). See Custom Providers section.
onPermissionRequest: PermissionHandler - Required. Handler called before each tool execution to approve or deny it. Use approveAll to allow everything, or provide a custom function for fine-grained control. See Permission Handling section.
onUserInputRequest?: UserInputHandler - Handler for user input requests from the agent. Enables the ask_user tool. See User Input Requests section.
onElicitationRequest?: ElicitationHandler - Handler for elicitation requests dispatched by the server. Enables this client to present form-based UI dialogs on behalf of the agent or other session participants. See Elicitation Requests section.
hooks?: SessionHooks - Hook handlers for session lifecycle events. See Session Hooks section.
resumeSession(sessionId: string, config?: ResumeSessionConfig): Promise<CopilotSession>
Resume an existing session. Returns the session with workspacePath populated if infinite sessions were enabled.
ping(message?: string): Promise<{ message: string; timestamp: number }>
Ping the server to check connectivity.
getState(): ConnectionState
Get current connection state.
listSessions(filter?: SessionListFilter): Promise<SessionMetadata[]>
List all available sessions. Optionally filter by working directory context.
SessionMetadata:
sessionId: string - Unique session identifier
startTime: Date - When the session was created
modifiedTime: Date - When the session was last modified
summary?: string - Optional session summary
isRemote: boolean - Whether the session is remote
context?: SessionContext - Working directory context from session creation
SessionContext:
cwd: string - Working directory where the session was created
gitRoot?: string - Git repository root (if in a git repo)
repository?: string - GitHub repository in "owner/repo" format
branch?: string - Current git branch
deleteSession(sessionId: string): Promise<void>
Delete a session and its data from disk.
getForegroundSessionId(): Promise<string | undefined>
Get the ID of the session currently displayed in the TUI. Only available when connecting to a server running in TUI+server mode (--ui-server).
setForegroundSessionId(sessionId: string): Promise<void>
Request the TUI to switch to displaying the specified session. Only available in TUI+server mode.
on(eventType: SessionLifecycleEventType, handler): () => void
Subscribe to a specific session lifecycle event type. Returns an unsubscribe function.
const unsubscribe = client.on("session.foreground", (event) => {
console.log(`Session ${event.sessionId} is now in foreground`);
});
on(handler: SessionLifecycleHandler): () => void
Subscribe to all session lifecycle events. Returns an unsubscribe function.
const unsubscribe = client.on((event) => {
console.log(`${event.type}: ${event.sessionId}`);
});
Lifecycle Event Types:
session.created - A new session was created
session.deleted - A session was deleted
session.updated - A session was updated (e.g., new messages)
session.foreground - A session became the foreground session in TUI
session.background - A session is no longer the foreground session
CopilotSession
Represents a single conversation session.
Properties
sessionId: string
The unique identifier for this session.
workspacePath?: string
Path to the session workspace directory when infinite sessions are enabled. Contains checkpoints/, plan.md, and files/ subdirectories. Undefined if infinite sessions are disabled.
Methods
send(options: MessageOptions): Promise<string>
Send a message to the session. Returns immediately after the message is queued; use event handlers or sendAndWait() to wait for completion.
Options:
prompt: string - The message/prompt to send
attachments?: Array<{type, path, displayName}> - File attachments
mode?: "enqueue" | "immediate" - Delivery mode
Returns the message ID.
sendAndWait(options: MessageOptions, timeout?: number): Promise<AssistantMessageEvent | undefined>
Send a message and wait until the session becomes idle.
Options:
prompt: string - The message/prompt to send
attachments?: Array<{type, path, displayName}> - File attachments
mode?: "enqueue" | "immediate" - Delivery mode
timeout?: number - Optional timeout in milliseconds
Returns the final assistant message event, or undefined if none was received.
on(eventType: string, handler: TypedSessionEventHandler): () => void
Subscribe to a specific event type. The handler receives properly typed events.
session.on("assistant.message", (event) => {
console.log(event.data.content);
});
session.on("session.idle", () => {
console.log("Session is idle");
});
session.on("assistant.message_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
on(handler: SessionEventHandler): () => void
Subscribe to all session events. Returns an unsubscribe function.
const unsubscribe = session.on((event) => {
console.log(event.type, event);
});
unsubscribe();
abort(): Promise<void>
Abort the currently processing message in this session.
getMessages(): Promise<SessionEvent[]>
Get all events/messages from this session.
disconnect(): Promise<void>
Disconnect the session and free resources. Session data on disk is preserved for later resumption.
capabilities: SessionCapabilities
Host capabilities reported when the session was created or resumed. Use this to check feature support before calling capability-gated APIs.
if (session.capabilities.ui?.elicitation) {
const ok = await session.ui.confirm("Deploy?");
}
Capabilities may update during the session. For example, when another client joins or disconnects with an elicitation handler. The SDK automatically applies capabilities.changed events, so this property always reflects the current state.
ui: SessionUiApi
Interactive UI methods for showing dialogs to the user. Only available when the CLI host supports elicitation (session.capabilities.ui?.elicitation === true). See UI Elicitation for full details.
destroy(): Promise<void> (deprecated)
Deprecated — use disconnect() instead.
Event Types
Sessions emit various events during processing:
user.message - User message added
assistant.message - Assistant response
assistant.message_delta - Streaming response chunk
tool.execution_start - Tool execution started
tool.execution_complete - Tool execution completed
command.execute - Command dispatch request (handled internally by the SDK)
commands.changed - Command registration changed
- And more...
See SessionEvent type in the source for full details.
Image Support
The SDK supports image attachments via the attachments parameter. You can attach images by providing their file path, or by passing base64-encoded data directly using a blob attachment:
await session.send({
prompt: "What's in this image?",
attachments: [
{
type: "file",
path: "/path/to/image.jpg",
},
],
});
await session.send({
prompt: "What's in this image?",
attachments: [
{
type: "blob",
data: base64ImageData,
mimeType: "image/png",
},
],
});
Supported image formats include JPG, PNG, GIF, and other common image types. The agent's view tool can also read images directly from the filesystem, so you can also ask questions like:
await session.send({ prompt: "What does the most recent jpg in this directory portray?" });
Streaming
Enable streaming to receive assistant response chunks as they're generated:
const session = await client.createSession({
model: "gpt-5",
streaming: true,
});
const done = new Promise<void>((resolve) => {
session.on("assistant.message_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
session.on("assistant.reasoning_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
session.on("assistant.message", (event) => {
console.log("\n--- Final message ---");
console.log(event.data.content);
});
session.on("assistant.reasoning", (event) => {
console.log("--- Reasoning ---");
console.log(event.data.content);
});
session.on("session.idle", () => {
resolve();
});
});
await session.send({ prompt: "Tell me a short story" });
await done;
When streaming: true:
assistant.message_delta events are sent with deltaContent containing incremental text
assistant.reasoning_delta events are sent with deltaContent for reasoning/chain-of-thought (model-dependent)
- Accumulate
deltaContent values to build the full response progressively
- The final
assistant.message and assistant.reasoning events contain the complete content
Note: assistant.message and assistant.reasoning (final events) are always sent regardless of streaming setting.
Advanced Usage
Manual Server Control
const client = new CopilotClient({ autoStart: false });
await client.start();
await client.stop();
Tools
You can let the CLI call back into your process when the model needs capabilities you own. Use defineTool with Zod schemas for type-safe tool definitions:
import { z } from "zod";
import { CopilotClient, defineTool } from "@github/copilot-sdk";
const session = await client.createSession({
model: "gpt-5",
tools: [
defineTool("lookup_issue", {
description: "Fetch issue details from our tracker",
parameters: z.object({
id: z.string().describe("Issue identifier"),
}),
handler: async ({ id }) => {
const issue = await fetchIssue(id);
return issue;
},
}),
],
});
When Copilot invokes lookup_issue, the client automatically runs your handler and responds to the CLI. Handlers can return any JSON-serializable value (automatically wrapped), a simple string, or a ToolResultObject for full control over result metadata. Raw JSON schemas are also supported if Zod isn't desired.
Overriding Built-in Tools
If you register a tool with the same name as a built-in CLI tool (e.g. edit_file, read_file), the SDK will throw an error unless you explicitly opt in by setting overridesBuiltInTool: true. This flag signals that you intend to replace the built-in tool with your custom implementation.
defineTool("edit_file", {
description: "Custom file editor with project-specific validation",
parameters: z.object({ path: z.string(), content: z.string() }),
overridesBuiltInTool: true,
handler: async ({ path, content }) => {
},
});
Skipping Permission Prompts
Set skipPermission: true on a tool definition to allow it to execute without triggering a permission prompt:
defineTool("safe_lookup", {
description: "A read-only lookup that needs no confirmation",
parameters: z.object({ id: z.string() }),
skipPermission: true,
handler: async ({ id }) => {
},
});
Commands
Register slash commands so that users of the CLI's TUI can invoke custom actions via /commandName. Each command has a name, optional description, and a handler called when the user executes it.
const session = await client.createSession({
onPermissionRequest: approveAll,
commands: [
{
name: "deploy",
description: "Deploy the app to production",
handler: async ({ commandName, args }) => {
console.log(`Deploying with args: ${args}`);
},
},
],
});
When the user types /deploy staging in the CLI, the SDK receives a command.execute event, routes it to your handler, and automatically responds to the CLI. If the handler throws, the error message is forwarded.
Commands are sent to the CLI on both createSession and resumeSession, so you can update the command set when resuming.
UI Elicitation
When the session has elicitation support — either from the CLI's TUI or from another client that registered an onElicitationRequest handler (see Elicitation Requests) — the SDK can request interactive form dialogs from the user. The session.ui object provides convenience methods built on a single generic elicitation RPC.
Capability check: Elicitation is only available when at least one connected participant advertises support. Always check session.capabilities.ui?.elicitation before calling UI methods — this property updates automatically as participants join and leave.
const session = await client.createSession({ onPermissionRequest: approveAll });
if (session.capabilities.ui?.elicitation) {
const ok = await session.ui.confirm("Deploy to production?");
const env = await session.ui.select("Pick environment", ["production", "staging", "dev"]);
const name = await session.ui.input("Project name:", {
title: "Name",
minLength: 1,
maxLength: 50,
});
const result = await session.ui.elicitation({
message: "Configure deployment",
requestedSchema: {
type: "object",
properties: {
region: { type: "string", enum: ["us-east", "eu-west"] },
dryRun: { type: "boolean", default: true },
},
required: ["region"],
},
});
}
All UI methods throw if elicitation is not supported by the host.
System Message Customization
Control the system prompt using systemMessage in session config:
const session = await client.createSession({
model: "gpt-5",
systemMessage: {
content: `
<workflow_rules>
- Always check for security vulnerabilities
- Suggest performance improvements when applicable
</workflow_rules>
`,
},
});
The SDK auto-injects environment context, tool instructions, and security guardrails. The default CLI persona is preserved, and your content is appended after SDK-managed sections. To change the persona or fully redefine the prompt, use mode: "replace" or mode: "customize".
Customize Mode
Use mode: "customize" to selectively override individual sections of the prompt while preserving the rest:
import { SYSTEM_PROMPT_SECTIONS } from "@github/copilot-sdk";
import type { SectionOverride, SystemPromptSection } from "@github/copilot-sdk";
const session = await client.createSession({
model: "gpt-5",
systemMessage: {
mode: "customize",
sections: {
tone: {
action: "replace",
content: "Respond in a warm, professional tone. Be thorough in explanations.",
},
code_change_rules: { action: "remove" },
guidelines: { action: "append", content: "\n* Always cite data sources" },
},
content: "Focus on financial analysis and reporting.",
},
});
Available section IDs: identity, tone, tool_efficiency, environment_context, code_change_rules, guidelines, safety, tool_instructions, custom_instructions, last_instructions. Use the SYSTEM_PROMPT_SECTIONS constant for descriptions of each section.
Each section override supports four actions:
replace — Replace the section content entirely
remove — Remove the section from the prompt
append — Add content after the existing section
prepend — Add content before the existing section
Unknown section IDs are handled gracefully: content from replace/append/prepend overrides is appended to additional instructions, and remove overrides are silently ignored.
Replace Mode
For full control (removes all guardrails), use mode: "replace":
const session = await client.createSession({
model: "gpt-5",
systemMessage: {
mode: "replace",
content: "You are a helpful assistant.",
},
});
Infinite Sessions
By default, sessions use infinite sessions which automatically manage context window limits through background compaction and persist state to a workspace directory.
const session = await client.createSession({ model: "gpt-5" });
console.log(session.workspacePath);
const session = await client.createSession({
model: "gpt-5",
infiniteSessions: {
enabled: true,
backgroundCompactionThreshold: 0.8,
bufferExhaustionThreshold: 0.95,
},
});
const session = await client.createSession({
model: "gpt-5",
infiniteSessions: { enabled: false },
});
When enabled, sessions emit compaction events:
session.compaction_start - Background compaction started
session.compaction_complete - Compaction finished (includes token counts)
Multiple Sessions
const session1 = await client.createSession({ model: "gpt-5" });
const session2 = await client.createSession({ model: "claude-sonnet-4.5" });
await session1.sendAndWait({ prompt: "Hello from session 1" });
await session2.sendAndWait({ prompt: "Hello from session 2" });
Custom Session IDs
const session = await client.createSession({
sessionId: "my-custom-session-id",
model: "gpt-5",
});
File Attachments
await session.send({
prompt: "Analyze this file",
attachments: [
{
type: "file",
path: "/path/to/file.js",
displayName: "My File",
},
],
});
Custom Providers
The SDK supports custom OpenAI-compatible API providers (BYOK - Bring Your Own Key), including local providers like Ollama. When using a custom provider, you must specify the model explicitly.
ProviderConfig:
type?: "openai" | "azure" | "anthropic" - Provider type (default: "openai")
baseUrl: string - API endpoint URL (required)
apiKey?: string - API key (optional for local providers like Ollama)
bearerToken?: string - Bearer token for authentication (takes precedence over apiKey)
wireApi?: "completions" | "responses" - API format for OpenAI/Azure (default: "completions")
azure?.apiVersion?: string - Azure API version (default: "2024-10-21")
Example with Ollama:
const session = await client.createSession({
model: "deepseek-coder-v2:16b",
provider: {
type: "openai",
baseUrl: "http://localhost:11434/v1",
},
});
await session.sendAndWait({ prompt: "Hello!" });
Example with custom OpenAI-compatible API:
const session = await client.createSession({
model: "gpt-4",
provider: {
type: "openai",
baseUrl: "https://my-api.example.com/v1",
apiKey: process.env.MY_API_KEY,
},
});
Example with Azure OpenAI:
const session = await client.createSession({
model: "gpt-4",
provider: {
type: "azure",
baseUrl: "https://my-resource.openai.azure.com",
apiKey: process.env.AZURE_OPENAI_KEY,
azure: {
apiVersion: "2024-10-21",
},
},
});
Important notes:
- When using a custom provider, the
model parameter is required. The SDK will throw an error if no model is specified.
- For Azure OpenAI endpoints (
*.openai.azure.com), you must use type: "azure", not type: "openai".
- The
baseUrl should be just the host (e.g., https://my-resource.openai.azure.com). Do not include /openai/v1 in the URL - the SDK handles path construction automatically.
Telemetry
The SDK supports OpenTelemetry for distributed tracing. Provide a telemetry config to enable trace export from the CLI process — this is all most users need:
const client = new CopilotClient({
telemetry: {
otlpEndpoint: "http://localhost:4318",
},
});
With just this configuration, the CLI emits spans for every session, message, and tool call to your collector. No additional dependencies or setup required.
TelemetryConfig options:
otlpEndpoint?: string - OTLP HTTP endpoint URL
filePath?: string - File path for JSON-lines trace output
exporterType?: string - "otlp-http" or "file"
sourceName?: string - Instrumentation scope name
captureContent?: boolean - Whether to capture message content
Advanced: Trace Context Propagation
You don't need this for normal telemetry collection. The telemetry config above is sufficient to get full traces from the CLI.
onGetTraceContext is only needed if your application creates its own OpenTelemetry spans and you want them to appear in the same distributed trace as the CLI's spans — for example, to nest a "handle tool call" span inside the CLI's "execute tool" span, or to show the SDK call as a child of your application's request-handling span.
If you're already using @opentelemetry/api in your app and want this linkage, provide a callback:
import { propagation, context } from "@opentelemetry/api";
const client = new CopilotClient({
telemetry: { otlpEndpoint: "http://localhost:4318" },
onGetTraceContext: () => {
const carrier: Record<string, string> = {};
propagation.inject(context.active(), carrier);
return carrier;
},
});
Inbound trace context from the CLI is available on the ToolInvocation object passed to tool handlers as traceparent and tracestate fields. See the OpenTelemetry guide for a full wire-up example.
Permission Handling
An onPermissionRequest handler is required whenever you create or resume a session. The handler is called before the agent executes each tool (file writes, shell commands, custom tools, etc.) and must return a decision.
Approve All (simplest)
Use the built-in approveAll helper to allow every tool call without any checks:
import { CopilotClient, approveAll } from "@github/copilot-sdk";
const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
});
Custom Permission Handler
Provide your own function to inspect each request and apply custom logic:
import type { PermissionRequest, PermissionRequestResult } from "@github/copilot-sdk";
const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: (request: PermissionRequest, invocation): PermissionRequestResult => {
if (request.kind === "shell") {
return { kind: "denied-interactively-by-user" };
}
return { kind: "approved" };
},
});
Permission Result Kinds
"approved" | Allow the tool to run |
"denied-interactively-by-user" | User explicitly denied the request |
"denied-no-approval-rule-and-could-not-request-from-user" | No approval rule matched and user could not be asked |
"denied-by-rules" | Denied by a policy rule |
"denied-by-content-exclusion-policy" | Denied due to a content exclusion policy |
"no-result" | Leave the request unanswered (only valid with protocol v1; rejected by protocol v2 servers) |
Resuming Sessions
Pass onPermissionRequest when resuming a session too — it is required:
const session = await client.resumeSession("session-id", {
onPermissionRequest: approveAll,
});
Per-Tool Skip Permission
To let a specific custom tool bypass the permission prompt entirely, set skipPermission: true on the tool definition. See Skipping Permission Prompts under Tools.
User Input Requests
Enable the agent to ask questions to the user using the ask_user tool by providing an onUserInputRequest handler:
const session = await client.createSession({
model: "gpt-5",
onUserInputRequest: async (request, invocation) => {
console.log(`Agent asks: ${request.question}`);
if (request.choices) {
console.log(`Choices: ${request.choices.join(", ")}`);
}
return {
answer: "User's answer here",
wasFreeform: true,
};
},
});
Elicitation Requests
Register an onElicitationRequest handler to let your client act as an elicitation provider — presenting form-based UI dialogs on behalf of the agent. When provided, the server notifies your client whenever a tool or MCP server needs structured user input.
const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
onElicitationRequest: async (context) => {
console.log(`Elicitation from ${context.elicitationSource}: ${context.message}`);
return {
action: "accept",
content: { region: "us-east", dryRun: true },
};
},
});
console.log(session.capabilities.ui?.elicitation);
When onElicitationRequest is provided, the SDK sends requestElicitation: true during session create/resume, which enables session.capabilities.ui.elicitation on the session.
In multi-client scenarios:
- If no connected client was previously providing an elicitation capability, but a new client joins that can, all clients will receive a
capabilities.changed event to notify them that elicitation is now possible. The SDK automatically updates session.capabilities when these events arrive.
- Similarly, if the last elicitation provider disconnects, all clients receive a
capabilities.changed event indicating elicitation is no longer available.
- The server fans out elicitation requests to all connected clients that registered a handler — the first response wins.
Session Hooks
Hook into session lifecycle events by providing handlers in the hooks configuration:
const session = await client.createSession({
model: "gpt-5",
hooks: {
onPreToolUse: async (input, invocation) => {
console.log(`About to run tool: ${input.toolName}`);
return {
permissionDecision: "allow",
modifiedArgs: input.toolArgs,
additionalContext: "Extra context for the model",
};
},
onPostToolUse: async (input, invocation) => {
console.log(`Tool ${input.toolName} completed`);
return {
additionalContext: "Post-execution notes",
};
},
onUserPromptSubmitted: async (input, invocation) => {
console.log(`User prompt: ${input.prompt}`);
return {
modifiedPrompt: input.prompt,
};
},
onSessionStart: async (input, invocation) => {
console.log(`Session started from: ${input.source}`);
return {
additionalContext: "Session initialization context",
};
},
onSessionEnd: async (input, invocation) => {
console.log(`Session ended: ${input.reason}`);
},
onErrorOccurred: async (input, invocation) => {
console.error(`Error in ${input.errorContext}: ${input.error}`);
return {
errorHandling: "retry",
};
},
},
});
Available hooks:
onPreToolUse - Intercept tool calls before execution. Can allow/deny or modify arguments.
onPostToolUse - Process tool results after execution. Can modify results or add context.
onUserPromptSubmitted - Intercept user prompts. Can modify the prompt before processing.
onSessionStart - Run logic when a session starts or resumes.
onSessionEnd - Cleanup or logging when session ends.
onErrorOccurred - Handle errors with retry/skip/abort strategies.
Error Handling
try {
const session = await client.createSession();
await session.send({ prompt: "Hello" });
} catch (error) {
console.error("Error:", error.message);
}
Requirements
- Node.js >= 18.0.0
- GitHub Copilot CLI installed and in PATH (or provide custom
cliPath)
License
MIT