cursor-agent-bridge 0.1.0 → 0.1.3

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/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as toOpenAIModelList, c as responsesToMessages, i as toCodexModelCatalog, n as CursorRunner, o as messagesToPrompt, r as parseAgentModelList, s as normalizeModel, t as startServer } from "./server-CuHDT_fJ.mjs";
1
+ import { a as toCodexModelCatalog, c as normalizeModel, i as parseAgentModelList, l as responsesToMessages, o as toOpenAIModelList, r as CursorRunner, s as messagesToPrompt, t as startServer } from "./server-BFgBwbF5.mjs";
2
2
  export { CursorRunner, messagesToPrompt, normalizeModel, parseAgentModelList, responsesToMessages, startServer, toCodexModelCatalog, toOpenAIModelList };
@@ -1,5 +1,4 @@
1
1
  import { execFile, spawn } from "node:child_process";
2
- import { EventEmitter } from "node:events";
3
2
  import { randomUUID } from "node:crypto";
4
3
  import http from "node:http";
5
4
  //#region src/adapter/messages.ts
@@ -136,18 +135,31 @@ function toCodexModelCatalog(models) {
136
135
  }
137
136
  //#endregion
138
137
  //#region src/cursor/runner.ts
139
- var CursorRunner = class extends EventEmitter {
138
+ const defaultMaxConcurrentRuns = 1;
139
+ const forceKillDelayMs = 1e3;
140
+ var CursorRunner = class {
140
141
  agentPath;
141
142
  defaultCwd;
142
143
  timeoutMs;
144
+ modelListCacheMs;
145
+ maxConcurrentRuns;
146
+ yolo;
147
+ modelCache;
148
+ activeRuns = 0;
149
+ runQueue = [];
150
+ activeChildren = /* @__PURE__ */ new Set();
143
151
  constructor(options = {}) {
144
- super();
145
152
  this.agentPath = options.agentPath ?? process.env.CURSOR_AGENT_PATH ?? "agent";
146
153
  this.defaultCwd = options.defaultCwd ?? process.cwd();
147
154
  this.timeoutMs = options.timeoutMs ?? 3e5;
155
+ this.modelListCacheMs = options.modelListCacheMs ?? 6e4;
156
+ this.maxConcurrentRuns = parsePositiveInteger(options.maxConcurrentRuns ?? Number(process.env.CURSOR_AGENT_MAX_CONCURRENT || defaultMaxConcurrentRuns), defaultMaxConcurrentRuns);
157
+ this.yolo = options.yolo ?? process.env.CURSOR_AGENT_YOLO !== "0";
148
158
  }
149
- listModels() {
150
- return new Promise((resolve, reject) => {
159
+ async listModels(options = {}) {
160
+ const now = Date.now();
161
+ if (!options.refresh && this.modelCache && this.modelCache.expiresAt > now) return this.modelCache.models;
162
+ const models = await new Promise((resolve, reject) => {
151
163
  execFile(this.agentPath, ["--list-models"], { timeout: 3e4 }, (error, stdout) => {
152
164
  if (error) {
153
165
  reject(error);
@@ -156,16 +168,62 @@ var CursorRunner = class extends EventEmitter {
156
168
  resolve(parseAgentModelList(stdout));
157
169
  });
158
170
  });
171
+ this.modelCache = {
172
+ expiresAt: now + this.modelListCacheMs,
173
+ models
174
+ };
175
+ return models;
176
+ }
177
+ async run(options, events = {}) {
178
+ const release = await this.acquireRunPermit(options.signal);
179
+ try {
180
+ if (options.signal?.aborted) throw new Error("Request aborted");
181
+ return await this.runWithPermit(options, events);
182
+ } finally {
183
+ release();
184
+ }
185
+ }
186
+ abortAll() {
187
+ for (const child of this.activeChildren) terminateChild(child);
188
+ }
189
+ acquireRunPermit(signal) {
190
+ return new Promise((resolve, reject) => {
191
+ if (signal?.aborted) {
192
+ reject(/* @__PURE__ */ new Error("Request aborted"));
193
+ return;
194
+ }
195
+ let queuedAcquire;
196
+ const onAbort = () => {
197
+ if (queuedAcquire) this.runQueue.splice(this.runQueue.indexOf(queuedAcquire), 1);
198
+ reject(/* @__PURE__ */ new Error("Request aborted"));
199
+ };
200
+ const acquire = () => {
201
+ signal?.removeEventListener("abort", onAbort);
202
+ this.activeRuns += 1;
203
+ resolve(() => {
204
+ this.activeRuns -= 1;
205
+ const next = this.runQueue.shift();
206
+ if (next) next();
207
+ });
208
+ };
209
+ if (this.activeRuns < this.maxConcurrentRuns) {
210
+ acquire();
211
+ return;
212
+ }
213
+ queuedAcquire = acquire;
214
+ signal?.addEventListener("abort", onAbort, { once: true });
215
+ this.runQueue.push(acquire);
216
+ });
159
217
  }
160
- run(options, events = {}) {
218
+ runWithPermit(options, events) {
161
219
  return new Promise((resolve, reject) => {
162
220
  const args = [
163
221
  "-p",
164
222
  "--output-format",
165
223
  "stream-json",
166
- "--stream-partial-output",
167
- "--yolo"
224
+ "--stream-partial-output"
168
225
  ];
226
+ if (this.yolo) args.push("--yolo");
169
227
  if (options.model !== "auto") args.push("--model", options.model);
170
228
  const child = spawn(this.agentPath, args, {
171
229
  cwd: options.cwd ?? this.defaultCwd,
@@ -176,32 +234,38 @@ var CursorRunner = class extends EventEmitter {
176
234
  "pipe"
177
235
  ]
178
236
  });
237
+ this.activeChildren.add(child);
179
238
  let buffer = "";
180
239
  let lastModel = options.model;
181
240
  let lastAssistantText = "";
182
241
  let finalText;
183
242
  let stderr = "";
184
243
  let settled = false;
244
+ let forceKillTimer;
185
245
  const timer = setTimeout(() => {
186
- child.kill("SIGTERM");
187
- reject(/* @__PURE__ */ new Error(`Cursor Agent request timed out after ${this.timeoutMs}ms`));
246
+ forceKillTimer = terminateChild(child);
247
+ settle(() => reject(/* @__PURE__ */ new Error(`Cursor Agent request timed out after ${this.timeoutMs}ms`)));
188
248
  }, this.timeoutMs);
249
+ const onAbort = () => {
250
+ forceKillTimer = terminateChild(child);
251
+ settle(() => reject(/* @__PURE__ */ new Error("Request aborted")));
252
+ };
189
253
  const settle = (fn) => {
190
254
  if (settled) return;
191
255
  settled = true;
192
256
  clearTimeout(timer);
257
+ if (forceKillTimer && child.exitCode !== null) clearTimeout(forceKillTimer);
258
+ options.signal?.removeEventListener("abort", onAbort);
259
+ this.activeChildren.delete(child);
193
260
  fn();
194
261
  };
195
- options.signal?.addEventListener("abort", () => {
196
- child.kill("SIGTERM");
197
- settle(() => reject(/* @__PURE__ */ new Error("Request aborted")));
198
- });
262
+ options.signal?.addEventListener("abort", onAbort, { once: true });
199
263
  child.stdin.write(options.prompt);
200
264
  child.stdin.end();
201
265
  child.stdout.on("data", (chunk) => {
202
266
  buffer += chunk.toString();
203
267
  const lines = buffer.split("\n");
204
- buffer = lines.pop() ?? "";
268
+ buffer = lines.pop();
205
269
  for (const line of lines) {
206
270
  const trimmed = line.trim();
207
271
  if (!trimmed) continue;
@@ -242,6 +306,15 @@ var CursorRunner = class extends EventEmitter {
242
306
  });
243
307
  }
244
308
  };
309
+ function parsePositiveInteger(value, fallback) {
310
+ return Number.isInteger(value) && value > 0 ? value : fallback;
311
+ }
312
+ function terminateChild(child) {
313
+ child.kill("SIGTERM");
314
+ return setTimeout(() => {
315
+ if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
316
+ }, forceKillDelayMs);
317
+ }
245
318
  function extractAssistantText(message) {
246
319
  const nested = message.message;
247
320
  if (!nested || typeof nested !== "object") return "";
@@ -254,6 +327,9 @@ function extractAssistantText(message) {
254
327
  }).join("");
255
328
  }
256
329
  //#endregion
330
+ //#region package.json
331
+ var version = "0.1.3";
332
+ //#endregion
257
333
  //#region src/adapter/openai.ts
258
334
  function createChatResponse(model, text) {
259
335
  return {
@@ -305,9 +381,9 @@ function createChatDoneChunk(id, model) {
305
381
  }]
306
382
  };
307
383
  }
308
- function createResponseObject(model, text, responseId = `resp_${randomUUID().replaceAll("-", "")}`) {
384
+ function createResponseObject(model, text, responseId = `resp_${randomUUID().replaceAll("-", "")}`, itemId = `msg_${randomUUID().replaceAll("-", "")}`) {
309
385
  const item = {
310
- id: `msg_${randomUUID().replaceAll("-", "")}`,
386
+ id: itemId,
311
387
  type: "message",
312
388
  status: "completed",
313
389
  role: "assistant",
@@ -331,46 +407,64 @@ function createResponseObject(model, text, responseId = `resp_${randomUUID().rep
331
407
  }
332
408
  };
333
409
  }
334
- function responseTextEvents(model, text) {
335
- const response = createResponseObject(model, text);
410
+ function createResponseStream(model) {
411
+ const response = createResponseObject(model, "");
336
412
  const item = response.output[0];
337
413
  /* v8 ignore next -- createResponseObject always creates one output item. */
338
414
  if (!item) throw new Error("Responses output item was not created");
339
415
  const part = item.content[0];
340
416
  /* v8 ignore next -- createResponseObject always creates one output text part. */
341
417
  if (!part) throw new Error("Responses output text part was not created");
342
- return [
343
- ["response.created", {
344
- ...response,
345
- status: "in_progress",
346
- output: []
347
- }],
348
- ["response.output_item.added", {
349
- response_id: response.id,
350
- output_index: 0,
351
- item: {
352
- ...item,
418
+ return {
419
+ response,
420
+ item,
421
+ part,
422
+ events: [
423
+ ["response.created", {
424
+ ...response,
353
425
  status: "in_progress",
354
- content: []
355
- }
356
- }],
357
- ["response.content_part.added", {
358
- response_id: response.id,
359
- item_id: item.id,
360
- output_index: 0,
361
- content_index: 0,
362
- part: {
363
- ...part,
364
- text: ""
365
- }
366
- }],
367
- ["response.output_text.delta", {
368
- response_id: response.id,
369
- item_id: item.id,
370
- output_index: 0,
371
- content_index: 0,
372
- delta: text
373
- }],
426
+ output: []
427
+ }],
428
+ ["response.output_item.added", {
429
+ response_id: response.id,
430
+ output_index: 0,
431
+ item: {
432
+ ...item,
433
+ status: "in_progress",
434
+ content: []
435
+ }
436
+ }],
437
+ ["response.content_part.added", {
438
+ response_id: response.id,
439
+ item_id: item.id,
440
+ output_index: 0,
441
+ content_index: 0,
442
+ part: {
443
+ ...part,
444
+ text: ""
445
+ }
446
+ }]
447
+ ]
448
+ };
449
+ }
450
+ function responseDeltaEvent(stream, delta) {
451
+ return ["response.output_text.delta", {
452
+ response_id: stream.response.id,
453
+ item_id: stream.item.id,
454
+ output_index: 0,
455
+ content_index: 0,
456
+ delta
457
+ }];
458
+ }
459
+ function responseDoneEvents(stream, model, text) {
460
+ const response = createResponseObject(model, text, stream.response.id, stream.item.id);
461
+ const item = response.output[0];
462
+ /* v8 ignore next -- createResponseObject always creates one output item. */
463
+ if (!item) throw new Error("Responses output item was not created");
464
+ const part = item.content[0];
465
+ /* v8 ignore next -- createResponseObject always creates one output text part. */
466
+ if (!part) throw new Error("Responses output text part was not created");
467
+ return [
374
468
  ["response.output_text.done", {
375
469
  response_id: response.id,
376
470
  item_id: item.id,
@@ -395,7 +489,17 @@ function responseTextEvents(model, text) {
395
489
  }
396
490
  //#endregion
397
491
  //#region src/server.ts
398
- const packageVersion = "0.1.0";
492
+ const packageVersion = version;
493
+ const defaultMaxBodyBytes = 1024 * 1024;
494
+ var RequestError = class extends Error {
495
+ status;
496
+ code;
497
+ constructor(status, code, message) {
498
+ super(message);
499
+ this.status = status;
500
+ this.code = code;
501
+ }
502
+ };
399
503
  async function startServer(config = {}) {
400
504
  const port = config.port ?? Number(process.env.PORT || 4646);
401
505
  const host = config.host ?? process.env.HOST ?? "127.0.0.1";
@@ -403,24 +507,22 @@ async function startServer(config = {}) {
403
507
  ...config.agentPath ? { agentPath: config.agentPath } : {},
404
508
  ...config.defaultCwd ? { defaultCwd: config.defaultCwd } : {}
405
509
  });
510
+ const maxBodyBytes = config.maxBodyBytes ?? defaultMaxBodyBytes;
406
511
  const server = http.createServer(async (req, res) => {
407
512
  try {
408
- await route(req, res, runner);
513
+ await route(req, res, runner, maxBodyBytes);
409
514
  } catch (error) {
410
- sendJson(res, 500, { error: {
411
- message: error instanceof Error ? error.message : String(error),
412
- type: "server_error",
413
- code: "internal_error"
414
- } });
515
+ sendError(res, error);
415
516
  }
416
517
  });
518
+ server.on("close", () => runner.abortAll());
417
519
  await new Promise((resolve, reject) => {
418
520
  server.listen(port, host, resolve);
419
521
  server.once("error", reject);
420
522
  });
421
523
  return server;
422
524
  }
423
- async function route(req, res, runner) {
525
+ async function route(req, res, runner, maxBodyBytes) {
424
526
  setCors(res);
425
527
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "127.0.0.1"}`);
426
528
  if (req.method === "OPTIONS") {
@@ -437,16 +539,16 @@ async function route(req, res, runner) {
437
539
  return;
438
540
  }
439
541
  if (req.method === "GET" && url.pathname === "/v1/models") {
440
- const models = await runner.listModels();
542
+ const models = await runner.listModels({ refresh: url.searchParams.get("refresh") === "1" });
441
543
  sendJson(res, 200, url.searchParams.has("client_version") || url.searchParams.get("format") === "codex" ? toCodexModelCatalog(models) : toOpenAIModelList(models));
442
544
  return;
443
545
  }
444
546
  if (req.method === "POST" && url.pathname === "/v1/chat/completions") {
445
- await handleChat(req, res, runner);
547
+ await handleChat(req, res, runner, maxBodyBytes);
446
548
  return;
447
549
  }
448
550
  if (req.method === "POST" && url.pathname === "/v1/responses") {
449
- await handleResponses(req, res, runner);
551
+ await handleResponses(req, res, runner, maxBodyBytes);
450
552
  return;
451
553
  }
452
554
  sendJson(res, 404, { error: {
@@ -455,8 +557,8 @@ async function route(req, res, runner) {
455
557
  code: "not_found"
456
558
  } });
457
559
  }
458
- async function handleChat(req, res, runner) {
459
- const body = await readJson(req);
560
+ async function handleChat(req, res, runner, maxBodyBytes) {
561
+ const body = await readJson(req, maxBodyBytes);
460
562
  if (!Array.isArray(body.messages) || body.messages.length === 0) {
461
563
  sendJson(res, 400, { error: {
462
564
  message: "messages is required and must be a non-empty array",
@@ -474,21 +576,32 @@ async function handleChat(req, res, runner) {
474
576
  writeSseHeaders(res);
475
577
  let isFirst = true;
476
578
  let lastModel = model;
477
- await runner.run({
478
- model,
479
- prompt,
480
- signal: abort.signal
481
- }, {
482
- onDelta: (text) => {
483
- res.write(`data: ${JSON.stringify(createChatChunk(id, lastModel, text, isFirst))}\n\n`);
484
- isFirst = false;
485
- },
486
- onModel: (nextModel) => {
487
- lastModel = nextModel;
579
+ let streamedText = "";
580
+ try {
581
+ const result = await runner.run({
582
+ model,
583
+ prompt,
584
+ signal: abort.signal
585
+ }, {
586
+ onDelta: (text) => {
587
+ streamedText += text;
588
+ res.write(`data: ${JSON.stringify(createChatChunk(id, lastModel, text, isFirst))}\n\n`);
589
+ isFirst = false;
590
+ },
591
+ onModel: (nextModel) => {
592
+ lastModel = nextModel;
593
+ }
594
+ });
595
+ lastModel = result.model;
596
+ if (result.text !== streamedText) {
597
+ const delta = result.text.startsWith(streamedText) ? result.text.slice(streamedText.length) : result.text;
598
+ if (delta) res.write(`data: ${JSON.stringify(createChatChunk(id, lastModel, delta, isFirst))}\n\n`);
488
599
  }
489
- });
490
- res.write(`data: ${JSON.stringify(createChatDoneChunk(id, lastModel))}\n\n`);
491
- res.write("data: [DONE]\n\n");
600
+ res.write(`data: ${JSON.stringify(createChatDoneChunk(id, lastModel))}\n\n`);
601
+ res.write("data: [DONE]\n\n");
602
+ } catch (error) {
603
+ writeSseError(res, error);
604
+ }
492
605
  res.end();
493
606
  return;
494
607
  }
@@ -499,43 +612,77 @@ async function handleChat(req, res, runner) {
499
612
  });
500
613
  sendJson(res, 200, createChatResponse(result.model, result.text));
501
614
  }
502
- async function handleResponses(req, res, runner) {
503
- const body = await readJson(req);
615
+ async function handleResponses(req, res, runner, maxBodyBytes) {
616
+ const body = await readJson(req, maxBodyBytes);
504
617
  const model = normalizeModel(body.model);
505
618
  const prompt = messagesToPrompt(responsesToMessages(body));
506
619
  const abort = new AbortController();
507
620
  req.on("close", () => abort.abort());
508
- const result = await runner.run({
509
- model,
510
- prompt,
511
- signal: abort.signal
512
- });
513
621
  if (body.stream === false) {
622
+ const result = await runner.run({
623
+ model,
624
+ prompt,
625
+ signal: abort.signal
626
+ });
514
627
  sendJson(res, 200, createResponseObject(result.model, result.text));
515
628
  return;
516
629
  }
517
630
  writeSseHeaders(res);
518
- for (const [event, data] of responseTextEvents(result.model, result.text)) {
519
- res.write(`event: ${event}\n`);
520
- res.write(`data: ${JSON.stringify({
521
- type: event,
522
- ...data
523
- })}\n\n`);
631
+ const stream = createResponseStream(model);
632
+ let lastModel = model;
633
+ let streamedText = "";
634
+ for (const [event, data] of stream.events) writeSseEvent(res, event, data);
635
+ try {
636
+ const result = await runner.run({
637
+ model,
638
+ prompt,
639
+ signal: abort.signal
640
+ }, {
641
+ onDelta: (text) => {
642
+ streamedText += text;
643
+ const [event, data] = responseDeltaEvent(stream, text);
644
+ writeSseEvent(res, event, data);
645
+ },
646
+ onModel: (nextModel) => {
647
+ lastModel = nextModel;
648
+ }
649
+ });
650
+ lastModel = result.model;
651
+ if (result.text !== streamedText) {
652
+ const delta = result.text.startsWith(streamedText) ? result.text.slice(streamedText.length) : result.text;
653
+ if (delta) {
654
+ streamedText += delta;
655
+ const [event, data] = responseDeltaEvent(stream, delta);
656
+ writeSseEvent(res, event, data);
657
+ }
658
+ }
659
+ for (const [event, data] of responseDoneEvents(stream, lastModel, result.text)) writeSseEvent(res, event, data);
660
+ } catch (error) {
661
+ writeSseError(res, error);
524
662
  }
525
663
  res.end();
526
664
  }
527
- function readJson(req) {
665
+ function readJson(req, maxBodyBytes = defaultMaxBodyBytes) {
528
666
  return new Promise((resolve, reject) => {
529
667
  let body = "";
668
+ let bytes = 0;
669
+ let tooLarge = false;
530
670
  req.setEncoding("utf8");
531
671
  req.on("data", (chunk) => {
672
+ if (tooLarge) return;
673
+ bytes += Buffer.byteLength(chunk);
674
+ if (bytes > maxBodyBytes) {
675
+ tooLarge = true;
676
+ reject(new RequestError(413, "payload_too_large", `Request body exceeds ${maxBodyBytes} bytes`));
677
+ return;
678
+ }
532
679
  body += chunk;
533
680
  });
534
681
  req.on("end", () => {
535
682
  try {
536
683
  resolve(body ? JSON.parse(body) : {});
537
- } catch (error) {
538
- reject(error);
684
+ } catch {
685
+ reject(new RequestError(400, "invalid_json", "Invalid JSON"));
539
686
  }
540
687
  });
541
688
  req.on("error", reject);
@@ -553,6 +700,38 @@ function writeSseHeaders(res) {
553
700
  connection: "keep-alive"
554
701
  });
555
702
  }
703
+ function writeSseEvent(res, event, data) {
704
+ res.write(`event: ${event}\n`);
705
+ res.write(`data: ${JSON.stringify({
706
+ type: event,
707
+ ...data
708
+ })}\n\n`);
709
+ }
710
+ function writeSseError(res, error) {
711
+ const message = error instanceof Error ? error.message : String(error);
712
+ res.write("event: error\n");
713
+ res.write(`data: ${JSON.stringify({
714
+ type: "error",
715
+ error: {
716
+ message,
717
+ type: "server_error",
718
+ code: "internal_error"
719
+ }
720
+ })}\n\n`);
721
+ }
722
+ function sendError(res, error) {
723
+ /* v8 ignore next 4 -- last-resort guard for unexpected errors after SSE headers. */
724
+ if (res.headersSent) {
725
+ writeSseError(res, error);
726
+ res.end();
727
+ return;
728
+ }
729
+ sendJson(res, error instanceof RequestError ? error.status : 500, { error: {
730
+ message: error instanceof Error ? error.message : String(error),
731
+ type: error instanceof RequestError ? "invalid_request_error" : "server_error",
732
+ code: error instanceof RequestError ? error.code : "internal_error"
733
+ } });
734
+ }
556
735
  function sendJson(res, status, value) {
557
736
  /* v8 ignore next -- this is a last-resort guard for errors after SSE headers. */
558
737
  if (res.headersSent) return;
@@ -564,6 +743,6 @@ function sendJson(res, status, value) {
564
743
  res.end(body);
565
744
  }
566
745
  //#endregion
567
- export { toOpenAIModelList as a, responsesToMessages as c, toCodexModelCatalog as i, CursorRunner as n, messagesToPrompt as o, parseAgentModelList as r, normalizeModel as s, startServer as t };
746
+ export { toCodexModelCatalog as a, normalizeModel as c, parseAgentModelList as i, responsesToMessages as l, version as n, toOpenAIModelList as o, CursorRunner as r, messagesToPrompt as s, startServer as t };
568
747
 
569
- //# sourceMappingURL=server-CuHDT_fJ.mjs.map
748
+ //# sourceMappingURL=server-BFgBwbF5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-BFgBwbF5.mjs","names":["packageJson.version"],"sources":["../src/adapter/messages.ts","../src/adapter/models.ts","../src/cursor/runner.ts","../package.json","../src/adapter/openai.ts","../src/server.ts"],"sourcesContent":["import type { ChatMessage, ResponsesRequest } from \"../types.js\";\n\nfunction contentToText(content: ChatMessage[\"content\"]): string {\n if (typeof content === \"string\") return content;\n\n return content\n .map((part) => part.text ?? part.input_text ?? part.output_text ?? \"\")\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport function messagesToPrompt(messages: ChatMessage[]): string {\n const nonEmpty = messages.filter(\n (message) => contentToText(message.content).length > 0,\n );\n\n if (nonEmpty.length === 1 && nonEmpty[0]?.role === \"user\") {\n return contentToText(nonEmpty[0].content);\n }\n\n return nonEmpty\n .map((message) => {\n const label =\n message.role === \"system\"\n ? \"System\"\n : message.role === \"assistant\"\n ? \"Assistant\"\n : \"User\";\n return `[${label}]\\n${contentToText(message.content)}`;\n })\n .join(\"\\n\\n\");\n}\n\nfunction responseContentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n\n return content\n .map((part) => {\n if (typeof part === \"string\") return part;\n if (!part || typeof part !== \"object\") return \"\";\n const record = part as Record<string, unknown>;\n return String(\n record.text ?? record.input_text ?? record.output_text ?? \"\",\n );\n })\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nexport function responsesToMessages(request: ResponsesRequest): ChatMessage[] {\n const messages: ChatMessage[] = [];\n\n if (request.instructions) {\n messages.push({ role: \"system\", content: request.instructions });\n }\n\n const inputItems = Array.isArray(request.input)\n ? request.input\n : [{ role: \"user\", content: request.input ?? \"\" }];\n\n for (const item of inputItems) {\n if (typeof item === \"string\") {\n messages.push({ role: \"user\", content: item });\n continue;\n }\n\n if (!item || typeof item !== \"object\") continue;\n const record = item as Record<string, unknown>;\n const role =\n record.role === \"assistant\"\n ? \"assistant\"\n : record.role === \"system\"\n ? \"system\"\n : \"user\";\n\n if (record.type === \"message\" || record.role) {\n const text = responseContentToText(record.content);\n if (text) messages.push({ role, content: text });\n continue;\n }\n\n if (record.type === \"input_text\" || record.type === \"output_text\") {\n const text = responseContentToText([record]);\n if (text) messages.push({ role: \"user\", content: text });\n }\n }\n\n return messages.length > 0 ? messages : [{ role: \"user\", content: \"\" }];\n}\n\nexport function normalizeModel(model: string | undefined): string {\n if (!model) return \"auto\";\n if (model.startsWith(\"cursor/\"))\n return model.slice(\"cursor/\".length) || \"auto\";\n if (model.startsWith(\"cursor-\"))\n return model.slice(\"cursor-\".length) || \"auto\";\n return model;\n}\n","import type { BridgeModel } from \"../types.js\";\n\nexport function parseAgentModelList(output: string): BridgeModel[] {\n return output\n .split(\"\\n\")\n .map((line) => line.trim())\n .map((line) => {\n const match = line.match(/^([a-zA-Z0-9_.-]+)\\s+-\\s+(.+)$/);\n return match ? { id: match[1] ?? \"\", name: match[2] ?? \"\" } : null;\n })\n .filter((model): model is BridgeModel => Boolean(model?.id && model.name));\n}\n\nexport function toOpenAIModelList(models: BridgeModel[]) {\n const created = Math.floor(Date.now() / 1000);\n return {\n object: \"list\",\n data: models.map((model) => ({\n id: model.id,\n object: \"model\",\n owned_by: \"cursor\",\n created,\n })),\n };\n}\n\nexport function toCodexModelCatalog(models: BridgeModel[]) {\n return {\n models: models.map((model, index) => ({\n slug: model.id,\n display_name: model.name,\n description: \"Cursor model via Cursor Agent CLI.\",\n default_reasoning_level: \"medium\",\n supported_reasoning_levels: [],\n shell_type: \"shell_command\",\n visibility: \"list\",\n supported_in_api: true,\n priority: Math.max(0, 1000 - index),\n additional_speed_tiers: [],\n service_tiers: [],\n default_service_tier: null,\n availability_nux: null,\n upgrade: null,\n base_instructions:\n \"You are Codex, a coding agent. Help the user with software engineering tasks in the current workspace.\",\n model_messages: null,\n supports_reasoning_summaries: false,\n default_reasoning_summary: \"none\",\n support_verbosity: false,\n default_verbosity: \"low\",\n apply_patch_tool_type: \"freeform\",\n web_search_tool_type: \"text_and_image\",\n truncation_policy: { mode: \"tokens\", limit: 10000 },\n supports_parallel_tool_calls: true,\n supports_image_detail_original: true,\n context_window: 128000,\n max_context_window: 128000,\n effective_context_window_percent: 95,\n experimental_supported_tools: [],\n input_modalities: [\"text\"],\n supports_search_tool: false,\n use_responses_lite: false,\n })),\n };\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { parseAgentModelList } from \"../adapter/models.js\";\nimport type {\n BridgeModel,\n CursorRunEvents,\n CursorRunOptions,\n CursorRunResult,\n} from \"../types.js\";\n\nexport interface CursorRunnerOptions {\n agentPath?: string;\n defaultCwd?: string;\n timeoutMs?: number;\n modelListCacheMs?: number;\n maxConcurrentRuns?: number;\n yolo?: boolean;\n}\n\ntype RunPermit = () => void;\nconst defaultMaxConcurrentRuns = 1;\nconst forceKillDelayMs = 1_000;\n\nexport class CursorRunner {\n readonly agentPath: string;\n readonly defaultCwd: string;\n readonly timeoutMs: number;\n readonly modelListCacheMs: number;\n readonly maxConcurrentRuns: number;\n readonly yolo: boolean;\n private modelCache?: { expiresAt: number; models: BridgeModel[] };\n private activeRuns = 0;\n private readonly runQueue: Array<() => void> = [];\n private readonly activeChildren = new Set<ReturnType<typeof spawn>>();\n\n constructor(options: CursorRunnerOptions = {}) {\n this.agentPath =\n options.agentPath ?? process.env.CURSOR_AGENT_PATH ?? \"agent\";\n this.defaultCwd = options.defaultCwd ?? process.cwd();\n this.timeoutMs = options.timeoutMs ?? 300_000;\n this.modelListCacheMs = options.modelListCacheMs ?? 60_000;\n this.maxConcurrentRuns = parsePositiveInteger(\n options.maxConcurrentRuns ??\n Number(\n process.env.CURSOR_AGENT_MAX_CONCURRENT || defaultMaxConcurrentRuns,\n ),\n defaultMaxConcurrentRuns,\n );\n this.yolo = options.yolo ?? process.env.CURSOR_AGENT_YOLO !== \"0\";\n }\n\n async listModels(\n options: { refresh?: boolean } = {},\n ): Promise<BridgeModel[]> {\n const now = Date.now();\n if (\n !options.refresh &&\n this.modelCache &&\n this.modelCache.expiresAt > now\n ) {\n return this.modelCache.models;\n }\n\n const models = await new Promise<BridgeModel[]>((resolve, reject) => {\n execFile(\n this.agentPath,\n [\"--list-models\"],\n { timeout: 30_000 },\n (error, stdout) => {\n if (error) {\n reject(error);\n return;\n }\n resolve(parseAgentModelList(stdout));\n },\n );\n });\n this.modelCache = { expiresAt: now + this.modelListCacheMs, models };\n return models;\n }\n\n async run(\n options: CursorRunOptions,\n events: CursorRunEvents = {},\n ): Promise<CursorRunResult> {\n const release = await this.acquireRunPermit(options.signal);\n try {\n if (options.signal?.aborted) throw new Error(\"Request aborted\");\n return await this.runWithPermit(options, events);\n } finally {\n release();\n }\n }\n\n abortAll() {\n for (const child of this.activeChildren) terminateChild(child);\n }\n\n private acquireRunPermit(signal?: AbortSignal): Promise<RunPermit> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error(\"Request aborted\"));\n return;\n }\n\n let queuedAcquire: (() => void) | undefined;\n const onAbort = () => {\n if (queuedAcquire) {\n this.runQueue.splice(this.runQueue.indexOf(queuedAcquire), 1);\n }\n reject(new Error(\"Request aborted\"));\n };\n const acquire = () => {\n signal?.removeEventListener(\"abort\", onAbort);\n this.activeRuns += 1;\n resolve(() => {\n this.activeRuns -= 1;\n const next = this.runQueue.shift();\n if (next) next();\n });\n };\n\n if (this.activeRuns < this.maxConcurrentRuns) {\n acquire();\n return;\n }\n\n queuedAcquire = acquire;\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n this.runQueue.push(acquire);\n });\n }\n\n private runWithPermit(\n options: CursorRunOptions,\n events: CursorRunEvents,\n ): Promise<CursorRunResult> {\n return new Promise((resolve, reject) => {\n const args = [\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--stream-partial-output\",\n ];\n if (this.yolo) args.push(\"--yolo\");\n if (options.model !== \"auto\") args.push(\"--model\", options.model);\n\n const child = spawn(this.agentPath, args, {\n cwd: options.cwd ?? this.defaultCwd,\n env: process.env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n this.activeChildren.add(child);\n\n let buffer = \"\";\n let lastModel = options.model;\n let lastAssistantText = \"\";\n let finalText: string | undefined;\n let stderr = \"\";\n let settled = false;\n let forceKillTimer: NodeJS.Timeout | undefined;\n\n const timer = setTimeout(() => {\n forceKillTimer = terminateChild(child);\n settle(() =>\n reject(\n new Error(\n `Cursor Agent request timed out after ${this.timeoutMs}ms`,\n ),\n ),\n );\n }, this.timeoutMs);\n\n const onAbort = () => {\n forceKillTimer = terminateChild(child);\n settle(() => reject(new Error(\"Request aborted\")));\n };\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (forceKillTimer && child.exitCode !== null)\n clearTimeout(forceKillTimer);\n options.signal?.removeEventListener(\"abort\", onAbort);\n this.activeChildren.delete(child);\n fn();\n };\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n child.stdin.write(options.prompt);\n child.stdin.end();\n\n child.stdout.on(\"data\", (chunk) => {\n buffer += chunk.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() as string;\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const message = JSON.parse(trimmed) as Record<string, unknown>;\n if (typeof message.model === \"string\") {\n lastModel = message.model;\n events.onModel?.(lastModel);\n }\n\n const text = extractAssistantText(message);\n if (text && text !== lastAssistantText) {\n const delta = text.startsWith(lastAssistantText)\n ? text.slice(lastAssistantText.length)\n : text;\n lastAssistantText = text;\n events.onDelta?.(delta);\n }\n\n if (typeof message.result === \"string\") finalText = message.result;\n } catch {\n // Cursor occasionally emits non-JSON progress lines. They are not protocol data.\n }\n }\n });\n\n child.stderr.on(\"data\", (chunk) => {\n stderr += chunk.toString();\n });\n\n child.on(\"error\", (error) => {\n settle(() => reject(error));\n });\n\n child.on(\"close\", (code) => {\n settle(() => {\n if (code === 0 && (finalText !== undefined || lastAssistantText)) {\n resolve({ text: finalText ?? lastAssistantText, model: lastModel });\n return;\n }\n reject(\n new Error(stderr.trim() || `Cursor Agent exited with code ${code}`),\n );\n });\n });\n });\n }\n}\n\nfunction parsePositiveInteger(value: number, fallback: number) {\n return Number.isInteger(value) && value > 0 ? value : fallback;\n}\n\nfunction terminateChild(child: ReturnType<typeof spawn>) {\n child.kill(\"SIGTERM\");\n return setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n child.kill(\"SIGKILL\");\n }\n }, forceKillDelayMs);\n}\n\nfunction extractAssistantText(message: Record<string, unknown>): string {\n const nested = message.message;\n if (!nested || typeof nested !== \"object\") return \"\";\n const content = (nested as Record<string, unknown>).content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((part) => {\n if (!part || typeof part !== \"object\") return \"\";\n const record = part as Record<string, unknown>;\n return record.type === \"text\" && typeof record.text === \"string\"\n ? record.text\n : \"\";\n })\n .join(\"\");\n}\n","","import { randomUUID } from \"node:crypto\";\n\nexport function createChatResponse(model: string, text: string) {\n return {\n id: `chatcmpl-${randomUUID().replaceAll(\"-\", \"\")}`,\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content: text },\n finish_reason: \"stop\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n}\n\nexport function createChatChunk(\n id: string,\n model: string,\n text: string,\n isFirst: boolean,\n) {\n return {\n id,\n object: \"chat.completion.chunk\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n delta: { role: isFirst ? \"assistant\" : undefined, content: text },\n finish_reason: null,\n },\n ],\n };\n}\n\nexport function createChatDoneChunk(id: string, model: string) {\n return {\n id,\n object: \"chat.completion.chunk\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }],\n };\n}\n\nexport function createResponseObject(\n model: string,\n text: string,\n responseId = `resp_${randomUUID().replaceAll(\"-\", \"\")}`,\n itemId = `msg_${randomUUID().replaceAll(\"-\", \"\")}`,\n) {\n const item: {\n id: string;\n type: \"message\";\n status: \"completed\";\n role: \"assistant\";\n content: Array<{\n type: \"output_text\";\n text: string;\n annotations: unknown[];\n }>;\n } = {\n id: itemId,\n type: \"message\",\n status: \"completed\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text, annotations: [] }],\n };\n\n return {\n id: responseId,\n object: \"response\",\n created_at: Math.floor(Date.now() / 1000),\n status: \"completed\",\n model,\n output: [item],\n usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0 },\n };\n}\n\nexport function createResponseStream(model: string) {\n const response = createResponseObject(model, \"\");\n const item = response.output[0];\n /* v8 ignore next -- createResponseObject always creates one output item. */\n if (!item) throw new Error(\"Responses output item was not created\");\n const part = item.content[0];\n /* v8 ignore next -- createResponseObject always creates one output text part. */\n if (!part) throw new Error(\"Responses output text part was not created\");\n\n return {\n response,\n item,\n part,\n events: [\n [\"response.created\", { ...response, status: \"in_progress\", output: [] }],\n [\n \"response.output_item.added\",\n {\n response_id: response.id,\n output_index: 0,\n item: { ...item, status: \"in_progress\", content: [] },\n },\n ],\n [\n \"response.content_part.added\",\n {\n response_id: response.id,\n item_id: item.id,\n output_index: 0,\n content_index: 0,\n part: { ...part, text: \"\" },\n },\n ],\n ] as const,\n };\n}\n\nexport function responseDeltaEvent(\n stream: ReturnType<typeof createResponseStream>,\n delta: string,\n) {\n return [\n \"response.output_text.delta\",\n {\n response_id: stream.response.id,\n item_id: stream.item.id,\n output_index: 0,\n content_index: 0,\n delta,\n },\n ] as const;\n}\n\nexport function responseDoneEvents(\n stream: ReturnType<typeof createResponseStream>,\n model: string,\n text: string,\n) {\n const response = createResponseObject(\n model,\n text,\n stream.response.id,\n stream.item.id,\n );\n const item = response.output[0];\n /* v8 ignore next -- createResponseObject always creates one output item. */\n if (!item) throw new Error(\"Responses output item was not created\");\n const part = item.content[0];\n /* v8 ignore next -- createResponseObject always creates one output text part. */\n if (!part) throw new Error(\"Responses output text part was not created\");\n\n return [\n [\n \"response.output_text.done\",\n {\n response_id: response.id,\n item_id: item.id,\n output_index: 0,\n content_index: 0,\n text,\n },\n ],\n [\n \"response.content_part.done\",\n {\n response_id: response.id,\n item_id: item.id,\n output_index: 0,\n content_index: 0,\n part,\n },\n ],\n [\n \"response.output_item.done\",\n { response_id: response.id, output_index: 0, item },\n ],\n [\"response.completed\", { response }],\n ] as const;\n}\n\nexport function responseTextEvents(model: string, text: string) {\n const stream = createResponseStream(model);\n return [\n ...stream.events,\n responseDeltaEvent(stream, text),\n ...responseDoneEvents(stream, model, text),\n ] as const;\n}\n","import { randomUUID } from \"node:crypto\";\nimport http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n messagesToPrompt,\n normalizeModel,\n responsesToMessages,\n} from \"./adapter/messages.js\";\nimport { toCodexModelCatalog, toOpenAIModelList } from \"./adapter/models.js\";\nimport {\n createChatChunk,\n createChatDoneChunk,\n createChatResponse,\n createResponseObject,\n createResponseStream,\n responseDeltaEvent,\n responseDoneEvents,\n} from \"./adapter/openai.js\";\nimport { CursorRunner } from \"./cursor/runner.js\";\nimport type {\n ChatCompletionRequest,\n ResponsesRequest,\n ServerConfig,\n} from \"./types.js\";\n\nconst packageVersion = packageJson.version;\nconst defaultMaxBodyBytes = 1024 * 1024;\n\nclass RequestError extends Error {\n readonly status: number;\n readonly code: string;\n\n constructor(status: number, code: string, message: string) {\n super(message);\n this.status = status;\n this.code = code;\n }\n}\n\nexport async function startServer(config: ServerConfig = {}) {\n const port = config.port ?? Number(process.env.PORT || 4646);\n const host = config.host ?? process.env.HOST ?? \"127.0.0.1\";\n const runner = new CursorRunner({\n ...(config.agentPath ? { agentPath: config.agentPath } : {}),\n ...(config.defaultCwd ? { defaultCwd: config.defaultCwd } : {}),\n });\n const maxBodyBytes = config.maxBodyBytes ?? defaultMaxBodyBytes;\n\n const server = http.createServer(async (req, res) => {\n try {\n await route(req, res, runner, maxBodyBytes);\n } catch (error) {\n sendError(res, error);\n }\n });\n server.on(\"close\", () => runner.abortAll());\n\n await new Promise<void>((resolve, reject) => {\n server.listen(port, host, resolve);\n server.once(\"error\", reject);\n });\n\n return server;\n}\n\nasync function route(\n req: IncomingMessage,\n res: ServerResponse,\n runner: CursorRunner,\n maxBodyBytes: number,\n) {\n setCors(res);\n const url = new URL(\n req.url ?? \"/\",\n `http://${req.headers.host ?? \"127.0.0.1\"}`,\n );\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/health\") {\n sendJson(res, 200, {\n status: \"ok\",\n provider: \"cursor-agent-bridge\",\n version: packageVersion,\n });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/v1/models\") {\n const models = await runner.listModels({\n refresh: url.searchParams.get(\"refresh\") === \"1\",\n });\n const wantsCodexCatalog =\n url.searchParams.has(\"client_version\") ||\n url.searchParams.get(\"format\") === \"codex\";\n sendJson(\n res,\n 200,\n wantsCodexCatalog\n ? toCodexModelCatalog(models)\n : toOpenAIModelList(models),\n );\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/chat/completions\") {\n await handleChat(req, res, runner, maxBodyBytes);\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/responses\") {\n await handleResponses(req, res, runner, maxBodyBytes);\n return;\n }\n\n sendJson(res, 404, {\n error: {\n message: \"Not found\",\n type: \"invalid_request_error\",\n code: \"not_found\",\n },\n });\n}\n\nasync function handleChat(\n req: IncomingMessage,\n res: ServerResponse,\n runner: CursorRunner,\n maxBodyBytes: number,\n) {\n const body = (await readJson(req, maxBodyBytes)) as ChatCompletionRequest;\n if (!Array.isArray(body.messages) || body.messages.length === 0) {\n sendJson(res, 400, {\n error: {\n message: \"messages is required and must be a non-empty array\",\n type: \"invalid_request_error\",\n code: \"invalid_messages\",\n },\n });\n return;\n }\n\n const model = normalizeModel(body.model);\n const prompt = messagesToPrompt(body.messages);\n const abort = new AbortController();\n req.on(\"close\", () => abort.abort());\n\n if (body.stream === true) {\n const id = `chatcmpl-${randomUUID().replaceAll(\"-\", \"\")}`;\n writeSseHeaders(res);\n let isFirst = true;\n let lastModel = model;\n let streamedText = \"\";\n try {\n const result = await runner.run(\n { model, prompt, signal: abort.signal },\n {\n onDelta: (text) => {\n streamedText += text;\n res.write(\n `data: ${JSON.stringify(createChatChunk(id, lastModel, text, isFirst))}\\n\\n`,\n );\n isFirst = false;\n },\n onModel: (nextModel) => {\n lastModel = nextModel;\n },\n },\n );\n lastModel = result.model;\n if (result.text !== streamedText) {\n const delta = result.text.startsWith(streamedText)\n ? result.text.slice(streamedText.length)\n : result.text;\n if (delta) {\n res.write(\n `data: ${JSON.stringify(createChatChunk(id, lastModel, delta, isFirst))}\\n\\n`,\n );\n }\n }\n res.write(\n `data: ${JSON.stringify(createChatDoneChunk(id, lastModel))}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n } catch (error) {\n writeSseError(res, error);\n }\n res.end();\n return;\n }\n\n const result = await runner.run({ model, prompt, signal: abort.signal });\n sendJson(res, 200, createChatResponse(result.model, result.text));\n}\n\nasync function handleResponses(\n req: IncomingMessage,\n res: ServerResponse,\n runner: CursorRunner,\n maxBodyBytes: number,\n) {\n const body = (await readJson(req, maxBodyBytes)) as ResponsesRequest;\n const model = normalizeModel(body.model);\n const prompt = messagesToPrompt(responsesToMessages(body));\n const abort = new AbortController();\n req.on(\"close\", () => abort.abort());\n\n if (body.stream === false) {\n const result = await runner.run({ model, prompt, signal: abort.signal });\n sendJson(res, 200, createResponseObject(result.model, result.text));\n return;\n }\n\n writeSseHeaders(res);\n const stream = createResponseStream(model);\n let lastModel = model;\n let streamedText = \"\";\n for (const [event, data] of stream.events) {\n writeSseEvent(res, event, data);\n }\n try {\n const result = await runner.run(\n { model, prompt, signal: abort.signal },\n {\n onDelta: (text) => {\n streamedText += text;\n const [event, data] = responseDeltaEvent(stream, text);\n writeSseEvent(res, event, data);\n },\n onModel: (nextModel) => {\n lastModel = nextModel;\n },\n },\n );\n lastModel = result.model;\n if (result.text !== streamedText) {\n const delta = result.text.startsWith(streamedText)\n ? result.text.slice(streamedText.length)\n : result.text;\n if (delta) {\n streamedText += delta;\n const [event, data] = responseDeltaEvent(stream, delta);\n writeSseEvent(res, event, data);\n }\n }\n for (const [event, data] of responseDoneEvents(\n stream,\n lastModel,\n result.text,\n )) {\n writeSseEvent(res, event, data);\n }\n } catch (error) {\n writeSseError(res, error);\n }\n res.end();\n}\n\nfunction readJson(\n req: IncomingMessage,\n maxBodyBytes = defaultMaxBodyBytes,\n): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n let bytes = 0;\n let tooLarge = false;\n req.setEncoding(\"utf8\");\n req.on(\"data\", (chunk) => {\n if (tooLarge) return;\n bytes += Buffer.byteLength(chunk);\n if (bytes > maxBodyBytes) {\n tooLarge = true;\n reject(\n new RequestError(\n 413,\n \"payload_too_large\",\n `Request body exceeds ${maxBodyBytes} bytes`,\n ),\n );\n return;\n }\n body += chunk;\n });\n req.on(\"end\", () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new RequestError(400, \"invalid_json\", \"Invalid JSON\"));\n }\n });\n req.on(\"error\", reject);\n });\n}\n\nfunction setCors(res: ServerResponse) {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET,POST,OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\");\n}\n\nfunction writeSseHeaders(res: ServerResponse) {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n}\n\nfunction writeSseEvent(\n res: ServerResponse,\n event: string,\n data: Record<string, unknown>,\n) {\n res.write(`event: ${event}\\n`);\n res.write(`data: ${JSON.stringify({ type: event, ...data })}\\n\\n`);\n}\n\nfunction writeSseError(res: ServerResponse, error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n res.write(\"event: error\\n\");\n res.write(\n `data: ${JSON.stringify({\n type: \"error\",\n error: {\n message,\n type: \"server_error\",\n code: \"internal_error\",\n },\n })}\\n\\n`,\n );\n}\n\nfunction sendError(res: ServerResponse, error: unknown) {\n /* v8 ignore next 4 -- last-resort guard for unexpected errors after SSE headers. */\n if (res.headersSent) {\n writeSseError(res, error);\n res.end();\n return;\n }\n const status = error instanceof RequestError ? error.status : 500;\n sendJson(res, status, {\n error: {\n message: error instanceof Error ? error.message : String(error),\n type:\n error instanceof RequestError\n ? \"invalid_request_error\"\n : \"server_error\",\n code: error instanceof RequestError ? error.code : \"internal_error\",\n },\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, value: unknown) {\n /* v8 ignore next -- this is a last-resort guard for errors after SSE headers. */\n if (res.headersSent) return;\n const body = JSON.stringify(value);\n res.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"content-length\": Buffer.byteLength(body),\n });\n res.end(body);\n}\n"],"mappings":"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"}