@memoraone/mcp 0.1.43 → 0.1.45

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 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.43",
234
+ version: "0.1.45",
235
235
  type: "module",
236
236
  main: "dist/index.cjs",
237
237
  exports: {
@@ -497,8 +497,8 @@ async function acquireLocalLock(lockName, options = {}) {
497
497
  while (retries <= maxRetries) {
498
498
  try {
499
499
  try {
500
- const stat4 = await fs3.stat(lockPath);
501
- if (Date.now() - stat4.mtimeMs > maxLockAgeMs) {
500
+ const stat6 = await fs3.stat(lockPath);
501
+ if (Date.now() - stat6.mtimeMs > maxLockAgeMs) {
502
502
  await fs3.unlink(lockPath);
503
503
  }
504
504
  } catch (err) {
@@ -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((resolve40) => setTimeout(resolve40, retryDelayMs));
534
+ await new Promise((resolve43) => setTimeout(resolve43, 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, path44, options = {}) {
1095
+ async function requestJson(baseUrl, method, path47, options = {}) {
1096
1096
  const fetchImpl = options.fetchImpl ?? fetch;
1097
- const url = `${baseUrl.replace(/\/+$/, "")}${path44.startsWith("/") ? path44 : `/${path44}`}`;
1097
+ const url = `${baseUrl.replace(/\/+$/, "")}${path47.startsWith("/") ? path47 : `/${path47}`}`;
1098
1098
  const res = await fetchImpl(url, {
1099
1099
  method,
1100
1100
  headers: {
@@ -1117,6 +1117,85 @@ async function requestJson(baseUrl, method, path44, options = {}) {
1117
1117
  }
1118
1118
  return { status: res.status, statusText: res.statusText, ok: res.ok, json };
1119
1119
  }
1120
+ function requireString(data, key, responseName) {
1121
+ const value = data[key];
1122
+ if (typeof value !== "string" || value.length === 0) {
1123
+ throw new Error(`[memoraone-mcp] Invalid ${responseName} response`);
1124
+ }
1125
+ return value;
1126
+ }
1127
+ function normalizePluginPairingSource(source) {
1128
+ if (source !== "cursor" && source !== "jetbrains") {
1129
+ throw new Error("[memoraone-mcp] Pairing source must be cursor or jetbrains");
1130
+ }
1131
+ return source;
1132
+ }
1133
+ function pairingRepositoryName(workspaceRoot) {
1134
+ const repositoryName = path8.basename(path8.resolve(workspaceRoot)).trim();
1135
+ if (repositoryName.length === 0 || repositoryName.length > 256 || repositoryName.includes("/") || repositoryName.includes("\\")) {
1136
+ throw new Error("[memoraone-mcp] Workspace basename is not safe pairing metadata");
1137
+ }
1138
+ return repositoryName;
1139
+ }
1140
+ async function createPluginPairingRequest(apiUrl, input2, options = {}) {
1141
+ const body = {
1142
+ repository_name: pairingRepositoryName(input2.workspaceRoot),
1143
+ source: normalizePluginPairingSource(input2.source)
1144
+ };
1145
+ const res = await requestJson(apiUrl, "POST", "/v1/local-connect/pairing-requests", {
1146
+ body,
1147
+ fetchImpl: options.fetchImpl
1148
+ });
1149
+ const data = res.json ?? {};
1150
+ return {
1151
+ requestId: requireString(data, "request_id", "pairing create"),
1152
+ pollingVerifier: requireString(data, "polling_verifier", "pairing create"),
1153
+ authorizationUrl: requireString(data, "authorization_url", "pairing create"),
1154
+ expiresAt: requireString(data, "expires_at", "pairing create")
1155
+ };
1156
+ }
1157
+ async function pollPluginPairingRequest(apiUrl, request, options = {}) {
1158
+ const requestId = encodeURIComponent(request.requestId);
1159
+ const res = await requestJson(
1160
+ apiUrl,
1161
+ "POST",
1162
+ `/v1/local-connect/pairing-requests/${requestId}/poll`,
1163
+ {
1164
+ body: { polling_verifier: request.pollingVerifier },
1165
+ fetchImpl: options.fetchImpl
1166
+ }
1167
+ );
1168
+ const data = res.json ?? {};
1169
+ const expiresAt = requireString(data, "expires_at", "pairing poll");
1170
+ if (data.status === "pending") {
1171
+ return { status: "pending", expiresAt };
1172
+ }
1173
+ if (data.status === "ready") {
1174
+ const code = requireString(data, "code", "pairing poll");
1175
+ if (!code.startsWith("mcc_")) {
1176
+ throw new Error("[memoraone-mcp] Invalid pairing poll response");
1177
+ }
1178
+ return { status: "ready", code, expiresAt };
1179
+ }
1180
+ throw new Error("[memoraone-mcp] Invalid pairing poll response");
1181
+ }
1182
+ async function cancelPluginPairingRequest(apiUrl, request, options = {}) {
1183
+ const requestId = encodeURIComponent(request.requestId);
1184
+ const res = await requestJson(
1185
+ apiUrl,
1186
+ "POST",
1187
+ `/v1/local-connect/pairing-requests/${requestId}/cancel`,
1188
+ {
1189
+ body: { polling_verifier: request.pollingVerifier },
1190
+ fetchImpl: options.fetchImpl
1191
+ }
1192
+ );
1193
+ const data = res.json ?? {};
1194
+ if (data.status !== "cancelled") {
1195
+ throw new Error("[memoraone-mcp] Invalid pairing cancel response");
1196
+ }
1197
+ return { status: "cancelled" };
1198
+ }
1120
1199
  function assertSafeRedeemBody(body) {
1121
1200
  if ("canonical_root" in body) {
1122
1201
  throw new Error("[memoraone-mcp] redeem body must not include canonical_root");
@@ -1273,6 +1352,30 @@ async function ensureRepositoryBindingForRoot(workspaceRoot, options = {}) {
1273
1352
  legacyM1WarningPath
1274
1353
  };
1275
1354
  }
1355
+ async function lookupLocalBindingIdentity(workspaceRoot, options = {}) {
1356
+ const resolved = path9.resolve(workspaceRoot);
1357
+ const identity = await captureRootFilesystemIdentity(resolved, options.identityDeps);
1358
+ const index = await loadPathIndex(options.homeDir);
1359
+ const lookup = lookupPathIndex(index, resolved, identity);
1360
+ if (lookup.kind !== "path") {
1361
+ return { status: "unbound", workspaceRoot: resolved };
1362
+ }
1363
+ const record = await readBindingRecord(lookup.repositoryBindingId, options.homeDir);
1364
+ if (!record) {
1365
+ return { status: "unbound", workspaceRoot: resolved };
1366
+ }
1367
+ if (path9.resolve(record.workspaceRoot) !== resolved) {
1368
+ return { status: "unbound", workspaceRoot: resolved };
1369
+ }
1370
+ if (!identityMatchesStored(record.filesystemIdentity, identity)) {
1371
+ return { status: "unbound", workspaceRoot: resolved };
1372
+ }
1373
+ return {
1374
+ status: "resolved",
1375
+ workspaceRoot: resolved,
1376
+ repositoryBindingId: record.repositoryBindingId
1377
+ };
1378
+ }
1276
1379
  async function resolveLocalBinding(workspaceRoot, options = {}) {
1277
1380
  const resolved = path9.resolve(workspaceRoot);
1278
1381
  const { repositoryBindingId, legacyM1WarningPath } = await ensureRepositoryBindingForRoot(
@@ -3394,7 +3497,7 @@ function resolveApiUrl(env2) {
3394
3497
  var DEFAULT_API_URL, DEV_API_URL;
3395
3498
  var init_configUtils = __esm({
3396
3499
  "src/configUtils.ts"() {
3397
- DEFAULT_API_URL = "http://localhost:3001";
3500
+ DEFAULT_API_URL = "https://api.memoraone.com";
3398
3501
  DEV_API_URL = "http://localhost:3001";
3399
3502
  }
3400
3503
  });
@@ -3549,11 +3652,11 @@ var init_repoFingerprint = __esm({
3549
3652
  };
3550
3653
  resolveGitDir = (gitPath) => {
3551
3654
  try {
3552
- const stat4 = fs13.statSync(gitPath);
3553
- if (stat4.isDirectory()) {
3655
+ const stat6 = fs13.statSync(gitPath);
3656
+ if (stat6.isDirectory()) {
3554
3657
  return gitPath;
3555
3658
  }
3556
- if (stat4.isFile()) {
3659
+ if (stat6.isFile()) {
3557
3660
  const content = fs13.readFileSync(gitPath, "utf8");
3558
3661
  const match = content.match(/^gitdir:\s*(.+)$/m);
3559
3662
  if (match) {
@@ -3644,8 +3747,8 @@ function getKnownJetBrainsMcpConfigLocations(homeDir, repoRoot) {
3644
3747
  }
3645
3748
  async function isZeroByteConfigFile(filePath) {
3646
3749
  if (!await pathExists3(filePath)) return false;
3647
- const stat4 = await fs14.stat(filePath);
3648
- return stat4.size === 0;
3750
+ const stat6 = await fs14.stat(filePath);
3751
+ return stat6.size === 0;
3649
3752
  }
3650
3753
  function stripDebugEnvVars(env2) {
3651
3754
  const next = {};
@@ -3847,7 +3950,7 @@ function formatOptionalJetBrainsHandshakeUnavailableDetail(detail) {
3847
3950
  async function verifyJetBrainsMcpHandshake(options) {
3848
3951
  const timeoutMs = options.timeoutMs ?? 15e3;
3849
3952
  const { server } = options;
3850
- return new Promise((resolve40) => {
3953
+ return new Promise((resolve43) => {
3851
3954
  let settled = false;
3852
3955
  const finish = (ok, detail, optionalUnavailable) => {
3853
3956
  if (settled) return;
@@ -3857,7 +3960,7 @@ async function verifyJetBrainsMcpHandshake(options) {
3857
3960
  child.kill();
3858
3961
  } catch {
3859
3962
  }
3860
- resolve40({ ok, detail, optionalUnavailable });
3963
+ resolve43({ ok, detail, optionalUnavailable });
3861
3964
  };
3862
3965
  const child = (0, import_node_child_process4.spawn)(server.command, [...server.args], {
3863
3966
  env: { ...process.env, ...server.env },
@@ -9528,6 +9631,14 @@ async function findRepoRoot(startDir) {
9528
9631
  function stripLeadingLineComments18(text) {
9529
9632
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
9530
9633
  }
9634
+ function memoraUsagePolicy() {
9635
+ return `- For every user question, check whether MemoraOne can provide relevant context before answering. If it can, use MemoraOne first.
9636
+ - Do not silently substitute IDE session history, local files, git history, or model memory when MemoraOne can provide relevant context.
9637
+ - Use **\`memora_status\`** for repository/project connection identity.
9638
+ - Use **\`memora_ask_with_memory\`** for previous questions/answers, conversation/history, decisions, facts, preferences, project context, and questions like "what did I/you say, ask, decide, or do before?"
9639
+ - Skip MemoraOne only when the question is clearly unrelated.
9640
+ - After the interaction: if anything meaningful happened\u2014question, answer, decision, discovery, action, correction, failure, or change\u2014record it back to MemoraOne so the next agent knows about it, especially if MemoraOne was not used before answering. Use **\`memora_post_event\`** and **\`memora_log_change_summary\`** according to their intended semantics; do not write trivial noise.`;
9641
+ }
9531
9642
  function cursorRuleBody() {
9532
9643
  return `${MANAGED_MARKER}
9533
9644
 
@@ -9537,7 +9648,7 @@ This repository uses **MemoraOne** via the MCP server named **memoraone** (repo-
9537
9648
 
9538
9649
  ### Tools
9539
9650
 
9540
- - Before answering questions about **prior decisions**, **remembered facts**, **identity or personal recall**, **preferences**, **repo history**, or **what to do next**, call **\`memora_ask_with_memory\`** so replies stay aligned with MemoraOne memory.
9651
+ ${memoraUsagePolicy()}
9541
9652
  - Use **\`memora_post_event\`** for durable project decisions, wiring, migrations, fixes, and meaningful product behavior changes. Prefer kind \`note\`, \`content.title\`, \`content.body\` (one concise, fact-promotable statement), and metadata \`source\` (e.g. \`cursor\`), \`purpose\`: \`dev-log\`, \`schema\`: \`v1\`.
9542
9653
  - Use **\`memora_log_change_summary\`** for concise code or feature deltas after implementation.
9543
9654
 
@@ -9555,7 +9666,7 @@ This repo is set up to use **MemoraOne** through MCP where your editor exposes i
9555
9666
 
9556
9667
  ## Behavior
9557
9668
 
9558
- - For questions about **earlier decisions**, **stored facts**, **personal or identity recall**, **preferences**, **project history**, or **recommended next steps**, use MemoraOne memory tools (e.g. **\`memora_ask_with_memory\`**) when available before answering.
9669
+ ${memoraUsagePolicy()}
9559
9670
  - Use **\`memora_post_event\`** for durable project decisions, wiring, migrations, fixes, and meaningful product behavior changes. Prefer kind \`note\`, \`content.title\`, \`content.body\` (one concise, fact-promotable statement), and metadata \`source\` (e.g. your agent name), \`purpose\`: \`dev-log\`, \`schema\`: \`v1\`.
9560
9671
  - Use **\`memora_log_change_summary\`** for concise code or feature deltas after implementation.
9561
9672
 
@@ -10317,6 +10428,7 @@ async function runSetupIdeFiles(o) {
10317
10428
  }
10318
10429
  const cursorContent = `---
10319
10430
  description: MemoraOne MCP \u2014 IDE agent instructions
10431
+ alwaysApply: true
10320
10432
  ---
10321
10433
 
10322
10434
  ` + cursorRuleBody();
@@ -12618,6 +12730,548 @@ var init_connectCommand = __esm({
12618
12730
  }
12619
12731
  });
12620
12732
 
12733
+ // src/pluginPairing.ts
12734
+ function backendErrorCode(error) {
12735
+ if (!(error instanceof MemoraOneHttpError) || !error.body || typeof error.body !== "object") {
12736
+ return void 0;
12737
+ }
12738
+ const code = error.body.error;
12739
+ return typeof code === "string" ? code : void 0;
12740
+ }
12741
+ function mapPairingError(error) {
12742
+ const code = backendErrorCode(error);
12743
+ if (code === "pairing_rejected") return "rejected";
12744
+ if (code === "pairing_cancelled") return "cancelled";
12745
+ if (code === "pairing_consumed") return "consumed";
12746
+ if (code === "pairing_expired") return "expired";
12747
+ if (code === "invalid_pairing_verifier" || code === "pairing_not_found" || code === "bad_request") {
12748
+ return "invalid";
12749
+ }
12750
+ if (error instanceof MemoraOneHttpError && error.status === 410) return "expired";
12751
+ if (error instanceof MemoraOneHttpError && (error.status === 400 || error.status === 401)) {
12752
+ return "invalid";
12753
+ }
12754
+ return "backend_failure";
12755
+ }
12756
+ async function beginPluginRepositoryPairing(options) {
12757
+ const workspaceRoot = path44.resolve(options.workspaceRoot);
12758
+ const apiUrl = (options.apiUrl ?? config2.apiUrl).replace(/\/+$/, "");
12759
+ if (options.source !== "cursor" && options.source !== "jetbrains") {
12760
+ throw new PluginPairingStartError("invalid");
12761
+ }
12762
+ try {
12763
+ pairingRepositoryName(workspaceRoot);
12764
+ } catch {
12765
+ throw new PluginPairingStartError("invalid");
12766
+ }
12767
+ let request;
12768
+ try {
12769
+ request = await createPluginPairingRequest(
12770
+ apiUrl,
12771
+ { workspaceRoot, source: options.source },
12772
+ { fetchImpl: options.fetchImpl }
12773
+ );
12774
+ } catch (error) {
12775
+ const status = mapPairingError(error);
12776
+ throw new PluginPairingStartError(status === "invalid" ? "invalid" : "backend_failure");
12777
+ }
12778
+ return new PluginRepositoryPairingSession(
12779
+ request,
12780
+ workspaceRoot,
12781
+ options.source,
12782
+ apiUrl,
12783
+ options.fetchImpl,
12784
+ options.connectOptions
12785
+ );
12786
+ }
12787
+ var path44, PluginPairingStartError, PluginRepositoryPairingSession;
12788
+ var init_pluginPairing = __esm({
12789
+ "src/pluginPairing.ts"() {
12790
+ path44 = __toESM(require("path"), 1);
12791
+ init_memoraClient();
12792
+ init_config();
12793
+ init_connectCommand();
12794
+ init_localConnectClient();
12795
+ PluginPairingStartError = class extends Error {
12796
+ constructor(status) {
12797
+ super(
12798
+ status === "invalid" ? "[memoraone-mcp] Invalid plugin pairing request" : "[memoraone-mcp] Plugin pairing request could not be created"
12799
+ );
12800
+ this.status = status;
12801
+ this.name = "PluginPairingStartError";
12802
+ }
12803
+ };
12804
+ PluginRepositoryPairingSession = class {
12805
+ constructor(request, workspaceRoot, source, apiUrl, fetchImpl, connectOptions = {}) {
12806
+ this.workspaceRoot = workspaceRoot;
12807
+ this.source = source;
12808
+ this.apiUrl = apiUrl;
12809
+ this.fetchImpl = fetchImpl;
12810
+ this.connectOptions = connectOptions;
12811
+ this.request = request;
12812
+ }
12813
+ /** Opaque, short-lived request metadata. Cleared when the session becomes terminal. */
12814
+ get requestId() {
12815
+ return this.request?.requestId;
12816
+ }
12817
+ get authorizationUrl() {
12818
+ return this.request?.authorizationUrl;
12819
+ }
12820
+ get expiresAt() {
12821
+ return this.request?.expiresAt;
12822
+ }
12823
+ finish(status) {
12824
+ this.terminalStatus = status;
12825
+ this.request = void 0;
12826
+ }
12827
+ async poll() {
12828
+ if (!this.request) {
12829
+ return {
12830
+ status: this.terminalStatus === "cancelled" ? "cancelled" : "consumed",
12831
+ operation: "poll"
12832
+ };
12833
+ }
12834
+ let polled;
12835
+ try {
12836
+ polled = await pollPluginPairingRequest(this.apiUrl, this.request, {
12837
+ fetchImpl: this.fetchImpl
12838
+ });
12839
+ } catch (error) {
12840
+ const status = mapPairingError(error);
12841
+ if (status !== "backend_failure") this.finish(status);
12842
+ return { status, operation: "poll" };
12843
+ }
12844
+ if (polled.status === "pending") {
12845
+ this.request.expiresAt = polled.expiresAt;
12846
+ return polled;
12847
+ }
12848
+ try {
12849
+ const connected = await runConnectCommand({
12850
+ ...this.connectOptions,
12851
+ code: polled.code,
12852
+ cwd: this.workspaceRoot,
12853
+ apiUrl: this.apiUrl,
12854
+ ideType: this.source,
12855
+ fetchImpl: this.connectOptions.fetchImpl ?? this.fetchImpl,
12856
+ // The marketplace plugin is the authoritative IDE launch source.
12857
+ configureIdes: false
12858
+ });
12859
+ if (connected.exitCode !== 0) {
12860
+ this.finish("backend_failure");
12861
+ return { status: "backend_failure", operation: "connect" };
12862
+ }
12863
+ this.finish("consumed");
12864
+ return {
12865
+ status: "ready",
12866
+ repositoryBindingId: connected.repositoryBindingId
12867
+ };
12868
+ } catch {
12869
+ this.finish("backend_failure");
12870
+ return { status: "backend_failure", operation: "connect" };
12871
+ }
12872
+ }
12873
+ async cancel() {
12874
+ if (!this.request) {
12875
+ const status = this.terminalStatus === "cancelled" ? "cancelled" : "consumed";
12876
+ return status === "cancelled" ? { status } : { status, operation: "cancel" };
12877
+ }
12878
+ try {
12879
+ await cancelPluginPairingRequest(this.apiUrl, this.request, {
12880
+ fetchImpl: this.fetchImpl
12881
+ });
12882
+ this.finish("cancelled");
12883
+ return { status: "cancelled" };
12884
+ } catch (error) {
12885
+ const status = mapPairingError(error);
12886
+ if (status !== "backend_failure") this.finish(status);
12887
+ return status === "cancelled" ? { status } : { status, operation: "cancel" };
12888
+ }
12889
+ }
12890
+ };
12891
+ }
12892
+ });
12893
+
12894
+ // src/pluginPairCommand.ts
12895
+ var pluginPairCommand_exports = {};
12896
+ __export(pluginPairCommand_exports, {
12897
+ DEFAULT_PLUGIN_PAIR_POLL_INTERVAL_MS: () => DEFAULT_PLUGIN_PAIR_POLL_INTERVAL_MS,
12898
+ PLUGIN_PAIR_USAGE: () => PLUGIN_PAIR_USAGE,
12899
+ cliPluginPair: () => cliPluginPair,
12900
+ parsePluginPairArgv: () => parsePluginPairArgv
12901
+ });
12902
+ function isPluginPairingSource(value) {
12903
+ return value === "cursor" || value === "jetbrains";
12904
+ }
12905
+ function parsePluginPairArgv(argv) {
12906
+ let workspaceRoot;
12907
+ let source;
12908
+ let apiUrl;
12909
+ for (let i = 0; i < argv.length; i++) {
12910
+ const a = argv[i];
12911
+ if (a === "--workspace-root") {
12912
+ const value = argv[++i];
12913
+ if (!value || value.startsWith("-")) return { error: PLUGIN_PAIR_USAGE };
12914
+ workspaceRoot = value;
12915
+ continue;
12916
+ }
12917
+ if (a.startsWith("--workspace-root=")) {
12918
+ const value = a.slice("--workspace-root=".length);
12919
+ if (!value) return { error: PLUGIN_PAIR_USAGE };
12920
+ workspaceRoot = value;
12921
+ continue;
12922
+ }
12923
+ if (a === "--source") {
12924
+ const value = argv[++i];
12925
+ if (!value || value.startsWith("-")) return { error: PLUGIN_PAIR_USAGE };
12926
+ source = value;
12927
+ continue;
12928
+ }
12929
+ if (a.startsWith("--source=")) {
12930
+ const value = a.slice("--source=".length);
12931
+ if (!value) return { error: PLUGIN_PAIR_USAGE };
12932
+ source = value;
12933
+ continue;
12934
+ }
12935
+ if (a === "--api-url") {
12936
+ const value = argv[++i];
12937
+ if (!value || value.startsWith("-")) return { error: PLUGIN_PAIR_USAGE };
12938
+ apiUrl = value;
12939
+ continue;
12940
+ }
12941
+ if (a.startsWith("--api-url=")) {
12942
+ const value = a.slice("--api-url=".length);
12943
+ if (!value) return { error: PLUGIN_PAIR_USAGE };
12944
+ apiUrl = value;
12945
+ continue;
12946
+ }
12947
+ if (a.startsWith("-")) {
12948
+ return { error: `Unknown plugin-pair option: ${a}` };
12949
+ }
12950
+ return { error: PLUGIN_PAIR_USAGE };
12951
+ }
12952
+ return { workspaceRoot, source, apiUrl };
12953
+ }
12954
+ function writeEvent(event, stdoutWrite) {
12955
+ const line = `${JSON.stringify(event)}
12956
+ `;
12957
+ if (SECRET_OUTPUT_RE.test(line)) {
12958
+ stdoutWrite(`${JSON.stringify({ event: "fatal", message: "Plugin pairing failed" })}
12959
+ `);
12960
+ return;
12961
+ }
12962
+ stdoutWrite(line);
12963
+ }
12964
+ function delay(ms, signal) {
12965
+ if (ms <= 0 || signal?.aborted) return Promise.resolve();
12966
+ return new Promise((resolve43) => {
12967
+ const timer = setTimeout(finish, ms);
12968
+ const onAbort = () => finish();
12969
+ function finish() {
12970
+ clearTimeout(timer);
12971
+ signal?.removeEventListener("abort", onAbort);
12972
+ resolve43();
12973
+ }
12974
+ signal?.addEventListener("abort", onAbort, { once: true });
12975
+ });
12976
+ }
12977
+ async function resolveWorkspaceRoot(workspaceRoot) {
12978
+ const resolved = path45.resolve(workspaceRoot);
12979
+ try {
12980
+ const st = await fs38.stat(resolved);
12981
+ if (!st.isDirectory()) {
12982
+ return { error: "workspace-root must be a directory" };
12983
+ }
12984
+ } catch {
12985
+ return { error: "workspace-root does not exist" };
12986
+ }
12987
+ return resolved;
12988
+ }
12989
+ function isRetryablePollFailure(result) {
12990
+ return result.status === "backend_failure" && result.operation === "poll";
12991
+ }
12992
+ function terminalEventFromPoll(result) {
12993
+ if (result.status === "pending" || result.status === "ready") return void 0;
12994
+ if (result.operation) {
12995
+ return { event: result.status, operation: result.operation };
12996
+ }
12997
+ return { event: result.status };
12998
+ }
12999
+ async function runPluginPairSession(session, options) {
13000
+ const { workspaceRoot, source, pollIntervalMs, signal, stdoutWrite } = options;
13001
+ const requestId = session.requestId;
13002
+ const authorizationUrl = session.authorizationUrl;
13003
+ const expiresAt = session.expiresAt;
13004
+ if (!requestId || !authorizationUrl || !expiresAt) {
13005
+ writeEvent({ event: "fatal", message: "Plugin pairing failed" }, stdoutWrite);
13006
+ return 1;
13007
+ }
13008
+ writeEvent(
13009
+ {
13010
+ event: "started",
13011
+ requestId,
13012
+ authorizationUrl,
13013
+ expiresAt,
13014
+ workspaceRoot,
13015
+ source
13016
+ },
13017
+ stdoutWrite
13018
+ );
13019
+ const cancelAndExit = async () => {
13020
+ const cancelled = await session.cancel();
13021
+ if (cancelled.status === "cancelled") {
13022
+ writeEvent({ event: "cancelled" }, stdoutWrite);
13023
+ } else {
13024
+ writeEvent(
13025
+ { event: cancelled.status, operation: cancelled.operation },
13026
+ stdoutWrite
13027
+ );
13028
+ }
13029
+ return 1;
13030
+ };
13031
+ while (!signal?.aborted) {
13032
+ const result = await session.poll();
13033
+ if (signal?.aborted) {
13034
+ if (result.status === "ready") {
13035
+ writeEvent(
13036
+ {
13037
+ event: "ready",
13038
+ repositoryBindingId: result.repositoryBindingId,
13039
+ workspaceRoot,
13040
+ source,
13041
+ status: "connected"
13042
+ },
13043
+ stdoutWrite
13044
+ );
13045
+ return 0;
13046
+ }
13047
+ return cancelAndExit();
13048
+ }
13049
+ if (result.status === "pending") {
13050
+ writeEvent({ event: "pending", expiresAt: result.expiresAt }, stdoutWrite);
13051
+ await delay(pollIntervalMs, signal);
13052
+ continue;
13053
+ }
13054
+ if (result.status === "ready") {
13055
+ writeEvent(
13056
+ {
13057
+ event: "ready",
13058
+ repositoryBindingId: result.repositoryBindingId,
13059
+ workspaceRoot,
13060
+ source,
13061
+ status: "connected"
13062
+ },
13063
+ stdoutWrite
13064
+ );
13065
+ return 0;
13066
+ }
13067
+ if (isRetryablePollFailure(result)) {
13068
+ await delay(pollIntervalMs, signal);
13069
+ continue;
13070
+ }
13071
+ const terminal = terminalEventFromPoll(result);
13072
+ if (terminal) {
13073
+ writeEvent(terminal, stdoutWrite);
13074
+ return 1;
13075
+ }
13076
+ writeEvent({ event: "fatal", message: "Plugin pairing failed" }, stdoutWrite);
13077
+ return 1;
13078
+ }
13079
+ return cancelAndExit();
13080
+ }
13081
+ async function cliPluginPair(argv, options = {}) {
13082
+ const stdoutWrite = options.stdoutWrite ?? ((chunk) => process.stdout.write(chunk));
13083
+ const parsed2 = parsePluginPairArgv(argv);
13084
+ if (parsed2.error) {
13085
+ writeEvent({ event: "fatal", message: parsed2.error }, stdoutWrite);
13086
+ return 1;
13087
+ }
13088
+ if (!parsed2.workspaceRoot || !parsed2.source) {
13089
+ writeEvent({ event: "fatal", message: PLUGIN_PAIR_USAGE }, stdoutWrite);
13090
+ return 1;
13091
+ }
13092
+ if (!isPluginPairingSource(parsed2.source)) {
13093
+ writeEvent({ event: "invalid" }, stdoutWrite);
13094
+ return 1;
13095
+ }
13096
+ const workspaceRootOrError = await resolveWorkspaceRoot(parsed2.workspaceRoot);
13097
+ if (typeof workspaceRootOrError !== "string") {
13098
+ writeEvent({ event: "fatal", message: workspaceRootOrError.error }, stdoutWrite);
13099
+ return 1;
13100
+ }
13101
+ const workspaceRoot = workspaceRootOrError;
13102
+ const source = parsed2.source;
13103
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_PLUGIN_PAIR_POLL_INTERVAL_MS;
13104
+ const beginPairing = options.beginPairing ?? beginPluginRepositoryPairing;
13105
+ try {
13106
+ const binding = await resolveAuthoritativeBinding(workspaceRoot);
13107
+ if (binding.status === "connected") {
13108
+ return 0;
13109
+ }
13110
+ } catch (error) {
13111
+ if (!(error instanceof ReconnectRequiredError)) {
13112
+ throw error;
13113
+ }
13114
+ }
13115
+ const abortController = new AbortController();
13116
+ const signal = options.signal ?? abortController.signal;
13117
+ const onStop = () => abortController.abort();
13118
+ const installSignalHandlers = options.installSignalHandlers === true;
13119
+ if (installSignalHandlers) {
13120
+ process.on("SIGINT", onStop);
13121
+ process.on("SIGTERM", onStop);
13122
+ }
13123
+ try {
13124
+ let session;
13125
+ try {
13126
+ session = await beginPairing({
13127
+ workspaceRoot,
13128
+ source,
13129
+ apiUrl: parsed2.apiUrl,
13130
+ fetchImpl: options.fetchImpl,
13131
+ connectOptions: options.connectOptions
13132
+ });
13133
+ } catch (error) {
13134
+ if (error instanceof PluginPairingStartError) {
13135
+ writeEvent({ event: error.status, operation: "start" }, stdoutWrite);
13136
+ return 1;
13137
+ }
13138
+ writeEvent({ event: "fatal", message: "Plugin pairing failed" }, stdoutWrite);
13139
+ return 1;
13140
+ }
13141
+ return await runPluginPairSession(session, {
13142
+ workspaceRoot,
13143
+ source,
13144
+ pollIntervalMs,
13145
+ signal,
13146
+ stdoutWrite
13147
+ });
13148
+ } finally {
13149
+ if (installSignalHandlers) {
13150
+ process.off("SIGINT", onStop);
13151
+ process.off("SIGTERM", onStop);
13152
+ }
13153
+ }
13154
+ }
13155
+ var fs38, path45, PLUGIN_PAIR_USAGE, DEFAULT_PLUGIN_PAIR_POLL_INTERVAL_MS, SECRET_OUTPUT_RE;
13156
+ var init_pluginPairCommand = __esm({
13157
+ "src/pluginPairCommand.ts"() {
13158
+ fs38 = __toESM(require("fs/promises"), 1);
13159
+ path45 = __toESM(require("path"), 1);
13160
+ init_pluginPairing();
13161
+ init_projectBinding();
13162
+ init_tokenRefreshCoordinator();
13163
+ PLUGIN_PAIR_USAGE = "Usage: memoraone-mcp plugin-pair --workspace-root <path> --source <cursor|jetbrains> [--api-url <url>]";
13164
+ DEFAULT_PLUGIN_PAIR_POLL_INTERVAL_MS = 1e3;
13165
+ SECRET_OUTPUT_RE = /\b(mcc_|mpv_|mia_|mir_|polling_verifier|pollingVerifier|access_token|refresh_token|api[_-]?key)\b/i;
13166
+ }
13167
+ });
13168
+
13169
+ // src/runtimeIdentityCommand.ts
13170
+ var runtimeIdentityCommand_exports = {};
13171
+ __export(runtimeIdentityCommand_exports, {
13172
+ RUNTIME_IDENTITY_USAGE: () => RUNTIME_IDENTITY_USAGE,
13173
+ cliRuntimeIdentity: () => cliRuntimeIdentity,
13174
+ parseRuntimeIdentityArgv: () => parseRuntimeIdentityArgv
13175
+ });
13176
+ function parseRuntimeIdentityArgv(argv) {
13177
+ let workspaceRoot;
13178
+ for (let i = 0; i < argv.length; i++) {
13179
+ const a = argv[i];
13180
+ if (a === "--workspace-root") {
13181
+ const value = argv[++i];
13182
+ if (!value || value.startsWith("-")) return { error: RUNTIME_IDENTITY_USAGE };
13183
+ workspaceRoot = value;
13184
+ continue;
13185
+ }
13186
+ if (a.startsWith("--workspace-root=")) {
13187
+ const value = a.slice("--workspace-root=".length);
13188
+ if (!value) return { error: RUNTIME_IDENTITY_USAGE };
13189
+ workspaceRoot = value;
13190
+ continue;
13191
+ }
13192
+ if (a.startsWith("-")) {
13193
+ return { error: `Unknown runtime-identity option: ${a}` };
13194
+ }
13195
+ return { error: RUNTIME_IDENTITY_USAGE };
13196
+ }
13197
+ return { workspaceRoot };
13198
+ }
13199
+ function writeJson(payload, stdoutWrite) {
13200
+ const line = `${JSON.stringify(payload)}
13201
+ `;
13202
+ if (SECRET_OUTPUT_RE2.test(line)) {
13203
+ stdoutWrite(`${JSON.stringify({ status: "error", error: "Runtime identity failed" })}
13204
+ `);
13205
+ return;
13206
+ }
13207
+ stdoutWrite(line);
13208
+ }
13209
+ async function resolveWorkspaceRoot2(workspaceRoot) {
13210
+ const resolved = path46.resolve(workspaceRoot);
13211
+ try {
13212
+ const st = await fs39.stat(resolved);
13213
+ if (!st.isDirectory()) {
13214
+ return { error: "workspace-root must be a directory", workspaceRoot: resolved };
13215
+ }
13216
+ } catch {
13217
+ return { error: "workspace-root does not exist", workspaceRoot: resolved };
13218
+ }
13219
+ return { workspaceRoot: resolved };
13220
+ }
13221
+ async function cliRuntimeIdentity(argv, options = {}) {
13222
+ const stdoutWrite = options.stdoutWrite ?? ((chunk) => process.stdout.write(chunk));
13223
+ const parsed2 = parseRuntimeIdentityArgv(argv);
13224
+ if (parsed2.error) {
13225
+ writeJson({ status: "error", error: parsed2.error }, stdoutWrite);
13226
+ return 1;
13227
+ }
13228
+ if (!parsed2.workspaceRoot) {
13229
+ writeJson({ status: "error", error: RUNTIME_IDENTITY_USAGE }, stdoutWrite);
13230
+ return 1;
13231
+ }
13232
+ const workspaceRootOrError = await resolveWorkspaceRoot2(parsed2.workspaceRoot);
13233
+ if ("error" in workspaceRootOrError) {
13234
+ writeJson(
13235
+ {
13236
+ status: "error",
13237
+ error: workspaceRootOrError.error,
13238
+ workspaceRoot: workspaceRootOrError.workspaceRoot
13239
+ },
13240
+ stdoutWrite
13241
+ );
13242
+ return 1;
13243
+ }
13244
+ const lookupIdentity = options.lookupIdentity ?? lookupLocalBindingIdentity;
13245
+ try {
13246
+ const result = await lookupIdentity(workspaceRootOrError.workspaceRoot, {
13247
+ homeDir: options.homeDir,
13248
+ identityDeps: options.identityDeps
13249
+ });
13250
+ writeJson(result, stdoutWrite);
13251
+ return 0;
13252
+ } catch {
13253
+ writeJson(
13254
+ {
13255
+ status: "error",
13256
+ error: "Runtime identity failed",
13257
+ workspaceRoot: workspaceRootOrError.workspaceRoot
13258
+ },
13259
+ stdoutWrite
13260
+ );
13261
+ return 1;
13262
+ }
13263
+ }
13264
+ var fs39, path46, RUNTIME_IDENTITY_USAGE, SECRET_OUTPUT_RE2;
13265
+ var init_runtimeIdentityCommand = __esm({
13266
+ "src/runtimeIdentityCommand.ts"() {
13267
+ fs39 = __toESM(require("fs/promises"), 1);
13268
+ path46 = __toESM(require("path"), 1);
13269
+ init_resolveLocalBinding();
13270
+ RUNTIME_IDENTITY_USAGE = "Usage: memoraone-mcp runtime-identity --workspace-root <path>";
13271
+ SECRET_OUTPUT_RE2 = /\b(mcc_|mpv_|mia_|mir_|polling_verifier|pollingVerifier|access_token|refresh_token|api[_-]?key|projectId|project_id)\b/i;
13272
+ }
13273
+ });
13274
+
12621
13275
  // src/bridgeClientRoots.ts
12622
13276
  function isInitializeDebugEnabled(env2 = process.env) {
12623
13277
  return TRUTHY.has(String(env2.MEMORAONE_DEBUG_INIT ?? "").trim().toLowerCase());
@@ -12758,8 +13412,8 @@ var init_bridgeClientRoots = __esm({
12758
13412
  if (this.closed) {
12759
13413
  return null;
12760
13414
  }
12761
- return new Promise((resolve40) => {
12762
- this.waiters.push(resolve40);
13415
+ return new Promise((resolve43) => {
13416
+ this.waiters.push(resolve43);
12763
13417
  });
12764
13418
  }
12765
13419
  /** Re-queue lines read during an intermediate protocol step (e.g. roots/list) for the main bridge loop. */
@@ -12986,9 +13640,9 @@ function extractJsonRpcId(line) {
12986
13640
  }
12987
13641
  }
12988
13642
  function connectWithRetry(socketPath, log, maxRetries, retryDelayMs, connect2) {
12989
- return new Promise((resolve40, reject) => {
13643
+ return new Promise((resolve43, reject) => {
12990
13644
  const tryConnect = (attempt) => {
12991
- connect2(socketPath).then(resolve40).catch((err) => {
13645
+ connect2(socketPath).then(resolve43).catch((err) => {
12992
13646
  if (attempt >= maxRetries) {
12993
13647
  reject(err);
12994
13648
  return;
@@ -13184,8 +13838,8 @@ var init_bridgeProxy = __esm({
13184
13838
  this.maxRetries = options.maxRetries ?? 5;
13185
13839
  this.retryDelayMs = options.retryDelayMs ?? 200;
13186
13840
  this.lineReader = options.lineReader ?? null;
13187
- this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve40, reject) => {
13188
- const socket = net.connect(socketPath, () => resolve40(socket));
13841
+ this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve43, reject) => {
13842
+ const socket = net.connect(socketPath, () => resolve43(socket));
13189
13843
  socket.on("error", reject);
13190
13844
  }));
13191
13845
  this.spawnDaemonImpl = options.spawnDaemon ?? (async (binding) => {
@@ -13317,7 +13971,7 @@ var init_bridgeProxy = __esm({
13317
13971
  }
13318
13972
  waitForDaemonJsonRpcResponse(id, timeoutMs = 3e4) {
13319
13973
  const key = this.waiterKey(id);
13320
- return new Promise((resolve40, reject) => {
13974
+ return new Promise((resolve43, reject) => {
13321
13975
  const timer = setTimeout(() => {
13322
13976
  this.pendingDaemonResponseWaiters.delete(key);
13323
13977
  reject(
@@ -13326,7 +13980,7 @@ var init_bridgeProxy = __esm({
13326
13980
  )
13327
13981
  );
13328
13982
  }, timeoutMs);
13329
- this.pendingDaemonResponseWaiters.set(key, { resolve: resolve40, reject, timer });
13983
+ this.pendingDaemonResponseWaiters.set(key, { resolve: resolve43, reject, timer });
13330
13984
  });
13331
13985
  }
13332
13986
  notifyDaemonResponseWaiters(line) {
@@ -13513,6 +14167,8 @@ if (args.includes("--help") || args.includes("-h")) {
13513
14167
  console.log(
13514
14168
  `Usage: memoraone-mcp [--version] [--help]
13515
14169
  memoraone-mcp connect <code> [--api-url <url>] [--verbose]
14170
+ memoraone-mcp plugin-pair --workspace-root <path> --source <cursor|jetbrains> [--api-url <url>]
14171
+ memoraone-mcp runtime-identity --workspace-root <path>
13516
14172
  memoraone-mcp [--daemon --binding-id <mrb_\u2026> [--ide ${IDE_TYPE_CLI_CHOICES}]]
13517
14173
  memoraone-mcp setup-ide-files [--all|--cursor|--vscode|--jetbrains|--claude-code|--windsurf|--opencode|--codex|--kiro|--kiro-cli|--cline|--cline-cli|--claude-desktop|--zed|--visual-studio|--copilot-cli|--auggie|--antigravity|--goose|--junie|--xcode|--copilot-jetbrains|--copilot-visual-studio] [--force] [--dry-run] [--no-gitignore] [--cleanup] [--dev] [--repair] [--workspace-root <path>] [--api-url <url>] [--verbose]
13518
14174
  Cursor API environment (with --cursor or --all): --local (node + built cli.cjs + local API) | --staging (npx + staging API)
@@ -13535,6 +14191,28 @@ if (args[0] === "cleanup") {
13535
14191
  `);
13536
14192
  process.exit(1);
13537
14193
  });
14194
+ } else if (args[0] === "plugin-pair") {
14195
+ Promise.resolve().then(() => (init_pluginPairCommand(), pluginPairCommand_exports)).then(
14196
+ ({ cliPluginPair: cliPluginPair2 }) => cliPluginPair2(args.slice(1), { installSignalHandlers: true })
14197
+ ).then((code) => process.exit(code)).catch((err) => {
14198
+ process.stdout.write(
14199
+ `${JSON.stringify({ event: "fatal", message: "Plugin pairing failed" })}
14200
+ `
14201
+ );
14202
+ process.stderr.write(`[memoraone-mcp] plugin-pair fatal: ${String(err)}
14203
+ `);
14204
+ process.exit(1);
14205
+ });
14206
+ } else if (args[0] === "runtime-identity") {
14207
+ Promise.resolve().then(() => (init_runtimeIdentityCommand(), runtimeIdentityCommand_exports)).then(({ cliRuntimeIdentity: cliRuntimeIdentity2 }) => cliRuntimeIdentity2(args.slice(1))).then((code) => process.exit(code)).catch((err) => {
14208
+ process.stdout.write(
14209
+ `${JSON.stringify({ status: "error", error: "Runtime identity failed" })}
14210
+ `
14211
+ );
14212
+ process.stderr.write(`[memoraone-mcp] runtime-identity fatal: ${String(err)}
14213
+ `);
14214
+ process.exit(1);
14215
+ });
13538
14216
  } else if (args[0] === "setup-ide-files") {
13539
14217
  Promise.resolve().then(() => (init_setupIdeFiles(), setupIdeFiles_exports)).then(({ cliSetupIdeFiles: cliSetupIdeFiles2 }) => cliSetupIdeFiles2(args.slice(1))).then((code) => process.exit(code)).catch((err) => {
13540
14218
  process.stderr.write(`[memoraone-mcp] setup-ide-files fatal: ${String(err)}
package/dist/daemon.cjs CHANGED
@@ -1528,7 +1528,7 @@ var dotenv = __toESM(require("dotenv"), 1);
1528
1528
  var import_v4 = require("zod/v4");
1529
1529
 
1530
1530
  // src/configUtils.ts
1531
- var DEFAULT_API_URL = "http://localhost:3001";
1531
+ var DEFAULT_API_URL = "https://api.memoraone.com";
1532
1532
  var DEV_API_URL = "http://localhost:3001";
1533
1533
  function resolveApiUrl(env2) {
1534
1534
  const explicitUrl = env2.MEMORAONE_API_URL?.trim();
@@ -3437,7 +3437,7 @@ async function main(opts = {}) {
3437
3437
  registeredToolNames.push("memora_get_personal_context");
3438
3438
  server.tool(
3439
3439
  "memora_status",
3440
- "Return non-secret project binding metadata for this MCP session",
3440
+ "Return non-secret project binding metadata for this MCP session. Use this for repository/project connection identity: which repository or project this session is bound to. Prefer this over guessing from local files, git remotes, or IDE context.",
3441
3441
  bindingStatusShape,
3442
3442
  async () => runWithSessionContext(sessionContext, async () => {
3443
3443
  if (!runtime.authoritativeBinding) return notInitializedResult;
@@ -3455,7 +3455,7 @@ async function main(opts = {}) {
3455
3455
  runtime,
3456
3456
  sessionContext,
3457
3457
  "memora_ask_with_memory",
3458
- "Answer using saved workspace knowledge and timeline. In user-visible replies, state facts directly; do not attribute answers to tools, storage, retrieval, or memory-style framing unless the user asks how you know.",
3458
+ 'Answer using saved workspace knowledge and timeline. Use this before answering previous questions/answers, conversation/history, decisions, facts, preferences, project context, or questions like "what did I/you say, ask, decide, or do before?". Do not silently substitute IDE session history, local files, git history, or model memory when MemoraOne can provide relevant context. Skip only when the question is clearly unrelated. In user-visible replies, state facts directly; do not attribute answers to tools, storage, retrieval, or memory-style framing unless the user asks how you know.',
3459
3459
  askWithMemoryShape,
3460
3460
  async (args) => {
3461
3461
  const result = await handleAskWithMemory(runtime.client, args);
package/dist/index.cjs CHANGED
@@ -45,7 +45,7 @@ var dotenv = __toESM(require("dotenv"), 1);
45
45
  var import_v4 = require("zod/v4");
46
46
 
47
47
  // src/configUtils.ts
48
- var DEFAULT_API_URL = "http://localhost:3001";
48
+ var DEFAULT_API_URL = "https://api.memoraone.com";
49
49
  var DEV_API_URL = "http://localhost:3001";
50
50
  function resolveApiUrl(env2) {
51
51
  const explicitUrl = env2.MEMORAONE_API_URL?.trim();
@@ -3363,7 +3363,7 @@ async function main(opts = {}) {
3363
3363
  registeredToolNames.push("memora_get_personal_context");
3364
3364
  server.tool(
3365
3365
  "memora_status",
3366
- "Return non-secret project binding metadata for this MCP session",
3366
+ "Return non-secret project binding metadata for this MCP session. Use this for repository/project connection identity: which repository or project this session is bound to. Prefer this over guessing from local files, git remotes, or IDE context.",
3367
3367
  bindingStatusShape,
3368
3368
  async () => runWithSessionContext(sessionContext, async () => {
3369
3369
  if (!runtime.authoritativeBinding) return notInitializedResult;
@@ -3381,7 +3381,7 @@ async function main(opts = {}) {
3381
3381
  runtime,
3382
3382
  sessionContext,
3383
3383
  "memora_ask_with_memory",
3384
- "Answer using saved workspace knowledge and timeline. In user-visible replies, state facts directly; do not attribute answers to tools, storage, retrieval, or memory-style framing unless the user asks how you know.",
3384
+ 'Answer using saved workspace knowledge and timeline. Use this before answering previous questions/answers, conversation/history, decisions, facts, preferences, project context, or questions like "what did I/you say, ask, decide, or do before?". Do not silently substitute IDE session history, local files, git history, or model memory when MemoraOne can provide relevant context. Skip only when the question is clearly unrelated. In user-visible replies, state facts directly; do not attribute answers to tools, storage, retrieval, or memory-style framing unless the user asks how you know.',
3385
3385
  askWithMemoryShape,
3386
3386
  async (args) => {
3387
3387
  const result = await handleAskWithMemory(runtime.client, args);
@@ -745,7 +745,7 @@ var dotenv = __toESM(require("dotenv"), 1);
745
745
  var import_v4 = require("zod/v4");
746
746
 
747
747
  // src/configUtils.ts
748
- var DEFAULT_API_URL = "http://localhost:3001";
748
+ var DEFAULT_API_URL = "https://api.memoraone.com";
749
749
  var DEV_API_URL = "http://localhost:3001";
750
750
  function resolveApiUrl(env2) {
751
751
  const explicitUrl = env2.MEMORAONE_API_URL?.trim();
@@ -7526,6 +7526,14 @@ async function findRepoRoot(startDir) {
7526
7526
  function stripLeadingLineComments18(text) {
7527
7527
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
7528
7528
  }
7529
+ function memoraUsagePolicy() {
7530
+ return `- For every user question, check whether MemoraOne can provide relevant context before answering. If it can, use MemoraOne first.
7531
+ - Do not silently substitute IDE session history, local files, git history, or model memory when MemoraOne can provide relevant context.
7532
+ - Use **\`memora_status\`** for repository/project connection identity.
7533
+ - Use **\`memora_ask_with_memory\`** for previous questions/answers, conversation/history, decisions, facts, preferences, project context, and questions like "what did I/you say, ask, decide, or do before?"
7534
+ - Skip MemoraOne only when the question is clearly unrelated.
7535
+ - After the interaction: if anything meaningful happened\u2014question, answer, decision, discovery, action, correction, failure, or change\u2014record it back to MemoraOne so the next agent knows about it, especially if MemoraOne was not used before answering. Use **\`memora_post_event\`** and **\`memora_log_change_summary\`** according to their intended semantics; do not write trivial noise.`;
7536
+ }
7529
7537
  function cursorRuleBody() {
7530
7538
  return `${MANAGED_MARKER}
7531
7539
 
@@ -7535,7 +7543,7 @@ This repository uses **MemoraOne** via the MCP server named **memoraone** (repo-
7535
7543
 
7536
7544
  ### Tools
7537
7545
 
7538
- - Before answering questions about **prior decisions**, **remembered facts**, **identity or personal recall**, **preferences**, **repo history**, or **what to do next**, call **\`memora_ask_with_memory\`** so replies stay aligned with MemoraOne memory.
7546
+ ${memoraUsagePolicy()}
7539
7547
  - Use **\`memora_post_event\`** for durable project decisions, wiring, migrations, fixes, and meaningful product behavior changes. Prefer kind \`note\`, \`content.title\`, \`content.body\` (one concise, fact-promotable statement), and metadata \`source\` (e.g. \`cursor\`), \`purpose\`: \`dev-log\`, \`schema\`: \`v1\`.
7540
7548
  - Use **\`memora_log_change_summary\`** for concise code or feature deltas after implementation.
7541
7549
 
@@ -7553,7 +7561,7 @@ This repo is set up to use **MemoraOne** through MCP where your editor exposes i
7553
7561
 
7554
7562
  ## Behavior
7555
7563
 
7556
- - For questions about **earlier decisions**, **stored facts**, **personal or identity recall**, **preferences**, **project history**, or **recommended next steps**, use MemoraOne memory tools (e.g. **\`memora_ask_with_memory\`**) when available before answering.
7564
+ ${memoraUsagePolicy()}
7557
7565
  - Use **\`memora_post_event\`** for durable project decisions, wiring, migrations, fixes, and meaningful product behavior changes. Prefer kind \`note\`, \`content.title\`, \`content.body\` (one concise, fact-promotable statement), and metadata \`source\` (e.g. your agent name), \`purpose\`: \`dev-log\`, \`schema\`: \`v1\`.
7558
7566
  - Use **\`memora_log_change_summary\`** for concise code or feature deltas after implementation.
7559
7567
 
@@ -7927,6 +7935,7 @@ async function runSetupIdeFiles(o) {
7927
7935
  }
7928
7936
  const cursorContent = `---
7929
7937
  description: MemoraOne MCP \u2014 IDE agent instructions
7938
+ alwaysApply: true
7930
7939
  ---
7931
7940
 
7932
7941
  ` + cursorRuleBody();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoraone/mcp",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "exports": {