@stablekernel/opencode-cursor 0.4.7-next.0 → 0.5.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,56 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.5.0-next.0] — 2026-07-23
8
+
9
+ Native-experience overhaul: in-process HTTP/1.1 transport under Bun, typed-error
10
+ reliability, and full streaming fidelity.
11
+
12
+ - **HTTP/1.1 in-process transport is now the default under Bun; the Node sidecar
13
+ is a fallback.** opencode runs on Bun, whose `node:http2` client breaks the
14
+ Cursor SDK's streaming RPC (`NGHTTP2_FRAME_SIZE_ERROR`; oven-sh/bun#31499).
15
+ The SDK now runs in-process over HTTP/1.1 + SSE
16
+ (`Cursor.configure({ local: { useHttp1ForAgent: true } })`) — no Node child
17
+ process required. Three transports are selectable via the `transport` provider
18
+ option or `OPENCODE_CURSOR_TRANSPORT`: `http1` (Bun default), `http2-direct`
19
+ (Node default), and `sidecar` (rollback). Resolution order is option →
20
+ `OPENCODE_CURSOR_TRANSPORT` → legacy `OPENCODE_CURSOR_SIDECAR`
21
+ (`1`→`sidecar`, `0`→`http2-direct`) → per-runtime default. Roll back with
22
+ `OPENCODE_CURSOR_TRANSPORT=sidecar`.
23
+ - **Typed error classification with per-kind recovery.** SDK errors are
24
+ classified into `agent-not-found`, `agent-busy`, `rate-limit`, `network`,
25
+ `auth`, `config`, and `unknown` (by error `name`/`status`/`code`, never
26
+ `instanceof` — sidecar-forwarded errors arrive as plain objects). `agent-busy`
27
+ resends once with `local.force`; `rate-limit`/`network` retry with bounded
28
+ backoff on the same agent; `auth`/`config` fail fast.
29
+ - **Idempotent resends.** Every (re)send of a turn carries an idempotency key so
30
+ a retry is a server-side dedupe, not a duplicate turn.
31
+ - **Stream watchdog.** A wedged run that streams nothing is bounded by
32
+ `OPENCODE_CURSOR_STALL_MS` (default `60000`): a pre-first-event stall cancels
33
+ and force-resends once; a stall after partial output surfaces a terminal error
34
+ rather than re-emitting the already-yielded prefix. Set to `0` to disable.
35
+ - **Fixed: silent-replay turns dropped their token usage.** A multi-message
36
+ interjection replays leading messages silently and streams only the last; the
37
+ usage from the silent turns is now summed into the visible turn's reported
38
+ usage instead of being lost.
39
+ - **Live tool-input streaming.** Cursor's `partial-tool-call` updates are bridged
40
+ to incremental tool-input parts, so tool arguments stream as they arrive
41
+ instead of appearing all at once when the call completes.
42
+ - **Thinking duration and compaction metadata.** `thinking-completed` carries the
43
+ reasoning duration, and Cursor's summary/compaction updates are surfaced as
44
+ compaction events in the stream.
45
+ - **SDK-authoritative model variants.** Variant construction prefers the SDK's
46
+ own `displayName`/`isDefault` metadata rather than deriving it locally.
47
+ - **`autoReview` option and multi-root delegation.** New `autoReview` provider
48
+ option gates tool calls through Cursor's classifier-backed Auto review
49
+ (best-effort, not a security boundary). `cursor_delegate` gains
50
+ `additionalCwds` to combine extra workspace roots into a multi-root agent
51
+ workspace.
52
+ - **Node floor raised to >=22.13** (`engines.node`, from >=22.0), and only
53
+ needed for the `sidecar` fallback transport.
54
+ - **Dependency bumps.** `@cursor/sdk` 1.0.23→1.0.24, `@opencode-ai/plugin`
55
+ 1.17.14→1.18.4, `@opencode-ai/sdk` 1.17.14→1.18.4.
56
+
7
57
  ## [0.4.7-next.0] — 2026-07-17
8
58
 
9
59
  - **Fixed: subagents silently ran Cursor's server-side `fast` default (e.g.
package/README.md CHANGED
@@ -15,8 +15,9 @@ It uses the [official Cursor SDK](https://cursor.com/docs/sdk/typescript) (`@cur
15
15
  ## Requirements
16
16
 
17
17
  - **opencode 1.17+**
18
- - **Node.js 22+ on your `PATH`** — opencode runs on [Bun](https://bun.sh); the plugin needs a
19
- Node sidecar to host the Cursor SDK (see [Runtime](#runtime-bun-and-the-node-sidecar)).
18
+ - **Node.js 22.13+ on your `PATH`** (optional) — opencode runs on [Bun](https://bun.sh) and the
19
+ plugin runs the Cursor SDK in-process by default; Node is only needed for the `sidecar`
20
+ transport fallback (see [Transport](#transport)).
20
21
  - A **Cursor account and API key** (from the Cursor dashboard).
21
22
 
22
23
  ## Install
@@ -28,7 +29,7 @@ curl -fsSL https://raw.githubusercontent.com/stablekernel/opencode-cursor/main/i
28
29
  ```
29
30
 
30
31
  Registers the plugin in your global `opencode.json` (`~/.config/opencode/opencode.json`), checks
31
- for Node.js 22+, and offers to set `CURSOR_API_KEY`. Flags:
32
+ for Node.js 22.13+, and offers to set `CURSOR_API_KEY`. Flags:
32
33
 
33
34
  - `--project` — write `./opencode.json` in the current directory instead.
34
35
  - `--yes` / `-y` — non-interactive.
@@ -137,20 +138,25 @@ See [SECURITY.md](./SECURITY.md) for the full threat model.
137
138
  | `mode` | `"agent"` | Default conversation mode (`"agent"` or `"plan"`) |
138
139
  | `params` | — | Default model params, e.g. `{ thinking: "high" }` |
139
140
  | `settingSources` | — | Cursor settings layers to load: `["project","user","all",...]` — pulls in your Cursor skills, rules, and `.cursor/mcp.json` |
140
- | `sandbox` | — | Run the agent's tools in Cursor's sandbox |
141
+ | `sandbox` | — | Run the agent's tools in [Cursor's sandbox](https://cursor.com/docs/agent/sandbox) |
142
+ | `autoReview` | `false` | Gate tool calls through Cursor's classifier-backed Auto review (best-effort, not a security boundary) |
141
143
  | `agents` | — | Cursor subagent definitions |
142
144
  | `session` | `"auto"` | Session reuse strategy — see [Session reuse](#session-reuse-session) |
143
145
  | `forwardMcp` | `true` | Forward opencode's configured MCP servers to the Cursor agent |
144
146
  | `mcpServers` | — | Extra MCP servers (Cursor `McpServerConfig` shape); merged with forwarded ones |
145
147
  | `toolDisplay` | `"blocks"` | How Cursor's internal tool activity is shown — see [Tool display](#tool-display) |
146
148
  | `systemPrompt` | `"rules"` | How opencode's system prompt reaches the agent — see [System prompt](#system-prompt) |
149
+ | `transport` | — | Cursor agent transport (`"http1"` \| `"http2-direct"` \| `"sidecar"`) — see [Transport](#transport) |
147
150
 
148
151
  | Environment variable | Default | Meaning |
149
152
  | --- | --- | --- |
150
153
  | `CURSOR_API_KEY` | — | API key fallback |
151
154
  | `OPENCODE_CURSOR_MODEL_CACHE_TTL_MS` | `86400000` | Model-list cache lifetime (ms) |
152
155
  | `OPENCODE_CURSOR_DEBUG` | — | Set to `1` for trace logging on stderr |
153
- | `OPENCODE_CURSOR_SIDECAR` | — | `1` = always use Node sidecar; `0` = never |
156
+ | `OPENCODE_CURSOR_TRANSPORT` | — | Force a transport: `http1` \| `http2-direct` \| `sidecar` see [Transport](#transport) |
157
+ | `OPENCODE_CURSOR_STALL_MS` | `60000` | Stream watchdog timeout (ms); `0` disables — see [Reliability](#reliability) |
158
+ | `OPENCODE_CURSOR_SIDECAR` | — | Legacy: `1` maps to `sidecar`, `0` maps to `http2-direct` (superseded by `OPENCODE_CURSOR_TRANSPORT`) |
159
+ | `OPENCODE_CURSOR_TOOL_INPUT_STREAM` | on | Set to `0` to disable live tool-input streaming (`tool-input-start`/`-delta`/`-end` parts) |
154
160
 
155
161
  ### Session reuse (`session`)
156
162
 
@@ -295,23 +301,56 @@ To force the fallback:
295
301
  { "provider": { "cursor": { "options": { "toolDisplay": "reasoning" } } } }
296
302
  ```
297
303
 
298
- ## Runtime: Bun and the Node sidecar
304
+ ## Transport
299
305
 
300
- opencode runs on [Bun](https://bun.sh), which has an `node:http2` incompatibility with the Cursor
301
- SDK's streaming RPC. The plugin transparently hosts the Cursor SDK in a short-lived **Node child
302
- process** when running under Bun. Under Node it runs in-process.
306
+ opencode runs on [Bun](https://bun.sh), whose `node:http2` client is incompatible with the Cursor
307
+ SDK's long-lived streaming RPC (`NGHTTP2_FRAME_SIZE_ERROR`; see
308
+ [oven-sh/bun#31499](https://github.com/oven-sh/bun/issues/31499)). The plugin works around this by
309
+ running the SDK over HTTP/1.1 in-process — no Node child process required. The historical Node
310
+ sidecar remains as a rollback fallback.
303
311
 
304
- This is why **Node.js 22+ on your `PATH`** is required. If Node isn't found, the plugin warns once
305
- and falls back to in-process (native Cursor tools will misbehave until Node is available).
312
+ | Transport | Where it runs | When it's the default |
313
+ | --- | --- | --- |
314
+ | `http1` | in-process, HTTP/1.1 + SSE (Bun-safe) | under Bun |
315
+ | `http2-direct` | in-process, SDK's default HTTP/2 | under Node (tests, scripts, non-Bun hosts) |
316
+ | `sidecar` | spawned Node child hosting the SDK | never (rollback only) |
317
+
318
+ Resolution order: the `transport` provider option → `OPENCODE_CURSOR_TRANSPORT` →
319
+ legacy `OPENCODE_CURSOR_SIDECAR` (`1`→`sidecar`, `0`→`http2-direct`) → the per-runtime default
320
+ above.
321
+
322
+ If you hit a regression on the in-process path, roll back to the sidecar:
323
+
324
+ ```bash
325
+ export OPENCODE_CURSOR_TRANSPORT=sidecar # requires Node.js 22.13+ on PATH
326
+ ```
327
+
328
+ An explicit `sidecar` request with no Node on `PATH` falls back to `http1` (Bun) or `http2-direct`
329
+ (Node) with a stderr notice.
330
+
331
+ ## Reliability
332
+
333
+ The provider classifies Cursor SDK errors into typed kinds (`agent-not-found`, `agent-busy`,
334
+ `rate-limit`, `network`, `auth`, `config`, `unknown`) and recovers per kind:
335
+
336
+ - **agent-busy** — a previous crash left a run wedged; the send is retried once with the SDK's
337
+ `local.force` escape hatch.
338
+ - **rate-limit / network** — bounded exponential backoff on the same agent.
339
+ - **auth / config** — fail fast (not retried).
340
+
341
+ Sends carry an idempotency key so a retry is a server-side dedupe, not a duplicate turn.
306
342
 
307
- Override with `OPENCODE_CURSOR_SIDECAR=1` (always sidecar) or `OPENCODE_CURSOR_SIDECAR=0` (never).
343
+ A **stream watchdog** guards against a wedged run that streams nothing: if no event arrives within
344
+ `OPENCODE_CURSOR_STALL_MS` (default `60000`), a pre-first-event stall cancels and force-resends
345
+ once; a stall after partial output is surfaced as a terminal error rather than re-emitting the
346
+ already-yielded prefix. Set `OPENCODE_CURSOR_STALL_MS=0` to disable.
308
347
 
309
348
  ## Troubleshooting
310
349
 
311
- - **Native Cursor tools hang / "Tool execution aborted" (`NGHTTP2_FRAME_SIZE_ERROR`).** Node isn't
312
- on your `PATH`. Install Node.js 22+, or force the sidecar with `OPENCODE_CURSOR_SIDECAR=1`.
313
- - **"Running under Bun without a usable Node sidecar" warning.** Install Node.js 22+, or set
314
- `OPENCODE_CURSOR_SIDECAR=0` to accept in-process behavior and silence the warning.
350
+ - **Native Cursor tools hang / "Tool execution aborted" (`NGHTTP2_FRAME_SIZE_ERROR`).** A
351
+ `http2-direct` transport was forced under Bun. Unset `OPENCODE_CURSOR_TRANSPORT` (defaults to the
352
+ Bun-safe `http1`), or roll back with `OPENCODE_CURSOR_TRANSPORT=sidecar` (needs Node.js 22.13+ on
353
+ `PATH`).
315
354
  - **Plugin enabled but no `cursor` provider/models appear, or you see a stale-version warning.**
316
355
  opencode caches the `@latest` plugin install on first use and never refreshes it.
317
356
  Exit opencode, delete `~/.cache/opencode/packages/@stablekernel/opencode-cursor@latest`