@memoraone/mcp 0.1.46 → 0.1.48
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 +176 -18
- package/dist/daemon.cjs +205 -29
- package/dist/index.cjs +202 -26
- package/dist/pluginPairing.cjs +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -231,7 +231,7 @@ var require_package = __commonJS({
|
|
|
231
231
|
"package.json"(exports2, module2) {
|
|
232
232
|
module2.exports = {
|
|
233
233
|
name: "@memoraone/mcp",
|
|
234
|
-
version: "0.1.
|
|
234
|
+
version: "0.1.48",
|
|
235
235
|
type: "module",
|
|
236
236
|
main: "dist/index.cjs",
|
|
237
237
|
exports: {
|
|
@@ -531,7 +531,7 @@ async function acquireLocalLock(lockName, options = {}) {
|
|
|
531
531
|
`[memoraone-mcp] Failed to acquire lock ${lockName} after ${maxRetries} retries`
|
|
532
532
|
);
|
|
533
533
|
}
|
|
534
|
-
await new Promise((
|
|
534
|
+
await new Promise((resolve44) => setTimeout(resolve44, retryDelayMs));
|
|
535
535
|
continue;
|
|
536
536
|
}
|
|
537
537
|
throw err;
|
|
@@ -1092,9 +1092,9 @@ var init_memoraClient = __esm({
|
|
|
1092
1092
|
});
|
|
1093
1093
|
|
|
1094
1094
|
// src/localState/localConnectClient.ts
|
|
1095
|
-
async function requestJson(baseUrl, method,
|
|
1095
|
+
async function requestJson(baseUrl, method, path48, options = {}) {
|
|
1096
1096
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1097
|
-
const url = `${baseUrl.replace(/\/+$/, "")}${
|
|
1097
|
+
const url = `${baseUrl.replace(/\/+$/, "")}${path48.startsWith("/") ? path48 : `/${path48}`}`;
|
|
1098
1098
|
const res = await fetchImpl(url, {
|
|
1099
1099
|
method,
|
|
1100
1100
|
headers: {
|
|
@@ -3950,7 +3950,7 @@ function formatOptionalJetBrainsHandshakeUnavailableDetail(detail) {
|
|
|
3950
3950
|
async function verifyJetBrainsMcpHandshake(options) {
|
|
3951
3951
|
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
3952
3952
|
const { server } = options;
|
|
3953
|
-
return new Promise((
|
|
3953
|
+
return new Promise((resolve44) => {
|
|
3954
3954
|
let settled = false;
|
|
3955
3955
|
const finish = (ok, detail, optionalUnavailable) => {
|
|
3956
3956
|
if (settled) return;
|
|
@@ -3960,7 +3960,7 @@ async function verifyJetBrainsMcpHandshake(options) {
|
|
|
3960
3960
|
child.kill();
|
|
3961
3961
|
} catch {
|
|
3962
3962
|
}
|
|
3963
|
-
|
|
3963
|
+
resolve44({ ok, detail, optionalUnavailable });
|
|
3964
3964
|
};
|
|
3965
3965
|
const child = (0, import_node_child_process4.spawn)(server.command, [...server.args], {
|
|
3966
3966
|
env: { ...process.env, ...server.env },
|
|
@@ -12854,7 +12854,7 @@ var init_pluginPairing = __esm({
|
|
|
12854
12854
|
ideType: this.source,
|
|
12855
12855
|
fetchImpl: this.connectOptions.fetchImpl ?? this.fetchImpl,
|
|
12856
12856
|
// Plugin pairing configures only the IDE that initiated the pairing.
|
|
12857
|
-
configureIdes:
|
|
12857
|
+
configureIdes: this.source !== "cursor",
|
|
12858
12858
|
setupIdeOptions: {
|
|
12859
12859
|
...this.connectOptions.setupIdeOptions,
|
|
12860
12860
|
targets: {
|
|
@@ -12993,13 +12993,13 @@ function writeEvent(event, stdoutWrite) {
|
|
|
12993
12993
|
}
|
|
12994
12994
|
function delay(ms, signal) {
|
|
12995
12995
|
if (ms <= 0 || signal?.aborted) return Promise.resolve();
|
|
12996
|
-
return new Promise((
|
|
12996
|
+
return new Promise((resolve44) => {
|
|
12997
12997
|
const timer = setTimeout(finish, ms);
|
|
12998
12998
|
const onAbort = () => finish();
|
|
12999
12999
|
function finish() {
|
|
13000
13000
|
clearTimeout(timer);
|
|
13001
13001
|
signal?.removeEventListener("abort", onAbort);
|
|
13002
|
-
|
|
13002
|
+
resolve44();
|
|
13003
13003
|
}
|
|
13004
13004
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
13005
13005
|
});
|
|
@@ -13442,8 +13442,8 @@ var init_bridgeClientRoots = __esm({
|
|
|
13442
13442
|
if (this.closed) {
|
|
13443
13443
|
return null;
|
|
13444
13444
|
}
|
|
13445
|
-
return new Promise((
|
|
13446
|
-
this.waiters.push(
|
|
13445
|
+
return new Promise((resolve44) => {
|
|
13446
|
+
this.waiters.push(resolve44);
|
|
13447
13447
|
});
|
|
13448
13448
|
}
|
|
13449
13449
|
/** Re-queue lines read during an intermediate protocol step (e.g. roots/list) for the main bridge loop. */
|
|
@@ -13463,6 +13463,153 @@ var init_bridgeClientRoots = __esm({
|
|
|
13463
13463
|
}
|
|
13464
13464
|
});
|
|
13465
13465
|
|
|
13466
|
+
// src/pluginStartupBindingWait.ts
|
|
13467
|
+
function errorMessage(err) {
|
|
13468
|
+
return err instanceof Error ? err.message : String(err);
|
|
13469
|
+
}
|
|
13470
|
+
function isUnboundPluginStartupBindingMessage(message) {
|
|
13471
|
+
return UNBOUND_MESSAGE_MARKERS.some((marker) => message.includes(marker));
|
|
13472
|
+
}
|
|
13473
|
+
function isCredentialsMissingMessage(message) {
|
|
13474
|
+
return message.includes(CREDENTIALS_MISSING_MARKER);
|
|
13475
|
+
}
|
|
13476
|
+
async function pendingBindingWindowOpen(isPendingBinding) {
|
|
13477
|
+
if (!isPendingBinding) {
|
|
13478
|
+
return false;
|
|
13479
|
+
}
|
|
13480
|
+
try {
|
|
13481
|
+
return Boolean(await isPendingBinding());
|
|
13482
|
+
} catch {
|
|
13483
|
+
return false;
|
|
13484
|
+
}
|
|
13485
|
+
}
|
|
13486
|
+
function shouldWaitForPluginStartupBinding(options = {}) {
|
|
13487
|
+
const env2 = options.env ?? process.env;
|
|
13488
|
+
if (env2[MEMORAONE_PLUGIN_ENV] !== MEMORAONE_CURSOR_PLUGIN) {
|
|
13489
|
+
return false;
|
|
13490
|
+
}
|
|
13491
|
+
if (options.daemonBindingHint) {
|
|
13492
|
+
return false;
|
|
13493
|
+
}
|
|
13494
|
+
return true;
|
|
13495
|
+
}
|
|
13496
|
+
function collectPluginStartupBindingRoots(options) {
|
|
13497
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13498
|
+
const roots = [];
|
|
13499
|
+
const add = (raw) => {
|
|
13500
|
+
if (raw === void 0 || raw === null || raw.trim() === "") {
|
|
13501
|
+
return;
|
|
13502
|
+
}
|
|
13503
|
+
const resolved = path47.resolve(raw);
|
|
13504
|
+
if (seen.has(resolved)) {
|
|
13505
|
+
return;
|
|
13506
|
+
}
|
|
13507
|
+
seen.add(resolved);
|
|
13508
|
+
roots.push(resolved);
|
|
13509
|
+
};
|
|
13510
|
+
for (const root of options.initializeRoots ?? []) {
|
|
13511
|
+
add(root);
|
|
13512
|
+
}
|
|
13513
|
+
for (const uri of options.rootsListUris ?? []) {
|
|
13514
|
+
add(uriToPath(uri));
|
|
13515
|
+
}
|
|
13516
|
+
add(getRepoScopedWorkspaceHint(options.env));
|
|
13517
|
+
return roots;
|
|
13518
|
+
}
|
|
13519
|
+
async function hasPendingPluginStartupBinding(workspaceRoots, options = {}) {
|
|
13520
|
+
for (const root of workspaceRoots) {
|
|
13521
|
+
try {
|
|
13522
|
+
const identity = await lookupLocalBindingIdentity(root, {
|
|
13523
|
+
homeDir: options.homeDir
|
|
13524
|
+
});
|
|
13525
|
+
if (identity.status !== "resolved") {
|
|
13526
|
+
continue;
|
|
13527
|
+
}
|
|
13528
|
+
const record = await readBindingRecord(
|
|
13529
|
+
identity.repositoryBindingId,
|
|
13530
|
+
options.homeDir
|
|
13531
|
+
);
|
|
13532
|
+
if (record?.status === "pending") {
|
|
13533
|
+
return true;
|
|
13534
|
+
}
|
|
13535
|
+
} catch {
|
|
13536
|
+
continue;
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
return false;
|
|
13540
|
+
}
|
|
13541
|
+
async function isRetryablePluginStartupBindingError(err, options = {}) {
|
|
13542
|
+
const message = errorMessage(err);
|
|
13543
|
+
if (isUnboundPluginStartupBindingMessage(message)) {
|
|
13544
|
+
return true;
|
|
13545
|
+
}
|
|
13546
|
+
if (isCredentialsMissingMessage(message) && await pendingBindingWindowOpen(options.isPendingBinding)) {
|
|
13547
|
+
return true;
|
|
13548
|
+
}
|
|
13549
|
+
return false;
|
|
13550
|
+
}
|
|
13551
|
+
function defaultSleep(ms) {
|
|
13552
|
+
return new Promise((resolve44) => {
|
|
13553
|
+
setTimeout(resolve44, ms);
|
|
13554
|
+
});
|
|
13555
|
+
}
|
|
13556
|
+
async function waitForPluginStartupBinding(resolve44, options = {}) {
|
|
13557
|
+
const now = options.now ?? Date.now;
|
|
13558
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
13559
|
+
const timeoutMs = options.timeoutMs ?? PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS;
|
|
13560
|
+
const intervalMs = options.intervalMs ?? PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS;
|
|
13561
|
+
const startedAt = now();
|
|
13562
|
+
let waitingLogged = false;
|
|
13563
|
+
let lastError;
|
|
13564
|
+
while (true) {
|
|
13565
|
+
try {
|
|
13566
|
+
const binding = await resolve44();
|
|
13567
|
+
if (waitingLogged) {
|
|
13568
|
+
options.log?.(
|
|
13569
|
+
`local MemoraOne binding available after Cursor plugin pairing (${now() - startedAt}ms)`
|
|
13570
|
+
);
|
|
13571
|
+
}
|
|
13572
|
+
return binding;
|
|
13573
|
+
} catch (err) {
|
|
13574
|
+
lastError = err;
|
|
13575
|
+
const retryable = await isRetryablePluginStartupBindingError(err, {
|
|
13576
|
+
isPendingBinding: options.isPendingBinding
|
|
13577
|
+
});
|
|
13578
|
+
if (!retryable) {
|
|
13579
|
+
throw err;
|
|
13580
|
+
}
|
|
13581
|
+
if (now() - startedAt >= timeoutMs) {
|
|
13582
|
+
throw lastError;
|
|
13583
|
+
}
|
|
13584
|
+
if (!waitingLogged) {
|
|
13585
|
+
options.log?.(
|
|
13586
|
+
"waiting for local MemoraOne binding after Cursor plugin pairing"
|
|
13587
|
+
);
|
|
13588
|
+
waitingLogged = true;
|
|
13589
|
+
}
|
|
13590
|
+
await sleep(intervalMs);
|
|
13591
|
+
}
|
|
13592
|
+
}
|
|
13593
|
+
}
|
|
13594
|
+
var path47, MEMORAONE_PLUGIN_ENV, MEMORAONE_CURSOR_PLUGIN, PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS, PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS, UNBOUND_MESSAGE_MARKERS, CREDENTIALS_MISSING_MARKER;
|
|
13595
|
+
var init_pluginStartupBindingWait = __esm({
|
|
13596
|
+
"src/pluginStartupBindingWait.ts"() {
|
|
13597
|
+
path47 = __toESM(require("path"), 1);
|
|
13598
|
+
init_initializeBinding();
|
|
13599
|
+
init_bindingStore();
|
|
13600
|
+
init_resolveLocalBinding();
|
|
13601
|
+
MEMORAONE_PLUGIN_ENV = "MEMORAONE_PLUGIN";
|
|
13602
|
+
MEMORAONE_CURSOR_PLUGIN = "cursor";
|
|
13603
|
+
PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
13604
|
+
PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS = 250;
|
|
13605
|
+
UNBOUND_MESSAGE_MARKERS = [
|
|
13606
|
+
"No local MemoraOne binding for this workspace",
|
|
13607
|
+
"No local binding for workspace"
|
|
13608
|
+
];
|
|
13609
|
+
CREDENTIALS_MISSING_MARKER = "Installation credentials missing";
|
|
13610
|
+
}
|
|
13611
|
+
});
|
|
13612
|
+
|
|
13466
13613
|
// src/ideType.ts
|
|
13467
13614
|
function mapReliableClientInfoName(name) {
|
|
13468
13615
|
if (typeof name !== "string") {
|
|
@@ -13670,9 +13817,9 @@ function extractJsonRpcId(line) {
|
|
|
13670
13817
|
}
|
|
13671
13818
|
}
|
|
13672
13819
|
function connectWithRetry(socketPath, log, maxRetries, retryDelayMs, connect2) {
|
|
13673
|
-
return new Promise((
|
|
13820
|
+
return new Promise((resolve44, reject) => {
|
|
13674
13821
|
const tryConnect = (attempt) => {
|
|
13675
|
-
connect2(socketPath).then(
|
|
13822
|
+
connect2(socketPath).then(resolve44).catch((err) => {
|
|
13676
13823
|
if (attempt >= maxRetries) {
|
|
13677
13824
|
reject(err);
|
|
13678
13825
|
return;
|
|
@@ -13841,6 +13988,7 @@ var init_bridgeProxy = __esm({
|
|
|
13841
13988
|
init_bridgeClientRoots();
|
|
13842
13989
|
init_cleanup();
|
|
13843
13990
|
init_initializeBinding();
|
|
13991
|
+
init_pluginStartupBindingWait();
|
|
13844
13992
|
init_projectBinding();
|
|
13845
13993
|
init_ideType();
|
|
13846
13994
|
init_socketPaths();
|
|
@@ -13868,8 +14016,8 @@ var init_bridgeProxy = __esm({
|
|
|
13868
14016
|
this.maxRetries = options.maxRetries ?? 5;
|
|
13869
14017
|
this.retryDelayMs = options.retryDelayMs ?? 200;
|
|
13870
14018
|
this.lineReader = options.lineReader ?? null;
|
|
13871
|
-
this.connectImpl = options.connect ?? ((socketPath) => new Promise((
|
|
13872
|
-
const socket = net.connect(socketPath, () =>
|
|
14019
|
+
this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve44, reject) => {
|
|
14020
|
+
const socket = net.connect(socketPath, () => resolve44(socket));
|
|
13873
14021
|
socket.on("error", reject);
|
|
13874
14022
|
}));
|
|
13875
14023
|
this.spawnDaemonImpl = options.spawnDaemon ?? (async (binding) => {
|
|
@@ -13953,10 +14101,20 @@ var init_bridgeProxy = __esm({
|
|
|
13953
14101
|
);
|
|
13954
14102
|
}
|
|
13955
14103
|
}
|
|
13956
|
-
const
|
|
14104
|
+
const resolveBinding = () => resolveBridgeSessionBinding(params, this.env, {
|
|
13957
14105
|
rootsListUris,
|
|
13958
14106
|
rootsListAttempted
|
|
13959
14107
|
});
|
|
14108
|
+
const binding = shouldWaitForPluginStartupBinding({ env: this.env }) ? await waitForPluginStartupBinding(resolveBinding, {
|
|
14109
|
+
isPendingBinding: () => hasPendingPluginStartupBinding(
|
|
14110
|
+
collectPluginStartupBindingRoots({
|
|
14111
|
+
initializeRoots,
|
|
14112
|
+
rootsListUris,
|
|
14113
|
+
env: this.env
|
|
14114
|
+
})
|
|
14115
|
+
),
|
|
14116
|
+
log: this.log
|
|
14117
|
+
}) : await resolveBinding();
|
|
13960
14118
|
const environmentLog = binding.environment !== void 0 ? ` environment=${binding.environment}` : "";
|
|
13961
14119
|
this.log(
|
|
13962
14120
|
`session binding binding=${binding.repositoryBindingId} project=${binding.projectId} workspace=${binding.workspaceRoot} source=${binding.bindingSource}${environmentLog}`
|
|
@@ -14001,7 +14159,7 @@ var init_bridgeProxy = __esm({
|
|
|
14001
14159
|
}
|
|
14002
14160
|
waitForDaemonJsonRpcResponse(id, timeoutMs = 3e4) {
|
|
14003
14161
|
const key = this.waiterKey(id);
|
|
14004
|
-
return new Promise((
|
|
14162
|
+
return new Promise((resolve44, reject) => {
|
|
14005
14163
|
const timer = setTimeout(() => {
|
|
14006
14164
|
this.pendingDaemonResponseWaiters.delete(key);
|
|
14007
14165
|
reject(
|
|
@@ -14010,7 +14168,7 @@ var init_bridgeProxy = __esm({
|
|
|
14010
14168
|
)
|
|
14011
14169
|
);
|
|
14012
14170
|
}, timeoutMs);
|
|
14013
|
-
this.pendingDaemonResponseWaiters.set(key, { resolve:
|
|
14171
|
+
this.pendingDaemonResponseWaiters.set(key, { resolve: resolve44, reject, timer });
|
|
14014
14172
|
});
|
|
14015
14173
|
}
|
|
14016
14174
|
notifyDaemonResponseWaiters(line) {
|
package/dist/daemon.cjs
CHANGED
|
@@ -416,7 +416,7 @@ async function acquireLocalLock(lockName, options = {}) {
|
|
|
416
416
|
`[memoraone-mcp] Failed to acquire lock ${lockName} after ${maxRetries} retries`
|
|
417
417
|
);
|
|
418
418
|
}
|
|
419
|
-
await new Promise((
|
|
419
|
+
await new Promise((resolve11) => setTimeout(resolve11, retryDelayMs));
|
|
420
420
|
continue;
|
|
421
421
|
}
|
|
422
422
|
throw err;
|
|
@@ -980,9 +980,9 @@ var MemoraClient = class {
|
|
|
980
980
|
...options?.headers ?? {}
|
|
981
981
|
};
|
|
982
982
|
}
|
|
983
|
-
async perform(method,
|
|
983
|
+
async perform(method, path16, body, options, retried = false) {
|
|
984
984
|
const nonce = crypto2.randomBytes(8).toString("hex");
|
|
985
|
-
const url = `${this.baseUrl}${
|
|
985
|
+
const url = `${this.baseUrl}${path16.startsWith("/") ? path16 : `/${path16}`}`;
|
|
986
986
|
this.resolveProjectId();
|
|
987
987
|
console.error(
|
|
988
988
|
`[memoraone-mcp][info] requestJson nonce=${nonce} stage=before_fetch method=${method} url=${url}`
|
|
@@ -1009,7 +1009,7 @@ var MemoraClient = class {
|
|
|
1009
1009
|
if (res.status === 401 && !options?.skipAuthRefresh && !retried) {
|
|
1010
1010
|
try {
|
|
1011
1011
|
await this.refreshAccessToken();
|
|
1012
|
-
return this.perform(method,
|
|
1012
|
+
return this.perform(method, path16, body, options, true);
|
|
1013
1013
|
} catch (err) {
|
|
1014
1014
|
if (err instanceof ReconnectRequiredError) {
|
|
1015
1015
|
await this.markReconnectRequired();
|
|
@@ -1029,22 +1029,22 @@ var MemoraClient = class {
|
|
|
1029
1029
|
}
|
|
1030
1030
|
return res.text ? JSON.parse(res.text) : null;
|
|
1031
1031
|
}
|
|
1032
|
-
async post(
|
|
1033
|
-
console.error(`[memoraone-mcp][info] MemoraClient.post ENTER path=${
|
|
1034
|
-
const result = await this.perform("POST",
|
|
1035
|
-
console.error(`[memoraone-mcp][info] MemoraClient.post EXIT path=${
|
|
1032
|
+
async post(path16, body, options) {
|
|
1033
|
+
console.error(`[memoraone-mcp][info] MemoraClient.post ENTER path=${path16}`);
|
|
1034
|
+
const result = await this.perform("POST", path16, body, options);
|
|
1035
|
+
console.error(`[memoraone-mcp][info] MemoraClient.post EXIT path=${path16}`);
|
|
1036
1036
|
return result;
|
|
1037
1037
|
}
|
|
1038
|
-
async get(
|
|
1039
|
-
return this.perform("GET",
|
|
1038
|
+
async get(path16, options) {
|
|
1039
|
+
return this.perform("GET", path16, void 0, options);
|
|
1040
1040
|
}
|
|
1041
1041
|
};
|
|
1042
1042
|
var memoraClient_default = MemoraClient;
|
|
1043
1043
|
|
|
1044
1044
|
// src/localState/localConnectClient.ts
|
|
1045
|
-
async function requestJson2(baseUrl, method,
|
|
1045
|
+
async function requestJson2(baseUrl, method, path16, options = {}) {
|
|
1046
1046
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1047
|
-
const url = `${baseUrl.replace(/\/+$/, "")}${
|
|
1047
|
+
const url = `${baseUrl.replace(/\/+$/, "")}${path16.startsWith("/") ? path16 : `/${path16}`}`;
|
|
1048
1048
|
const res = await fetchImpl(url, {
|
|
1049
1049
|
method,
|
|
1050
1050
|
headers: {
|
|
@@ -1228,6 +1228,30 @@ async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
|
|
|
1228
1228
|
legacyM1WarningPath
|
|
1229
1229
|
};
|
|
1230
1230
|
}
|
|
1231
|
+
async function lookupLocalBindingIdentity(workspaceRoot, options = {}) {
|
|
1232
|
+
const resolved = path9.resolve(workspaceRoot);
|
|
1233
|
+
const identity = await captureRootFilesystemIdentity(resolved, options.identityDeps);
|
|
1234
|
+
const index = await loadPathIndex(options.homeDir);
|
|
1235
|
+
const lookup = lookupPathIndex(index, resolved, identity);
|
|
1236
|
+
if (lookup.kind !== "path") {
|
|
1237
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1238
|
+
}
|
|
1239
|
+
const record = await readBindingRecord(lookup.repositoryBindingId, options.homeDir);
|
|
1240
|
+
if (!record) {
|
|
1241
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1242
|
+
}
|
|
1243
|
+
if (path9.resolve(record.workspaceRoot) !== resolved) {
|
|
1244
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1245
|
+
}
|
|
1246
|
+
if (!identityMatchesStored(record.filesystemIdentity, identity)) {
|
|
1247
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1248
|
+
}
|
|
1249
|
+
return {
|
|
1250
|
+
status: "resolved",
|
|
1251
|
+
workspaceRoot: resolved,
|
|
1252
|
+
repositoryBindingId: record.repositoryBindingId
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1231
1255
|
async function resolveLocalBinding(workspaceRoot, options = {}) {
|
|
1232
1256
|
const resolved = path9.resolve(workspaceRoot);
|
|
1233
1257
|
const { repositoryBindingId, legacyM1WarningPath } = await ensureRepositoryBindingForRoot(
|
|
@@ -1793,6 +1817,145 @@ async function resolveBindingFromInitializeParams(params, options = {}) {
|
|
|
1793
1817
|
});
|
|
1794
1818
|
}
|
|
1795
1819
|
|
|
1820
|
+
// src/pluginStartupBindingWait.ts
|
|
1821
|
+
var path14 = __toESM(require("path"), 1);
|
|
1822
|
+
var MEMORAONE_PLUGIN_ENV = "MEMORAONE_PLUGIN";
|
|
1823
|
+
var MEMORAONE_CURSOR_PLUGIN = "cursor";
|
|
1824
|
+
var PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1825
|
+
var PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS = 250;
|
|
1826
|
+
var UNBOUND_MESSAGE_MARKERS = [
|
|
1827
|
+
"No local MemoraOne binding for this workspace",
|
|
1828
|
+
"No local binding for workspace"
|
|
1829
|
+
];
|
|
1830
|
+
var CREDENTIALS_MISSING_MARKER = "Installation credentials missing";
|
|
1831
|
+
function errorMessage(err) {
|
|
1832
|
+
return err instanceof Error ? err.message : String(err);
|
|
1833
|
+
}
|
|
1834
|
+
function isUnboundPluginStartupBindingMessage(message) {
|
|
1835
|
+
return UNBOUND_MESSAGE_MARKERS.some((marker) => message.includes(marker));
|
|
1836
|
+
}
|
|
1837
|
+
function isCredentialsMissingMessage(message) {
|
|
1838
|
+
return message.includes(CREDENTIALS_MISSING_MARKER);
|
|
1839
|
+
}
|
|
1840
|
+
async function pendingBindingWindowOpen(isPendingBinding) {
|
|
1841
|
+
if (!isPendingBinding) {
|
|
1842
|
+
return false;
|
|
1843
|
+
}
|
|
1844
|
+
try {
|
|
1845
|
+
return Boolean(await isPendingBinding());
|
|
1846
|
+
} catch {
|
|
1847
|
+
return false;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
function shouldWaitForPluginStartupBinding(options = {}) {
|
|
1851
|
+
const env2 = options.env ?? process.env;
|
|
1852
|
+
if (env2[MEMORAONE_PLUGIN_ENV] !== MEMORAONE_CURSOR_PLUGIN) {
|
|
1853
|
+
return false;
|
|
1854
|
+
}
|
|
1855
|
+
if (options.daemonBindingHint) {
|
|
1856
|
+
return false;
|
|
1857
|
+
}
|
|
1858
|
+
return true;
|
|
1859
|
+
}
|
|
1860
|
+
function collectPluginStartupBindingRoots(options) {
|
|
1861
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1862
|
+
const roots = [];
|
|
1863
|
+
const add = (raw) => {
|
|
1864
|
+
if (raw === void 0 || raw === null || raw.trim() === "") {
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
const resolved = path14.resolve(raw);
|
|
1868
|
+
if (seen.has(resolved)) {
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
seen.add(resolved);
|
|
1872
|
+
roots.push(resolved);
|
|
1873
|
+
};
|
|
1874
|
+
for (const root of options.initializeRoots ?? []) {
|
|
1875
|
+
add(root);
|
|
1876
|
+
}
|
|
1877
|
+
for (const uri of options.rootsListUris ?? []) {
|
|
1878
|
+
add(uriToPath(uri));
|
|
1879
|
+
}
|
|
1880
|
+
add(getRepoScopedWorkspaceHint(options.env));
|
|
1881
|
+
return roots;
|
|
1882
|
+
}
|
|
1883
|
+
async function hasPendingPluginStartupBinding(workspaceRoots, options = {}) {
|
|
1884
|
+
for (const root of workspaceRoots) {
|
|
1885
|
+
try {
|
|
1886
|
+
const identity = await lookupLocalBindingIdentity(root, {
|
|
1887
|
+
homeDir: options.homeDir
|
|
1888
|
+
});
|
|
1889
|
+
if (identity.status !== "resolved") {
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
const record = await readBindingRecord(
|
|
1893
|
+
identity.repositoryBindingId,
|
|
1894
|
+
options.homeDir
|
|
1895
|
+
);
|
|
1896
|
+
if (record?.status === "pending") {
|
|
1897
|
+
return true;
|
|
1898
|
+
}
|
|
1899
|
+
} catch {
|
|
1900
|
+
continue;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
async function isRetryablePluginStartupBindingError(err, options = {}) {
|
|
1906
|
+
const message = errorMessage(err);
|
|
1907
|
+
if (isUnboundPluginStartupBindingMessage(message)) {
|
|
1908
|
+
return true;
|
|
1909
|
+
}
|
|
1910
|
+
if (isCredentialsMissingMessage(message) && await pendingBindingWindowOpen(options.isPendingBinding)) {
|
|
1911
|
+
return true;
|
|
1912
|
+
}
|
|
1913
|
+
return false;
|
|
1914
|
+
}
|
|
1915
|
+
function defaultSleep(ms) {
|
|
1916
|
+
return new Promise((resolve11) => {
|
|
1917
|
+
setTimeout(resolve11, ms);
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
async function waitForPluginStartupBinding(resolve11, options = {}) {
|
|
1921
|
+
const now = options.now ?? Date.now;
|
|
1922
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
1923
|
+
const timeoutMs = options.timeoutMs ?? PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS;
|
|
1924
|
+
const intervalMs = options.intervalMs ?? PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS;
|
|
1925
|
+
const startedAt = now();
|
|
1926
|
+
let waitingLogged = false;
|
|
1927
|
+
let lastError;
|
|
1928
|
+
while (true) {
|
|
1929
|
+
try {
|
|
1930
|
+
const binding = await resolve11();
|
|
1931
|
+
if (waitingLogged) {
|
|
1932
|
+
options.log?.(
|
|
1933
|
+
`local MemoraOne binding available after Cursor plugin pairing (${now() - startedAt}ms)`
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
return binding;
|
|
1937
|
+
} catch (err) {
|
|
1938
|
+
lastError = err;
|
|
1939
|
+
const retryable = await isRetryablePluginStartupBindingError(err, {
|
|
1940
|
+
isPendingBinding: options.isPendingBinding
|
|
1941
|
+
});
|
|
1942
|
+
if (!retryable) {
|
|
1943
|
+
throw err;
|
|
1944
|
+
}
|
|
1945
|
+
if (now() - startedAt >= timeoutMs) {
|
|
1946
|
+
throw lastError;
|
|
1947
|
+
}
|
|
1948
|
+
if (!waitingLogged) {
|
|
1949
|
+
options.log?.(
|
|
1950
|
+
"waiting for local MemoraOne binding after Cursor plugin pairing"
|
|
1951
|
+
);
|
|
1952
|
+
waitingLogged = true;
|
|
1953
|
+
}
|
|
1954
|
+
await sleep(intervalMs);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1796
1959
|
// src/bridgeClientRoots.ts
|
|
1797
1960
|
var readline = __toESM(require("readline"), 1);
|
|
1798
1961
|
var TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
@@ -2227,9 +2390,9 @@ function buildPersonalContextPath(parsed2) {
|
|
|
2227
2390
|
}
|
|
2228
2391
|
async function handleGetPersonalContext(client, args) {
|
|
2229
2392
|
const parsed2 = getPersonalContextInputSchema.parse(args ?? {});
|
|
2230
|
-
const
|
|
2393
|
+
const path16 = buildPersonalContextPath(parsed2);
|
|
2231
2394
|
try {
|
|
2232
|
-
const result = await client.get(
|
|
2395
|
+
const result = await client.get(path16);
|
|
2233
2396
|
return { ok: true, result };
|
|
2234
2397
|
} catch (err) {
|
|
2235
2398
|
if (err instanceof MemoraOneHttpError) {
|
|
@@ -2701,8 +2864,8 @@ async function handleCreateConceptVersion(client, args) {
|
|
|
2701
2864
|
if (input.tags !== void 0) body.tags = input.tags;
|
|
2702
2865
|
if (input.parent_id !== void 0) body.parent_id = input.parent_id;
|
|
2703
2866
|
try {
|
|
2704
|
-
const
|
|
2705
|
-
return projectCreatedConceptVersionResponse(await client.post(
|
|
2867
|
+
const path16 = `/concepts/${encodeURIComponent(input.id)}/versions`;
|
|
2868
|
+
return projectCreatedConceptVersionResponse(await client.post(path16, body));
|
|
2706
2869
|
} catch (error) {
|
|
2707
2870
|
rethrowToolRequestError("memora_create_concept_version", error);
|
|
2708
2871
|
}
|
|
@@ -2737,7 +2900,7 @@ function handleBindingStatus(binding, options = {}) {
|
|
|
2737
2900
|
// src/heartbeat.ts
|
|
2738
2901
|
var crypto5 = __toESM(require("crypto"), 1);
|
|
2739
2902
|
var fs10 = __toESM(require("fs"), 1);
|
|
2740
|
-
var
|
|
2903
|
+
var path15 = __toESM(require("path"), 1);
|
|
2741
2904
|
|
|
2742
2905
|
// src/localState/mcpSessionId.ts
|
|
2743
2906
|
var import_node_crypto4 = require("crypto");
|
|
@@ -2770,9 +2933,9 @@ function resolvePackageVersion() {
|
|
|
2770
2933
|
if (fromEnv) return fromEnv;
|
|
2771
2934
|
const moduleDir = typeof __dirname !== "undefined" ? __dirname : void 0;
|
|
2772
2935
|
const candidates = [
|
|
2773
|
-
...moduleDir ? [
|
|
2774
|
-
|
|
2775
|
-
|
|
2936
|
+
...moduleDir ? [path15.join(moduleDir, "..", "package.json"), path15.join(moduleDir, "package.json")] : [],
|
|
2937
|
+
path15.join(process.cwd(), "package.json"),
|
|
2938
|
+
path15.join(process.cwd(), "packages", "mcp", "package.json")
|
|
2776
2939
|
];
|
|
2777
2940
|
for (const candidate of candidates) {
|
|
2778
2941
|
try {
|
|
@@ -3291,8 +3454,8 @@ function registerToolWithWorklog(server, runtime, sessionContext, toolName, desc
|
|
|
3291
3454
|
async function main(opts = {}) {
|
|
3292
3455
|
let bindingReadyResolve = null;
|
|
3293
3456
|
let bindingReadyReject = null;
|
|
3294
|
-
const bindingReady = new Promise((
|
|
3295
|
-
bindingReadyResolve =
|
|
3457
|
+
const bindingReady = new Promise((resolve11, reject) => {
|
|
3458
|
+
bindingReadyResolve = resolve11;
|
|
3296
3459
|
bindingReadyReject = reject;
|
|
3297
3460
|
});
|
|
3298
3461
|
const devMode = Boolean(config2.devMode);
|
|
@@ -3373,12 +3536,25 @@ async function main(opts = {}) {
|
|
|
3373
3536
|
console.error("[memoraone-mcp][init-debug] Workspace resolution strategy: initialize.rootUri");
|
|
3374
3537
|
}
|
|
3375
3538
|
}
|
|
3376
|
-
const
|
|
3539
|
+
const resolveBinding = () => resolveBindingFromInitializeParams(params, {
|
|
3377
3540
|
fallbackWorkspaceRoots: getEnvWorkspaceRootCandidates(),
|
|
3378
3541
|
rootsListUris,
|
|
3379
3542
|
rootsListAttempted,
|
|
3380
3543
|
...getBridgeBindingResolveOptions()
|
|
3381
3544
|
});
|
|
3545
|
+
const binding = shouldWaitForPluginStartupBinding({
|
|
3546
|
+
env: process.env,
|
|
3547
|
+
daemonBindingHint: opts.daemonBindingHint
|
|
3548
|
+
}) ? await waitForPluginStartupBinding(resolveBinding, {
|
|
3549
|
+
isPendingBinding: () => hasPendingPluginStartupBinding(
|
|
3550
|
+
collectPluginStartupBindingRoots({
|
|
3551
|
+
initializeRoots,
|
|
3552
|
+
rootsListUris,
|
|
3553
|
+
env: process.env
|
|
3554
|
+
})
|
|
3555
|
+
),
|
|
3556
|
+
log: (msg) => console.error(`[memoraone-mcp] ${msg}`)
|
|
3557
|
+
}) : await resolveBinding();
|
|
3382
3558
|
workspaceRoot = binding.workspaceRoot;
|
|
3383
3559
|
return binding;
|
|
3384
3560
|
};
|
|
@@ -3765,10 +3941,10 @@ async function main(opts = {}) {
|
|
|
3765
3941
|
console.error("[memoraone-mcp] MCP server ready");
|
|
3766
3942
|
}
|
|
3767
3943
|
if (opts.sessionSocket) {
|
|
3768
|
-
await new Promise((
|
|
3944
|
+
await new Promise((resolve11) => {
|
|
3769
3945
|
opts.sessionSocket.once("close", () => {
|
|
3770
3946
|
shutdown("session closed", false);
|
|
3771
|
-
|
|
3947
|
+
resolve11();
|
|
3772
3948
|
});
|
|
3773
3949
|
});
|
|
3774
3950
|
}
|
|
@@ -3812,7 +3988,7 @@ async function ensureSocketClean(socketPath) {
|
|
|
3812
3988
|
} catch {
|
|
3813
3989
|
return;
|
|
3814
3990
|
}
|
|
3815
|
-
return new Promise((
|
|
3991
|
+
return new Promise((resolve11) => {
|
|
3816
3992
|
const client = net.createConnection({ path: socketPath }, () => {
|
|
3817
3993
|
client.destroy();
|
|
3818
3994
|
log("daemon already running, exiting");
|
|
@@ -3824,7 +4000,7 @@ async function ensureSocketClean(socketPath) {
|
|
|
3824
4000
|
log("stale socket removed");
|
|
3825
4001
|
} catch {
|
|
3826
4002
|
}
|
|
3827
|
-
|
|
4003
|
+
resolve11();
|
|
3828
4004
|
});
|
|
3829
4005
|
});
|
|
3830
4006
|
}
|
|
@@ -3915,14 +4091,14 @@ async function runDaemon() {
|
|
|
3915
4091
|
process.on("SIGINT", () => shutdownNow("SIGINT"));
|
|
3916
4092
|
process.on("SIGTERM", () => shutdownNow("SIGTERM"));
|
|
3917
4093
|
process.on("exit", cleanupSocketFile);
|
|
3918
|
-
return new Promise((
|
|
4094
|
+
return new Promise((resolve11) => {
|
|
3919
4095
|
server.listen(socketPath, () => {
|
|
3920
4096
|
writeBindingSidecar(socketPath, binding, ideType ?? "");
|
|
3921
4097
|
log(`daemon started, listening on ${socketPath}`);
|
|
3922
4098
|
void daemonHeartbeat.start().catch((err) => {
|
|
3923
4099
|
log(`daemon heartbeat start error: ${String(err)}`);
|
|
3924
4100
|
});
|
|
3925
|
-
|
|
4101
|
+
resolve11();
|
|
3926
4102
|
});
|
|
3927
4103
|
});
|
|
3928
4104
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -593,7 +593,7 @@ async function acquireLocalLock(lockName, options = {}) {
|
|
|
593
593
|
`[memoraone-mcp] Failed to acquire lock ${lockName} after ${maxRetries} retries`
|
|
594
594
|
);
|
|
595
595
|
}
|
|
596
|
-
await new Promise((
|
|
596
|
+
await new Promise((resolve11) => setTimeout(resolve11, retryDelayMs));
|
|
597
597
|
continue;
|
|
598
598
|
}
|
|
599
599
|
throw err;
|
|
@@ -612,9 +612,9 @@ async function withLocalLock(lockName, fn, options = {}) {
|
|
|
612
612
|
|
|
613
613
|
// src/localState/localConnectClient.ts
|
|
614
614
|
var path6 = __toESM(require("path"), 1);
|
|
615
|
-
async function requestJson(baseUrl, method,
|
|
615
|
+
async function requestJson(baseUrl, method, path16, options = {}) {
|
|
616
616
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
617
|
-
const url = `${baseUrl.replace(/\/+$/, "")}${
|
|
617
|
+
const url = `${baseUrl.replace(/\/+$/, "")}${path16.startsWith("/") ? path16 : `/${path16}`}`;
|
|
618
618
|
const res = await fetchImpl(url, {
|
|
619
619
|
method,
|
|
620
620
|
headers: {
|
|
@@ -950,9 +950,9 @@ var MemoraClient = class {
|
|
|
950
950
|
...options?.headers ?? {}
|
|
951
951
|
};
|
|
952
952
|
}
|
|
953
|
-
async perform(method,
|
|
953
|
+
async perform(method, path16, body, options, retried = false) {
|
|
954
954
|
const nonce = crypto2.randomBytes(8).toString("hex");
|
|
955
|
-
const url = `${this.baseUrl}${
|
|
955
|
+
const url = `${this.baseUrl}${path16.startsWith("/") ? path16 : `/${path16}`}`;
|
|
956
956
|
this.resolveProjectId();
|
|
957
957
|
console.error(
|
|
958
958
|
`[memoraone-mcp][info] requestJson nonce=${nonce} stage=before_fetch method=${method} url=${url}`
|
|
@@ -979,7 +979,7 @@ var MemoraClient = class {
|
|
|
979
979
|
if (res.status === 401 && !options?.skipAuthRefresh && !retried) {
|
|
980
980
|
try {
|
|
981
981
|
await this.refreshAccessToken();
|
|
982
|
-
return this.perform(method,
|
|
982
|
+
return this.perform(method, path16, body, options, true);
|
|
983
983
|
} catch (err) {
|
|
984
984
|
if (err instanceof ReconnectRequiredError) {
|
|
985
985
|
await this.markReconnectRequired();
|
|
@@ -999,14 +999,14 @@ var MemoraClient = class {
|
|
|
999
999
|
}
|
|
1000
1000
|
return res.text ? JSON.parse(res.text) : null;
|
|
1001
1001
|
}
|
|
1002
|
-
async post(
|
|
1003
|
-
console.error(`[memoraone-mcp][info] MemoraClient.post ENTER path=${
|
|
1004
|
-
const result = await this.perform("POST",
|
|
1005
|
-
console.error(`[memoraone-mcp][info] MemoraClient.post EXIT path=${
|
|
1002
|
+
async post(path16, body, options) {
|
|
1003
|
+
console.error(`[memoraone-mcp][info] MemoraClient.post ENTER path=${path16}`);
|
|
1004
|
+
const result = await this.perform("POST", path16, body, options);
|
|
1005
|
+
console.error(`[memoraone-mcp][info] MemoraClient.post EXIT path=${path16}`);
|
|
1006
1006
|
return result;
|
|
1007
1007
|
}
|
|
1008
|
-
async get(
|
|
1009
|
-
return this.perform("GET",
|
|
1008
|
+
async get(path16, options) {
|
|
1009
|
+
return this.perform("GET", path16, void 0, options);
|
|
1010
1010
|
}
|
|
1011
1011
|
};
|
|
1012
1012
|
var memoraClient_default = MemoraClient;
|
|
@@ -1313,6 +1313,30 @@ async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
|
|
|
1313
1313
|
legacyM1WarningPath
|
|
1314
1314
|
};
|
|
1315
1315
|
}
|
|
1316
|
+
async function lookupLocalBindingIdentity(workspaceRoot, options = {}) {
|
|
1317
|
+
const resolved = path10.resolve(workspaceRoot);
|
|
1318
|
+
const identity = await captureRootFilesystemIdentity(resolved, options.identityDeps);
|
|
1319
|
+
const index = await loadPathIndex(options.homeDir);
|
|
1320
|
+
const lookup = lookupPathIndex(index, resolved, identity);
|
|
1321
|
+
if (lookup.kind !== "path") {
|
|
1322
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1323
|
+
}
|
|
1324
|
+
const record = await readBindingRecord(lookup.repositoryBindingId, options.homeDir);
|
|
1325
|
+
if (!record) {
|
|
1326
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1327
|
+
}
|
|
1328
|
+
if (path10.resolve(record.workspaceRoot) !== resolved) {
|
|
1329
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1330
|
+
}
|
|
1331
|
+
if (!identityMatchesStored(record.filesystemIdentity, identity)) {
|
|
1332
|
+
return { status: "unbound", workspaceRoot: resolved };
|
|
1333
|
+
}
|
|
1334
|
+
return {
|
|
1335
|
+
status: "resolved",
|
|
1336
|
+
workspaceRoot: resolved,
|
|
1337
|
+
repositoryBindingId: record.repositoryBindingId
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1316
1340
|
async function resolveLocalBinding(workspaceRoot, options = {}) {
|
|
1317
1341
|
const resolved = path10.resolve(workspaceRoot);
|
|
1318
1342
|
const { repositoryBindingId, legacyM1WarningPath } = await ensureRepositoryBindingForRoot(
|
|
@@ -1690,9 +1714,148 @@ async function resolveBindingFromInitializeParams(params, options = {}) {
|
|
|
1690
1714
|
});
|
|
1691
1715
|
}
|
|
1692
1716
|
|
|
1717
|
+
// src/pluginStartupBindingWait.ts
|
|
1718
|
+
var path13 = __toESM(require("path"), 1);
|
|
1719
|
+
var MEMORAONE_PLUGIN_ENV = "MEMORAONE_PLUGIN";
|
|
1720
|
+
var MEMORAONE_CURSOR_PLUGIN = "cursor";
|
|
1721
|
+
var PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1722
|
+
var PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS = 250;
|
|
1723
|
+
var UNBOUND_MESSAGE_MARKERS = [
|
|
1724
|
+
"No local MemoraOne binding for this workspace",
|
|
1725
|
+
"No local binding for workspace"
|
|
1726
|
+
];
|
|
1727
|
+
var CREDENTIALS_MISSING_MARKER = "Installation credentials missing";
|
|
1728
|
+
function errorMessage(err) {
|
|
1729
|
+
return err instanceof Error ? err.message : String(err);
|
|
1730
|
+
}
|
|
1731
|
+
function isUnboundPluginStartupBindingMessage(message) {
|
|
1732
|
+
return UNBOUND_MESSAGE_MARKERS.some((marker) => message.includes(marker));
|
|
1733
|
+
}
|
|
1734
|
+
function isCredentialsMissingMessage(message) {
|
|
1735
|
+
return message.includes(CREDENTIALS_MISSING_MARKER);
|
|
1736
|
+
}
|
|
1737
|
+
async function pendingBindingWindowOpen(isPendingBinding) {
|
|
1738
|
+
if (!isPendingBinding) {
|
|
1739
|
+
return false;
|
|
1740
|
+
}
|
|
1741
|
+
try {
|
|
1742
|
+
return Boolean(await isPendingBinding());
|
|
1743
|
+
} catch {
|
|
1744
|
+
return false;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
function shouldWaitForPluginStartupBinding(options = {}) {
|
|
1748
|
+
const env2 = options.env ?? process.env;
|
|
1749
|
+
if (env2[MEMORAONE_PLUGIN_ENV] !== MEMORAONE_CURSOR_PLUGIN) {
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
if (options.daemonBindingHint) {
|
|
1753
|
+
return false;
|
|
1754
|
+
}
|
|
1755
|
+
return true;
|
|
1756
|
+
}
|
|
1757
|
+
function collectPluginStartupBindingRoots(options) {
|
|
1758
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1759
|
+
const roots = [];
|
|
1760
|
+
const add = (raw) => {
|
|
1761
|
+
if (raw === void 0 || raw === null || raw.trim() === "") {
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
const resolved = path13.resolve(raw);
|
|
1765
|
+
if (seen.has(resolved)) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
seen.add(resolved);
|
|
1769
|
+
roots.push(resolved);
|
|
1770
|
+
};
|
|
1771
|
+
for (const root of options.initializeRoots ?? []) {
|
|
1772
|
+
add(root);
|
|
1773
|
+
}
|
|
1774
|
+
for (const uri of options.rootsListUris ?? []) {
|
|
1775
|
+
add(uriToPath(uri));
|
|
1776
|
+
}
|
|
1777
|
+
add(getRepoScopedWorkspaceHint(options.env));
|
|
1778
|
+
return roots;
|
|
1779
|
+
}
|
|
1780
|
+
async function hasPendingPluginStartupBinding(workspaceRoots, options = {}) {
|
|
1781
|
+
for (const root of workspaceRoots) {
|
|
1782
|
+
try {
|
|
1783
|
+
const identity = await lookupLocalBindingIdentity(root, {
|
|
1784
|
+
homeDir: options.homeDir
|
|
1785
|
+
});
|
|
1786
|
+
if (identity.status !== "resolved") {
|
|
1787
|
+
continue;
|
|
1788
|
+
}
|
|
1789
|
+
const record = await readBindingRecord(
|
|
1790
|
+
identity.repositoryBindingId,
|
|
1791
|
+
options.homeDir
|
|
1792
|
+
);
|
|
1793
|
+
if (record?.status === "pending") {
|
|
1794
|
+
return true;
|
|
1795
|
+
}
|
|
1796
|
+
} catch {
|
|
1797
|
+
continue;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
return false;
|
|
1801
|
+
}
|
|
1802
|
+
async function isRetryablePluginStartupBindingError(err, options = {}) {
|
|
1803
|
+
const message = errorMessage(err);
|
|
1804
|
+
if (isUnboundPluginStartupBindingMessage(message)) {
|
|
1805
|
+
return true;
|
|
1806
|
+
}
|
|
1807
|
+
if (isCredentialsMissingMessage(message) && await pendingBindingWindowOpen(options.isPendingBinding)) {
|
|
1808
|
+
return true;
|
|
1809
|
+
}
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
function defaultSleep(ms) {
|
|
1813
|
+
return new Promise((resolve11) => {
|
|
1814
|
+
setTimeout(resolve11, ms);
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
async function waitForPluginStartupBinding(resolve11, options = {}) {
|
|
1818
|
+
const now = options.now ?? Date.now;
|
|
1819
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
1820
|
+
const timeoutMs = options.timeoutMs ?? PLUGIN_STARTUP_BINDING_WAIT_TIMEOUT_MS;
|
|
1821
|
+
const intervalMs = options.intervalMs ?? PLUGIN_STARTUP_BINDING_WAIT_INTERVAL_MS;
|
|
1822
|
+
const startedAt = now();
|
|
1823
|
+
let waitingLogged = false;
|
|
1824
|
+
let lastError;
|
|
1825
|
+
while (true) {
|
|
1826
|
+
try {
|
|
1827
|
+
const binding = await resolve11();
|
|
1828
|
+
if (waitingLogged) {
|
|
1829
|
+
options.log?.(
|
|
1830
|
+
`local MemoraOne binding available after Cursor plugin pairing (${now() - startedAt}ms)`
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
return binding;
|
|
1834
|
+
} catch (err) {
|
|
1835
|
+
lastError = err;
|
|
1836
|
+
const retryable = await isRetryablePluginStartupBindingError(err, {
|
|
1837
|
+
isPendingBinding: options.isPendingBinding
|
|
1838
|
+
});
|
|
1839
|
+
if (!retryable) {
|
|
1840
|
+
throw err;
|
|
1841
|
+
}
|
|
1842
|
+
if (now() - startedAt >= timeoutMs) {
|
|
1843
|
+
throw lastError;
|
|
1844
|
+
}
|
|
1845
|
+
if (!waitingLogged) {
|
|
1846
|
+
options.log?.(
|
|
1847
|
+
"waiting for local MemoraOne binding after Cursor plugin pairing"
|
|
1848
|
+
);
|
|
1849
|
+
waitingLogged = true;
|
|
1850
|
+
}
|
|
1851
|
+
await sleep(intervalMs);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1693
1856
|
// src/bindingSidecar.ts
|
|
1694
1857
|
var fs9 = __toESM(require("fs"), 1);
|
|
1695
|
-
var
|
|
1858
|
+
var path14 = __toESM(require("path"), 1);
|
|
1696
1859
|
function bindingSidecarPath(socketPath) {
|
|
1697
1860
|
if (socketPath.endsWith(".sock")) {
|
|
1698
1861
|
return `${socketPath.slice(0, -".sock".length)}.binding.json`;
|
|
@@ -2153,9 +2316,9 @@ function buildPersonalContextPath(parsed2) {
|
|
|
2153
2316
|
}
|
|
2154
2317
|
async function handleGetPersonalContext(client, args) {
|
|
2155
2318
|
const parsed2 = getPersonalContextInputSchema.parse(args ?? {});
|
|
2156
|
-
const
|
|
2319
|
+
const path16 = buildPersonalContextPath(parsed2);
|
|
2157
2320
|
try {
|
|
2158
|
-
const result = await client.get(
|
|
2321
|
+
const result = await client.get(path16);
|
|
2159
2322
|
return { ok: true, result };
|
|
2160
2323
|
} catch (err) {
|
|
2161
2324
|
if (err instanceof MemoraOneHttpError) {
|
|
@@ -2627,8 +2790,8 @@ async function handleCreateConceptVersion(client, args) {
|
|
|
2627
2790
|
if (input.tags !== void 0) body.tags = input.tags;
|
|
2628
2791
|
if (input.parent_id !== void 0) body.parent_id = input.parent_id;
|
|
2629
2792
|
try {
|
|
2630
|
-
const
|
|
2631
|
-
return projectCreatedConceptVersionResponse(await client.post(
|
|
2793
|
+
const path16 = `/concepts/${encodeURIComponent(input.id)}/versions`;
|
|
2794
|
+
return projectCreatedConceptVersionResponse(await client.post(path16, body));
|
|
2632
2795
|
} catch (error) {
|
|
2633
2796
|
rethrowToolRequestError("memora_create_concept_version", error);
|
|
2634
2797
|
}
|
|
@@ -2663,7 +2826,7 @@ function handleBindingStatus(binding, options = {}) {
|
|
|
2663
2826
|
// src/heartbeat.ts
|
|
2664
2827
|
var crypto5 = __toESM(require("crypto"), 1);
|
|
2665
2828
|
var fs10 = __toESM(require("fs"), 1);
|
|
2666
|
-
var
|
|
2829
|
+
var path15 = __toESM(require("path"), 1);
|
|
2667
2830
|
|
|
2668
2831
|
// src/localState/mcpSessionId.ts
|
|
2669
2832
|
var import_node_crypto4 = require("crypto");
|
|
@@ -2696,9 +2859,9 @@ function resolvePackageVersion() {
|
|
|
2696
2859
|
if (fromEnv) return fromEnv;
|
|
2697
2860
|
const moduleDir = typeof __dirname !== "undefined" ? __dirname : void 0;
|
|
2698
2861
|
const candidates = [
|
|
2699
|
-
...moduleDir ? [
|
|
2700
|
-
|
|
2701
|
-
|
|
2862
|
+
...moduleDir ? [path15.join(moduleDir, "..", "package.json"), path15.join(moduleDir, "package.json")] : [],
|
|
2863
|
+
path15.join(process.cwd(), "package.json"),
|
|
2864
|
+
path15.join(process.cwd(), "packages", "mcp", "package.json")
|
|
2702
2865
|
];
|
|
2703
2866
|
for (const candidate of candidates) {
|
|
2704
2867
|
try {
|
|
@@ -3217,8 +3380,8 @@ function registerToolWithWorklog(server, runtime, sessionContext, toolName, desc
|
|
|
3217
3380
|
async function main(opts = {}) {
|
|
3218
3381
|
let bindingReadyResolve = null;
|
|
3219
3382
|
let bindingReadyReject = null;
|
|
3220
|
-
const bindingReady = new Promise((
|
|
3221
|
-
bindingReadyResolve =
|
|
3383
|
+
const bindingReady = new Promise((resolve11, reject) => {
|
|
3384
|
+
bindingReadyResolve = resolve11;
|
|
3222
3385
|
bindingReadyReject = reject;
|
|
3223
3386
|
});
|
|
3224
3387
|
const devMode = Boolean(config2.devMode);
|
|
@@ -3299,12 +3462,25 @@ async function main(opts = {}) {
|
|
|
3299
3462
|
console.error("[memoraone-mcp][init-debug] Workspace resolution strategy: initialize.rootUri");
|
|
3300
3463
|
}
|
|
3301
3464
|
}
|
|
3302
|
-
const
|
|
3465
|
+
const resolveBinding = () => resolveBindingFromInitializeParams(params, {
|
|
3303
3466
|
fallbackWorkspaceRoots: getEnvWorkspaceRootCandidates(),
|
|
3304
3467
|
rootsListUris,
|
|
3305
3468
|
rootsListAttempted,
|
|
3306
3469
|
...getBridgeBindingResolveOptions()
|
|
3307
3470
|
});
|
|
3471
|
+
const binding = shouldWaitForPluginStartupBinding({
|
|
3472
|
+
env: process.env,
|
|
3473
|
+
daemonBindingHint: opts.daemonBindingHint
|
|
3474
|
+
}) ? await waitForPluginStartupBinding(resolveBinding, {
|
|
3475
|
+
isPendingBinding: () => hasPendingPluginStartupBinding(
|
|
3476
|
+
collectPluginStartupBindingRoots({
|
|
3477
|
+
initializeRoots,
|
|
3478
|
+
rootsListUris,
|
|
3479
|
+
env: process.env
|
|
3480
|
+
})
|
|
3481
|
+
),
|
|
3482
|
+
log: (msg) => console.error(`[memoraone-mcp] ${msg}`)
|
|
3483
|
+
}) : await resolveBinding();
|
|
3308
3484
|
workspaceRoot = binding.workspaceRoot;
|
|
3309
3485
|
return binding;
|
|
3310
3486
|
};
|
|
@@ -3691,10 +3867,10 @@ async function main(opts = {}) {
|
|
|
3691
3867
|
console.error("[memoraone-mcp] MCP server ready");
|
|
3692
3868
|
}
|
|
3693
3869
|
if (opts.sessionSocket) {
|
|
3694
|
-
await new Promise((
|
|
3870
|
+
await new Promise((resolve11) => {
|
|
3695
3871
|
opts.sessionSocket.once("close", () => {
|
|
3696
3872
|
shutdown("session closed", false);
|
|
3697
|
-
|
|
3873
|
+
resolve11();
|
|
3698
3874
|
});
|
|
3699
3875
|
});
|
|
3700
3876
|
}
|
package/dist/pluginPairing.cjs
CHANGED
|
@@ -9982,7 +9982,7 @@ var PluginRepositoryPairingSession = class {
|
|
|
9982
9982
|
ideType: this.source,
|
|
9983
9983
|
fetchImpl: this.connectOptions.fetchImpl ?? this.fetchImpl,
|
|
9984
9984
|
// Plugin pairing configures only the IDE that initiated the pairing.
|
|
9985
|
-
configureIdes:
|
|
9985
|
+
configureIdes: this.source !== "cursor",
|
|
9986
9986
|
setupIdeOptions: {
|
|
9987
9987
|
...this.connectOptions.setupIdeOptions,
|
|
9988
9988
|
targets: {
|