cursor-supermemory 1.0.0
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/.cursor-plugin/plugin.json +14 -0
- package/.mcp.json +8 -0
- package/README.md +40 -0
- package/commands/supermemory-config.md +21 -0
- package/commands/supermemory-logout.md +12 -0
- package/commands/supermemory-setup.md +14 -0
- package/dist/cli.js +1767 -0
- package/dist/mcp-server.js +1654 -0
- package/dist/session-end.js +1447 -0
- package/dist/session-start.js +1479 -0
- package/hooks/hooks.json +18 -0
- package/package.json +28 -0
- package/rules/supermemory.mdc +21 -0
- package/skills/memory-init/SKILL.md +13 -0
- package/skills/memory-save/SKILL.md +10 -0
- package/skills/memory-search/SKILL.md +9 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1767 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import path2 from "node:path";
|
|
3
|
+
import os2 from "node:os";
|
|
4
|
+
import fs2 from "node:fs";
|
|
5
|
+
|
|
6
|
+
// src/auth.ts
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
var CREDENTIALS_DIR = path.join(os.homedir(), ".supermemory-cursor");
|
|
11
|
+
var CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, "credentials.json");
|
|
12
|
+
var AUTH_PORT = 19878;
|
|
13
|
+
var AUTH_URL = "https://console.supermemory.ai/auth/connect";
|
|
14
|
+
var SUCCESS_HTML = `<!DOCTYPE html>
|
|
15
|
+
<html><head><style>
|
|
16
|
+
body { background: #111; color: #fff; font-family: system-ui; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
|
17
|
+
h1 { font-size: 2rem; }
|
|
18
|
+
</style></head><body><h1>Connected to Cursor!</h1></body></html>`;
|
|
19
|
+
function loadCredentials() {
|
|
20
|
+
try {
|
|
21
|
+
if (!fs.existsSync(CREDENTIALS_FILE))
|
|
22
|
+
return null;
|
|
23
|
+
const data = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, "utf-8"));
|
|
24
|
+
if (data.apiKey)
|
|
25
|
+
return data;
|
|
26
|
+
return null;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function saveCredentials(apiKey) {
|
|
32
|
+
fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 448 });
|
|
33
|
+
const data = { apiKey, createdAt: new Date().toISOString() };
|
|
34
|
+
fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
35
|
+
}
|
|
36
|
+
function clearCredentials() {
|
|
37
|
+
try {
|
|
38
|
+
if (fs.existsSync(CREDENTIALS_FILE)) {
|
|
39
|
+
fs.unlinkSync(CREDENTIALS_FILE);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function startAuthFlow(timeoutMs = 120000) {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
let settled = false;
|
|
50
|
+
const server = Bun.serve({
|
|
51
|
+
port: AUTH_PORT,
|
|
52
|
+
hostname: "127.0.0.1",
|
|
53
|
+
fetch(req) {
|
|
54
|
+
const url = new URL(req.url);
|
|
55
|
+
if (url.pathname !== "/callback") {
|
|
56
|
+
return new Response("Not found", { status: 404 });
|
|
57
|
+
}
|
|
58
|
+
const apiKey = url.searchParams.get("apikey") || url.searchParams.get("api_key");
|
|
59
|
+
if (!apiKey?.startsWith("sm_")) {
|
|
60
|
+
return new Response("Invalid API key", { status: 400 });
|
|
61
|
+
}
|
|
62
|
+
saveCredentials(apiKey);
|
|
63
|
+
settled = true;
|
|
64
|
+
server.stop();
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
resolve({ success: true, apiKey });
|
|
67
|
+
return new Response(SUCCESS_HTML, {
|
|
68
|
+
headers: { "Content-Type": "text/html" }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const callbackUrl = `http://localhost:${AUTH_PORT}/callback`;
|
|
73
|
+
const authUrl = `${AUTH_URL}?callback=${encodeURIComponent(callbackUrl)}&client=cursor`;
|
|
74
|
+
process.stderr.write(`
|
|
75
|
+
Open this URL to connect Supermemory to Cursor:
|
|
76
|
+
|
|
77
|
+
${authUrl}
|
|
78
|
+
|
|
79
|
+
Waiting...
|
|
80
|
+
`);
|
|
81
|
+
const opener = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
82
|
+
Bun.$`${opener} ${authUrl}`.quiet().nothrow();
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
if (!settled) {
|
|
85
|
+
server.stop();
|
|
86
|
+
resolve({ success: false, error: "Authentication timed out" });
|
|
87
|
+
}
|
|
88
|
+
}, timeoutMs);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/config.ts
|
|
93
|
+
var DEFAULTS = {
|
|
94
|
+
similarityThreshold: 0.3,
|
|
95
|
+
maxMemories: 10,
|
|
96
|
+
maxProjectMemories: 5,
|
|
97
|
+
injectProfile: true,
|
|
98
|
+
userContainerTag: null,
|
|
99
|
+
projectContainerTag: null
|
|
100
|
+
};
|
|
101
|
+
function readJson(filePath) {
|
|
102
|
+
try {
|
|
103
|
+
if (!fs2.existsSync(filePath))
|
|
104
|
+
return null;
|
|
105
|
+
return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function findProjectConfig(cwd) {
|
|
111
|
+
let dir = cwd;
|
|
112
|
+
while (true) {
|
|
113
|
+
const configPath = path2.join(dir, ".cursor", ".supermemory", "config.json");
|
|
114
|
+
const data = readJson(configPath);
|
|
115
|
+
if (data)
|
|
116
|
+
return data;
|
|
117
|
+
const parent = path2.dirname(dir);
|
|
118
|
+
if (parent === dir)
|
|
119
|
+
break;
|
|
120
|
+
dir = parent;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function loadConfig(cwd) {
|
|
125
|
+
const projectConfig = findProjectConfig(cwd || process.cwd());
|
|
126
|
+
const globalConfig = readJson(path2.join(os2.homedir(), ".config", "cursor", "supermemory.json"));
|
|
127
|
+
const merged = { ...DEFAULTS, ...globalConfig, ...projectConfig };
|
|
128
|
+
return {
|
|
129
|
+
apiKey: process.env.SUPERMEMORY_API_KEY ?? merged.apiKey ?? null,
|
|
130
|
+
similarityThreshold: merged.similarityThreshold,
|
|
131
|
+
maxMemories: merged.maxMemories,
|
|
132
|
+
maxProjectMemories: merged.maxProjectMemories,
|
|
133
|
+
injectProfile: merged.injectProfile,
|
|
134
|
+
userContainerTag: merged.userContainerTag,
|
|
135
|
+
projectContainerTag: merged.projectContainerTag
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function getApiKey(config) {
|
|
139
|
+
if (config.apiKey)
|
|
140
|
+
return config.apiKey;
|
|
141
|
+
const creds = loadCredentials();
|
|
142
|
+
return creds?.apiKey ?? null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/tags.ts
|
|
146
|
+
import crypto from "node:crypto";
|
|
147
|
+
import os3 from "node:os";
|
|
148
|
+
import { execSync } from "node:child_process";
|
|
149
|
+
function sha256(input) {
|
|
150
|
+
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 16);
|
|
151
|
+
}
|
|
152
|
+
function getGitEmail() {
|
|
153
|
+
try {
|
|
154
|
+
return execSync("git config user.email", {
|
|
155
|
+
encoding: "utf-8",
|
|
156
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
157
|
+
}).trim() || null;
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function getGitRoot(dir) {
|
|
163
|
+
try {
|
|
164
|
+
return execSync("git rev-parse --show-toplevel", {
|
|
165
|
+
cwd: dir,
|
|
166
|
+
encoding: "utf-8",
|
|
167
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
168
|
+
}).trim() || null;
|
|
169
|
+
} catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function getMachineId() {
|
|
174
|
+
return `${os3.hostname()}_${os3.userInfo().username}`;
|
|
175
|
+
}
|
|
176
|
+
function getUserTag(config) {
|
|
177
|
+
const identity = config.userContainerTag ?? process.env.SUPERMEMORY_USER_TAG ?? process.env.CURSOR_USER_EMAIL ?? getGitEmail() ?? getMachineId();
|
|
178
|
+
return `cursor_user_${sha256(identity)}`;
|
|
179
|
+
}
|
|
180
|
+
function getProjectTag(workspaceRoot, config) {
|
|
181
|
+
const identity = config.projectContainerTag ?? process.env.SUPERMEMORY_PROJECT_TAG ?? (getGitRoot(workspaceRoot) || workspaceRoot);
|
|
182
|
+
return `cursor_project_${sha256(identity)}`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// node_modules/supermemory/internal/tslib.mjs
|
|
186
|
+
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
187
|
+
if (kind === "m")
|
|
188
|
+
throw new TypeError("Private method is not writable");
|
|
189
|
+
if (kind === "a" && !f)
|
|
190
|
+
throw new TypeError("Private accessor was defined without a setter");
|
|
191
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
192
|
+
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
193
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
194
|
+
}
|
|
195
|
+
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
196
|
+
if (kind === "a" && !f)
|
|
197
|
+
throw new TypeError("Private accessor was defined without a getter");
|
|
198
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
199
|
+
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
200
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// node_modules/supermemory/internal/utils/uuid.mjs
|
|
204
|
+
var uuid4 = function() {
|
|
205
|
+
const { crypto: crypto2 } = globalThis;
|
|
206
|
+
if (crypto2?.randomUUID) {
|
|
207
|
+
uuid4 = crypto2.randomUUID.bind(crypto2);
|
|
208
|
+
return crypto2.randomUUID();
|
|
209
|
+
}
|
|
210
|
+
const u8 = new Uint8Array(1);
|
|
211
|
+
const randomByte = crypto2 ? () => crypto2.getRandomValues(u8)[0] : () => Math.random() * 255 & 255;
|
|
212
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => (+c ^ randomByte() & 15 >> +c / 4).toString(16));
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// node_modules/supermemory/internal/errors.mjs
|
|
216
|
+
function isAbortError(err) {
|
|
217
|
+
return typeof err === "object" && err !== null && (("name" in err) && err.name === "AbortError" || ("message" in err) && String(err.message).includes("FetchRequestCanceledException"));
|
|
218
|
+
}
|
|
219
|
+
var castToError = (err) => {
|
|
220
|
+
if (err instanceof Error)
|
|
221
|
+
return err;
|
|
222
|
+
if (typeof err === "object" && err !== null) {
|
|
223
|
+
try {
|
|
224
|
+
if (Object.prototype.toString.call(err) === "[object Error]") {
|
|
225
|
+
const error = new Error(err.message, err.cause ? { cause: err.cause } : {});
|
|
226
|
+
if (err.stack)
|
|
227
|
+
error.stack = err.stack;
|
|
228
|
+
if (err.cause && !error.cause)
|
|
229
|
+
error.cause = err.cause;
|
|
230
|
+
if (err.name)
|
|
231
|
+
error.name = err.name;
|
|
232
|
+
return error;
|
|
233
|
+
}
|
|
234
|
+
} catch {}
|
|
235
|
+
try {
|
|
236
|
+
return new Error(JSON.stringify(err));
|
|
237
|
+
} catch {}
|
|
238
|
+
}
|
|
239
|
+
return new Error(err);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// node_modules/supermemory/core/error.mjs
|
|
243
|
+
class SupermemoryError extends Error {
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
class APIError extends SupermemoryError {
|
|
247
|
+
constructor(status, error, message, headers) {
|
|
248
|
+
super(`${APIError.makeMessage(status, error, message)}`);
|
|
249
|
+
this.status = status;
|
|
250
|
+
this.headers = headers;
|
|
251
|
+
this.error = error;
|
|
252
|
+
}
|
|
253
|
+
static makeMessage(status, error, message) {
|
|
254
|
+
const msg = error?.message ? typeof error.message === "string" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;
|
|
255
|
+
if (status && msg) {
|
|
256
|
+
return `${status} ${msg}`;
|
|
257
|
+
}
|
|
258
|
+
if (status) {
|
|
259
|
+
return `${status} status code (no body)`;
|
|
260
|
+
}
|
|
261
|
+
if (msg) {
|
|
262
|
+
return msg;
|
|
263
|
+
}
|
|
264
|
+
return "(no status code or body)";
|
|
265
|
+
}
|
|
266
|
+
static generate(status, errorResponse, message, headers) {
|
|
267
|
+
if (!status || !headers) {
|
|
268
|
+
return new APIConnectionError({ message, cause: castToError(errorResponse) });
|
|
269
|
+
}
|
|
270
|
+
const error = errorResponse;
|
|
271
|
+
if (status === 400) {
|
|
272
|
+
return new BadRequestError(status, error, message, headers);
|
|
273
|
+
}
|
|
274
|
+
if (status === 401) {
|
|
275
|
+
return new AuthenticationError(status, error, message, headers);
|
|
276
|
+
}
|
|
277
|
+
if (status === 403) {
|
|
278
|
+
return new PermissionDeniedError(status, error, message, headers);
|
|
279
|
+
}
|
|
280
|
+
if (status === 404) {
|
|
281
|
+
return new NotFoundError(status, error, message, headers);
|
|
282
|
+
}
|
|
283
|
+
if (status === 409) {
|
|
284
|
+
return new ConflictError(status, error, message, headers);
|
|
285
|
+
}
|
|
286
|
+
if (status === 422) {
|
|
287
|
+
return new UnprocessableEntityError(status, error, message, headers);
|
|
288
|
+
}
|
|
289
|
+
if (status === 429) {
|
|
290
|
+
return new RateLimitError(status, error, message, headers);
|
|
291
|
+
}
|
|
292
|
+
if (status >= 500) {
|
|
293
|
+
return new InternalServerError(status, error, message, headers);
|
|
294
|
+
}
|
|
295
|
+
return new APIError(status, error, message, headers);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
class APIUserAbortError extends APIError {
|
|
300
|
+
constructor({ message } = {}) {
|
|
301
|
+
super(undefined, undefined, message || "Request was aborted.", undefined);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
class APIConnectionError extends APIError {
|
|
306
|
+
constructor({ message, cause }) {
|
|
307
|
+
super(undefined, undefined, message || "Connection error.", undefined);
|
|
308
|
+
if (cause)
|
|
309
|
+
this.cause = cause;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
class APIConnectionTimeoutError extends APIConnectionError {
|
|
314
|
+
constructor({ message } = {}) {
|
|
315
|
+
super({ message: message ?? "Request timed out." });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
class BadRequestError extends APIError {
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
class AuthenticationError extends APIError {
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
class PermissionDeniedError extends APIError {
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
class NotFoundError extends APIError {
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
class ConflictError extends APIError {
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
class UnprocessableEntityError extends APIError {
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
class RateLimitError extends APIError {
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
class InternalServerError extends APIError {
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// node_modules/supermemory/internal/utils/values.mjs
|
|
344
|
+
var startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
|
|
345
|
+
var isAbsoluteURL = (url) => {
|
|
346
|
+
return startsWithSchemeRegexp.test(url);
|
|
347
|
+
};
|
|
348
|
+
var isArray = (val) => (isArray = Array.isArray, isArray(val));
|
|
349
|
+
var isReadonlyArray = isArray;
|
|
350
|
+
function isEmptyObj(obj) {
|
|
351
|
+
if (!obj)
|
|
352
|
+
return true;
|
|
353
|
+
for (const _k in obj)
|
|
354
|
+
return false;
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
function hasOwn(obj, key) {
|
|
358
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
359
|
+
}
|
|
360
|
+
var validatePositiveInteger = (name, n) => {
|
|
361
|
+
if (typeof n !== "number" || !Number.isInteger(n)) {
|
|
362
|
+
throw new SupermemoryError(`${name} must be an integer`);
|
|
363
|
+
}
|
|
364
|
+
if (n < 0) {
|
|
365
|
+
throw new SupermemoryError(`${name} must be a positive integer`);
|
|
366
|
+
}
|
|
367
|
+
return n;
|
|
368
|
+
};
|
|
369
|
+
var safeJSON = (text) => {
|
|
370
|
+
try {
|
|
371
|
+
return JSON.parse(text);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// node_modules/supermemory/internal/utils/sleep.mjs
|
|
378
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
379
|
+
|
|
380
|
+
// node_modules/supermemory/version.mjs
|
|
381
|
+
var VERSION = "4.11.1";
|
|
382
|
+
|
|
383
|
+
// node_modules/supermemory/internal/detect-platform.mjs
|
|
384
|
+
function getDetectedPlatform() {
|
|
385
|
+
if (typeof Deno !== "undefined" && Deno.build != null) {
|
|
386
|
+
return "deno";
|
|
387
|
+
}
|
|
388
|
+
if (typeof EdgeRuntime !== "undefined") {
|
|
389
|
+
return "edge";
|
|
390
|
+
}
|
|
391
|
+
if (Object.prototype.toString.call(typeof globalThis.process !== "undefined" ? globalThis.process : 0) === "[object process]") {
|
|
392
|
+
return "node";
|
|
393
|
+
}
|
|
394
|
+
return "unknown";
|
|
395
|
+
}
|
|
396
|
+
var getPlatformProperties = () => {
|
|
397
|
+
const detectedPlatform = getDetectedPlatform();
|
|
398
|
+
if (detectedPlatform === "deno") {
|
|
399
|
+
return {
|
|
400
|
+
"X-Stainless-Lang": "js",
|
|
401
|
+
"X-Stainless-Package-Version": VERSION,
|
|
402
|
+
"X-Stainless-OS": normalizePlatform(Deno.build.os),
|
|
403
|
+
"X-Stainless-Arch": normalizeArch(Deno.build.arch),
|
|
404
|
+
"X-Stainless-Runtime": "deno",
|
|
405
|
+
"X-Stainless-Runtime-Version": typeof Deno.version === "string" ? Deno.version : Deno.version?.deno ?? "unknown"
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (typeof EdgeRuntime !== "undefined") {
|
|
409
|
+
return {
|
|
410
|
+
"X-Stainless-Lang": "js",
|
|
411
|
+
"X-Stainless-Package-Version": VERSION,
|
|
412
|
+
"X-Stainless-OS": "Unknown",
|
|
413
|
+
"X-Stainless-Arch": `other:${EdgeRuntime}`,
|
|
414
|
+
"X-Stainless-Runtime": "edge",
|
|
415
|
+
"X-Stainless-Runtime-Version": globalThis.process.version
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if (detectedPlatform === "node") {
|
|
419
|
+
return {
|
|
420
|
+
"X-Stainless-Lang": "js",
|
|
421
|
+
"X-Stainless-Package-Version": VERSION,
|
|
422
|
+
"X-Stainless-OS": normalizePlatform(globalThis.process.platform ?? "unknown"),
|
|
423
|
+
"X-Stainless-Arch": normalizeArch(globalThis.process.arch ?? "unknown"),
|
|
424
|
+
"X-Stainless-Runtime": "node",
|
|
425
|
+
"X-Stainless-Runtime-Version": globalThis.process.version ?? "unknown"
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const browserInfo = getBrowserInfo();
|
|
429
|
+
if (browserInfo) {
|
|
430
|
+
return {
|
|
431
|
+
"X-Stainless-Lang": "js",
|
|
432
|
+
"X-Stainless-Package-Version": VERSION,
|
|
433
|
+
"X-Stainless-OS": "Unknown",
|
|
434
|
+
"X-Stainless-Arch": "unknown",
|
|
435
|
+
"X-Stainless-Runtime": `browser:${browserInfo.browser}`,
|
|
436
|
+
"X-Stainless-Runtime-Version": browserInfo.version
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
return {
|
|
440
|
+
"X-Stainless-Lang": "js",
|
|
441
|
+
"X-Stainless-Package-Version": VERSION,
|
|
442
|
+
"X-Stainless-OS": "Unknown",
|
|
443
|
+
"X-Stainless-Arch": "unknown",
|
|
444
|
+
"X-Stainless-Runtime": "unknown",
|
|
445
|
+
"X-Stainless-Runtime-Version": "unknown"
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
function getBrowserInfo() {
|
|
449
|
+
if (typeof navigator === "undefined" || !navigator) {
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
const browserPatterns = [
|
|
453
|
+
{ key: "edge", pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
|
|
454
|
+
{ key: "ie", pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
|
|
455
|
+
{ key: "ie", pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
|
|
456
|
+
{ key: "chrome", pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
|
|
457
|
+
{ key: "firefox", pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
|
|
458
|
+
{ key: "safari", pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ }
|
|
459
|
+
];
|
|
460
|
+
for (const { key, pattern } of browserPatterns) {
|
|
461
|
+
const match = pattern.exec(navigator.userAgent);
|
|
462
|
+
if (match) {
|
|
463
|
+
const major = match[1] || 0;
|
|
464
|
+
const minor = match[2] || 0;
|
|
465
|
+
const patch = match[3] || 0;
|
|
466
|
+
return { browser: key, version: `${major}.${minor}.${patch}` };
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
var normalizeArch = (arch) => {
|
|
472
|
+
if (arch === "x32")
|
|
473
|
+
return "x32";
|
|
474
|
+
if (arch === "x86_64" || arch === "x64")
|
|
475
|
+
return "x64";
|
|
476
|
+
if (arch === "arm")
|
|
477
|
+
return "arm";
|
|
478
|
+
if (arch === "aarch64" || arch === "arm64")
|
|
479
|
+
return "arm64";
|
|
480
|
+
if (arch)
|
|
481
|
+
return `other:${arch}`;
|
|
482
|
+
return "unknown";
|
|
483
|
+
};
|
|
484
|
+
var normalizePlatform = (platform) => {
|
|
485
|
+
platform = platform.toLowerCase();
|
|
486
|
+
if (platform.includes("ios"))
|
|
487
|
+
return "iOS";
|
|
488
|
+
if (platform === "android")
|
|
489
|
+
return "Android";
|
|
490
|
+
if (platform === "darwin")
|
|
491
|
+
return "MacOS";
|
|
492
|
+
if (platform === "win32")
|
|
493
|
+
return "Windows";
|
|
494
|
+
if (platform === "freebsd")
|
|
495
|
+
return "FreeBSD";
|
|
496
|
+
if (platform === "openbsd")
|
|
497
|
+
return "OpenBSD";
|
|
498
|
+
if (platform === "linux")
|
|
499
|
+
return "Linux";
|
|
500
|
+
if (platform)
|
|
501
|
+
return `Other:${platform}`;
|
|
502
|
+
return "Unknown";
|
|
503
|
+
};
|
|
504
|
+
var _platformHeaders;
|
|
505
|
+
var getPlatformHeaders = () => {
|
|
506
|
+
return _platformHeaders ?? (_platformHeaders = getPlatformProperties());
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// node_modules/supermemory/internal/shims.mjs
|
|
510
|
+
function getDefaultFetch() {
|
|
511
|
+
if (typeof fetch !== "undefined") {
|
|
512
|
+
return fetch;
|
|
513
|
+
}
|
|
514
|
+
throw new Error("`fetch` is not defined as a global; Either pass `fetch` to the client, `new Supermemory({ fetch })` or polyfill the global, `globalThis.fetch = fetch`");
|
|
515
|
+
}
|
|
516
|
+
function makeReadableStream(...args) {
|
|
517
|
+
const ReadableStream = globalThis.ReadableStream;
|
|
518
|
+
if (typeof ReadableStream === "undefined") {
|
|
519
|
+
throw new Error("`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`");
|
|
520
|
+
}
|
|
521
|
+
return new ReadableStream(...args);
|
|
522
|
+
}
|
|
523
|
+
function ReadableStreamFrom(iterable) {
|
|
524
|
+
let iter = Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
|
525
|
+
return makeReadableStream({
|
|
526
|
+
async pull(controller) {
|
|
527
|
+
const { done, value } = await iter.next();
|
|
528
|
+
if (done) {
|
|
529
|
+
controller.close();
|
|
530
|
+
} else {
|
|
531
|
+
controller.enqueue(value);
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
async cancel() {
|
|
535
|
+
await iter.return?.();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
async function CancelReadableStream(stream) {
|
|
540
|
+
if (stream === null || typeof stream !== "object")
|
|
541
|
+
return;
|
|
542
|
+
if (stream[Symbol.asyncIterator]) {
|
|
543
|
+
await stream[Symbol.asyncIterator]().return?.();
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const reader = stream.getReader();
|
|
547
|
+
const cancelPromise = reader.cancel();
|
|
548
|
+
reader.releaseLock();
|
|
549
|
+
await cancelPromise;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// node_modules/supermemory/internal/request-options.mjs
|
|
553
|
+
var FallbackEncoder = ({ headers, body }) => {
|
|
554
|
+
return {
|
|
555
|
+
bodyHeaders: {
|
|
556
|
+
"content-type": "application/json"
|
|
557
|
+
},
|
|
558
|
+
body: JSON.stringify(body)
|
|
559
|
+
};
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
// node_modules/supermemory/internal/uploads.mjs
|
|
563
|
+
var checkFileSupport = () => {
|
|
564
|
+
if (typeof File === "undefined") {
|
|
565
|
+
const { process: process2 } = globalThis;
|
|
566
|
+
const isOldNode = typeof process2?.versions?.node === "string" && parseInt(process2.versions.node.split(".")) < 20;
|
|
567
|
+
throw new Error("`File` is not defined as a global, which is required for file uploads." + (isOldNode ? " Update to Node 20 LTS or newer, or set `globalThis.File` to `import('node:buffer').File`." : ""));
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
function makeFile(fileBits, fileName, options) {
|
|
571
|
+
checkFileSupport();
|
|
572
|
+
return new File(fileBits, fileName ?? "unknown_file", options);
|
|
573
|
+
}
|
|
574
|
+
function getName(value) {
|
|
575
|
+
return (typeof value === "object" && value !== null && (("name" in value) && value.name && String(value.name) || ("url" in value) && value.url && String(value.url) || ("filename" in value) && value.filename && String(value.filename) || ("path" in value) && value.path && String(value.path)) || "").split(/[\\/]/).pop() || undefined;
|
|
576
|
+
}
|
|
577
|
+
var isAsyncIterable = (value) => value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
578
|
+
var multipartFormRequestOptions = async (opts, fetch2) => {
|
|
579
|
+
return { ...opts, body: await createForm(opts.body, fetch2) };
|
|
580
|
+
};
|
|
581
|
+
var supportsFormDataMap = /* @__PURE__ */ new WeakMap;
|
|
582
|
+
function supportsFormData(fetchObject) {
|
|
583
|
+
const fetch2 = typeof fetchObject === "function" ? fetchObject : fetchObject.fetch;
|
|
584
|
+
const cached = supportsFormDataMap.get(fetch2);
|
|
585
|
+
if (cached)
|
|
586
|
+
return cached;
|
|
587
|
+
const promise = (async () => {
|
|
588
|
+
try {
|
|
589
|
+
const FetchResponse = "Response" in fetch2 ? fetch2.Response : (await fetch2("data:,")).constructor;
|
|
590
|
+
const data = new FormData;
|
|
591
|
+
if (data.toString() === await new FetchResponse(data).text()) {
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
return true;
|
|
595
|
+
} catch {
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
})();
|
|
599
|
+
supportsFormDataMap.set(fetch2, promise);
|
|
600
|
+
return promise;
|
|
601
|
+
}
|
|
602
|
+
var createForm = async (body, fetch2) => {
|
|
603
|
+
if (!await supportsFormData(fetch2)) {
|
|
604
|
+
throw new TypeError("The provided fetch function does not support file uploads with the current global FormData class.");
|
|
605
|
+
}
|
|
606
|
+
const form = new FormData;
|
|
607
|
+
await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value)));
|
|
608
|
+
return form;
|
|
609
|
+
};
|
|
610
|
+
var isNamedBlob = (value) => value instanceof Blob && ("name" in value);
|
|
611
|
+
var addFormValue = async (form, key, value) => {
|
|
612
|
+
if (value === undefined)
|
|
613
|
+
return;
|
|
614
|
+
if (value == null) {
|
|
615
|
+
throw new TypeError(`Received null for "${key}"; to pass null in FormData, you must use the string 'null'`);
|
|
616
|
+
}
|
|
617
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
618
|
+
form.append(key, String(value));
|
|
619
|
+
} else if (value instanceof Response) {
|
|
620
|
+
form.append(key, makeFile([await value.blob()], getName(value)));
|
|
621
|
+
} else if (isAsyncIterable(value)) {
|
|
622
|
+
form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value)));
|
|
623
|
+
} else if (isNamedBlob(value)) {
|
|
624
|
+
form.append(key, value, getName(value));
|
|
625
|
+
} else if (Array.isArray(value)) {
|
|
626
|
+
await Promise.all(value.map((entry) => addFormValue(form, key + "[]", entry)));
|
|
627
|
+
} else if (typeof value === "object") {
|
|
628
|
+
await Promise.all(Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)));
|
|
629
|
+
} else {
|
|
630
|
+
throw new TypeError(`Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`);
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// node_modules/supermemory/internal/to-file.mjs
|
|
635
|
+
var isBlobLike = (value) => value != null && typeof value === "object" && typeof value.size === "number" && typeof value.type === "string" && typeof value.text === "function" && typeof value.slice === "function" && typeof value.arrayBuffer === "function";
|
|
636
|
+
var isFileLike = (value) => value != null && typeof value === "object" && typeof value.name === "string" && typeof value.lastModified === "number" && isBlobLike(value);
|
|
637
|
+
var isResponseLike = (value) => value != null && typeof value === "object" && typeof value.url === "string" && typeof value.blob === "function";
|
|
638
|
+
async function toFile(value, name, options) {
|
|
639
|
+
checkFileSupport();
|
|
640
|
+
value = await value;
|
|
641
|
+
if (isFileLike(value)) {
|
|
642
|
+
if (value instanceof File) {
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
return makeFile([await value.arrayBuffer()], value.name);
|
|
646
|
+
}
|
|
647
|
+
if (isResponseLike(value)) {
|
|
648
|
+
const blob = await value.blob();
|
|
649
|
+
name || (name = new URL(value.url).pathname.split(/[\\/]/).pop());
|
|
650
|
+
return makeFile(await getBytes(blob), name, options);
|
|
651
|
+
}
|
|
652
|
+
const parts = await getBytes(value);
|
|
653
|
+
name || (name = getName(value));
|
|
654
|
+
if (!options?.type) {
|
|
655
|
+
const type = parts.find((part) => typeof part === "object" && ("type" in part) && part.type);
|
|
656
|
+
if (typeof type === "string") {
|
|
657
|
+
options = { ...options, type };
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return makeFile(parts, name, options);
|
|
661
|
+
}
|
|
662
|
+
async function getBytes(value) {
|
|
663
|
+
let parts = [];
|
|
664
|
+
if (typeof value === "string" || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
665
|
+
parts.push(value);
|
|
666
|
+
} else if (isBlobLike(value)) {
|
|
667
|
+
parts.push(value instanceof Blob ? value : await value.arrayBuffer());
|
|
668
|
+
} else if (isAsyncIterable(value)) {
|
|
669
|
+
for await (const chunk of value) {
|
|
670
|
+
parts.push(...await getBytes(chunk));
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
const constructor = value?.constructor?.name;
|
|
674
|
+
throw new Error(`Unexpected data type: ${typeof value}${constructor ? `; constructor: ${constructor}` : ""}${propsForError(value)}`);
|
|
675
|
+
}
|
|
676
|
+
return parts;
|
|
677
|
+
}
|
|
678
|
+
function propsForError(value) {
|
|
679
|
+
if (typeof value !== "object" || value === null)
|
|
680
|
+
return "";
|
|
681
|
+
const props = Object.getOwnPropertyNames(value);
|
|
682
|
+
return `; props: [${props.map((p) => `"${p}"`).join(", ")}]`;
|
|
683
|
+
}
|
|
684
|
+
// node_modules/supermemory/core/resource.mjs
|
|
685
|
+
class APIResource {
|
|
686
|
+
constructor(client) {
|
|
687
|
+
this._client = client;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// node_modules/supermemory/internal/headers.mjs
|
|
692
|
+
var brand_privateNullableHeaders = /* @__PURE__ */ Symbol("brand.privateNullableHeaders");
|
|
693
|
+
function* iterateHeaders(headers) {
|
|
694
|
+
if (!headers)
|
|
695
|
+
return;
|
|
696
|
+
if (brand_privateNullableHeaders in headers) {
|
|
697
|
+
const { values, nulls } = headers;
|
|
698
|
+
yield* values.entries();
|
|
699
|
+
for (const name of nulls) {
|
|
700
|
+
yield [name, null];
|
|
701
|
+
}
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
let shouldClear = false;
|
|
705
|
+
let iter;
|
|
706
|
+
if (headers instanceof Headers) {
|
|
707
|
+
iter = headers.entries();
|
|
708
|
+
} else if (isReadonlyArray(headers)) {
|
|
709
|
+
iter = headers;
|
|
710
|
+
} else {
|
|
711
|
+
shouldClear = true;
|
|
712
|
+
iter = Object.entries(headers ?? {});
|
|
713
|
+
}
|
|
714
|
+
for (let row of iter) {
|
|
715
|
+
const name = row[0];
|
|
716
|
+
if (typeof name !== "string")
|
|
717
|
+
throw new TypeError("expected header name to be a string");
|
|
718
|
+
const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
|
|
719
|
+
let didClear = false;
|
|
720
|
+
for (const value of values) {
|
|
721
|
+
if (value === undefined)
|
|
722
|
+
continue;
|
|
723
|
+
if (shouldClear && !didClear) {
|
|
724
|
+
didClear = true;
|
|
725
|
+
yield [name, null];
|
|
726
|
+
}
|
|
727
|
+
yield [name, value];
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
var buildHeaders = (newHeaders) => {
|
|
732
|
+
const targetHeaders = new Headers;
|
|
733
|
+
const nullHeaders = new Set;
|
|
734
|
+
for (const headers of newHeaders) {
|
|
735
|
+
const seenHeaders = new Set;
|
|
736
|
+
for (const [name, value] of iterateHeaders(headers)) {
|
|
737
|
+
const lowerName = name.toLowerCase();
|
|
738
|
+
if (!seenHeaders.has(lowerName)) {
|
|
739
|
+
targetHeaders.delete(name);
|
|
740
|
+
seenHeaders.add(lowerName);
|
|
741
|
+
}
|
|
742
|
+
if (value === null) {
|
|
743
|
+
targetHeaders.delete(name);
|
|
744
|
+
nullHeaders.add(lowerName);
|
|
745
|
+
} else {
|
|
746
|
+
targetHeaders.append(name, value);
|
|
747
|
+
nullHeaders.delete(lowerName);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders };
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
// node_modules/supermemory/internal/utils/path.mjs
|
|
755
|
+
function encodeURIPath(str) {
|
|
756
|
+
return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
|
|
757
|
+
}
|
|
758
|
+
var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
759
|
+
var createPathTagFunction = (pathEncoder = encodeURIPath) => function path(statics, ...params) {
|
|
760
|
+
if (statics.length === 1)
|
|
761
|
+
return statics[0];
|
|
762
|
+
let postPath = false;
|
|
763
|
+
const invalidSegments = [];
|
|
764
|
+
const path3 = statics.reduce((previousValue, currentValue, index) => {
|
|
765
|
+
if (/[?#]/.test(currentValue)) {
|
|
766
|
+
postPath = true;
|
|
767
|
+
}
|
|
768
|
+
const value = params[index];
|
|
769
|
+
let encoded = (postPath ? encodeURIComponent : pathEncoder)("" + value);
|
|
770
|
+
if (index !== params.length && (value == null || typeof value === "object" && value.toString === Object.getPrototypeOf(Object.getPrototypeOf(value.hasOwnProperty ?? EMPTY) ?? EMPTY)?.toString)) {
|
|
771
|
+
encoded = value + "";
|
|
772
|
+
invalidSegments.push({
|
|
773
|
+
start: previousValue.length + currentValue.length,
|
|
774
|
+
length: encoded.length,
|
|
775
|
+
error: `Value of type ${Object.prototype.toString.call(value).slice(8, -1)} is not a valid path parameter`
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return previousValue + currentValue + (index === params.length ? "" : encoded);
|
|
779
|
+
}, "");
|
|
780
|
+
const pathOnly = path3.split(/[?#]/, 1)[0];
|
|
781
|
+
const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
|
|
782
|
+
let match;
|
|
783
|
+
while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
|
|
784
|
+
invalidSegments.push({
|
|
785
|
+
start: match.index,
|
|
786
|
+
length: match[0].length,
|
|
787
|
+
error: `Value "${match[0]}" can't be safely passed as a path parameter`
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
invalidSegments.sort((a, b) => a.start - b.start);
|
|
791
|
+
if (invalidSegments.length > 0) {
|
|
792
|
+
let lastEnd = 0;
|
|
793
|
+
const underline = invalidSegments.reduce((acc, segment) => {
|
|
794
|
+
const spaces = " ".repeat(segment.start - lastEnd);
|
|
795
|
+
const arrows = "^".repeat(segment.length);
|
|
796
|
+
lastEnd = segment.start + segment.length;
|
|
797
|
+
return acc + spaces + arrows;
|
|
798
|
+
}, "");
|
|
799
|
+
throw new SupermemoryError(`Path parameters result in path with invalid segments:
|
|
800
|
+
${invalidSegments.map((e) => e.error).join(`
|
|
801
|
+
`)}
|
|
802
|
+
${path3}
|
|
803
|
+
${underline}`);
|
|
804
|
+
}
|
|
805
|
+
return path3;
|
|
806
|
+
};
|
|
807
|
+
var path3 = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
|
|
808
|
+
|
|
809
|
+
// node_modules/supermemory/resources/connections.mjs
|
|
810
|
+
class Connections extends APIResource {
|
|
811
|
+
create(provider, body = {}, options) {
|
|
812
|
+
return this._client.post(path3`/v3/connections/${provider}`, { body, ...options });
|
|
813
|
+
}
|
|
814
|
+
list(body = {}, options) {
|
|
815
|
+
return this._client.post("/v3/connections/list", { body, ...options });
|
|
816
|
+
}
|
|
817
|
+
configure(connectionID, body, options) {
|
|
818
|
+
return this._client.post(path3`/v3/connections/${connectionID}/configure`, { body, ...options });
|
|
819
|
+
}
|
|
820
|
+
deleteByID(connectionID, options) {
|
|
821
|
+
return this._client.delete(path3`/v3/connections/${connectionID}`, options);
|
|
822
|
+
}
|
|
823
|
+
deleteByProvider(provider, body, options) {
|
|
824
|
+
return this._client.delete(path3`/v3/connections/${provider}`, { body, ...options });
|
|
825
|
+
}
|
|
826
|
+
getByID(connectionID, options) {
|
|
827
|
+
return this._client.get(path3`/v3/connections/${connectionID}`, options);
|
|
828
|
+
}
|
|
829
|
+
getByTag(provider, body, options) {
|
|
830
|
+
return this._client.post(path3`/v3/connections/${provider}/connection`, { body, ...options });
|
|
831
|
+
}
|
|
832
|
+
import(provider, body = {}, options) {
|
|
833
|
+
return this._client.post(path3`/v3/connections/${provider}/import`, {
|
|
834
|
+
body,
|
|
835
|
+
...options,
|
|
836
|
+
headers: buildHeaders([{ Accept: "text/plain" }, options?.headers])
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
listDocuments(provider, body = {}, options) {
|
|
840
|
+
return this._client.post(path3`/v3/connections/${provider}/documents`, { body, ...options });
|
|
841
|
+
}
|
|
842
|
+
resources(connectionID, query = {}, options) {
|
|
843
|
+
return this._client.get(path3`/v3/connections/${connectionID}/resources`, { query, ...options });
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
// node_modules/supermemory/resources/documents.mjs
|
|
847
|
+
class Documents extends APIResource {
|
|
848
|
+
update(id, body = {}, options) {
|
|
849
|
+
return this._client.patch(path3`/v3/documents/${id}`, { body, ...options });
|
|
850
|
+
}
|
|
851
|
+
list(body = {}, options) {
|
|
852
|
+
return this._client.post("/v3/documents/list", { body, ...options });
|
|
853
|
+
}
|
|
854
|
+
delete(id, options) {
|
|
855
|
+
return this._client.delete(path3`/v3/documents/${id}`, {
|
|
856
|
+
...options,
|
|
857
|
+
headers: buildHeaders([{ Accept: "*/*" }, options?.headers])
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
add(body, options) {
|
|
861
|
+
return this._client.post("/v3/documents", { body, ...options });
|
|
862
|
+
}
|
|
863
|
+
batchAdd(body, options) {
|
|
864
|
+
return this._client.post("/v3/documents/batch", { body, ...options });
|
|
865
|
+
}
|
|
866
|
+
deleteBulk(body = {}, options) {
|
|
867
|
+
return this._client.delete("/v3/documents/bulk", { body, ...options });
|
|
868
|
+
}
|
|
869
|
+
get(id, options) {
|
|
870
|
+
return this._client.get(path3`/v3/documents/${id}`, options);
|
|
871
|
+
}
|
|
872
|
+
listProcessing(options) {
|
|
873
|
+
return this._client.get("/v3/documents/processing", options);
|
|
874
|
+
}
|
|
875
|
+
uploadFile(body, options) {
|
|
876
|
+
return this._client.post("/v3/documents/file", multipartFormRequestOptions({ body, ...options }, this._client));
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
// node_modules/supermemory/resources/memories.mjs
|
|
880
|
+
class Memories extends APIResource {
|
|
881
|
+
forget(body, options) {
|
|
882
|
+
return this._client.delete("/v4/memories", { body, ...options });
|
|
883
|
+
}
|
|
884
|
+
updateMemory(body, options) {
|
|
885
|
+
return this._client.patch("/v4/memories", { body, ...options });
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
// node_modules/supermemory/resources/search.mjs
|
|
889
|
+
class Search extends APIResource {
|
|
890
|
+
documents(body, options) {
|
|
891
|
+
return this._client.post("/v3/search", { body, ...options });
|
|
892
|
+
}
|
|
893
|
+
execute(body, options) {
|
|
894
|
+
return this._client.post("/v3/search", { body, ...options });
|
|
895
|
+
}
|
|
896
|
+
memories(body, options) {
|
|
897
|
+
return this._client.post("/v4/search", { body, ...options });
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
// node_modules/supermemory/resources/settings.mjs
|
|
901
|
+
class Settings extends APIResource {
|
|
902
|
+
update(body = {}, options) {
|
|
903
|
+
return this._client.patch("/v3/settings", { body, ...options });
|
|
904
|
+
}
|
|
905
|
+
get(options) {
|
|
906
|
+
return this._client.get("/v3/settings", options);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
// node_modules/supermemory/internal/utils/log.mjs
|
|
910
|
+
var levelNumbers = {
|
|
911
|
+
off: 0,
|
|
912
|
+
error: 200,
|
|
913
|
+
warn: 300,
|
|
914
|
+
info: 400,
|
|
915
|
+
debug: 500
|
|
916
|
+
};
|
|
917
|
+
var parseLogLevel = (maybeLevel, sourceName, client) => {
|
|
918
|
+
if (!maybeLevel) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
if (hasOwn(levelNumbers, maybeLevel)) {
|
|
922
|
+
return maybeLevel;
|
|
923
|
+
}
|
|
924
|
+
loggerFor(client).warn(`${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(Object.keys(levelNumbers))}`);
|
|
925
|
+
return;
|
|
926
|
+
};
|
|
927
|
+
function noop() {}
|
|
928
|
+
function makeLogFn(fnLevel, logger, logLevel) {
|
|
929
|
+
if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) {
|
|
930
|
+
return noop;
|
|
931
|
+
} else {
|
|
932
|
+
return logger[fnLevel].bind(logger);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
var noopLogger = {
|
|
936
|
+
error: noop,
|
|
937
|
+
warn: noop,
|
|
938
|
+
info: noop,
|
|
939
|
+
debug: noop
|
|
940
|
+
};
|
|
941
|
+
var cachedLoggers = /* @__PURE__ */ new WeakMap;
|
|
942
|
+
function loggerFor(client) {
|
|
943
|
+
const logger = client.logger;
|
|
944
|
+
const logLevel = client.logLevel ?? "off";
|
|
945
|
+
if (!logger) {
|
|
946
|
+
return noopLogger;
|
|
947
|
+
}
|
|
948
|
+
const cachedLogger = cachedLoggers.get(logger);
|
|
949
|
+
if (cachedLogger && cachedLogger[0] === logLevel) {
|
|
950
|
+
return cachedLogger[1];
|
|
951
|
+
}
|
|
952
|
+
const levelLogger = {
|
|
953
|
+
error: makeLogFn("error", logger, logLevel),
|
|
954
|
+
warn: makeLogFn("warn", logger, logLevel),
|
|
955
|
+
info: makeLogFn("info", logger, logLevel),
|
|
956
|
+
debug: makeLogFn("debug", logger, logLevel)
|
|
957
|
+
};
|
|
958
|
+
cachedLoggers.set(logger, [logLevel, levelLogger]);
|
|
959
|
+
return levelLogger;
|
|
960
|
+
}
|
|
961
|
+
var formatRequestDetails = (details) => {
|
|
962
|
+
if (details.options) {
|
|
963
|
+
details.options = { ...details.options };
|
|
964
|
+
delete details.options["headers"];
|
|
965
|
+
}
|
|
966
|
+
if (details.headers) {
|
|
967
|
+
details.headers = Object.fromEntries((details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map(([name, value]) => [
|
|
968
|
+
name,
|
|
969
|
+
name.toLowerCase() === "authorization" || name.toLowerCase() === "cookie" || name.toLowerCase() === "set-cookie" ? "***" : value
|
|
970
|
+
]));
|
|
971
|
+
}
|
|
972
|
+
if ("retryOfRequestLogID" in details) {
|
|
973
|
+
if (details.retryOfRequestLogID) {
|
|
974
|
+
details.retryOf = details.retryOfRequestLogID;
|
|
975
|
+
}
|
|
976
|
+
delete details.retryOfRequestLogID;
|
|
977
|
+
}
|
|
978
|
+
return details;
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
// node_modules/supermemory/internal/parse.mjs
|
|
982
|
+
async function defaultParseResponse(client, props) {
|
|
983
|
+
const { response, requestLogID, retryOfRequestLogID, startTime } = props;
|
|
984
|
+
const body = await (async () => {
|
|
985
|
+
if (response.status === 204) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
if (props.options.__binaryResponse) {
|
|
989
|
+
return response;
|
|
990
|
+
}
|
|
991
|
+
const contentType = response.headers.get("content-type");
|
|
992
|
+
const mediaType = contentType?.split(";")[0]?.trim();
|
|
993
|
+
const isJSON = mediaType?.includes("application/json") || mediaType?.endsWith("+json");
|
|
994
|
+
if (isJSON) {
|
|
995
|
+
const contentLength = response.headers.get("content-length");
|
|
996
|
+
if (contentLength === "0") {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
const json = await response.json();
|
|
1000
|
+
return json;
|
|
1001
|
+
}
|
|
1002
|
+
const text = await response.text();
|
|
1003
|
+
return text;
|
|
1004
|
+
})();
|
|
1005
|
+
loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
|
|
1006
|
+
retryOfRequestLogID,
|
|
1007
|
+
url: response.url,
|
|
1008
|
+
status: response.status,
|
|
1009
|
+
body,
|
|
1010
|
+
durationMs: Date.now() - startTime
|
|
1011
|
+
}));
|
|
1012
|
+
return body;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// node_modules/supermemory/core/api-promise.mjs
|
|
1016
|
+
var _APIPromise_client;
|
|
1017
|
+
|
|
1018
|
+
class APIPromise extends Promise {
|
|
1019
|
+
constructor(client, responsePromise, parseResponse = defaultParseResponse) {
|
|
1020
|
+
super((resolve) => {
|
|
1021
|
+
resolve(null);
|
|
1022
|
+
});
|
|
1023
|
+
this.responsePromise = responsePromise;
|
|
1024
|
+
this.parseResponse = parseResponse;
|
|
1025
|
+
_APIPromise_client.set(this, undefined);
|
|
1026
|
+
__classPrivateFieldSet(this, _APIPromise_client, client, "f");
|
|
1027
|
+
}
|
|
1028
|
+
_thenUnwrap(transform) {
|
|
1029
|
+
return new APIPromise(__classPrivateFieldGet(this, _APIPromise_client, "f"), this.responsePromise, async (client, props) => transform(await this.parseResponse(client, props), props));
|
|
1030
|
+
}
|
|
1031
|
+
asResponse() {
|
|
1032
|
+
return this.responsePromise.then((p) => p.response);
|
|
1033
|
+
}
|
|
1034
|
+
async withResponse() {
|
|
1035
|
+
const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
|
|
1036
|
+
return { data, response };
|
|
1037
|
+
}
|
|
1038
|
+
parse() {
|
|
1039
|
+
if (!this.parsedPromise) {
|
|
1040
|
+
this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(__classPrivateFieldGet(this, _APIPromise_client, "f"), data));
|
|
1041
|
+
}
|
|
1042
|
+
return this.parsedPromise;
|
|
1043
|
+
}
|
|
1044
|
+
then(onfulfilled, onrejected) {
|
|
1045
|
+
return this.parse().then(onfulfilled, onrejected);
|
|
1046
|
+
}
|
|
1047
|
+
catch(onrejected) {
|
|
1048
|
+
return this.parse().catch(onrejected);
|
|
1049
|
+
}
|
|
1050
|
+
finally(onfinally) {
|
|
1051
|
+
return this.parse().finally(onfinally);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
_APIPromise_client = new WeakMap;
|
|
1055
|
+
|
|
1056
|
+
// node_modules/supermemory/internal/utils/env.mjs
|
|
1057
|
+
var readEnv = (env) => {
|
|
1058
|
+
if (typeof globalThis.process !== "undefined") {
|
|
1059
|
+
return globalThis.process.env?.[env]?.trim() ?? undefined;
|
|
1060
|
+
}
|
|
1061
|
+
if (typeof globalThis.Deno !== "undefined") {
|
|
1062
|
+
return globalThis.Deno.env?.get?.(env)?.trim();
|
|
1063
|
+
}
|
|
1064
|
+
return;
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1067
|
+
// node_modules/supermemory/client.mjs
|
|
1068
|
+
var _Supermemory_instances;
|
|
1069
|
+
var _a;
|
|
1070
|
+
var _Supermemory_encoder;
|
|
1071
|
+
var _Supermemory_baseURLOverridden;
|
|
1072
|
+
|
|
1073
|
+
class Supermemory {
|
|
1074
|
+
constructor({ baseURL = readEnv("SUPERMEMORY_BASE_URL"), apiKey = readEnv("SUPERMEMORY_API_KEY"), ...opts } = {}) {
|
|
1075
|
+
_Supermemory_instances.add(this);
|
|
1076
|
+
_Supermemory_encoder.set(this, undefined);
|
|
1077
|
+
this.memories = new Memories(this);
|
|
1078
|
+
this.documents = new Documents(this);
|
|
1079
|
+
this.search = new Search(this);
|
|
1080
|
+
this.settings = new Settings(this);
|
|
1081
|
+
this.connections = new Connections(this);
|
|
1082
|
+
if (apiKey === undefined) {
|
|
1083
|
+
throw new SupermemoryError("The SUPERMEMORY_API_KEY environment variable is missing or empty; either provide it, or instantiate the Supermemory client with an apiKey option, like new Supermemory({ apiKey: 'My API Key' }).");
|
|
1084
|
+
}
|
|
1085
|
+
const options = {
|
|
1086
|
+
apiKey,
|
|
1087
|
+
...opts,
|
|
1088
|
+
baseURL: baseURL || `https://api.supermemory.ai`
|
|
1089
|
+
};
|
|
1090
|
+
this.baseURL = options.baseURL;
|
|
1091
|
+
this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT;
|
|
1092
|
+
this.logger = options.logger ?? console;
|
|
1093
|
+
const defaultLogLevel = "warn";
|
|
1094
|
+
this.logLevel = defaultLogLevel;
|
|
1095
|
+
this.logLevel = parseLogLevel(options.logLevel, "ClientOptions.logLevel", this) ?? parseLogLevel(readEnv("SUPERMEMORY_LOG"), "process.env['SUPERMEMORY_LOG']", this) ?? defaultLogLevel;
|
|
1096
|
+
this.fetchOptions = options.fetchOptions;
|
|
1097
|
+
this.maxRetries = options.maxRetries ?? 2;
|
|
1098
|
+
this.fetch = options.fetch ?? getDefaultFetch();
|
|
1099
|
+
__classPrivateFieldSet(this, _Supermemory_encoder, FallbackEncoder, "f");
|
|
1100
|
+
this._options = options;
|
|
1101
|
+
this.apiKey = apiKey;
|
|
1102
|
+
}
|
|
1103
|
+
withOptions(options) {
|
|
1104
|
+
const client = new this.constructor({
|
|
1105
|
+
...this._options,
|
|
1106
|
+
baseURL: this.baseURL,
|
|
1107
|
+
maxRetries: this.maxRetries,
|
|
1108
|
+
timeout: this.timeout,
|
|
1109
|
+
logger: this.logger,
|
|
1110
|
+
logLevel: this.logLevel,
|
|
1111
|
+
fetch: this.fetch,
|
|
1112
|
+
fetchOptions: this.fetchOptions,
|
|
1113
|
+
apiKey: this.apiKey,
|
|
1114
|
+
...options
|
|
1115
|
+
});
|
|
1116
|
+
return client;
|
|
1117
|
+
}
|
|
1118
|
+
add(body, options) {
|
|
1119
|
+
return this.post("/v3/documents", { body, ...options });
|
|
1120
|
+
}
|
|
1121
|
+
profile(body, options) {
|
|
1122
|
+
return this.post("/v4/profile", { body, ...options });
|
|
1123
|
+
}
|
|
1124
|
+
defaultQuery() {
|
|
1125
|
+
return this._options.defaultQuery;
|
|
1126
|
+
}
|
|
1127
|
+
validateHeaders({ values, nulls }) {
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
async authHeaders(opts) {
|
|
1131
|
+
return buildHeaders([{ Authorization: `Bearer ${this.apiKey}` }]);
|
|
1132
|
+
}
|
|
1133
|
+
stringifyQuery(query) {
|
|
1134
|
+
return Object.entries(query).filter(([_, value]) => typeof value !== "undefined").map(([key, value]) => {
|
|
1135
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1136
|
+
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
1137
|
+
}
|
|
1138
|
+
if (value === null) {
|
|
1139
|
+
return `${encodeURIComponent(key)}=`;
|
|
1140
|
+
}
|
|
1141
|
+
throw new SupermemoryError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);
|
|
1142
|
+
}).join("&");
|
|
1143
|
+
}
|
|
1144
|
+
getUserAgent() {
|
|
1145
|
+
return `${this.constructor.name}/JS ${VERSION}`;
|
|
1146
|
+
}
|
|
1147
|
+
defaultIdempotencyKey() {
|
|
1148
|
+
return `stainless-node-retry-${uuid4()}`;
|
|
1149
|
+
}
|
|
1150
|
+
makeStatusError(status, error, message, headers) {
|
|
1151
|
+
return APIError.generate(status, error, message, headers);
|
|
1152
|
+
}
|
|
1153
|
+
buildURL(path4, query, defaultBaseURL) {
|
|
1154
|
+
const baseURL = !__classPrivateFieldGet(this, _Supermemory_instances, "m", _Supermemory_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
|
|
1155
|
+
const url = isAbsoluteURL(path4) ? new URL(path4) : new URL(baseURL + (baseURL.endsWith("/") && path4.startsWith("/") ? path4.slice(1) : path4));
|
|
1156
|
+
const defaultQuery = this.defaultQuery();
|
|
1157
|
+
if (!isEmptyObj(defaultQuery)) {
|
|
1158
|
+
query = { ...defaultQuery, ...query };
|
|
1159
|
+
}
|
|
1160
|
+
if (typeof query === "object" && query && !Array.isArray(query)) {
|
|
1161
|
+
url.search = this.stringifyQuery(query);
|
|
1162
|
+
}
|
|
1163
|
+
return url.toString();
|
|
1164
|
+
}
|
|
1165
|
+
async prepareOptions(options) {}
|
|
1166
|
+
async prepareRequest(request, { url, options }) {}
|
|
1167
|
+
get(path4, opts) {
|
|
1168
|
+
return this.methodRequest("get", path4, opts);
|
|
1169
|
+
}
|
|
1170
|
+
post(path4, opts) {
|
|
1171
|
+
return this.methodRequest("post", path4, opts);
|
|
1172
|
+
}
|
|
1173
|
+
patch(path4, opts) {
|
|
1174
|
+
return this.methodRequest("patch", path4, opts);
|
|
1175
|
+
}
|
|
1176
|
+
put(path4, opts) {
|
|
1177
|
+
return this.methodRequest("put", path4, opts);
|
|
1178
|
+
}
|
|
1179
|
+
delete(path4, opts) {
|
|
1180
|
+
return this.methodRequest("delete", path4, opts);
|
|
1181
|
+
}
|
|
1182
|
+
methodRequest(method, path4, opts) {
|
|
1183
|
+
return this.request(Promise.resolve(opts).then((opts2) => {
|
|
1184
|
+
return { method, path: path4, ...opts2 };
|
|
1185
|
+
}));
|
|
1186
|
+
}
|
|
1187
|
+
request(options, remainingRetries = null) {
|
|
1188
|
+
return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined));
|
|
1189
|
+
}
|
|
1190
|
+
async makeRequest(optionsInput, retriesRemaining, retryOfRequestLogID) {
|
|
1191
|
+
const options = await optionsInput;
|
|
1192
|
+
const maxRetries = options.maxRetries ?? this.maxRetries;
|
|
1193
|
+
if (retriesRemaining == null) {
|
|
1194
|
+
retriesRemaining = maxRetries;
|
|
1195
|
+
}
|
|
1196
|
+
await this.prepareOptions(options);
|
|
1197
|
+
const { req, url, timeout } = await this.buildRequest(options, {
|
|
1198
|
+
retryCount: maxRetries - retriesRemaining
|
|
1199
|
+
});
|
|
1200
|
+
await this.prepareRequest(req, { url, options });
|
|
1201
|
+
const requestLogID = "log_" + (Math.random() * (1 << 24) | 0).toString(16).padStart(6, "0");
|
|
1202
|
+
const retryLogStr = retryOfRequestLogID === undefined ? "" : `, retryOf: ${retryOfRequestLogID}`;
|
|
1203
|
+
const startTime = Date.now();
|
|
1204
|
+
loggerFor(this).debug(`[${requestLogID}] sending request`, formatRequestDetails({
|
|
1205
|
+
retryOfRequestLogID,
|
|
1206
|
+
method: options.method,
|
|
1207
|
+
url,
|
|
1208
|
+
options,
|
|
1209
|
+
headers: req.headers
|
|
1210
|
+
}));
|
|
1211
|
+
if (options.signal?.aborted) {
|
|
1212
|
+
throw new APIUserAbortError;
|
|
1213
|
+
}
|
|
1214
|
+
const controller = new AbortController;
|
|
1215
|
+
const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);
|
|
1216
|
+
const headersTime = Date.now();
|
|
1217
|
+
if (response instanceof globalThis.Error) {
|
|
1218
|
+
const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
|
|
1219
|
+
if (options.signal?.aborted) {
|
|
1220
|
+
throw new APIUserAbortError;
|
|
1221
|
+
}
|
|
1222
|
+
const isTimeout = isAbortError(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
1223
|
+
if (retriesRemaining) {
|
|
1224
|
+
loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - ${retryMessage}`);
|
|
1225
|
+
loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (${retryMessage})`, formatRequestDetails({
|
|
1226
|
+
retryOfRequestLogID,
|
|
1227
|
+
url,
|
|
1228
|
+
durationMs: headersTime - startTime,
|
|
1229
|
+
message: response.message
|
|
1230
|
+
}));
|
|
1231
|
+
return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID);
|
|
1232
|
+
}
|
|
1233
|
+
loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - error; no more retries left`);
|
|
1234
|
+
loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (error; no more retries left)`, formatRequestDetails({
|
|
1235
|
+
retryOfRequestLogID,
|
|
1236
|
+
url,
|
|
1237
|
+
durationMs: headersTime - startTime,
|
|
1238
|
+
message: response.message
|
|
1239
|
+
}));
|
|
1240
|
+
if (isTimeout) {
|
|
1241
|
+
throw new APIConnectionTimeoutError;
|
|
1242
|
+
}
|
|
1243
|
+
throw new APIConnectionError({ cause: response });
|
|
1244
|
+
}
|
|
1245
|
+
const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${response.ok ? "succeeded" : "failed"} with status ${response.status} in ${headersTime - startTime}ms`;
|
|
1246
|
+
if (!response.ok) {
|
|
1247
|
+
const shouldRetry = await this.shouldRetry(response);
|
|
1248
|
+
if (retriesRemaining && shouldRetry) {
|
|
1249
|
+
const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;
|
|
1250
|
+
await CancelReadableStream(response.body);
|
|
1251
|
+
loggerFor(this).info(`${responseInfo} - ${retryMessage2}`);
|
|
1252
|
+
loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage2})`, formatRequestDetails({
|
|
1253
|
+
retryOfRequestLogID,
|
|
1254
|
+
url: response.url,
|
|
1255
|
+
status: response.status,
|
|
1256
|
+
headers: response.headers,
|
|
1257
|
+
durationMs: headersTime - startTime
|
|
1258
|
+
}));
|
|
1259
|
+
return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers);
|
|
1260
|
+
}
|
|
1261
|
+
const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`;
|
|
1262
|
+
loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
|
|
1263
|
+
const errText = await response.text().catch((err2) => castToError(err2).message);
|
|
1264
|
+
const errJSON = safeJSON(errText);
|
|
1265
|
+
const errMessage = errJSON ? undefined : errText;
|
|
1266
|
+
loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({
|
|
1267
|
+
retryOfRequestLogID,
|
|
1268
|
+
url: response.url,
|
|
1269
|
+
status: response.status,
|
|
1270
|
+
headers: response.headers,
|
|
1271
|
+
message: errMessage,
|
|
1272
|
+
durationMs: Date.now() - startTime
|
|
1273
|
+
}));
|
|
1274
|
+
const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers);
|
|
1275
|
+
throw err;
|
|
1276
|
+
}
|
|
1277
|
+
loggerFor(this).info(responseInfo);
|
|
1278
|
+
loggerFor(this).debug(`[${requestLogID}] response start`, formatRequestDetails({
|
|
1279
|
+
retryOfRequestLogID,
|
|
1280
|
+
url: response.url,
|
|
1281
|
+
status: response.status,
|
|
1282
|
+
headers: response.headers,
|
|
1283
|
+
durationMs: headersTime - startTime
|
|
1284
|
+
}));
|
|
1285
|
+
return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
|
|
1286
|
+
}
|
|
1287
|
+
async fetchWithTimeout(url, init, ms, controller) {
|
|
1288
|
+
const { signal, method, ...options } = init || {};
|
|
1289
|
+
const abort = this._makeAbort(controller);
|
|
1290
|
+
if (signal)
|
|
1291
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
1292
|
+
const timeout = setTimeout(abort, ms);
|
|
1293
|
+
const isReadableBody = globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream || typeof options.body === "object" && options.body !== null && Symbol.asyncIterator in options.body;
|
|
1294
|
+
const fetchOptions = {
|
|
1295
|
+
signal: controller.signal,
|
|
1296
|
+
...isReadableBody ? { duplex: "half" } : {},
|
|
1297
|
+
method: "GET",
|
|
1298
|
+
...options
|
|
1299
|
+
};
|
|
1300
|
+
if (method) {
|
|
1301
|
+
fetchOptions.method = method.toUpperCase();
|
|
1302
|
+
}
|
|
1303
|
+
try {
|
|
1304
|
+
return await this.fetch.call(undefined, url, fetchOptions);
|
|
1305
|
+
} finally {
|
|
1306
|
+
clearTimeout(timeout);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
async shouldRetry(response) {
|
|
1310
|
+
const shouldRetryHeader = response.headers.get("x-should-retry");
|
|
1311
|
+
if (shouldRetryHeader === "true")
|
|
1312
|
+
return true;
|
|
1313
|
+
if (shouldRetryHeader === "false")
|
|
1314
|
+
return false;
|
|
1315
|
+
if (response.status === 408)
|
|
1316
|
+
return true;
|
|
1317
|
+
if (response.status === 409)
|
|
1318
|
+
return true;
|
|
1319
|
+
if (response.status === 429)
|
|
1320
|
+
return true;
|
|
1321
|
+
if (response.status >= 500)
|
|
1322
|
+
return true;
|
|
1323
|
+
return false;
|
|
1324
|
+
}
|
|
1325
|
+
async retryRequest(options, retriesRemaining, requestLogID, responseHeaders) {
|
|
1326
|
+
let timeoutMillis;
|
|
1327
|
+
const retryAfterMillisHeader = responseHeaders?.get("retry-after-ms");
|
|
1328
|
+
if (retryAfterMillisHeader) {
|
|
1329
|
+
const timeoutMs = parseFloat(retryAfterMillisHeader);
|
|
1330
|
+
if (!Number.isNaN(timeoutMs)) {
|
|
1331
|
+
timeoutMillis = timeoutMs;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
const retryAfterHeader = responseHeaders?.get("retry-after");
|
|
1335
|
+
if (retryAfterHeader && !timeoutMillis) {
|
|
1336
|
+
const timeoutSeconds = parseFloat(retryAfterHeader);
|
|
1337
|
+
if (!Number.isNaN(timeoutSeconds)) {
|
|
1338
|
+
timeoutMillis = timeoutSeconds * 1000;
|
|
1339
|
+
} else {
|
|
1340
|
+
timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
|
|
1344
|
+
const maxRetries = options.maxRetries ?? this.maxRetries;
|
|
1345
|
+
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
|
|
1346
|
+
}
|
|
1347
|
+
await sleep(timeoutMillis);
|
|
1348
|
+
return this.makeRequest(options, retriesRemaining - 1, requestLogID);
|
|
1349
|
+
}
|
|
1350
|
+
calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
|
|
1351
|
+
const initialRetryDelay = 0.5;
|
|
1352
|
+
const maxRetryDelay = 8;
|
|
1353
|
+
const numRetries = maxRetries - retriesRemaining;
|
|
1354
|
+
const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
|
|
1355
|
+
const jitter = 1 - Math.random() * 0.25;
|
|
1356
|
+
return sleepSeconds * jitter * 1000;
|
|
1357
|
+
}
|
|
1358
|
+
async buildRequest(inputOptions, { retryCount = 0 } = {}) {
|
|
1359
|
+
const options = { ...inputOptions };
|
|
1360
|
+
const { method, path: path4, query, defaultBaseURL } = options;
|
|
1361
|
+
const url = this.buildURL(path4, query, defaultBaseURL);
|
|
1362
|
+
if ("timeout" in options)
|
|
1363
|
+
validatePositiveInteger("timeout", options.timeout);
|
|
1364
|
+
options.timeout = options.timeout ?? this.timeout;
|
|
1365
|
+
const { bodyHeaders, body } = this.buildBody({ options });
|
|
1366
|
+
const reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount });
|
|
1367
|
+
const req = {
|
|
1368
|
+
method,
|
|
1369
|
+
headers: reqHeaders,
|
|
1370
|
+
...options.signal && { signal: options.signal },
|
|
1371
|
+
...globalThis.ReadableStream && body instanceof globalThis.ReadableStream && { duplex: "half" },
|
|
1372
|
+
...body && { body },
|
|
1373
|
+
...this.fetchOptions ?? {},
|
|
1374
|
+
...options.fetchOptions ?? {}
|
|
1375
|
+
};
|
|
1376
|
+
return { req, url, timeout: options.timeout };
|
|
1377
|
+
}
|
|
1378
|
+
async buildHeaders({ options, method, bodyHeaders, retryCount }) {
|
|
1379
|
+
let idempotencyHeaders = {};
|
|
1380
|
+
if (this.idempotencyHeader && method !== "get") {
|
|
1381
|
+
if (!options.idempotencyKey)
|
|
1382
|
+
options.idempotencyKey = this.defaultIdempotencyKey();
|
|
1383
|
+
idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey;
|
|
1384
|
+
}
|
|
1385
|
+
const headers = buildHeaders([
|
|
1386
|
+
idempotencyHeaders,
|
|
1387
|
+
{
|
|
1388
|
+
Accept: "application/json",
|
|
1389
|
+
"User-Agent": this.getUserAgent(),
|
|
1390
|
+
"X-Stainless-Retry-Count": String(retryCount),
|
|
1391
|
+
...options.timeout ? { "X-Stainless-Timeout": String(Math.trunc(options.timeout / 1000)) } : {},
|
|
1392
|
+
...getPlatformHeaders()
|
|
1393
|
+
},
|
|
1394
|
+
await this.authHeaders(options),
|
|
1395
|
+
this._options.defaultHeaders,
|
|
1396
|
+
bodyHeaders,
|
|
1397
|
+
options.headers
|
|
1398
|
+
]);
|
|
1399
|
+
this.validateHeaders(headers);
|
|
1400
|
+
return headers.values;
|
|
1401
|
+
}
|
|
1402
|
+
_makeAbort(controller) {
|
|
1403
|
+
return () => controller.abort();
|
|
1404
|
+
}
|
|
1405
|
+
buildBody({ options: { body, headers: rawHeaders } }) {
|
|
1406
|
+
if (!body) {
|
|
1407
|
+
return { bodyHeaders: undefined, body: undefined };
|
|
1408
|
+
}
|
|
1409
|
+
const headers = buildHeaders([rawHeaders]);
|
|
1410
|
+
if (ArrayBuffer.isView(body) || body instanceof ArrayBuffer || body instanceof DataView || typeof body === "string" && headers.values.has("content-type") || globalThis.Blob && body instanceof globalThis.Blob || body instanceof FormData || body instanceof URLSearchParams || globalThis.ReadableStream && body instanceof globalThis.ReadableStream) {
|
|
1411
|
+
return { bodyHeaders: undefined, body };
|
|
1412
|
+
} else if (typeof body === "object" && ((Symbol.asyncIterator in body) || (Symbol.iterator in body) && ("next" in body) && typeof body.next === "function")) {
|
|
1413
|
+
return { bodyHeaders: undefined, body: ReadableStreamFrom(body) };
|
|
1414
|
+
} else {
|
|
1415
|
+
return __classPrivateFieldGet(this, _Supermemory_encoder, "f").call(this, { body, headers });
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
_a = Supermemory, _Supermemory_encoder = new WeakMap, _Supermemory_instances = new WeakSet, _Supermemory_baseURLOverridden = function _Supermemory_baseURLOverridden2() {
|
|
1420
|
+
return this.baseURL !== "https://api.supermemory.ai";
|
|
1421
|
+
};
|
|
1422
|
+
Supermemory.Supermemory = _a;
|
|
1423
|
+
Supermemory.DEFAULT_TIMEOUT = 60000;
|
|
1424
|
+
Supermemory.SupermemoryError = SupermemoryError;
|
|
1425
|
+
Supermemory.APIError = APIError;
|
|
1426
|
+
Supermemory.APIConnectionError = APIConnectionError;
|
|
1427
|
+
Supermemory.APIConnectionTimeoutError = APIConnectionTimeoutError;
|
|
1428
|
+
Supermemory.APIUserAbortError = APIUserAbortError;
|
|
1429
|
+
Supermemory.NotFoundError = NotFoundError;
|
|
1430
|
+
Supermemory.ConflictError = ConflictError;
|
|
1431
|
+
Supermemory.RateLimitError = RateLimitError;
|
|
1432
|
+
Supermemory.BadRequestError = BadRequestError;
|
|
1433
|
+
Supermemory.AuthenticationError = AuthenticationError;
|
|
1434
|
+
Supermemory.InternalServerError = InternalServerError;
|
|
1435
|
+
Supermemory.PermissionDeniedError = PermissionDeniedError;
|
|
1436
|
+
Supermemory.UnprocessableEntityError = UnprocessableEntityError;
|
|
1437
|
+
Supermemory.toFile = toFile;
|
|
1438
|
+
Supermemory.Memories = Memories;
|
|
1439
|
+
Supermemory.Documents = Documents;
|
|
1440
|
+
Supermemory.Search = Search;
|
|
1441
|
+
Supermemory.Settings = Settings;
|
|
1442
|
+
Supermemory.Connections = Connections;
|
|
1443
|
+
// src/client.ts
|
|
1444
|
+
import { createHash, createHmac } from "node:crypto";
|
|
1445
|
+
var INTEGRITY_VERSION = 1;
|
|
1446
|
+
var SEED = "7f2a9c4b8e1d6f3a5c0b9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a";
|
|
1447
|
+
function sha2562(input) {
|
|
1448
|
+
return createHash("sha256").update(input).digest("hex");
|
|
1449
|
+
}
|
|
1450
|
+
function integrityHeaders(apiKey, containerTag) {
|
|
1451
|
+
const contentHash = sha2562(containerTag);
|
|
1452
|
+
const payload = [sha2562(apiKey), contentHash, INTEGRITY_VERSION].join(":");
|
|
1453
|
+
const sig = createHmac("sha256", SEED).update(payload).digest("base64url");
|
|
1454
|
+
return {
|
|
1455
|
+
"X-Content-Hash": contentHash,
|
|
1456
|
+
"X-Request-Integrity": `v${INTEGRITY_VERSION}.${sig}`
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
function createClient(apiKey, containerTag = "cursor") {
|
|
1460
|
+
return new Supermemory({
|
|
1461
|
+
apiKey,
|
|
1462
|
+
defaultHeaders: integrityHeaders(apiKey, containerTag)
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// src/mcp-server.ts
|
|
1467
|
+
var TOOLS = [
|
|
1468
|
+
{
|
|
1469
|
+
name: "supermemory_search",
|
|
1470
|
+
description: "Search the user's memory for relevant information. Use this to find previously stored knowledge, preferences, and context.",
|
|
1471
|
+
inputSchema: {
|
|
1472
|
+
type: "object",
|
|
1473
|
+
properties: {
|
|
1474
|
+
query: { type: "string", description: "Search query" },
|
|
1475
|
+
container: {
|
|
1476
|
+
type: "string",
|
|
1477
|
+
enum: ["user", "project"],
|
|
1478
|
+
description: "Search user memories or project memories",
|
|
1479
|
+
default: "user"
|
|
1480
|
+
},
|
|
1481
|
+
limit: {
|
|
1482
|
+
type: "number",
|
|
1483
|
+
description: "Max results to return",
|
|
1484
|
+
default: 10
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
required: ["query"]
|
|
1488
|
+
}
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: "supermemory_add",
|
|
1492
|
+
description: "Save information to the user's memory. Use this to remember preferences, facts, decisions, or any knowledge worth persisting.",
|
|
1493
|
+
inputSchema: {
|
|
1494
|
+
type: "object",
|
|
1495
|
+
properties: {
|
|
1496
|
+
content: { type: "string", description: "Content to save" },
|
|
1497
|
+
container: {
|
|
1498
|
+
type: "string",
|
|
1499
|
+
enum: ["user", "project"],
|
|
1500
|
+
description: "Save to user memories or project memories",
|
|
1501
|
+
default: "user"
|
|
1502
|
+
}
|
|
1503
|
+
},
|
|
1504
|
+
required: ["content"]
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
name: "supermemory_profile",
|
|
1509
|
+
description: "Get the user's profile summary — a distilled view of who they are based on their memories.",
|
|
1510
|
+
inputSchema: {
|
|
1511
|
+
type: "object",
|
|
1512
|
+
properties: {
|
|
1513
|
+
query: {
|
|
1514
|
+
type: "string",
|
|
1515
|
+
description: "Optional search query to include relevant results"
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
name: "supermemory_list",
|
|
1522
|
+
description: "List stored documents/memories.",
|
|
1523
|
+
inputSchema: {
|
|
1524
|
+
type: "object",
|
|
1525
|
+
properties: {
|
|
1526
|
+
limit: { type: "number", description: "Max items", default: 20 },
|
|
1527
|
+
page: { type: "number", description: "Page number", default: 1 }
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
name: "supermemory_forget",
|
|
1533
|
+
description: "Forget a specific memory. Use when the user asks to remove or forget something.",
|
|
1534
|
+
inputSchema: {
|
|
1535
|
+
type: "object",
|
|
1536
|
+
properties: {
|
|
1537
|
+
id: { type: "string", description: "Memory ID to forget" },
|
|
1538
|
+
content: {
|
|
1539
|
+
type: "string",
|
|
1540
|
+
description: "Exact content match (if ID unknown)"
|
|
1541
|
+
},
|
|
1542
|
+
container: {
|
|
1543
|
+
type: "string",
|
|
1544
|
+
enum: ["user", "project"],
|
|
1545
|
+
default: "user"
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
];
|
|
1551
|
+
function getAuth() {
|
|
1552
|
+
const config = loadConfig();
|
|
1553
|
+
const apiKey = getApiKey(config);
|
|
1554
|
+
if (!apiKey) {
|
|
1555
|
+
throw new Error("Not authenticated. Run `cursor-supermemory login` to connect your account.");
|
|
1556
|
+
}
|
|
1557
|
+
const userTag = getUserTag(config);
|
|
1558
|
+
const projectTag = getProjectTag(process.cwd(), config);
|
|
1559
|
+
return { apiKey, userTag, projectTag };
|
|
1560
|
+
}
|
|
1561
|
+
function containerTag(auth, container) {
|
|
1562
|
+
return container === "project" ? auth.projectTag : auth.userTag;
|
|
1563
|
+
}
|
|
1564
|
+
async function handleSearch(args) {
|
|
1565
|
+
const auth = getAuth();
|
|
1566
|
+
const tag = containerTag(auth, args.container);
|
|
1567
|
+
const client = createClient(auth.apiKey, tag);
|
|
1568
|
+
const result = await client.search.memories({
|
|
1569
|
+
q: args.query,
|
|
1570
|
+
containerTag: tag,
|
|
1571
|
+
limit: args.limit || 10
|
|
1572
|
+
});
|
|
1573
|
+
const formatted = result.results.map((r) => ({
|
|
1574
|
+
id: r.id,
|
|
1575
|
+
memory: r.memory ?? r.chunk ?? "",
|
|
1576
|
+
similarity: r.similarity,
|
|
1577
|
+
updatedAt: r.updatedAt
|
|
1578
|
+
}));
|
|
1579
|
+
return JSON.stringify(formatted, null, 2);
|
|
1580
|
+
}
|
|
1581
|
+
async function handleAdd(args) {
|
|
1582
|
+
const auth = getAuth();
|
|
1583
|
+
const tag = containerTag(auth, args.container);
|
|
1584
|
+
const client = createClient(auth.apiKey, tag);
|
|
1585
|
+
const result = await client.add({
|
|
1586
|
+
content: args.content,
|
|
1587
|
+
containerTag: tag
|
|
1588
|
+
});
|
|
1589
|
+
return JSON.stringify(result, null, 2);
|
|
1590
|
+
}
|
|
1591
|
+
async function handleProfile(args) {
|
|
1592
|
+
const auth = getAuth();
|
|
1593
|
+
const client = createClient(auth.apiKey, auth.userTag);
|
|
1594
|
+
const result = await client.profile({
|
|
1595
|
+
containerTag: auth.userTag,
|
|
1596
|
+
q: args.query
|
|
1597
|
+
});
|
|
1598
|
+
return JSON.stringify(result, null, 2);
|
|
1599
|
+
}
|
|
1600
|
+
async function handleList(args) {
|
|
1601
|
+
const auth = getAuth();
|
|
1602
|
+
const client = createClient(auth.apiKey, auth.userTag);
|
|
1603
|
+
const result = await client.documents.list({
|
|
1604
|
+
limit: args.limit || 20,
|
|
1605
|
+
page: args.page || 1
|
|
1606
|
+
});
|
|
1607
|
+
return JSON.stringify(result, null, 2);
|
|
1608
|
+
}
|
|
1609
|
+
async function handleForget(args) {
|
|
1610
|
+
const auth = getAuth();
|
|
1611
|
+
const tag = containerTag(auth, args.container);
|
|
1612
|
+
const client = createClient(auth.apiKey, tag);
|
|
1613
|
+
const params = {
|
|
1614
|
+
containerTag: containerTag(auth, args.container)
|
|
1615
|
+
};
|
|
1616
|
+
if (args.id)
|
|
1617
|
+
params.id = args.id;
|
|
1618
|
+
if (args.content)
|
|
1619
|
+
params.content = args.content;
|
|
1620
|
+
if (!params.id && !params.content) {
|
|
1621
|
+
throw new Error("Provide either id or content to forget.");
|
|
1622
|
+
}
|
|
1623
|
+
const result = await client.memories.forget(params);
|
|
1624
|
+
return JSON.stringify(result, null, 2);
|
|
1625
|
+
}
|
|
1626
|
+
var HANDLERS = {
|
|
1627
|
+
supermemory_search: handleSearch,
|
|
1628
|
+
supermemory_add: handleAdd,
|
|
1629
|
+
supermemory_profile: handleProfile,
|
|
1630
|
+
supermemory_list: handleList,
|
|
1631
|
+
supermemory_forget: handleForget
|
|
1632
|
+
};
|
|
1633
|
+
function jsonRpcResponse(id, result) {
|
|
1634
|
+
return JSON.stringify({ jsonrpc: "2.0", id, result });
|
|
1635
|
+
}
|
|
1636
|
+
function jsonRpcError(id, code, message) {
|
|
1637
|
+
return JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
|
|
1638
|
+
}
|
|
1639
|
+
async function handleMessage(msg) {
|
|
1640
|
+
const { id, method, params } = msg;
|
|
1641
|
+
switch (method) {
|
|
1642
|
+
case "initialize":
|
|
1643
|
+
return jsonRpcResponse(id, {
|
|
1644
|
+
protocolVersion: "2024-11-05",
|
|
1645
|
+
capabilities: { tools: {} },
|
|
1646
|
+
serverInfo: { name: "supermemory", version: "1.0.0" }
|
|
1647
|
+
});
|
|
1648
|
+
case "notifications/initialized":
|
|
1649
|
+
return null;
|
|
1650
|
+
case "tools/list":
|
|
1651
|
+
return jsonRpcResponse(id, { tools: TOOLS });
|
|
1652
|
+
case "tools/call": {
|
|
1653
|
+
const toolName = params?.name;
|
|
1654
|
+
const handler = HANDLERS[toolName];
|
|
1655
|
+
if (!handler) {
|
|
1656
|
+
return jsonRpcError(id, -32601, `Unknown tool: ${toolName}`);
|
|
1657
|
+
}
|
|
1658
|
+
try {
|
|
1659
|
+
const text = await handler(params?.arguments ?? {});
|
|
1660
|
+
return jsonRpcResponse(id, {
|
|
1661
|
+
content: [{ type: "text", text }]
|
|
1662
|
+
});
|
|
1663
|
+
} catch (err) {
|
|
1664
|
+
return jsonRpcResponse(id, {
|
|
1665
|
+
content: [{ type: "text", text: `Error: ${err.message}` }],
|
|
1666
|
+
isError: true
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
default:
|
|
1671
|
+
if (id !== undefined) {
|
|
1672
|
+
return jsonRpcError(id, -32601, `Method not found: ${method}`);
|
|
1673
|
+
}
|
|
1674
|
+
return null;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
async function startMcpServer() {
|
|
1678
|
+
const decoder = new TextDecoder;
|
|
1679
|
+
let buffer = "";
|
|
1680
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
1681
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
1682
|
+
while (true) {
|
|
1683
|
+
const headerEnd = buffer.indexOf(`\r
|
|
1684
|
+
\r
|
|
1685
|
+
`);
|
|
1686
|
+
if (headerEnd === -1)
|
|
1687
|
+
break;
|
|
1688
|
+
const header = buffer.slice(0, headerEnd);
|
|
1689
|
+
const match = header.match(/Content-Length:\s*(\d+)/i);
|
|
1690
|
+
if (!match) {
|
|
1691
|
+
buffer = buffer.slice(headerEnd + 4);
|
|
1692
|
+
continue;
|
|
1693
|
+
}
|
|
1694
|
+
const contentLength = parseInt(match[1], 10);
|
|
1695
|
+
const bodyStart = headerEnd + 4;
|
|
1696
|
+
if (buffer.length < bodyStart + contentLength)
|
|
1697
|
+
break;
|
|
1698
|
+
const body = buffer.slice(bodyStart, bodyStart + contentLength);
|
|
1699
|
+
buffer = buffer.slice(bodyStart + contentLength);
|
|
1700
|
+
try {
|
|
1701
|
+
const msg = JSON.parse(body);
|
|
1702
|
+
const response = await handleMessage(msg);
|
|
1703
|
+
if (response) {
|
|
1704
|
+
const out = `Content-Length: ${Buffer.byteLength(response)}\r
|
|
1705
|
+
\r
|
|
1706
|
+
${response}`;
|
|
1707
|
+
process.stdout.write(out);
|
|
1708
|
+
}
|
|
1709
|
+
} catch (err) {
|
|
1710
|
+
const errResp = jsonRpcError(null, -32700, "Parse error");
|
|
1711
|
+
const out = `Content-Length: ${Buffer.byteLength(errResp)}\r
|
|
1712
|
+
\r
|
|
1713
|
+
${errResp}`;
|
|
1714
|
+
process.stdout.write(out);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// src/cli.ts
|
|
1721
|
+
var command = process.argv[2];
|
|
1722
|
+
switch (command) {
|
|
1723
|
+
case "mcp":
|
|
1724
|
+
await startMcpServer();
|
|
1725
|
+
break;
|
|
1726
|
+
case "login": {
|
|
1727
|
+
const existing = loadCredentials();
|
|
1728
|
+
if (existing) {
|
|
1729
|
+
console.log("Already authenticated. Use `logout` first to re-authenticate.");
|
|
1730
|
+
process.exit(0);
|
|
1731
|
+
}
|
|
1732
|
+
console.log("Opening browser to authenticate...");
|
|
1733
|
+
const result = await startAuthFlow();
|
|
1734
|
+
if (result.success) {
|
|
1735
|
+
console.log("Authenticated successfully.");
|
|
1736
|
+
} else {
|
|
1737
|
+
console.error(`Authentication failed: ${result.error}`);
|
|
1738
|
+
process.exit(1);
|
|
1739
|
+
}
|
|
1740
|
+
break;
|
|
1741
|
+
}
|
|
1742
|
+
case "logout": {
|
|
1743
|
+
const removed = clearCredentials();
|
|
1744
|
+
console.log(removed ? "Logged out." : "No credentials found.");
|
|
1745
|
+
break;
|
|
1746
|
+
}
|
|
1747
|
+
case "status": {
|
|
1748
|
+
const creds = loadCredentials();
|
|
1749
|
+
if (creds) {
|
|
1750
|
+
console.log(`Authenticated since ${creds.createdAt}`);
|
|
1751
|
+
console.log(`API key: ${creds.apiKey.slice(0, 6)}...${creds.apiKey.slice(-4)}`);
|
|
1752
|
+
} else {
|
|
1753
|
+
console.log("Not authenticated. Run `cursor-supermemory login` to connect.");
|
|
1754
|
+
}
|
|
1755
|
+
break;
|
|
1756
|
+
}
|
|
1757
|
+
default:
|
|
1758
|
+
console.log(`cursor-supermemory — Persistent AI memory for Cursor
|
|
1759
|
+
|
|
1760
|
+
Commands:
|
|
1761
|
+
mcp Start the MCP server (stdio)
|
|
1762
|
+
login Authenticate with Supermemory
|
|
1763
|
+
logout Remove stored credentials
|
|
1764
|
+
status Show authentication status`);
|
|
1765
|
+
if (command)
|
|
1766
|
+
process.exit(1);
|
|
1767
|
+
}
|