@github/copilot-sdk 1.0.13 → 1.0.14-preview.0
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 +16 -0
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +19 -3
- package/dist/cjs/ffiRuntimeHost.js +140 -55
- package/dist/cjs/generated/rpc.js +59 -7
- package/dist/cjs/session.js +1 -0
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +19 -3
- package/dist/ffiRuntimeHost.d.ts +8 -2
- package/dist/ffiRuntimeHost.js +140 -55
- package/dist/generated/rpc.d.ts +706 -45
- package/dist/generated/rpc.js +59 -7
- package/dist/generated/session-events.d.ts +461 -17
- package/dist/index.d.ts +1 -1
- package/dist/session.js +1 -0
- package/dist/types.d.ts +18 -1
- package/package.json +12 -11
package/dist/ffiRuntimeHost.js
CHANGED
|
@@ -4,6 +4,7 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { PassThrough, Writable } from "node:stream";
|
|
5
5
|
const SYMBOL_PREFIX = "copilot_runtime_";
|
|
6
6
|
const KEEP_ALIVE_INTERVAL_MS = 1 << 30;
|
|
7
|
+
const CLEANUP_RETRY_INTERVAL_MS = 100;
|
|
7
8
|
let loadedLibraryPath;
|
|
8
9
|
let loadedLibrary;
|
|
9
10
|
function loadLibrary(libraryPath) {
|
|
@@ -96,12 +97,16 @@ class FfiRuntimeHost {
|
|
|
96
97
|
cliEntrypoint;
|
|
97
98
|
environment;
|
|
98
99
|
args;
|
|
100
|
+
static quarantinedHosts = /* @__PURE__ */ new Set();
|
|
99
101
|
lib;
|
|
100
102
|
serverId = 0;
|
|
101
103
|
connectionId = 0;
|
|
102
104
|
disposed = false;
|
|
105
|
+
starting = false;
|
|
103
106
|
outboundCallback;
|
|
104
107
|
keepAliveTimer;
|
|
108
|
+
cleanupRetryTimer;
|
|
109
|
+
cleanupInProgress = false;
|
|
105
110
|
/** The stream JSON-RPC reads server→client frames from. */
|
|
106
111
|
receiveStream;
|
|
107
112
|
/** The stream JSON-RPC writes client→server frames to. */
|
|
@@ -123,49 +128,65 @@ class FfiRuntimeHost {
|
|
|
123
128
|
}
|
|
124
129
|
/** Starts the in-process Rust runtime and opens the FFI JSON-RPC connection. */
|
|
125
130
|
async start() {
|
|
131
|
+
if (this.disposed) {
|
|
132
|
+
throw new Error("The in-process runtime host is disposed.");
|
|
133
|
+
}
|
|
134
|
+
this.starting = true;
|
|
126
135
|
const argvJson = buildArgvJson(this.cliEntrypoint, this.args);
|
|
127
136
|
const envJson = buildEnvJson(this.environment);
|
|
128
|
-
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
try {
|
|
138
|
+
this.serverId = await new Promise((resolvePromise, rejectPromise) => {
|
|
139
|
+
this.lib.hostStart.async(
|
|
140
|
+
argvJson,
|
|
141
|
+
argvJson.length,
|
|
142
|
+
envJson,
|
|
143
|
+
envJson ? envJson.length : 0,
|
|
144
|
+
(error, result) => {
|
|
145
|
+
if (error) {
|
|
146
|
+
rejectPromise(error);
|
|
147
|
+
} else {
|
|
148
|
+
resolvePromise(result);
|
|
149
|
+
}
|
|
139
150
|
}
|
|
140
|
-
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
if (!this.serverId) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`copilot_runtime_host_start failed (library '${this.libraryPath}').`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (this.disposed) {
|
|
159
|
+
throw new Error("The in-process runtime host was disposed during startup.");
|
|
160
|
+
}
|
|
161
|
+
this.outboundCallback = koffi.register(
|
|
162
|
+
(_userData, bytesPtr, bytesLen) => this.feedInbound(bytesPtr, bytesLen),
|
|
163
|
+
this.lib.outboundCallbackType
|
|
141
164
|
);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
this.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
this.connectionId = this.lib.connectionOpen(
|
|
166
|
+
this.serverId,
|
|
167
|
+
this.outboundCallback,
|
|
168
|
+
null,
|
|
169
|
+
null,
|
|
170
|
+
0,
|
|
171
|
+
null,
|
|
172
|
+
0,
|
|
173
|
+
null,
|
|
174
|
+
0
|
|
175
|
+
);
|
|
176
|
+
if (!this.connectionId) {
|
|
177
|
+
this.unregisterCallback();
|
|
178
|
+
this.lib.hostShutdown(this.serverId);
|
|
179
|
+
this.serverId = 0;
|
|
180
|
+
throw new Error("copilot_runtime_connection_open failed.");
|
|
181
|
+
}
|
|
182
|
+
this.keepAliveTimer = setInterval(() => {
|
|
183
|
+
}, KEEP_ALIVE_INTERVAL_MS);
|
|
184
|
+
} finally {
|
|
185
|
+
this.starting = false;
|
|
186
|
+
if (this.disposed) {
|
|
187
|
+
void this.tryFinalizeCleanup();
|
|
188
|
+
}
|
|
166
189
|
}
|
|
167
|
-
this.keepAliveTimer = setInterval(() => {
|
|
168
|
-
}, KEEP_ALIVE_INTERVAL_MS);
|
|
169
190
|
}
|
|
170
191
|
writeFrame(frame) {
|
|
171
192
|
if (this.disposed || !this.connectionId) {
|
|
@@ -204,41 +225,105 @@ class FfiRuntimeHost {
|
|
|
204
225
|
}
|
|
205
226
|
unregisterCallback() {
|
|
206
227
|
if (this.outboundCallback === void 0) {
|
|
207
|
-
return;
|
|
228
|
+
return true;
|
|
208
229
|
}
|
|
209
230
|
const callback = this.outboundCallback;
|
|
210
|
-
this.outboundCallback = void 0;
|
|
211
231
|
try {
|
|
212
232
|
koffi.unregister(callback);
|
|
213
|
-
|
|
233
|
+
this.outboundCallback = void 0;
|
|
234
|
+
return true;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error(
|
|
237
|
+
`Failed to unregister in-process FFI callback: ${error instanceof Error ? error.stack ?? error.message : String(error)}`
|
|
238
|
+
);
|
|
239
|
+
FfiRuntimeHost.quarantinedHosts.add(this);
|
|
240
|
+
return false;
|
|
214
241
|
}
|
|
215
242
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (this.disposed) {
|
|
243
|
+
scheduleCleanupRetry() {
|
|
244
|
+
if (this.cleanupRetryTimer !== void 0) {
|
|
219
245
|
return;
|
|
220
246
|
}
|
|
221
|
-
this.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
247
|
+
this.cleanupRetryTimer = setTimeout(() => {
|
|
248
|
+
this.cleanupRetryTimer = void 0;
|
|
249
|
+
void this.tryFinalizeCleanup();
|
|
250
|
+
}, CLEANUP_RETRY_INTERVAL_MS);
|
|
251
|
+
}
|
|
252
|
+
async tryFinalizeCleanup() {
|
|
253
|
+
if (this.cleanupInProgress) {
|
|
254
|
+
this.scheduleCleanupRetry();
|
|
255
|
+
return;
|
|
225
256
|
}
|
|
257
|
+
this.cleanupInProgress = true;
|
|
226
258
|
try {
|
|
227
259
|
if (this.connectionId) {
|
|
228
|
-
|
|
260
|
+
let closed = false;
|
|
261
|
+
try {
|
|
262
|
+
closed = await new Promise((resolvePromise, rejectPromise) => {
|
|
263
|
+
this.lib.connectionClose.async(
|
|
264
|
+
this.connectionId,
|
|
265
|
+
(error, result) => {
|
|
266
|
+
if (error) {
|
|
267
|
+
rejectPromise(error);
|
|
268
|
+
} else {
|
|
269
|
+
resolvePromise(result);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(
|
|
276
|
+
`Failed to close in-process FFI connection: ${error instanceof Error ? error.stack ?? error.message : String(error)}`
|
|
277
|
+
);
|
|
278
|
+
FfiRuntimeHost.quarantinedHosts.add(this);
|
|
279
|
+
if (this.keepAliveTimer !== void 0) {
|
|
280
|
+
clearInterval(this.keepAliveTimer);
|
|
281
|
+
this.keepAliveTimer = void 0;
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (!closed) {
|
|
286
|
+
this.scheduleCleanupRetry();
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
229
289
|
this.connectionId = 0;
|
|
230
290
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
291
|
+
const callbackUnregistered = this.unregisterCallback();
|
|
292
|
+
if (this.keepAliveTimer !== void 0) {
|
|
293
|
+
clearInterval(this.keepAliveTimer);
|
|
294
|
+
this.keepAliveTimer = void 0;
|
|
295
|
+
}
|
|
234
296
|
if (this.serverId) {
|
|
235
|
-
|
|
297
|
+
try {
|
|
298
|
+
if (!this.lib.hostShutdown(this.serverId)) {
|
|
299
|
+
console.error(
|
|
300
|
+
`In-process FFI host shutdown did not recognize server ${this.serverId}.`
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error(
|
|
305
|
+
`Failed to shut down in-process FFI host: ${error instanceof Error ? error.stack ?? error.message : String(error)}`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
236
308
|
this.serverId = 0;
|
|
237
309
|
}
|
|
238
|
-
|
|
310
|
+
if (callbackUnregistered) {
|
|
311
|
+
FfiRuntimeHost.quarantinedHosts.delete(this);
|
|
312
|
+
}
|
|
313
|
+
} finally {
|
|
314
|
+
this.cleanupInProgress = false;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/** Awaits the initial cleanup attempt; a non-quiescent close is retried in the background. */
|
|
318
|
+
async dispose() {
|
|
319
|
+
if (this.disposed) {
|
|
320
|
+
return;
|
|
239
321
|
}
|
|
322
|
+
this.disposed = true;
|
|
240
323
|
this.receiveStream.end();
|
|
241
|
-
this.
|
|
324
|
+
if (!this.starting) {
|
|
325
|
+
await this.tryFinalizeCleanup();
|
|
326
|
+
}
|
|
242
327
|
}
|
|
243
328
|
}
|
|
244
329
|
export {
|