cursor-agent-bridge 0.1.3 → 0.1.4

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 CHANGED
@@ -16,6 +16,7 @@ clients.
16
16
  Check Cursor Agent first:
17
17
 
18
18
  ```bash
19
+ # Install from https://cursor.com/install, then authenticate the CLI.
19
20
  agent login
20
21
  agent --list-models
21
22
  ```
@@ -119,7 +120,25 @@ run `cursor-agent-bridge serve` yourself before starting Codex.
119
120
 
120
121
  ## Codex Config
121
122
 
122
- Create `~/.codex/cursor.config.toml`:
123
+ Create or update `~/.codex/cursor.config.toml`:
124
+
125
+ ```bash
126
+ cursor-agent-bridge config write
127
+ ```
128
+
129
+ Preview the generated profile without writing a file:
130
+
131
+ ```bash
132
+ cursor-agent-bridge config print
133
+ ```
134
+
135
+ Validate an existing profile:
136
+
137
+ ```bash
138
+ cursor-agent-bridge config check
139
+ ```
140
+
141
+ The generated profile looks like this:
123
142
 
124
143
  ```toml
125
144
  model_provider = "cursor"
@@ -140,6 +159,24 @@ codex --profile cursor
140
159
  Use `/model` in Codex to pick a Cursor model. The model catalog comes from
141
160
  `agent --list-models`.
142
161
 
162
+ ## Troubleshooting
163
+
164
+ Run a full preflight before starting Codex:
165
+
166
+ ```bash
167
+ cursor-agent-bridge doctor
168
+ ```
169
+
170
+ List available Cursor models without starting the HTTP server:
171
+
172
+ ```bash
173
+ cursor-agent-bridge models
174
+ cursor-agent-bridge models --json
175
+ ```
176
+
177
+ If `config write` finds a different `model_provider`, pass `--force` to switch
178
+ the profile to `cursor`.
179
+
143
180
  ## API
144
181
 
145
182
  ```text
package/dist/cli.mjs CHANGED
@@ -1,10 +1,420 @@
1
1
  #!/usr/bin/env node
2
- import { n as version, t as startServer } from "./server-BFgBwbF5.mjs";
2
+ import { i as CursorRunner, n as engines, r as version, s as toOpenAIModelList, t as startServer } from "./server-Bk7ol2lA.mjs";
3
3
  import { execFile, execFileSync, spawn } from "node:child_process";
4
- import { chmodSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
5
  import { homedir } from "node:os";
6
6
  import { dirname, join, resolve } from "node:path";
7
7
  import { promisify } from "node:util";
8
+ import { chmodSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
9
+ //#region src/cli-args.ts
10
+ function readArg(name, fallback) {
11
+ const index = process.argv.indexOf(name);
12
+ if (index < 0) return fallback;
13
+ const value = process.argv[index + 1];
14
+ if (!value || value.startsWith("-")) throw new Error(`Missing value for ${name}`);
15
+ return value;
16
+ }
17
+ function parsePort(value, fallback) {
18
+ if (value === void 0) return fallback;
19
+ const port = Number(value);
20
+ if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(`Invalid port: ${value}`);
21
+ return port;
22
+ }
23
+ function readHostAndPort(defaultHost = "127.0.0.1", defaultPort = 4646) {
24
+ return {
25
+ host: readArg("--host", process.env.HOST) ?? defaultHost,
26
+ port: parsePort(readArg("--port", process.env.PORT), defaultPort)
27
+ };
28
+ }
29
+ //#endregion
30
+ //#region src/codex-config.ts
31
+ const DEFAULT_CODEX_PROFILE = "cursor";
32
+ function resolveCodexConfigPath(profile = DEFAULT_CODEX_PROFILE, homeDir = homedir()) {
33
+ assertValidProfile(profile);
34
+ return join(homeDir, ".codex", `${profile}.config.toml`);
35
+ }
36
+ function buildBaseUrl(host, port) {
37
+ return `http://${host}:${port}/v1`;
38
+ }
39
+ function buildCodexConfigToml(options) {
40
+ const profile = options.profile ?? "cursor";
41
+ assertValidProfile(profile);
42
+ const baseUrl = buildBaseUrl(options.host, options.port);
43
+ return `model_provider = ${formatTomlString(profile)}
44
+ model = "auto"
45
+
46
+ [model_providers.${profile}]
47
+ name = "Cursor Agent Bridge"
48
+ base_url = ${formatTomlString(baseUrl)}
49
+ wire_api = "responses"
50
+ `;
51
+ }
52
+ function parseCodexConfig(content, profile = DEFAULT_CODEX_PROFILE) {
53
+ assertValidProfile(profile);
54
+ const fields = {};
55
+ const providerSection = `model_providers.${profile}`;
56
+ let section = "";
57
+ for (const rawLine of content.split("\n")) {
58
+ const line = rawLine.trim();
59
+ if (!line || line.startsWith("#")) continue;
60
+ const sectionMatch = line.match(/^\[(.+)\]$/);
61
+ if (sectionMatch) {
62
+ section = sectionMatch[1] ?? "";
63
+ continue;
64
+ }
65
+ const assignment = line.match(/^([A-Za-z0-9_.-]+)\s*=\s*(.+)$/);
66
+ if (!assignment) continue;
67
+ const key = assignment[1] ?? "";
68
+ const value = parseTomlValue(assignment[2] ?? "");
69
+ if (section === providerSection) {
70
+ if (key === "name") fields.providerName = value;
71
+ if (key === "base_url") fields.baseUrl = value;
72
+ if (key === "wire_api") fields.wireApi = value;
73
+ continue;
74
+ }
75
+ if (section) continue;
76
+ if (key === "model_provider") fields.modelProvider = value;
77
+ if (key === "model") fields.model = value;
78
+ }
79
+ return fields;
80
+ }
81
+ function checkCodexConfig(content, options) {
82
+ const profile = options.profile ?? "cursor";
83
+ const expectedBaseUrl = buildBaseUrl(options.host, options.port);
84
+ const fields = parseCodexConfig(content, profile);
85
+ const issues = [];
86
+ if (fields.modelProvider !== profile) issues.push(`model_provider should be "${profile}"${fields.modelProvider ? `, found "${fields.modelProvider}"` : ", but it is missing"}`);
87
+ if (fields.baseUrl !== expectedBaseUrl) issues.push(`base_url should be "${expectedBaseUrl}"${fields.baseUrl ? `, found "${fields.baseUrl}"` : ", but it is missing"}`);
88
+ if (fields.wireApi !== "responses") issues.push(`wire_api should be "responses"${fields.wireApi ? `, found "${fields.wireApi}"` : ", but it is missing"}`);
89
+ return {
90
+ ok: issues.length === 0,
91
+ issues
92
+ };
93
+ }
94
+ async function writeCodexConfig(options) {
95
+ let existing;
96
+ try {
97
+ existing = await readFile(options.filePath, "utf8");
98
+ } catch (error) {
99
+ if (error.code !== "ENOENT") throw error;
100
+ }
101
+ if (existing === void 0) {
102
+ await mkdir(dirname(options.filePath), { recursive: true });
103
+ await writeFile(options.filePath, buildCodexConfigToml(options), "utf8");
104
+ return {
105
+ path: options.filePath,
106
+ created: true,
107
+ updated: false
108
+ };
109
+ }
110
+ const merged = mergeCodexConfig(existing, options);
111
+ if ("error" in merged) throw new Error(merged.error);
112
+ if (!merged.changed) return {
113
+ path: options.filePath,
114
+ created: false,
115
+ updated: false
116
+ };
117
+ await writeFile(options.filePath, merged.content, "utf8");
118
+ return {
119
+ path: options.filePath,
120
+ created: false,
121
+ updated: true
122
+ };
123
+ }
124
+ function mergeCodexConfig(existing, options) {
125
+ const profile = options.profile ?? "cursor";
126
+ assertValidProfile(profile);
127
+ const providerSection = `model_providers.${profile}`;
128
+ const expected = buildCodexConfigToml(options);
129
+ const parsed = parseCodexConfig(existing, profile);
130
+ if (parsed.modelProvider && parsed.modelProvider !== profile && !options.force) return { error: `model_provider is "${parsed.modelProvider}". Re-run with --force to switch it to "${profile}".` };
131
+ const lines = existing.split("\n");
132
+ const output = [];
133
+ let section = "";
134
+ let inProviderSection = false;
135
+ let sawModelProvider = false;
136
+ let sawModel = false;
137
+ let sawProviderSection = false;
138
+ const handledProviderKeys = /* @__PURE__ */ new Set();
139
+ for (const rawLine of lines) {
140
+ const trimmed = rawLine.trim();
141
+ const sectionMatch = trimmed.match(/^\[(.+)\]$/);
142
+ if (sectionMatch) {
143
+ if (inProviderSection) appendMissingProviderKeys();
144
+ section = sectionMatch[1] ?? "";
145
+ inProviderSection = section === providerSection;
146
+ if (inProviderSection) sawProviderSection = true;
147
+ output.push(rawLine);
148
+ continue;
149
+ }
150
+ const assignment = trimmed.match(/^([A-Za-z0-9_.-]+)\s*=\s*(.+)$/);
151
+ if (!assignment) {
152
+ output.push(rawLine);
153
+ continue;
154
+ }
155
+ const key = assignment[1] ?? "";
156
+ if (!section) {
157
+ if (key === "model_provider") {
158
+ sawModelProvider = true;
159
+ output.push(`model_provider = ${formatTomlString(profile)}`);
160
+ continue;
161
+ }
162
+ if (key === "model") {
163
+ sawModel = true;
164
+ if (parsed.model === void 0 || options.force) output.push("model = \"auto\"");
165
+ else output.push(rawLine);
166
+ continue;
167
+ }
168
+ }
169
+ if (inProviderSection) {
170
+ if (key === "name") {
171
+ handledProviderKeys.add("name");
172
+ output.push("name = \"Cursor Agent Bridge\"");
173
+ continue;
174
+ }
175
+ if (key === "base_url") {
176
+ handledProviderKeys.add("base_url");
177
+ output.push(`base_url = ${formatTomlString(buildBaseUrl(options.host, options.port))}`);
178
+ continue;
179
+ }
180
+ if (key === "wire_api") {
181
+ handledProviderKeys.add("wire_api");
182
+ output.push("wire_api = \"responses\"");
183
+ continue;
184
+ }
185
+ }
186
+ output.push(rawLine);
187
+ }
188
+ if (inProviderSection) appendMissingProviderKeys();
189
+ const missingTopLevel = [];
190
+ if (!sawModelProvider) missingTopLevel.push(`model_provider = ${formatTomlString(profile)}`);
191
+ if (!sawModel) missingTopLevel.push("model = \"auto\"");
192
+ let content = output.join("\n").trimEnd();
193
+ if (missingTopLevel.length > 0) content = `${missingTopLevel.join("\n")}\n${content}`;
194
+ if (!sawProviderSection) {
195
+ const providerBlock = expected.split("\n").slice(3).join("\n");
196
+ content = `${content}\n\n${providerBlock}\n`;
197
+ }
198
+ const changed = normalizeToml(content) !== normalizeToml(existing);
199
+ return {
200
+ content: `${content.trimEnd()}\n`,
201
+ changed
202
+ };
203
+ function appendMissingProviderKeys() {
204
+ if (!handledProviderKeys.has("name")) output.push("name = \"Cursor Agent Bridge\"");
205
+ if (!handledProviderKeys.has("base_url")) output.push(`base_url = ${formatTomlString(buildBaseUrl(options.host, options.port))}`);
206
+ if (!handledProviderKeys.has("wire_api")) output.push("wire_api = \"responses\"");
207
+ }
208
+ }
209
+ function assertValidProfile(profile) {
210
+ if (/^[A-Za-z0-9_-]+$/.test(profile)) return;
211
+ throw new Error("Invalid Codex profile. Use only letters, numbers, underscores, or hyphens.");
212
+ }
213
+ function formatTomlString(value) {
214
+ return `"${value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"").replaceAll("\b", "\\b").replaceAll(" ", "\\t").replaceAll("\n", "\\n").replaceAll("\f", "\\f").replaceAll("\r", "\\r")}"`;
215
+ }
216
+ function normalizeToml(content) {
217
+ return content.replace(/\r\n/g, "\n").trimEnd();
218
+ }
219
+ function parseTomlValue(raw) {
220
+ const trimmed = stripInlineTomlComment(raw).trim();
221
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"")) return unescapeTomlString(trimmed.slice(1, -1));
222
+ if (trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
223
+ return trimmed;
224
+ }
225
+ function unescapeTomlString(value) {
226
+ return value.replace(/\\(["\\btnfr])/g, (_match, escaped) => ({
227
+ "\"": "\"",
228
+ "\\": "\\",
229
+ b: "\b",
230
+ t: " ",
231
+ n: "\n",
232
+ f: "\f",
233
+ r: "\r"
234
+ })[escaped] ?? escaped);
235
+ }
236
+ function stripInlineTomlComment(raw) {
237
+ let quote;
238
+ for (let index = 0; index < raw.length; index += 1) {
239
+ const char = raw[index];
240
+ if ((char === "\"" || char === "'") && raw[index - 1] !== "\\") {
241
+ quote = quote === char ? void 0 : quote ?? char;
242
+ continue;
243
+ }
244
+ if (!quote && char === "#") return raw.slice(0, index);
245
+ }
246
+ return raw;
247
+ }
248
+ //#endregion
249
+ //#region src/doctor.ts
250
+ const execFileAsync$1 = promisify(execFile);
251
+ async function runDoctor(options) {
252
+ const checks = [];
253
+ const fetchFn = options.fetchFn ?? fetch;
254
+ const execFileFn = options.execFileFn ?? execFileAsync$1;
255
+ const readFileFn = options.readFileFn ?? readFile;
256
+ const agentPath = options.agentPath ?? process.env.CURSOR_AGENT_PATH ?? "agent";
257
+ const profile = options.profile ?? "cursor";
258
+ const codexConfigPath = options.codexConfigPath ?? resolveCodexConfigPath(profile);
259
+ checks.push(checkNodeVersion(options.nodeVersionRange ?? engines.node));
260
+ checks.push({
261
+ name: "bridge-version",
262
+ ok: true,
263
+ message: `cursor-agent-bridge ${version}`
264
+ });
265
+ const agentCheck = await checkAgentExecutable(agentPath, execFileFn);
266
+ checks.push(agentCheck);
267
+ if (agentCheck.ok) checks.push(await checkAgentLogin(agentPath, options.runner));
268
+ checks.push(await checkBridgeHealth(options.host, options.port, fetchFn));
269
+ if (!options.skipCodexConfig) checks.push(await checkCodexConfigFile({
270
+ codexConfigPath,
271
+ host: options.host,
272
+ port: options.port,
273
+ profile,
274
+ readFileFn
275
+ }));
276
+ return {
277
+ ok: checks.every((check) => check.ok),
278
+ checks
279
+ };
280
+ }
281
+ function formatDoctorReport(result) {
282
+ const lines = result.checks.map((check) => {
283
+ const prefix = check.ok ? "✓" : "✗";
284
+ const hint = check.hint ? `\n → ${check.hint}` : "";
285
+ return `${prefix} ${check.name}: ${check.message}${hint}`;
286
+ });
287
+ lines.push("");
288
+ lines.push(result.ok ? "All checks passed. Codex can use Cursor Agent through the bridge." : "Some checks failed. Fix the items above before starting Codex.");
289
+ return `${lines.join("\n")}\n`;
290
+ }
291
+ function checkNodeVersion(requiredRange) {
292
+ const current = process.version.slice(1);
293
+ const minimum = parseMinimumNodeVersion(requiredRange);
294
+ const ok = compareNodeVersion(current, minimum) >= 0;
295
+ return ok ? {
296
+ name: "node-version",
297
+ ok,
298
+ message: `Node ${current} satisfies ${requiredRange}`
299
+ } : {
300
+ name: "node-version",
301
+ ok,
302
+ message: `Node ${current} does not satisfy ${requiredRange}`,
303
+ hint: `Install Node ${minimum} or newer.`
304
+ };
305
+ }
306
+ async function checkAgentExecutable(agentPath, execFileFn) {
307
+ try {
308
+ await execFileFn(agentPath, ["--help"], { timeout: 5e3 });
309
+ return {
310
+ name: "agent-cli",
311
+ ok: true,
312
+ message: `Cursor Agent CLI found at ${agentPath}`
313
+ };
314
+ } catch (error) {
315
+ return {
316
+ name: "agent-cli",
317
+ ok: false,
318
+ message: error instanceof Error ? error.message : "Cursor Agent CLI not found",
319
+ hint: "Install the Cursor Agent CLI and ensure `agent` is on PATH, or set CURSOR_AGENT_PATH."
320
+ };
321
+ }
322
+ }
323
+ async function checkAgentLogin(agentPath, runner = new CursorRunner({ agentPath })) {
324
+ try {
325
+ const models = await runner.listModels({ refresh: true });
326
+ if (models.length === 0) return {
327
+ name: "agent-login",
328
+ ok: false,
329
+ message: "Cursor Agent responded, but returned no models",
330
+ hint: "Run `agent login` and confirm `agent --list-models` returns models."
331
+ };
332
+ return {
333
+ name: "agent-login",
334
+ ok: true,
335
+ message: `Cursor Agent is logged in (${models.length} models available)`
336
+ };
337
+ } catch (error) {
338
+ return {
339
+ name: "agent-login",
340
+ ok: false,
341
+ message: error instanceof Error ? error.message : "Cursor Agent login check failed",
342
+ hint: "Run `agent login` and retry `cursor-agent-bridge doctor`."
343
+ };
344
+ }
345
+ }
346
+ async function checkBridgeHealth(host, port, fetchFn) {
347
+ const url = `http://${host}:${port}/health`;
348
+ try {
349
+ const response = await fetchFn(url, { signal: AbortSignal.timeout(3e3) });
350
+ if (!response.ok) return {
351
+ name: "bridge-health",
352
+ ok: false,
353
+ message: `${url} returned HTTP ${response.status}`,
354
+ hint: "Start the bridge with `cursor-agent-bridge serve` or `cursor-agent-bridge launch-agent install`."
355
+ };
356
+ const payload = await response.json();
357
+ return {
358
+ name: "bridge-health",
359
+ ok: true,
360
+ message: payload.version ? `Bridge is listening on ${url} (version ${payload.version})` : `Bridge is listening on ${url}`
361
+ };
362
+ } catch (error) {
363
+ return {
364
+ name: "bridge-health",
365
+ ok: false,
366
+ message: error instanceof Error ? error.message : "Bridge health check failed",
367
+ hint: "Start the bridge with `cursor-agent-bridge serve` or `cursor-agent-bridge launch-agent install`."
368
+ };
369
+ }
370
+ }
371
+ async function checkCodexConfigFile(options) {
372
+ try {
373
+ const result = checkCodexConfig(await options.readFileFn(options.codexConfigPath, "utf8"), {
374
+ host: options.host,
375
+ port: options.port,
376
+ profile: options.profile
377
+ });
378
+ if (result.ok) return {
379
+ name: "codex-config",
380
+ ok: true,
381
+ message: `Codex config looks correct at ${options.codexConfigPath}`
382
+ };
383
+ return {
384
+ name: "codex-config",
385
+ ok: false,
386
+ message: result.issues.join("; "),
387
+ hint: "Run `cursor-agent-bridge config write` or `cursor-agent-bridge config print`."
388
+ };
389
+ } catch (error) {
390
+ if (error.code === "ENOENT") return {
391
+ name: "codex-config",
392
+ ok: false,
393
+ message: `Codex config not found at ${options.codexConfigPath}`,
394
+ hint: "Run `cursor-agent-bridge config write` to create it."
395
+ };
396
+ return {
397
+ name: "codex-config",
398
+ ok: false,
399
+ message: error instanceof Error ? error.message : "Codex config check failed",
400
+ hint: "Verify the Codex config path and file permissions."
401
+ };
402
+ }
403
+ }
404
+ function parseMinimumNodeVersion(range) {
405
+ const match = range.match(/(\d+)\.(\d+)(?:\.(\d+))?/);
406
+ if (!match) return "0.0.0";
407
+ return `${match[1]}.${match[2]}.${match[3] ?? 0}`;
408
+ }
409
+ function compareNodeVersion(left, right) {
410
+ const toParts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
411
+ const [leftMajor = 0, leftMinor = 0, leftPatch = 0] = toParts(left);
412
+ const [rightMajor = 0, rightMinor = 0, rightPatch = 0] = toParts(right);
413
+ if (leftMajor !== rightMajor) return leftMajor - rightMajor;
414
+ if (leftMinor !== rightMinor) return leftMinor - rightMinor;
415
+ return leftPatch - rightPatch;
416
+ }
417
+ //#endregion
8
418
  //#region src/launch-agent.ts
9
419
  const defaultLabel = "com.xwartz.cursor-agent-bridge";
10
420
  const defaultLogDir = join(homedir(), ".codex", "logs");
@@ -270,25 +680,17 @@ async function runUpgrade(options) {
270
680
  }
271
681
  //#endregion
272
682
  //#region src/cli.ts
273
- function readArg(name, fallback) {
274
- const index = process.argv.indexOf(name);
275
- if (index < 0) return fallback;
276
- const value = process.argv[index + 1];
277
- if (!value || value.startsWith("-")) throw new Error(`Missing value for ${name}`);
278
- return value;
279
- }
280
- function parsePort(value, fallback) {
281
- if (value === void 0) return fallback;
282
- const port = Number(value);
283
- if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(`Invalid port: ${value}`);
284
- return port;
285
- }
286
683
  const command = process.argv[2] && !process.argv[2]?.startsWith("-") ? process.argv[2] : "serve";
287
684
  if (command === "help" || process.argv.includes("--help") || process.argv.includes("-h")) {
288
685
  console.log(`cursor-agent-bridge
289
686
 
290
687
  Usage:
291
688
  cursor-agent-bridge serve [--host 127.0.0.1] [--port 4646]
689
+ cursor-agent-bridge doctor [--host 127.0.0.1] [--port 4646] [--profile cursor] [--file ~/.codex/cursor.config.toml] [--skip-codex-config]
690
+ cursor-agent-bridge config print [--host 127.0.0.1] [--port 4646] [--profile cursor]
691
+ cursor-agent-bridge config check [--file ~/.codex/cursor.config.toml] [--host 127.0.0.1] [--port 4646] [--profile cursor]
692
+ cursor-agent-bridge config write [--file ~/.codex/cursor.config.toml] [--host 127.0.0.1] [--port 4646] [--profile cursor] [--force]
693
+ cursor-agent-bridge models [--json] [--refresh]
292
694
  cursor-agent-bridge launch-agent install [--host 127.0.0.1] [--port 4646] [--agent-path agent]
293
695
  cursor-agent-bridge launch-agent uninstall
294
696
  cursor-agent-bridge launch-agent status
@@ -321,12 +723,90 @@ if (command === "upgrade") {
321
723
  });
322
724
  process.exit(exitCode);
323
725
  }
726
+ if (command === "doctor") try {
727
+ const { host, port } = readHostAndPort();
728
+ const profile = readArg("--profile", "cursor") ?? "cursor";
729
+ const codexConfigPath = readArg("--file", void 0);
730
+ const result = await runDoctor({
731
+ host,
732
+ port,
733
+ profile,
734
+ skipCodexConfig: process.argv.includes("--skip-codex-config"),
735
+ ...process.env.CURSOR_AGENT_PATH ? { agentPath: process.env.CURSOR_AGENT_PATH } : {},
736
+ ...codexConfigPath ? { codexConfigPath } : {}
737
+ });
738
+ process.stdout.write(formatDoctorReport(result));
739
+ process.exit(result.ok ? 0 : 1);
740
+ } catch (error) {
741
+ console.error(error instanceof Error ? error.message : String(error));
742
+ process.exit(1);
743
+ }
744
+ if (command === "config") {
745
+ const action = process.argv[3] ?? "print";
746
+ try {
747
+ const { host, port } = readHostAndPort();
748
+ const profile = readArg("--profile", "cursor") ?? "cursor";
749
+ const filePath = readArg("--file", void 0) ?? resolveCodexConfigPath(profile);
750
+ if (action === "print") {
751
+ process.stdout.write(buildCodexConfigToml({
752
+ host,
753
+ port,
754
+ profile
755
+ }));
756
+ console.error(`Start Codex with: codex --profile ${profile}`);
757
+ process.exit(0);
758
+ }
759
+ if (action === "check") {
760
+ const result = checkCodexConfig(await readFile(filePath, "utf8"), {
761
+ host,
762
+ port,
763
+ profile
764
+ });
765
+ if (result.ok) {
766
+ console.log(`Codex config looks correct: ${filePath}`);
767
+ process.exit(0);
768
+ }
769
+ for (const issue of result.issues) console.error(issue);
770
+ process.exit(1);
771
+ }
772
+ if (action === "write") {
773
+ const result = await writeCodexConfig({
774
+ filePath,
775
+ host,
776
+ port,
777
+ profile,
778
+ force: process.argv.includes("--force")
779
+ });
780
+ if (result.created) console.log(`Created Codex config at ${result.path}`);
781
+ else if (result.updated) console.log(`Updated Codex config at ${result.path}`);
782
+ else console.log(`Codex config already up to date at ${result.path}`);
783
+ console.log(`Start Codex with: codex --profile ${profile}`);
784
+ process.exit(0);
785
+ }
786
+ } catch (error) {
787
+ console.error(error instanceof Error ? error.message : String(error));
788
+ process.exit(1);
789
+ }
790
+ console.error(`Unknown config action: ${action}`);
791
+ process.exit(1);
792
+ }
793
+ if (command === "models") try {
794
+ const models = await new CursorRunner({ ...process.env.CURSOR_AGENT_PATH ? { agentPath: process.env.CURSOR_AGENT_PATH } : {} }).listModels({ refresh: process.argv.includes("--refresh") });
795
+ if (process.argv.includes("--json")) {
796
+ console.log(JSON.stringify(toOpenAIModelList(models), null, 2));
797
+ process.exit(0);
798
+ }
799
+ for (const model of models) console.log(model.id);
800
+ process.exit(0);
801
+ } catch (error) {
802
+ console.error(error instanceof Error ? error.message : String(error));
803
+ process.exit(1);
804
+ }
324
805
  if (command === "launch-agent") {
325
806
  const action = process.argv[3] ?? "status";
326
807
  try {
327
808
  if (action === "install") {
328
- const host = readArg("--host", process.env.HOST) ?? "127.0.0.1";
329
- const port = parsePort(readArg("--port", process.env.PORT), 4646);
809
+ const { host, port } = readHostAndPort();
330
810
  const agentPath = readArg("--agent-path", process.env.CURSOR_AGENT_PATH);
331
811
  const paths = installLaunchAgent({
332
812
  cliPath: process.argv[1] ?? "cursor-agent-bridge",
@@ -361,8 +841,9 @@ if (command !== "serve") {
361
841
  let host;
362
842
  let port;
363
843
  try {
364
- host = readArg("--host", process.env.HOST) ?? "127.0.0.1";
365
- port = parsePort(readArg("--port", process.env.PORT), 4646);
844
+ const options = readHostAndPort();
845
+ host = options.host;
846
+ port = options.port;
366
847
  } catch (error) {
367
848
  console.error(error instanceof Error ? error.message : String(error));
368
849
  process.exit(1);
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["packageJson.version"],"sources":["../src/launch-agent.ts","../src/upgrade.ts","../src/cli.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\nconst defaultLabel = \"com.xwartz.cursor-agent-bridge\";\nconst defaultLogDir = join(homedir(), \".codex\", \"logs\");\n\nexport type LaunchAgentOptions = {\n cliPath: string;\n host?: string;\n port?: number;\n agentPath?: string;\n label?: string;\n};\n\nexport type LaunchAgentPaths = {\n label: string;\n plistPath: string;\n stdoutPath: string;\n stderrPath: string;\n};\n\nexport function getLaunchAgentPaths(label = defaultLabel): LaunchAgentPaths {\n return {\n label,\n plistPath: join(homedir(), \"Library\", \"LaunchAgents\", `${label}.plist`),\n stdoutPath: join(defaultLogDir, \"cursor-agent-bridge.log\"),\n stderrPath: join(defaultLogDir, \"cursor-agent-bridge.err.log\"),\n };\n}\n\nexport function createLaunchAgentPlist(options: LaunchAgentOptions) {\n const label = options.label ?? defaultLabel;\n const host = options.host ?? \"127.0.0.1\";\n const port = options.port ?? 4646;\n const paths = getLaunchAgentPaths(label);\n const args = [\n resolve(options.cliPath),\n \"serve\",\n \"--host\",\n host,\n \"--port\",\n String(port),\n ];\n const env: Record<string, string> = {\n PATH: [\n dirname(resolve(options.cliPath)),\n join(homedir(), \".local\", \"bin\"),\n \"/usr/local/bin\",\n \"/opt/homebrew/bin\",\n \"/usr/bin\",\n \"/bin\",\n \"/usr/sbin\",\n \"/sbin\",\n ].join(\":\"),\n };\n\n if (options.agentPath) {\n env.CURSOR_AGENT_PATH = options.agentPath;\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${escapePlist(label)}</string>\n\n <key>ProgramArguments</key>\n <array>\n${args.map((arg) => ` <string>${escapePlist(arg)}</string>`).join(\"\\n\")}\n </array>\n\n <key>EnvironmentVariables</key>\n <dict>\n${Object.entries(env)\n .map(\n ([key, value]) =>\n ` <key>${escapePlist(key)}</key>\\n <string>${escapePlist(value)}</string>`,\n )\n .join(\"\\n\")}\n </dict>\n\n <key>RunAtLoad</key>\n <true/>\n\n <key>KeepAlive</key>\n <true/>\n\n <key>StandardOutPath</key>\n <string>${escapePlist(paths.stdoutPath)}</string>\n\n <key>StandardErrorPath</key>\n <string>${escapePlist(paths.stderrPath)}</string>\n</dict>\n</plist>\n`;\n}\n\nexport function installLaunchAgent(options: LaunchAgentOptions) {\n ensureMacOS();\n const label = options.label ?? defaultLabel;\n const paths = getLaunchAgentPaths(label);\n mkdirSync(dirname(paths.plistPath), { recursive: true });\n mkdirSync(defaultLogDir, { recursive: true });\n\n if (existsSync(paths.plistPath)) {\n bootout(paths.plistPath);\n }\n\n writeFileSync(paths.plistPath, createLaunchAgentPlist(options));\n chmodSync(paths.plistPath, 0o644);\n execFileSync(\"launchctl\", [\"bootstrap\", launchctlDomain(), paths.plistPath], {\n stdio: \"pipe\",\n });\n return paths;\n}\n\nexport function uninstallLaunchAgent(label = defaultLabel) {\n ensureMacOS();\n const paths = getLaunchAgentPaths(label);\n bootout(paths.plistPath);\n rmSync(paths.plistPath, { force: true });\n return paths;\n}\n\nexport function printLaunchAgentStatus(label = defaultLabel) {\n ensureMacOS();\n return execFileSync(\"launchctl\", [\"print\", `${launchctlDomain()}/${label}`], {\n encoding: \"utf8\",\n });\n}\n\nfunction bootout(plistPath: string) {\n try {\n execFileSync(\"launchctl\", [\"bootout\", launchctlDomain(), plistPath], {\n stdio: \"pipe\",\n });\n } catch {\n // It is fine if the service is not loaded yet.\n }\n}\n\nfunction launchctlDomain() {\n return `gui/${process.getuid?.() ?? execFileSync(\"id\", [\"-u\"], { encoding: \"utf8\" }).trim()}`;\n}\n\nfunction ensureMacOS() {\n if (process.platform !== \"darwin\") {\n throw new Error(\"LaunchAgent management is only available on macOS.\");\n }\n}\n\nfunction escapePlist(value: string) {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\");\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { promisify } from \"node:util\";\nimport { getLaunchAgentPaths } from \"./launch-agent.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport const PACKAGE_NAME = \"cursor-agent-bridge\";\nexport const DEFAULT_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;\nconst REGISTRY_TIMEOUT_MS = 10_000;\n\nexport type PackageManager = \"npm\" | \"pnpm\";\nexport type PackageManagerPreference = PackageManager | \"auto\";\n\nexport type ExecFileFn = (\n file: string,\n args?: readonly string[] | null,\n options?: { env?: NodeJS.ProcessEnv },\n) => Promise<unknown>;\n\nexport type SpawnFn = (\n command: string,\n args: readonly string[],\n options: { stdio: \"inherit\"; env?: NodeJS.ProcessEnv },\n) => {\n on(event: \"error\", listener: (error: Error) => void): unknown;\n on(event: \"close\", listener: (code: number | null) => void): unknown;\n};\n\nexport type UpgradeOptions = {\n currentVersion: string;\n checkOnly?: boolean;\n target?: string;\n manager?: PackageManagerPreference;\n registryUrl?: string;\n fetchFn?: typeof fetch;\n spawnFn?: SpawnFn;\n execFileFn?: ExecFileFn;\n existsFn?: typeof existsSync;\n log?: (...args: unknown[]) => void;\n errorLog?: (...args: unknown[]) => void;\n};\n\nexport function compareSemver(left: string, right: string): -1 | 0 | 1 {\n const toParts = (value: string) => {\n const [major = 0, minor = 0, patch = 0] = value\n .split(\".\")\n .map((part) => Number.parseInt(part, 10) || 0);\n return [major, minor, patch] as const;\n };\n const [leftMajor, leftMinor, leftPatch] = toParts(left);\n const [rightMajor, rightMinor, rightPatch] = toParts(right);\n\n if (leftMajor !== rightMajor) {\n return leftMajor < rightMajor ? -1 : 1;\n }\n if (leftMinor !== rightMinor) {\n return leftMinor < rightMinor ? -1 : 1;\n }\n if (leftPatch !== rightPatch) {\n return leftPatch < rightPatch ? -1 : 1;\n }\n return 0;\n}\n\nexport async function fetchLatestVersion(options?: {\n registryUrl?: string;\n fetchFn?: typeof fetch;\n timeoutMs?: number;\n}): Promise<string> {\n const registryUrl = options?.registryUrl ?? DEFAULT_REGISTRY_URL;\n const fetchFn = options?.fetchFn ?? fetch;\n const timeoutMs = options?.timeoutMs ?? REGISTRY_TIMEOUT_MS;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetchFn(registryUrl, { signal: controller.signal });\n if (!response.ok) {\n throw new Error(`Registry returned ${response.status}`);\n }\n\n const payload = (await response.json()) as { version?: string };\n if (!payload.version) {\n throw new Error(\"Registry response missing version\");\n }\n return payload.version;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function commandExists(\n command: string,\n execFileFn: ExecFileFn,\n): Promise<boolean> {\n try {\n await execFileFn(\"which\", [command]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function detectPackageManager(\n preference: PackageManagerPreference,\n execFileFn: ExecFileFn = execFileAsync,\n): Promise<PackageManager> {\n if (preference === \"npm\") return \"npm\";\n if (preference === \"pnpm\") return \"pnpm\";\n\n if (!(await commandExists(\"pnpm\", execFileFn))) {\n return \"npm\";\n }\n\n try {\n await execFileFn(\"pnpm\", [\"list\", \"-g\", PACKAGE_NAME, \"--json\"], {\n env: process.env,\n });\n return \"pnpm\";\n } catch {\n return \"npm\";\n }\n}\n\nexport function buildInstallCommand(\n manager: PackageManager,\n target: string,\n): { command: string; args: string[] } {\n const versionSpec =\n target === \"latest\" ? \"@latest\" : `@${target.replace(/^@/, \"\")}`;\n const packageSpec = `${PACKAGE_NAME}${versionSpec}`;\n\n if (manager === \"pnpm\") {\n return { command: \"pnpm\", args: [\"add\", \"-g\", packageSpec] };\n }\n\n return { command: \"npm\", args: [\"install\", \"-g\", packageSpec] };\n}\n\nfunction printManualUpgradeHint(errorLog: (...args: unknown[]) => void) {\n errorLog(\"Upgrade manually:\");\n errorLog(` pnpm add -g ${PACKAGE_NAME}@latest`);\n errorLog(` npm install -g ${PACKAGE_NAME}@latest`);\n}\n\nasync function resolveTargetVersion(\n target: string,\n registryUrl: string,\n fetchFn: typeof fetch,\n): Promise<string> {\n if (target === \"latest\") {\n return fetchLatestVersion({ registryUrl, fetchFn });\n }\n return target.replace(/^@/, \"\");\n}\n\nasync function runInstall(\n manager: PackageManager,\n target: string,\n spawnFn: SpawnFn,\n): Promise<number> {\n const { command, args } = buildInstallCommand(manager, target);\n return new Promise((resolve, reject) => {\n const child = spawnFn(command, args, {\n stdio: \"inherit\",\n env: process.env,\n });\n\n child.on(\"error\", reject);\n child.on(\"close\", (code) => resolve(code ?? 1));\n });\n}\n\nexport async function runUpgrade(options: UpgradeOptions): Promise<number> {\n const log = options.log ?? console.log;\n const errorLog = options.errorLog ?? console.error;\n const checkOnly = options.checkOnly ?? false;\n const target = options.target ?? \"latest\";\n const managerPreference = options.manager ?? \"auto\";\n const registryUrl = options.registryUrl ?? DEFAULT_REGISTRY_URL;\n const fetchFn = options.fetchFn ?? fetch;\n const spawnFn: SpawnFn =\n options.spawnFn ??\n ((command, args, spawnOptions) => spawn(command, args, spawnOptions));\n const execFileFn = options.execFileFn ?? execFileAsync;\n const existsFn = options.existsFn ?? existsSync;\n\n let targetVersion: string;\n try {\n targetVersion = await resolveTargetVersion(target, registryUrl, fetchFn);\n } catch (error) {\n errorLog(\n `Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`,\n );\n printManualUpgradeHint(errorLog);\n return 1;\n }\n\n const comparison = compareSemver(options.currentVersion, targetVersion);\n if (comparison >= 0) {\n log(`${PACKAGE_NAME} is up to date (${options.currentVersion})`);\n return 0;\n }\n\n if (checkOnly) {\n log(`Update available: ${options.currentVersion} -> ${targetVersion}`);\n return 1;\n }\n\n let manager: PackageManager;\n manager = await detectPackageManager(managerPreference, execFileFn);\n\n log(`Installing ${PACKAGE_NAME}@${targetVersion} via ${manager}...`);\n try {\n const exitCode = await runInstall(manager, target, spawnFn);\n if (exitCode !== 0) {\n errorLog(`${manager} install failed with exit code ${exitCode}`);\n printManualUpgradeHint(errorLog);\n return exitCode;\n }\n } catch (error) {\n errorLog(\n `Install failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n printManualUpgradeHint(errorLog);\n return 1;\n }\n\n log(`Installed ${PACKAGE_NAME}@${targetVersion}`);\n log(\"Run `cursor-agent-bridge --version` to verify the upgrade.\");\n\n const launchAgentPlist = getLaunchAgentPaths().plistPath;\n if (existsFn(launchAgentPlist)) {\n log(\n \"LaunchAgent detected. Run `cursor-agent-bridge launch-agent install` to refresh the service.\",\n );\n }\n\n return 0;\n}\n","#!/usr/bin/env node\n\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n installLaunchAgent,\n printLaunchAgentStatus,\n uninstallLaunchAgent,\n} from \"./launch-agent.js\";\nimport { startServer } from \"./server.js\";\nimport { runUpgrade } from \"./upgrade.js\";\n\nfunction readArg(name: string, fallback: string | undefined) {\n const index = process.argv.indexOf(name);\n if (index < 0) return fallback;\n const value = process.argv[index + 1];\n if (!value || value.startsWith(\"-\"))\n throw new Error(`Missing value for ${name}`);\n return value;\n}\n\nfunction parsePort(value: string | undefined, fallback: number) {\n if (value === undefined) return fallback;\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(`Invalid port: ${value}`);\n }\n return port;\n}\n\nconst command =\n process.argv[2] && !process.argv[2]?.startsWith(\"-\")\n ? process.argv[2]\n : \"serve\";\n\nif (\n command === \"help\" ||\n process.argv.includes(\"--help\") ||\n process.argv.includes(\"-h\")\n) {\n console.log(`cursor-agent-bridge\n\nUsage:\n cursor-agent-bridge serve [--host 127.0.0.1] [--port 4646]\n cursor-agent-bridge launch-agent install [--host 127.0.0.1] [--port 4646] [--agent-path agent]\n cursor-agent-bridge launch-agent uninstall\n cursor-agent-bridge launch-agent status\n cursor-agent-bridge upgrade [--check] [--target latest] [--manager auto|npm|pnpm]\n\nEnvironment:\n HOST Listen host, default 127.0.0.1\n PORT Listen port, default 4646\n CURSOR_AGENT_PATH Cursor Agent CLI path, default agent\n`);\n process.exit(0);\n}\n\nif (command === \"version\" || process.argv.includes(\"--version\")) {\n console.log(packageJson.version);\n process.exit(0);\n}\n\nif (command === \"upgrade\") {\n const checkOnly = process.argv.includes(\"--check\");\n const target = readArg(\"--target\", \"latest\") ?? \"latest\";\n const manager = readArg(\"--manager\", \"auto\") ?? \"auto\";\n\n if (manager !== \"auto\" && manager !== \"npm\" && manager !== \"pnpm\") {\n console.error(\"Invalid --manager value. Use auto, npm, or pnpm.\");\n process.exit(1);\n }\n\n const exitCode = await runUpgrade({\n currentVersion: packageJson.version,\n checkOnly,\n target,\n manager,\n });\n process.exit(exitCode);\n}\n\nif (command === \"launch-agent\") {\n const action = process.argv[3] ?? \"status\";\n try {\n if (action === \"install\") {\n const host = readArg(\"--host\", process.env.HOST) ?? \"127.0.0.1\";\n const port = parsePort(readArg(\"--port\", process.env.PORT), 4646);\n const agentPath = readArg(\"--agent-path\", process.env.CURSOR_AGENT_PATH);\n const paths = installLaunchAgent({\n cliPath: process.argv[1] ?? \"cursor-agent-bridge\",\n host,\n port,\n ...(agentPath ? { agentPath } : {}),\n });\n console.log(`Installed ${paths.label}`);\n console.log(paths.plistPath);\n process.exit(0);\n }\n\n if (action === \"uninstall\") {\n const paths = uninstallLaunchAgent();\n console.log(`Uninstalled ${paths.label}`);\n process.exit(0);\n }\n\n if (action === \"status\") {\n process.stdout.write(printLaunchAgentStatus());\n process.exit(0);\n }\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n\n console.error(`Unknown launch-agent action: ${action}`);\n process.exit(1);\n}\n\nif (command !== \"serve\") {\n console.error(`Unknown command: ${command}`);\n process.exit(1);\n}\n\nlet host: string;\nlet port: number;\ntry {\n host = readArg(\"--host\", process.env.HOST) ?? \"127.0.0.1\";\n port = parsePort(readArg(\"--port\", process.env.PORT), 4646);\n} catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n}\n\nconst server = await startServer({\n host,\n port,\n ...(process.env.CURSOR_AGENT_PATH\n ? { agentPath: process.env.CURSOR_AGENT_PATH }\n : {}),\n});\nconsole.log(`cursor-agent-bridge listening on http://${host}:${port}`);\n\nfunction shutdown() {\n server.close(() => process.exit(0));\n}\n\nprocess.on(\"SIGINT\", shutdown);\nprocess.on(\"SIGTERM\", shutdown);\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["execFileAsync","packageJson.version","packageJson.version"],"sources":["../src/cli-args.ts","../src/codex-config.ts","../src/doctor.ts","../src/launch-agent.ts","../src/upgrade.ts","../src/cli.ts"],"sourcesContent":["export function readArg(name: string, fallback: string | undefined) {\n const index = process.argv.indexOf(name)\n if (index < 0) return fallback\n const value = process.argv[index + 1]\n if (!value || value.startsWith(\"-\"))\n throw new Error(`Missing value for ${name}`)\n return value\n}\n\nexport function parsePort(value: string | undefined, fallback: number) {\n if (value === undefined) return fallback\n const port = Number(value)\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(`Invalid port: ${value}`)\n }\n return port\n}\n\nexport function readHostAndPort(defaultHost = \"127.0.0.1\", defaultPort = 4646) {\n const host = readArg(\"--host\", process.env.HOST) ?? defaultHost\n const port = parsePort(readArg(\"--port\", process.env.PORT), defaultPort)\n return { host, port }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { homedir } from \"node:os\"\nimport { dirname, join } from \"node:path\"\n\nexport const DEFAULT_CODEX_PROFILE = \"cursor\"\n\nexport type CodexConfigOptions = {\n host: string\n port: number\n profile?: string\n}\n\nexport type CodexConfigFields = {\n modelProvider?: string\n model?: string\n providerName?: string\n baseUrl?: string\n wireApi?: string\n}\n\nexport type CodexConfigCheckResult = {\n ok: boolean\n issues: string[]\n}\n\nexport type WriteCodexConfigResult = {\n path: string\n created: boolean\n updated: boolean\n}\n\nexport function resolveCodexConfigPath(\n profile = DEFAULT_CODEX_PROFILE,\n homeDir = homedir(),\n) {\n assertValidProfile(profile)\n return join(homeDir, \".codex\", `${profile}.config.toml`)\n}\n\nexport function buildBaseUrl(host: string, port: number) {\n return `http://${host}:${port}/v1`\n}\n\nexport function buildCodexConfigToml(options: CodexConfigOptions) {\n const profile = options.profile ?? DEFAULT_CODEX_PROFILE\n assertValidProfile(profile)\n const baseUrl = buildBaseUrl(options.host, options.port)\n return `model_provider = ${formatTomlString(profile)}\nmodel = \"auto\"\n\n[model_providers.${profile}]\nname = \"Cursor Agent Bridge\"\nbase_url = ${formatTomlString(baseUrl)}\nwire_api = \"responses\"\n`\n}\n\nexport function parseCodexConfig(\n content: string,\n profile = DEFAULT_CODEX_PROFILE,\n) {\n assertValidProfile(profile)\n const fields: CodexConfigFields = {}\n const providerSection = `model_providers.${profile}`\n let section = \"\"\n\n for (const rawLine of content.split(\"\\n\")) {\n const line = rawLine.trim()\n if (!line || line.startsWith(\"#\")) continue\n\n const sectionMatch = line.match(/^\\[(.+)\\]$/)\n if (sectionMatch) {\n section = sectionMatch[1] ?? \"\"\n continue\n }\n\n const assignment = line.match(/^([A-Za-z0-9_.-]+)\\s*=\\s*(.+)$/)\n if (!assignment) continue\n\n const key = assignment[1] ?? \"\"\n const value = parseTomlValue(assignment[2] ?? \"\")\n\n if (section === providerSection) {\n if (key === \"name\") fields.providerName = value\n if (key === \"base_url\") fields.baseUrl = value\n if (key === \"wire_api\") fields.wireApi = value\n continue\n }\n\n if (section) continue\n if (key === \"model_provider\") fields.modelProvider = value\n if (key === \"model\") fields.model = value\n }\n\n return fields\n}\n\nexport function checkCodexConfig(\n content: string,\n options: CodexConfigOptions,\n): CodexConfigCheckResult {\n const profile = options.profile ?? DEFAULT_CODEX_PROFILE\n const expectedBaseUrl = buildBaseUrl(options.host, options.port)\n const fields = parseCodexConfig(content, profile)\n const issues: string[] = []\n\n if (fields.modelProvider !== profile) {\n issues.push(\n `model_provider should be \"${profile}\"${\n fields.modelProvider\n ? `, found \"${fields.modelProvider}\"`\n : \", but it is missing\"\n }`,\n )\n }\n\n if (fields.baseUrl !== expectedBaseUrl) {\n issues.push(\n `base_url should be \"${expectedBaseUrl}\"${\n fields.baseUrl ? `, found \"${fields.baseUrl}\"` : \", but it is missing\"\n }`,\n )\n }\n\n if (fields.wireApi !== \"responses\") {\n issues.push(\n `wire_api should be \"responses\"${\n fields.wireApi ? `, found \"${fields.wireApi}\"` : \", but it is missing\"\n }`,\n )\n }\n\n return { ok: issues.length === 0, issues }\n}\n\nexport async function writeCodexConfig(\n options: CodexConfigOptions & {\n filePath: string\n force?: boolean\n },\n): Promise<WriteCodexConfigResult> {\n let existing: string | undefined\n\n try {\n existing = await readFile(options.filePath, \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n\n if (existing === undefined) {\n await mkdir(dirname(options.filePath), { recursive: true })\n await writeFile(options.filePath, buildCodexConfigToml(options), \"utf8\")\n return { path: options.filePath, created: true, updated: false }\n }\n\n const merged = mergeCodexConfig(existing, options)\n if (\"error\" in merged) throw new Error(merged.error)\n\n if (!merged.changed) {\n return { path: options.filePath, created: false, updated: false }\n }\n\n await writeFile(options.filePath, merged.content, \"utf8\")\n return { path: options.filePath, created: false, updated: true }\n}\n\nfunction mergeCodexConfig(\n existing: string,\n options: CodexConfigOptions & { force?: boolean },\n) {\n const profile = options.profile ?? DEFAULT_CODEX_PROFILE\n assertValidProfile(profile)\n const providerSection = `model_providers.${profile}`\n const expected = buildCodexConfigToml(options)\n const parsed = parseCodexConfig(existing, profile)\n\n if (\n parsed.modelProvider &&\n parsed.modelProvider !== profile &&\n !options.force\n ) {\n return {\n error: `model_provider is \"${parsed.modelProvider}\". Re-run with --force to switch it to \"${profile}\".`,\n }\n }\n\n const lines = existing.split(\"\\n\")\n const output: string[] = []\n let section = \"\"\n let inProviderSection = false\n let sawModelProvider = false\n let sawModel = false\n let sawProviderSection = false\n const handledProviderKeys = new Set<string>()\n\n for (const rawLine of lines) {\n const trimmed = rawLine.trim()\n const sectionMatch = trimmed.match(/^\\[(.+)\\]$/)\n if (sectionMatch) {\n if (inProviderSection) appendMissingProviderKeys()\n section = sectionMatch[1] ?? \"\"\n inProviderSection = section === providerSection\n if (inProviderSection) sawProviderSection = true\n output.push(rawLine)\n continue\n }\n\n const assignment = trimmed.match(/^([A-Za-z0-9_.-]+)\\s*=\\s*(.+)$/)\n if (!assignment) {\n output.push(rawLine)\n continue\n }\n\n const key = assignment[1] ?? \"\"\n\n if (!section) {\n if (key === \"model_provider\") {\n sawModelProvider = true\n output.push(`model_provider = ${formatTomlString(profile)}`)\n continue\n }\n if (key === \"model\") {\n sawModel = true\n if (parsed.model === undefined || options.force) {\n output.push('model = \"auto\"')\n } else {\n output.push(rawLine)\n }\n continue\n }\n }\n\n if (inProviderSection) {\n if (key === \"name\") {\n handledProviderKeys.add(\"name\")\n output.push('name = \"Cursor Agent Bridge\"')\n continue\n }\n if (key === \"base_url\") {\n handledProviderKeys.add(\"base_url\")\n output.push(\n `base_url = ${formatTomlString(buildBaseUrl(options.host, options.port))}`,\n )\n continue\n }\n if (key === \"wire_api\") {\n handledProviderKeys.add(\"wire_api\")\n output.push('wire_api = \"responses\"')\n continue\n }\n }\n\n output.push(rawLine)\n }\n\n if (inProviderSection) appendMissingProviderKeys()\n\n const missingTopLevel: string[] = []\n if (!sawModelProvider)\n missingTopLevel.push(`model_provider = ${formatTomlString(profile)}`)\n if (!sawModel) missingTopLevel.push('model = \"auto\"')\n\n let content = output.join(\"\\n\").trimEnd()\n if (missingTopLevel.length > 0) {\n content = `${missingTopLevel.join(\"\\n\")}\\n${content}`\n }\n\n if (!sawProviderSection) {\n const providerBlock = expected.split(\"\\n\").slice(3).join(\"\\n\")\n content = `${content}\\n\\n${providerBlock}\\n`\n }\n\n const changed = normalizeToml(content) !== normalizeToml(existing)\n return { content: `${content.trimEnd()}\\n`, changed }\n\n function appendMissingProviderKeys() {\n if (!handledProviderKeys.has(\"name\")) {\n output.push('name = \"Cursor Agent Bridge\"')\n }\n if (!handledProviderKeys.has(\"base_url\")) {\n output.push(\n `base_url = ${formatTomlString(buildBaseUrl(options.host, options.port))}`,\n )\n }\n if (!handledProviderKeys.has(\"wire_api\")) {\n output.push('wire_api = \"responses\"')\n }\n }\n}\n\nfunction assertValidProfile(profile: string) {\n if (/^[A-Za-z0-9_-]+$/.test(profile)) return\n throw new Error(\n \"Invalid Codex profile. Use only letters, numbers, underscores, or hyphens.\",\n )\n}\n\nfunction formatTomlString(value: string) {\n return `\"${value\n .replaceAll(\"\\\\\", \"\\\\\\\\\")\n .replaceAll('\"', '\\\\\"')\n .replaceAll(\"\\b\", \"\\\\b\")\n .replaceAll(\"\\t\", \"\\\\t\")\n .replaceAll(\"\\n\", \"\\\\n\")\n .replaceAll(\"\\f\", \"\\\\f\")\n .replaceAll(\"\\r\", \"\\\\r\")}\"`\n}\n\nfunction normalizeToml(content: string) {\n return content.replace(/\\r\\n/g, \"\\n\").trimEnd()\n}\n\nfunction parseTomlValue(raw: string) {\n const trimmed = stripInlineTomlComment(raw).trim()\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return unescapeTomlString(trimmed.slice(1, -1))\n }\n if (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\nfunction unescapeTomlString(value: string) {\n return value.replace(\n /\\\\([\"\\\\btnfr])/g,\n (_match, escaped: string) =>\n ({\n '\"': '\"',\n \"\\\\\": \"\\\\\",\n b: \"\\b\",\n t: \"\\t\",\n n: \"\\n\",\n f: \"\\f\",\n r: \"\\r\",\n })[escaped] ?? escaped,\n )\n}\n\nfunction stripInlineTomlComment(raw: string) {\n let quote: string | undefined\n for (let index = 0; index < raw.length; index += 1) {\n const char = raw[index]\n if ((char === '\"' || char === \"'\") && raw[index - 1] !== \"\\\\\") {\n quote = quote === char ? undefined : (quote ?? char)\n continue\n }\n\n if (!quote && char === \"#\") {\n return raw.slice(0, index)\n }\n }\n\n return raw\n}\n","import { execFile } from \"node:child_process\"\nimport { readFile } from \"node:fs/promises\"\nimport { promisify } from \"node:util\"\nimport packageJson from \"../package.json\" with { type: \"json\" }\nimport {\n checkCodexConfig,\n DEFAULT_CODEX_PROFILE,\n resolveCodexConfigPath,\n} from \"./codex-config.js\"\nimport { CursorRunner } from \"./cursor/runner.js\"\n\nconst execFileAsync = promisify(execFile)\n\nexport type DoctorCheck = {\n name: string\n ok: boolean\n message: string\n hint?: string\n}\n\nexport type ExecFileFn = (\n file: string,\n args?: readonly string[] | null,\n options?: { timeout?: number },\n) => Promise<unknown>\n\nexport type DoctorOptions = {\n host: string\n port: number\n agentPath?: string\n profile?: string\n nodeVersionRange?: string\n codexConfigPath?: string\n skipCodexConfig?: boolean\n runner?: CursorRunner\n fetchFn?: typeof fetch\n execFileFn?: ExecFileFn\n readFileFn?: typeof readFile\n}\n\nexport async function runDoctor(options: DoctorOptions) {\n const checks: DoctorCheck[] = []\n const fetchFn = options.fetchFn ?? fetch\n const execFileFn = options.execFileFn ?? execFileAsync\n const readFileFn = options.readFileFn ?? readFile\n const agentPath =\n options.agentPath ?? process.env.CURSOR_AGENT_PATH ?? \"agent\"\n const profile = options.profile ?? DEFAULT_CODEX_PROFILE\n const codexConfigPath =\n options.codexConfigPath ?? resolveCodexConfigPath(profile)\n\n checks.push(\n checkNodeVersion(options.nodeVersionRange ?? packageJson.engines.node),\n )\n checks.push({\n name: \"bridge-version\",\n ok: true,\n message: `cursor-agent-bridge ${packageJson.version}`,\n })\n\n const agentCheck = await checkAgentExecutable(agentPath, execFileFn)\n checks.push(agentCheck)\n\n if (agentCheck.ok) {\n checks.push(await checkAgentLogin(agentPath, options.runner))\n }\n\n checks.push(await checkBridgeHealth(options.host, options.port, fetchFn))\n\n if (!options.skipCodexConfig) {\n checks.push(\n await checkCodexConfigFile({\n codexConfigPath,\n host: options.host,\n port: options.port,\n profile,\n readFileFn,\n }),\n )\n }\n\n return {\n ok: checks.every((check) => check.ok),\n checks,\n }\n}\n\nexport function formatDoctorReport(result: {\n ok: boolean\n checks: DoctorCheck[]\n}) {\n const lines = result.checks.map((check) => {\n const prefix = check.ok ? \"✓\" : \"✗\"\n const hint = check.hint ? `\\n → ${check.hint}` : \"\"\n return `${prefix} ${check.name}: ${check.message}${hint}`\n })\n\n lines.push(\"\")\n lines.push(\n result.ok\n ? \"All checks passed. Codex can use Cursor Agent through the bridge.\"\n : \"Some checks failed. Fix the items above before starting Codex.\",\n )\n\n return `${lines.join(\"\\n\")}\\n`\n}\n\nfunction checkNodeVersion(requiredRange: string): DoctorCheck {\n const current = process.version.slice(1)\n const minimum = parseMinimumNodeVersion(requiredRange)\n const ok = compareNodeVersion(current, minimum) >= 0\n\n return ok\n ? {\n name: \"node-version\",\n ok,\n message: `Node ${current} satisfies ${requiredRange}`,\n }\n : {\n name: \"node-version\",\n ok,\n message: `Node ${current} does not satisfy ${requiredRange}`,\n hint: `Install Node ${minimum} or newer.`,\n }\n}\n\nasync function checkAgentExecutable(\n agentPath: string,\n execFileFn: ExecFileFn,\n): Promise<DoctorCheck> {\n try {\n await execFileFn(agentPath, [\"--help\"], { timeout: 5_000 })\n return {\n name: \"agent-cli\",\n ok: true,\n message: `Cursor Agent CLI found at ${agentPath}`,\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Cursor Agent CLI not found\"\n return {\n name: \"agent-cli\",\n ok: false,\n message,\n hint: \"Install the Cursor Agent CLI and ensure `agent` is on PATH, or set CURSOR_AGENT_PATH.\",\n }\n }\n}\n\nasync function checkAgentLogin(\n agentPath: string,\n runner = new CursorRunner({ agentPath }),\n): Promise<DoctorCheck> {\n try {\n const models = await runner.listModels({\n refresh: true,\n })\n if (models.length === 0) {\n return {\n name: \"agent-login\",\n ok: false,\n message: \"Cursor Agent responded, but returned no models\",\n hint: \"Run `agent login` and confirm `agent --list-models` returns models.\",\n }\n }\n\n return {\n name: \"agent-login\",\n ok: true,\n message: `Cursor Agent is logged in (${models.length} models available)`,\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Cursor Agent login check failed\"\n return {\n name: \"agent-login\",\n ok: false,\n message,\n hint: \"Run `agent login` and retry `cursor-agent-bridge doctor`.\",\n }\n }\n}\n\nasync function checkBridgeHealth(\n host: string,\n port: number,\n fetchFn: typeof fetch,\n): Promise<DoctorCheck> {\n const url = `http://${host}:${port}/health`\n try {\n const response = await fetchFn(url, { signal: AbortSignal.timeout(3_000) })\n if (!response.ok) {\n return {\n name: \"bridge-health\",\n ok: false,\n message: `${url} returned HTTP ${response.status}`,\n hint: \"Start the bridge with `cursor-agent-bridge serve` or `cursor-agent-bridge launch-agent install`.\",\n }\n }\n\n const payload = (await response.json()) as { version?: string }\n return {\n name: \"bridge-health\",\n ok: true,\n message: payload.version\n ? `Bridge is listening on ${url} (version ${payload.version})`\n : `Bridge is listening on ${url}`,\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Bridge health check failed\"\n return {\n name: \"bridge-health\",\n ok: false,\n message,\n hint: \"Start the bridge with `cursor-agent-bridge serve` or `cursor-agent-bridge launch-agent install`.\",\n }\n }\n}\n\nasync function checkCodexConfigFile(options: {\n codexConfigPath: string\n host: string\n port: number\n profile: string\n readFileFn: typeof readFile\n}): Promise<DoctorCheck> {\n try {\n const content = await options.readFileFn(options.codexConfigPath, \"utf8\")\n const result = checkCodexConfig(content, {\n host: options.host,\n port: options.port,\n profile: options.profile,\n })\n\n if (result.ok) {\n return {\n name: \"codex-config\",\n ok: true,\n message: `Codex config looks correct at ${options.codexConfigPath}`,\n }\n }\n\n return {\n name: \"codex-config\",\n ok: false,\n message: result.issues.join(\"; \"),\n hint: \"Run `cursor-agent-bridge config write` or `cursor-agent-bridge config print`.\",\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return {\n name: \"codex-config\",\n ok: false,\n message: `Codex config not found at ${options.codexConfigPath}`,\n hint: \"Run `cursor-agent-bridge config write` to create it.\",\n }\n }\n\n const message =\n error instanceof Error ? error.message : \"Codex config check failed\"\n return {\n name: \"codex-config\",\n ok: false,\n message,\n hint: \"Verify the Codex config path and file permissions.\",\n }\n }\n}\n\nfunction parseMinimumNodeVersion(range: string) {\n const match = range.match(/(\\d+)\\.(\\d+)(?:\\.(\\d+))?/)\n if (!match) return \"0.0.0\"\n return `${match[1]}.${match[2]}.${match[3] ?? 0}`\n}\n\nfunction compareNodeVersion(left: string, right: string) {\n const toParts = (value: string) =>\n value.split(\".\").map((part) => Number.parseInt(part, 10) || 0)\n const [leftMajor = 0, leftMinor = 0, leftPatch = 0] = toParts(left)\n const [rightMajor = 0, rightMinor = 0, rightPatch = 0] = toParts(right)\n\n if (leftMajor !== rightMajor) return leftMajor - rightMajor\n if (leftMinor !== rightMinor) return leftMinor - rightMinor\n return leftPatch - rightPatch\n}\n","import { execFileSync } from \"node:child_process\"\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { dirname, join, resolve } from \"node:path\"\n\nconst defaultLabel = \"com.xwartz.cursor-agent-bridge\"\nconst defaultLogDir = join(homedir(), \".codex\", \"logs\")\n\nexport type LaunchAgentOptions = {\n cliPath: string\n host?: string\n port?: number\n agentPath?: string\n label?: string\n}\n\nexport type LaunchAgentPaths = {\n label: string\n plistPath: string\n stdoutPath: string\n stderrPath: string\n}\n\nexport function getLaunchAgentPaths(label = defaultLabel): LaunchAgentPaths {\n return {\n label,\n plistPath: join(homedir(), \"Library\", \"LaunchAgents\", `${label}.plist`),\n stdoutPath: join(defaultLogDir, \"cursor-agent-bridge.log\"),\n stderrPath: join(defaultLogDir, \"cursor-agent-bridge.err.log\"),\n }\n}\n\nexport function createLaunchAgentPlist(options: LaunchAgentOptions) {\n const label = options.label ?? defaultLabel\n const host = options.host ?? \"127.0.0.1\"\n const port = options.port ?? 4646\n const paths = getLaunchAgentPaths(label)\n const args = [\n resolve(options.cliPath),\n \"serve\",\n \"--host\",\n host,\n \"--port\",\n String(port),\n ]\n const env: Record<string, string> = {\n PATH: [\n dirname(resolve(options.cliPath)),\n join(homedir(), \".local\", \"bin\"),\n \"/usr/local/bin\",\n \"/opt/homebrew/bin\",\n \"/usr/bin\",\n \"/bin\",\n \"/usr/sbin\",\n \"/sbin\",\n ].join(\":\"),\n }\n\n if (options.agentPath) {\n env.CURSOR_AGENT_PATH = options.agentPath\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${escapePlist(label)}</string>\n\n <key>ProgramArguments</key>\n <array>\n${args.map((arg) => ` <string>${escapePlist(arg)}</string>`).join(\"\\n\")}\n </array>\n\n <key>EnvironmentVariables</key>\n <dict>\n${Object.entries(env)\n .map(\n ([key, value]) =>\n ` <key>${escapePlist(key)}</key>\\n <string>${escapePlist(value)}</string>`,\n )\n .join(\"\\n\")}\n </dict>\n\n <key>RunAtLoad</key>\n <true/>\n\n <key>KeepAlive</key>\n <true/>\n\n <key>StandardOutPath</key>\n <string>${escapePlist(paths.stdoutPath)}</string>\n\n <key>StandardErrorPath</key>\n <string>${escapePlist(paths.stderrPath)}</string>\n</dict>\n</plist>\n`\n}\n\nexport function installLaunchAgent(options: LaunchAgentOptions) {\n ensureMacOS()\n const label = options.label ?? defaultLabel\n const paths = getLaunchAgentPaths(label)\n mkdirSync(dirname(paths.plistPath), { recursive: true })\n mkdirSync(defaultLogDir, { recursive: true })\n\n if (existsSync(paths.plistPath)) {\n bootout(paths.plistPath)\n }\n\n writeFileSync(paths.plistPath, createLaunchAgentPlist(options))\n chmodSync(paths.plistPath, 0o644)\n execFileSync(\"launchctl\", [\"bootstrap\", launchctlDomain(), paths.plistPath], {\n stdio: \"pipe\",\n })\n return paths\n}\n\nexport function uninstallLaunchAgent(label = defaultLabel) {\n ensureMacOS()\n const paths = getLaunchAgentPaths(label)\n bootout(paths.plistPath)\n rmSync(paths.plistPath, { force: true })\n return paths\n}\n\nexport function printLaunchAgentStatus(label = defaultLabel) {\n ensureMacOS()\n return execFileSync(\"launchctl\", [\"print\", `${launchctlDomain()}/${label}`], {\n encoding: \"utf8\",\n })\n}\n\nfunction bootout(plistPath: string) {\n try {\n execFileSync(\"launchctl\", [\"bootout\", launchctlDomain(), plistPath], {\n stdio: \"pipe\",\n })\n } catch {\n // It is fine if the service is not loaded yet.\n }\n}\n\nfunction launchctlDomain() {\n return `gui/${process.getuid?.() ?? execFileSync(\"id\", [\"-u\"], { encoding: \"utf8\" }).trim()}`\n}\n\nfunction ensureMacOS() {\n if (process.platform !== \"darwin\") {\n throw new Error(\"LaunchAgent management is only available on macOS.\")\n }\n}\n\nfunction escapePlist(value: string) {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\")\n}\n","import { execFile, spawn } from \"node:child_process\"\nimport { existsSync } from \"node:fs\"\nimport { promisify } from \"node:util\"\nimport { getLaunchAgentPaths } from \"./launch-agent.js\"\n\nconst execFileAsync = promisify(execFile)\n\nexport const PACKAGE_NAME = \"cursor-agent-bridge\"\nexport const DEFAULT_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`\nconst REGISTRY_TIMEOUT_MS = 10_000\n\nexport type PackageManager = \"npm\" | \"pnpm\"\nexport type PackageManagerPreference = PackageManager | \"auto\"\n\nexport type ExecFileFn = (\n file: string,\n args?: readonly string[] | null,\n options?: { env?: NodeJS.ProcessEnv },\n) => Promise<unknown>\n\nexport type SpawnFn = (\n command: string,\n args: readonly string[],\n options: { stdio: \"inherit\"; env?: NodeJS.ProcessEnv },\n) => {\n on(event: \"error\", listener: (error: Error) => void): unknown\n on(event: \"close\", listener: (code: number | null) => void): unknown\n}\n\nexport type UpgradeOptions = {\n currentVersion: string\n checkOnly?: boolean\n target?: string\n manager?: PackageManagerPreference\n registryUrl?: string\n fetchFn?: typeof fetch\n spawnFn?: SpawnFn\n execFileFn?: ExecFileFn\n existsFn?: typeof existsSync\n log?: (...args: unknown[]) => void\n errorLog?: (...args: unknown[]) => void\n}\n\nexport function compareSemver(left: string, right: string): -1 | 0 | 1 {\n const toParts = (value: string) => {\n const [major = 0, minor = 0, patch = 0] = value\n .split(\".\")\n .map((part) => Number.parseInt(part, 10) || 0)\n return [major, minor, patch] as const\n }\n const [leftMajor, leftMinor, leftPatch] = toParts(left)\n const [rightMajor, rightMinor, rightPatch] = toParts(right)\n\n if (leftMajor !== rightMajor) {\n return leftMajor < rightMajor ? -1 : 1\n }\n if (leftMinor !== rightMinor) {\n return leftMinor < rightMinor ? -1 : 1\n }\n if (leftPatch !== rightPatch) {\n return leftPatch < rightPatch ? -1 : 1\n }\n return 0\n}\n\nexport async function fetchLatestVersion(options?: {\n registryUrl?: string\n fetchFn?: typeof fetch\n timeoutMs?: number\n}): Promise<string> {\n const registryUrl = options?.registryUrl ?? DEFAULT_REGISTRY_URL\n const fetchFn = options?.fetchFn ?? fetch\n const timeoutMs = options?.timeoutMs ?? REGISTRY_TIMEOUT_MS\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), timeoutMs)\n\n try {\n const response = await fetchFn(registryUrl, { signal: controller.signal })\n if (!response.ok) {\n throw new Error(`Registry returned ${response.status}`)\n }\n\n const payload = (await response.json()) as { version?: string }\n if (!payload.version) {\n throw new Error(\"Registry response missing version\")\n }\n return payload.version\n } finally {\n clearTimeout(timeout)\n }\n}\n\nasync function commandExists(\n command: string,\n execFileFn: ExecFileFn,\n): Promise<boolean> {\n try {\n await execFileFn(\"which\", [command])\n return true\n } catch {\n return false\n }\n}\n\nexport async function detectPackageManager(\n preference: PackageManagerPreference,\n execFileFn: ExecFileFn = execFileAsync,\n): Promise<PackageManager> {\n if (preference === \"npm\") return \"npm\"\n if (preference === \"pnpm\") return \"pnpm\"\n\n if (!(await commandExists(\"pnpm\", execFileFn))) {\n return \"npm\"\n }\n\n try {\n await execFileFn(\"pnpm\", [\"list\", \"-g\", PACKAGE_NAME, \"--json\"], {\n env: process.env,\n })\n return \"pnpm\"\n } catch {\n return \"npm\"\n }\n}\n\nexport function buildInstallCommand(\n manager: PackageManager,\n target: string,\n): { command: string; args: string[] } {\n const versionSpec =\n target === \"latest\" ? \"@latest\" : `@${target.replace(/^@/, \"\")}`\n const packageSpec = `${PACKAGE_NAME}${versionSpec}`\n\n if (manager === \"pnpm\") {\n return { command: \"pnpm\", args: [\"add\", \"-g\", packageSpec] }\n }\n\n return { command: \"npm\", args: [\"install\", \"-g\", packageSpec] }\n}\n\nfunction printManualUpgradeHint(errorLog: (...args: unknown[]) => void) {\n errorLog(\"Upgrade manually:\")\n errorLog(` pnpm add -g ${PACKAGE_NAME}@latest`)\n errorLog(` npm install -g ${PACKAGE_NAME}@latest`)\n}\n\nasync function resolveTargetVersion(\n target: string,\n registryUrl: string,\n fetchFn: typeof fetch,\n): Promise<string> {\n if (target === \"latest\") {\n return fetchLatestVersion({ registryUrl, fetchFn })\n }\n return target.replace(/^@/, \"\")\n}\n\nasync function runInstall(\n manager: PackageManager,\n target: string,\n spawnFn: SpawnFn,\n): Promise<number> {\n const { command, args } = buildInstallCommand(manager, target)\n return new Promise((resolve, reject) => {\n const child = spawnFn(command, args, {\n stdio: \"inherit\",\n env: process.env,\n })\n\n child.on(\"error\", reject)\n child.on(\"close\", (code) => resolve(code ?? 1))\n })\n}\n\nexport async function runUpgrade(options: UpgradeOptions): Promise<number> {\n const log = options.log ?? console.log\n const errorLog = options.errorLog ?? console.error\n const checkOnly = options.checkOnly ?? false\n const target = options.target ?? \"latest\"\n const managerPreference = options.manager ?? \"auto\"\n const registryUrl = options.registryUrl ?? DEFAULT_REGISTRY_URL\n const fetchFn = options.fetchFn ?? fetch\n const spawnFn: SpawnFn =\n options.spawnFn ??\n ((command, args, spawnOptions) => spawn(command, args, spawnOptions))\n const execFileFn = options.execFileFn ?? execFileAsync\n const existsFn = options.existsFn ?? existsSync\n\n let targetVersion: string\n try {\n targetVersion = await resolveTargetVersion(target, registryUrl, fetchFn)\n } catch (error) {\n errorLog(\n `Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`,\n )\n printManualUpgradeHint(errorLog)\n return 1\n }\n\n const comparison = compareSemver(options.currentVersion, targetVersion)\n if (comparison >= 0) {\n log(`${PACKAGE_NAME} is up to date (${options.currentVersion})`)\n return 0\n }\n\n if (checkOnly) {\n log(`Update available: ${options.currentVersion} -> ${targetVersion}`)\n return 1\n }\n\n let manager: PackageManager\n manager = await detectPackageManager(managerPreference, execFileFn)\n\n log(`Installing ${PACKAGE_NAME}@${targetVersion} via ${manager}...`)\n try {\n const exitCode = await runInstall(manager, target, spawnFn)\n if (exitCode !== 0) {\n errorLog(`${manager} install failed with exit code ${exitCode}`)\n printManualUpgradeHint(errorLog)\n return exitCode\n }\n } catch (error) {\n errorLog(\n `Install failed: ${error instanceof Error ? error.message : String(error)}`,\n )\n printManualUpgradeHint(errorLog)\n return 1\n }\n\n log(`Installed ${PACKAGE_NAME}@${targetVersion}`)\n log(\"Run `cursor-agent-bridge --version` to verify the upgrade.\")\n\n const launchAgentPlist = getLaunchAgentPaths().plistPath\n if (existsFn(launchAgentPlist)) {\n log(\n \"LaunchAgent detected. Run `cursor-agent-bridge launch-agent install` to refresh the service.\",\n )\n }\n\n return 0\n}\n","#!/usr/bin/env node\n\nimport { readFile } from \"node:fs/promises\"\nimport packageJson from \"../package.json\" with { type: \"json\" }\nimport { toOpenAIModelList } from \"./adapter/models.js\"\nimport { readArg, readHostAndPort } from \"./cli-args.js\"\nimport {\n buildCodexConfigToml,\n checkCodexConfig,\n DEFAULT_CODEX_PROFILE,\n resolveCodexConfigPath,\n writeCodexConfig,\n} from \"./codex-config.js\"\nimport { CursorRunner } from \"./cursor/runner.js\"\nimport { formatDoctorReport, runDoctor } from \"./doctor.js\"\nimport {\n installLaunchAgent,\n printLaunchAgentStatus,\n uninstallLaunchAgent,\n} from \"./launch-agent.js\"\nimport { startServer } from \"./server.js\"\nimport { runUpgrade } from \"./upgrade.js\"\n\nconst command =\n process.argv[2] && !process.argv[2]?.startsWith(\"-\")\n ? process.argv[2]\n : \"serve\"\n\nif (\n command === \"help\" ||\n process.argv.includes(\"--help\") ||\n process.argv.includes(\"-h\")\n) {\n console.log(`cursor-agent-bridge\n\nUsage:\n cursor-agent-bridge serve [--host 127.0.0.1] [--port 4646]\n cursor-agent-bridge doctor [--host 127.0.0.1] [--port 4646] [--profile cursor] [--file ~/.codex/cursor.config.toml] [--skip-codex-config]\n cursor-agent-bridge config print [--host 127.0.0.1] [--port 4646] [--profile cursor]\n cursor-agent-bridge config check [--file ~/.codex/cursor.config.toml] [--host 127.0.0.1] [--port 4646] [--profile cursor]\n cursor-agent-bridge config write [--file ~/.codex/cursor.config.toml] [--host 127.0.0.1] [--port 4646] [--profile cursor] [--force]\n cursor-agent-bridge models [--json] [--refresh]\n cursor-agent-bridge launch-agent install [--host 127.0.0.1] [--port 4646] [--agent-path agent]\n cursor-agent-bridge launch-agent uninstall\n cursor-agent-bridge launch-agent status\n cursor-agent-bridge upgrade [--check] [--target latest] [--manager auto|npm|pnpm]\n\nEnvironment:\n HOST Listen host, default 127.0.0.1\n PORT Listen port, default 4646\n CURSOR_AGENT_PATH Cursor Agent CLI path, default agent\n`)\n process.exit(0)\n}\n\nif (command === \"version\" || process.argv.includes(\"--version\")) {\n console.log(packageJson.version)\n process.exit(0)\n}\n\nif (command === \"upgrade\") {\n const checkOnly = process.argv.includes(\"--check\")\n const target = readArg(\"--target\", \"latest\") ?? \"latest\"\n const manager = readArg(\"--manager\", \"auto\") ?? \"auto\"\n\n if (manager !== \"auto\" && manager !== \"npm\" && manager !== \"pnpm\") {\n console.error(\"Invalid --manager value. Use auto, npm, or pnpm.\")\n process.exit(1)\n }\n\n const exitCode = await runUpgrade({\n currentVersion: packageJson.version,\n checkOnly,\n target,\n manager,\n })\n process.exit(exitCode)\n}\n\nif (command === \"doctor\") {\n try {\n const { host, port } = readHostAndPort()\n const profile =\n readArg(\"--profile\", DEFAULT_CODEX_PROFILE) ?? DEFAULT_CODEX_PROFILE\n const codexConfigPath = readArg(\"--file\", undefined)\n const result = await runDoctor({\n host,\n port,\n profile,\n skipCodexConfig: process.argv.includes(\"--skip-codex-config\"),\n ...(process.env.CURSOR_AGENT_PATH\n ? { agentPath: process.env.CURSOR_AGENT_PATH }\n : {}),\n ...(codexConfigPath ? { codexConfigPath } : {}),\n })\n process.stdout.write(formatDoctorReport(result))\n process.exit(result.ok ? 0 : 1)\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n}\n\nif (command === \"config\") {\n const action = process.argv[3] ?? \"print\"\n try {\n const { host, port } = readHostAndPort()\n const profile =\n readArg(\"--profile\", DEFAULT_CODEX_PROFILE) ?? DEFAULT_CODEX_PROFILE\n const filePath =\n readArg(\"--file\", undefined) ?? resolveCodexConfigPath(profile)\n\n if (action === \"print\") {\n process.stdout.write(buildCodexConfigToml({ host, port, profile }))\n console.error(`Start Codex with: codex --profile ${profile}`)\n process.exit(0)\n }\n\n if (action === \"check\") {\n const content = await readFile(filePath, \"utf8\")\n const result = checkCodexConfig(content, { host, port, profile })\n if (result.ok) {\n console.log(`Codex config looks correct: ${filePath}`)\n process.exit(0)\n }\n\n for (const issue of result.issues) {\n console.error(issue)\n }\n process.exit(1)\n }\n\n if (action === \"write\") {\n const result = await writeCodexConfig({\n filePath,\n host,\n port,\n profile,\n force: process.argv.includes(\"--force\"),\n })\n\n if (result.created) {\n console.log(`Created Codex config at ${result.path}`)\n } else if (result.updated) {\n console.log(`Updated Codex config at ${result.path}`)\n } else {\n console.log(`Codex config already up to date at ${result.path}`)\n }\n\n console.log(`Start Codex with: codex --profile ${profile}`)\n process.exit(0)\n }\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n console.error(`Unknown config action: ${action}`)\n process.exit(1)\n}\n\nif (command === \"models\") {\n try {\n const runner = new CursorRunner({\n ...(process.env.CURSOR_AGENT_PATH\n ? { agentPath: process.env.CURSOR_AGENT_PATH }\n : {}),\n })\n const models = await runner.listModels({\n refresh: process.argv.includes(\"--refresh\"),\n })\n\n if (process.argv.includes(\"--json\")) {\n console.log(JSON.stringify(toOpenAIModelList(models), null, 2))\n process.exit(0)\n }\n\n for (const model of models) {\n console.log(model.id)\n }\n process.exit(0)\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n}\n\nif (command === \"launch-agent\") {\n const action = process.argv[3] ?? \"status\"\n try {\n if (action === \"install\") {\n const { host, port } = readHostAndPort()\n const agentPath = readArg(\"--agent-path\", process.env.CURSOR_AGENT_PATH)\n const paths = installLaunchAgent({\n cliPath: process.argv[1] ?? \"cursor-agent-bridge\",\n host,\n port,\n ...(agentPath ? { agentPath } : {}),\n })\n console.log(`Installed ${paths.label}`)\n console.log(paths.plistPath)\n process.exit(0)\n }\n\n if (action === \"uninstall\") {\n const paths = uninstallLaunchAgent()\n console.log(`Uninstalled ${paths.label}`)\n process.exit(0)\n }\n\n if (action === \"status\") {\n process.stdout.write(printLaunchAgentStatus())\n process.exit(0)\n }\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n console.error(`Unknown launch-agent action: ${action}`)\n process.exit(1)\n}\n\nif (command !== \"serve\") {\n console.error(`Unknown command: ${command}`)\n process.exit(1)\n}\n\nlet host: string\nlet port: number\ntry {\n const options = readHostAndPort()\n host = options.host\n port = options.port\n} catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n}\n\nconst server = await startServer({\n host,\n port,\n ...(process.env.CURSOR_AGENT_PATH\n ? { agentPath: process.env.CURSOR_AGENT_PATH }\n : {}),\n})\nconsole.log(`cursor-agent-bridge listening on http://${host}:${port}`)\n\nfunction shutdown() {\n server.close(() => process.exit(0))\n}\n\nprocess.on(\"SIGINT\", shutdown)\nprocess.on(\"SIGTERM\", shutdown)\n"],"mappings":";;;;;;;;;AAAA,SAAgB,QAAQ,MAAc,UAA8B;CAClE,MAAM,QAAQ,QAAQ,KAAK,QAAQ,IAAI;CACvC,IAAI,QAAQ,GAAG,OAAO;CACtB,MAAM,QAAQ,QAAQ,KAAK,QAAQ;CACnC,IAAI,CAAC,SAAS,MAAM,WAAW,GAAG,GAChC,MAAM,IAAI,MAAM,qBAAqB,MAAM;CAC7C,OAAO;AACT;AAEA,SAAgB,UAAU,OAA2B,UAAkB;CACrE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAChD,MAAM,IAAI,MAAM,iBAAiB,OAAO;CAE1C,OAAO;AACT;AAEA,SAAgB,gBAAgB,cAAc,aAAa,cAAc,MAAM;CAG7E,OAAO;EAAE,MAFI,QAAQ,UAAU,QAAQ,IAAI,IAAI,KAAK;EAErC,MADF,UAAU,QAAQ,UAAU,QAAQ,IAAI,IAAI,GAAG,WAC1C;CAAE;AACtB;;;AClBA,MAAa,wBAAwB;AA2BrC,SAAgB,uBACd,UAAU,uBACV,UAAU,QAAQ,GAClB;CACA,mBAAmB,OAAO;CAC1B,OAAO,KAAK,SAAS,UAAU,GAAG,QAAQ,aAAa;AACzD;AAEA,SAAgB,aAAa,MAAc,MAAc;CACvD,OAAO,UAAU,KAAK,GAAG,KAAK;AAChC;AAEA,SAAgB,qBAAqB,SAA6B;CAChE,MAAM,UAAU,QAAQ,WAAA;CACxB,mBAAmB,OAAO;CAC1B,MAAM,UAAU,aAAa,QAAQ,MAAM,QAAQ,IAAI;CACvD,OAAO,oBAAoB,iBAAiB,OAAO,EAAE;;;mBAGpC,QAAQ;;aAEd,iBAAiB,OAAO,EAAE;;;AAGvC;AAEA,SAAgB,iBACd,SACA,UAAU,uBACV;CACA,mBAAmB,OAAO;CAC1B,MAAM,SAA4B,CAAC;CACnC,MAAM,kBAAkB,mBAAmB;CAC3C,IAAI,UAAU;CAEd,KAAK,MAAM,WAAW,QAAQ,MAAM,IAAI,GAAG;EACzC,MAAM,OAAO,QAAQ,KAAK;EAC1B,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,GAAG;EAEnC,MAAM,eAAe,KAAK,MAAM,YAAY;EAC5C,IAAI,cAAc;GAChB,UAAU,aAAa,MAAM;GAC7B;EACF;EAEA,MAAM,aAAa,KAAK,MAAM,gCAAgC;EAC9D,IAAI,CAAC,YAAY;EAEjB,MAAM,MAAM,WAAW,MAAM;EAC7B,MAAM,QAAQ,eAAe,WAAW,MAAM,EAAE;EAEhD,IAAI,YAAY,iBAAiB;GAC/B,IAAI,QAAQ,QAAQ,OAAO,eAAe;GAC1C,IAAI,QAAQ,YAAY,OAAO,UAAU;GACzC,IAAI,QAAQ,YAAY,OAAO,UAAU;GACzC;EACF;EAEA,IAAI,SAAS;EACb,IAAI,QAAQ,kBAAkB,OAAO,gBAAgB;EACrD,IAAI,QAAQ,SAAS,OAAO,QAAQ;CACtC;CAEA,OAAO;AACT;AAEA,SAAgB,iBACd,SACA,SACwB;CACxB,MAAM,UAAU,QAAQ,WAAA;CACxB,MAAM,kBAAkB,aAAa,QAAQ,MAAM,QAAQ,IAAI;CAC/D,MAAM,SAAS,iBAAiB,SAAS,OAAO;CAChD,MAAM,SAAmB,CAAC;CAE1B,IAAI,OAAO,kBAAkB,SAC3B,OAAO,KACL,6BAA6B,QAAQ,GACnC,OAAO,gBACH,YAAY,OAAO,cAAc,KACjC,uBAER;CAGF,IAAI,OAAO,YAAY,iBACrB,OAAO,KACL,uBAAuB,gBAAgB,GACrC,OAAO,UAAU,YAAY,OAAO,QAAQ,KAAK,uBAErD;CAGF,IAAI,OAAO,YAAY,aACrB,OAAO,KACL,iCACE,OAAO,UAAU,YAAY,OAAO,QAAQ,KAAK,uBAErD;CAGF,OAAO;EAAE,IAAI,OAAO,WAAW;EAAG;CAAO;AAC3C;AAEA,eAAsB,iBACpB,SAIiC;CACjC,IAAI;CAEJ,IAAI;EACF,WAAW,MAAM,SAAS,QAAQ,UAAU,MAAM;CACpD,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,MAAM;CAChE;CAEA,IAAI,aAAa,KAAA,GAAW;EAC1B,MAAM,MAAM,QAAQ,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EAC1D,MAAM,UAAU,QAAQ,UAAU,qBAAqB,OAAO,GAAG,MAAM;EACvE,OAAO;GAAE,MAAM,QAAQ;GAAU,SAAS;GAAM,SAAS;EAAM;CACjE;CAEA,MAAM,SAAS,iBAAiB,UAAU,OAAO;CACjD,IAAI,WAAW,QAAQ,MAAM,IAAI,MAAM,OAAO,KAAK;CAEnD,IAAI,CAAC,OAAO,SACV,OAAO;EAAE,MAAM,QAAQ;EAAU,SAAS;EAAO,SAAS;CAAM;CAGlE,MAAM,UAAU,QAAQ,UAAU,OAAO,SAAS,MAAM;CACxD,OAAO;EAAE,MAAM,QAAQ;EAAU,SAAS;EAAO,SAAS;CAAK;AACjE;AAEA,SAAS,iBACP,UACA,SACA;CACA,MAAM,UAAU,QAAQ,WAAA;CACxB,mBAAmB,OAAO;CAC1B,MAAM,kBAAkB,mBAAmB;CAC3C,MAAM,WAAW,qBAAqB,OAAO;CAC7C,MAAM,SAAS,iBAAiB,UAAU,OAAO;CAEjD,IACE,OAAO,iBACP,OAAO,kBAAkB,WACzB,CAAC,QAAQ,OAET,OAAO,EACL,OAAO,sBAAsB,OAAO,cAAc,0CAA0C,QAAQ,IACtG;CAGF,MAAM,QAAQ,SAAS,MAAM,IAAI;CACjC,MAAM,SAAmB,CAAC;CAC1B,IAAI,UAAU;CACd,IAAI,oBAAoB;CACxB,IAAI,mBAAmB;CACvB,IAAI,WAAW;CACf,IAAI,qBAAqB;CACzB,MAAM,sCAAsB,IAAI,IAAY;CAE5C,KAAK,MAAM,WAAW,OAAO;EAC3B,MAAM,UAAU,QAAQ,KAAK;EAC7B,MAAM,eAAe,QAAQ,MAAM,YAAY;EAC/C,IAAI,cAAc;GAChB,IAAI,mBAAmB,0BAA0B;GACjD,UAAU,aAAa,MAAM;GAC7B,oBAAoB,YAAY;GAChC,IAAI,mBAAmB,qBAAqB;GAC5C,OAAO,KAAK,OAAO;GACnB;EACF;EAEA,MAAM,aAAa,QAAQ,MAAM,gCAAgC;EACjE,IAAI,CAAC,YAAY;GACf,OAAO,KAAK,OAAO;GACnB;EACF;EAEA,MAAM,MAAM,WAAW,MAAM;EAE7B,IAAI,CAAC,SAAS;GACZ,IAAI,QAAQ,kBAAkB;IAC5B,mBAAmB;IACnB,OAAO,KAAK,oBAAoB,iBAAiB,OAAO,GAAG;IAC3D;GACF;GACA,IAAI,QAAQ,SAAS;IACnB,WAAW;IACX,IAAI,OAAO,UAAU,KAAA,KAAa,QAAQ,OACxC,OAAO,KAAK,kBAAgB;SAE5B,OAAO,KAAK,OAAO;IAErB;GACF;EACF;EAEA,IAAI,mBAAmB;GACrB,IAAI,QAAQ,QAAQ;IAClB,oBAAoB,IAAI,MAAM;IAC9B,OAAO,KAAK,gCAA8B;IAC1C;GACF;GACA,IAAI,QAAQ,YAAY;IACtB,oBAAoB,IAAI,UAAU;IAClC,OAAO,KACL,cAAc,iBAAiB,aAAa,QAAQ,MAAM,QAAQ,IAAI,CAAC,GACzE;IACA;GACF;GACA,IAAI,QAAQ,YAAY;IACtB,oBAAoB,IAAI,UAAU;IAClC,OAAO,KAAK,0BAAwB;IACpC;GACF;EACF;EAEA,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,mBAAmB,0BAA0B;CAEjD,MAAM,kBAA4B,CAAC;CACnC,IAAI,CAAC,kBACH,gBAAgB,KAAK,oBAAoB,iBAAiB,OAAO,GAAG;CACtE,IAAI,CAAC,UAAU,gBAAgB,KAAK,kBAAgB;CAEpD,IAAI,UAAU,OAAO,KAAK,IAAI,CAAC,CAAC,QAAQ;CACxC,IAAI,gBAAgB,SAAS,GAC3B,UAAU,GAAG,gBAAgB,KAAK,IAAI,EAAE,IAAI;CAG9C,IAAI,CAAC,oBAAoB;EACvB,MAAM,gBAAgB,SAAS,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;EAC7D,UAAU,GAAG,QAAQ,MAAM,cAAc;CAC3C;CAEA,MAAM,UAAU,cAAc,OAAO,MAAM,cAAc,QAAQ;CACjE,OAAO;EAAE,SAAS,GAAG,QAAQ,QAAQ,EAAE;EAAK;CAAQ;CAEpD,SAAS,4BAA4B;EACnC,IAAI,CAAC,oBAAoB,IAAI,MAAM,GACjC,OAAO,KAAK,gCAA8B;EAE5C,IAAI,CAAC,oBAAoB,IAAI,UAAU,GACrC,OAAO,KACL,cAAc,iBAAiB,aAAa,QAAQ,MAAM,QAAQ,IAAI,CAAC,GACzE;EAEF,IAAI,CAAC,oBAAoB,IAAI,UAAU,GACrC,OAAO,KAAK,0BAAwB;CAExC;AACF;AAEA,SAAS,mBAAmB,SAAiB;CAC3C,IAAI,mBAAmB,KAAK,OAAO,GAAG;CACtC,MAAM,IAAI,MACR,4EACF;AACF;AAEA,SAAS,iBAAiB,OAAe;CACvC,OAAO,IAAI,MACR,WAAW,MAAM,MAAM,CAAC,CACxB,WAAW,MAAK,MAAK,CAAC,CACtB,WAAW,MAAM,KAAK,CAAC,CACvB,WAAW,KAAM,KAAK,CAAC,CACvB,WAAW,MAAM,KAAK,CAAC,CACvB,WAAW,MAAM,KAAK,CAAC,CACvB,WAAW,MAAM,KAAK,EAAE;AAC7B;AAEA,SAAS,cAAc,SAAiB;CACtC,OAAO,QAAQ,QAAQ,SAAS,IAAI,CAAC,CAAC,QAAQ;AAChD;AAEA,SAAS,eAAe,KAAa;CACnC,MAAM,UAAU,uBAAuB,GAAG,CAAC,CAAC,KAAK;CACjD,IAAI,QAAQ,WAAW,IAAG,KAAK,QAAQ,SAAS,IAAG,GACjD,OAAO,mBAAmB,QAAQ,MAAM,GAAG,EAAE,CAAC;CAEhD,IAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GACjD,OAAO,QAAQ,MAAM,GAAG,EAAE;CAE5B,OAAO;AACT;AAEA,SAAS,mBAAmB,OAAe;CACzC,OAAO,MAAM,QACX,oBACC,QAAQ,aACN;EACC,MAAK;EACL,MAAM;EACN,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACL,EAAA,CAAG,YAAY,OACnB;AACF;AAEA,SAAS,uBAAuB,KAAa;CAC3C,IAAI;CACJ,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,QAAQ,SAAS,GAAG;EAClD,MAAM,OAAO,IAAI;EACjB,KAAK,SAAS,QAAO,SAAS,QAAQ,IAAI,QAAQ,OAAO,MAAM;GAC7D,QAAQ,UAAU,OAAO,KAAA,IAAa,SAAS;GAC/C;EACF;EAEA,IAAI,CAAC,SAAS,SAAS,KACrB,OAAO,IAAI,MAAM,GAAG,KAAK;CAE7B;CAEA,OAAO;AACT;;;ACvVA,MAAMA,kBAAgB,UAAU,QAAQ;AA6BxC,eAAsB,UAAU,SAAwB;CACtD,MAAM,SAAwB,CAAC;CAC/B,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,aAAa,QAAQ,cAAcA;CACzC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,YACJ,QAAQ,aAAa,QAAQ,IAAI,qBAAqB;CACxD,MAAM,UAAU,QAAQ,WAAA;CACxB,MAAM,kBACJ,QAAQ,mBAAmB,uBAAuB,OAAO;CAE3D,OAAO,KACL,iBAAiB,QAAQ,oBAAA,QAAwC,IAAI,CACvE;CACA,OAAO,KAAK;EACV,MAAM;EACN,IAAI;EACJ,SAAS,uBAAuBC;CAClC,CAAC;CAED,MAAM,aAAa,MAAM,qBAAqB,WAAW,UAAU;CACnE,OAAO,KAAK,UAAU;CAEtB,IAAI,WAAW,IACb,OAAO,KAAK,MAAM,gBAAgB,WAAW,QAAQ,MAAM,CAAC;CAG9D,OAAO,KAAK,MAAM,kBAAkB,QAAQ,MAAM,QAAQ,MAAM,OAAO,CAAC;CAExE,IAAI,CAAC,QAAQ,iBACX,OAAO,KACL,MAAM,qBAAqB;EACzB;EACA,MAAM,QAAQ;EACd,MAAM,QAAQ;EACd;EACA;CACF,CAAC,CACH;CAGF,OAAO;EACL,IAAI,OAAO,OAAO,UAAU,MAAM,EAAE;EACpC;CACF;AACF;AAEA,SAAgB,mBAAmB,QAGhC;CACD,MAAM,QAAQ,OAAO,OAAO,KAAK,UAAU;EACzC,MAAM,SAAS,MAAM,KAAK,MAAM;EAChC,MAAM,OAAO,MAAM,OAAO,SAAS,MAAM,SAAS;EAClD,OAAO,GAAG,OAAO,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU;CACrD,CAAC;CAED,MAAM,KAAK,EAAE;CACb,MAAM,KACJ,OAAO,KACH,sEACA,gEACN;CAEA,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC7B;AAEA,SAAS,iBAAiB,eAAoC;CAC5D,MAAM,UAAU,QAAQ,QAAQ,MAAM,CAAC;CACvC,MAAM,UAAU,wBAAwB,aAAa;CACrD,MAAM,KAAK,mBAAmB,SAAS,OAAO,KAAK;CAEnD,OAAO,KACH;EACE,MAAM;EACN;EACA,SAAS,QAAQ,QAAQ,aAAa;CACxC,IACA;EACE,MAAM;EACN;EACA,SAAS,QAAQ,QAAQ,oBAAoB;EAC7C,MAAM,gBAAgB,QAAQ;CAChC;AACN;AAEA,eAAe,qBACb,WACA,YACsB;CACtB,IAAI;EACF,MAAM,WAAW,WAAW,CAAC,QAAQ,GAAG,EAAE,SAAS,IAAM,CAAC;EAC1D,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,6BAA6B;EACxC;CACF,SAAS,OAAO;EAGd,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAJA,iBAAiB,QAAQ,MAAM,UAAU;GAKzC,MAAM;EACR;CACF;AACF;AAEA,eAAe,gBACb,WACA,SAAS,IAAI,aAAa,EAAE,UAAU,CAAC,GACjB;CACtB,IAAI;EACF,MAAM,SAAS,MAAM,OAAO,WAAW,EACrC,SAAS,KACX,CAAC;EACD,IAAI,OAAO,WAAW,GACpB,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS;GACT,MAAM;EACR;EAGF,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,8BAA8B,OAAO,OAAO;EACvD;CACF,SAAS,OAAO;EAGd,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAJA,iBAAiB,QAAQ,MAAM,UAAU;GAKzC,MAAM;EACR;CACF;AACF;AAEA,eAAe,kBACb,MACA,MACA,SACsB;CACtB,MAAM,MAAM,UAAU,KAAK,GAAG,KAAK;CACnC,IAAI;EACF,MAAM,WAAW,MAAM,QAAQ,KAAK,EAAE,QAAQ,YAAY,QAAQ,GAAK,EAAE,CAAC;EAC1E,IAAI,CAAC,SAAS,IACZ,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,GAAG,IAAI,iBAAiB,SAAS;GAC1C,MAAM;EACR;EAGF,MAAM,UAAW,MAAM,SAAS,KAAK;EACrC,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,QAAQ,UACb,0BAA0B,IAAI,YAAY,QAAQ,QAAQ,KAC1D,0BAA0B;EAChC;CACF,SAAS,OAAO;EAGd,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAJA,iBAAiB,QAAQ,MAAM,UAAU;GAKzC,MAAM;EACR;CACF;AACF;AAEA,eAAe,qBAAqB,SAMX;CACvB,IAAI;EAEF,MAAM,SAAS,iBAAiB,MADV,QAAQ,WAAW,QAAQ,iBAAiB,MAAM,GAC/B;GACvC,MAAM,QAAQ;GACd,MAAM,QAAQ;GACd,SAAS,QAAQ;EACnB,CAAC;EAED,IAAI,OAAO,IACT,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,iCAAiC,QAAQ;EACpD;EAGF,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,OAAO,OAAO,KAAK,IAAI;GAChC,MAAM;EACR;CACF,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAC5C,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAAS,6BAA6B,QAAQ;GAC9C,MAAM;EACR;EAKF,OAAO;GACL,MAAM;GACN,IAAI;GACJ,SAJA,iBAAiB,QAAQ,MAAM,UAAU;GAKzC,MAAM;EACR;CACF;AACF;AAEA,SAAS,wBAAwB,OAAe;CAC9C,MAAM,QAAQ,MAAM,MAAM,0BAA0B;CACpD,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,GAAG,MAAM,MAAM;AAChD;AAEA,SAAS,mBAAmB,MAAc,OAAe;CACvD,MAAM,WAAW,UACf,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS,OAAO,SAAS,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,CAAC,YAAY,GAAG,YAAY,GAAG,YAAY,KAAK,QAAQ,IAAI;CAClE,MAAM,CAAC,aAAa,GAAG,aAAa,GAAG,aAAa,KAAK,QAAQ,KAAK;CAEtE,IAAI,cAAc,YAAY,OAAO,YAAY;CACjD,IAAI,cAAc,YAAY,OAAO,YAAY;CACjD,OAAO,YAAY;AACrB;;;AClRA,MAAM,eAAe;AACrB,MAAM,gBAAgB,KAAK,QAAQ,GAAG,UAAU,MAAM;AAiBtD,SAAgB,oBAAoB,QAAQ,cAAgC;CAC1E,OAAO;EACL;EACA,WAAW,KAAK,QAAQ,GAAG,WAAW,gBAAgB,GAAG,MAAM,OAAO;EACtE,YAAY,KAAK,eAAe,yBAAyB;EACzD,YAAY,KAAK,eAAe,6BAA6B;CAC/D;AACF;AAEA,SAAgB,uBAAuB,SAA6B;CAClE,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,QAAQ,oBAAoB,KAAK;CACvC,MAAM,OAAO;EACX,QAAQ,QAAQ,OAAO;EACvB;EACA;EACA;EACA;EACA,OAAO,IAAI;CACb;CACA,MAAM,MAA8B,EAClC,MAAM;EACJ,QAAQ,QAAQ,QAAQ,OAAO,CAAC;EAChC,KAAK,QAAQ,GAAG,UAAU,KAAK;EAC/B;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,GAAG,EACZ;CAEA,IAAI,QAAQ,WACV,IAAI,oBAAoB,QAAQ;CAGlC,OAAO;;;;;YAKG,YAAY,KAAK,EAAE;;;;EAI7B,KAAK,KAAK,QAAQ,eAAe,YAAY,GAAG,EAAE,UAAU,CAAC,CAAC,KAAK,IAAI,EAAE;;;;;EAKzE,OAAO,QAAQ,GAAG,CAAC,CAClB,KACE,CAAC,KAAK,WACL,YAAY,YAAY,GAAG,EAAE,sBAAsB,YAAY,KAAK,EAAE,UAC1E,CAAC,CACA,KAAK,IAAI,EAAE;;;;;;;;;;YAUF,YAAY,MAAM,UAAU,EAAE;;;YAG9B,YAAY,MAAM,UAAU,EAAE;;;;AAI1C;AAEA,SAAgB,mBAAmB,SAA6B;CAC9D,YAAY;CAEZ,MAAM,QAAQ,oBADA,QAAQ,SAAS,YACQ;CACvC,UAAU,QAAQ,MAAM,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;CACvD,UAAU,eAAe,EAAE,WAAW,KAAK,CAAC;CAE5C,IAAI,WAAW,MAAM,SAAS,GAC5B,QAAQ,MAAM,SAAS;CAGzB,cAAc,MAAM,WAAW,uBAAuB,OAAO,CAAC;CAC9D,UAAU,MAAM,WAAW,GAAK;CAChC,aAAa,aAAa;EAAC;EAAa,gBAAgB;EAAG,MAAM;CAAS,GAAG,EAC3E,OAAO,OACT,CAAC;CACD,OAAO;AACT;AAEA,SAAgB,qBAAqB,QAAQ,cAAc;CACzD,YAAY;CACZ,MAAM,QAAQ,oBAAoB,KAAK;CACvC,QAAQ,MAAM,SAAS;CACvB,OAAO,MAAM,WAAW,EAAE,OAAO,KAAK,CAAC;CACvC,OAAO;AACT;AAEA,SAAgB,uBAAuB,QAAQ,cAAc;CAC3D,YAAY;CACZ,OAAO,aAAa,aAAa,CAAC,SAAS,GAAG,gBAAgB,EAAE,GAAG,OAAO,GAAG,EAC3E,UAAU,OACZ,CAAC;AACH;AAEA,SAAS,QAAQ,WAAmB;CAClC,IAAI;EACF,aAAa,aAAa;GAAC;GAAW,gBAAgB;GAAG;EAAS,GAAG,EACnE,OAAO,OACT,CAAC;CACH,QAAQ,CAER;AACF;AAEA,SAAS,kBAAkB;CACzB,OAAO,OAAO,QAAQ,SAAS,KAAK,aAAa,MAAM,CAAC,IAAI,GAAG,EAAE,UAAU,OAAO,CAAC,CAAC,CAAC,KAAK;AAC5F;AAEA,SAAS,cAAc;CACrB,IAAI,QAAQ,aAAa,UACvB,MAAM,IAAI,MAAM,oDAAoD;AAExE;AAEA,SAAS,YAAY,OAAe;CAClC,OAAO,MACJ,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,QAAQ;AAC7B;;;AClKA,MAAM,gBAAgB,UAAU,QAAQ;AAExC,MAAa,eAAe;AAC5B,MAAa,uBAAuB,8BAA8B,aAAa;AAC/E,MAAM,sBAAsB;AAkC5B,SAAgB,cAAc,MAAc,OAA2B;CACrE,MAAM,WAAW,UAAkB;EACjC,MAAM,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,KAAK,MACvC,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,OAAO,SAAS,MAAM,EAAE,KAAK,CAAC;EAC/C,OAAO;GAAC;GAAO;GAAO;EAAK;CAC7B;CACA,MAAM,CAAC,WAAW,WAAW,aAAa,QAAQ,IAAI;CACtD,MAAM,CAAC,YAAY,YAAY,cAAc,QAAQ,KAAK;CAE1D,IAAI,cAAc,YAChB,OAAO,YAAY,aAAa,KAAK;CAEvC,IAAI,cAAc,YAChB,OAAO,YAAY,aAAa,KAAK;CAEvC,IAAI,cAAc,YAChB,OAAO,YAAY,aAAa,KAAK;CAEvC,OAAO;AACT;AAEA,eAAsB,mBAAmB,SAIrB;CAClB,MAAM,cAAc,SAAS,eAAe;CAC5C,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,aAAa;CACxC,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,UAAU,iBAAiB,WAAW,MAAM,GAAG,SAAS;CAE9D,IAAI;EACF,MAAM,WAAW,MAAM,QAAQ,aAAa,EAAE,QAAQ,WAAW,OAAO,CAAC;EACzE,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,qBAAqB,SAAS,QAAQ;EAGxD,MAAM,UAAW,MAAM,SAAS,KAAK;EACrC,IAAI,CAAC,QAAQ,SACX,MAAM,IAAI,MAAM,mCAAmC;EAErD,OAAO,QAAQ;CACjB,UAAU;EACR,aAAa,OAAO;CACtB;AACF;AAEA,eAAe,cACb,SACA,YACkB;CAClB,IAAI;EACF,MAAM,WAAW,SAAS,CAAC,OAAO,CAAC;EACnC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAsB,qBACpB,YACA,aAAyB,eACA;CACzB,IAAI,eAAe,OAAO,OAAO;CACjC,IAAI,eAAe,QAAQ,OAAO;CAElC,IAAI,CAAE,MAAM,cAAc,QAAQ,UAAU,GAC1C,OAAO;CAGT,IAAI;EACF,MAAM,WAAW,QAAQ;GAAC;GAAQ;GAAM;GAAc;EAAQ,GAAG,EAC/D,KAAK,QAAQ,IACf,CAAC;EACD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,oBACd,SACA,QACqC;CAGrC,MAAM,cAAc,GAAG,eADrB,WAAW,WAAW,YAAY,IAAI,OAAO,QAAQ,MAAM,EAAE;CAG/D,IAAI,YAAY,QACd,OAAO;EAAE,SAAS;EAAQ,MAAM;GAAC;GAAO;GAAM;EAAW;CAAE;CAG7D,OAAO;EAAE,SAAS;EAAO,MAAM;GAAC;GAAW;GAAM;EAAW;CAAE;AAChE;AAEA,SAAS,uBAAuB,UAAwC;CACtE,SAAS,mBAAmB;CAC5B,SAAS,iBAAiB,aAAa,QAAQ;CAC/C,SAAS,oBAAoB,aAAa,QAAQ;AACpD;AAEA,eAAe,qBACb,QACA,aACA,SACiB;CACjB,IAAI,WAAW,UACb,OAAO,mBAAmB;EAAE;EAAa;CAAQ,CAAC;CAEpD,OAAO,OAAO,QAAQ,MAAM,EAAE;AAChC;AAEA,eAAe,WACb,SACA,QACA,SACiB;CACjB,MAAM,EAAE,SAAS,SAAS,oBAAoB,SAAS,MAAM;CAC7D,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,QAAQ,SAAS,MAAM;GACnC,OAAO;GACP,KAAK,QAAQ;EACf,CAAC;EAED,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAChD,CAAC;AACH;AAEA,eAAsB,WAAW,SAA0C;CACzE,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,WAAW,QAAQ,YAAY,QAAQ;CAC7C,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,oBAAoB,QAAQ,WAAW;CAC7C,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,UACJ,QAAQ,aACN,SAAS,MAAM,iBAAiB,MAAM,SAAS,MAAM,YAAY;CACrE,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,WAAW,QAAQ,YAAY;CAErC,IAAI;CACJ,IAAI;EACF,gBAAgB,MAAM,qBAAqB,QAAQ,aAAa,OAAO;CACzE,SAAS,OAAO;EACd,SACE,gCAAgC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GACvF;EACA,uBAAuB,QAAQ;EAC/B,OAAO;CACT;CAGA,IADmB,cAAc,QAAQ,gBAAgB,aAC5C,KAAK,GAAG;EACnB,IAAI,GAAG,aAAa,kBAAkB,QAAQ,eAAe,EAAE;EAC/D,OAAO;CACT;CAEA,IAAI,WAAW;EACb,IAAI,qBAAqB,QAAQ,eAAe,MAAM,eAAe;EACrE,OAAO;CACT;CAEA,IAAI;CACJ,UAAU,MAAM,qBAAqB,mBAAmB,UAAU;CAElE,IAAI,cAAc,aAAa,GAAG,cAAc,OAAO,QAAQ,IAAI;CACnE,IAAI;EACF,MAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,OAAO;EAC1D,IAAI,aAAa,GAAG;GAClB,SAAS,GAAG,QAAQ,iCAAiC,UAAU;GAC/D,uBAAuB,QAAQ;GAC/B,OAAO;EACT;CACF,SAAS,OAAO;EACd,SACE,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC1E;EACA,uBAAuB,QAAQ;EAC/B,OAAO;CACT;CAEA,IAAI,aAAa,aAAa,GAAG,eAAe;CAChD,IAAI,4DAA4D;CAEhE,MAAM,mBAAmB,oBAAoB,CAAC,CAAC;CAC/C,IAAI,SAAS,gBAAgB,GAC3B,IACE,8FACF;CAGF,OAAO;AACT;;;ACzNA,MAAM,UACJ,QAAQ,KAAK,MAAM,CAAC,QAAQ,KAAK,EAAE,EAAE,WAAW,GAAG,IAC/C,QAAQ,KAAK,KACb;AAEN,IACE,YAAY,UACZ,QAAQ,KAAK,SAAS,QAAQ,KAC9B,QAAQ,KAAK,SAAS,IAAI,GAC1B;CACA,QAAQ,IAAI;;;;;;;;;;;;;;;;;;CAkBb;CACC,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,YAAY,aAAa,QAAQ,KAAK,SAAS,WAAW,GAAG;CAC/D,QAAQ,IAAIC,OAAmB;CAC/B,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,YAAY,WAAW;CACzB,MAAM,YAAY,QAAQ,KAAK,SAAS,SAAS;CACjD,MAAM,SAAS,QAAQ,YAAY,QAAQ,KAAK;CAChD,MAAM,UAAU,QAAQ,aAAa,MAAM,KAAK;CAEhD,IAAI,YAAY,UAAU,YAAY,SAAS,YAAY,QAAQ;EACjE,QAAQ,MAAM,kDAAkD;EAChE,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,WAAW,MAAM,WAAW;EAChC,gBAAgBA;EAChB;EACA;EACA;CACF,CAAC;CACD,QAAQ,KAAK,QAAQ;AACvB;AAEA,IAAI,YAAY,UACd,IAAI;CACF,MAAM,EAAE,MAAM,SAAS,gBAAgB;CACvC,MAAM,UACJ,QAAQ,aAAA,QAAkC,KAAA;CAC5C,MAAM,kBAAkB,QAAQ,UAAU,KAAA,CAAS;CACnD,MAAM,SAAS,MAAM,UAAU;EAC7B;EACA;EACA;EACA,iBAAiB,QAAQ,KAAK,SAAS,qBAAqB;EAC5D,GAAI,QAAQ,IAAI,oBACZ,EAAE,WAAW,QAAQ,IAAI,kBAAkB,IAC3C,CAAC;EACL,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;CAC/C,CAAC;CACD,QAAQ,OAAO,MAAM,mBAAmB,MAAM,CAAC;CAC/C,QAAQ,KAAK,OAAO,KAAK,IAAI,CAAC;AAChC,SAAS,OAAO;CACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CACpE,QAAQ,KAAK,CAAC;AAChB;AAGF,IAAI,YAAY,UAAU;CACxB,MAAM,SAAS,QAAQ,KAAK,MAAM;CAClC,IAAI;EACF,MAAM,EAAE,MAAM,SAAS,gBAAgB;EACvC,MAAM,UACJ,QAAQ,aAAA,QAAkC,KAAA;EAC5C,MAAM,WACJ,QAAQ,UAAU,KAAA,CAAS,KAAK,uBAAuB,OAAO;EAEhE,IAAI,WAAW,SAAS;GACtB,QAAQ,OAAO,MAAM,qBAAqB;IAAE;IAAM;IAAM;GAAQ,CAAC,CAAC;GAClE,QAAQ,MAAM,qCAAqC,SAAS;GAC5D,QAAQ,KAAK,CAAC;EAChB;EAEA,IAAI,WAAW,SAAS;GAEtB,MAAM,SAAS,iBAAiB,MADV,SAAS,UAAU,MAAM,GACN;IAAE;IAAM;IAAM;GAAQ,CAAC;GAChE,IAAI,OAAO,IAAI;IACb,QAAQ,IAAI,+BAA+B,UAAU;IACrD,QAAQ,KAAK,CAAC;GAChB;GAEA,KAAK,MAAM,SAAS,OAAO,QACzB,QAAQ,MAAM,KAAK;GAErB,QAAQ,KAAK,CAAC;EAChB;EAEA,IAAI,WAAW,SAAS;GACtB,MAAM,SAAS,MAAM,iBAAiB;IACpC;IACA;IACA;IACA;IACA,OAAO,QAAQ,KAAK,SAAS,SAAS;GACxC,CAAC;GAED,IAAI,OAAO,SACT,QAAQ,IAAI,2BAA2B,OAAO,MAAM;QAC/C,IAAI,OAAO,SAChB,QAAQ,IAAI,2BAA2B,OAAO,MAAM;QAEpD,QAAQ,IAAI,sCAAsC,OAAO,MAAM;GAGjE,QAAQ,IAAI,qCAAqC,SAAS;GAC1D,QAAQ,KAAK,CAAC;EAChB;CACF,SAAS,OAAO;EACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EACpE,QAAQ,KAAK,CAAC;CAChB;CAEA,QAAQ,MAAM,0BAA0B,QAAQ;CAChD,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,YAAY,UACd,IAAI;CAMF,MAAM,SAAS,MAAM,IALF,aAAa,EAC9B,GAAI,QAAQ,IAAI,oBACZ,EAAE,WAAW,QAAQ,IAAI,kBAAkB,IAC3C,CAAC,EACP,CAC0B,CAAC,CAAC,WAAW,EACrC,SAAS,QAAQ,KAAK,SAAS,WAAW,EAC5C,CAAC;CAED,IAAI,QAAQ,KAAK,SAAS,QAAQ,GAAG;EACnC,QAAQ,IAAI,KAAK,UAAU,kBAAkB,MAAM,GAAG,MAAM,CAAC,CAAC;EAC9D,QAAQ,KAAK,CAAC;CAChB;CAEA,KAAK,MAAM,SAAS,QAClB,QAAQ,IAAI,MAAM,EAAE;CAEtB,QAAQ,KAAK,CAAC;AAChB,SAAS,OAAO;CACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CACpE,QAAQ,KAAK,CAAC;AAChB;AAGF,IAAI,YAAY,gBAAgB;CAC9B,MAAM,SAAS,QAAQ,KAAK,MAAM;CAClC,IAAI;EACF,IAAI,WAAW,WAAW;GACxB,MAAM,EAAE,MAAM,SAAS,gBAAgB;GACvC,MAAM,YAAY,QAAQ,gBAAgB,QAAQ,IAAI,iBAAiB;GACvE,MAAM,QAAQ,mBAAmB;IAC/B,SAAS,QAAQ,KAAK,MAAM;IAC5B;IACA;IACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;GACnC,CAAC;GACD,QAAQ,IAAI,aAAa,MAAM,OAAO;GACtC,QAAQ,IAAI,MAAM,SAAS;GAC3B,QAAQ,KAAK,CAAC;EAChB;EAEA,IAAI,WAAW,aAAa;GAC1B,MAAM,QAAQ,qBAAqB;GACnC,QAAQ,IAAI,eAAe,MAAM,OAAO;GACxC,QAAQ,KAAK,CAAC;EAChB;EAEA,IAAI,WAAW,UAAU;GACvB,QAAQ,OAAO,MAAM,uBAAuB,CAAC;GAC7C,QAAQ,KAAK,CAAC;EAChB;CACF,SAAS,OAAO;EACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EACpE,QAAQ,KAAK,CAAC;CAChB;CAEA,QAAQ,MAAM,gCAAgC,QAAQ;CACtD,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,YAAY,SAAS;CACvB,QAAQ,MAAM,oBAAoB,SAAS;CAC3C,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI;AACJ,IAAI;AACJ,IAAI;CACF,MAAM,UAAU,gBAAgB;CAChC,OAAO,QAAQ;CACf,OAAO,QAAQ;AACjB,SAAS,OAAO;CACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CACpE,QAAQ,KAAK,CAAC;AAChB;AAEA,MAAM,SAAS,MAAM,YAAY;CAC/B;CACA;CACA,GAAI,QAAQ,IAAI,oBACZ,EAAE,WAAW,QAAQ,IAAI,kBAAkB,IAC3C,CAAC;AACP,CAAC;AACD,QAAQ,IAAI,2CAA2C,KAAK,GAAG,MAAM;AAErE,SAAS,WAAW;CAClB,OAAO,YAAY,QAAQ,KAAK,CAAC,CAAC;AACpC;AAEA,QAAQ,GAAG,UAAU,QAAQ;AAC7B,QAAQ,GAAG,WAAW,QAAQ"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
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";
1
+ import { a as parseAgentModelList, c as messagesToPrompt, i as CursorRunner, l as normalizeModel, o as toCodexModelCatalog, s as toOpenAIModelList, t as startServer, u as responsesToMessages } from "./server-Bk7ol2lA.mjs";
2
2
  export { CursorRunner, messagesToPrompt, normalizeModel, parseAgentModelList, responsesToMessages, startServer, toCodexModelCatalog, toOpenAIModelList };
@@ -328,7 +328,8 @@ function extractAssistantText(message) {
328
328
  }
329
329
  //#endregion
330
330
  //#region package.json
331
- var version = "0.1.3";
331
+ var version = "0.1.4";
332
+ var engines = { "node": ">=22.13" };
332
333
  //#endregion
333
334
  //#region src/adapter/openai.ts
334
335
  function createChatResponse(model, text) {
@@ -743,6 +744,6 @@ function sendJson(res, status, value) {
743
744
  res.end(body);
744
745
  }
745
746
  //#endregion
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 };
747
+ export { parseAgentModelList as a, messagesToPrompt as c, CursorRunner as i, normalizeModel as l, engines as n, toCodexModelCatalog as o, version as r, toOpenAIModelList as s, startServer as t, responsesToMessages as u };
747
748
 
748
- //# sourceMappingURL=server-BFgBwbF5.mjs.map
749
+ //# sourceMappingURL=server-Bk7ol2lA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-Bk7ol2lA.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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-agent-bridge",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Responses-compatible API bridge for Cursor Agent CLI",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1 +0,0 @@
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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"}