npm package: @nothumanwork/cursor-agents-sdk
Description: Typed Node-friendly utilities for driving the Cursor Agent CLI programmatically.
Latest version: 0.7.0

# Cursor Agents SDK

Typed, Node-friendly helpers for driving the [`cursor-agent`](https://cursor.com/docs/cli/overview) CLI in automation, CI, or custom developer tools. The SDK keeps parity with the documentation inside `./cursor-cli`, exposing:

- `CursorAgent` – spawns the CLI with safe defaults, structured JSON output, streaming NDJSON parsing, and `AbortSignal` cancellation.
- `buildCursorAgentCommand` – deterministic CLI argument construction (always pairs `--print` + `--output-format`).
- `CursorStreamEventSchema` / `CursorJsonResultSchema` – Zod validators aligned with Cursor's documented output, including tool call events.

## Installation

```bash
npm install @nothumanlabs/cursor-agents-sdk
# or
pnpm add @nothumanlabs/cursor-agents-sdk
# or
bun add @nothumanlabs/cursor-agents-sdk
```

The install script downloads the latest published `cursor-agent` binary from
`https://downloads.cursor.com/lab`. The command is linked as the package
`"bin"`, so `npx cursor-agent`, `pnpm exec cursor-agent`, or `bunx cursor-agent`
will launch the vendored CLI without additional setup.

Environment toggles:

| Variable | Description |
| --- | --- |
| `CURSOR_AGENT_SDK_VERSION` | Override the binary version tag (default: `2025.10.22-f894c20`). |
| `CURSOR_AGENT_SDK_BASE_URL` | Override the download base URL. |
| `CURSOR_AGENT_SDK_FORCE=1` | Force re-downloading the binary even if cached. |
| `CURSOR_AGENT_SDK_SKIP=1` | Skip the download (useful for CI with cached vendor folders). |
| `CURSOR_AGENT_SDK_STRICT=1` | Fail the install if checksum retrieval or verification fails. |
| `CURSOR_AGENT_SDK_BIN_NAME` | Customize the binary name written to the manifest. |

Manifest metadata is written to `vendor/manifest.json`. Programmatic consumers
can read the manifest or resolve the executable location with
`resolveCursorAgentBinaryPath()`.

## Usage

```ts
import {
  CursorAgent,
  type CursorAgentGenerateOptions,
  parseCursorEventLine,
} from "cursor-agents-sdk";

const agent = new CursorAgent({
  // apiKey defaults to process.env.CURSOR_API_KEY when omitted
  defaultModel: "sonnet-4",
});

const result = await agent.generate({
  prompt: "Summarize CONTRIBUTING.md",
  chatId: "previous-session-id", // optional resume
});
console.log(result.result);

for await (const event of agent.stream({
  prompt: "Review the staged diff for security issues",
  streamPartialOutput: true,
})) {
  if (event.type === "assistant") {
    console.log(event.message.content[0]?.text);
  }
}
```

If you only need the CLI command, reuse the builder:

```ts
import { spawn } from "node:child_process";
import { buildCursorAgentCommand } from "cursor-agents-sdk";

const command = buildCursorAgentCommand(
  { forceWrites: true },
  { prompt: "apply the diff", outputFormat: "json" },
);

await new Promise<void>((resolve, reject) => {
  const child = spawn(command[0], command.slice(1), { stdio: "inherit" });
  child.once("error", reject);
  child.once("close", (code) => {
    if (code === 0) {
      resolve();
    } else {
      reject(new Error(`cursor-agent exited with code ${code ?? "unknown"}`));
    }
  });
});
```

To delegate to the binary directly, resolve the vendored path via the manifest:

```ts
import { spawn } from "node:child_process";
import { resolveCursorAgentBinaryPath } from "cursor-agents-sdk";

const cursorAgentPath = await resolveCursorAgentBinaryPath();

await new Promise<void>((resolve, reject) => {
  const child = spawn(cursorAgentPath, ["status"], { stdio: "inherit" });
  child.once("error", reject);
  child.once("close", (code) => {
    if (code === 0) {
      resolve();
    } else {
      reject(new Error(`cursor-agent exited with code ${code ?? "unknown"}`));
    }
  });
});
```

## Development

| Task | Command |
| --- | --- |
| Install deps + generate dist | `bun install` |
| Type-check & emit types | `bun run build:types` |
| Bundle JS + declarations | `bun run build` |
| Lint / format | `bun run lint` / `bun run format` |
| Tests | `bun test` |

Git hooks (via `simple-git-hooks`) run `bun run lint && bun test` before each commit, keeping the publish artifact (`dist/**`) in sync with `src/**`.

The repo follows TDD by default: add or adjust tests (`*.test.ts`) before changing implementation, especially when reflecting new Cursor CLI behaviors documented in `./cursor-cli`.

## Changelog
### 28/10/2025 - Migration to NodeJS compatibility
The library was heavily reliant on Bun's Javascript runtime, causing some severe incompatibility issues with environments where Bun won't natively run (e.g. Cloudflare Workers, Vercel...)

Removed dependencies on Bun's native features (i.e. `Bun.spawn`, `subprocess`, `env`...). Migrating to using Node libraries.

* `examples/showcase.mjs` - can be run using `node examples/showcase.mjs` and it uses the built (to target Node) version of the library in `dist/index.js`