@rama_nigg/open-cursor 2.1.5 → 2.1.7

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
@@ -15,8 +15,6 @@ No prompt limits. No broken streams. Full thinking + tool support in Opencode. Y
15
15
  curl -fsSL https://raw.githubusercontent.com/Nomadcxx/opencode-cursor/main/install.sh | bash
16
16
  ```
17
17
 
18
- Note: if `npm` is available, `install.sh` installs/upgrades `@rama_nigg/open-cursor` and configures OpenCode automatically. Otherwise it falls back to building from source.
19
-
20
18
  **Option B: npm Package (Recommended)**
21
19
 
22
20
  ```bash
@@ -28,7 +26,7 @@ Upgrade later with:
28
26
 
29
27
  ```bash
30
28
  npm update -g @rama_nigg/open-cursor
31
- open-cursor sync-models
29
+ open-cursor install
32
30
  ```
33
31
 
34
32
  **Option C: TUI Installer**
@@ -89,7 +87,39 @@ Or if you'd rather do it by hand, add this to `~/.config/opencode/opencode.json`
89
87
  "npm": "@ai-sdk/openai-compatible",
90
88
  "options": { "baseURL": "http://127.0.0.1:32124/v1" },
91
89
  "models": {
92
- "auto": { "name": "Auto" }
90
+ "auto": { "name": "Auto" },
91
+ "composer-1.5": { "name": "Composer 1.5" },
92
+ "composer-1": { "name": "Composer 1" },
93
+ "gpt-5.3-codex": { "name": "GPT-5.3 Codex" },
94
+ "gpt-5.3-codex-low": { "name": "GPT-5.3 Codex Low" },
95
+ "gpt-5.3-codex-high": { "name": "GPT-5.3 Codex High" },
96
+ "gpt-5.3-codex-xhigh": { "name": "GPT-5.3 Codex Extra High" },
97
+ "gpt-5.3-codex-fast": { "name": "GPT-5.3 Codex Fast" },
98
+ "gpt-5.3-codex-low-fast": { "name": "GPT-5.3 Codex Low Fast" },
99
+ "gpt-5.3-codex-high-fast": { "name": "GPT-5.3 Codex High Fast" },
100
+ "gpt-5.3-codex-xhigh-fast": { "name": "GPT-5.3 Codex Extra High Fast" },
101
+ "gpt-5.2": { "name": "GPT-5.2" },
102
+ "gpt-5.2-codex": { "name": "GPT-5.2 Codex" },
103
+ "gpt-5.2-codex-high": { "name": "GPT-5.2 Codex High" },
104
+ "gpt-5.2-codex-low": { "name": "GPT-5.2 Codex Low" },
105
+ "gpt-5.2-codex-xhigh": { "name": "GPT-5.2 Codex Extra High" },
106
+ "gpt-5.2-codex-fast": { "name": "GPT-5.2 Codex Fast" },
107
+ "gpt-5.2-codex-high-fast": { "name": "GPT-5.2 Codex High Fast" },
108
+ "gpt-5.2-codex-low-fast": { "name": "GPT-5.2 Codex Low Fast" },
109
+ "gpt-5.2-codex-xhigh-fast": { "name": "GPT-5.2 Codex Extra High Fast" },
110
+ "gpt-5.1-codex-max": { "name": "GPT-5.1 Codex Max" },
111
+ "gpt-5.1-codex-max-high": { "name": "GPT-5.1 Codex Max High" },
112
+ "opus-4.6-thinking": { "name": "Claude 4.6 Opus (Thinking)" },
113
+ "sonnet-4.5-thinking": { "name": "Claude 4.5 Sonnet (Thinking)" },
114
+ "gpt-5.2-high": { "name": "GPT-5.2 High" },
115
+ "opus-4.6": { "name": "Claude 4.6 Opus" },
116
+ "opus-4.5": { "name": "Claude 4.5 Opus" },
117
+ "opus-4.5-thinking": { "name": "Claude 4.5 Opus (Thinking)" },
118
+ "sonnet-4.5": { "name": "Claude 4.5 Sonnet" },
119
+ "gpt-5.1-high": { "name": "GPT-5.1 High" },
120
+ "gemini-3-pro": { "name": "Gemini 3 Pro" },
121
+ "gemini-3-flash": { "name": "Gemini 3 Flash" },
122
+ "grok": { "name": "Grok" }
93
123
  }
94
124
  }
95
125
  }
@@ -131,35 +161,6 @@ opencode run "your prompt" --model cursor-acp/auto
131
161
  opencode run "your prompt" --model cursor-acp/sonnet-4.5
132
162
  ```
133
163
 
134
- If installed via npm, manage setup with:
135
-
136
- ```bash
137
- open-cursor status
138
- open-cursor sync-models
139
- ```
140
-
141
- ## Models
142
-
143
- Models are pulled from `cursor-agent models` and written to your config during installation. If Cursor adds new models later:
144
-
145
- ```bash
146
- open-cursor sync-models
147
- ```
148
-
149
- Or, if you installed from source (no npm CLI):
150
-
151
- ```bash
152
- ./scripts/sync-models.sh
153
- ```
154
-
155
- The proxy also exposes a `/v1/models` endpoint that fetches models in real-time:
156
-
157
- ```bash
158
- curl http://127.0.0.1:32124/v1/models
159
- ```
160
-
161
- Common models: `auto`, `composer-1.5`, `gpt-5.3-codex`, `opus-4.6-thinking`, `sonnet-4.5`, `gemini-3-pro`, `grok`
162
-
163
164
  ## Architecture
164
165
 
165
166
  ```mermaid
@@ -203,15 +204,6 @@ Detailed architecture: [docs/architecture/runtime-tool-loop.md](docs/architectur
203
204
  | **Dependencies** | bun, cursor-agent | npm | bun, cursor-agent | Node.js 18+ |
204
205
  | **Port** | 32124 | 18741 | 32123 | 4141 |
205
206
 
206
- **Key advantages of cursor-acp:**
207
-
208
- - Avoids E2BIG errors with large prompts (uses HTTP body, not CLI args)
209
- - Structured error parsing with actionable suggestions
210
- - Cross-platform (not locked to macOS Keychain)
211
- - TUI installer for easy setup
212
- - Native tool calling with 10 built-in tools, SDK/MCP executor support, and a skills/alias system
213
- - Uses official cursor-agent CLI (more stable than reverse-engineering Connect-RPC)
214
-
215
207
  ## Prerequisites
216
208
 
217
209
  - [Bun](https://bun.sh/)
@@ -254,10 +246,6 @@ Integration CI pins OpenCode-owned loop mode to deterministic settings:
254
246
  - `CURSOR_ACP_FORWARD_TOOL_CALLS=false`
255
247
  - `CURSOR_ACP_EMIT_TOOL_UPDATES=false`
256
248
 
257
- ## Publishing
258
-
259
- For maintainers, release and npm publish steps are documented in [docs/PUBLISHING.md](docs/PUBLISHING.md).
260
-
261
249
  ## Troubleshooting
262
250
 
263
251
  **"fetch() URL is invalid"** - Run `opencode auth login` without arguments
@@ -278,26 +266,10 @@ Common causes:
278
266
 
279
267
  ### Debug Logging
280
268
 
281
- Set the log level via environment variable:
282
- - `CURSOR_ACP_LOG_LEVEL=debug` - Verbose output for troubleshooting
283
- - `CURSOR_ACP_LOG_LEVEL=info` - Default level
284
- - `CURSOR_ACP_LOG_LEVEL=warn` - Warnings and errors only
285
- - `CURSOR_ACP_LOG_LEVEL=error` - Errors only
286
-
287
- Provider-boundary rollout:
288
- - Default: `CURSOR_ACP_PROVIDER_BOUNDARY=v1`
289
- - Default: `CURSOR_ACP_PROVIDER_BOUNDARY_AUTOFALLBACK=true`
290
- - `CURSOR_ACP_PROVIDER_BOUNDARY=legacy` - Original provider/runtime boundary behavior
291
- - `CURSOR_ACP_PROVIDER_BOUNDARY=v1` - Shared boundary/interception path
292
- - `CURSOR_ACP_PROVIDER_BOUNDARY_AUTOFALLBACK=false` - Disable fallback and keep strict `v1` behavior
293
- - `CURSOR_ACP_TOOL_LOOP_MAX_REPEAT=3` - Max repeated failing tool-call fingerprints before guard termination (or fallback when enabled)
294
-
295
- Auto-fallback trigger conditions:
296
- - Only active when `CURSOR_ACP_PROVIDER_BOUNDARY=v1`
297
- - Triggered when `v1` boundary extraction throws during tool-call interception
298
- - Triggered when the tool-loop guard threshold is reached (same tool + arg shape + error class)
299
- - Does not trigger for normal cases like disallowed tools or no tool call
300
- - Does not trigger for unrelated runtime errors (for example, tool mapper/tool execution failures)
269
+ Enable verbose logs:
270
+ ```bash
271
+ CURSOR_ACP_LOG_LEVEL=debug opencode run "your prompt" --model cursor-acp/auto
272
+ ```
301
273
 
302
274
  Disable log output entirely:
303
275
  ```bash
@@ -1,21 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
3
  var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __toESM = (mod, isNodeMode, target) => {
9
- target = mod != null ? __create(__getProtoOf(mod)) : {};
10
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
- for (let key of __getOwnPropNames(mod))
12
- if (!__hasOwnProp.call(to, key))
13
- __defProp(to, key, {
14
- get: () => mod[key],
15
- enumerable: true
16
- });
17
- return to;
18
- };
19
4
  var __export = (target, all) => {
20
5
  for (var name in all)
21
6
  __defProp(target, name, {
@@ -1,21 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
3
  var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __toESM = (mod, isNodeMode, target) => {
9
- target = mod != null ? __create(__getProtoOf(mod)) : {};
10
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
- for (let key of __getOwnPropNames(mod))
12
- if (!__hasOwnProp.call(to, key))
13
- __defProp(to, key, {
14
- get: () => mod[key],
15
- enumerable: true
16
- });
17
- return to;
18
- };
19
4
  var __export = (target, all) => {
20
5
  for (var name in all)
21
6
  __defProp(target, name, {
@@ -177,18 +162,170 @@ function fallbackModels() {
177
162
  }
178
163
 
179
164
  // src/cli/opencode-cursor.ts
165
+ var BRANDING_HEADER = `
166
+ ▄▄▄ ▄▄▄▄ ▄▄▄▄▄ ▄▄ ▄▄ ▄▄▄ ▄▄ ▄▄ ▄▄▄▄ ▄▄▄▄ ▄▄▄ ▄▄▄▄
167
+ ██ ██ ██ ██ ██▄▄ ███▄██ ▄▄▄ ██ ▀▀ ██ ██ ██ ██ ██▄▄▄ ██ ██ ██ ██
168
+ ▀█▄█▀ ██▀▀ ██▄▄▄ ██ ▀██ ▀█▄█▀ ▀█▄█▀ ██▀█▄ ▄▄▄█▀ ▀█▄█▀ ██▀█▄
169
+ `;
170
+ function getBrandingHeader() {
171
+ return BRANDING_HEADER.trim();
172
+ }
173
+ function checkBun() {
174
+ try {
175
+ const version = execFileSync2("bun", ["--version"], { encoding: "utf8" }).trim();
176
+ return { name: "bun", passed: true, message: `v${version}` };
177
+ } catch {
178
+ return {
179
+ name: "bun",
180
+ passed: false,
181
+ message: "not found - install with: curl -fsSL https://bun.sh/install | bash"
182
+ };
183
+ }
184
+ }
185
+ function checkCursorAgent() {
186
+ try {
187
+ const output = execFileSync2("cursor-agent", ["--version"], { encoding: "utf8" }).trim();
188
+ const version = output.split(`
189
+ `)[0] || "installed";
190
+ return { name: "cursor-agent", passed: true, message: version };
191
+ } catch {
192
+ return {
193
+ name: "cursor-agent",
194
+ passed: false,
195
+ message: "not found - install with: curl -fsS https://cursor.com/install | bash"
196
+ };
197
+ }
198
+ }
199
+ function checkCursorAgentLogin() {
200
+ try {
201
+ execFileSync2("cursor-agent", ["models"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
202
+ return { name: "cursor-agent login", passed: true, message: "logged in" };
203
+ } catch {
204
+ return {
205
+ name: "cursor-agent login",
206
+ passed: false,
207
+ message: "not logged in - run: cursor-agent login",
208
+ warning: true
209
+ };
210
+ }
211
+ }
212
+ function checkOpenCode() {
213
+ try {
214
+ const version = execFileSync2("opencode", ["--version"], { encoding: "utf8" }).trim();
215
+ return { name: "OpenCode", passed: true, message: version };
216
+ } catch {
217
+ return {
218
+ name: "OpenCode",
219
+ passed: false,
220
+ message: "not found - install with: curl -fsSL https://opencode.ai/install | bash"
221
+ };
222
+ }
223
+ }
224
+ function checkPluginFile(pluginPath) {
225
+ try {
226
+ if (!existsSync(pluginPath)) {
227
+ return {
228
+ name: "Plugin file",
229
+ passed: false,
230
+ message: "not found - run: open-cursor install"
231
+ };
232
+ }
233
+ const stat = lstatSync(pluginPath);
234
+ if (stat.isSymbolicLink()) {
235
+ const target = readFileSync(pluginPath, "utf8");
236
+ return { name: "Plugin file", passed: true, message: `symlink → ${target}` };
237
+ }
238
+ return { name: "Plugin file", passed: true, message: "file (copy)" };
239
+ } catch {
240
+ return {
241
+ name: "Plugin file",
242
+ passed: false,
243
+ message: "error reading plugin file"
244
+ };
245
+ }
246
+ }
247
+ function checkProviderConfig(configPath) {
248
+ try {
249
+ if (!existsSync(configPath)) {
250
+ return {
251
+ name: "Provider config",
252
+ passed: false,
253
+ message: "config not found - run: open-cursor install"
254
+ };
255
+ }
256
+ const config = readConfig(configPath);
257
+ const provider = config.provider?.["cursor-acp"];
258
+ if (!provider) {
259
+ return {
260
+ name: "Provider config",
261
+ passed: false,
262
+ message: "cursor-acp provider missing - run: open-cursor install"
263
+ };
264
+ }
265
+ const modelCount = Object.keys(provider.models || {}).length;
266
+ return { name: "Provider config", passed: true, message: `${modelCount} models` };
267
+ } catch {
268
+ return {
269
+ name: "Provider config",
270
+ passed: false,
271
+ message: "error reading config"
272
+ };
273
+ }
274
+ }
275
+ function checkAiSdk(opencodeDir) {
276
+ try {
277
+ const sdkPath = join(opencodeDir, "node_modules", "@ai-sdk", "openai-compatible");
278
+ if (existsSync(sdkPath)) {
279
+ return { name: "AI SDK", passed: true, message: "@ai-sdk/openai-compatible installed" };
280
+ }
281
+ return {
282
+ name: "AI SDK",
283
+ passed: false,
284
+ message: "not installed - run: open-cursor install"
285
+ };
286
+ } catch {
287
+ return {
288
+ name: "AI SDK",
289
+ passed: false,
290
+ message: "error checking AI SDK"
291
+ };
292
+ }
293
+ }
294
+ function runDoctorChecks(configPath, pluginPath) {
295
+ const opencodeDir = dirname(configPath);
296
+ return [
297
+ checkBun(),
298
+ checkCursorAgent(),
299
+ checkCursorAgentLogin(),
300
+ checkOpenCode(),
301
+ checkPluginFile(pluginPath),
302
+ checkProviderConfig(configPath),
303
+ checkAiSdk(opencodeDir)
304
+ ];
305
+ }
180
306
  var PROVIDER_ID = "cursor-acp";
181
307
  var DEFAULT_BASE_URL = "http://127.0.0.1:32124/v1";
182
308
  function printHelp() {
183
309
  const binName = basename(process.argv[1] || "open-cursor");
310
+ console.log(getBrandingHeader());
184
311
  console.log(`${binName}
185
312
 
186
- Usage:
187
- ${binName} install [--config <path>] [--plugin-dir <path>] [--base-url <url>] [--copy] [--skip-models] [--no-backup]
188
- ${binName} sync-models [--config <path>] [--no-backup]
189
- ${binName} uninstall [--config <path>] [--plugin-dir <path>] [--no-backup]
190
- ${binName} status [--config <path>] [--plugin-dir <path>]
191
- ${binName} help
313
+ Commands:
314
+ install Configure OpenCode for Cursor (idempotent, safe to re-run)
315
+ sync-models Refresh model list from cursor-agent
316
+ status Show current configuration state
317
+ doctor Diagnose common issues
318
+ uninstall Remove cursor-acp from OpenCode config
319
+ help Show this help message
320
+
321
+ Options:
322
+ --config <path> Path to opencode.json (default: ~/.config/opencode/opencode.json)
323
+ --plugin-dir <path> Path to plugin directory (default: ~/.config/opencode/plugin)
324
+ --base-url <url> Proxy base URL (default: http://127.0.0.1:32124/v1)
325
+ --copy Copy plugin instead of symlink
326
+ --skip-models Skip model sync during install
327
+ --no-backup Don't create config backup
328
+ --json Output in JSON format (status command only)
192
329
  `);
193
330
  }
194
331
  function parseArgs(argv) {
@@ -212,6 +349,8 @@ function parseArgs(argv) {
212
349
  } else if (arg === "--base-url" && rest[i + 1]) {
213
350
  options.baseUrl = rest[i + 1];
214
351
  i += 1;
352
+ } else if (arg === "--json") {
353
+ options.json = true;
215
354
  } else {
216
355
  throw new Error(`Unknown argument: ${arg}`);
217
356
  }
@@ -219,13 +358,14 @@ function parseArgs(argv) {
219
358
  return { command, options };
220
359
  }
221
360
  function normalizeCommand(value) {
222
- switch ((value || "install").toLowerCase()) {
361
+ switch ((value || "help").toLowerCase()) {
223
362
  case "install":
224
363
  case "sync-models":
225
364
  case "uninstall":
226
365
  case "status":
366
+ case "doctor":
227
367
  case "help":
228
- return value ? value.toLowerCase() : "install";
368
+ return value ? value.toLowerCase() : "help";
229
369
  default:
230
370
  throw new Error(`Unknown command: ${value}`);
231
371
  }
@@ -377,21 +517,97 @@ function commandUninstall(options) {
377
517
  console.log(`Removed plugin link: ${pluginPath}`);
378
518
  console.log(`Removed provider "${PROVIDER_ID}" from ${configPath}`);
379
519
  }
380
- function commandStatus(options) {
381
- const { configPath, pluginPath } = resolvePaths(options);
382
- const pluginExists = existsSync(pluginPath);
383
- const pluginType = pluginExists ? lstatSync(pluginPath).isSymbolicLink() ? "symlink" : "file" : "missing";
384
- let providerExists = false;
385
- let pluginEnabled = false;
520
+ function getStatusResult(configPath, pluginPath) {
521
+ let pluginType = "missing";
522
+ let pluginTarget;
523
+ if (existsSync(pluginPath)) {
524
+ const stat = lstatSync(pluginPath);
525
+ pluginType = stat.isSymbolicLink() ? "symlink" : "file";
526
+ if (pluginType === "symlink") {
527
+ try {
528
+ pluginTarget = readFileSync(pluginPath, "utf8");
529
+ } catch {
530
+ pluginTarget = undefined;
531
+ }
532
+ }
533
+ }
534
+ let providerEnabled = false;
535
+ let baseUrl = "http://127.0.0.1:32124/v1";
536
+ let modelCount = 0;
386
537
  if (existsSync(configPath)) {
387
538
  const config = readConfig(configPath);
388
- providerExists = Boolean(config.provider?.[PROVIDER_ID]);
389
- pluginEnabled = Array.isArray(config.plugin) && config.plugin.includes(PROVIDER_ID);
539
+ const provider = config.provider?.["cursor-acp"];
540
+ providerEnabled = !!provider;
541
+ if (provider?.options?.baseURL) {
542
+ baseUrl = provider.options.baseURL;
543
+ }
544
+ modelCount = Object.keys(provider?.models || {}).length;
545
+ }
546
+ const opencodeDir = dirname(configPath);
547
+ const sdkPath = join(opencodeDir, "node_modules", "@ai-sdk", "openai-compatible");
548
+ const aiSdkInstalled = existsSync(sdkPath);
549
+ return {
550
+ plugin: {
551
+ path: pluginPath,
552
+ type: pluginType,
553
+ target: pluginTarget
554
+ },
555
+ provider: {
556
+ configPath,
557
+ name: "cursor-acp",
558
+ enabled: providerEnabled,
559
+ baseUrl,
560
+ modelCount
561
+ },
562
+ aiSdk: {
563
+ installed: aiSdkInstalled
564
+ }
565
+ };
566
+ }
567
+ function commandStatus(options) {
568
+ const { configPath, pluginPath } = resolvePaths(options);
569
+ const result = getStatusResult(configPath, pluginPath);
570
+ if (options.json) {
571
+ console.log(JSON.stringify(result, null, 2));
572
+ return;
573
+ }
574
+ console.log("");
575
+ console.log("Plugin");
576
+ console.log(` Path: ${result.plugin.path}`);
577
+ if (result.plugin.type === "symlink" && result.plugin.target) {
578
+ console.log(` Type: symlink → ${result.plugin.target}`);
579
+ } else if (result.plugin.type === "file") {
580
+ console.log(` Type: file (copy)`);
581
+ } else {
582
+ console.log(` Type: missing`);
583
+ }
584
+ console.log("");
585
+ console.log("Provider");
586
+ console.log(` Config: ${result.provider.configPath}`);
587
+ console.log(` Name: ${result.provider.name}`);
588
+ console.log(` Enabled: ${result.provider.enabled ? "yes" : "no"}`);
589
+ console.log(` Base URL: ${result.provider.baseUrl}`);
590
+ console.log(` Models: ${result.provider.modelCount}`);
591
+ console.log("");
592
+ console.log("AI SDK");
593
+ console.log(` @ai-sdk/openai-compatible: ${result.aiSdk.installed ? "installed" : "not installed"}`);
594
+ }
595
+ function commandDoctor(options) {
596
+ const { configPath, pluginPath } = resolvePaths(options);
597
+ const checks = runDoctorChecks(configPath, pluginPath);
598
+ console.log("");
599
+ for (const check of checks) {
600
+ const symbol = check.passed ? "✓" : check.warning ? "⚠" : "✗";
601
+ const color = check.passed ? "\x1B[32m" : check.warning ? "\x1B[33m" : "\x1B[31m";
602
+ console.log(` ${color}${symbol}\x1B[0m ${check.name}: ${check.message}`);
603
+ }
604
+ const failed = checks.filter((c) => !c.passed && !c.warning);
605
+ console.log("");
606
+ if (failed.length === 0) {
607
+ console.log("All checks passed!");
608
+ } else {
609
+ console.log(`${failed.length} check(s) failed. See messages above.`);
390
610
  }
391
- console.log(`Plugin file: ${pluginPath} (${pluginType})`);
392
- console.log(`Provider in config: ${providerExists ? "yes" : "no"}`);
393
- console.log(`Plugin enabled in config: ${pluginEnabled ? "yes" : "no"}`);
394
- console.log(`Config path: ${configPath}`);
395
611
  }
396
612
  function main() {
397
613
  let parsed;
@@ -418,6 +634,9 @@ function main() {
418
634
  case "status":
419
635
  commandStatus(parsed.options);
420
636
  return;
637
+ case "doctor":
638
+ commandDoctor(parsed.options);
639
+ return;
421
640
  case "help":
422
641
  printHelp();
423
642
  return;
@@ -429,3 +648,11 @@ function main() {
429
648
  }
430
649
  }
431
650
  main();
651
+ export {
652
+ runDoctorChecks,
653
+ getStatusResult,
654
+ getBrandingHeader,
655
+ checkCursorAgentLogin,
656
+ checkCursorAgent,
657
+ checkBun
658
+ };