@memoraone/mcp 0.1.31 → 0.1.33

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.
Files changed (2) hide show
  1. package/dist/cli.cjs +205 -71
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -30,7 +30,7 @@ var require_package = __commonJS({
30
30
  "package.json"(exports2, module2) {
31
31
  module2.exports = {
32
32
  name: "@memoraone/mcp",
33
- version: "0.1.31",
33
+ version: "0.1.33",
34
34
  type: "module",
35
35
  main: "dist/index.cjs",
36
36
  bin: {
@@ -562,8 +562,8 @@ var StdioLineReader = class {
562
562
  if (this.closed) {
563
563
  return null;
564
564
  }
565
- return new Promise((resolve8) => {
566
- this.waiters.push(resolve8);
565
+ return new Promise((resolve9) => {
566
+ this.waiters.push(resolve9);
567
567
  });
568
568
  }
569
569
  /** Re-queue lines read during an intermediate protocol step (e.g. roots/list) for the main bridge loop. */
@@ -822,9 +822,9 @@ function summarizeJsonRpcMethod(line) {
822
822
  }
823
823
  }
824
824
  function connectWithRetry(socketPath, log, maxRetries, retryDelayMs, connect2) {
825
- return new Promise((resolve8, reject) => {
825
+ return new Promise((resolve9, reject) => {
826
826
  const tryConnect = (attempt) => {
827
- connect2(socketPath).then(resolve8).catch((err) => {
827
+ connect2(socketPath).then(resolve9).catch((err) => {
828
828
  if (attempt >= maxRetries) {
829
829
  reject(err);
830
830
  return;
@@ -897,8 +897,8 @@ var BridgeDaemonRouter = class {
897
897
  this.maxRetries = options.maxRetries ?? 5;
898
898
  this.retryDelayMs = options.retryDelayMs ?? 200;
899
899
  this.lineReader = options.lineReader ?? null;
900
- this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve8, reject) => {
901
- const socket = net.connect(socketPath, () => resolve8(socket));
900
+ this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve9, reject) => {
901
+ const socket = net.connect(socketPath, () => resolve9(socket));
902
902
  socket.on("error", reject);
903
903
  }));
904
904
  this.spawnDaemonImpl = options.spawnDaemon ?? (async (binding) => {
@@ -1142,9 +1142,9 @@ async function runBridgeProxy(options) {
1142
1142
  }
1143
1143
 
1144
1144
  // src/setupIdeFiles.ts
1145
- var fs7 = __toESM(require("fs/promises"), 1);
1145
+ var fs8 = __toESM(require("fs/promises"), 1);
1146
1146
  var os4 = __toESM(require("os"), 1);
1147
- var path9 = __toESM(require("path"), 1);
1147
+ var path10 = __toESM(require("path"), 1);
1148
1148
 
1149
1149
  // src/cleanup.ts
1150
1150
  var fs5 = __toESM(require("fs/promises"), 1);
@@ -1161,16 +1161,38 @@ var path6 = __toESM(require("path"), 1);
1161
1161
  var import_node_child_process2 = require("child_process");
1162
1162
  var import_node_util = require("util");
1163
1163
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process2.execFile);
1164
- function buildMemoraoneCursorMcpServer(npxPath, workspaceRoot) {
1164
+ var MEMORAONE_PROD_API_URL = "https://api.memoraone.com";
1165
+ var MEMORAONE_LOCAL_API_URL = "http://localhost:3001";
1166
+ var MEMORAONE_STAGING_API_URL = "https://memora-api-staging-phbtrzocjq-uk.a.run.app";
1167
+ var MEMORAONE_STAGING_API_URL_PREFIX = "https://memora-api-staging-";
1168
+ function cursorMcpApiUrl(environment) {
1169
+ if (environment === "local") return MEMORAONE_LOCAL_API_URL;
1170
+ if (environment === "staging") return MEMORAONE_STAGING_API_URL;
1171
+ return MEMORAONE_PROD_API_URL;
1172
+ }
1173
+ function buildMemoraoneCursorMcpServer(options) {
1165
1174
  const env = {
1166
- MEMORAONE_API_URL: "https://api.memoraone.com",
1175
+ MEMORAONE_API_URL: cursorMcpApiUrl(options.environment),
1167
1176
  MEMORAONE_IDE_TYPE: "cursor"
1168
1177
  };
1169
- if (workspaceRoot !== void 0) {
1170
- env[MEMORAONE_WORKSPACE_ROOT_ENV] = path6.resolve(workspaceRoot);
1178
+ if (options.workspaceRoot !== void 0) {
1179
+ env[MEMORAONE_WORKSPACE_ROOT_ENV] = path6.resolve(options.workspaceRoot);
1180
+ }
1181
+ if (options.environment === "local") {
1182
+ if (!options.cliPath) {
1183
+ throw new Error("[setup-ide-files] Local Cursor MCP config requires a built CLI path.");
1184
+ }
1185
+ return {
1186
+ command: "node",
1187
+ args: [options.cliPath],
1188
+ env
1189
+ };
1190
+ }
1191
+ if (!options.npxPath) {
1192
+ throw new Error("[setup-ide-files] Cursor MCP config requires a resolved npx path.");
1171
1193
  }
1172
1194
  return {
1173
- command: npxPath,
1195
+ command: options.npxPath,
1174
1196
  args: ["-y", "@memoraone/mcp@latest"],
1175
1197
  env
1176
1198
  };
@@ -1269,12 +1291,24 @@ async function resolveNpxPath() {
1269
1291
  }
1270
1292
  return null;
1271
1293
  }
1272
- function mergeCursorRepoMcpConfigObject(existing, npxPath, repoRoot) {
1294
+ function mergeCursorRepoMcpConfigObject(existing, writeOptions) {
1295
+ const environment = writeOptions.environment ?? "production";
1273
1296
  const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
1274
1297
  const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
1275
- mcpServers.memoraone = buildMemoraoneCursorMcpServer(npxPath, repoRoot);
1298
+ mcpServers.memoraone = buildMemoraoneCursorMcpServer({
1299
+ environment,
1300
+ npxPath: writeOptions.npxPath,
1301
+ cliPath: writeOptions.cliPath,
1302
+ workspaceRoot: writeOptions.repoRoot
1303
+ });
1276
1304
  return { ...base, mcpServers };
1277
1305
  }
1306
+ function isMemoraoneManagedApiUrl(url) {
1307
+ if (typeof url !== "string" || url.length === 0) return false;
1308
+ if (url === MEMORAONE_PROD_API_URL) return true;
1309
+ if (url === MEMORAONE_LOCAL_API_URL) return true;
1310
+ return url.startsWith(MEMORAONE_STAGING_API_URL_PREFIX);
1311
+ }
1278
1312
  function isManagedMemoraoneCursorServer(server) {
1279
1313
  if (!server || typeof server !== "object") return false;
1280
1314
  const s = server;
@@ -1282,7 +1316,7 @@ function isManagedMemoraoneCursorServer(server) {
1282
1316
  if (s.args[0] !== "-y" || s.args[1] !== "@memoraone/mcp@latest") return false;
1283
1317
  const env = s.env;
1284
1318
  if (!env || typeof env !== "object") return false;
1285
- return memoraoneEnvMatchesBase(env);
1319
+ return memoraoneEnvMatchesManagedCleanupShape(env);
1286
1320
  }
1287
1321
  function cursorConfigHasManagedMemoraone(parsed) {
1288
1322
  if (!parsed || typeof parsed !== "object") return false;
@@ -1290,8 +1324,8 @@ function cursorConfigHasManagedMemoraone(parsed) {
1290
1324
  if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) return false;
1291
1325
  return isManagedMemoraoneCursorServer(mcpServers.memoraone);
1292
1326
  }
1293
- function memoraoneEnvMatchesBase(env) {
1294
- return env.MEMORAONE_API_URL === "https://api.memoraone.com" && env.MEMORAONE_IDE_TYPE === "cursor";
1327
+ function memoraoneEnvMatchesManagedCleanupShape(env) {
1328
+ return env.MEMORAONE_IDE_TYPE === "cursor" && isMemoraoneManagedApiUrl(env.MEMORAONE_API_URL);
1295
1329
  }
1296
1330
  function getCursorRepoMcpConfigPath(repoRoot) {
1297
1331
  return path6.join(repoRoot, ".cursor", "mcp.json");
@@ -1386,9 +1420,13 @@ function logCursorMcpConfigAudit(prefix, audit) {
1386
1420
  }
1387
1421
  }
1388
1422
  function logCursorMcpCliSummary(info, dryRun) {
1389
- const { repoConfigPath, repoOutcome, npxPath, repoBackupPath, globalConfigPath, globalMemoraoneRemoved, globalBackupPath } = info;
1423
+ const { repoConfigPath, repoOutcome, npxPath, cliPath, repoBackupPath, globalConfigPath, globalMemoraoneRemoved, globalBackupPath } = info;
1390
1424
  console.log(`[setup-ide-files] Cursor repo MCP config: ${repoConfigPath}`);
1391
- console.log(`[setup-ide-files] Resolved npx: ${npxPath}`);
1425
+ if (cliPath) {
1426
+ console.log(`[setup-ide-files] Resolved local CLI: ${cliPath}`);
1427
+ } else if (npxPath) {
1428
+ console.log(`[setup-ide-files] Resolved npx: ${npxPath}`);
1429
+ }
1392
1430
  if (repoBackupPath) {
1393
1431
  console.log(`[setup-ide-files] Cursor repo MCP config backup: ${repoBackupPath}`);
1394
1432
  }
@@ -2085,7 +2123,7 @@ async function buildJetBrainsMemoraoneServer(options) {
2085
2123
  async function verifyJetBrainsMcpHandshake(options) {
2086
2124
  const timeoutMs = options.timeoutMs ?? 15e3;
2087
2125
  const { server } = options;
2088
- return new Promise((resolve8) => {
2126
+ return new Promise((resolve9) => {
2089
2127
  let settled = false;
2090
2128
  const finish = (ok, detail) => {
2091
2129
  if (settled) return;
@@ -2095,7 +2133,7 @@ async function verifyJetBrainsMcpHandshake(options) {
2095
2133
  child.kill();
2096
2134
  } catch {
2097
2135
  }
2098
- resolve8({ ok, detail });
2136
+ resolve9({ ok, detail });
2099
2137
  };
2100
2138
  const child = (0, import_node_child_process4.spawn)(server.command, [...server.args], {
2101
2139
  env: { ...process.env, ...server.env },
@@ -2299,6 +2337,60 @@ function logJetBrainsMcpCliSummary(info, dryRun) {
2299
2337
  );
2300
2338
  }
2301
2339
 
2340
+ // src/resolveBuiltCliPath.ts
2341
+ var fs7 = __toESM(require("fs/promises"), 1);
2342
+ var path9 = __toESM(require("path"), 1);
2343
+ var MONOREPO_CLI_REL = path9.join("packages", "mcp", "dist", "cli.cjs");
2344
+ async function pathExists3(filePath) {
2345
+ try {
2346
+ await fs7.access(filePath);
2347
+ return true;
2348
+ } catch {
2349
+ return false;
2350
+ }
2351
+ }
2352
+ async function findMonorepoCliFrom(startDir) {
2353
+ let current = path9.resolve(startDir);
2354
+ const root = path9.parse(current).root;
2355
+ while (true) {
2356
+ const candidate = path9.join(current, MONOREPO_CLI_REL);
2357
+ if (await pathExists3(candidate)) {
2358
+ return path9.resolve(candidate);
2359
+ }
2360
+ if (current === root) break;
2361
+ current = path9.dirname(current);
2362
+ }
2363
+ return null;
2364
+ }
2365
+ async function resolveBuiltCliPathAsync(options) {
2366
+ const searchDirs = [];
2367
+ if (options?.searchFrom !== void 0) {
2368
+ const dirs = Array.isArray(options.searchFrom) ? options.searchFrom : [options.searchFrom];
2369
+ searchDirs.push(...dirs);
2370
+ }
2371
+ searchDirs.push(process.cwd());
2372
+ const seen = /* @__PURE__ */ new Set();
2373
+ for (const dir of searchDirs) {
2374
+ const key = path9.resolve(dir);
2375
+ if (seen.has(key)) continue;
2376
+ seen.add(key);
2377
+ const found = await findMonorepoCliFrom(key);
2378
+ if (found) return found;
2379
+ }
2380
+ const here = process.argv[1] ? path9.dirname(path9.resolve(process.argv[1])) : process.cwd();
2381
+ const candidates = [
2382
+ path9.join(here, "cli.cjs"),
2383
+ path9.join(here, "..", "dist", "cli.cjs"),
2384
+ path9.join(here, "..", "..", "dist", "cli.cjs")
2385
+ ];
2386
+ for (const candidate of candidates) {
2387
+ if (await pathExists3(candidate)) {
2388
+ return path9.resolve(candidate);
2389
+ }
2390
+ }
2391
+ return null;
2392
+ }
2393
+
2302
2394
  // src/setupIdeFiles.ts
2303
2395
  var MANAGED_MARKER = "<!-- MemoraOne managed IDE helper -->";
2304
2396
  var GITIGNORE_MEMORAONE_COMMENT = "# MemoraOne local project binding / API key";
@@ -2314,15 +2406,15 @@ function buildMemoraoneMcpServer(ideType, command = "npx") {
2314
2406
  };
2315
2407
  }
2316
2408
  function assertUnderRepoRoot(repoRoot, absPath) {
2317
- const normRoot = path9.resolve(repoRoot) + path9.sep;
2318
- const normPath = path9.resolve(absPath);
2319
- if (normPath !== path9.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
2409
+ const normRoot = path10.resolve(repoRoot) + path10.sep;
2410
+ const normPath = path10.resolve(absPath);
2411
+ if (normPath !== path10.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
2320
2412
  throw new Error(`[setup-ide-files] Refusing to write outside repo root: ${absPath}`);
2321
2413
  }
2322
2414
  }
2323
- async function pathExists3(filePath) {
2415
+ async function pathExists4(filePath) {
2324
2416
  try {
2325
- await fs7.access(filePath);
2417
+ await fs8.access(filePath);
2326
2418
  return true;
2327
2419
  } catch {
2328
2420
  return false;
@@ -2343,12 +2435,12 @@ ${GITIGNORE_MEMORAONE_ENTRY}
2343
2435
  }
2344
2436
  async function ensureGitignoreMemoraone(repoRoot, opts) {
2345
2437
  if (opts.noGitignore) return "skipped";
2346
- const abs = path9.join(repoRoot, ".gitignore");
2438
+ const abs = path10.join(repoRoot, ".gitignore");
2347
2439
  assertUnderRepoRoot(repoRoot, abs);
2348
2440
  let prior = "";
2349
2441
  let existed = false;
2350
2442
  try {
2351
- prior = await fs7.readFile(abs, "utf8");
2443
+ prior = await fs8.readFile(abs, "utf8");
2352
2444
  existed = true;
2353
2445
  } catch (err) {
2354
2446
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
@@ -2359,22 +2451,22 @@ async function ensureGitignoreMemoraone(repoRoot, opts) {
2359
2451
  const separator = existed && prior.length > 0 ? prior.endsWith("\n") ? "\n" : "\n\n" : "";
2360
2452
  const next = (existed ? prior : "") + separator + block;
2361
2453
  if (opts.dryRun) return existed ? "updated" : "created";
2362
- await fs7.writeFile(abs, next, "utf8");
2454
+ await fs8.writeFile(abs, next, "utf8");
2363
2455
  return existed ? "updated" : "created";
2364
2456
  }
2365
2457
  async function findRepoRoot(startDir) {
2366
- let current = path9.resolve(startDir);
2367
- const root = path9.parse(current).root;
2458
+ let current = path10.resolve(startDir);
2459
+ const root = path10.parse(current).root;
2368
2460
  while (true) {
2369
- const gitPath = path9.join(current, ".git");
2370
- const m1Path = path9.join(current, "memoraone.m1");
2371
- if (await pathExists3(gitPath) || await pathExists3(m1Path)) {
2461
+ const gitPath = path10.join(current, ".git");
2462
+ const m1Path = path10.join(current, "memoraone.m1");
2463
+ if (await pathExists4(gitPath) || await pathExists4(m1Path)) {
2372
2464
  return current;
2373
2465
  }
2374
2466
  if (current === root) {
2375
2467
  return null;
2376
2468
  }
2377
- current = path9.dirname(current);
2469
+ current = path10.dirname(current);
2378
2470
  }
2379
2471
  }
2380
2472
  function stripLeadingLineComments3(text) {
@@ -2427,47 +2519,47 @@ function buildVscodeMcpJsonBody(existing) {
2427
2519
  const merged = { ...base, servers };
2428
2520
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
2429
2521
  }
2430
- function buildCursorMcpJsonBody(existing, npxPath, repoRoot) {
2431
- const merged = mergeCursorRepoMcpConfigObject(existing, npxPath, repoRoot);
2522
+ function buildCursorMcpJsonBody(existing, writeOptions) {
2523
+ const merged = mergeCursorRepoMcpConfigObject(existing, writeOptions);
2432
2524
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
2433
2525
  }
2434
2526
  async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
2435
- const abs = path9.join(repoRoot, relPath);
2527
+ const abs = path10.join(repoRoot, relPath);
2436
2528
  assertUnderRepoRoot(repoRoot, abs);
2437
2529
  let prior = "";
2438
2530
  let existed = false;
2439
2531
  try {
2440
- prior = await fs7.readFile(abs, "utf8");
2532
+ prior = await fs8.readFile(abs, "utf8");
2441
2533
  existed = true;
2442
2534
  } catch (err) {
2443
2535
  if (err?.code !== "ENOENT") throw err;
2444
2536
  }
2445
2537
  if (!existed) {
2446
2538
  if (opts.dryRun) return "created";
2447
- await fs7.mkdir(path9.dirname(abs), { recursive: true });
2448
- await fs7.writeFile(abs, fullContent, "utf8");
2539
+ await fs8.mkdir(path10.dirname(abs), { recursive: true });
2540
+ await fs8.writeFile(abs, fullContent, "utf8");
2449
2541
  return "created";
2450
2542
  }
2451
2543
  if (prior.includes(MANAGED_MARKER)) {
2452
2544
  if (prior === fullContent) return "skipped";
2453
2545
  if (opts.dryRun) return "updated";
2454
- await fs7.mkdir(path9.dirname(abs), { recursive: true });
2455
- await fs7.writeFile(abs, fullContent, "utf8");
2546
+ await fs8.mkdir(path10.dirname(abs), { recursive: true });
2547
+ await fs8.writeFile(abs, fullContent, "utf8");
2456
2548
  return "updated";
2457
2549
  }
2458
2550
  if (!opts.force) return "skipped-untracked";
2459
2551
  if (opts.dryRun) return "updated";
2460
- await fs7.mkdir(path9.dirname(abs), { recursive: true });
2461
- await fs7.writeFile(abs, fullContent, "utf8");
2552
+ await fs8.mkdir(path10.dirname(abs), { recursive: true });
2553
+ await fs8.writeFile(abs, fullContent, "utf8");
2462
2554
  return "updated";
2463
2555
  }
2464
2556
  async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
2465
- const abs = path9.join(repoRoot, relPath);
2557
+ const abs = path10.join(repoRoot, relPath);
2466
2558
  assertUnderRepoRoot(repoRoot, abs);
2467
2559
  let raw = "";
2468
2560
  let existed = false;
2469
2561
  try {
2470
- raw = await fs7.readFile(abs, "utf8");
2562
+ raw = await fs8.readFile(abs, "utf8");
2471
2563
  existed = true;
2472
2564
  } catch (err) {
2473
2565
  if (err?.code !== "ENOENT") throw err;
@@ -2475,8 +2567,8 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
2475
2567
  if (!existed) {
2476
2568
  const body = buildBody(null);
2477
2569
  if (opts.dryRun) return "created";
2478
- await fs7.mkdir(path9.dirname(abs), { recursive: true });
2479
- await fs7.writeFile(abs, body, "utf8");
2570
+ await fs8.mkdir(path10.dirname(abs), { recursive: true });
2571
+ await fs8.writeFile(abs, body, "utf8");
2480
2572
  return "created";
2481
2573
  }
2482
2574
  const managed = raw.includes(MANAGED_MARKER);
@@ -2491,8 +2583,8 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
2491
2583
  const next = buildBody(parsed);
2492
2584
  if (managed && next === raw) return "skipped";
2493
2585
  if (opts.dryRun) return "updated";
2494
- await fs7.mkdir(path9.dirname(abs), { recursive: true });
2495
- await fs7.writeFile(abs, next, "utf8");
2586
+ await fs8.mkdir(path10.dirname(abs), { recursive: true });
2587
+ await fs8.writeFile(abs, next, "utf8");
2496
2588
  return "updated";
2497
2589
  }
2498
2590
  function parseSetupIdeFlags(argv) {
@@ -2506,6 +2598,8 @@ function parseSetupIdeFlags(argv) {
2506
2598
  let cleanup = false;
2507
2599
  let devMode = false;
2508
2600
  let repair = false;
2601
+ let local = false;
2602
+ let staging = false;
2509
2603
  const unknown = [];
2510
2604
  for (const a of argv) {
2511
2605
  if (a === "--cursor") cursor = true;
@@ -2518,6 +2612,8 @@ function parseSetupIdeFlags(argv) {
2518
2612
  else if (a === "--cleanup") cleanup = true;
2519
2613
  else if (a === "--dev") devMode = true;
2520
2614
  else if (a === "--repair") repair = true;
2615
+ else if (a === "--local") local = true;
2616
+ else if (a === "--staging") staging = true;
2521
2617
  else if (a.startsWith("-")) unknown.push(a);
2522
2618
  }
2523
2619
  const specific = cursor || vscode || jetbrains;
@@ -2527,7 +2623,16 @@ function parseSetupIdeFlags(argv) {
2527
2623
  } else {
2528
2624
  targets = { cursor, vscode, jetbrains };
2529
2625
  }
2530
- return { targets, force, dryRun, noGitignore, cleanup, devMode, repair, unknown };
2626
+ let flagError;
2627
+ if (local && staging) {
2628
+ flagError = "[setup-ide-files] --local and --staging are mutually exclusive.";
2629
+ }
2630
+ return { targets, force, dryRun, noGitignore, cleanup, devMode, repair, local, staging, all, unknown, flagError };
2631
+ }
2632
+ function cursorEnvironmentFromFlags(local, staging) {
2633
+ if (local) return "local";
2634
+ if (staging) return "staging";
2635
+ return "production";
2531
2636
  }
2532
2637
  function summarizeOutcomes(outcomes) {
2533
2638
  const created = [];
@@ -2728,20 +2833,44 @@ description: MemoraOne MCP \u2014 IDE agent instructions
2728
2833
 
2729
2834
  ` + cursorRuleBody();
2730
2835
  if (o.targets.cursor) {
2731
- let npxPath;
2732
- if (o.npxPathOverride !== void 0) {
2733
- npxPath = o.npxPathOverride;
2836
+ const cursorEnvironment = o.cursorEnvironment ?? "production";
2837
+ let npxPath = null;
2838
+ let cliPath;
2839
+ if (cursorEnvironment === "local") {
2840
+ let resolvedCliPath = o.cursorLocalCliPathOverride;
2841
+ if (resolvedCliPath === void 0) {
2842
+ resolvedCliPath = await resolveBuiltCliPathAsync({ searchFrom: [repoRoot, o.cwd] });
2843
+ }
2844
+ if (!resolvedCliPath) {
2845
+ return {
2846
+ exitCode: 1,
2847
+ repoRoot,
2848
+ outcomes,
2849
+ error: "[setup-ide-files] Local mode requires a built CLI at packages/mcp/dist/cli.cjs. Run pnpm build first."
2850
+ };
2851
+ }
2852
+ cliPath = resolvedCliPath;
2734
2853
  } else {
2735
- npxPath = await resolveNpxPath();
2736
- }
2737
- if (!npxPath) {
2738
- return {
2739
- exitCode: 1,
2740
- repoRoot,
2741
- outcomes,
2742
- error: "[setup-ide-files] Could not resolve a working npx executable. Install Node.js/npm or ensure npx is on PATH before configuring Cursor MCP."
2743
- };
2854
+ if (o.npxPathOverride !== void 0) {
2855
+ npxPath = o.npxPathOverride;
2856
+ } else {
2857
+ npxPath = await resolveNpxPath();
2858
+ }
2859
+ if (!npxPath) {
2860
+ return {
2861
+ exitCode: 1,
2862
+ repoRoot,
2863
+ outcomes,
2864
+ error: "[setup-ide-files] Could not resolve a working npx executable. Install Node.js/npm or ensure npx is on PATH before configuring Cursor MCP."
2865
+ };
2866
+ }
2744
2867
  }
2868
+ const cursorWriteOptions = {
2869
+ environment: cursorEnvironment,
2870
+ npxPath: npxPath ?? void 0,
2871
+ cliPath,
2872
+ repoRoot
2873
+ };
2745
2874
  outcomes[".cursor/rules/memoraone-mcp.mdc"] = await writeManagedMarkdown(
2746
2875
  repoRoot,
2747
2876
  ".cursor/rules/memoraone-mcp.mdc",
@@ -2751,7 +2880,7 @@ description: MemoraOne MCP \u2014 IDE agent instructions
2751
2880
  outcomes[".cursor/mcp.json"] = await writeIdeMcpJson(
2752
2881
  repoRoot,
2753
2882
  ".cursor/mcp.json",
2754
- (existing) => buildCursorMcpJsonBody(existing, npxPath, repoRoot),
2883
+ (existing) => buildCursorMcpJsonBody(existing, cursorWriteOptions),
2755
2884
  { force: o.force, dryRun: o.dryRun }
2756
2885
  );
2757
2886
  const repoConfigPath = getCursorRepoMcpConfigPath(repoRoot);
@@ -2795,7 +2924,7 @@ description: MemoraOne MCP \u2014 IDE agent instructions
2795
2924
  cursorMcp = {
2796
2925
  repoConfigPath,
2797
2926
  repoOutcome,
2798
- npxPath,
2927
+ ...cursorEnvironment === "local" ? { cliPath } : { npxPath },
2799
2928
  globalConfigPath,
2800
2929
  globalMemoraoneRemoved,
2801
2930
  globalBackupPath
@@ -2863,7 +2992,11 @@ description: MemoraOne MCP \u2014 IDE agent instructions
2863
2992
  return { exitCode: 0, repoRoot, outcomes, cursorMcp, jetbrainsMcp, daemonCleanup };
2864
2993
  }
2865
2994
  async function cliSetupIdeFiles(argv) {
2866
- const { targets, force, dryRun, noGitignore, cleanup, devMode, repair, unknown } = parseSetupIdeFlags(argv);
2995
+ const { targets, force, dryRun, noGitignore, cleanup, devMode, repair, local, staging, unknown, flagError } = parseSetupIdeFlags(argv);
2996
+ if (flagError) {
2997
+ console.error(flagError);
2998
+ return 1;
2999
+ }
2867
3000
  if (unknown.length) {
2868
3001
  console.error(`[setup-ide-files] Unknown option(s): ${unknown.join(", ")}`);
2869
3002
  return 1;
@@ -2875,7 +3008,8 @@ async function cliSetupIdeFiles(argv) {
2875
3008
  dryRun,
2876
3009
  noGitignore,
2877
3010
  devMode,
2878
- repair
3011
+ repair,
3012
+ cursorEnvironment: cursorEnvironmentFromFlags(local, staging)
2879
3013
  });
2880
3014
  if (result.error) {
2881
3015
  console.error(result.error);
@@ -2930,7 +3064,7 @@ if (args.includes("--version") || args.includes("-v")) {
2930
3064
  }
2931
3065
  if (args.includes("--help") || args.includes("-h")) {
2932
3066
  console.log(
2933
- "Usage: memoraone-mcp [--version] [--help] [--daemon --project-id <uuid> [--ide cursor|copilot-vscode|jetbrains]]\n memoraone-mcp setup-ide-files [--all|--cursor|--vscode|--jetbrains] [--force] [--dry-run] [--no-gitignore] [--cleanup] [--dev] [--repair]\n memoraone-mcp cleanup [--project-id <uuid>] [--ide cursor|copilot-vscode|jetbrains] [--dry-run] [--all-projects] [--yes]"
3067
+ "Usage: memoraone-mcp [--version] [--help] [--daemon --project-id <uuid> [--ide cursor|copilot-vscode|jetbrains]]\n memoraone-mcp setup-ide-files [--all|--cursor|--vscode|--jetbrains] [--force] [--dry-run] [--no-gitignore] [--cleanup] [--dev] [--repair]\n Cursor API environment (with --cursor or --all): --local (node + built cli.cjs + localhost) | --staging (npx + staging API)\n memoraone-mcp cleanup [--project-id <uuid>] [--ide cursor|copilot-vscode|jetbrains] [--dry-run] [--all-projects] [--yes]"
2934
3068
  );
2935
3069
  process.exit(0);
2936
3070
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoraone/mcp",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {