Skip to content

Commit bef6e5a

Browse files
committed
docs+release: v0.5.0-next.0 — transport, reliability, streaming fidelity
1 parent 45e5d0b commit bef6e5a

5 files changed

Lines changed: 110 additions & 22 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,56 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
## [0.5.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+
757
## [0.4.7-next.0] — 2026-07-17
858

959
- **Fixed: subagents silently ran Cursor's server-side `fast` default (e.g.

‎CONTRIBUTING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ When reporting a runtime bug, please include:
1818

1919
## Development setup
2020

21-
Requires **Node.js 22+**.
21+
Requires **Node.js 22.13+**.
2222

2323
```bash
2424
npm install

‎README.md‎

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ It uses the [official Cursor SDK](https://cursor.com/docs/sdk/typescript) (`@cur
1515
## Requirements
1616

1717
- **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)).
2021
- A **Cursor account and API key** (from the Cursor dashboard).
2122

2223
## Install
@@ -28,7 +29,7 @@ curl -fsSL https://raw.githubusercontent.com/stablekernel/opencode-cursor/main/i
2829
```
2930

3031
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:
3233

3334
- `--project` — write `./opencode.json` in the current directory instead.
3435
- `--yes` / `-y` — non-interactive.
@@ -137,20 +138,24 @@ See [SECURITY.md](./SECURITY.md) for the full threat model.
137138
| `mode` | `"agent"` | Default conversation mode (`"agent"` or `"plan"`) |
138139
| `params` | — | Default model params, e.g. `{ thinking: "high" }` |
139140
| `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) |
141143
| `agents` | — | Cursor subagent definitions |
142144
| `session` | `"auto"` | Session reuse strategy — see [Session reuse](#session-reuse-session) |
143145
| `forwardMcp` | `true` | Forward opencode's configured MCP servers to the Cursor agent |
144146
| `mcpServers` | — | Extra MCP servers (Cursor `McpServerConfig` shape); merged with forwarded ones |
145147
| `toolDisplay` | `"blocks"` | How Cursor's internal tool activity is shown — see [Tool display](#tool-display) |
146148
| `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) |
147150

148151
| Environment variable | Default | Meaning |
149152
| --- | --- | --- |
150153
| `CURSOR_API_KEY` | — | API key fallback |
151154
| `OPENCODE_CURSOR_MODEL_CACHE_TTL_MS` | `86400000` | Model-list cache lifetime (ms) |
152155
| `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`) |
154159

155160
### Session reuse (`session`)
156161

@@ -295,23 +300,56 @@ To force the fallback:
295300
{ "provider": { "cursor": { "options": { "toolDisplay": "reasoning" } } } }
296301
```
297302

298-
## Runtime: Bun and the Node sidecar
303+
## Transport
299304

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.
305+
opencode runs on [Bun](https://bun.sh), whose `node:http2` client is incompatible with the Cursor
306+
SDK's long-lived streaming RPC (`NGHTTP2_FRAME_SIZE_ERROR`; see
307+
[oven-sh/bun#31499](https://github.com/oven-sh/bun/issues/31499)). The plugin works around this by
308+
running the SDK over HTTP/1.1 in-process — no Node child process required. The historical Node
309+
sidecar remains as a rollback fallback.
303310

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).
311+
| Transport | Where it runs | When it's the default |
312+
| --- | --- | --- |
313+
| `http1` | in-process, HTTP/1.1 + SSE (Bun-safe) | under Bun |
314+
| `http2-direct` | in-process, SDK's default HTTP/2 | under Node (tests, scripts, non-Bun hosts) |
315+
| `sidecar` | spawned Node child hosting the SDK | never (rollback only) |
316+
317+
Resolution order: the `transport` provider option → `OPENCODE_CURSOR_TRANSPORT` →
318+
legacy `OPENCODE_CURSOR_SIDECAR` (`1`→`sidecar`, `0`→`http2-direct`) → the per-runtime default
319+
above.
320+
321+
If you hit a regression on the in-process path, roll back to the sidecar:
322+
323+
```bash
324+
export OPENCODE_CURSOR_TRANSPORT=sidecar # requires Node.js 22.13+ on PATH
325+
```
326+
327+
An explicit `sidecar` request with no Node on `PATH` falls back to `http1` (Bun) or `http2-direct`
328+
(Node) with a stderr notice.
329+
330+
## Reliability
331+
332+
The provider classifies Cursor SDK errors into typed kinds (`agent-not-found`, `agent-busy`,
333+
`rate-limit`, `network`, `auth`, `config`, `unknown`) and recovers per kind:
334+
335+
- **agent-busy** — a previous crash left a run wedged; the send is retried once with the SDK's
336+
`local.force` escape hatch.
337+
- **rate-limit / network** — bounded exponential backoff on the same agent.
338+
- **auth / config** — fail fast (not retried).
339+
340+
Sends carry an idempotency key so a retry is a server-side dedupe, not a duplicate turn.
306341

307-
Override with `OPENCODE_CURSOR_SIDECAR=1` (always sidecar) or `OPENCODE_CURSOR_SIDECAR=0` (never).
342+
A **stream watchdog** guards against a wedged run that streams nothing: if no event arrives within
343+
`OPENCODE_CURSOR_STALL_MS` (default `60000`), a pre-first-event stall cancels and force-resends
344+
once; a stall after partial output is surfaced as a terminal error rather than re-emitting the
345+
already-yielded prefix. Set `OPENCODE_CURSOR_STALL_MS=0` to disable.
308346

309347
## Troubleshooting
310348

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.
349+
- **Native Cursor tools hang / "Tool execution aborted" (`NGHTTP2_FRAME_SIZE_ERROR`).** A
350+
`http2-direct` transport was forced under Bun. Unset `OPENCODE_CURSOR_TRANSPORT` (defaults to the
351+
Bun-safe `http1`), or roll back with `OPENCODE_CURSOR_TRANSPORT=sidecar` (needs Node.js 22.13+ on
352+
`PATH`).
315353
- **Plugin enabled but no `cursor` provider/models appear, or you see a stale-version warning.**
316354
opencode caches the `@latest` plugin install on first use and never refreshes it.
317355
Exit opencode, delete `~/.cache/opencode/packages/@stablekernel/opencode-cursor@latest`

‎install.sh‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
# startup; @latest makes it re-resolve to the newest release). Reuses an
1212
# existing opencode.jsonc or opencode.json if present (comments preserved),
1313
# else creates opencode.json. An older/pinned entry is upgraded in place.
14-
# 2. Verifies Node.js 22+ is on your PATH — the plugin spawns a short-lived
15-
# Node sidecar to host the Cursor SDK (opencode itself runs on Bun).
14+
# 2. Verifies Node.js 22.13+ is on your PATH — the plugin can spawn a
15+
# short-lived Node sidecar to host the Cursor SDK (opencode runs on Bun).
1616
# 3. Offers to set CURSOR_API_KEY in your shell profile if it is not set.
1717
#
1818
# Flags:
@@ -107,8 +107,8 @@ info "${DIM}${REPO_URL}${RESET}"
107107
info "Scope: $SCOPE"
108108
info "Config: $CONFIG_PATH"
109109

110-
# ---- 1. Node.js 22+ check ----------------------------------------------------
111-
step "Checking Node.js (>= ${MIN_NODE_MAJOR}) on PATH"
110+
# ---- 1. Node.js 22.13+ check -------------------------------------------------
111+
step "Checking Node.js (>= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}) on PATH"
112112
if command -v node >/dev/null 2>&1; then
113113
NODE_VER="$(node --version 2>/dev/null | sed 's/^v//')"
114114
NODE_MAJOR="${NODE_VER%%.*}"

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@stablekernel/opencode-cursor",
3-
"version": "0.4.7-next.0",
3+
"version": "0.5.0-next.0",
44
"description": "opencode provider plugin backed by the official Cursor SDK (@cursor/sdk) — adds a Cursor provider and lists its models",
55
"type": "module",
66
"license": "MIT",

0 commit comments

Comments
 (0)