@github/copilot-sdk 0.1.24 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +61 -3
- package/dist/generated/rpc.d.ts +141 -0
- package/dist/generated/rpc.js +17 -0
- package/dist/generated/session-events.d.ts +32 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,6 +10,19 @@ TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
|
|
|
10
10
|
npm install @github/copilot-sdk
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## Run the Sample
|
|
14
|
+
|
|
15
|
+
Try the interactive chat sample (from the repo root):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd nodejs
|
|
19
|
+
npm ci
|
|
20
|
+
npm run build
|
|
21
|
+
cd samples
|
|
22
|
+
npm install
|
|
23
|
+
npm start
|
|
24
|
+
```
|
|
25
|
+
|
|
13
26
|
## Quick Start
|
|
14
27
|
|
|
15
28
|
```typescript
|
package/dist/client.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare class CopilotClient {
|
|
|
9
9
|
private actualHost;
|
|
10
10
|
private state;
|
|
11
11
|
private sessions;
|
|
12
|
+
private stderrBuffer;
|
|
12
13
|
private options;
|
|
13
14
|
private isExternalServer;
|
|
14
15
|
private forceStopping;
|
|
@@ -17,6 +18,7 @@ export declare class CopilotClient {
|
|
|
17
18
|
private sessionLifecycleHandlers;
|
|
18
19
|
private typedLifecycleHandlers;
|
|
19
20
|
private _rpc;
|
|
21
|
+
private processExitPromise;
|
|
20
22
|
/**
|
|
21
23
|
* Typed server-scoped RPC methods.
|
|
22
24
|
* @throws Error if the client is not connected
|
package/dist/client.js
CHANGED
|
@@ -34,6 +34,8 @@ class CopilotClient {
|
|
|
34
34
|
actualHost = "localhost";
|
|
35
35
|
state = "disconnected";
|
|
36
36
|
sessions = /* @__PURE__ */ new Map();
|
|
37
|
+
stderrBuffer = "";
|
|
38
|
+
// Captures CLI stderr for error messages
|
|
37
39
|
options;
|
|
38
40
|
isExternalServer = false;
|
|
39
41
|
forceStopping = false;
|
|
@@ -42,6 +44,8 @@ class CopilotClient {
|
|
|
42
44
|
sessionLifecycleHandlers = /* @__PURE__ */ new Set();
|
|
43
45
|
typedLifecycleHandlers = /* @__PURE__ */ new Map();
|
|
44
46
|
_rpc = null;
|
|
47
|
+
processExitPromise = null;
|
|
48
|
+
// Rejects when CLI process exits
|
|
45
49
|
/**
|
|
46
50
|
* Typed server-scoped RPC methods.
|
|
47
51
|
* @throws Error if the client is not connected
|
|
@@ -251,6 +255,8 @@ class CopilotClient {
|
|
|
251
255
|
}
|
|
252
256
|
this.state = "disconnected";
|
|
253
257
|
this.actualPort = null;
|
|
258
|
+
this.stderrBuffer = "";
|
|
259
|
+
this.processExitPromise = null;
|
|
254
260
|
return errors;
|
|
255
261
|
}
|
|
256
262
|
/**
|
|
@@ -306,6 +312,8 @@ class CopilotClient {
|
|
|
306
312
|
}
|
|
307
313
|
this.state = "disconnected";
|
|
308
314
|
this.actualPort = null;
|
|
315
|
+
this.stderrBuffer = "";
|
|
316
|
+
this.processExitPromise = null;
|
|
309
317
|
}
|
|
310
318
|
/**
|
|
311
319
|
* Creates a new conversation session with the Copilot CLI.
|
|
@@ -362,6 +370,7 @@ class CopilotClient {
|
|
|
362
370
|
workingDirectory: config.workingDirectory,
|
|
363
371
|
streaming: config.streaming,
|
|
364
372
|
mcpServers: config.mcpServers,
|
|
373
|
+
envValueMode: "direct",
|
|
365
374
|
customAgents: config.customAgents,
|
|
366
375
|
configDir: config.configDir,
|
|
367
376
|
skillDirectories: config.skillDirectories,
|
|
@@ -434,6 +443,7 @@ class CopilotClient {
|
|
|
434
443
|
configDir: config.configDir,
|
|
435
444
|
streaming: config.streaming,
|
|
436
445
|
mcpServers: config.mcpServers,
|
|
446
|
+
envValueMode: "direct",
|
|
437
447
|
customAgents: config.customAgents,
|
|
438
448
|
skillDirectories: config.skillDirectories,
|
|
439
449
|
disabledSkills: config.disabledSkills,
|
|
@@ -545,7 +555,12 @@ class CopilotClient {
|
|
|
545
555
|
*/
|
|
546
556
|
async verifyProtocolVersion() {
|
|
547
557
|
const expectedVersion = getSdkProtocolVersion();
|
|
548
|
-
|
|
558
|
+
let pingResult;
|
|
559
|
+
if (this.processExitPromise) {
|
|
560
|
+
pingResult = await Promise.race([this.ping(), this.processExitPromise]);
|
|
561
|
+
} else {
|
|
562
|
+
pingResult = await this.ping();
|
|
563
|
+
}
|
|
549
564
|
const serverVersion = pingResult.protocolVersion;
|
|
550
565
|
if (serverVersion === void 0) {
|
|
551
566
|
throw new Error(
|
|
@@ -714,6 +729,7 @@ class CopilotClient {
|
|
|
714
729
|
*/
|
|
715
730
|
async startCLIServer() {
|
|
716
731
|
return new Promise((resolve, reject) => {
|
|
732
|
+
this.stderrBuffer = "";
|
|
717
733
|
const args = [
|
|
718
734
|
...this.options.cliArgs,
|
|
719
735
|
"--headless",
|
|
@@ -776,6 +792,7 @@ class CopilotClient {
|
|
|
776
792
|
});
|
|
777
793
|
}
|
|
778
794
|
this.cliProcess.stderr?.on("data", (data) => {
|
|
795
|
+
this.stderrBuffer += data.toString();
|
|
779
796
|
const lines = data.toString().split("\n");
|
|
780
797
|
for (const line of lines) {
|
|
781
798
|
if (line.trim()) {
|
|
@@ -787,13 +804,54 @@ class CopilotClient {
|
|
|
787
804
|
this.cliProcess.on("error", (error) => {
|
|
788
805
|
if (!resolved) {
|
|
789
806
|
resolved = true;
|
|
790
|
-
|
|
807
|
+
const stderrOutput = this.stderrBuffer.trim();
|
|
808
|
+
if (stderrOutput) {
|
|
809
|
+
reject(
|
|
810
|
+
new Error(
|
|
811
|
+
`Failed to start CLI server: ${error.message}
|
|
812
|
+
stderr: ${stderrOutput}`
|
|
813
|
+
)
|
|
814
|
+
);
|
|
815
|
+
} else {
|
|
816
|
+
reject(new Error(`Failed to start CLI server: ${error.message}`));
|
|
817
|
+
}
|
|
791
818
|
}
|
|
792
819
|
});
|
|
820
|
+
this.processExitPromise = new Promise((_, rejectProcessExit) => {
|
|
821
|
+
this.cliProcess.on("exit", (code) => {
|
|
822
|
+
setTimeout(() => {
|
|
823
|
+
const stderrOutput = this.stderrBuffer.trim();
|
|
824
|
+
if (stderrOutput) {
|
|
825
|
+
rejectProcessExit(
|
|
826
|
+
new Error(
|
|
827
|
+
`CLI server exited with code ${code}
|
|
828
|
+
stderr: ${stderrOutput}`
|
|
829
|
+
)
|
|
830
|
+
);
|
|
831
|
+
} else {
|
|
832
|
+
rejectProcessExit(
|
|
833
|
+
new Error(`CLI server exited unexpectedly with code ${code}`)
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
}, 50);
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
this.processExitPromise.catch(() => {
|
|
840
|
+
});
|
|
793
841
|
this.cliProcess.on("exit", (code) => {
|
|
794
842
|
if (!resolved) {
|
|
795
843
|
resolved = true;
|
|
796
|
-
|
|
844
|
+
const stderrOutput = this.stderrBuffer.trim();
|
|
845
|
+
if (stderrOutput) {
|
|
846
|
+
reject(
|
|
847
|
+
new Error(
|
|
848
|
+
`CLI server exited with code ${code}
|
|
849
|
+
stderr: ${stderrOutput}`
|
|
850
|
+
)
|
|
851
|
+
);
|
|
852
|
+
} else {
|
|
853
|
+
reject(new Error(`CLI server exited with code ${code}`));
|
|
854
|
+
}
|
|
797
855
|
} else if (this.options.autoRestart && this.state === "connected") {
|
|
798
856
|
void this.reconnect();
|
|
799
857
|
}
|
package/dist/generated/rpc.d.ts
CHANGED
|
@@ -163,6 +163,130 @@ export interface SessionModelSwitchToParams {
|
|
|
163
163
|
sessionId: string;
|
|
164
164
|
modelId: string;
|
|
165
165
|
}
|
|
166
|
+
export interface SessionModeGetResult {
|
|
167
|
+
/**
|
|
168
|
+
* The current agent mode.
|
|
169
|
+
*/
|
|
170
|
+
mode: "interactive" | "plan" | "autopilot";
|
|
171
|
+
}
|
|
172
|
+
export interface SessionModeGetParams {
|
|
173
|
+
/**
|
|
174
|
+
* Target session identifier
|
|
175
|
+
*/
|
|
176
|
+
sessionId: string;
|
|
177
|
+
}
|
|
178
|
+
export interface SessionModeSetResult {
|
|
179
|
+
/**
|
|
180
|
+
* The agent mode after switching.
|
|
181
|
+
*/
|
|
182
|
+
mode: "interactive" | "plan" | "autopilot";
|
|
183
|
+
}
|
|
184
|
+
export interface SessionModeSetParams {
|
|
185
|
+
/**
|
|
186
|
+
* Target session identifier
|
|
187
|
+
*/
|
|
188
|
+
sessionId: string;
|
|
189
|
+
/**
|
|
190
|
+
* The mode to switch to. Valid values: "interactive", "plan", "autopilot".
|
|
191
|
+
*/
|
|
192
|
+
mode: "interactive" | "plan" | "autopilot";
|
|
193
|
+
}
|
|
194
|
+
export interface SessionPlanReadResult {
|
|
195
|
+
/**
|
|
196
|
+
* Whether plan.md exists in the workspace
|
|
197
|
+
*/
|
|
198
|
+
exists: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* The content of plan.md, or null if it does not exist
|
|
201
|
+
*/
|
|
202
|
+
content: string | null;
|
|
203
|
+
}
|
|
204
|
+
export interface SessionPlanReadParams {
|
|
205
|
+
/**
|
|
206
|
+
* Target session identifier
|
|
207
|
+
*/
|
|
208
|
+
sessionId: string;
|
|
209
|
+
}
|
|
210
|
+
export interface SessionPlanUpdateResult {
|
|
211
|
+
}
|
|
212
|
+
export interface SessionPlanUpdateParams {
|
|
213
|
+
/**
|
|
214
|
+
* Target session identifier
|
|
215
|
+
*/
|
|
216
|
+
sessionId: string;
|
|
217
|
+
/**
|
|
218
|
+
* The new content for plan.md
|
|
219
|
+
*/
|
|
220
|
+
content: string;
|
|
221
|
+
}
|
|
222
|
+
export interface SessionPlanDeleteResult {
|
|
223
|
+
}
|
|
224
|
+
export interface SessionPlanDeleteParams {
|
|
225
|
+
/**
|
|
226
|
+
* Target session identifier
|
|
227
|
+
*/
|
|
228
|
+
sessionId: string;
|
|
229
|
+
}
|
|
230
|
+
export interface SessionWorkspaceListFilesResult {
|
|
231
|
+
/**
|
|
232
|
+
* Relative file paths in the workspace files directory
|
|
233
|
+
*/
|
|
234
|
+
files: string[];
|
|
235
|
+
}
|
|
236
|
+
export interface SessionWorkspaceListFilesParams {
|
|
237
|
+
/**
|
|
238
|
+
* Target session identifier
|
|
239
|
+
*/
|
|
240
|
+
sessionId: string;
|
|
241
|
+
}
|
|
242
|
+
export interface SessionWorkspaceReadFileResult {
|
|
243
|
+
/**
|
|
244
|
+
* File content as a UTF-8 string
|
|
245
|
+
*/
|
|
246
|
+
content: string;
|
|
247
|
+
}
|
|
248
|
+
export interface SessionWorkspaceReadFileParams {
|
|
249
|
+
/**
|
|
250
|
+
* Target session identifier
|
|
251
|
+
*/
|
|
252
|
+
sessionId: string;
|
|
253
|
+
/**
|
|
254
|
+
* Relative path within the workspace files directory
|
|
255
|
+
*/
|
|
256
|
+
path: string;
|
|
257
|
+
}
|
|
258
|
+
export interface SessionWorkspaceCreateFileResult {
|
|
259
|
+
}
|
|
260
|
+
export interface SessionWorkspaceCreateFileParams {
|
|
261
|
+
/**
|
|
262
|
+
* Target session identifier
|
|
263
|
+
*/
|
|
264
|
+
sessionId: string;
|
|
265
|
+
/**
|
|
266
|
+
* Relative path within the workspace files directory
|
|
267
|
+
*/
|
|
268
|
+
path: string;
|
|
269
|
+
/**
|
|
270
|
+
* File content to write as a UTF-8 string
|
|
271
|
+
*/
|
|
272
|
+
content: string;
|
|
273
|
+
}
|
|
274
|
+
export interface SessionFleetStartResult {
|
|
275
|
+
/**
|
|
276
|
+
* Whether fleet mode was successfully activated
|
|
277
|
+
*/
|
|
278
|
+
started: boolean;
|
|
279
|
+
}
|
|
280
|
+
export interface SessionFleetStartParams {
|
|
281
|
+
/**
|
|
282
|
+
* Target session identifier
|
|
283
|
+
*/
|
|
284
|
+
sessionId: string;
|
|
285
|
+
/**
|
|
286
|
+
* Optional user prompt to combine with fleet instructions
|
|
287
|
+
*/
|
|
288
|
+
prompt?: string;
|
|
289
|
+
}
|
|
166
290
|
/** Create typed server-scoped RPC methods (no session required). */
|
|
167
291
|
export declare function createServerRpc(connection: MessageConnection): {
|
|
168
292
|
ping: (params: PingParams) => Promise<PingResult>;
|
|
@@ -182,4 +306,21 @@ export declare function createSessionRpc(connection: MessageConnection, sessionI
|
|
|
182
306
|
getCurrent: () => Promise<SessionModelGetCurrentResult>;
|
|
183
307
|
switchTo: (params: Omit<SessionModelSwitchToParams, "sessionId">) => Promise<SessionModelSwitchToResult>;
|
|
184
308
|
};
|
|
309
|
+
mode: {
|
|
310
|
+
get: () => Promise<SessionModeGetResult>;
|
|
311
|
+
set: (params: Omit<SessionModeSetParams, "sessionId">) => Promise<SessionModeSetResult>;
|
|
312
|
+
};
|
|
313
|
+
plan: {
|
|
314
|
+
read: () => Promise<SessionPlanReadResult>;
|
|
315
|
+
update: (params: Omit<SessionPlanUpdateParams, "sessionId">) => Promise<SessionPlanUpdateResult>;
|
|
316
|
+
delete: () => Promise<SessionPlanDeleteResult>;
|
|
317
|
+
};
|
|
318
|
+
workspace: {
|
|
319
|
+
listFiles: () => Promise<SessionWorkspaceListFilesResult>;
|
|
320
|
+
readFile: (params: Omit<SessionWorkspaceReadFileParams, "sessionId">) => Promise<SessionWorkspaceReadFileResult>;
|
|
321
|
+
createFile: (params: Omit<SessionWorkspaceCreateFileParams, "sessionId">) => Promise<SessionWorkspaceCreateFileResult>;
|
|
322
|
+
};
|
|
323
|
+
fleet: {
|
|
324
|
+
start: (params: Omit<SessionFleetStartParams, "sessionId">) => Promise<SessionFleetStartResult>;
|
|
325
|
+
};
|
|
185
326
|
};
|
package/dist/generated/rpc.js
CHANGED
|
@@ -17,6 +17,23 @@ function createSessionRpc(connection, sessionId) {
|
|
|
17
17
|
model: {
|
|
18
18
|
getCurrent: async () => connection.sendRequest("session.model.getCurrent", { sessionId }),
|
|
19
19
|
switchTo: async (params) => connection.sendRequest("session.model.switchTo", { sessionId, ...params })
|
|
20
|
+
},
|
|
21
|
+
mode: {
|
|
22
|
+
get: async () => connection.sendRequest("session.mode.get", { sessionId }),
|
|
23
|
+
set: async (params) => connection.sendRequest("session.mode.set", { sessionId, ...params })
|
|
24
|
+
},
|
|
25
|
+
plan: {
|
|
26
|
+
read: async () => connection.sendRequest("session.plan.read", { sessionId }),
|
|
27
|
+
update: async (params) => connection.sendRequest("session.plan.update", { sessionId, ...params }),
|
|
28
|
+
delete: async () => connection.sendRequest("session.plan.delete", { sessionId })
|
|
29
|
+
},
|
|
30
|
+
workspace: {
|
|
31
|
+
listFiles: async () => connection.sendRequest("session.workspace.listFiles", { sessionId }),
|
|
32
|
+
readFile: async (params) => connection.sendRequest("session.workspace.readFile", { sessionId, ...params }),
|
|
33
|
+
createFile: async (params) => connection.sendRequest("session.workspace.createFile", { sessionId, ...params })
|
|
34
|
+
},
|
|
35
|
+
fleet: {
|
|
36
|
+
start: async (params) => connection.sendRequest("session.fleet.start", { sessionId, ...params })
|
|
20
37
|
}
|
|
21
38
|
};
|
|
22
39
|
}
|
|
@@ -97,6 +97,38 @@ export type SessionEvent = {
|
|
|
97
97
|
previousModel?: string;
|
|
98
98
|
newModel: string;
|
|
99
99
|
};
|
|
100
|
+
} | {
|
|
101
|
+
id: string;
|
|
102
|
+
timestamp: string;
|
|
103
|
+
parentId: string | null;
|
|
104
|
+
ephemeral?: boolean;
|
|
105
|
+
type: "session.mode_changed";
|
|
106
|
+
data: {
|
|
107
|
+
previousMode: string;
|
|
108
|
+
newMode: string;
|
|
109
|
+
};
|
|
110
|
+
} | {
|
|
111
|
+
id: string;
|
|
112
|
+
timestamp: string;
|
|
113
|
+
parentId: string | null;
|
|
114
|
+
ephemeral?: boolean;
|
|
115
|
+
type: "session.plan_changed";
|
|
116
|
+
data: {
|
|
117
|
+
operation: "create" | "update" | "delete";
|
|
118
|
+
};
|
|
119
|
+
} | {
|
|
120
|
+
id: string;
|
|
121
|
+
timestamp: string;
|
|
122
|
+
parentId: string | null;
|
|
123
|
+
ephemeral?: boolean;
|
|
124
|
+
type: "session.workspace_file_changed";
|
|
125
|
+
data: {
|
|
126
|
+
/**
|
|
127
|
+
* Relative path within the workspace files directory
|
|
128
|
+
*/
|
|
129
|
+
path: string;
|
|
130
|
+
operation: "create" | "update";
|
|
131
|
+
};
|
|
100
132
|
} | {
|
|
101
133
|
id: string;
|
|
102
134
|
timestamp: string;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "git",
|
|
5
5
|
"url": "https://github.com/github/copilot-sdk.git"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.25",
|
|
8
8
|
"description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"author": "GitHub",
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@github/copilot": "^0.0.
|
|
43
|
+
"@github/copilot": "^0.0.411",
|
|
44
44
|
"vscode-jsonrpc": "^8.2.1",
|
|
45
45
|
"zod": "^4.3.6"
|
|
46
46
|
},
|