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 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.