@memoraone/mcp 0.1.38 → 0.1.40
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/dist/cli.cjs +10630 -2440
- package/dist/daemon.cjs +634 -90
- package/dist/index.cjs +770 -226
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -39,8 +39,8 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
|
39
39
|
|
|
40
40
|
// src/config.ts
|
|
41
41
|
var process2 = __toESM(require("process"), 1);
|
|
42
|
-
var
|
|
43
|
-
var
|
|
42
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
43
|
+
var path3 = __toESM(require("path"), 1);
|
|
44
44
|
var dotenv = __toESM(require("dotenv"), 1);
|
|
45
45
|
var import_v4 = require("zod/v4");
|
|
46
46
|
|
|
@@ -62,9 +62,130 @@ function resolveApiUrl(env2) {
|
|
|
62
62
|
return DEFAULT_API_URL;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// src/socketPaths.ts
|
|
66
|
+
var os = __toESM(require("os"), 1);
|
|
67
|
+
var path2 = __toESM(require("path"), 1);
|
|
68
|
+
var fs = __toESM(require("fs"), 1);
|
|
69
|
+
|
|
70
|
+
// src/bindingIdentity.ts
|
|
71
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
72
|
+
var path = __toESM(require("path"), 1);
|
|
73
|
+
var BINDING_SOCKET_HASH_LENGTH = 16;
|
|
74
|
+
function hashBindingIdentity(repositoryBindingId, workspaceRoot, ideType) {
|
|
75
|
+
const input = [
|
|
76
|
+
repositoryBindingId.trim(),
|
|
77
|
+
path.resolve(workspaceRoot),
|
|
78
|
+
ideType
|
|
79
|
+
].join("|");
|
|
80
|
+
return crypto.createHash("sha256").update(input).digest("hex").slice(0, BINDING_SOCKET_HASH_LENGTH);
|
|
81
|
+
}
|
|
82
|
+
function bindingsMatch(a, b) {
|
|
83
|
+
const envA = a.environment ?? void 0;
|
|
84
|
+
const envB = b.environment ?? void 0;
|
|
85
|
+
return a.repositoryBindingId === b.repositoryBindingId && a.projectId.trim().toLowerCase() === b.projectId.trim().toLowerCase() && path.resolve(a.workspaceRoot) === path.resolve(b.workspaceRoot) && (a.installationPublicId ?? void 0) === (b.installationPublicId ?? void 0) && envA === envB && a.status === b.status;
|
|
86
|
+
}
|
|
87
|
+
function formatMissingInitializeWorkspaceError(options) {
|
|
88
|
+
const lines = [
|
|
89
|
+
"[memoraone-mcp] Could not resolve workspace from MCP initialize params."
|
|
90
|
+
];
|
|
91
|
+
if (options?.rootsListAttempted) {
|
|
92
|
+
lines.push(
|
|
93
|
+
"Cursor initialize lacked workspaceFolders/rootUri; roots/list was attempted but returned no usable repo root."
|
|
94
|
+
);
|
|
95
|
+
if (options.rootsListUris && options.rootsListUris.length > 0) {
|
|
96
|
+
lines.push(`roots/list URIs: ${options.rootsListUris.join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
lines.push(
|
|
99
|
+
"Global Cursor MCP cannot safely bind per-window repos without a workspace signal from Cursor (initialize roots or roots/list)."
|
|
100
|
+
);
|
|
101
|
+
lines.push(
|
|
102
|
+
"Reload MCP in this Cursor window, or ensure this repo has a managed .cursor/mcp.json from setup-ide-files --cursor."
|
|
103
|
+
);
|
|
104
|
+
return lines.join("\n");
|
|
105
|
+
}
|
|
106
|
+
lines.push(
|
|
107
|
+
"Reload MCP in this Cursor window so initialize includes workspaceFolders, rootUri, or a usable roots/list response for this repo."
|
|
108
|
+
);
|
|
109
|
+
return lines.join("\n");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/socketPaths.ts
|
|
113
|
+
var BASE_DIR = process.env.MEMORAONE_MCP_LOCK_DIR || path2.join(os.homedir(), ".memoraone-mcp");
|
|
114
|
+
var HASH_SOCKET_FILENAME_RE = new RegExp(
|
|
115
|
+
`^mcp-[0-9a-f]{${BINDING_SOCKET_HASH_LENGTH}}\\.sock$`,
|
|
116
|
+
"i"
|
|
117
|
+
);
|
|
118
|
+
var IDE_TYPES = [
|
|
119
|
+
"cursor",
|
|
120
|
+
"copilot-vscode",
|
|
121
|
+
"jetbrains",
|
|
122
|
+
"claude-code",
|
|
123
|
+
"windsurf",
|
|
124
|
+
"opencode",
|
|
125
|
+
"codex",
|
|
126
|
+
"zed",
|
|
127
|
+
"kiro",
|
|
128
|
+
"visual-studio",
|
|
129
|
+
"cline",
|
|
130
|
+
"roo-code",
|
|
131
|
+
// dormant: unsupported for setup/connect
|
|
132
|
+
"auggie",
|
|
133
|
+
"continue",
|
|
134
|
+
// dormant: unsupported for setup/connect
|
|
135
|
+
"copilot-cli",
|
|
136
|
+
"kiro-cli",
|
|
137
|
+
"cline-cli",
|
|
138
|
+
"continue-cli",
|
|
139
|
+
// dormant: unsupported (no writer; wire id only)
|
|
140
|
+
"claude-desktop",
|
|
141
|
+
"gemini-cli",
|
|
142
|
+
// dormant: individual-user CLI unsupported; writer kept internal
|
|
143
|
+
"antigravity",
|
|
144
|
+
"antigravity-cli",
|
|
145
|
+
// Antigravity CLI (agy); shares MCP config with IDE; identity from clientInfo
|
|
146
|
+
"goose",
|
|
147
|
+
"junie",
|
|
148
|
+
"xcode",
|
|
149
|
+
"copilot-jetbrains",
|
|
150
|
+
"copilot-visual-studio"
|
|
151
|
+
];
|
|
152
|
+
var IDE_TYPE_SET = new Set(IDE_TYPES);
|
|
153
|
+
var IDE_TYPE_CLI_CHOICES = IDE_TYPES.join("|");
|
|
154
|
+
var IDE_TYPE_ALTERNATION = [...IDE_TYPES].sort((a, b) => b.length - a.length).join("|");
|
|
155
|
+
var LEGACY_SOCKET_FILENAME_RE = new RegExp(
|
|
156
|
+
`^mcp-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:-([0-9a-f]{12}))?(?:-(${IDE_TYPE_ALTERNATION}))?\\.sock$`,
|
|
157
|
+
"i"
|
|
158
|
+
);
|
|
159
|
+
var IDE_FROM_COMMAND_LINE_RE = new RegExp(
|
|
160
|
+
`--ide\\s+(${IDE_TYPE_ALTERNATION})(?:\\s|$)`
|
|
161
|
+
);
|
|
162
|
+
function parseIdeType(value) {
|
|
163
|
+
if (value === void 0 || value.trim() === "" || !IDE_TYPE_SET.has(value)) {
|
|
164
|
+
return void 0;
|
|
165
|
+
}
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
function resolveIdeTypeFromEnv(env2 = process.env) {
|
|
169
|
+
return parseIdeType(env2.MEMORAONE_IDE_TYPE);
|
|
170
|
+
}
|
|
171
|
+
function resolveBindingIdeType(env2 = process.env, ideTypeOverride) {
|
|
172
|
+
if (ideTypeOverride !== void 0) {
|
|
173
|
+
return ideTypeOverride;
|
|
174
|
+
}
|
|
175
|
+
return resolveIdeTypeFromEnv(env2) ?? "";
|
|
176
|
+
}
|
|
177
|
+
function getBindingSocketFilename(binding, env2 = process.env, ideTypeOverride) {
|
|
178
|
+
const ideType = resolveBindingIdeType(env2, ideTypeOverride);
|
|
179
|
+
const hash = hashBindingIdentity(binding.repositoryBindingId, binding.workspaceRoot, ideType);
|
|
180
|
+
return `mcp-${hash}.sock`;
|
|
181
|
+
}
|
|
182
|
+
function getBindingSocketPath(binding, env2 = process.env, ideTypeOverride) {
|
|
183
|
+
return path2.join(BASE_DIR, getBindingSocketFilename(binding, env2, ideTypeOverride));
|
|
184
|
+
}
|
|
185
|
+
|
|
65
186
|
// src/config.ts
|
|
66
|
-
var dotenvPath =
|
|
67
|
-
if (
|
|
187
|
+
var dotenvPath = path3.resolve(process2.cwd(), ".env");
|
|
188
|
+
if (fs2.existsSync(dotenvPath)) {
|
|
68
189
|
try {
|
|
69
190
|
dotenv.config({ path: dotenvPath });
|
|
70
191
|
} catch (err) {
|
|
@@ -78,7 +199,7 @@ var EnvSchema = import_v4.z.object({
|
|
|
78
199
|
MEMORAONE_AGENT_NAME: import_v4.z.string().min(1).optional(),
|
|
79
200
|
MEMORAONE_AGENT_TYPE: import_v4.z.string().min(1).optional(),
|
|
80
201
|
MEMORAONE_SOURCE: import_v4.z.string().min(1).optional(),
|
|
81
|
-
MEMORAONE_IDE_TYPE: import_v4.z.enum(
|
|
202
|
+
MEMORAONE_IDE_TYPE: import_v4.z.enum(IDE_TYPES).optional(),
|
|
82
203
|
MEMORAONE_WORKLOG: import_v4.z.string().min(1).optional(),
|
|
83
204
|
MEMORAONE_HEARTBEAT: import_v4.z.string().min(1).optional(),
|
|
84
205
|
MEMORAONE_HEARTBEAT_INTERVAL_MS: import_v4.z.string().min(1).optional()
|
|
@@ -127,11 +248,13 @@ var config2 = {
|
|
|
127
248
|
devMode: parseBooleanFlag(parsed.data.MEMORAONE_DEV_MODE, false),
|
|
128
249
|
worklogEnabled: parseBooleanFlag(parsed.data.MEMORAONE_WORKLOG, true),
|
|
129
250
|
heartbeatEnabled: parseBooleanFlag(parsed.data.MEMORAONE_HEARTBEAT, true),
|
|
130
|
-
|
|
251
|
+
// Cadence is owned by LOCAL_MCP_HEARTBEAT_INTERVAL_MS in heartbeat.ts (1_000).
|
|
252
|
+
// Env override is accepted for forward-compat but the timer path ignores it.
|
|
253
|
+
heartbeatIntervalMs: Number.parseInt(parsed.data.MEMORAONE_HEARTBEAT_INTERVAL_MS ?? "1000", 10)
|
|
131
254
|
};
|
|
132
255
|
|
|
133
256
|
// src/client/memoraClient.ts
|
|
134
|
-
var
|
|
257
|
+
var crypto2 = __toESM(require("crypto"), 1);
|
|
135
258
|
|
|
136
259
|
// src/localState/installationCredentials.ts
|
|
137
260
|
var import_node_crypto2 = require("crypto");
|
|
@@ -344,39 +467,39 @@ function hasUsableAccessToken(payload) {
|
|
|
344
467
|
}
|
|
345
468
|
|
|
346
469
|
// src/localState/localLocks.ts
|
|
347
|
-
var
|
|
470
|
+
var fs4 = __toESM(require("fs/promises"), 1);
|
|
348
471
|
|
|
349
472
|
// src/localState/atomicFs.ts
|
|
350
|
-
var
|
|
351
|
-
var
|
|
473
|
+
var fs3 = __toESM(require("fs/promises"), 1);
|
|
474
|
+
var path4 = __toESM(require("path"), 1);
|
|
352
475
|
var import_node_crypto3 = require("crypto");
|
|
353
476
|
var STATE_DIR_MODE = 448;
|
|
354
477
|
var STATE_FILE_MODE = 384;
|
|
355
478
|
async function ensurePrivateDir(dirPath) {
|
|
356
|
-
await
|
|
479
|
+
await fs3.mkdir(dirPath, { recursive: true, mode: STATE_DIR_MODE });
|
|
357
480
|
try {
|
|
358
|
-
await
|
|
481
|
+
await fs3.chmod(dirPath, STATE_DIR_MODE);
|
|
359
482
|
} catch {
|
|
360
483
|
}
|
|
361
484
|
}
|
|
362
485
|
async function writeFileAtomic(filePath, content, options = {}) {
|
|
363
486
|
const mode = options.mode ?? STATE_FILE_MODE;
|
|
364
|
-
const dir =
|
|
487
|
+
const dir = path4.dirname(filePath);
|
|
365
488
|
await ensurePrivateDir(dir);
|
|
366
|
-
const tmpPath =
|
|
489
|
+
const tmpPath = path4.join(
|
|
367
490
|
dir,
|
|
368
|
-
`.${
|
|
491
|
+
`.${path4.basename(filePath)}.${process.pid}.${(0, import_node_crypto3.randomBytes)(8).toString("hex")}.tmp`
|
|
369
492
|
);
|
|
370
493
|
try {
|
|
371
|
-
await
|
|
372
|
-
await
|
|
494
|
+
await fs3.writeFile(tmpPath, content, { encoding: "utf8", mode });
|
|
495
|
+
await fs3.rename(tmpPath, filePath);
|
|
373
496
|
try {
|
|
374
|
-
await
|
|
497
|
+
await fs3.chmod(filePath, mode);
|
|
375
498
|
} catch {
|
|
376
499
|
}
|
|
377
500
|
} catch (err) {
|
|
378
501
|
try {
|
|
379
|
-
await
|
|
502
|
+
await fs3.unlink(tmpPath);
|
|
380
503
|
} catch {
|
|
381
504
|
}
|
|
382
505
|
throw err;
|
|
@@ -384,7 +507,7 @@ async function writeFileAtomic(filePath, content, options = {}) {
|
|
|
384
507
|
}
|
|
385
508
|
async function readJsonFile(filePath) {
|
|
386
509
|
try {
|
|
387
|
-
const raw = await
|
|
510
|
+
const raw = await fs3.readFile(filePath, "utf8");
|
|
388
511
|
return JSON.parse(raw);
|
|
389
512
|
} catch (err) {
|
|
390
513
|
if (err?.code === "ENOENT") {
|
|
@@ -402,26 +525,26 @@ async function writeJsonAtomic(filePath, value, options = {}) {
|
|
|
402
525
|
}
|
|
403
526
|
|
|
404
527
|
// src/localState/statePaths.ts
|
|
405
|
-
var
|
|
406
|
-
var
|
|
528
|
+
var os2 = __toESM(require("os"), 1);
|
|
529
|
+
var path5 = __toESM(require("path"), 1);
|
|
407
530
|
var MEMORAONE_STATE_DIRNAME = ".memoraone";
|
|
408
|
-
function getMemoraoneStateDir(homeDir =
|
|
409
|
-
return
|
|
531
|
+
function getMemoraoneStateDir(homeDir = os2.homedir()) {
|
|
532
|
+
return path5.join(homeDir, MEMORAONE_STATE_DIRNAME);
|
|
410
533
|
}
|
|
411
|
-
function getPathIndexPath(homeDir =
|
|
412
|
-
return
|
|
534
|
+
function getPathIndexPath(homeDir = os2.homedir()) {
|
|
535
|
+
return path5.join(getMemoraoneStateDir(homeDir), "path-index.json");
|
|
413
536
|
}
|
|
414
|
-
function getBindingsDir(homeDir =
|
|
415
|
-
return
|
|
537
|
+
function getBindingsDir(homeDir = os2.homedir()) {
|
|
538
|
+
return path5.join(getMemoraoneStateDir(homeDir), "bindings");
|
|
416
539
|
}
|
|
417
|
-
function getBindingFilePath(repositoryBindingId, homeDir =
|
|
418
|
-
return
|
|
540
|
+
function getBindingFilePath(repositoryBindingId, homeDir = os2.homedir()) {
|
|
541
|
+
return path5.join(getBindingsDir(homeDir), `${repositoryBindingId}.json`);
|
|
419
542
|
}
|
|
420
|
-
function getLocksDir(homeDir =
|
|
421
|
-
return
|
|
543
|
+
function getLocksDir(homeDir = os2.homedir()) {
|
|
544
|
+
return path5.join(getMemoraoneStateDir(homeDir), "locks");
|
|
422
545
|
}
|
|
423
|
-
function getLockPath(lockName, homeDir =
|
|
424
|
-
return
|
|
546
|
+
function getLockPath(lockName, homeDir = os2.homedir()) {
|
|
547
|
+
return path5.join(getLocksDir(homeDir), `${lockName}.lock`);
|
|
425
548
|
}
|
|
426
549
|
|
|
427
550
|
// src/localState/localLocks.ts
|
|
@@ -436,16 +559,16 @@ async function acquireLocalLock(lockName, options = {}) {
|
|
|
436
559
|
while (retries <= maxRetries) {
|
|
437
560
|
try {
|
|
438
561
|
try {
|
|
439
|
-
const stat3 = await
|
|
562
|
+
const stat3 = await fs4.stat(lockPath);
|
|
440
563
|
if (Date.now() - stat3.mtimeMs > maxLockAgeMs) {
|
|
441
|
-
await
|
|
564
|
+
await fs4.unlink(lockPath);
|
|
442
565
|
}
|
|
443
566
|
} catch (err) {
|
|
444
567
|
if (err?.code !== "ENOENT") {
|
|
445
568
|
throw err;
|
|
446
569
|
}
|
|
447
570
|
}
|
|
448
|
-
const fd = await
|
|
571
|
+
const fd = await fs4.open(lockPath, "wx");
|
|
449
572
|
await fd.writeFile(
|
|
450
573
|
JSON.stringify({
|
|
451
574
|
pid: process.pid,
|
|
@@ -456,7 +579,7 @@ async function acquireLocalLock(lockName, options = {}) {
|
|
|
456
579
|
await fd.close();
|
|
457
580
|
return async () => {
|
|
458
581
|
try {
|
|
459
|
-
await
|
|
582
|
+
await fs4.unlink(lockPath);
|
|
460
583
|
} catch (err) {
|
|
461
584
|
if (err?.code !== "ENOENT") {
|
|
462
585
|
}
|
|
@@ -595,8 +718,8 @@ async function refreshInstallationAccessToken(options) {
|
|
|
595
718
|
}
|
|
596
719
|
|
|
597
720
|
// src/localState/bindingStore.ts
|
|
598
|
-
var
|
|
599
|
-
var
|
|
721
|
+
var fs5 = __toESM(require("fs/promises"), 1);
|
|
722
|
+
var path6 = __toESM(require("path"), 1);
|
|
600
723
|
|
|
601
724
|
// src/localState/bindingRecord.ts
|
|
602
725
|
var BINDING_RECORD_VERSION = 1;
|
|
@@ -827,7 +950,7 @@ var MemoraClient = class {
|
|
|
827
950
|
};
|
|
828
951
|
}
|
|
829
952
|
async perform(method, path14, body, options, retried = false) {
|
|
830
|
-
const nonce =
|
|
953
|
+
const nonce = crypto2.randomBytes(8).toString("hex");
|
|
831
954
|
const url = `${this.baseUrl}${path14.startsWith("/") ? path14 : `/${path14}`}`;
|
|
832
955
|
this.resolveProjectId();
|
|
833
956
|
console.error(
|
|
@@ -891,20 +1014,20 @@ var MemoraClient = class {
|
|
|
891
1014
|
var memoraClient_default = MemoraClient;
|
|
892
1015
|
|
|
893
1016
|
// src/projectBinding.ts
|
|
894
|
-
var
|
|
895
|
-
var
|
|
1017
|
+
var fs8 = __toESM(require("fs/promises"), 1);
|
|
1018
|
+
var path10 = __toESM(require("path"), 1);
|
|
896
1019
|
|
|
897
1020
|
// src/localState/resolveLocalBinding.ts
|
|
898
|
-
var
|
|
899
|
-
var
|
|
1021
|
+
var fs7 = __toESM(require("fs/promises"), 1);
|
|
1022
|
+
var path9 = __toESM(require("path"), 1);
|
|
900
1023
|
|
|
901
1024
|
// src/localState/pathIndex.ts
|
|
902
|
-
var
|
|
1025
|
+
var path8 = __toESM(require("path"), 1);
|
|
903
1026
|
|
|
904
1027
|
// src/localState/rootFilesystemIdentity.ts
|
|
905
|
-
var
|
|
906
|
-
var
|
|
907
|
-
var
|
|
1028
|
+
var fs6 = __toESM(require("fs/promises"), 1);
|
|
1029
|
+
var os3 = __toESM(require("os"), 1);
|
|
1030
|
+
var path7 = __toESM(require("path"), 1);
|
|
908
1031
|
var import_node_child_process = require("child_process");
|
|
909
1032
|
var import_node_util = require("util");
|
|
910
1033
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
@@ -929,13 +1052,13 @@ async function readDarwinDeviceId() {
|
|
|
929
1052
|
}
|
|
930
1053
|
async function readLinuxDeviceId() {
|
|
931
1054
|
try {
|
|
932
|
-
const content = await
|
|
1055
|
+
const content = await fs6.readFile("/etc/machine-id", "utf8");
|
|
933
1056
|
const id = content.trim();
|
|
934
1057
|
if (id) return id;
|
|
935
1058
|
} catch {
|
|
936
1059
|
}
|
|
937
1060
|
try {
|
|
938
|
-
const content = await
|
|
1061
|
+
const content = await fs6.readFile("/var/lib/dbus/machine-id", "utf8");
|
|
939
1062
|
const id = content.trim();
|
|
940
1063
|
if (id) return id;
|
|
941
1064
|
} catch {
|
|
@@ -955,7 +1078,7 @@ async function readWindowsDeviceId() {
|
|
|
955
1078
|
}
|
|
956
1079
|
return match[1].trim();
|
|
957
1080
|
}
|
|
958
|
-
async function resolveDeviceId(platform2 =
|
|
1081
|
+
async function resolveDeviceId(platform2 = os3.platform()) {
|
|
959
1082
|
if (platform2 === "darwin") return readDarwinDeviceId();
|
|
960
1083
|
if (platform2 === "linux") return readLinuxDeviceId();
|
|
961
1084
|
if (platform2 === "win32") return readWindowsDeviceId();
|
|
@@ -968,10 +1091,10 @@ async function resolveDeviceId(platform2 = os2.platform()) {
|
|
|
968
1091
|
throw new Error(`[memoraone-mcp] Unsupported platform for device ID: ${platform2}`);
|
|
969
1092
|
}
|
|
970
1093
|
async function captureRootFilesystemIdentity(rootPath, deps = {}) {
|
|
971
|
-
const resolved =
|
|
972
|
-
const platform2 = deps.platform ??
|
|
1094
|
+
const resolved = path7.resolve(rootPath);
|
|
1095
|
+
const platform2 = deps.platform ?? os3.platform();
|
|
973
1096
|
const statRoot = deps.statRoot ?? (async (p) => {
|
|
974
|
-
const st2 = await
|
|
1097
|
+
const st2 = await fs6.stat(p);
|
|
975
1098
|
return {
|
|
976
1099
|
ino: st2.ino,
|
|
977
1100
|
dev: st2.dev,
|
|
@@ -1055,7 +1178,7 @@ async function savePathIndex(index, homeDir) {
|
|
|
1055
1178
|
await writeJsonAtomic(getPathIndexPath(homeDir), next);
|
|
1056
1179
|
}
|
|
1057
1180
|
function lookupPathIndex(index, workspaceRoot, identity) {
|
|
1058
|
-
const resolved =
|
|
1181
|
+
const resolved = path8.resolve(workspaceRoot);
|
|
1059
1182
|
const byPathId = index.byPath[resolved];
|
|
1060
1183
|
if (byPathId) {
|
|
1061
1184
|
return { kind: "path", repositoryBindingId: assertRepositoryBindingId(byPathId) };
|
|
@@ -1081,14 +1204,14 @@ function lookupPathIndex(index, workspaceRoot, identity) {
|
|
|
1081
1204
|
}
|
|
1082
1205
|
async function upsertPathIndexEntry(options) {
|
|
1083
1206
|
const repositoryBindingId = assertRepositoryBindingId(options.repositoryBindingId);
|
|
1084
|
-
const resolved =
|
|
1207
|
+
const resolved = path8.resolve(options.workspaceRoot);
|
|
1085
1208
|
const identityKey = filesystemIdentityKey(options.identity);
|
|
1086
1209
|
return withLocalLock(
|
|
1087
1210
|
"path-index",
|
|
1088
1211
|
async () => {
|
|
1089
1212
|
const index = await loadPathIndex(options.homeDir);
|
|
1090
|
-
if (options.previousPath &&
|
|
1091
|
-
delete index.byPath[
|
|
1213
|
+
if (options.previousPath && path8.resolve(options.previousPath) !== resolved) {
|
|
1214
|
+
delete index.byPath[path8.resolve(options.previousPath)];
|
|
1092
1215
|
}
|
|
1093
1216
|
for (const [p, id] of Object.entries(index.byPath)) {
|
|
1094
1217
|
if (id === repositoryBindingId && p !== resolved) {
|
|
@@ -1114,16 +1237,16 @@ function identityMatchesStored(stored, current) {
|
|
|
1114
1237
|
|
|
1115
1238
|
// src/localState/resolveLocalBinding.ts
|
|
1116
1239
|
async function detectLegacyM1Warning(workspaceRoot) {
|
|
1117
|
-
const candidate =
|
|
1240
|
+
const candidate = path9.join(path9.resolve(workspaceRoot), CANONICAL_M1_FILENAME);
|
|
1118
1241
|
try {
|
|
1119
|
-
await
|
|
1242
|
+
await fs7.access(candidate);
|
|
1120
1243
|
return candidate;
|
|
1121
1244
|
} catch {
|
|
1122
1245
|
return void 0;
|
|
1123
1246
|
}
|
|
1124
1247
|
}
|
|
1125
1248
|
async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
|
|
1126
|
-
const resolved =
|
|
1249
|
+
const resolved = path9.resolve(workspaceRoot);
|
|
1127
1250
|
const identity = await captureRootFilesystemIdentity(resolved, options.identityDeps);
|
|
1128
1251
|
const legacyM1WarningPath = await detectLegacyM1Warning(resolved);
|
|
1129
1252
|
const index = await loadPathIndex(options.homeDir);
|
|
@@ -1131,7 +1254,7 @@ async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
|
|
|
1131
1254
|
if (lookup.kind === "path") {
|
|
1132
1255
|
const record = await readBindingRecord(lookup.repositoryBindingId, options.homeDir);
|
|
1133
1256
|
if (record && identityMatchesStored(record.filesystemIdentity, identity)) {
|
|
1134
|
-
if (
|
|
1257
|
+
if (path9.resolve(record.workspaceRoot) !== resolved) {
|
|
1135
1258
|
const updated = {
|
|
1136
1259
|
...record,
|
|
1137
1260
|
workspaceRoot: resolved,
|
|
@@ -1193,7 +1316,7 @@ async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
|
|
|
1193
1316
|
};
|
|
1194
1317
|
}
|
|
1195
1318
|
async function resolveLocalBinding(workspaceRoot, options = {}) {
|
|
1196
|
-
const resolved =
|
|
1319
|
+
const resolved = path9.resolve(workspaceRoot);
|
|
1197
1320
|
const { repositoryBindingId, legacyM1WarningPath } = await ensureRepositoryBindingForRoot(
|
|
1198
1321
|
resolved,
|
|
1199
1322
|
{ ...options, createIfMissing: false }
|
|
@@ -1257,9 +1380,9 @@ function toResolvedBinding(local) {
|
|
|
1257
1380
|
};
|
|
1258
1381
|
}
|
|
1259
1382
|
async function warnLegacyM1IfPresent(workspaceRoot) {
|
|
1260
|
-
const candidate =
|
|
1383
|
+
const candidate = path10.join(path10.resolve(workspaceRoot), CANONICAL_M1_FILENAME);
|
|
1261
1384
|
try {
|
|
1262
|
-
await
|
|
1385
|
+
await fs8.access(candidate);
|
|
1263
1386
|
process.stderr.write(
|
|
1264
1387
|
`[memoraone-mcp] warning: ignoring legacy ${CANONICAL_M1_FILENAME} (not used for credentials or binding)
|
|
1265
1388
|
`
|
|
@@ -1316,7 +1439,7 @@ function normalizeWorkspaceSearchRoots(workspaceRoot) {
|
|
|
1316
1439
|
if (raw === void 0) continue;
|
|
1317
1440
|
const trimmed = String(raw).trim();
|
|
1318
1441
|
if (trimmed === "") continue;
|
|
1319
|
-
const resolved =
|
|
1442
|
+
const resolved = path10.resolve(trimmed);
|
|
1320
1443
|
if (!seen.has(resolved)) {
|
|
1321
1444
|
seen.add(resolved);
|
|
1322
1445
|
out.push(resolved);
|
|
@@ -1327,7 +1450,7 @@ function normalizeWorkspaceSearchRoots(workspaceRoot) {
|
|
|
1327
1450
|
function bindingRelevantValuesMatch(a, b) {
|
|
1328
1451
|
const envA = a.environment ?? void 0;
|
|
1329
1452
|
const envB = b.environment ?? void 0;
|
|
1330
|
-
return a.repositoryBindingId === b.repositoryBindingId && a.projectId.trim().toLowerCase() === b.projectId.trim().toLowerCase() &&
|
|
1453
|
+
return a.repositoryBindingId === b.repositoryBindingId && a.projectId.trim().toLowerCase() === b.projectId.trim().toLowerCase() && path10.resolve(a.workspaceRoot) === path10.resolve(b.workspaceRoot) && (a.installationPublicId ?? void 0) === (b.installationPublicId ?? void 0) && envA === envB && a.status === b.status;
|
|
1331
1454
|
}
|
|
1332
1455
|
async function reconcileResolvedBindingWithDisk(cached) {
|
|
1333
1456
|
const repositoryBindingId = assertRepositoryBindingId(cached.repositoryBindingId);
|
|
@@ -1337,7 +1460,7 @@ async function reconcileResolvedBindingWithDisk(cached) {
|
|
|
1337
1460
|
`[memoraone-mcp] Cached binding missing for ${repositoryBindingId}. Run: memoraone-mcp connect <code>`
|
|
1338
1461
|
);
|
|
1339
1462
|
}
|
|
1340
|
-
const workspaceRoot =
|
|
1463
|
+
const workspaceRoot = path10.resolve(record.workspaceRoot);
|
|
1341
1464
|
const identity = await captureRootFilesystemIdentity(workspaceRoot);
|
|
1342
1465
|
if (!identitiesMatch(record.filesystemIdentity, identity)) {
|
|
1343
1466
|
throw new ReconnectRequiredError(
|
|
@@ -1379,82 +1502,6 @@ function encodeResolvedBinding(binding) {
|
|
|
1379
1502
|
// src/initializeBinding.ts
|
|
1380
1503
|
var path11 = __toESM(require("path"), 1);
|
|
1381
1504
|
var import_node_url = require("url");
|
|
1382
|
-
|
|
1383
|
-
// src/bindingIdentity.ts
|
|
1384
|
-
var crypto2 = __toESM(require("crypto"), 1);
|
|
1385
|
-
var path9 = __toESM(require("path"), 1);
|
|
1386
|
-
var BINDING_SOCKET_HASH_LENGTH = 16;
|
|
1387
|
-
function hashBindingIdentity(repositoryBindingId, workspaceRoot, ideType) {
|
|
1388
|
-
const input = [
|
|
1389
|
-
repositoryBindingId.trim(),
|
|
1390
|
-
path9.resolve(workspaceRoot),
|
|
1391
|
-
ideType
|
|
1392
|
-
].join("|");
|
|
1393
|
-
return crypto2.createHash("sha256").update(input).digest("hex").slice(0, BINDING_SOCKET_HASH_LENGTH);
|
|
1394
|
-
}
|
|
1395
|
-
function bindingsMatch(a, b) {
|
|
1396
|
-
const envA = a.environment ?? void 0;
|
|
1397
|
-
const envB = b.environment ?? void 0;
|
|
1398
|
-
return a.repositoryBindingId === b.repositoryBindingId && a.projectId.trim().toLowerCase() === b.projectId.trim().toLowerCase() && path9.resolve(a.workspaceRoot) === path9.resolve(b.workspaceRoot) && (a.installationPublicId ?? void 0) === (b.installationPublicId ?? void 0) && envA === envB && a.status === b.status;
|
|
1399
|
-
}
|
|
1400
|
-
function formatMissingInitializeWorkspaceError(options) {
|
|
1401
|
-
const lines = [
|
|
1402
|
-
"[memoraone-mcp] Could not resolve workspace from MCP initialize params."
|
|
1403
|
-
];
|
|
1404
|
-
if (options?.rootsListAttempted) {
|
|
1405
|
-
lines.push(
|
|
1406
|
-
"Cursor initialize lacked workspaceFolders/rootUri; roots/list was attempted but returned no usable repo root."
|
|
1407
|
-
);
|
|
1408
|
-
if (options.rootsListUris && options.rootsListUris.length > 0) {
|
|
1409
|
-
lines.push(`roots/list URIs: ${options.rootsListUris.join(", ")}`);
|
|
1410
|
-
}
|
|
1411
|
-
lines.push(
|
|
1412
|
-
"Global Cursor MCP cannot safely bind per-window repos without a workspace signal from Cursor (initialize roots or roots/list)."
|
|
1413
|
-
);
|
|
1414
|
-
lines.push(
|
|
1415
|
-
"Reload MCP in this Cursor window, or ensure this repo has a managed .cursor/mcp.json from setup-ide-files --cursor."
|
|
1416
|
-
);
|
|
1417
|
-
return lines.join("\n");
|
|
1418
|
-
}
|
|
1419
|
-
lines.push(
|
|
1420
|
-
"Reload MCP in this Cursor window so initialize includes workspaceFolders, rootUri, or a usable roots/list response for this repo."
|
|
1421
|
-
);
|
|
1422
|
-
return lines.join("\n");
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
// src/socketPaths.ts
|
|
1426
|
-
var os3 = __toESM(require("os"), 1);
|
|
1427
|
-
var path10 = __toESM(require("path"), 1);
|
|
1428
|
-
var fs8 = __toESM(require("fs"), 1);
|
|
1429
|
-
var BASE_DIR = process.env.MEMORAONE_MCP_LOCK_DIR || path10.join(os3.homedir(), ".memoraone-mcp");
|
|
1430
|
-
var HASH_SOCKET_FILENAME_RE = new RegExp(
|
|
1431
|
-
`^mcp-[0-9a-f]{${BINDING_SOCKET_HASH_LENGTH}}\\.sock$`,
|
|
1432
|
-
"i"
|
|
1433
|
-
);
|
|
1434
|
-
var IDE_TYPES = ["cursor", "copilot-vscode", "jetbrains"];
|
|
1435
|
-
var IDE_TYPE_SET = new Set(IDE_TYPES);
|
|
1436
|
-
function parseIdeType(value) {
|
|
1437
|
-
if (value === void 0 || value.trim() === "" || !IDE_TYPE_SET.has(value)) {
|
|
1438
|
-
return void 0;
|
|
1439
|
-
}
|
|
1440
|
-
return value;
|
|
1441
|
-
}
|
|
1442
|
-
function resolveIdeTypeFromEnv(env2 = process.env) {
|
|
1443
|
-
return parseIdeType(env2.MEMORAONE_IDE_TYPE);
|
|
1444
|
-
}
|
|
1445
|
-
function resolveBindingIdeType(env2 = process.env) {
|
|
1446
|
-
return resolveIdeTypeFromEnv(env2) ?? "";
|
|
1447
|
-
}
|
|
1448
|
-
function getBindingSocketFilename(binding, env2 = process.env) {
|
|
1449
|
-
const ideType = resolveBindingIdeType(env2);
|
|
1450
|
-
const hash = hashBindingIdentity(binding.repositoryBindingId, binding.workspaceRoot, ideType);
|
|
1451
|
-
return `mcp-${hash}.sock`;
|
|
1452
|
-
}
|
|
1453
|
-
function getBindingSocketPath(binding, env2 = process.env) {
|
|
1454
|
-
return path10.join(BASE_DIR, getBindingSocketFilename(binding, env2));
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
// src/initializeBinding.ts
|
|
1458
1505
|
var MEMORAONE_WORKSPACE_ROOT_ENV = "MEMORAONE_WORKSPACE_ROOT";
|
|
1459
1506
|
function getBridgeBindingResolveOptions(env2 = process.env) {
|
|
1460
1507
|
const ideType = resolveIdeTypeFromEnv(env2);
|
|
@@ -1770,8 +1817,79 @@ var logCommandShape = {
|
|
|
1770
1817
|
// src/tools/bindingStatus.ts
|
|
1771
1818
|
var bindingStatusShape = {};
|
|
1772
1819
|
|
|
1773
|
-
// src/tools/
|
|
1820
|
+
// src/tools/listTimeline.ts
|
|
1774
1821
|
var import_v411 = require("zod/v4");
|
|
1822
|
+
var listTimelineDescription = "List timeline events for the project bound to this Local MCP installation.";
|
|
1823
|
+
var listTimelineInputSchema = import_v411.z.object({
|
|
1824
|
+
since: import_v411.z.string().optional(),
|
|
1825
|
+
concept: import_v411.z.string().optional(),
|
|
1826
|
+
kind: import_v411.z.union([import_v411.z.string(), import_v411.z.array(import_v411.z.string())]).optional(),
|
|
1827
|
+
sort: import_v411.z.enum(["newest", "oldest"]).optional(),
|
|
1828
|
+
limit: import_v411.z.number().int().min(1).max(200).optional(),
|
|
1829
|
+
cursor: import_v411.z.string().optional()
|
|
1830
|
+
}).strict();
|
|
1831
|
+
|
|
1832
|
+
// src/tools/listConcepts.ts
|
|
1833
|
+
var import_v412 = require("zod/v4");
|
|
1834
|
+
var listConceptsDescription = "List concepts for the project bound to this Local MCP installation.";
|
|
1835
|
+
var listConceptsInputSchema = import_v412.z.object({
|
|
1836
|
+
q: import_v412.z.string().min(1).optional(),
|
|
1837
|
+
tag: import_v412.z.string().min(1).optional(),
|
|
1838
|
+
parent_id: import_v412.z.string().min(1).optional(),
|
|
1839
|
+
limit: import_v412.z.number().int().min(1).max(200).optional(),
|
|
1840
|
+
cursor: import_v412.z.string().min(1).optional()
|
|
1841
|
+
}).strict();
|
|
1842
|
+
|
|
1843
|
+
// src/tools/getConcept.ts
|
|
1844
|
+
var import_v413 = require("zod/v4");
|
|
1845
|
+
var getConceptDescription = "Get one concept by ID from the project bound to this Local MCP installation.";
|
|
1846
|
+
var getConceptInputSchema = import_v413.z.object({
|
|
1847
|
+
id: import_v413.z.string().trim().min(1)
|
|
1848
|
+
}).strict();
|
|
1849
|
+
|
|
1850
|
+
// src/tools/createConceptVersion.ts
|
|
1851
|
+
var import_v414 = require("zod/v4");
|
|
1852
|
+
var createConceptVersionDescription = "Create a version of a concept in the project bound to this Local MCP installation.";
|
|
1853
|
+
var createConceptVersionInputSchema = import_v414.z.object({
|
|
1854
|
+
id: import_v414.z.string().trim().min(1),
|
|
1855
|
+
value: import_v414.z.unknown(),
|
|
1856
|
+
reason: import_v414.z.string().optional(),
|
|
1857
|
+
confidence: import_v414.z.number().finite().min(0).max(1).optional(),
|
|
1858
|
+
source_ref: import_v414.z.string().optional(),
|
|
1859
|
+
tags: import_v414.z.array(import_v414.z.string()).optional(),
|
|
1860
|
+
parent_id: import_v414.z.union([import_v414.z.string(), import_v414.z.null()]).optional()
|
|
1861
|
+
}).strict();
|
|
1862
|
+
function isJsonValue(value) {
|
|
1863
|
+
if (value === null) return true;
|
|
1864
|
+
if (typeof value === "boolean" || typeof value === "string") return true;
|
|
1865
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
1866
|
+
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
1867
|
+
if (typeof value !== "object") return false;
|
|
1868
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1869
|
+
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
1870
|
+
return Object.values(value).every(isJsonValue);
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
// src/tools/toolInventory.ts
|
|
1874
|
+
var LOCAL_MCP_TOOL_NAMES = [
|
|
1875
|
+
"memora_ask_with_memory",
|
|
1876
|
+
"memora_post_event",
|
|
1877
|
+
"memora_create_fact",
|
|
1878
|
+
"memora_add_personal_context",
|
|
1879
|
+
"memora_get_personal_context",
|
|
1880
|
+
"memora_log_intent",
|
|
1881
|
+
"memora_log_change_summary",
|
|
1882
|
+
"memora_log_tool_result",
|
|
1883
|
+
"memora_log_command",
|
|
1884
|
+
"memora_status",
|
|
1885
|
+
"memora_list_timeline",
|
|
1886
|
+
"memora_list_concepts",
|
|
1887
|
+
"memora_get_concept",
|
|
1888
|
+
"memora_create_concept_version"
|
|
1889
|
+
];
|
|
1890
|
+
|
|
1891
|
+
// src/tools/handlers/postEvent.ts
|
|
1892
|
+
var import_v415 = require("zod/v4");
|
|
1775
1893
|
var crypto4 = __toESM(require("crypto"), 1);
|
|
1776
1894
|
|
|
1777
1895
|
// src/runContext.ts
|
|
@@ -1827,14 +1945,14 @@ function generateRunId() {
|
|
|
1827
1945
|
}
|
|
1828
1946
|
|
|
1829
1947
|
// src/tools/handlers/postEvent.ts
|
|
1830
|
-
var postEventInputSchema =
|
|
1831
|
-
kind:
|
|
1832
|
-
actor:
|
|
1833
|
-
identifier:
|
|
1834
|
-
id:
|
|
1948
|
+
var postEventInputSchema = import_v415.z.object({
|
|
1949
|
+
kind: import_v415.z.string().min(1),
|
|
1950
|
+
actor: import_v415.z.object({
|
|
1951
|
+
identifier: import_v415.z.string().min(1),
|
|
1952
|
+
id: import_v415.z.string().min(1).optional()
|
|
1835
1953
|
}),
|
|
1836
|
-
content:
|
|
1837
|
-
metadata:
|
|
1954
|
+
content: import_v415.z.record(import_v415.z.string(), import_v415.z.any()),
|
|
1955
|
+
metadata: import_v415.z.record(import_v415.z.string(), import_v415.z.any()).optional()
|
|
1838
1956
|
});
|
|
1839
1957
|
function buildPostEventContentFields(content) {
|
|
1840
1958
|
if (typeof content.message === "string") {
|
|
@@ -1906,10 +2024,10 @@ async function handlePostEvent(client, args) {
|
|
|
1906
2024
|
}
|
|
1907
2025
|
|
|
1908
2026
|
// src/tools/handlers/createFact.ts
|
|
1909
|
-
var
|
|
1910
|
-
var createFactInputSchema =
|
|
1911
|
-
content:
|
|
1912
|
-
metadata:
|
|
2027
|
+
var import_v416 = require("zod/v4");
|
|
2028
|
+
var createFactInputSchema = import_v416.z.object({
|
|
2029
|
+
content: import_v416.z.string().min(1),
|
|
2030
|
+
metadata: import_v416.z.record(import_v416.z.string(), import_v416.z.any()).optional()
|
|
1913
2031
|
});
|
|
1914
2032
|
async function handleCreateFact(client, args) {
|
|
1915
2033
|
const parsed2 = createFactInputSchema.parse(args ?? {});
|
|
@@ -1954,13 +2072,13 @@ async function handleCreateFact(client, args) {
|
|
|
1954
2072
|
}
|
|
1955
2073
|
|
|
1956
2074
|
// src/tools/handlers/addPersonalContext.ts
|
|
1957
|
-
var
|
|
1958
|
-
var addPersonalContextInputSchema =
|
|
1959
|
-
content:
|
|
1960
|
-
category:
|
|
1961
|
-
tags:
|
|
1962
|
-
scope_type:
|
|
1963
|
-
scope_id:
|
|
2075
|
+
var import_v417 = require("zod/v4");
|
|
2076
|
+
var addPersonalContextInputSchema = import_v417.z.object({
|
|
2077
|
+
content: import_v417.z.string().min(1),
|
|
2078
|
+
category: import_v417.z.string().optional(),
|
|
2079
|
+
tags: import_v417.z.array(import_v417.z.string()).optional(),
|
|
2080
|
+
scope_type: import_v417.z.enum(["general", "project"]).optional(),
|
|
2081
|
+
scope_id: import_v417.z.string().optional()
|
|
1964
2082
|
});
|
|
1965
2083
|
async function handleAddPersonalContext(client, args) {
|
|
1966
2084
|
const parsed2 = addPersonalContextInputSchema.parse(args ?? {});
|
|
@@ -1996,12 +2114,12 @@ async function handleAddPersonalContext(client, args) {
|
|
|
1996
2114
|
}
|
|
1997
2115
|
|
|
1998
2116
|
// src/tools/handlers/getPersonalContext.ts
|
|
1999
|
-
var
|
|
2000
|
-
var getPersonalContextInputSchema =
|
|
2001
|
-
query:
|
|
2002
|
-
scope_type:
|
|
2003
|
-
scope_id:
|
|
2004
|
-
limit:
|
|
2117
|
+
var import_v418 = require("zod/v4");
|
|
2118
|
+
var getPersonalContextInputSchema = import_v418.z.object({
|
|
2119
|
+
query: import_v418.z.string().optional(),
|
|
2120
|
+
scope_type: import_v418.z.enum(["general", "project"]).optional(),
|
|
2121
|
+
scope_id: import_v418.z.string().optional(),
|
|
2122
|
+
limit: import_v418.z.number().int().positive().optional()
|
|
2005
2123
|
});
|
|
2006
2124
|
function buildPersonalContextPath(parsed2) {
|
|
2007
2125
|
const params = new URLSearchParams();
|
|
@@ -2038,13 +2156,13 @@ async function handleGetPersonalContext(client, args) {
|
|
|
2038
2156
|
}
|
|
2039
2157
|
|
|
2040
2158
|
// src/tools/handlers/askWithMemory.ts
|
|
2041
|
-
var
|
|
2042
|
-
var askWithMemoryInputSchema =
|
|
2043
|
-
question:
|
|
2044
|
-
code_context:
|
|
2045
|
-
file_path:
|
|
2046
|
-
selected_text:
|
|
2047
|
-
language:
|
|
2159
|
+
var import_v419 = require("zod/v4");
|
|
2160
|
+
var askWithMemoryInputSchema = import_v419.z.object({
|
|
2161
|
+
question: import_v419.z.string().min(1),
|
|
2162
|
+
code_context: import_v419.z.object({
|
|
2163
|
+
file_path: import_v419.z.string().optional(),
|
|
2164
|
+
selected_text: import_v419.z.string().optional(),
|
|
2165
|
+
language: import_v419.z.string().optional()
|
|
2048
2166
|
}).optional()
|
|
2049
2167
|
});
|
|
2050
2168
|
function isAskWithMemoryResponse(value) {
|
|
@@ -2080,13 +2198,13 @@ async function handleAskWithMemory(client, args) {
|
|
|
2080
2198
|
}
|
|
2081
2199
|
|
|
2082
2200
|
// src/tools/handlers/logIntent.ts
|
|
2083
|
-
var
|
|
2084
|
-
var logIntentInputSchema =
|
|
2085
|
-
intent:
|
|
2086
|
-
message:
|
|
2087
|
-
context:
|
|
2088
|
-
intent_source:
|
|
2089
|
-
run_id:
|
|
2201
|
+
var import_v420 = require("zod/v4");
|
|
2202
|
+
var logIntentInputSchema = import_v420.z.object({
|
|
2203
|
+
intent: import_v420.z.enum(["task", "decision"]),
|
|
2204
|
+
message: import_v420.z.string().min(1),
|
|
2205
|
+
context: import_v420.z.record(import_v420.z.string(), import_v420.z.any()).optional(),
|
|
2206
|
+
intent_source: import_v420.z.string().optional().default("cursor_chat"),
|
|
2207
|
+
run_id: import_v420.z.string().min(1).optional()
|
|
2090
2208
|
});
|
|
2091
2209
|
async function handleLogIntent(client, args) {
|
|
2092
2210
|
const parsed2 = logIntentInputSchema.parse(args ?? {});
|
|
@@ -2128,18 +2246,18 @@ async function handleLogIntent(client, args) {
|
|
|
2128
2246
|
}
|
|
2129
2247
|
|
|
2130
2248
|
// src/tools/handlers/logChangeSummary.ts
|
|
2131
|
-
var
|
|
2132
|
-
var logChangeSummaryInputSchema =
|
|
2133
|
-
summary:
|
|
2134
|
-
scope:
|
|
2135
|
-
files:
|
|
2136
|
-
stats:
|
|
2137
|
-
files:
|
|
2138
|
-
add:
|
|
2139
|
-
del:
|
|
2249
|
+
var import_v421 = require("zod/v4");
|
|
2250
|
+
var logChangeSummaryInputSchema = import_v421.z.object({
|
|
2251
|
+
summary: import_v421.z.string().min(1),
|
|
2252
|
+
scope: import_v421.z.string().min(1).optional(),
|
|
2253
|
+
files: import_v421.z.array(import_v421.z.string().min(1)).optional(),
|
|
2254
|
+
stats: import_v421.z.object({
|
|
2255
|
+
files: import_v421.z.number().int().nonnegative().optional(),
|
|
2256
|
+
add: import_v421.z.number().int().nonnegative().optional(),
|
|
2257
|
+
del: import_v421.z.number().int().nonnegative().optional()
|
|
2140
2258
|
}).optional(),
|
|
2141
|
-
commit:
|
|
2142
|
-
run_id:
|
|
2259
|
+
commit: import_v421.z.string().min(1).optional(),
|
|
2260
|
+
run_id: import_v421.z.string().min(1).optional()
|
|
2143
2261
|
});
|
|
2144
2262
|
async function handleLogChangeSummary(client, args) {
|
|
2145
2263
|
const parsed2 = logChangeSummaryInputSchema.parse(args ?? {});
|
|
@@ -2174,17 +2292,17 @@ async function handleLogChangeSummary(client, args) {
|
|
|
2174
2292
|
}
|
|
2175
2293
|
|
|
2176
2294
|
// src/tools/handlers/logToolResult.ts
|
|
2177
|
-
var
|
|
2178
|
-
var logToolResultInputSchema =
|
|
2179
|
-
tool:
|
|
2180
|
-
status:
|
|
2181
|
-
summary:
|
|
2182
|
-
run_id:
|
|
2183
|
-
duration_ms:
|
|
2184
|
-
error_code:
|
|
2185
|
-
error_message:
|
|
2186
|
-
error_kind:
|
|
2187
|
-
stats:
|
|
2295
|
+
var import_v422 = require("zod/v4");
|
|
2296
|
+
var logToolResultInputSchema = import_v422.z.object({
|
|
2297
|
+
tool: import_v422.z.string().min(1),
|
|
2298
|
+
status: import_v422.z.enum(["ok", "error", "partial"]),
|
|
2299
|
+
summary: import_v422.z.string().min(1),
|
|
2300
|
+
run_id: import_v422.z.string().min(1).optional(),
|
|
2301
|
+
duration_ms: import_v422.z.number().int().nonnegative().optional(),
|
|
2302
|
+
error_code: import_v422.z.string().min(1).optional(),
|
|
2303
|
+
error_message: import_v422.z.string().min(1).optional(),
|
|
2304
|
+
error_kind: import_v422.z.enum(["infra", "logic", "auth", "rate_limit", "validation", "unknown"]).optional(),
|
|
2305
|
+
stats: import_v422.z.record(import_v422.z.string(), import_v422.z.any()).optional()
|
|
2188
2306
|
});
|
|
2189
2307
|
async function handleLogToolResult(client, args) {
|
|
2190
2308
|
const parsed2 = logToolResultInputSchema.parse(args ?? {});
|
|
@@ -2222,15 +2340,15 @@ async function handleLogToolResult(client, args) {
|
|
|
2222
2340
|
}
|
|
2223
2341
|
|
|
2224
2342
|
// src/tools/handlers/logCommand.ts
|
|
2225
|
-
var
|
|
2226
|
-
var logCommandInputSchema =
|
|
2227
|
-
cmd:
|
|
2228
|
-
summary:
|
|
2229
|
-
cwd:
|
|
2230
|
-
exit_code:
|
|
2231
|
-
duration_ms:
|
|
2232
|
-
run_id:
|
|
2233
|
-
stats:
|
|
2343
|
+
var import_v423 = require("zod/v4");
|
|
2344
|
+
var logCommandInputSchema = import_v423.z.object({
|
|
2345
|
+
cmd: import_v423.z.string().min(1),
|
|
2346
|
+
summary: import_v423.z.string().min(1),
|
|
2347
|
+
cwd: import_v423.z.string().min(1).optional(),
|
|
2348
|
+
exit_code: import_v423.z.number().int().optional(),
|
|
2349
|
+
duration_ms: import_v423.z.number().int().nonnegative().optional(),
|
|
2350
|
+
run_id: import_v423.z.string().min(1).optional(),
|
|
2351
|
+
stats: import_v423.z.record(import_v423.z.string(), import_v423.z.any()).optional()
|
|
2234
2352
|
});
|
|
2235
2353
|
async function handleLogCommand(client, args) {
|
|
2236
2354
|
const parsed2 = logCommandInputSchema.parse(args ?? {});
|
|
@@ -2265,6 +2383,244 @@ async function handleLogCommand(client, args) {
|
|
|
2265
2383
|
return { ok: true };
|
|
2266
2384
|
}
|
|
2267
2385
|
|
|
2386
|
+
// src/tools/responseProjection.ts
|
|
2387
|
+
var timelineItemKeys = [
|
|
2388
|
+
"id",
|
|
2389
|
+
"ts",
|
|
2390
|
+
"kind",
|
|
2391
|
+
"concept",
|
|
2392
|
+
"old_value",
|
|
2393
|
+
"new_value",
|
|
2394
|
+
"reason",
|
|
2395
|
+
"confidence",
|
|
2396
|
+
"links",
|
|
2397
|
+
"source_ref",
|
|
2398
|
+
"redacted",
|
|
2399
|
+
"redaction_reason",
|
|
2400
|
+
"summary",
|
|
2401
|
+
"consolidated_of"
|
|
2402
|
+
];
|
|
2403
|
+
var conceptVersionKeys = [
|
|
2404
|
+
"version",
|
|
2405
|
+
"ts",
|
|
2406
|
+
"reason",
|
|
2407
|
+
"confidence",
|
|
2408
|
+
"source_ref",
|
|
2409
|
+
"value"
|
|
2410
|
+
];
|
|
2411
|
+
function invalidResponse() {
|
|
2412
|
+
throw new Error("Invalid Memora response");
|
|
2413
|
+
}
|
|
2414
|
+
function isRecord(value) {
|
|
2415
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2416
|
+
}
|
|
2417
|
+
function pickFields(raw, keys) {
|
|
2418
|
+
const result = {};
|
|
2419
|
+
for (const key of keys) {
|
|
2420
|
+
if (Object.prototype.hasOwnProperty.call(raw, key) && raw[key] !== void 0) {
|
|
2421
|
+
result[key] = raw[key];
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
return result;
|
|
2425
|
+
}
|
|
2426
|
+
function pickConceptVersion(raw) {
|
|
2427
|
+
return pickFields(raw, conceptVersionKeys);
|
|
2428
|
+
}
|
|
2429
|
+
function pickConceptItem(raw) {
|
|
2430
|
+
if (typeof raw.id !== "string" || raw.id.trim() === "") invalidResponse();
|
|
2431
|
+
const item = { id: raw.id };
|
|
2432
|
+
if (Object.prototype.hasOwnProperty.call(raw, "tags")) {
|
|
2433
|
+
if (!Array.isArray(raw.tags) || !raw.tags.every((tag) => typeof tag === "string")) {
|
|
2434
|
+
invalidResponse();
|
|
2435
|
+
}
|
|
2436
|
+
item.tags = raw.tags;
|
|
2437
|
+
}
|
|
2438
|
+
if (Object.prototype.hasOwnProperty.call(raw, "parent_id")) {
|
|
2439
|
+
if (raw.parent_id !== null && typeof raw.parent_id !== "string") invalidResponse();
|
|
2440
|
+
item.parent_id = raw.parent_id;
|
|
2441
|
+
}
|
|
2442
|
+
if (Object.prototype.hasOwnProperty.call(raw, "latest")) {
|
|
2443
|
+
if (raw.latest === null) {
|
|
2444
|
+
item.latest = null;
|
|
2445
|
+
} else if (isRecord(raw.latest)) {
|
|
2446
|
+
item.latest = pickConceptVersion(raw.latest);
|
|
2447
|
+
} else {
|
|
2448
|
+
invalidResponse();
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
return item;
|
|
2452
|
+
}
|
|
2453
|
+
function normalizeCursor(raw) {
|
|
2454
|
+
for (const key of ["next_cursor", "nextCursor"]) {
|
|
2455
|
+
if (!Object.prototype.hasOwnProperty.call(raw, key)) continue;
|
|
2456
|
+
const value = raw[key];
|
|
2457
|
+
if (value === null) return null;
|
|
2458
|
+
if (typeof value === "string") return value;
|
|
2459
|
+
invalidResponse();
|
|
2460
|
+
}
|
|
2461
|
+
return null;
|
|
2462
|
+
}
|
|
2463
|
+
function projectTimelineResponse(data) {
|
|
2464
|
+
if (!isRecord(data) || !Array.isArray(data.items) || !isRecord(data.page)) {
|
|
2465
|
+
invalidResponse();
|
|
2466
|
+
}
|
|
2467
|
+
if (typeof data.page.limit !== "number" || !Number.isFinite(data.page.limit) || data.page.sort !== "newest" && data.page.sort !== "oldest") {
|
|
2468
|
+
invalidResponse();
|
|
2469
|
+
}
|
|
2470
|
+
const items = data.items.map((entry) => {
|
|
2471
|
+
if (!isRecord(entry)) invalidResponse();
|
|
2472
|
+
return pickFields(entry, timelineItemKeys);
|
|
2473
|
+
});
|
|
2474
|
+
return {
|
|
2475
|
+
items,
|
|
2476
|
+
page: {
|
|
2477
|
+
limit: data.page.limit,
|
|
2478
|
+
sort: data.page.sort,
|
|
2479
|
+
next_cursor: normalizeCursor(data.page)
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
function projectConceptListResponse(data, requestedLimit) {
|
|
2484
|
+
if (!isRecord(data)) invalidResponse();
|
|
2485
|
+
let entries;
|
|
2486
|
+
if (Object.prototype.hasOwnProperty.call(data, "rows")) {
|
|
2487
|
+
entries = data.rows;
|
|
2488
|
+
} else if (Object.prototype.hasOwnProperty.call(data, "items")) {
|
|
2489
|
+
entries = data.items;
|
|
2490
|
+
} else {
|
|
2491
|
+
invalidResponse();
|
|
2492
|
+
}
|
|
2493
|
+
if (!Array.isArray(entries)) invalidResponse();
|
|
2494
|
+
let cursorSource = data;
|
|
2495
|
+
if (!Object.prototype.hasOwnProperty.call(data, "next_cursor") && !Object.prototype.hasOwnProperty.call(data, "nextCursor") && Object.prototype.hasOwnProperty.call(data, "page")) {
|
|
2496
|
+
if (!isRecord(data.page)) invalidResponse();
|
|
2497
|
+
cursorSource = data.page;
|
|
2498
|
+
}
|
|
2499
|
+
return {
|
|
2500
|
+
items: entries.map((entry) => {
|
|
2501
|
+
if (!isRecord(entry)) invalidResponse();
|
|
2502
|
+
return pickConceptItem(entry);
|
|
2503
|
+
}),
|
|
2504
|
+
page: {
|
|
2505
|
+
limit: requestedLimit ?? 50,
|
|
2506
|
+
next_cursor: normalizeCursor(cursorSource)
|
|
2507
|
+
}
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
function projectConceptResponse(data) {
|
|
2511
|
+
if (!isRecord(data)) invalidResponse();
|
|
2512
|
+
const item = pickConceptItem(data);
|
|
2513
|
+
if (!Object.prototype.hasOwnProperty.call(data, "history")) {
|
|
2514
|
+
return { ...item, history: [] };
|
|
2515
|
+
}
|
|
2516
|
+
if (!Array.isArray(data.history)) invalidResponse();
|
|
2517
|
+
const history = data.history.map((entry) => {
|
|
2518
|
+
if (!isRecord(entry)) invalidResponse();
|
|
2519
|
+
return pickConceptVersion(entry);
|
|
2520
|
+
});
|
|
2521
|
+
return { ...item, history };
|
|
2522
|
+
}
|
|
2523
|
+
function projectCreatedConceptVersionResponse(data) {
|
|
2524
|
+
if (!isRecord(data)) invalidResponse();
|
|
2525
|
+
return pickConceptItem(data);
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
// src/tools/handlers/toolRequestError.ts
|
|
2529
|
+
function rethrowToolRequestError(toolName, error) {
|
|
2530
|
+
if (error instanceof SyntaxError) {
|
|
2531
|
+
throw new Error("Invalid Memora response");
|
|
2532
|
+
}
|
|
2533
|
+
if (!(error instanceof MemoraOneHttpError)) throw error;
|
|
2534
|
+
let detail = "request failed";
|
|
2535
|
+
if (error.status === 401) detail = "authentication failed";
|
|
2536
|
+
else if (error.status === 403) detail = "connection unavailable";
|
|
2537
|
+
else if (error.status === 404) detail = "resource not found";
|
|
2538
|
+
else if (error.status === 409) detail = "conflict";
|
|
2539
|
+
else if (error.status >= 500) detail = "backend error";
|
|
2540
|
+
throw new Error(`${toolName} failed: ${error.status} ${detail}`);
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
// src/tools/handlers/listTimeline.ts
|
|
2544
|
+
function buildQuery(input) {
|
|
2545
|
+
const parts = [];
|
|
2546
|
+
const append = (key, value) => {
|
|
2547
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
2548
|
+
};
|
|
2549
|
+
if (input.since !== void 0) append("since", input.since);
|
|
2550
|
+
if (input.concept !== void 0) append("concept", input.concept);
|
|
2551
|
+
if (input.kind !== void 0) {
|
|
2552
|
+
for (const kind of Array.isArray(input.kind) ? input.kind : [input.kind]) {
|
|
2553
|
+
append("kind", kind);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
if (input.sort !== void 0) append("sort", input.sort);
|
|
2557
|
+
if (input.limit !== void 0) append("limit", String(input.limit));
|
|
2558
|
+
if (input.cursor !== void 0) append("cursor", input.cursor);
|
|
2559
|
+
return parts.length === 0 ? "" : `?${parts.join("&")}`;
|
|
2560
|
+
}
|
|
2561
|
+
async function handleListTimeline(client, args) {
|
|
2562
|
+
const input = listTimelineInputSchema.parse(args ?? {});
|
|
2563
|
+
try {
|
|
2564
|
+
return projectTimelineResponse(await client.get(`/timeline${buildQuery(input)}`));
|
|
2565
|
+
} catch (error) {
|
|
2566
|
+
rethrowToolRequestError("memora_list_timeline", error);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
// src/tools/handlers/listConcepts.ts
|
|
2571
|
+
function buildQuery2(input) {
|
|
2572
|
+
const parts = [];
|
|
2573
|
+
const append = (key, value) => {
|
|
2574
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
2575
|
+
};
|
|
2576
|
+
if (input.q !== void 0) append("q", input.q);
|
|
2577
|
+
if (input.tag !== void 0) append("tag", input.tag);
|
|
2578
|
+
if (input.parent_id !== void 0) append("parent_id", input.parent_id);
|
|
2579
|
+
if (input.limit !== void 0) append("limit", String(input.limit));
|
|
2580
|
+
if (input.cursor !== void 0) append("cursor", input.cursor);
|
|
2581
|
+
return parts.length === 0 ? "" : `?${parts.join("&")}`;
|
|
2582
|
+
}
|
|
2583
|
+
async function handleListConcepts(client, args) {
|
|
2584
|
+
const input = listConceptsInputSchema.parse(args ?? {});
|
|
2585
|
+
try {
|
|
2586
|
+
const data = await client.get(`/concepts${buildQuery2(input)}`);
|
|
2587
|
+
return projectConceptListResponse(data, input.limit);
|
|
2588
|
+
} catch (error) {
|
|
2589
|
+
rethrowToolRequestError("memora_list_concepts", error);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
// src/tools/handlers/getConcept.ts
|
|
2594
|
+
async function handleGetConcept(client, args) {
|
|
2595
|
+
const input = getConceptInputSchema.parse(args ?? {});
|
|
2596
|
+
try {
|
|
2597
|
+
const data = await client.get(`/concepts/${encodeURIComponent(input.id)}`);
|
|
2598
|
+
return projectConceptResponse(data);
|
|
2599
|
+
} catch (error) {
|
|
2600
|
+
rethrowToolRequestError("memora_get_concept", error);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// src/tools/handlers/createConceptVersion.ts
|
|
2605
|
+
async function handleCreateConceptVersion(client, args) {
|
|
2606
|
+
const input = createConceptVersionInputSchema.parse(args ?? {});
|
|
2607
|
+
if (!isJsonValue(input.value)) {
|
|
2608
|
+
throw new Error("Invalid arguments: value must be a valid JSON value");
|
|
2609
|
+
}
|
|
2610
|
+
const body = { value: input.value };
|
|
2611
|
+
if (input.reason !== void 0) body.reason = input.reason;
|
|
2612
|
+
if (input.confidence !== void 0) body.confidence = input.confidence;
|
|
2613
|
+
if (input.source_ref !== void 0) body.source_ref = input.source_ref;
|
|
2614
|
+
if (input.tags !== void 0) body.tags = input.tags;
|
|
2615
|
+
if (input.parent_id !== void 0) body.parent_id = input.parent_id;
|
|
2616
|
+
try {
|
|
2617
|
+
const path14 = `/concepts/${encodeURIComponent(input.id)}/versions`;
|
|
2618
|
+
return projectCreatedConceptVersionResponse(await client.post(path14, body));
|
|
2619
|
+
} catch (error) {
|
|
2620
|
+
rethrowToolRequestError("memora_create_concept_version", error);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
|
|
2268
2624
|
// src/tools/handlers/bindingStatus.ts
|
|
2269
2625
|
function buildBindingStatus(binding, options = {}) {
|
|
2270
2626
|
const status = {
|
|
@@ -2315,8 +2671,9 @@ function isHeartbeatDebugEnabled() {
|
|
|
2315
2671
|
const value = String(process.env.MEMORAONE_DEBUG_HEARTBEAT ?? "").trim().toLowerCase();
|
|
2316
2672
|
return ["1", "true", "yes", "on"].includes(value);
|
|
2317
2673
|
}
|
|
2674
|
+
var LOCAL_MCP_HEARTBEAT_INTERVAL_MS = 1e3;
|
|
2318
2675
|
function resolveHeartbeatIntervalMs() {
|
|
2319
|
-
return
|
|
2676
|
+
return LOCAL_MCP_HEARTBEAT_INTERVAL_MS;
|
|
2320
2677
|
}
|
|
2321
2678
|
function redactSensitiveText(text) {
|
|
2322
2679
|
return text.replace(/mcs_[A-Za-z0-9_-]+/g, "mcs_[redacted]").replace(/mia_[A-Za-z0-9_-]+/g, "mia_[redacted]").replace(/mir_[A-Za-z0-9_-]+/g, "mir_[redacted]").replace(/mcc_[A-Za-z0-9_-]+/g, "mcc_[redacted]").replace(/Bearer\s+\S+/gi, "Bearer [redacted]");
|
|
@@ -2426,6 +2783,7 @@ async function sendProjectHeartbeat(client, ctx) {
|
|
|
2426
2783
|
}
|
|
2427
2784
|
function createDaemonHeartbeat(opts) {
|
|
2428
2785
|
let interval = null;
|
|
2786
|
+
let runGeneration = 0;
|
|
2429
2787
|
let client = null;
|
|
2430
2788
|
let announced = false;
|
|
2431
2789
|
let studioActive = null;
|
|
@@ -2494,21 +2852,24 @@ function createDaemonHeartbeat(opts) {
|
|
|
2494
2852
|
studioActive = true;
|
|
2495
2853
|
}
|
|
2496
2854
|
};
|
|
2497
|
-
const tick = async () => {
|
|
2498
|
-
if (!client) return;
|
|
2855
|
+
const tick = async (generation) => {
|
|
2856
|
+
if (!client || generation !== runGeneration) return;
|
|
2499
2857
|
const outcome = await sendProjectHeartbeat(client, ctx);
|
|
2858
|
+
if (generation !== runGeneration || !interval) return;
|
|
2500
2859
|
applyHeartbeatOutcome(outcome);
|
|
2501
2860
|
};
|
|
2502
2861
|
const beginInterval = () => {
|
|
2503
2862
|
if (interval) return;
|
|
2504
2863
|
const intervalMs = resolveHeartbeatIntervalMs();
|
|
2864
|
+
const generation = runGeneration;
|
|
2505
2865
|
log(
|
|
2506
2866
|
`daemon owns heartbeat for binding=${opts.binding.repositoryBindingId} project=${opts.binding.projectId} ideType=${ctx.ideType ?? "unknown"} interval=${intervalMs}ms`
|
|
2507
2867
|
);
|
|
2508
|
-
void tick();
|
|
2509
2868
|
interval = setInterval(() => {
|
|
2510
|
-
void tick();
|
|
2869
|
+
void tick(generation);
|
|
2511
2870
|
}, intervalMs);
|
|
2871
|
+
interval.unref?.();
|
|
2872
|
+
void tick(generation);
|
|
2512
2873
|
};
|
|
2513
2874
|
const start = async () => {
|
|
2514
2875
|
if (!config2.heartbeatEnabled) {
|
|
@@ -2541,6 +2902,7 @@ function createDaemonHeartbeat(opts) {
|
|
|
2541
2902
|
}
|
|
2542
2903
|
};
|
|
2543
2904
|
const stop = () => {
|
|
2905
|
+
runGeneration += 1;
|
|
2544
2906
|
if (interval) {
|
|
2545
2907
|
clearInterval(interval);
|
|
2546
2908
|
interval = null;
|
|
@@ -2560,7 +2922,7 @@ function createDaemonHeartbeat(opts) {
|
|
|
2560
2922
|
return;
|
|
2561
2923
|
}
|
|
2562
2924
|
if (client && interval) {
|
|
2563
|
-
void tick();
|
|
2925
|
+
void tick(runGeneration);
|
|
2564
2926
|
}
|
|
2565
2927
|
};
|
|
2566
2928
|
const getIdeType = () => ctx.ideType;
|
|
@@ -2580,12 +2942,125 @@ function createDaemonHeartbeat(opts) {
|
|
|
2580
2942
|
}
|
|
2581
2943
|
|
|
2582
2944
|
// src/ideType.ts
|
|
2945
|
+
var RELIABLE_CLIENT_INFO_NAMES = /* @__PURE__ */ new Map([
|
|
2946
|
+
// Existing
|
|
2947
|
+
["claude-code", "claude-code"],
|
|
2948
|
+
["devin", "windsurf"],
|
|
2949
|
+
["windsurf", "windsurf"],
|
|
2950
|
+
// Zed
|
|
2951
|
+
["zed", "zed"],
|
|
2952
|
+
// Kiro IDE (exact only — not generic "kiro …" mcp-remote wrappers)
|
|
2953
|
+
["kiro", "kiro"],
|
|
2954
|
+
// Visual Studio (never Visual Studio Code)
|
|
2955
|
+
["visual studio", "visual-studio"],
|
|
2956
|
+
["visual-studio", "visual-studio"],
|
|
2957
|
+
// Cline IDE
|
|
2958
|
+
["cline", "cline"],
|
|
2959
|
+
// Roo Code
|
|
2960
|
+
["roo code", "roo-code"],
|
|
2961
|
+
["roo-code", "roo-code"],
|
|
2962
|
+
// Auggie / Augment Code (canonical wire ID: auggie)
|
|
2963
|
+
["auggie", "auggie"],
|
|
2964
|
+
["augment", "auggie"],
|
|
2965
|
+
["augment code", "auggie"],
|
|
2966
|
+
["augment-code", "auggie"],
|
|
2967
|
+
// Continue IDE (not bare "continue")
|
|
2968
|
+
["continue-client", "continue"],
|
|
2969
|
+
// Continue CLI
|
|
2970
|
+
["continue-cli-client", "continue-cli"],
|
|
2971
|
+
["continue-cli", "continue-cli"],
|
|
2972
|
+
["continue cli", "continue-cli"],
|
|
2973
|
+
// Copilot CLI (not GitHub Copilot in VS Code)
|
|
2974
|
+
["github-copilot-developer", "copilot-cli"],
|
|
2975
|
+
["copilot-cli", "copilot-cli"],
|
|
2976
|
+
["copilot cli", "copilot-cli"],
|
|
2977
|
+
// Kiro CLI (explicit CLI names only — not Amazon Q / Q-DEV-CLI)
|
|
2978
|
+
["kiro-cli", "kiro-cli"],
|
|
2979
|
+
["kiro cli", "kiro-cli"],
|
|
2980
|
+
// Cline CLI
|
|
2981
|
+
["cline-cli", "cline-cli"],
|
|
2982
|
+
["cline cli", "cline-cli"],
|
|
2983
|
+
// Claude Desktop (never bare "claude"; never claude-code)
|
|
2984
|
+
["claude-ai", "claude-desktop"],
|
|
2985
|
+
["claude-desktop", "claude-desktop"],
|
|
2986
|
+
["claude desktop", "claude-desktop"],
|
|
2987
|
+
// Gemini CLI (not bare "gemini")
|
|
2988
|
+
["gemini-cli", "gemini-cli"],
|
|
2989
|
+
["gemini cli", "gemini-cli"],
|
|
2990
|
+
// Google Antigravity IDE vs CLI (shared MCP config; clientInfo distinguishes)
|
|
2991
|
+
["antigravity", "antigravity"],
|
|
2992
|
+
["antigravity ide", "antigravity"],
|
|
2993
|
+
["antigravity-client", "antigravity-cli"],
|
|
2994
|
+
// Goose
|
|
2995
|
+
["goose", "goose"],
|
|
2996
|
+
// JetBrains Junie (distinct from generic jetbrains / copilot-jetbrains)
|
|
2997
|
+
["junie", "junie"],
|
|
2998
|
+
// GitHub Copilot for Xcode
|
|
2999
|
+
["xcode", "xcode"],
|
|
3000
|
+
["copilot-xcode", "xcode"],
|
|
3001
|
+
["github-copilot-xcode", "xcode"],
|
|
3002
|
+
// GitHub Copilot for JetBrains (distinct from jetbrains AI Assistant)
|
|
3003
|
+
["copilot-jetbrains", "copilot-jetbrains"],
|
|
3004
|
+
["github-copilot-jetbrains", "copilot-jetbrains"],
|
|
3005
|
+
["github copilot jetbrains", "copilot-jetbrains"],
|
|
3006
|
+
// GitHub Copilot in Visual Studio (distinct from visual-studio / copilot-vscode)
|
|
3007
|
+
["copilot-visual-studio", "copilot-visual-studio"],
|
|
3008
|
+
["github-copilot-visual-studio", "copilot-visual-studio"],
|
|
3009
|
+
["github copilot visual studio", "copilot-visual-studio"]
|
|
3010
|
+
]);
|
|
3011
|
+
function mapReliableClientInfoName(name) {
|
|
3012
|
+
if (typeof name !== "string") {
|
|
3013
|
+
return void 0;
|
|
3014
|
+
}
|
|
3015
|
+
const normalized = name.trim().toLowerCase();
|
|
3016
|
+
if (normalized === "") {
|
|
3017
|
+
return void 0;
|
|
3018
|
+
}
|
|
3019
|
+
const exact = RELIABLE_CLIENT_INFO_NAMES.get(normalized);
|
|
3020
|
+
if (exact) {
|
|
3021
|
+
return exact;
|
|
3022
|
+
}
|
|
3023
|
+
if (/^windsurf[\s_-].+$/.test(normalized)) {
|
|
3024
|
+
return "windsurf";
|
|
3025
|
+
}
|
|
3026
|
+
return void 0;
|
|
3027
|
+
}
|
|
3028
|
+
function mapReliableHostIdentity(env2) {
|
|
3029
|
+
if (env2.WINDSURF_IDE_TYPE === "windsurf") {
|
|
3030
|
+
return "windsurf";
|
|
3031
|
+
}
|
|
3032
|
+
if (env2.ACP_BACKEND === "windsurf") {
|
|
3033
|
+
return "windsurf";
|
|
3034
|
+
}
|
|
3035
|
+
if (env2.__CFBundleIdentifier === "com.exafunction.windsurf") {
|
|
3036
|
+
return "windsurf";
|
|
3037
|
+
}
|
|
3038
|
+
if (env2.__CFBundleIdentifier === "com.anthropic.claudefordesktop") {
|
|
3039
|
+
return "claude-desktop";
|
|
3040
|
+
}
|
|
3041
|
+
if (env2.__CFBundleIdentifier === "dev.zed.Zed") {
|
|
3042
|
+
return "zed";
|
|
3043
|
+
}
|
|
3044
|
+
if (Object.prototype.hasOwnProperty.call(env2, "COPILOT_CLI")) {
|
|
3045
|
+
return "copilot-cli";
|
|
3046
|
+
}
|
|
3047
|
+
return void 0;
|
|
3048
|
+
}
|
|
2583
3049
|
function inferIdeType(params, options = {}) {
|
|
2584
3050
|
const env2 = options.env ?? process.env;
|
|
2585
3051
|
const argv = (options.argv ?? process.argv).join(" ").toLowerCase();
|
|
2586
|
-
const
|
|
2587
|
-
|
|
2588
|
-
|
|
3052
|
+
const hasExplicitConfigOption = Object.prototype.hasOwnProperty.call(options, "configIdeType");
|
|
3053
|
+
const explicitHint = hasExplicitConfigOption ? options.configIdeType : resolveIdeTypeFromEnv(env2) ?? config2.ideType;
|
|
3054
|
+
const fromClientInfo = mapReliableClientInfoName(params?.clientInfo?.name);
|
|
3055
|
+
if (fromClientInfo) {
|
|
3056
|
+
return fromClientInfo;
|
|
3057
|
+
}
|
|
3058
|
+
const fromHost = mapReliableHostIdentity(env2);
|
|
3059
|
+
if (fromHost) {
|
|
3060
|
+
return fromHost;
|
|
3061
|
+
}
|
|
3062
|
+
if (explicitHint) {
|
|
3063
|
+
return explicitHint;
|
|
2589
3064
|
}
|
|
2590
3065
|
const clientInfoName = String(params?.clientInfo?.name ?? "").toLowerCase();
|
|
2591
3066
|
const clientInfoVersion = String(params?.clientInfo?.version ?? "").toLowerCase();
|
|
@@ -2610,7 +3085,7 @@ function inferIdeType(params, options = {}) {
|
|
|
2610
3085
|
if (hasJetBrainsSignals) {
|
|
2611
3086
|
return "jetbrains";
|
|
2612
3087
|
}
|
|
2613
|
-
const hasVsCodeSignals = envKeys.some((key) => key.startsWith("VSCODE_")) || /(visual studio code|vscode|vs code
|
|
3088
|
+
const hasVsCodeSignals = envKeys.some((key) => key.startsWith("VSCODE_")) || /(visual studio code|vscode|vs code)/.test(clientInfoName) || /(visual studio code|vscode|vs code)/.test(argv);
|
|
2614
3089
|
if (hasVsCodeSignals) {
|
|
2615
3090
|
return "copilot-vscode";
|
|
2616
3091
|
}
|
|
@@ -2742,7 +3217,11 @@ async function main(opts = {}) {
|
|
|
2742
3217
|
`[memoraone-mcp] refreshed stale cached binding ${reconciled.binding.repositoryBindingId}: project=${reconciled.binding.projectId}`
|
|
2743
3218
|
);
|
|
2744
3219
|
try {
|
|
2745
|
-
const socketPath = getBindingSocketPath(
|
|
3220
|
+
const socketPath = getBindingSocketPath(
|
|
3221
|
+
opts.daemonBindingHint,
|
|
3222
|
+
process.env,
|
|
3223
|
+
runtime.ideType ?? ""
|
|
3224
|
+
);
|
|
2746
3225
|
writeBindingSidecar(socketPath, reconciled.binding, runtime.ideType ?? "");
|
|
2747
3226
|
} catch (err) {
|
|
2748
3227
|
console.error(
|
|
@@ -2935,6 +3414,71 @@ async function main(opts = {}) {
|
|
|
2935
3414
|
}
|
|
2936
3415
|
);
|
|
2937
3416
|
registeredToolNames.push("memora_log_command");
|
|
3417
|
+
server.registerTool(
|
|
3418
|
+
"memora_list_timeline",
|
|
3419
|
+
{
|
|
3420
|
+
description: listTimelineDescription,
|
|
3421
|
+
inputSchema: listTimelineInputSchema
|
|
3422
|
+
},
|
|
3423
|
+
async (args) => runWithSessionContext(sessionContext, async () => {
|
|
3424
|
+
if (!runtime.client || !runtime.projectId) return notInitializedResult;
|
|
3425
|
+
const result = await handleListTimeline(runtime.client, args);
|
|
3426
|
+
return {
|
|
3427
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
3428
|
+
};
|
|
3429
|
+
})
|
|
3430
|
+
);
|
|
3431
|
+
registeredToolNames.push("memora_list_timeline");
|
|
3432
|
+
server.registerTool(
|
|
3433
|
+
"memora_list_concepts",
|
|
3434
|
+
{
|
|
3435
|
+
description: listConceptsDescription,
|
|
3436
|
+
inputSchema: listConceptsInputSchema
|
|
3437
|
+
},
|
|
3438
|
+
async (args) => runWithSessionContext(sessionContext, async () => {
|
|
3439
|
+
if (!runtime.client || !runtime.projectId) return notInitializedResult;
|
|
3440
|
+
const result = await handleListConcepts(runtime.client, args);
|
|
3441
|
+
return {
|
|
3442
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
3443
|
+
};
|
|
3444
|
+
})
|
|
3445
|
+
);
|
|
3446
|
+
registeredToolNames.push("memora_list_concepts");
|
|
3447
|
+
server.registerTool(
|
|
3448
|
+
"memora_get_concept",
|
|
3449
|
+
{
|
|
3450
|
+
description: getConceptDescription,
|
|
3451
|
+
inputSchema: getConceptInputSchema
|
|
3452
|
+
},
|
|
3453
|
+
async (args) => runWithSessionContext(sessionContext, async () => {
|
|
3454
|
+
if (!runtime.client || !runtime.projectId) return notInitializedResult;
|
|
3455
|
+
const result = await handleGetConcept(runtime.client, args);
|
|
3456
|
+
return {
|
|
3457
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
3458
|
+
};
|
|
3459
|
+
})
|
|
3460
|
+
);
|
|
3461
|
+
registeredToolNames.push("memora_get_concept");
|
|
3462
|
+
server.registerTool(
|
|
3463
|
+
"memora_create_concept_version",
|
|
3464
|
+
{
|
|
3465
|
+
description: createConceptVersionDescription,
|
|
3466
|
+
inputSchema: createConceptVersionInputSchema
|
|
3467
|
+
},
|
|
3468
|
+
async (args) => runWithSessionContext(sessionContext, async () => {
|
|
3469
|
+
if (!runtime.client || !runtime.projectId) return notInitializedResult;
|
|
3470
|
+
const result = await handleCreateConceptVersion(runtime.client, args);
|
|
3471
|
+
return {
|
|
3472
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
3473
|
+
};
|
|
3474
|
+
})
|
|
3475
|
+
);
|
|
3476
|
+
registeredToolNames.push("memora_create_concept_version");
|
|
3477
|
+
if (registeredToolNames.length !== LOCAL_MCP_TOOL_NAMES.length || registeredToolNames.some(
|
|
3478
|
+
(name) => !LOCAL_MCP_TOOL_NAMES.includes(name)
|
|
3479
|
+
)) {
|
|
3480
|
+
throw new Error("Local MCP tool registration inventory mismatch");
|
|
3481
|
+
}
|
|
2938
3482
|
server.server.setRequestHandler(
|
|
2939
3483
|
import_types.InitializeRequestSchema,
|
|
2940
3484
|
async (request) => runWithSessionContext(sessionContext, async () => {
|