@alumnium/cursor 0.0.0-stage → 0.24.0-alpha.2

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/src/index.js ADDED
@@ -0,0 +1,1069 @@
1
+ // cursor/src/llm/CursorLanguageModel.ts
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { APICallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
6
+ import { z } from "zod";
7
+ import { Logger } from "@alumnium/core/internal";
8
+ var logger = Logger.get(
9
+ "packages/typescript/cursor/src/llm/CursorLanguageModel.ts",
10
+ );
11
+ var CHAT_CONTEXT = `# Execution context
12
+ You are used as a chat completion model inside another application.
13
+ Do NOT read or write files, run terminal commands, search the web, or use any
14
+ built-in or MCP tools. Reply with a single final assistant message directly.`;
15
+ var ToolCallsResponse = z.object({
16
+ tool_calls: z.array(
17
+ z.object({
18
+ name: z.string(),
19
+ arguments: z.record(z.string(), z.unknown()).optional(),
20
+ args: z.record(z.string(), z.unknown()).optional(),
21
+ }),
22
+ ),
23
+ });
24
+
25
+ class CursorLanguageModel {
26
+ specificationVersion = "v4";
27
+ provider = "cursor";
28
+ modelId;
29
+ supportedUrls = {};
30
+ #options;
31
+ #sandbox = true;
32
+ constructor(options) {
33
+ this.modelId = options.modelId;
34
+ this.#options = options;
35
+ }
36
+ async doGenerate(options) {
37
+ const abort = createAbortScope(options.abortSignal);
38
+ try {
39
+ return await this.#generateOnce(options, abort);
40
+ } catch (error) {
41
+ options.abortSignal?.throwIfAborted();
42
+ if (
43
+ this.#sandbox &&
44
+ error instanceof Error &&
45
+ error.name === "ConfigurationError" &&
46
+ /sandbox/i.test(error.message)
47
+ ) {
48
+ logger.warn(
49
+ "Cursor SDK sandboxing is not supported; retrying without it.",
50
+ );
51
+ this.#sandbox = false;
52
+ return await this.doGenerate(options);
53
+ }
54
+ if (
55
+ error instanceof Error &&
56
+ (error.name === "RateLimitError" ||
57
+ error.name === "TimeoutError" ||
58
+ ("isRetryable" in error && error.isRetryable === true))
59
+ ) {
60
+ throw new APICallError({
61
+ message: error.message,
62
+ url: "cursor://local",
63
+ requestBodyValues: { model: this.modelId },
64
+ isRetryable: true,
65
+ cause: error,
66
+ });
67
+ }
68
+ throw error;
69
+ } finally {
70
+ abort.dispose();
71
+ }
72
+ }
73
+ async doStream(options) {
74
+ const result = await this.doGenerate(options);
75
+ return {
76
+ stream: new ReadableStream({
77
+ start(controller) {
78
+ controller.enqueue({
79
+ type: "stream-start",
80
+ warnings: result.warnings,
81
+ });
82
+ controller.enqueue({ type: "response-metadata", ...result.response });
83
+ for (const part of result.content) {
84
+ if (part.type === "text") {
85
+ const id = crypto.randomUUID();
86
+ controller.enqueue({ type: "text-start", id });
87
+ controller.enqueue({ type: "text-delta", id, delta: part.text });
88
+ controller.enqueue({ type: "text-end", id });
89
+ } else if (part.type === "tool-call") {
90
+ controller.enqueue(part);
91
+ }
92
+ }
93
+ controller.enqueue({
94
+ type: "finish",
95
+ usage: result.usage,
96
+ finishReason: result.finishReason,
97
+ });
98
+ controller.close();
99
+ },
100
+ }),
101
+ };
102
+ }
103
+ async #generateOnce(options, abort) {
104
+ const signal = options.abortSignal;
105
+ signal?.throwIfAborted();
106
+ const prompt = serializePrompt(options);
107
+ const contract = responseContract(options);
108
+ const sdk = await abort.run((this.#options.sdkLoader ?? loadCursorSdk)());
109
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "alumnium-cursor-"));
110
+ let agent;
111
+ try {
112
+ const cwd = path.join(root, "workspace");
113
+ await fs.mkdir(cwd);
114
+ const store = new sdk.JsonlLocalAgentStore(path.join(root, "store"));
115
+ signal?.throwIfAborted();
116
+ agent = await abort.run(
117
+ sdk.Agent.create({
118
+ ...(this.#options.apiKey ? { apiKey: this.#options.apiKey } : {}),
119
+ model: { id: this.modelId },
120
+ local: {
121
+ cwd,
122
+ settingSources: [],
123
+ sandboxOptions: { enabled: this.#sandbox },
124
+ store,
125
+ },
126
+ }),
127
+ async (lateAgent) => {
128
+ try {
129
+ lateAgent.close();
130
+ } finally {
131
+ await fs.rm(root, { recursive: true, force: true });
132
+ }
133
+ },
134
+ );
135
+ const first = await send(
136
+ agent,
137
+ {
138
+ text: [prompt.text, CHAT_CONTEXT, contract].filter(Boolean).join(`
139
+
140
+ `),
141
+ images: prompt.images,
142
+ },
143
+ abort,
144
+ );
145
+ const usages = [first.usage];
146
+ let content;
147
+ try {
148
+ content = parseResponse(first.result ?? "", options);
149
+ } catch (error) {
150
+ const retry = await send(
151
+ agent,
152
+ {
153
+ text: `Your previous reply was invalid: ${error instanceof Error ? error.message : String(error)}
154
+ Respond again following this contract exactly:
155
+ ${contract}`,
156
+ },
157
+ abort,
158
+ );
159
+ usages.push(retry.usage);
160
+ content = parseResponse(retry.result ?? "", options);
161
+ }
162
+ return {
163
+ content,
164
+ finishReason: {
165
+ unified: content.some((part) => part.type === "tool-call")
166
+ ? "tool-calls"
167
+ : "stop",
168
+ raw: "finished",
169
+ },
170
+ usage: toUsage(usages),
171
+ warnings: [],
172
+ response: { id: first.id, modelId: this.modelId },
173
+ };
174
+ } finally {
175
+ try {
176
+ agent?.close();
177
+ } finally {
178
+ await fs.rm(root, { recursive: true, force: true });
179
+ }
180
+ }
181
+ }
182
+ }
183
+ async function loadCursorSdk() {
184
+ return import("@cursor/sdk");
185
+ }
186
+ function serializePrompt(options) {
187
+ const images = [];
188
+ const sections = options.prompt.map((message) => {
189
+ const text =
190
+ message.role === "system"
191
+ ? message.content
192
+ : message.content.map((part) => {
193
+ if (part.type === "text" || part.type === "reasoning")
194
+ return part.text;
195
+ if (part.type === "tool-call")
196
+ return JSON.stringify({
197
+ tool_call_id: part.toolCallId,
198
+ name: part.toolName,
199
+ arguments: part.input,
200
+ });
201
+ if (part.type === "tool-result")
202
+ return JSON.stringify({
203
+ tool_call_id: part.toolCallId,
204
+ name: part.toolName,
205
+ output: part.output,
206
+ });
207
+ if (part.type === "file" && part.mediaType.startsWith("image/")) {
208
+ if (part.data.type === "url") return part.data.url.toString();
209
+ if (part.data.type === "data") {
210
+ images.push({
211
+ mimeType: part.mediaType,
212
+ data:
213
+ typeof part.data.data === "string"
214
+ ? part.data.data
215
+ : Buffer.from(part.data.data).toString("base64"),
216
+ });
217
+ return `[image ${images.length} attached]`;
218
+ }
219
+ }
220
+ throw new UnsupportedFunctionalityError({
221
+ functionality: `Cursor prompt part: ${part.type}`,
222
+ });
223
+ }).join(`
224
+ `);
225
+ const role = message.role === "tool" ? "tool_result" : message.role;
226
+ return `<${role}>
227
+ ${text}
228
+ </${role}>`;
229
+ });
230
+ return {
231
+ text: sections.join(`
232
+
233
+ `),
234
+ images,
235
+ };
236
+ }
237
+ function responseContract(options) {
238
+ if (options.responseFormat?.type === "json") {
239
+ return `# Structured output
240
+ Respond with ONLY valid JSON, with no other text.
241
+ ${options.responseFormat.description ?? ""}
242
+ JSON schema: ${JSON.stringify(options.responseFormat.schema ?? {})}`;
243
+ }
244
+ const tools = activeTools(options);
245
+ if (!tools.length) return "";
246
+ return `# Tool calling
247
+ Decide which of these tools to call to fulfill the request. Do not execute them yourself.
248
+ Available tools (JSON schema per tool):
249
+ ${JSON.stringify(tools)}
250
+ Respond with ONLY a JSON object of this exact shape and no other text:
251
+ {"tool_calls": [{"name": "<tool_name>", "arguments": {<parameters>}}]}
252
+ List multiple entries when several calls are needed, in execution order.
253
+ ${options.toolChoice?.type === "required" || options.toolChoice?.type === "tool" ? "You MUST call at least one of the listed tools." : 'If no tool applies, respond with {"tool_calls": []}.'}`;
254
+ }
255
+ function activeTools(options) {
256
+ if (options.toolChoice?.type === "none") return [];
257
+ return (options.tools ?? [])
258
+ .map((tool) => {
259
+ if (tool.type !== "function")
260
+ throw new UnsupportedFunctionalityError({
261
+ functionality: "Cursor provider-defined tools",
262
+ });
263
+ return tool;
264
+ })
265
+ .filter(
266
+ (tool) =>
267
+ options.toolChoice?.type !== "tool" ||
268
+ tool.name === options.toolChoice.toolName,
269
+ );
270
+ }
271
+ function parseResponse(text, options) {
272
+ if (options.responseFormat?.type === "json")
273
+ return [{ type: "text", text: JSON.stringify(parseJson(text)) }];
274
+ const tools = activeTools(options);
275
+ if (!tools.length) return [{ type: "text", text }];
276
+ const calls = ToolCallsResponse.parse(parseJson(text)).tool_calls;
277
+ if (
278
+ !calls.length &&
279
+ (options.toolChoice?.type === "required" ||
280
+ options.toolChoice?.type === "tool")
281
+ )
282
+ throw new Error("At least one tool call is required");
283
+ return calls.map((call) => {
284
+ if (!tools.some((tool) => tool.name === call.name))
285
+ throw new Error(`Unknown or disallowed tool: ${call.name}`);
286
+ return {
287
+ type: "tool-call",
288
+ toolCallId: `call_${crypto.randomUUID()}`,
289
+ toolName: call.name,
290
+ input: JSON.stringify(call.arguments ?? call.args ?? {}),
291
+ };
292
+ });
293
+ }
294
+ function parseJson(text) {
295
+ try {
296
+ return JSON.parse(text);
297
+ } catch {}
298
+ const start = text.search(/[[{]/);
299
+ let depth = 0;
300
+ let quoted = false;
301
+ let escaped = false;
302
+ for (let index = start; index >= 0 && index < text.length; index++) {
303
+ const char = text[index];
304
+ if (escaped) escaped = false;
305
+ else if (quoted && char === "\\") escaped = true;
306
+ else if (char === '"') quoted = !quoted;
307
+ else if (!quoted) {
308
+ if (char === "{" || char === "[") depth++;
309
+ else if ((char === "}" || char === "]") && --depth === 0)
310
+ return JSON.parse(text.slice(start, index + 1));
311
+ }
312
+ }
313
+ throw new Error("Response does not contain valid JSON");
314
+ }
315
+ async function send(agent, payload, abort) {
316
+ abort.signal?.throwIfAborted();
317
+ const run = await abort.run(agent.send(payload), (lateRun) => {
318
+ lateRun.cancel().catch(() => {});
319
+ });
320
+ let result;
321
+ try {
322
+ result = await abort.run(run.wait());
323
+ } catch (error) {
324
+ run.cancel().catch(() => {});
325
+ throw error;
326
+ }
327
+ if (result.status !== "finished")
328
+ throw new Error(
329
+ `Cursor agent run ${result.status}: ${result.error?.message ?? "no error details"}`,
330
+ );
331
+ return result;
332
+ }
333
+ function createAbortScope(signal) {
334
+ signal?.throwIfAborted();
335
+ let onAbort = () => {};
336
+ const aborted = new Promise((_, reject) => {
337
+ onAbort = () => reject(signal?.reason);
338
+ signal?.addEventListener("abort", onAbort, { once: true });
339
+ });
340
+ return {
341
+ signal,
342
+ async run(promise, onLateResult) {
343
+ if (!signal) return promise;
344
+ return Promise.race([
345
+ promise.then(async (value) => {
346
+ if (signal.aborted) {
347
+ await onLateResult?.(value);
348
+ signal.throwIfAborted();
349
+ }
350
+ return value;
351
+ }),
352
+ aborted,
353
+ ]);
354
+ },
355
+ dispose() {
356
+ signal?.removeEventListener("abort", onAbort);
357
+ },
358
+ };
359
+ }
360
+ function toUsage(usages) {
361
+ const reported = usages.filter((usage) => usage !== undefined);
362
+ function sum(key) {
363
+ return reported.some((usage) => usage[key] !== undefined)
364
+ ? reported.reduce((total, usage) => total + (usage[key] ?? 0), 0)
365
+ : undefined;
366
+ }
367
+ const noCache = sum("inputTokens");
368
+ const cacheRead = sum("cacheReadTokens");
369
+ const cacheWrite = sum("cacheWriteTokens");
370
+ return {
371
+ inputTokens: {
372
+ total:
373
+ noCache === undefined
374
+ ? undefined
375
+ : noCache + (cacheRead ?? 0) + (cacheWrite ?? 0),
376
+ noCache,
377
+ cacheRead,
378
+ cacheWrite,
379
+ },
380
+ outputTokens: {
381
+ total: sum("outputTokens"),
382
+ text: undefined,
383
+ reasoning: sum("reasoningTokens"),
384
+ },
385
+ };
386
+ }
387
+ // cursor/src/standalone/installCursorSdk.ts
388
+ import { createHash } from "node:crypto";
389
+ import fs4 from "node:fs/promises";
390
+ import { createRequire } from "node:module";
391
+ import os2 from "node:os";
392
+ import path4 from "node:path";
393
+ import { gunzipSync } from "node:zlib";
394
+ // cursor/src/llm/cursorProviders.ts
395
+ import {
396
+ Env as Env2,
397
+ isSingleFileExecutable,
398
+ Logger as Logger3,
399
+ maskString,
400
+ LlmFactory,
401
+ } from "@alumnium/core/internal";
402
+ import { Env, Logger as Logger2, retry } from "@alumnium/core/internal";
403
+
404
+ // cursor/src/standalone/cursorSdkManifest.ts
405
+ var CURSOR_SDK_PACKAGE_NAME = "@cursor/sdk";
406
+
407
+ // cursor/src/standalone/cursorSdkResolver.ts
408
+ import fs2 from "node:fs";
409
+ import Module from "node:module";
410
+ import path2 from "node:path";
411
+ var installedVendorRoots = new Map();
412
+ function installVendorResolveHook(vendorRoot, packageNames) {
413
+ const existing = installedVendorRoots.get(vendorRoot);
414
+ if (existing) return existing;
415
+ const vendorNodeModules = path2.join(vendorRoot, "node_modules");
416
+ const vendorPrefix = vendorRoot + path2.sep;
417
+ const resolutionCache = new Map();
418
+ const moduleWithResolveFilename = Module;
419
+ const resolveFilename = moduleWithResolveFilename._resolveFilename;
420
+ moduleWithResolveFilename._resolveFilename = function (...args) {
421
+ const [request, parent] = args;
422
+ if (
423
+ typeof request === "string" &&
424
+ isBareSpecifier(request) &&
425
+ parent?.filename?.startsWith(vendorPrefix)
426
+ ) {
427
+ let resolved = resolutionCache.get(request);
428
+ if (!resolutionCache.has(request)) {
429
+ const { packageName, subpath } = splitBareSpecifier(request);
430
+ resolved = packageNames.has(packageName)
431
+ ? resolvePackageEntry(vendorNodeModules, packageName, subpath)
432
+ : undefined;
433
+ resolutionCache.set(request, resolved);
434
+ }
435
+ if (resolved) return resolved;
436
+ }
437
+ return resolveFilename.call(this, ...args);
438
+ };
439
+ const handle = {
440
+ uninstall() {
441
+ moduleWithResolveFilename._resolveFilename = resolveFilename;
442
+ installedVendorRoots.delete(vendorRoot);
443
+ },
444
+ };
445
+ installedVendorRoots.set(vendorRoot, handle);
446
+ return handle;
447
+ }
448
+ function isBareSpecifier(request) {
449
+ return (
450
+ !request.startsWith(".") &&
451
+ !path2.isAbsolute(request) &&
452
+ !request.startsWith("node:") &&
453
+ !request.startsWith("bun:")
454
+ );
455
+ }
456
+ function splitBareSpecifier(request) {
457
+ const segments = request.split("/");
458
+ const nameLength = request.startsWith("@") ? 2 : 1;
459
+ return {
460
+ packageName: segments.slice(0, nameLength).join("/"),
461
+ subpath:
462
+ segments.length > nameLength
463
+ ? `./${segments.slice(nameLength).join("/")}`
464
+ : ".",
465
+ };
466
+ }
467
+ function resolvePackageEntry(vendorNodeModules, packageName, subpath) {
468
+ const packageDir = path2.join(vendorNodeModules, packageName);
469
+ const manifest = readPackageManifest(packageDir);
470
+ if (!manifest) return;
471
+ if (manifest.exports != null) {
472
+ const target = lookupExports(manifest.exports, subpath);
473
+ return target === undefined
474
+ ? undefined
475
+ : resolveExportTarget(packageDir, target);
476
+ }
477
+ const candidate =
478
+ subpath === "."
479
+ ? typeof manifest.main === "string"
480
+ ? manifest.main
481
+ : "index.js"
482
+ : subpath;
483
+ return probeFile(path2.join(packageDir, candidate));
484
+ }
485
+ var manifestCache = new Map();
486
+ function readPackageManifest(packageDir) {
487
+ if (!manifestCache.has(packageDir)) {
488
+ let manifest;
489
+ try {
490
+ manifest = JSON.parse(
491
+ fs2.readFileSync(path2.join(packageDir, "package.json"), "utf-8"),
492
+ );
493
+ } catch {
494
+ manifest = undefined;
495
+ }
496
+ manifestCache.set(packageDir, manifest);
497
+ }
498
+ return manifestCache.get(packageDir);
499
+ }
500
+ function lookupExports(exports, subpath) {
501
+ const isSubpathMap =
502
+ typeof exports === "object" &&
503
+ exports !== null &&
504
+ !Array.isArray(exports) &&
505
+ Object.keys(exports).every((key) => key === "." || key.startsWith("./"));
506
+ if (!isSubpathMap) return subpath === "." ? exports : undefined;
507
+ const map = exports;
508
+ if (subpath in map) return map[subpath];
509
+ for (const [key, value] of Object.entries(map)) {
510
+ const asterisk = key.indexOf("*");
511
+ if (asterisk < 0 || key.indexOf("*", asterisk + 1) >= 0) continue;
512
+ const prefix = key.slice(0, asterisk);
513
+ const suffix = key.slice(asterisk + 1);
514
+ if (
515
+ subpath.length > prefix.length + suffix.length &&
516
+ subpath.startsWith(prefix) &&
517
+ subpath.endsWith(suffix)
518
+ ) {
519
+ const wildcard = subpath.slice(
520
+ prefix.length,
521
+ subpath.length - suffix.length,
522
+ );
523
+ return typeof value === "string"
524
+ ? value.replaceAll("*", wildcard)
525
+ : value;
526
+ }
527
+ }
528
+ return;
529
+ }
530
+ var ACCEPTED_CONDITIONS = new Set(["require", "node", "default"]);
531
+ function resolveExportTarget(packageDir, target) {
532
+ if (typeof target === "string") {
533
+ if (!target.startsWith("./")) return;
534
+ const resolved = path2.join(packageDir, target);
535
+ return isFile(resolved) ? resolved : undefined;
536
+ }
537
+ if (Array.isArray(target)) {
538
+ for (const entry of target) {
539
+ const resolved = resolveExportTarget(packageDir, entry);
540
+ if (resolved) return resolved;
541
+ }
542
+ return;
543
+ }
544
+ if (typeof target === "object" && target !== null) {
545
+ for (const [condition, value] of Object.entries(target)) {
546
+ if (!ACCEPTED_CONDITIONS.has(condition)) continue;
547
+ const resolved = resolveExportTarget(packageDir, value);
548
+ if (resolved) return resolved;
549
+ }
550
+ }
551
+ return;
552
+ }
553
+ function probeFile(candidate) {
554
+ for (const probe of [
555
+ candidate,
556
+ `${candidate}.js`,
557
+ `${candidate}.json`,
558
+ path2.join(candidate, "index.js"),
559
+ path2.join(candidate, "index.json"),
560
+ ]) {
561
+ if (isFile(probe)) return probe;
562
+ }
563
+ return;
564
+ }
565
+ function isFile(filePath) {
566
+ try {
567
+ return fs2.statSync(filePath).isFile();
568
+ } catch {
569
+ return false;
570
+ }
571
+ }
572
+
573
+ // cursor/src/standalone/cursorSdkVendorManifest.ts
574
+ var cursorSdkVendorManifest = {
575
+ sdkVersion: "1.0.30",
576
+ packages: [
577
+ {
578
+ name: "@bufbuild/protobuf",
579
+ version: "1.10.0",
580
+ integrity:
581
+ "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==",
582
+ },
583
+ {
584
+ name: "@connectrpc/connect",
585
+ version: "1.7.0",
586
+ integrity:
587
+ "sha512-iNKdJRi69YP3mq6AePRT8F/HrxWCewrhxnLMNm0vpqXAR8biwzRtO6Hjx80C6UvtKJ5sFmffQT7I4Baecz389w==",
588
+ },
589
+ {
590
+ name: "@connectrpc/connect-node",
591
+ version: "1.7.0",
592
+ integrity:
593
+ "sha512-6vaPIkG/NyhxlYgytLoR9KYbPhczEboFB2OYWkA9qvUz1K7efXfeGrlRxoLtpa+r8VxyIOw73w5ktNe743nD+A==",
594
+ },
595
+ {
596
+ name: "@connectrpc/connect-web",
597
+ version: "1.7.0",
598
+ integrity:
599
+ "sha512-qyP0YOnUPRWwCc/VfsoydMJvkb7EyUPr2q9sHgBuJzbADjiqck1gKH5V5ZPzPhTLBvmz5UvG+wiZ5sMRQHU1MQ==",
600
+ },
601
+ {
602
+ name: "@cursor/sdk",
603
+ version: "1.0.30",
604
+ integrity:
605
+ "sha512-s3gIXfTD3w8ys+KFE81JjjoiJcynkHsf/JCDyXrnbliIac3dkT59hwYZII3XhsT1DlXIfqg+YzSMru6w1CkZow==",
606
+ },
607
+ {
608
+ name: "@cursor/sdk-darwin-arm64",
609
+ version: "1.0.30",
610
+ integrity:
611
+ "sha512-O0w2fLd6jxrvAUOJGsKBs8VSi5OojqqEOMFBzHTHS82wU/DX3ZlizK3czzCXxDKs3l8j/BVQwVCxP9jMFcf41Q==",
612
+ os: "darwin",
613
+ cpu: "arm64",
614
+ bin: {
615
+ rg: "bin/rg",
616
+ },
617
+ },
618
+ {
619
+ name: "@cursor/sdk-darwin-x64",
620
+ version: "1.0.30",
621
+ integrity:
622
+ "sha512-TdjreV7V6gtSKbUaXDarfE1735PES6uzLgLxp42E5kT6EXpjQhKsifdsYOMdsO/RBw166kya/XxG24L/FUfEHA==",
623
+ os: "darwin",
624
+ cpu: "x64",
625
+ bin: {
626
+ rg: "bin/rg",
627
+ },
628
+ },
629
+ {
630
+ name: "@cursor/sdk-linux-arm64",
631
+ version: "1.0.30",
632
+ integrity:
633
+ "sha512-1+bsmri6vJ2YuqL/SQ6QSx/ymu2eBzjGgT1bTgN47tCzxDgNOKacXtghpx4zdHM5AmOtT+aLXVVxXjStXmNtcA==",
634
+ os: "linux",
635
+ cpu: "arm64",
636
+ bin: {
637
+ rg: "bin/rg",
638
+ },
639
+ },
640
+ {
641
+ name: "@cursor/sdk-linux-x64",
642
+ version: "1.0.30",
643
+ integrity:
644
+ "sha512-5TRAM1xNwVr0Lox2ay5U5h+VY1OeqJLgnS28da7mx+ZkmeAU+hzuUFq2/lcIqoJrp2qBRdUH5WzI44JNtjBKmg==",
645
+ os: "linux",
646
+ cpu: "x64",
647
+ bin: {
648
+ rg: "bin/rg",
649
+ },
650
+ },
651
+ {
652
+ name: "@cursor/sdk-win32-x64",
653
+ version: "1.0.30",
654
+ integrity:
655
+ "sha512-kVjpWmLTFLL131TQm3ytz1HbAeyjBRAHMtr6vyLtbBMuLBb0la5igvt58Xi8mXwekymWXim1+rZj7ZYUO3K1rw==",
656
+ os: "win32",
657
+ cpu: "x64",
658
+ bin: {
659
+ rg: "bin/rg.exe",
660
+ },
661
+ },
662
+ {
663
+ name: "@fastify/busboy",
664
+ version: "2.1.1",
665
+ integrity:
666
+ "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
667
+ },
668
+ {
669
+ name: "@statsig/client-core",
670
+ version: "3.31.0",
671
+ integrity:
672
+ "sha512-SuxQD6TmVszPG7FoMKwTk/uyBuVFk7XnxI3T/E0uyb7PL7GNjONtfsoh+NqBBVUJVse0CUeSFfgJPoZy1ZOslQ==",
673
+ },
674
+ {
675
+ name: "@statsig/js-client",
676
+ version: "3.31.0",
677
+ integrity:
678
+ "sha512-LFa5E0LjT6sTfZv3sNGoyRLSZ1078+agdgOA+Vm1ecjG+KbSOfBLTW7hMwimrJ29slRwbYDzbtKaPJo/R37N2g==",
679
+ },
680
+ {
681
+ name: "undici",
682
+ version: "5.29.0",
683
+ integrity:
684
+ "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
685
+ },
686
+ {
687
+ name: "zod",
688
+ version: "3.25.76",
689
+ integrity:
690
+ "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
691
+ },
692
+ ],
693
+ };
694
+
695
+ // cursor/src/standalone/untar.ts
696
+ import fs3 from "node:fs/promises";
697
+ import path3 from "node:path";
698
+ var BLOCK_SIZE = 512;
699
+ var OFFSETS = {
700
+ name: [0, 100],
701
+ mode: [100, 8],
702
+ size: [124, 12],
703
+ checksum: [148, 8],
704
+ typeflag: 156,
705
+ prefix: [345, 155],
706
+ };
707
+ async function untarInto(tarBytes, destDir) {
708
+ let offset = 0;
709
+ let pendingPath;
710
+ while (offset + BLOCK_SIZE <= tarBytes.length) {
711
+ const header = tarBytes.subarray(offset, offset + BLOCK_SIZE);
712
+ if (isZeroBlock(header)) break;
713
+ verifyChecksum(header);
714
+ const size = readNumeric(header, ...OFFSETS.size);
715
+ const dataStart = offset + BLOCK_SIZE;
716
+ if (dataStart + size > tarBytes.length) {
717
+ throw new Error("Truncated tar archive");
718
+ }
719
+ const data = tarBytes.subarray(dataStart, dataStart + size);
720
+ offset = dataStart + Math.ceil(size / BLOCK_SIZE) * BLOCK_SIZE;
721
+ const typeflag = String.fromCharCode(header[OFFSETS.typeflag] ?? 0);
722
+ if (typeflag === "x") {
723
+ pendingPath = parsePaxPath(data) ?? pendingPath;
724
+ continue;
725
+ }
726
+ if (typeflag === "L") {
727
+ pendingPath = decodeToNul(data);
728
+ continue;
729
+ }
730
+ if (typeflag === "1" || typeflag === "2") {
731
+ throw new Error(
732
+ `Tar entry "${decodeToNul(header.subarray(...spanOf(OFFSETS.name)))}" is a link; links are not allowed in npm tarballs`,
733
+ );
734
+ }
735
+ if (typeflag !== "0" && typeflag !== "\x00" && typeflag !== "5") {
736
+ pendingPath = undefined;
737
+ continue;
738
+ }
739
+ const entryPath = pendingPath ?? ustarPath(header);
740
+ pendingPath = undefined;
741
+ const segments = sanitizedSegments(entryPath).slice(1);
742
+ if (!segments.length) continue;
743
+ const target = path3.join(destDir, ...segments);
744
+ if (typeflag === "5") {
745
+ await fs3.mkdir(target, { recursive: true });
746
+ continue;
747
+ }
748
+ await fs3.mkdir(path3.dirname(target), { recursive: true });
749
+ const mode = readNumeric(header, ...OFFSETS.mode);
750
+ await fs3.writeFile(target, data, {
751
+ mode: mode & 73 ? 493 : 420,
752
+ });
753
+ }
754
+ }
755
+ function spanOf(field) {
756
+ return [field[0], field[0] + field[1]];
757
+ }
758
+ function isZeroBlock(block) {
759
+ return block.every((byte) => byte === 0);
760
+ }
761
+ function verifyChecksum(header) {
762
+ const stored = readNumeric(header, ...OFFSETS.checksum);
763
+ const [checksumStart, checksumEnd] = spanOf(OFFSETS.checksum);
764
+ let computed = 0;
765
+ for (let index = 0; index < BLOCK_SIZE; index++) {
766
+ computed +=
767
+ index >= checksumStart && index < checksumEnd ? 32 : header[index];
768
+ }
769
+ if (computed !== stored) {
770
+ throw new Error("Tar header checksum mismatch — the archive is corrupted");
771
+ }
772
+ }
773
+ function readNumeric(header, start, length) {
774
+ const first = header[start];
775
+ if (first & 128) {
776
+ let value = first & 127;
777
+ for (let index = start + 1; index < start + length; index++) {
778
+ value = value * 256 + header[index];
779
+ }
780
+ return value;
781
+ }
782
+ const text = decodeToNul(header.subarray(start, start + length)).trim();
783
+ return text ? Number.parseInt(text, 8) : 0;
784
+ }
785
+ function decodeToNul(bytes) {
786
+ const nul = bytes.indexOf(0);
787
+ return new TextDecoder().decode(nul < 0 ? bytes : bytes.subarray(0, nul));
788
+ }
789
+ function ustarPath(header) {
790
+ const name = decodeToNul(header.subarray(...spanOf(OFFSETS.name)));
791
+ const prefix = decodeToNul(header.subarray(...spanOf(OFFSETS.prefix)));
792
+ return prefix ? `${prefix}/${name}` : name;
793
+ }
794
+ function parsePaxPath(data) {
795
+ const text = Buffer.from(data).toString("latin1");
796
+ let cursor = 0;
797
+ let result;
798
+ while (cursor < text.length) {
799
+ const lengthEnd = text.indexOf(" ", cursor);
800
+ if (lengthEnd < 0) break;
801
+ const recordLength = Number(text.slice(cursor, lengthEnd));
802
+ if (!Number.isInteger(recordLength) || recordLength <= 0) break;
803
+ const recordEnd = cursor + recordLength;
804
+ const equals = text.indexOf("=", lengthEnd + 1);
805
+ if (equals > 0 && equals < recordEnd) {
806
+ const key = text.slice(lengthEnd + 1, equals);
807
+ if (key === "path") {
808
+ const value = text.slice(equals + 1, recordEnd - 1);
809
+ result = Buffer.from(value, "latin1").toString("utf8");
810
+ }
811
+ }
812
+ cursor = recordEnd;
813
+ }
814
+ return result;
815
+ }
816
+ function sanitizedSegments(entryPath) {
817
+ if (entryPath.startsWith("/") || /^[A-Za-z]:/.test(entryPath)) {
818
+ throw new Error(`Tar entry "${entryPath}" has an absolute path`);
819
+ }
820
+ const segments = entryPath
821
+ .split("/")
822
+ .filter((segment) => segment !== "" && segment !== ".");
823
+ for (const segment of segments) {
824
+ if (segment === ".." || segment.includes("\\") || segment.includes(":")) {
825
+ throw new Error(`Tar entry "${entryPath}" has an unsafe path`);
826
+ }
827
+ }
828
+ return segments;
829
+ }
830
+
831
+ // cursor/src/standalone/installCursorSdk.ts
832
+ var logger2 = Logger2.get(
833
+ "packages/typescript/cursor/src/standalone/installCursorSdk.ts",
834
+ );
835
+ var MARKER_FILENAME = ".alumnium-complete";
836
+ var STALE_PARTIAL_AGE_MS = 24 * 60 * 60 * 1000;
837
+ var loadPromise;
838
+ function loadVendoredCursorSdk() {
839
+ loadPromise ??= loadVendoredCursorSdkInternal().catch((error) => {
840
+ loadPromise = undefined;
841
+ throw error;
842
+ });
843
+ return loadPromise;
844
+ }
845
+ async function loadVendoredCursorSdkInternal() {
846
+ const manifest = cursorSdkVendorManifest;
847
+ const explicitDir = Env.ALUMNIUM_CURSOR_SDK_DIR;
848
+ let vendorRoot;
849
+ if (explicitDir) {
850
+ vendorRoot = path4.resolve(explicitDir);
851
+ await assertExplicitVendorDir(vendorRoot, manifest);
852
+ } else {
853
+ vendorRoot = path4.join(
854
+ os2.homedir(),
855
+ ".alumnium",
856
+ "vendor",
857
+ "cursor-sdk",
858
+ manifest.sdkVersion,
859
+ );
860
+ await ensureVendorTree(manifest, vendorRoot);
861
+ }
862
+ return loadSdkFromVendorRoot(manifest, vendorRoot);
863
+ }
864
+ async function ensureVendorTree(manifest, vendorRoot) {
865
+ const markerPath = path4.join(vendorRoot, MARKER_FILENAME);
866
+ if (await pathExists(markerPath)) return;
867
+ await fs4.rm(vendorRoot, { recursive: true, force: true });
868
+ const packages = packagesForPlatform(manifest);
869
+ logger2.info(
870
+ `Downloading the Cursor SDK (~24 MB, one time) from registry.npmjs.org into ${vendorRoot}`,
871
+ );
872
+ const partialDir = `${vendorRoot}.partial-${process.pid}-${crypto.randomUUID().slice(0, 8)}`;
873
+ try {
874
+ for (const pkg of packages) {
875
+ try {
876
+ await retry({ maxAttempts: 3, backOff: 500 }, () =>
877
+ downloadAndExtract(pkg, partialDir),
878
+ );
879
+ } catch (error) {
880
+ throw new Error(
881
+ `Failed to download Cursor SDK package ${pkg.name}@${pkg.version} from registry.npmjs.org: ` +
882
+ `${error instanceof Error ? error.message : String(error)}. ` +
883
+ "The Cursor provider performs a one-time ~24 MB download on first use. " +
884
+ "Check network/proxy settings (HTTPS_PROXY is honored), or point " +
885
+ "ALUMNIUM_CURSOR_SDK_DIR at a pre-installed node_modules tree.",
886
+ { cause: error },
887
+ );
888
+ }
889
+ }
890
+ await fs4.writeFile(
891
+ path4.join(partialDir, MARKER_FILENAME),
892
+ JSON.stringify(
893
+ {
894
+ sdkVersion: manifest.sdkVersion,
895
+ installedAt: new Date().toISOString(),
896
+ platform: `${process.platform}-${process.arch}`,
897
+ },
898
+ null,
899
+ 2,
900
+ ),
901
+ );
902
+ await promoteToVendorRoot(partialDir, markerPath, vendorRoot);
903
+ } finally {
904
+ await fs4.rm(partialDir, { recursive: true, force: true }).catch(() => {});
905
+ await sweepStalePartials(vendorRoot);
906
+ }
907
+ }
908
+ function packagesForPlatform(
909
+ manifest,
910
+ platform = process.platform,
911
+ arch = process.arch,
912
+ ) {
913
+ const [universal, platformSpecific] = manifest.packages.reduce(
914
+ ([plain, restricted], pkg) => {
915
+ (pkg.os || pkg.cpu ? restricted : plain).push(pkg);
916
+ return [plain, restricted];
917
+ },
918
+ [[], []],
919
+ );
920
+ const ripgrep =
921
+ platformSpecific.find((pkg) => pkg.os === platform && pkg.cpu === arch) ??
922
+ (platform === "win32"
923
+ ? platformSpecific.find((pkg) => pkg.os === "win32" && pkg.cpu === "x64")
924
+ : undefined);
925
+ if (!ripgrep) {
926
+ logger2.warn(
927
+ `No Cursor ripgrep package for ${platform}-${arch}; Cursor agent file-search tools may be unavailable.`,
928
+ );
929
+ return universal;
930
+ }
931
+ return [...universal, ripgrep];
932
+ }
933
+ async function downloadAndExtract(pkg, partialDir) {
934
+ const basename = pkg.name.split("/").pop();
935
+ const url = `https://registry.npmjs.org/${pkg.name}/-/${basename}-${pkg.version}.tgz`;
936
+ const response = await fetch(url);
937
+ if (!response.ok) {
938
+ throw new Error(`HTTP ${response.status} fetching ${url}`);
939
+ }
940
+ const tgzBytes = new Uint8Array(await response.arrayBuffer());
941
+ const digest = createHash("sha512").update(tgzBytes).digest("base64");
942
+ const expected = pkg.integrity.slice("sha512-".length);
943
+ if (digest !== expected) {
944
+ throw new Error(
945
+ `Integrity check failed for ${pkg.name}@${pkg.version} (expected sha512-${expected}, got sha512-${digest}) — ` +
946
+ "the download may be corrupted or tampered with; report at " +
947
+ "https://github.com/alumnium-hq/alumnium/issues if it persists",
948
+ );
949
+ }
950
+ await untarInto(
951
+ gunzipSync(tgzBytes),
952
+ path4.join(partialDir, "node_modules", pkg.name),
953
+ );
954
+ }
955
+ async function promoteToVendorRoot(partialDir, markerPath, vendorRoot) {
956
+ for (let attempt = 1; ; attempt++) {
957
+ try {
958
+ await fs4.rename(partialDir, vendorRoot);
959
+ return;
960
+ } catch (error) {
961
+ if (await pathExists(markerPath)) return;
962
+ if (attempt >= 3) throw error;
963
+ await new Promise((resolve) => setTimeout(resolve, 200 * attempt));
964
+ }
965
+ }
966
+ }
967
+ async function sweepStalePartials(vendorRoot) {
968
+ try {
969
+ const parentDir = path4.dirname(vendorRoot);
970
+ const prefix = `${path4.basename(vendorRoot)}.partial-`;
971
+ for (const entry of await fs4.readdir(parentDir)) {
972
+ if (!entry.startsWith(prefix)) continue;
973
+ const entryPath = path4.join(parentDir, entry);
974
+ const { mtimeMs } = await fs4.stat(entryPath);
975
+ if (Date.now() - mtimeMs > STALE_PARTIAL_AGE_MS) {
976
+ await fs4.rm(entryPath, { recursive: true, force: true });
977
+ }
978
+ }
979
+ } catch {}
980
+ }
981
+ async function assertExplicitVendorDir(vendorRoot, manifest) {
982
+ const manifestPath = path4.join(
983
+ vendorRoot,
984
+ "node_modules",
985
+ CURSOR_SDK_PACKAGE_NAME,
986
+ "package.json",
987
+ );
988
+ let installedVersion;
989
+ try {
990
+ installedVersion = JSON.parse(
991
+ await fs4.readFile(manifestPath, "utf-8"),
992
+ ).version;
993
+ } catch (error) {
994
+ throw new Error(
995
+ `ALUMNIUM_CURSOR_SDK_DIR is set to ${vendorRoot} but ${manifestPath} cannot be read`,
996
+ { cause: error },
997
+ );
998
+ }
999
+ if (installedVersion !== manifest.sdkVersion) {
1000
+ logger2.warn(
1001
+ `ALUMNIUM_CURSOR_SDK_DIR holds @cursor/sdk@${installedVersion}, but this Alumnium build expects ${manifest.sdkVersion}`,
1002
+ );
1003
+ }
1004
+ }
1005
+ async function loadSdkFromVendorRoot(manifest, vendorRoot) {
1006
+ const vendorNodeModules = path4.join(vendorRoot, "node_modules");
1007
+ installVendorResolveHook(
1008
+ vendorRoot,
1009
+ new Set(manifest.packages.map((pkg) => pkg.name)),
1010
+ );
1011
+ const ripgrep = packagesForPlatform(manifest).find((pkg) => pkg.bin);
1012
+ const ripgrepRelPath =
1013
+ ripgrep?.bin?.rg ?? Object.values(ripgrep?.bin ?? {})[0];
1014
+ if (ripgrep && ripgrepRelPath) {
1015
+ const ripgrepPath = path4.join(
1016
+ vendorNodeModules,
1017
+ ripgrep.name,
1018
+ ripgrepRelPath,
1019
+ );
1020
+ if (await pathExists(ripgrepPath)) {
1021
+ if (process.platform !== "win32") await fs4.chmod(ripgrepPath, 493);
1022
+ process.env.CURSOR_RIPGREP_PATH ??= ripgrepPath;
1023
+ }
1024
+ }
1025
+ const entryPath = resolvePackageEntry(
1026
+ vendorNodeModules,
1027
+ CURSOR_SDK_PACKAGE_NAME,
1028
+ ".",
1029
+ );
1030
+ if (!entryPath) {
1031
+ throw new Error(
1032
+ `Vendored Cursor SDK at ${vendorRoot} is missing or unreadable; delete the directory to reinstall`,
1033
+ );
1034
+ }
1035
+ const requireFromVendor = createRequire(
1036
+ path4.join(vendorNodeModules, CURSOR_SDK_PACKAGE_NAME, "package.json"),
1037
+ );
1038
+ return requireFromVendor(entryPath);
1039
+ }
1040
+ async function pathExists(target) {
1041
+ try {
1042
+ await fs4.access(target);
1043
+ return true;
1044
+ } catch {
1045
+ return false;
1046
+ }
1047
+ }
1048
+
1049
+ // cursor/src/llm/cursorProviders.ts
1050
+ var logger3 = Logger3.get(
1051
+ "packages/typescript/cursor/src/llm/cursorProviders.ts",
1052
+ );
1053
+ var cursorProviders = {
1054
+ cursor: (model) => {
1055
+ logger3.debug(`Creating Cursor LLM with model ${model.name}`);
1056
+ const apiKey = Env2.CURSOR_API_KEY;
1057
+ if (apiKey) logger3.debug(`Cursor API Key is set: ${maskString(apiKey)}`);
1058
+ return new CursorLanguageModel({
1059
+ modelId: model.name,
1060
+ ...(apiKey ? { apiKey } : {}),
1061
+ ...(isSingleFileExecutable() ? { sdkLoader: loadVendoredCursorSdk } : {}),
1062
+ });
1063
+ },
1064
+ };
1065
+ LlmFactory.register(cursorProviders);
1066
+ export { CursorLanguageModel, cursorProviders };
1067
+
1068
+ //# debugId=DB1C28E1D421279564756E2164756E21
1069
+ //# sourceMappingURL=index.js.map