@github/copilot-language-server 1.528.0 → 1.530.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.
@@ -20,13 +20,17 @@ var extension_exports = {};
20
20
  __export(extension_exports, {
21
21
  Canvas: () => import_canvas.Canvas,
22
22
  CanvasError: () => import_canvas.CanvasError,
23
+ FactoryResumeError: () => import_factory.FactoryResumeError,
23
24
  createCanvas: () => import_canvas.createCanvas,
25
+ defineFactory: () => import_factory.defineFactory,
26
+ isFactoryRunTerminal: () => import_factory.isFactoryRunTerminal,
24
27
  joinSession: () => joinSession
25
28
  });
26
29
  module.exports = __toCommonJS(extension_exports);
27
30
  var import_client = require("./client.js");
28
31
  var import_types = require("./types.js");
29
32
  var import_canvas = require("./canvas.js");
33
+ var import_factory = require("./factory.js");
30
34
  async function joinSession(config = {}) {
31
35
  const sessionId = process.env.SESSION_ID;
32
36
  if (!sessionId) {
@@ -35,18 +39,29 @@ async function joinSession(config = {}) {
35
39
  );
36
40
  }
37
41
  const client = new import_client.CopilotClient({ _internalConnection: { kind: "parent-process" } });
38
- const { extensionSdkPath: _stripped, ...rest } = config;
42
+ const {
43
+ extensionSdkPath: _stripped,
44
+ factories,
45
+ ...rest
46
+ } = config;
39
47
  void _stripped;
40
- return client.resumeSession(sessionId, {
41
- ...rest,
42
- onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler,
43
- suppressResumeEvent: config.suppressResumeEvent ?? true
44
- });
48
+ return client.resumeSessionForExtension(
49
+ sessionId,
50
+ {
51
+ ...rest,
52
+ onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler,
53
+ suppressResumeEvent: config.suppressResumeEvent ?? true
54
+ },
55
+ factories
56
+ );
45
57
  }
46
58
  // Annotate the CommonJS export names for ESM import in node:
47
59
  0 && (module.exports = {
48
60
  Canvas,
49
61
  CanvasError,
62
+ FactoryResumeError,
50
63
  createCanvas,
64
+ defineFactory,
65
+ isFactoryRunTerminal,
51
66
  joinSession
52
67
  });
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var factory_exports = {};
20
+ __export(factory_exports, {
21
+ FactoryResumeError: () => FactoryResumeError,
22
+ defineFactory: () => defineFactory,
23
+ getFactoryDefinition: () => getFactoryDefinition,
24
+ isFactoryRunTerminal: () => isFactoryRunTerminal
25
+ });
26
+ module.exports = __toCommonJS(factory_exports);
27
+ const FACTORY_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
28
+ "completed",
29
+ "halted",
30
+ "cancelled",
31
+ "error"
32
+ ]);
33
+ function isFactoryRunTerminal(status) {
34
+ return FACTORY_TERMINAL_STATUSES.has(status);
35
+ }
36
+ class FactoryResumeError extends Error {
37
+ constructor(code, message) {
38
+ super(message);
39
+ this.code = code;
40
+ this.name = "FactoryResumeError";
41
+ }
42
+ code;
43
+ }
44
+ const factoryHandles = /* @__PURE__ */ new WeakMap();
45
+ const MAX_FACTORY_TIMEOUT_SECONDS = 2147483647e-3;
46
+ const NANO_AIU_PER_AIU = 1e9;
47
+ function deepFreeze(value) {
48
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
49
+ Object.freeze(value);
50
+ for (const nested of Object.values(value)) {
51
+ deepFreeze(nested);
52
+ }
53
+ }
54
+ return value;
55
+ }
56
+ function validateLimits(meta) {
57
+ const limits = meta.limits;
58
+ if (!limits) {
59
+ return;
60
+ }
61
+ for (const field of ["maxConcurrentSubagents", "maxTotalSubagents"]) {
62
+ const value = limits[field];
63
+ if (value !== void 0 && (!Number.isInteger(value) || value <= 0)) {
64
+ throw new Error(`Factory limit "${field}" must be a positive integer`);
65
+ }
66
+ }
67
+ if (limits.timeoutSeconds !== void 0 && (!Number.isFinite(limits.timeoutSeconds) || limits.timeoutSeconds <= 0)) {
68
+ throw new Error(
69
+ 'Factory limit "timeoutSeconds" must be a positive, finite number of seconds'
70
+ );
71
+ }
72
+ if (limits.timeoutSeconds !== void 0 && limits.timeoutSeconds > MAX_FACTORY_TIMEOUT_SECONDS) {
73
+ throw new Error(
74
+ `Factory limit "timeoutSeconds" must not exceed ${MAX_FACTORY_TIMEOUT_SECONDS} seconds`
75
+ );
76
+ }
77
+ if (limits.maxAiCredits !== void 0) {
78
+ const maxNanoAiu = Math.round(limits.maxAiCredits * NANO_AIU_PER_AIU);
79
+ if (!Number.isFinite(limits.maxAiCredits) || limits.maxAiCredits <= 0 || !Number.isSafeInteger(maxNanoAiu) || maxNanoAiu < 1) {
80
+ throw new Error(
81
+ 'Factory limit "maxAiCredits" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling'
82
+ );
83
+ }
84
+ }
85
+ }
86
+ function validatePhases(meta) {
87
+ const titles = /* @__PURE__ */ new Set();
88
+ for (const phase of meta.phases) {
89
+ if (phase.title.trim().length === 0) {
90
+ throw new Error("Factory phase titles must not be empty");
91
+ }
92
+ if (titles.has(phase.title)) {
93
+ throw new Error(`Factory phase title "${phase.title}" is declared more than once`);
94
+ }
95
+ titles.add(phase.title);
96
+ }
97
+ }
98
+ function defineFactory(definition) {
99
+ const meta = deepFreeze(structuredClone(definition.meta));
100
+ validateLimits(meta);
101
+ validatePhases(meta);
102
+ const stored = {
103
+ meta,
104
+ run: definition.run
105
+ };
106
+ const handle = Object.freeze({ meta });
107
+ factoryHandles.set(handle, stored);
108
+ return handle;
109
+ }
110
+ function getFactoryDefinition(handle) {
111
+ const definition = factoryHandles.get(handle);
112
+ if (!definition) {
113
+ throw new Error("Invalid factory handle");
114
+ }
115
+ return definition;
116
+ }
117
+ // Annotate the CommonJS export names for ESM import in node:
118
+ 0 && (module.exports = {
119
+ FactoryResumeError,
120
+ defineFactory,
121
+ getFactoryDefinition,
122
+ isFactoryRunTerminal
123
+ });
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var ffiRuntimeHost_exports = {};
30
+ __export(ffiRuntimeHost_exports, {
31
+ FfiRuntimeHost: () => FfiRuntimeHost
32
+ });
33
+ module.exports = __toCommonJS(ffiRuntimeHost_exports);
34
+ var import_node_fs = require("node:fs");
35
+ var import_koffi = __toESM(require("koffi"), 1);
36
+ var import_node_path = require("node:path");
37
+ var import_node_stream = require("node:stream");
38
+ const SYMBOL_PREFIX = "copilot_runtime_";
39
+ const KEEP_ALIVE_INTERVAL_MS = 1 << 30;
40
+ let loadedLibraryPath;
41
+ let loadedLibrary;
42
+ function loadLibrary(libraryPath) {
43
+ if (loadedLibrary) {
44
+ if (loadedLibraryPath !== libraryPath) {
45
+ throw new Error(
46
+ `An in-process FFI runtime library is already loaded from '${loadedLibraryPath}'; loading a different library from '${libraryPath}' in the same process is not supported.`
47
+ );
48
+ }
49
+ return loadedLibrary;
50
+ }
51
+ const lib = import_koffi.default.load(libraryPath);
52
+ const outboundCallbackType = import_koffi.default.pointer(
53
+ import_koffi.default.proto(
54
+ `void ${SYMBOL_PREFIX}outbound(void *userData, uint8 *bytesPtr, size_t bytesLen)`
55
+ )
56
+ );
57
+ loadedLibrary = {
58
+ hostStart: lib.func(`${SYMBOL_PREFIX}host_start`, "uint32", [
59
+ "uint8*",
60
+ "size_t",
61
+ "uint8*",
62
+ "size_t"
63
+ ]),
64
+ hostShutdown: lib.func(`${SYMBOL_PREFIX}host_shutdown`, "bool", ["uint32"]),
65
+ connectionOpen: lib.func(`${SYMBOL_PREFIX}connection_open`, "uint32", [
66
+ "uint32",
67
+ outboundCallbackType,
68
+ "void*",
69
+ "uint8*",
70
+ "size_t",
71
+ "uint8*",
72
+ "size_t",
73
+ "uint8*",
74
+ "size_t"
75
+ ]),
76
+ connectionWrite: lib.func(`${SYMBOL_PREFIX}connection_write`, "bool", [
77
+ "uint32",
78
+ "uint8*",
79
+ "size_t"
80
+ ]),
81
+ connectionClose: lib.func(`${SYMBOL_PREFIX}connection_close`, "bool", ["uint32"]),
82
+ outboundCallbackType
83
+ };
84
+ loadedLibraryPath = libraryPath;
85
+ return loadedLibrary;
86
+ }
87
+ function buildArgvJson(cliEntrypoint, args) {
88
+ const argv = cliEntrypoint.toLowerCase().endsWith(".js") ? ["node", cliEntrypoint, "--embedded-host", "--no-auto-update"] : [cliEntrypoint, "--embedded-host", "--no-auto-update"];
89
+ argv.push(...args);
90
+ return Buffer.from(JSON.stringify(argv), "utf8");
91
+ }
92
+ function buildEnvJson(environment) {
93
+ if (!environment) {
94
+ return null;
95
+ }
96
+ const obj = {};
97
+ for (const [key, value] of Object.entries(environment)) {
98
+ if (value !== void 0) {
99
+ obj[key] = value;
100
+ }
101
+ }
102
+ if (Object.keys(obj).length === 0) {
103
+ return null;
104
+ }
105
+ return Buffer.from(JSON.stringify(obj), "utf8");
106
+ }
107
+ class FfiRuntimeHost {
108
+ constructor(libraryPath, cliEntrypoint, environment, args) {
109
+ this.libraryPath = libraryPath;
110
+ this.cliEntrypoint = cliEntrypoint;
111
+ this.environment = environment;
112
+ this.args = args;
113
+ this.lib = loadLibrary(libraryPath);
114
+ this.receiveStream = new import_node_stream.PassThrough();
115
+ this.sendStream = new import_node_stream.Writable({
116
+ // connection_write enqueues the frame into the runtime's inbound channel and
117
+ // returns immediately, so a synchronous FFI call is sufficient here.
118
+ write: (chunk, _encoding, callback) => {
119
+ try {
120
+ this.writeFrame(chunk);
121
+ callback();
122
+ } catch (error) {
123
+ callback(error);
124
+ }
125
+ }
126
+ });
127
+ }
128
+ libraryPath;
129
+ cliEntrypoint;
130
+ environment;
131
+ args;
132
+ lib;
133
+ serverId = 0;
134
+ connectionId = 0;
135
+ disposed = false;
136
+ outboundCallback;
137
+ keepAliveTimer;
138
+ /** The stream JSON-RPC reads server→client frames from. */
139
+ receiveStream;
140
+ /** The stream JSON-RPC writes client→server frames to. */
141
+ sendStream;
142
+ /**
143
+ * Resolves the cdylib next to the given CLI entrypoint and prepares the FFI host.
144
+ * The cdylib is resolved as `prebuilds/<prebuildsFolder>/runtime.node` relative to
145
+ * the entrypoint directory (the napi-rs `<node-platform>-<arch>` layout, e.g.
146
+ * `linux-x64`). Throws if it cannot be found.
147
+ */
148
+ static create(cliEntrypoint, prebuildsFolder, environment, args) {
149
+ const fullEntrypoint = (0, import_node_path.resolve)(cliEntrypoint);
150
+ const distDir = (0, import_node_path.dirname)(fullEntrypoint);
151
+ const libraryPath = (0, import_node_path.join)(distDir, "prebuilds", prebuildsFolder, "runtime.node");
152
+ if (!(0, import_node_fs.existsSync)(libraryPath)) {
153
+ throw new Error(`FFI runtime library not found. Looked for '${libraryPath}'.`);
154
+ }
155
+ return new FfiRuntimeHost(libraryPath, fullEntrypoint, environment, args);
156
+ }
157
+ /**
158
+ * Starts the in-process runtime: spawns the CLI worker via the native host,
159
+ * waits for readiness, and opens the FFI JSON-RPC connection.
160
+ */
161
+ async start() {
162
+ const argvJson = buildArgvJson(this.cliEntrypoint, this.args);
163
+ const envJson = buildEnvJson(this.environment);
164
+ this.serverId = await new Promise((resolvePromise, rejectPromise) => {
165
+ this.lib.hostStart.async(
166
+ argvJson,
167
+ argvJson.length,
168
+ envJson,
169
+ envJson ? envJson.length : 0,
170
+ (error, result) => {
171
+ if (error) {
172
+ rejectPromise(error);
173
+ } else {
174
+ resolvePromise(result);
175
+ }
176
+ }
177
+ );
178
+ });
179
+ if (!this.serverId) {
180
+ throw new Error(
181
+ `copilot_runtime_host_start failed (library '${this.libraryPath}', entrypoint '${this.cliEntrypoint}').`
182
+ );
183
+ }
184
+ this.outboundCallback = import_koffi.default.register(
185
+ (_userData, bytesPtr, bytesLen) => this.feedInbound(bytesPtr, bytesLen),
186
+ this.lib.outboundCallbackType
187
+ );
188
+ this.connectionId = this.lib.connectionOpen(
189
+ this.serverId,
190
+ this.outboundCallback,
191
+ null,
192
+ null,
193
+ 0,
194
+ null,
195
+ 0,
196
+ null,
197
+ 0
198
+ );
199
+ if (!this.connectionId) {
200
+ this.unregisterCallback();
201
+ this.lib.hostShutdown(this.serverId);
202
+ this.serverId = 0;
203
+ throw new Error("copilot_runtime_connection_open failed.");
204
+ }
205
+ this.keepAliveTimer = setInterval(() => {
206
+ }, KEEP_ALIVE_INTERVAL_MS);
207
+ }
208
+ writeFrame(frame) {
209
+ if (this.disposed || !this.connectionId) {
210
+ throw new Error("The in-process runtime connection is closed.");
211
+ }
212
+ const ok = this.lib.connectionWrite(this.connectionId, frame, frame.length);
213
+ if (!ok) {
214
+ throw new Error("Failed to write a frame to the in-process runtime connection.");
215
+ }
216
+ }
217
+ /**
218
+ * Native outbound (server→client) callback. koffi delivers it on the JS event loop
219
+ * via a threadsafe function, so the frame is decoded and written straight to
220
+ * {@link receiveStream}. The native pointer is only valid for this call, so the
221
+ * bytes are copied out before returning.
222
+ */
223
+ feedInbound(bytesPtr, bytesLen) {
224
+ try {
225
+ if (this.disposed || this.receiveStream.writableEnded) {
226
+ return;
227
+ }
228
+ const length = Number(bytesLen);
229
+ if (!bytesPtr || length <= 0) {
230
+ return;
231
+ }
232
+ const bytes = import_koffi.default.decode(
233
+ bytesPtr,
234
+ import_koffi.default.array("uint8", length, "Typed")
235
+ );
236
+ this.receiveStream.write(Buffer.from(bytes));
237
+ } catch (error) {
238
+ console.error(
239
+ `In-process FFI inbound callback failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`
240
+ );
241
+ }
242
+ }
243
+ unregisterCallback() {
244
+ if (this.outboundCallback === void 0) {
245
+ return;
246
+ }
247
+ const callback = this.outboundCallback;
248
+ this.outboundCallback = void 0;
249
+ try {
250
+ import_koffi.default.unregister(callback);
251
+ } catch {
252
+ }
253
+ }
254
+ /** Closes the FFI connection, shuts down the native host, and releases resources. */
255
+ dispose() {
256
+ if (this.disposed) {
257
+ return;
258
+ }
259
+ this.disposed = true;
260
+ if (this.keepAliveTimer !== void 0) {
261
+ clearInterval(this.keepAliveTimer);
262
+ this.keepAliveTimer = void 0;
263
+ }
264
+ try {
265
+ if (this.connectionId) {
266
+ this.lib.connectionClose(this.connectionId);
267
+ this.connectionId = 0;
268
+ }
269
+ } catch {
270
+ }
271
+ try {
272
+ if (this.serverId) {
273
+ this.lib.hostShutdown(this.serverId);
274
+ this.serverId = 0;
275
+ }
276
+ } catch {
277
+ }
278
+ this.receiveStream.end();
279
+ this.unregisterCallback();
280
+ }
281
+ }
282
+ // Annotate the CommonJS export names for ESM import in node:
283
+ 0 && (module.exports = {
284
+ FfiRuntimeHost
285
+ });