cursor-composer-in-claude 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +303 -0
  2. package/dist/cli/accounts.d.ts +18 -0
  3. package/dist/cli/accounts.js +149 -0
  4. package/dist/cli/accounts.js.map +1 -0
  5. package/dist/cli/args.d.ts +14 -0
  6. package/dist/cli/args.js +93 -0
  7. package/dist/cli/args.js.map +1 -0
  8. package/dist/cli/constants.d.ts +1 -0
  9. package/dist/cli/constants.js +4 -0
  10. package/dist/cli/constants.js.map +1 -0
  11. package/dist/cli/login.d.ts +1 -0
  12. package/dist/cli/login.js +143 -0
  13. package/dist/cli/login.js.map +1 -0
  14. package/dist/cli/reset-hwid.d.ts +24 -0
  15. package/dist/cli/reset-hwid.js +286 -0
  16. package/dist/cli/reset-hwid.js.map +1 -0
  17. package/dist/cli/usage.d.ts +27 -0
  18. package/dist/cli/usage.js +177 -0
  19. package/dist/cli/usage.js.map +1 -0
  20. package/dist/cli.d.ts +2 -0
  21. package/dist/cli.js +58 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/client.d.ts +95 -0
  24. package/dist/client.js +316 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/lib/account-pool.d.ts +35 -0
  27. package/dist/lib/account-pool.js +143 -0
  28. package/dist/lib/account-pool.js.map +1 -0
  29. package/dist/lib/acp-client.d.ts +53 -0
  30. package/dist/lib/acp-client.js +517 -0
  31. package/dist/lib/acp-client.js.map +1 -0
  32. package/dist/lib/agent-cmd-args.d.ts +9 -0
  33. package/dist/lib/agent-cmd-args.js +29 -0
  34. package/dist/lib/agent-cmd-args.js.map +1 -0
  35. package/dist/lib/agent-runner.d.ts +12 -0
  36. package/dist/lib/agent-runner.js +144 -0
  37. package/dist/lib/agent-runner.js.map +1 -0
  38. package/dist/lib/anthropic.d.ts +26 -0
  39. package/dist/lib/anthropic.js +70 -0
  40. package/dist/lib/anthropic.js.map +1 -0
  41. package/dist/lib/cli-stream-parser.d.ts +8 -0
  42. package/dist/lib/cli-stream-parser.js +46 -0
  43. package/dist/lib/cli-stream-parser.js.map +1 -0
  44. package/dist/lib/config.d.ts +52 -0
  45. package/dist/lib/config.js +47 -0
  46. package/dist/lib/config.js.map +1 -0
  47. package/dist/lib/cursor-cli.d.ts +9 -0
  48. package/dist/lib/cursor-cli.js +30 -0
  49. package/dist/lib/cursor-cli.js.map +1 -0
  50. package/dist/lib/env.d.ts +54 -0
  51. package/dist/lib/env.js +247 -0
  52. package/dist/lib/env.js.map +1 -0
  53. package/dist/lib/handlers/anthropic-messages.d.ts +9 -0
  54. package/dist/lib/handlers/anthropic-messages.js +281 -0
  55. package/dist/lib/handlers/anthropic-messages.js.map +1 -0
  56. package/dist/lib/handlers/chat-completions.d.ts +9 -0
  57. package/dist/lib/handlers/chat-completions.js +275 -0
  58. package/dist/lib/handlers/chat-completions.js.map +1 -0
  59. package/dist/lib/handlers/health.d.ts +7 -0
  60. package/dist/lib/handlers/health.js +15 -0
  61. package/dist/lib/handlers/health.js.map +1 -0
  62. package/dist/lib/handlers/models.d.ts +15 -0
  63. package/dist/lib/handlers/models.js +44 -0
  64. package/dist/lib/handlers/models.js.map +1 -0
  65. package/dist/lib/http.d.ts +5 -0
  66. package/dist/lib/http.js +36 -0
  67. package/dist/lib/http.js.map +1 -0
  68. package/dist/lib/max-mode-preflight.d.ts +5 -0
  69. package/dist/lib/max-mode-preflight.js +62 -0
  70. package/dist/lib/max-mode-preflight.js.map +1 -0
  71. package/dist/lib/model-map.d.ts +17 -0
  72. package/dist/lib/model-map.js +62 -0
  73. package/dist/lib/model-map.js.map +1 -0
  74. package/dist/lib/openai.d.ts +17 -0
  75. package/dist/lib/openai.js +111 -0
  76. package/dist/lib/openai.js.map +1 -0
  77. package/dist/lib/process.d.ts +32 -0
  78. package/dist/lib/process.js +174 -0
  79. package/dist/lib/process.js.map +1 -0
  80. package/dist/lib/request-listener.d.ts +7 -0
  81. package/dist/lib/request-listener.js +99 -0
  82. package/dist/lib/request-listener.js.map +1 -0
  83. package/dist/lib/request-log.d.ts +16 -0
  84. package/dist/lib/request-log.js +147 -0
  85. package/dist/lib/request-log.js.map +1 -0
  86. package/dist/lib/resolve-model.d.ts +8 -0
  87. package/dist/lib/resolve-model.js +18 -0
  88. package/dist/lib/resolve-model.js.map +1 -0
  89. package/dist/lib/sanitize.d.ts +21 -0
  90. package/dist/lib/sanitize.js +79 -0
  91. package/dist/lib/sanitize.js.map +1 -0
  92. package/dist/lib/server.d.ts +13 -0
  93. package/dist/lib/server.js +118 -0
  94. package/dist/lib/server.js.map +1 -0
  95. package/dist/lib/token-cache.d.ts +10 -0
  96. package/dist/lib/token-cache.js +35 -0
  97. package/dist/lib/token-cache.js.map +1 -0
  98. package/dist/lib/win-cmdline-limit.d.ts +32 -0
  99. package/dist/lib/win-cmdline-limit.js +92 -0
  100. package/dist/lib/win-cmdline-limit.js.map +1 -0
  101. package/dist/lib/workspace.d.ts +19 -0
  102. package/dist/lib/workspace.js +77 -0
  103. package/dist/lib/workspace.js.map +1 -0
  104. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # cursor-composer-in-claude
2
+
3
+ OpenAI-compatible proxy for Cursor CLI. Expose Cursor models on localhost so any LLM client (OpenAI SDK, LiteLLM, LangChain, etc.) can call them as a standard chat API.
4
+
5
+ This package works as **one npm dependency**: use it as an **SDK** in your app to call the proxy API, and/or run the **CLI** to start the proxy server. Core behavior is unchanged.
6
+
7
+ **OpenAI-compatible mode is not the Cursor IDE:** the HTTP API does not automatically attach your repo, `@codebase`, or host shell the way the desktop app does. See [Local workspace and agent frameworks](#local-workspace-and-agent-frameworks).
8
+
9
+ ## Prerequisites (required for the proxy to work)
10
+
11
+ - **Node.js** 18+
12
+ - **Cursor agent CLI** (`agent`). This package does **not** install or bundle the CLI. You must install and set it up separately. This project is developed and tested with `agent` version **2026.02.27-e7d2ef6**.
13
+
14
+ ```bash
15
+ curl https://cursor.com/install -fsS | bash
16
+ agent login
17
+ agent --list-models
18
+ ```
19
+
20
+ For automation, set `CURSOR_API_KEY` instead of using `agent login`.
21
+
22
+ ## macOS Keychain
23
+
24
+ This fork **always** forces `CURSOR_SKIP_KEYCHAIN=1` into every spawned Cursor agent process. The macOS keychain popup will never appear, regardless of what the parent process sets. No configuration needed.
25
+
26
+ ## Install
27
+
28
+ **From npm (use as SDK in another project):**
29
+
30
+ ```bash
31
+ npm install cursor-composer-in-claude
32
+ ```
33
+
34
+ **From source (develop or run CLI locally):**
35
+
36
+ ```bash
37
+ git clone <this-repo>
38
+ cd cursor-composer-in-claude
39
+ npm install
40
+ npm run build
41
+ ```
42
+
43
+ ## Run the proxy (CLI)
44
+
45
+ Start the server so the API is available (e.g. for the SDK or any HTTP client):
46
+
47
+ ```bash
48
+ npx cursor-api-proxy
49
+ # or from repo: npm start / node dist/cli.js
50
+ ```
51
+
52
+ To expose on your network (e.g. Tailscale):
53
+
54
+ ```bash
55
+ npx cursor-api-proxy --tailscale
56
+ ```
57
+
58
+ By default the server listens on **http://127.0.0.1:8765**. Optionally set `CURSOR_BRIDGE_API_KEY` to require `Authorization: Bearer <key>` on requests.
59
+
60
+ ### HTTPS with Tailscale (MagicDNS)
61
+
62
+ To serve over HTTPS so browsers and clients trust the connection (e.g. `https://macbook.tail4048eb.ts.net:8765`):
63
+
64
+ 1. **Generate Tailscale certificates** on this machine (run from the project directory or where you want the cert files):
65
+
66
+ ```bash
67
+ sudo tailscale cert macbook.tail4048eb.ts.net
68
+ ```
69
+
70
+ This creates `macbook.tail4048eb.ts.net.crt` and `macbook.tail4048eb.ts.net.key` in the current directory.
71
+
72
+ 2. **Run the proxy with TLS** and optional Tailscale bind:
73
+
74
+ ```bash
75
+ export CURSOR_BRIDGE_API_KEY=your-secret
76
+ export CURSOR_BRIDGE_TLS_CERT=/path/to/macbook.tail4048eb.ts.net.crt
77
+ export CURSOR_BRIDGE_TLS_KEY=/path/to/macbook.tail4048eb.ts.net.key
78
+ # Bind to Tailscale IP so the service is only on the tailnet (optional):
79
+ export CURSOR_BRIDGE_HOST=100.123.47.103
80
+ npm start
81
+ ```
82
+
83
+ Or bind to all interfaces and use HTTPS:
84
+
85
+ ```bash
86
+ CURSOR_BRIDGE_TLS_CERT=./macbook.tail4048eb.ts.net.crt \
87
+ CURSOR_BRIDGE_TLS_KEY=./macbook.tail4048eb.ts.net.key \
88
+ CURSOR_BRIDGE_API_KEY=your-secret \
89
+ npm start -- --tailscale
90
+ ```
91
+
92
+ 3. **Access the API** from any device on your tailnet:
93
+ - Base URL: `https://macbook.tail4048eb.ts.net:8765/v1` (use your MagicDNS name and port)
94
+ - Browsers will show a padlock; no certificate warnings when using Tailscale-issued certs.
95
+
96
+ ## Local workspace and agent frameworks
97
+
98
+ When you point an agent runtime (OpenClaw, LangChain, a custom harness, etc.) at this proxy with a normal `baseUrl` + `apiKey`, you get a **cloud model behind an OpenAI-shaped HTTP API**. That is **not** the same product surface as the **Cursor IDE**, which can index and act on a local workspace.
99
+
100
+ - **No implicit project context:** The model only sees what you put in the request—`messages`, optional tools schema, and **tool results that your client executes and sends back**. There is no automatic filesystem, repo layout, or `@codebase` injection from the proxy alone.
101
+ - **If “local” actions work, they work in the client:** Reads, shell commands, and directory listings happen only when **your agent framework** implements tools and runs them on the host, then returns outputs in follow-up messages. The proxy does not substitute for that.
102
+ - **Server-side workspace (optional):** The Cursor CLI may run with a workspace directory (`CURSOR_BRIDGE_WORKSPACE`, per-request `X-Cursor-Workspace`). By default, `CURSOR_BRIDGE_CHAT_ONLY_WORKSPACE=true` runs the CLI in an **empty temp directory** so it does not read or write your real project; the proxy also overrides `HOME`, `USERPROFILE`, and `CURSOR_CONFIG_DIR` so the agent does not load global or project rules from elsewhere. Set it to `false` if you intentionally want the CLI to see a path on the machine where the proxy runs (still not the same as IDE indexing—see env table below).
103
+ - **Recommended patterns for agents:** Use **client-side tools** (e.g. `read_file`, `run_terminal_cmd`) and pass results as tool messages; add **RAG** or retrieval and inject snippets into `user` content; or paste relevant files into the prompt. There is no built-in “sync entire workspace through the proxy” today; if that changes, it will be documented here.
104
+
105
+ ## Use as SDK in another project
106
+
107
+ Install the package and ensure the **Cursor agent CLI is installed and set up** (see Prerequisites). When you use the SDK with the default URL, **the proxy starts in the background automatically** if it is not already running. You can still start it yourself with `npx cursor-api-proxy` or set `CURSOR_PROXY_URL` to point at an existing proxy (then the SDK will not start another).
108
+
109
+ - **Base URL**: `http://127.0.0.1:8765/v1` (override with `CURSOR_PROXY_URL` or options).
110
+ - **API key**: Use any value (e.g. `unused`), or set `CURSOR_BRIDGE_API_KEY` and pass it in options or env.
111
+ - **Disable auto-start**: Pass `startProxy: false` (or use a custom `baseUrl`) if you run the proxy yourself and don’t want the SDK to start it.
112
+ - **Shutdown behavior**: When the SDK starts the proxy, it also stops it automatically when the Node.js process exits or receives normal termination signals. `stopManagedProxy()` is still available if you want to shut it down earlier. `SIGKILL` cannot be intercepted.
113
+
114
+ ### Option A: OpenAI SDK + helper (recommended)
115
+
116
+ This is an optional consumer-side example. `openai` is not a dependency of `cursor-api-proxy`; install it only in the app where you want to use this example.
117
+
118
+ ```js
119
+ import OpenAI from "openai";
120
+ import { getOpenAIOptionsAsync } from "cursor-composer-in-claude";
121
+
122
+ const opts = await getOpenAIOptionsAsync(); // starts proxy if needed
123
+ const client = new OpenAI(opts);
124
+
125
+ const completion = await client.chat.completions.create({
126
+ model: "gpt-5.2",
127
+ messages: [{ role: "user", content: "Hello" }],
128
+ });
129
+ console.log(completion.choices[0].message.content);
130
+ ```
131
+
132
+ For a sync config without auto-start, use `getOpenAIOptions()` and ensure the proxy is already running.
133
+
134
+ ### Option B: Minimal client (no OpenAI SDK)
135
+
136
+ ```js
137
+ import { createCursorProxyClient } from "cursor-composer-in-claude";
138
+
139
+ const proxy = createCursorProxyClient(); // proxy starts on first request if needed
140
+ const data = await proxy.chatCompletionsCreate({
141
+ model: "auto",
142
+ messages: [{ role: "user", content: "Hello" }],
143
+ });
144
+ console.log(data.choices?.[0]?.message?.content);
145
+ ```
146
+
147
+ ### Option C: Raw OpenAI client (no SDK import from this package)
148
+
149
+ ```js
150
+ import OpenAI from "openai";
151
+
152
+ const client = new OpenAI({
153
+ baseURL: "http://127.0.0.1:8765/v1",
154
+ apiKey: process.env.CURSOR_BRIDGE_API_KEY || "unused",
155
+ });
156
+ // Start the proxy yourself (npx cursor-api-proxy) or use Option A/B for auto-start.
157
+ ```
158
+
159
+ ### Endpoints
160
+
161
+ | Method | Path | Description |
162
+ | ------ | ---------------------- | --------------------------------------------------------------------- |
163
+ | GET | `/health` | Server and config info |
164
+ | GET | `/v1/models` | List Cursor models (from `agent --list-models`) |
165
+ | POST | `/v1/chat/completions` | Chat completion (OpenAI shape; supports `stream: true`) |
166
+ | POST | `/v1/messages` | Anthropic Messages API (used by Claude Code; supports `stream: true`) |
167
+
168
+ **Usage / token fields:** Responses may include `usage` with `prompt_tokens`, `completion_tokens`, and `total_tokens`. These are **heuristic estimates** (character count ÷ 4), not Cursor billing meters. Do not use them for invoicing.
169
+
170
+ ## Environment variables
171
+
172
+ Environment handling is centralized in one module. Aliases, defaults, path resolution, platform fallbacks, and `--tailscale` host behavior are resolved consistently before the server starts.
173
+
174
+ | Variable | Default | Description |
175
+ |----------|---------|-------------|
176
+ | `CURSOR_BRIDGE_HOST` | `127.0.0.1` | Bind address |
177
+ | `CURSOR_BRIDGE_PORT` | `8765` | Port |
178
+ | `CURSOR_BRIDGE_API_KEY` | — | If set, require `Authorization: Bearer <key>` on requests |
179
+ | `CURSOR_API_KEY` / `CURSOR_AUTH_TOKEN` | — | Cursor access token passed to spawned CLI/ACP children (automation, headless). Same value can be used for both names. |
180
+ | `CURSOR_BRIDGE_WORKSPACE` | process cwd | Base workspace directory for Cursor CLI. With `CURSOR_BRIDGE_CHAT_ONLY_WORKSPACE=false`, header `X-Cursor-Workspace` must point to an **existing directory under this path** (after resolving real paths). |
181
+ | `CURSOR_BRIDGE_MODE` | — | Ignored; proxy always runs in **ask** (chat-only) mode so the CLI never creates or edits files. |
182
+ | `CURSOR_BRIDGE_DEFAULT_MODEL` | `auto` | Default model when request omits one |
183
+ | `CURSOR_BRIDGE_STRICT_MODEL` | `true` | Use last requested model when none specified |
184
+ | `CURSOR_BRIDGE_FORCE` | `false` | Pass `--force` to Cursor CLI |
185
+ | `CURSOR_BRIDGE_APPROVE_MCPS` | `false` | Pass `--approve-mcps` to Cursor CLI |
186
+ | `CURSOR_BRIDGE_TIMEOUT_MS` | `300000` | Timeout per completion (ms) |
187
+ | `CURSOR_BRIDGE_TLS_CERT` | — | Path to TLS certificate file (e.g. Tailscale cert). Use with `CURSOR_BRIDGE_TLS_KEY` for HTTPS. |
188
+ | `CURSOR_BRIDGE_TLS_KEY` | — | Path to TLS private key file. Use with `CURSOR_BRIDGE_TLS_CERT` for HTTPS. |
189
+ | `CURSOR_BRIDGE_SESSIONS_LOG` | `~/.cursor-api-proxy/sessions.log` | Path to log file; each request is appended as a line (timestamp, method, path, IP, status). |
190
+ | `CURSOR_BRIDGE_CHAT_ONLY_WORKSPACE` | `true` | When `true` (default), the CLI runs in an empty temp dir so it **cannot read or write your project**; pure chat only. The proxy also overrides `HOME`, `USERPROFILE`, and `CURSOR_CONFIG_DIR` so the agent cannot load rules from `~/.cursor` or project rules from elsewhere. Set to `false` to pass the real workspace (e.g. for `X-Cursor-Workspace`). |
191
+ | `CURSOR_BRIDGE_VERBOSE` | `false` | When `true`, print full request messages and response content to stdout for every completion (both stream and sync). |
192
+ | `CURSOR_BRIDGE_MAX_MODE` | `false` | When `true`, enable Cursor **Max Mode** for all requests (larger context window, higher tool-call limits). The proxy writes `maxMode: true` to `cli-config.json` before each run. Works when using `CURSOR_AGENT_NODE`/`CURSOR_AGENT_SCRIPT`, the versioned layout (`versions/YYYY.MM.DD-commit/`), or node.exe + index.js next to agent.cmd. |
193
+ | `CURSOR_BRIDGE_WIN_CMDLINE_MAX` | `30000` | **(Windows)** Upper bound (UTF-16 units, pessimistic) for the full `CreateProcess` command line. If the prompt would exceed it, the proxy keeps the **tail** of the prompt and prepends a short omission notice, logs a warning, and sets `X-Cursor-Proxy-Prompt-Truncated: true` on the response. Clamped to `4096`–`32700`. |
194
+ | `CURSOR_CONFIG_DIRS` | — | Comma-separated configuration directories for round-robin account rotation (alias: `CURSOR_ACCOUNT_DIRS`). Auto-discovers authenticated accounts under `~/.cursor-api-proxy/accounts/` when unset. |
195
+ | `CURSOR_BRIDGE_MULTI_PORT` | `false` | When `true` and multiple config dirs are set, spawns a separate server per directory on incrementing ports starting from `CURSOR_BRIDGE_PORT`. |
196
+ | `CURSOR_BRIDGE_PROMPT_VIA_STDIN` | `false` | When `true`, sends the user prompt via **stdin** instead of argv (helps on Windows if argv is truncated). |
197
+ | `CURSOR_SKIP_KEYCHAIN` | `1` (always) | **Always injected** into every spawned agent process. The macOS keychain popup is suppressed by default. |
198
+ | `CURSOR_BRIDGE_USE_ACP` | `false` | When `true`, uses **ACP (Agent Client Protocol)** over stdio (`agent acp`). Avoids Windows argv limits. See [Cursor ACP docs](https://cursor.com/docs/cli/acp). Set `NODE_DEBUG=cursor-api-proxy:acp` to debug. |
199
+ | `CURSOR_BRIDGE_ACP_SKIP_AUTHENTICATE` | auto | When `CURSOR_API_KEY` is set, skips the ACP authenticate step. Set to `true` to skip when using `agent login` instead. |
200
+ | `CURSOR_BRIDGE_ACP_RAW_DEBUG` | `false` | When `1` or `true`, log raw JSON-RPC from ACP stdout (requires `NODE_DEBUG=cursor-api-proxy:acp`). |
201
+ | `CURSOR_AGENT_BIN` | `agent` | Path to Cursor CLI binary. Alias precedence: `CURSOR_AGENT_BIN`, then `CURSOR_CLI_BIN`, then `CURSOR_CLI_PATH`. |
202
+ | `CURSOR_AGENT_NODE` | — | **(Windows)** Path to Node.js. With `CURSOR_AGENT_SCRIPT`, spawns Node directly and bypasses cmd.exe’s ~8191 limit (CreateProcess ~32K still applies; see `CURSOR_BRIDGE_WIN_CMDLINE_MAX`). |
203
+ | `CURSOR_AGENT_SCRIPT` | — | **(Windows)** Path to the agent script (e.g. `agent.cmd` or `.js`). Use with `CURSOR_AGENT_NODE` for long prompts. |
204
+
205
+ Notes:
206
+
207
+ - The `login` subcommand depends on `chrome-launcher`; its dependency tree may pull typings into production installs. Prefer `npm audit` before release; upstream may move types to `devDependencies` over time.
208
+ - `--tailscale` changes the default host to `0.0.0.0` only when `CURSOR_BRIDGE_HOST` is not already set.
209
+ - ACP `session/request_permission` uses `reject-once` (least-privilege) so the agent cannot grant file/tool access; intentional for chat-only mode.
210
+ - Relative paths such as `CURSOR_BRIDGE_WORKSPACE`, `CURSOR_BRIDGE_SESSIONS_LOG`, `CURSOR_BRIDGE_TLS_CERT`, and `CURSOR_BRIDGE_TLS_KEY` are resolved from the current working directory.
211
+
212
+ #### Windows command line limits
213
+
214
+ Two different limits matter:
215
+
216
+ 1. **cmd.exe** — about **8191** characters. If the proxy invokes the agent through `cmd.exe`, long prompts can fail before the process starts.
217
+ 2. **CreateProcess** — about **32,767** characters for the **entire** command line (executable path plus all arguments), even when spawning `node.exe` and the script directly.
218
+
219
+ When `agent.cmd` is used (e.g. under `%LOCALAPPDATA%\cursor-agent\`), the proxy **auto-detects the versioned layout** (`versions/YYYY.MM.DD-commit/`) and spawns `node.exe` + `index.js` from the latest version directly, bypassing cmd.exe. If that does not apply, set both `CURSOR_AGENT_NODE` and `CURSOR_AGENT_SCRIPT` so the proxy spawns Node with the script and args **without** cmd.exe.
220
+
221
+ Very large prompts can still hit the **CreateProcess** cap and produce `spawn ENAMETOOLONG`. The proxy mitigates that on Windows by **truncating the start of the prompt** while **keeping the tail** (recent context), prepending a short notice, logging a warning, and optionally exposing `X-Cursor-Proxy-Prompt-Truncated: true`. Tune the budget with `CURSOR_BRIDGE_WIN_CMDLINE_MAX` (default `30000`). **ACP** or **stdin prompt** avoids argv length limits for prompt delivery.
222
+
223
+ Example (adjust paths to your install):
224
+
225
+ ```bash
226
+ set CURSOR_AGENT_NODE=C:\Program Files\nodejs\node.exe
227
+ set CURSOR_AGENT_SCRIPT=C:\path\to\Cursor\resources\agent\agent.cmd
228
+ # or for cursor-agent versioned layout:
229
+ # set CURSOR_AGENT_NODE=%LOCALAPPDATA%\cursor-agent\versions\2026.03.11-6dfa30c\node.exe
230
+ # set CURSOR_AGENT_SCRIPT=%LOCALAPPDATA%\cursor-agent\versions\2026.03.11-6dfa30c\index.js
231
+ ```
232
+
233
+ CLI flags:
234
+
235
+ | Flag | Description |
236
+ | -------------- | ------------------------------------------------------------------------------------------ |
237
+ | `--tailscale` | Bind to `0.0.0.0` for access from tailnet/LAN (unless `CURSOR_BRIDGE_HOST` is already set) |
238
+ | `-h`, `--help` | Show CLI usage |
239
+
240
+ Optional per-request override: send header `X-Cursor-Workspace: <path>` to use a subdirectory of `CURSOR_BRIDGE_WORKSPACE` for that request (requires `CURSOR_BRIDGE_CHAT_ONLY_WORKSPACE=false` and an existing path on the proxy host).
241
+
242
+ **CLI subcommands** (see `cursor-api-proxy --help`): `login <name>`, `accounts` (list), `logout`, `usage`, `reset-hwid` (see `--help` for options). Flags above still apply to the server entrypoint.
243
+
244
+ ## Multi-Account Setup
245
+
246
+ You can use multiple Cursor accounts to distribute load and avoid hitting usage limits. The proxy now includes a built-in account manager that makes this very easy.
247
+
248
+ ### 1. Adding Accounts (Easy Method)
249
+
250
+ You can add new accounts using the CLI `login` command. This will launch the Cursor CLI login process in an isolated profile directory: `~/.cursor-api-proxy/accounts/` on macOS/Linux, or `%USERPROFILE%\.cursor-api-proxy\accounts\` on Windows.
251
+
252
+ ```bash
253
+ npx cursor-api-proxy login account1
254
+ ```
255
+
256
+ _(A clean, incognito browser window will open for you to log into Cursor. Once done, the session is saved)._
257
+
258
+ Repeat this for as many accounts as you want:
259
+
260
+ ```bash
261
+ npx cursor-api-proxy login account2
262
+ npx cursor-api-proxy login account3
263
+ ```
264
+
265
+ **Auto-Discovery:** When you start the proxy server normally (`npx cursor-api-proxy`), it will automatically find all accounts under that `accounts` directory and include them in the rotation pool.
266
+
267
+ ### 2. Manual Config Directories
268
+
269
+ If you already have separate configuration folders (or want to specify them explicitly), you can override auto-discovery using the `CURSOR_CONFIG_DIRS` environment variable:
270
+
271
+ ```bash
272
+ CURSOR_CONFIG_DIRS=/path/to/cursor-agent-1,/path/to/cursor-agent-2 npm start
273
+ ```
274
+
275
+ ### 3. Modes of operation
276
+
277
+ **A. Single Port, Round-Robin Rotation (Default)**
278
+ In this mode, the proxy listens on one port and rotates through the available accounts for each request, selecting the least busy account automatically. This is active by default when multiple accounts are found.
279
+
280
+ **B. Multi-Port (One Server Per Account)**
281
+ If you want granular control (for example, to explicitly assign specific clients to specific accounts), you can use multi-port mode. The proxy will spawn multiple instances on incrementing ports, starting from `CURSOR_BRIDGE_PORT`.
282
+
283
+ ```bash
284
+ CURSOR_BRIDGE_MULTI_PORT=true CURSOR_BRIDGE_PORT=8765 npm start
285
+ ```
286
+
287
+ _Result: account1 is on 8765, account2 is on 8766, etc._
288
+
289
+ ## Streaming
290
+
291
+ The proxy supports `stream: true` on `POST /v1/chat/completions` and `POST /v1/messages`. It returns Server-Sent Events (SSE) in OpenAI’s streaming format. Cursor CLI emits incremental deltas plus a final full message; the proxy deduplicates output so clients receive each chunk only once.
292
+
293
+ **Test streaming:** from repo root, with the proxy running:
294
+
295
+ ```bash
296
+ node examples/test-stream.mjs
297
+ ```
298
+
299
+ See [examples/README.md](examples/README.md) for details.
300
+
301
+ ## License
302
+
303
+ MIT
@@ -0,0 +1,18 @@
1
+ export interface AccountInfo {
2
+ name: string;
3
+ configDir: string;
4
+ authenticated: boolean;
5
+ email?: string;
6
+ displayName?: string;
7
+ authId?: string;
8
+ plan?: string;
9
+ subscriptionStatus?: string;
10
+ expiresAt?: string;
11
+ }
12
+ /**
13
+ * Reads authentication and plan metadata from a saved account directory.
14
+ * Never throws — returns `authenticated: false` on any read/parse error.
15
+ */
16
+ export declare function readAccountInfo(name: string, configDir: string): AccountInfo;
17
+ export declare function handleAccountsList(): Promise<void>;
18
+ export declare function handleLogout(accountName: string): Promise<void>;
@@ -0,0 +1,149 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { ACCOUNTS_DIR } from "./constants.js";
4
+ import { readCachedToken, readKeychainToken, tokenSub, fetchAccountUsage, fetchStripeProfile, formatUsageSummary, describePlan, } from "./usage.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Helpers
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Reads authentication and plan metadata from a saved account directory.
10
+ * Never throws — returns `authenticated: false` on any read/parse error.
11
+ */
12
+ export function readAccountInfo(name, configDir) {
13
+ const info = { name, configDir, authenticated: false };
14
+ const configFile = path.join(configDir, "cli-config.json");
15
+ if (!fs.existsSync(configFile))
16
+ return info;
17
+ try {
18
+ const raw = JSON.parse(fs.readFileSync(configFile, "utf-8"));
19
+ if (raw.authInfo) {
20
+ info.authenticated = true;
21
+ info.email = raw.authInfo.email;
22
+ info.displayName = raw.authInfo.displayName;
23
+ info.authId = raw.authInfo.authId;
24
+ }
25
+ }
26
+ catch {
27
+ // malformed config — treat as unauthenticated
28
+ }
29
+ const statsigFile = path.join(configDir, "statsig-cache.json");
30
+ if (!fs.existsSync(statsigFile))
31
+ return info;
32
+ try {
33
+ const statsigRaw = JSON.parse(fs.readFileSync(statsigFile, "utf-8"));
34
+ if (!statsigRaw.data)
35
+ return info;
36
+ const statsig = JSON.parse(statsigRaw.data);
37
+ const custom = statsig?.user?.custom;
38
+ if (!custom)
39
+ return info;
40
+ if (custom.isEnterpriseUser) {
41
+ info.plan = "Enterprise";
42
+ }
43
+ else if (custom.stripeSubscriptionStatus === "active") {
44
+ info.plan = "Pro";
45
+ }
46
+ else {
47
+ info.plan = "Free";
48
+ }
49
+ info.subscriptionStatus = custom.stripeSubscriptionStatus;
50
+ if (custom.stripeMembershipExpiration) {
51
+ info.expiresAt = new Date(custom.stripeMembershipExpiration).toLocaleDateString();
52
+ }
53
+ }
54
+ catch {
55
+ // malformed statsig cache — skip plan info
56
+ }
57
+ return info;
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Commands
61
+ // ---------------------------------------------------------------------------
62
+ export async function handleAccountsList() {
63
+ if (!fs.existsSync(ACCOUNTS_DIR)) {
64
+ console.log("No accounts found. Use 'cursor-api-proxy login' to add one.");
65
+ return;
66
+ }
67
+ const entries = fs.readdirSync(ACCOUNTS_DIR, { withFileTypes: true });
68
+ const names = entries.filter((e) => e.isDirectory()).map((e) => e.name);
69
+ if (names.length === 0) {
70
+ console.log("No accounts found. Use 'cursor-api-proxy login' to add one.");
71
+ return;
72
+ }
73
+ console.log("🔑 Cursor Accounts:\n");
74
+ // Try to find an available token (per-account cache first, shared keychain fallback)
75
+ const keychainToken = readKeychainToken();
76
+ for (let i = 0; i < names.length; i++) {
77
+ const name = names[i];
78
+ const configDir = path.join(ACCOUNTS_DIR, name);
79
+ const info = readAccountInfo(name, configDir);
80
+ console.log(` ${i + 1}. ${name}`);
81
+ if (info.authenticated) {
82
+ // Per-account cached token wins. Fall back to keychain ONLY if its JWT
83
+ // sub matches this account's authId (prevents showing another account's data).
84
+ const cachedToken = readCachedToken(configDir);
85
+ const keychainMatchesAccount = !!keychainToken &&
86
+ !!info.authId &&
87
+ tokenSub(keychainToken) === info.authId;
88
+ const token = cachedToken ?? (keychainMatchesAccount ? keychainToken : undefined);
89
+ // Fetch live data before printing so we can decide what to show
90
+ let liveProfile = null;
91
+ let liveUsage = null;
92
+ if (token) {
93
+ try {
94
+ [liveUsage, liveProfile] = await Promise.all([
95
+ fetchAccountUsage(token),
96
+ fetchStripeProfile(token),
97
+ ]);
98
+ }
99
+ catch {
100
+ /* ignore transient fetch errors */
101
+ }
102
+ }
103
+ if (info.email) {
104
+ const display = info.displayName ? ` (${info.displayName})` : "";
105
+ console.log(` � ${info.email}${display}`);
106
+ }
107
+ // Show static plan only when live data isn't available (avoids contradictions)
108
+ if (info.plan && !liveProfile) {
109
+ const canceled = info.subscriptionStatus === "canceled" ? " · canceled" : "";
110
+ const expiry = info.expiresAt ? ` · expires ${info.expiresAt}` : "";
111
+ console.log(` 📊 ${info.plan}${canceled}${expiry}`);
112
+ }
113
+ console.log(` ✅ Authenticated`);
114
+ if (liveProfile) {
115
+ console.log(` 💳 ${describePlan(liveProfile)}`);
116
+ }
117
+ if (liveUsage) {
118
+ for (const line of formatUsageSummary(liveUsage))
119
+ console.log(line);
120
+ }
121
+ }
122
+ else {
123
+ console.log(` ⚠️ Not authenticated`);
124
+ }
125
+ console.log("");
126
+ }
127
+ console.log("Tip: run 'cursor-api-proxy logout <name>' to remove an account.");
128
+ }
129
+ export async function handleLogout(accountName) {
130
+ if (!accountName) {
131
+ console.error("❌ Error: Please specify the account name to remove.");
132
+ console.error("Usage: cursor-api-proxy logout <account-name>");
133
+ process.exit(1);
134
+ }
135
+ const configDir = path.join(ACCOUNTS_DIR, accountName);
136
+ if (!fs.existsSync(configDir)) {
137
+ console.error(`❌ Account '${accountName}' not found.`);
138
+ process.exit(1);
139
+ }
140
+ try {
141
+ fs.rmSync(configDir, { recursive: true, force: true });
142
+ console.log(`✅ Account '${accountName}' removed.`);
143
+ }
144
+ catch (err) {
145
+ console.error(`❌ Error removing account:`, err);
146
+ process.exit(1);
147
+ }
148
+ }
149
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/cli/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type ParsedArgs = {
2
+ tailscale: boolean;
3
+ help: boolean;
4
+ login: boolean;
5
+ accountsList: boolean;
6
+ logout: boolean;
7
+ accountName: string;
8
+ proxies: string[];
9
+ resetHwid: boolean;
10
+ deepClean: boolean;
11
+ dryRun: boolean;
12
+ };
13
+ export declare function parseArgs(argv: string[]): ParsedArgs;
14
+ export declare function printHelp(version: string): void;
@@ -0,0 +1,93 @@
1
+ export function parseArgs(argv) {
2
+ let tailscale = false;
3
+ let help = false;
4
+ let login = false;
5
+ let accountsList = false;
6
+ let logout = false;
7
+ let accountName = "";
8
+ let proxies = [];
9
+ let resetHwid = false;
10
+ let deepClean = false;
11
+ let dryRun = false;
12
+ for (let i = 0; i < argv.length; i++) {
13
+ const arg = argv[i];
14
+ if (arg === "login" || arg === "add-account") {
15
+ login = true;
16
+ if (i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
17
+ accountName = argv[++i];
18
+ }
19
+ continue;
20
+ }
21
+ if (arg === "logout" || arg === "remove-account") {
22
+ logout = true;
23
+ if (i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
24
+ accountName = argv[++i];
25
+ }
26
+ continue;
27
+ }
28
+ if (arg === "accounts" || arg === "list-accounts") {
29
+ accountsList = true;
30
+ continue;
31
+ }
32
+ if (arg === "reset-hwid" || arg === "reset") {
33
+ resetHwid = true;
34
+ continue;
35
+ }
36
+ if (arg === "--deep-clean") {
37
+ deepClean = true;
38
+ continue;
39
+ }
40
+ if (arg === "--dry-run") {
41
+ dryRun = true;
42
+ continue;
43
+ }
44
+ if (arg === "--tailscale") {
45
+ tailscale = true;
46
+ continue;
47
+ }
48
+ if (arg === "--help" || arg === "-h") {
49
+ help = true;
50
+ continue;
51
+ }
52
+ if (arg.startsWith("--proxy=")) {
53
+ proxies = arg
54
+ .slice("--proxy=".length)
55
+ .split(",")
56
+ .map((p) => p.trim())
57
+ .filter(Boolean);
58
+ continue;
59
+ }
60
+ throw new Error(`Unknown argument: ${arg}`);
61
+ }
62
+ return {
63
+ tailscale,
64
+ help,
65
+ login,
66
+ accountsList,
67
+ logout,
68
+ accountName,
69
+ proxies,
70
+ resetHwid,
71
+ deepClean,
72
+ dryRun,
73
+ };
74
+ }
75
+ export function printHelp(version) {
76
+ console.log(`cursor-api-proxy v${version}`);
77
+ console.log("");
78
+ console.log("Usage:");
79
+ console.log(" cursor-api-proxy [options]");
80
+ console.log("");
81
+ console.log("Commands:");
82
+ console.log(" login [name] Log into a Cursor account (saved to ~/.cursor-api-proxy/accounts/)");
83
+ console.log(" login [name] --proxy=... Same, but open Chrome through a random proxy from a comma-separated list");
84
+ console.log(" logout <name> Remove a saved Cursor account");
85
+ console.log(" accounts List saved accounts with plan info");
86
+ console.log(" reset-hwid Reset Cursor machine/telemetry IDs (anti-ban)");
87
+ console.log(" reset-hwid --deep-clean Also wipe session storage and cookies");
88
+ console.log("");
89
+ console.log("Options:");
90
+ console.log(" --tailscale Bind to 0.0.0.0 for tailnet/LAN access");
91
+ console.log(" -h, --help Show this help message");
92
+ }
93
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const ACCOUNTS_DIR: string;
@@ -0,0 +1,4 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ export const ACCOUNTS_DIR = path.join(process.env.HOME || process.env.USERPROFILE || os.homedir(), ".cursor-api-proxy", "accounts");
4
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/cli/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CACnC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,OAAO,EAAE,EAC3D,mBAAmB,EACnB,UAAU,CACX,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function handleLogin(accountName: string, proxies?: string[]): Promise<void>;