effect-cursor-sdk 0.1.1
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/LICENSE +21 -0
- package/README.md +275 -0
- package/dist/index.d.ts +840 -0
- package/dist/index.js +1186 -0
- package/dist/index.js.map +1 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Benjamin Kraatz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# effect-cursor-sdk
|
|
2
|
+
|
|
3
|
+
Effect-native access to the new [Cursor SDK](https://cursor.com/docs/sdk/typescript).
|
|
4
|
+
|
|
5
|
+
`effect-cursor-sdk` wraps `@cursor/sdk` with Effect services, layers, scoped resource management, tagged errors, observability hooks, deterministic mocks, and ready-made runtimes. The upstream SDK remains the source of truth for Cursor-owned types; this package adds Effect ergonomics without creating a parallel model that can drift.
|
|
6
|
+
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> This project is in early development. While all functionality is available, there is still much room for improvement. Contributions are welcome!
|
|
9
|
+
|
|
10
|
+
## Philosophy
|
|
11
|
+
|
|
12
|
+
- SDK-first: every public `@cursor/sdk` capability should be usable through this package.
|
|
13
|
+
- Effect-native: APIs return `Effect`, `Stream`, `Context.Service`, and `Layer` values.
|
|
14
|
+
- Type-preserving: SDK data types are re-exported instead of rebuilt.
|
|
15
|
+
- Resource-safe: scoped helpers make it easy to dispose agents correctly.
|
|
16
|
+
- Observable: SDK calls are wrapped in spans and metrics with secret redaction utilities.
|
|
17
|
+
- Testable: mock layers and fixtures let applications test Cursor workflows without network calls.
|
|
18
|
+
|
|
19
|
+
## Feature Coverage
|
|
20
|
+
|
|
21
|
+
| SDK capability | Effect wrapper |
|
|
22
|
+
| -------------------------------------------------------------------------------- | ---------------------------------------------- |
|
|
23
|
+
| `Agent.create`, `Agent.resume`, `Agent.prompt` | `CursorAgentService` |
|
|
24
|
+
| `agent.send`, `reload`, `close`, async dispose | `CursorAgentService` |
|
|
25
|
+
| `run.wait`, `stream`, `conversation`, `cancel`, status listeners, support checks | `CursorRunService` |
|
|
26
|
+
| `agent.listArtifacts`, `downloadArtifact` | `CursorArtifactService` |
|
|
27
|
+
| `Agent.list`, `get`, `listRuns`, `getRun`, messages | `CursorInspectionService` |
|
|
28
|
+
| `Agent.archive`, `unarchive`, `delete` | `CursorInspectionService` |
|
|
29
|
+
| `Cursor.me`, models, repositories | `CursorInspectionService` |
|
|
30
|
+
| MCP servers, sub-agents, local/cloud options, model options | SDK-owned `AgentOptions` and re-exported types |
|
|
31
|
+
| Local run event helpers and platform helpers | Re-exported from `@cursor/sdk` |
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bun add effect-cursor-sdk effect @cursor/sdk
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For development in this repo:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun install
|
|
43
|
+
bun run typecheck
|
|
44
|
+
bun run test
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { CursorAgentService, CursorRunService, liveLayer } from "effect-cursor-sdk";
|
|
51
|
+
import { Effect, Stream } from "effect";
|
|
52
|
+
|
|
53
|
+
const program = Effect.gen(function* () {
|
|
54
|
+
const agents = yield* CursorAgentService;
|
|
55
|
+
const runs = yield* CursorRunService;
|
|
56
|
+
|
|
57
|
+
const agent = yield* agents.create({
|
|
58
|
+
apiKey: process.env.CURSOR_API_KEY,
|
|
59
|
+
model: { id: "composer-2" },
|
|
60
|
+
local: { cwd: process.cwd() },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const run = yield* agents.send(agent, "Explain this repository");
|
|
64
|
+
const text = yield* runs.collectText(run);
|
|
65
|
+
|
|
66
|
+
yield* agents.dispose(agent);
|
|
67
|
+
return text;
|
|
68
|
+
}).pipe(Effect.provide(liveLayer));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`AgentOptions.apiKey` is a plain string at the SDK boundary. To keep the key in `Redacted` form until that boundary, read `CURSOR_API_KEY` (and optional `CURSOR_MODEL`, `CURSOR_LOCAL_CWD`) with `loadCursorConfig`, then merge into `AgentOptions` with `agentOptionsFromConfig`.
|
|
72
|
+
In a future version, we might drop the plain `AgentOptions` boundary and require all options to be passed through `CursorConfig` / `loadCursorConfig` / `agentOptionsFromConfig`.
|
|
73
|
+
|
|
74
|
+
Effect’s default `ConfigProvider` reads `process.env`, so you usually do not need to install a custom provider for this.
|
|
75
|
+
|
|
76
|
+
### Quick start with `loadCursorConfig`
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import {
|
|
80
|
+
CursorAgentService,
|
|
81
|
+
CursorRunService,
|
|
82
|
+
agentOptionsFromConfig,
|
|
83
|
+
loadCursorConfig,
|
|
84
|
+
liveLayer,
|
|
85
|
+
} from "effect-cursor-sdk";
|
|
86
|
+
import { Effect } from "effect";
|
|
87
|
+
|
|
88
|
+
const program = Effect.gen(function* () {
|
|
89
|
+
const agents = yield* CursorAgentService;
|
|
90
|
+
const runs = yield* CursorRunService;
|
|
91
|
+
|
|
92
|
+
const config = yield* loadCursorConfig;
|
|
93
|
+
const agent = yield* agents.create(
|
|
94
|
+
// Flexible: use the config from the environment, and override with local options.
|
|
95
|
+
agentOptionsFromConfig(config, {
|
|
96
|
+
model: { id: "composer-2" },
|
|
97
|
+
local: { cwd: process.cwd() },
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const run = yield* agents.send(agent, "Explain this repository");
|
|
102
|
+
const text = yield* runs.collectText(run);
|
|
103
|
+
|
|
104
|
+
yield* agents.dispose(agent);
|
|
105
|
+
return text;
|
|
106
|
+
}).pipe(Effect.provide(liveLayer));
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Scoped Agents
|
|
110
|
+
|
|
111
|
+
Prefer `scoped` when an agent should be disposed automatically:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { CursorAgentService, liveLayer } from "effect-cursor-sdk";
|
|
115
|
+
import { Effect } from "effect";
|
|
116
|
+
|
|
117
|
+
const program = Effect.scoped(
|
|
118
|
+
Effect.gen(function* () {
|
|
119
|
+
const agents = yield* CursorAgentService;
|
|
120
|
+
const agent = yield* agents.scoped({
|
|
121
|
+
model: { id: "composer-2" },
|
|
122
|
+
local: { cwd: process.cwd() },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return yield* agents.send(agent, "Find risky code paths");
|
|
126
|
+
}),
|
|
127
|
+
).pipe(Effect.provide(liveLayer));
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Cloud Agents
|
|
131
|
+
|
|
132
|
+
Cloud options are passed through as SDK `AgentOptions`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const agent =
|
|
136
|
+
yield *
|
|
137
|
+
agents.create({
|
|
138
|
+
apiKey: process.env.CURSOR_API_KEY,
|
|
139
|
+
model: { id: "composer-2" },
|
|
140
|
+
cloud: {
|
|
141
|
+
repos: [{ url: "https://github.com/your-org/your-repo", startingRef: "main" }],
|
|
142
|
+
autoCreatePR: true,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Streaming
|
|
148
|
+
|
|
149
|
+
`CursorRunService.streamEvents` preserves SDK event shapes and returns an Effect `Stream`.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const run = yield * agents.send(agent, "Refactor the auth module");
|
|
153
|
+
|
|
154
|
+
yield *
|
|
155
|
+
runs
|
|
156
|
+
.streamEvents(run)
|
|
157
|
+
.pipe(
|
|
158
|
+
Stream.runForEach((event) =>
|
|
159
|
+
event.type === "assistant"
|
|
160
|
+
? Effect.sync(() => console.log(event.message.content))
|
|
161
|
+
: Effect.void,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Inspection And Metadata
|
|
167
|
+
|
|
168
|
+
Use `CursorInspectionService` for agent/run listings, messages, lifecycle operations, account metadata, model discovery, and connected repositories.
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const inspection = yield * CursorInspectionService;
|
|
172
|
+
|
|
173
|
+
const agents = yield * inspection.listAgents({ runtime: "cloud", includeArchived: true });
|
|
174
|
+
const models = yield * inspection.listModels();
|
|
175
|
+
const repos = yield * inspection.listRepositories();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Errors
|
|
179
|
+
|
|
180
|
+
SDK failures are mapped into tagged errors such as `CursorAuthenticationError`, `CursorRateLimitError`, `CursorConfigurationError`, `CursorNetworkError`, and `CursorUnsupportedOperationError`. The original SDK error is preserved as `cause`, with safe operation context and retryability where available.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
program.pipe(
|
|
184
|
+
Effect.catchTag("CursorRateLimitError", (error) =>
|
|
185
|
+
Effect.logWarning(`Cursor rate limited request: ${error.message}`),
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Observability
|
|
191
|
+
|
|
192
|
+
Live service methods are wrapped with operation spans such as `cursor.agent.create`, `cursor.run.wait`, and `cursor.artifacts.download`. The package also exports metrics for operation starts, failures, and stream events, plus `redact` for safe metadata handling.
|
|
193
|
+
|
|
194
|
+
Never log API keys, MCP credentials, authorization headers, or prompt image data. The provided redaction helper treats those as sensitive by default.
|
|
195
|
+
|
|
196
|
+
> [!WARNING]
|
|
197
|
+
> The [redaction helper](./src/cursor-telemetry.ts#177) is a best-effort redactor for logs and attributes — not a cryptographic guarantee; do not rely on it for compliance redaction without review.
|
|
198
|
+
|
|
199
|
+
## Mocks And Tests
|
|
200
|
+
|
|
201
|
+
Use `mockLayer` for deterministic tests:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { CursorAgentService, mockLayer } from "effect-cursor-sdk";
|
|
205
|
+
import { Effect } from "effect";
|
|
206
|
+
|
|
207
|
+
const testProgram = Effect.gen(function* () {
|
|
208
|
+
const agents = yield* CursorAgentService;
|
|
209
|
+
const agent = yield* agents.create({ model: { id: "composer-2" } });
|
|
210
|
+
return yield* agents.send(agent, "Hello");
|
|
211
|
+
}).pipe(
|
|
212
|
+
Effect.provide(
|
|
213
|
+
mockLayer({
|
|
214
|
+
result: { id: "run-1", status: "finished", result: "ok" },
|
|
215
|
+
}),
|
|
216
|
+
),
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## API Surface
|
|
221
|
+
|
|
222
|
+
The main exports are:
|
|
223
|
+
|
|
224
|
+
- `CursorAgentService`
|
|
225
|
+
- `CursorRunService`
|
|
226
|
+
- `CursorArtifactService`
|
|
227
|
+
- `CursorInspectionService`
|
|
228
|
+
- `CursorSdkFactory`
|
|
229
|
+
- `liveLayer`, `mockLayer`, `liveRuntime`, `makeMockRuntime`
|
|
230
|
+
- `CursorConfig`, `cursorConfig`, `agentOptionsFromConfig`, `loadCursorConfig`
|
|
231
|
+
- tagged Cursor error classes and `mapCursorError`
|
|
232
|
+
- SDK-owned types and utilities re-exported from `@cursor/sdk`
|
|
233
|
+
|
|
234
|
+
Use generated TypeScript declarations for exact signatures.
|
|
235
|
+
|
|
236
|
+
## Quality Gates
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
bun run typecheck
|
|
240
|
+
bun run lint
|
|
241
|
+
bun run format:check
|
|
242
|
+
bun run test
|
|
243
|
+
bun run test:coverage
|
|
244
|
+
bun run build
|
|
245
|
+
bun run lint:package
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Coverage is measured with Vitest v8 coverage. The suite focuses on deterministic wrapper behavior; live SDK network paths should be validated separately with credentials and a disposable repository.
|
|
249
|
+
|
|
250
|
+
## Versioning and Publishing
|
|
251
|
+
|
|
252
|
+
Use conventional commits for readable history and changelog context:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
feat: add cursor artifact helpers
|
|
256
|
+
fix: map cursor rate limit errors
|
|
257
|
+
docs: clarify runtime setup
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
User-facing changes should include a Changeset:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
bun run changeset
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
On `main`, GitHub Actions uses Changesets to open a version PR when pending Changesets exist. After that PR is merged, the same workflow runs `bun run release` and publishes to NPM with the `NPM_TOKEN` repository secret.
|
|
267
|
+
|
|
268
|
+
For local release preparation, apply pending Changesets and publish only after the package is approved for public release:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
bun run version
|
|
272
|
+
bun run release
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`bun run release` runs `typecheck`, `lint`, `test`, `build`, and `publint` before publishing to NPM.
|