@memoraone/mcp 0.1.28 → 0.1.29

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 +307 -59
  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.28",
33
+ version: "0.1.29",
34
34
  type: "module",
35
35
  main: "dist/index.cjs",
36
36
  bin: {
@@ -67,9 +67,9 @@ var require_package = __commonJS({
67
67
  });
68
68
 
69
69
  // src/cli.ts
70
- var path5 = __toESM(require("path"), 1);
70
+ var path6 = __toESM(require("path"), 1);
71
71
  var net = __toESM(require("net"), 1);
72
- var import_node_child_process2 = require("child_process");
72
+ var import_node_child_process3 = require("child_process");
73
73
 
74
74
  // src/socketPaths.ts
75
75
  var os = __toESM(require("os"), 1);
@@ -292,8 +292,8 @@ function encodeResolvedBinding(binding) {
292
292
  }
293
293
 
294
294
  // src/setupIdeFiles.ts
295
- var fs4 = __toESM(require("fs/promises"), 1);
296
- var path4 = __toESM(require("path"), 1);
295
+ var fs5 = __toESM(require("fs/promises"), 1);
296
+ var path5 = __toESM(require("path"), 1);
297
297
 
298
298
  // src/cleanup.ts
299
299
  var fs3 = __toESM(require("fs/promises"), 1);
@@ -685,13 +685,219 @@ async function cliCleanup(argv) {
685
685
  return result.exitCode;
686
686
  }
687
687
 
688
+ // src/cursorGlobalMcpConfig.ts
689
+ var fs4 = __toESM(require("fs/promises"), 1);
690
+ var os2 = __toESM(require("os"), 1);
691
+ var path4 = __toESM(require("path"), 1);
692
+ var import_node_child_process2 = require("child_process");
693
+ var import_node_util2 = require("util");
694
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
695
+ function buildMemoraoneCursorMcpServer(npxPath) {
696
+ return {
697
+ command: npxPath,
698
+ args: ["-y", "@memoraone/mcp@latest"],
699
+ env: {
700
+ MEMORAONE_API_URL: "https://api.memoraone.com",
701
+ MEMORAONE_IDE_TYPE: "cursor"
702
+ }
703
+ };
704
+ }
705
+ async function pathExists(filePath) {
706
+ try {
707
+ await fs4.access(filePath);
708
+ return true;
709
+ } catch {
710
+ return false;
711
+ }
712
+ }
713
+ function stripLeadingLineComments(text) {
714
+ return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
715
+ }
716
+ function getKnownCursorGlobalMcpConfigCandidates(homeDir) {
717
+ return [path4.join(homeDir, ".cursor", "mcp.json")];
718
+ }
719
+ async function detectCursorGlobalMcpConfig(options) {
720
+ if (options?.explicitPath) {
721
+ return { ok: true, path: options.explicitPath, detectedExisting: await pathExists(options.explicitPath) };
722
+ }
723
+ const homeDir = options?.homeDir ?? os2.homedir();
724
+ const candidates = getKnownCursorGlobalMcpConfigCandidates(homeDir);
725
+ const existing = [];
726
+ for (const candidate of candidates) {
727
+ if (await pathExists(candidate)) existing.push(candidate);
728
+ }
729
+ if (existing.length > 1) {
730
+ return {
731
+ ok: false,
732
+ error: "[setup-ide-files] Multiple Cursor global MCP config paths found. Specify one explicitly.",
733
+ candidates: existing
734
+ };
735
+ }
736
+ if (existing.length === 1) {
737
+ return { ok: true, path: existing[0], detectedExisting: true };
738
+ }
739
+ const defaultPath = candidates[0];
740
+ if (!defaultPath) {
741
+ return {
742
+ ok: false,
743
+ error: "[setup-ide-files] No known Cursor global MCP config path.",
744
+ candidates: []
745
+ };
746
+ }
747
+ return { ok: true, path: defaultPath, detectedExisting: false };
748
+ }
749
+ function formatBackupTimestamp(d = /* @__PURE__ */ new Date()) {
750
+ const pad = (n) => String(n).padStart(2, "0");
751
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
752
+ }
753
+ async function isWorkingNpx(npxPath) {
754
+ try {
755
+ if (!await pathExists(npxPath)) return false;
756
+ if (process.platform !== "win32") {
757
+ try {
758
+ await fs4.access(npxPath, fs4.constants.X_OK);
759
+ } catch {
760
+ return false;
761
+ }
762
+ }
763
+ await execFileAsync2(npxPath, ["--version"], { timeout: 1e4 });
764
+ return true;
765
+ } catch {
766
+ return false;
767
+ }
768
+ }
769
+ async function resolveNpxPath() {
770
+ const npxName = process.platform === "win32" ? "npx.cmd" : "npx";
771
+ const candidates = [];
772
+ if (process.platform === "darwin") {
773
+ candidates.push("/opt/homebrew/bin/npx", "/usr/local/bin/npx");
774
+ } else if (process.platform === "linux") {
775
+ candidates.push("/usr/local/bin/npx");
776
+ }
777
+ const pathSep = process.platform === "win32" ? ";" : ":";
778
+ for (const dir of (process.env.PATH ?? "").split(pathSep)) {
779
+ if (!dir) continue;
780
+ candidates.push(path4.join(dir, npxName));
781
+ }
782
+ try {
783
+ const lookupCmd = process.platform === "win32" ? "where" : "which";
784
+ const { stdout } = await execFileAsync2(lookupCmd, [npxName], { timeout: 5e3 });
785
+ const first = stdout.trim().split(/\r?\n/).map((line) => line.trim()).find(Boolean);
786
+ if (first) candidates.unshift(first);
787
+ } catch {
788
+ }
789
+ const seen = /* @__PURE__ */ new Set();
790
+ for (const candidate of candidates) {
791
+ const abs = path4.isAbsolute(candidate) ? candidate : path4.resolve(candidate);
792
+ const key = process.platform === "win32" ? abs.toLowerCase() : abs;
793
+ if (seen.has(key)) continue;
794
+ seen.add(key);
795
+ if (await isWorkingNpx(abs)) return abs;
796
+ }
797
+ return null;
798
+ }
799
+ function mergeCursorGlobalMcpConfigObject(existing, npxPath) {
800
+ const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
801
+ const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
802
+ mcpServers.memoraone = buildMemoraoneCursorMcpServer(npxPath);
803
+ return { ...base, mcpServers };
804
+ }
805
+ function memoraoneServerMatches(server, npxPath) {
806
+ if (!server || typeof server !== "object") return false;
807
+ const s = server;
808
+ if (s.command !== npxPath) return false;
809
+ if (!Array.isArray(s.args) || s.args.length !== 2) return false;
810
+ if (s.args[0] !== "-y" || s.args[1] !== "@memoraone/mcp@latest") return false;
811
+ const env = s.env;
812
+ if (!env || typeof env !== "object") return false;
813
+ const e = env;
814
+ return e.MEMORAONE_API_URL === "https://api.memoraone.com" && e.MEMORAONE_IDE_TYPE === "cursor";
815
+ }
816
+ function validateCursorGlobalMcpConfig(parsed, npxPath) {
817
+ if (!parsed || typeof parsed !== "object") {
818
+ throw new Error("[setup-ide-files] Cursor global MCP config must be a JSON object.");
819
+ }
820
+ const mcpServers = parsed.mcpServers;
821
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
822
+ throw new Error("[setup-ide-files] Cursor global MCP config missing mcpServers object.");
823
+ }
824
+ const memoraone = mcpServers.memoraone;
825
+ if (!memoraoneServerMatches(memoraone, npxPath)) {
826
+ throw new Error(
827
+ "[setup-ide-files] Cursor global MCP config mcpServers.memoraone is missing or invalid."
828
+ );
829
+ }
830
+ }
831
+ async function setupCursorGlobalMcpConfig(options) {
832
+ const { configPath, npxPath, dryRun } = options;
833
+ const existed = await pathExists(configPath);
834
+ let existing = null;
835
+ if (existed) {
836
+ const raw = await fs4.readFile(configPath, "utf8");
837
+ try {
838
+ existing = JSON.parse(stripLeadingLineComments(raw));
839
+ } catch {
840
+ throw new Error(
841
+ `[setup-ide-files] Invalid JSON in Cursor global MCP config: ${configPath}`
842
+ );
843
+ }
844
+ }
845
+ const merged = mergeCursorGlobalMcpConfigObject(existing, npxPath);
846
+ const body = JSON.stringify(merged, null, 2) + "\n";
847
+ if (existed) {
848
+ const currentMemoraone = existing && typeof existing.mcpServers === "object" && existing.mcpServers !== null && !Array.isArray(existing.mcpServers) ? existing.mcpServers.memoraone : void 0;
849
+ if (memoraoneServerMatches(currentMemoraone, npxPath)) {
850
+ return { outcome: "skipped" };
851
+ }
852
+ }
853
+ if (dryRun) {
854
+ return { outcome: existed ? "updated" : "created" };
855
+ }
856
+ let backupPath;
857
+ if (existed) {
858
+ backupPath = `${configPath}.backup-${formatBackupTimestamp()}`;
859
+ await fs4.copyFile(configPath, backupPath);
860
+ }
861
+ await fs4.mkdir(path4.dirname(configPath), { recursive: true });
862
+ await fs4.writeFile(configPath, body, "utf8");
863
+ const verifyRaw = await fs4.readFile(configPath, "utf8");
864
+ const verifyParsed = JSON.parse(stripLeadingLineComments(verifyRaw));
865
+ validateCursorGlobalMcpConfig(verifyParsed, npxPath);
866
+ return { outcome: existed ? "updated" : "created", backupPath };
867
+ }
868
+ function logCursorGlobalMcpCliSummary(info, dryRun) {
869
+ const { configPath, npxPath, backupPath, outcome } = info;
870
+ console.log(`[setup-ide-files] Cursor global MCP config: ${configPath}`);
871
+ console.log(`[setup-ide-files] Resolved npx: ${npxPath}`);
872
+ if (backupPath) {
873
+ console.log(`[setup-ide-files] Cursor global MCP config backup: ${backupPath}`);
874
+ }
875
+ if (outcome === "created") {
876
+ console.log(
877
+ dryRun ? `[setup-ide-files] Cursor global MCP config would be created: ${configPath}` : `[setup-ide-files] Cursor global MCP config created: ${configPath}`
878
+ );
879
+ } else if (outcome === "updated") {
880
+ console.log(
881
+ dryRun ? `[setup-ide-files] Cursor global MCP config would be updated: ${configPath}` : `[setup-ide-files] Cursor global MCP config updated: ${configPath}`
882
+ );
883
+ } else if (outcome === "skipped") {
884
+ console.log(`[setup-ide-files] Cursor global MCP config unchanged: ${configPath}`);
885
+ }
886
+ console.log(
887
+ "[setup-ide-files] Repo-level .cursor/mcp.json was not created or modified."
888
+ );
889
+ console.log(
890
+ "[setup-ide-files] Fully quit Cursor and reopen this repo for MCP changes to take effect."
891
+ );
892
+ }
893
+
688
894
  // src/setupIdeFiles.ts
689
895
  var MANAGED_MARKER = "<!-- MemoraOne managed IDE helper -->";
690
896
  var GITIGNORE_MEMORAONE_COMMENT = "# MemoraOne local project binding / API key";
691
897
  var GITIGNORE_MEMORAONE_ENTRY = "memoraone.m1";
692
- function buildMemoraoneMcpServer(ideType) {
898
+ function buildMemoraoneMcpServer(ideType, command = "npx") {
693
899
  return {
694
- command: "npx",
900
+ command,
695
901
  args: ["-y", "@memoraone/mcp@latest"],
696
902
  env: {
697
903
  MEMORAONE_API_URL: "https://api.memoraone.com",
@@ -700,15 +906,15 @@ function buildMemoraoneMcpServer(ideType) {
700
906
  };
701
907
  }
702
908
  function assertUnderRepoRoot(repoRoot, absPath) {
703
- const normRoot = path4.resolve(repoRoot) + path4.sep;
704
- const normPath = path4.resolve(absPath);
705
- if (normPath !== path4.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
909
+ const normRoot = path5.resolve(repoRoot) + path5.sep;
910
+ const normPath = path5.resolve(absPath);
911
+ if (normPath !== path5.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
706
912
  throw new Error(`[setup-ide-files] Refusing to write outside repo root: ${absPath}`);
707
913
  }
708
914
  }
709
- async function pathExists(filePath) {
915
+ async function pathExists2(filePath) {
710
916
  try {
711
- await fs4.access(filePath);
917
+ await fs5.access(filePath);
712
918
  return true;
713
919
  } catch {
714
920
  return false;
@@ -729,12 +935,12 @@ ${GITIGNORE_MEMORAONE_ENTRY}
729
935
  }
730
936
  async function ensureGitignoreMemoraone(repoRoot, opts) {
731
937
  if (opts.noGitignore) return "skipped";
732
- const abs = path4.join(repoRoot, ".gitignore");
938
+ const abs = path5.join(repoRoot, ".gitignore");
733
939
  assertUnderRepoRoot(repoRoot, abs);
734
940
  let prior = "";
735
941
  let existed = false;
736
942
  try {
737
- prior = await fs4.readFile(abs, "utf8");
943
+ prior = await fs5.readFile(abs, "utf8");
738
944
  existed = true;
739
945
  } catch (err) {
740
946
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
@@ -745,25 +951,25 @@ async function ensureGitignoreMemoraone(repoRoot, opts) {
745
951
  const separator = existed && prior.length > 0 ? prior.endsWith("\n") ? "\n" : "\n\n" : "";
746
952
  const next = (existed ? prior : "") + separator + block;
747
953
  if (opts.dryRun) return existed ? "updated" : "created";
748
- await fs4.writeFile(abs, next, "utf8");
954
+ await fs5.writeFile(abs, next, "utf8");
749
955
  return existed ? "updated" : "created";
750
956
  }
751
957
  async function findRepoRoot(startDir) {
752
- let current = path4.resolve(startDir);
753
- const root = path4.parse(current).root;
958
+ let current = path5.resolve(startDir);
959
+ const root = path5.parse(current).root;
754
960
  while (true) {
755
- const gitPath = path4.join(current, ".git");
756
- const m1Path = path4.join(current, "memoraone.m1");
757
- if (await pathExists(gitPath) || await pathExists(m1Path)) {
961
+ const gitPath = path5.join(current, ".git");
962
+ const m1Path = path5.join(current, "memoraone.m1");
963
+ if (await pathExists2(gitPath) || await pathExists2(m1Path)) {
758
964
  return current;
759
965
  }
760
966
  if (current === root) {
761
967
  return null;
762
968
  }
763
- current = path4.dirname(current);
969
+ current = path5.dirname(current);
764
970
  }
765
971
  }
766
- function stripLeadingLineComments(text) {
972
+ function stripLeadingLineComments2(text) {
767
973
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
768
974
  }
769
975
  function cursorRuleBody() {
@@ -813,50 +1019,43 @@ function buildVscodeMcpJsonBody(existing) {
813
1019
  const merged = { ...base, servers };
814
1020
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
815
1021
  }
816
- function buildCursorMcpJsonBody(existing) {
817
- const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
818
- const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
819
- mcpServers.memoraone = buildMemoraoneMcpServer("cursor");
820
- const merged = { ...base, mcpServers };
821
- return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
822
- }
823
1022
  async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
824
- const abs = path4.join(repoRoot, relPath);
1023
+ const abs = path5.join(repoRoot, relPath);
825
1024
  assertUnderRepoRoot(repoRoot, abs);
826
1025
  let prior = "";
827
1026
  let existed = false;
828
1027
  try {
829
- prior = await fs4.readFile(abs, "utf8");
1028
+ prior = await fs5.readFile(abs, "utf8");
830
1029
  existed = true;
831
1030
  } catch (err) {
832
1031
  if (err?.code !== "ENOENT") throw err;
833
1032
  }
834
1033
  if (!existed) {
835
1034
  if (opts.dryRun) return "created";
836
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
837
- await fs4.writeFile(abs, fullContent, "utf8");
1035
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1036
+ await fs5.writeFile(abs, fullContent, "utf8");
838
1037
  return "created";
839
1038
  }
840
1039
  if (prior.includes(MANAGED_MARKER)) {
841
1040
  if (prior === fullContent) return "skipped";
842
1041
  if (opts.dryRun) return "updated";
843
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
844
- await fs4.writeFile(abs, fullContent, "utf8");
1042
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1043
+ await fs5.writeFile(abs, fullContent, "utf8");
845
1044
  return "updated";
846
1045
  }
847
1046
  if (!opts.force) return "skipped-untracked";
848
1047
  if (opts.dryRun) return "updated";
849
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
850
- await fs4.writeFile(abs, fullContent, "utf8");
1048
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1049
+ await fs5.writeFile(abs, fullContent, "utf8");
851
1050
  return "updated";
852
1051
  }
853
1052
  async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
854
- const abs = path4.join(repoRoot, relPath);
1053
+ const abs = path5.join(repoRoot, relPath);
855
1054
  assertUnderRepoRoot(repoRoot, abs);
856
1055
  let raw = "";
857
1056
  let existed = false;
858
1057
  try {
859
- raw = await fs4.readFile(abs, "utf8");
1058
+ raw = await fs5.readFile(abs, "utf8");
860
1059
  existed = true;
861
1060
  } catch (err) {
862
1061
  if (err?.code !== "ENOENT") throw err;
@@ -864,15 +1063,15 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
864
1063
  if (!existed) {
865
1064
  const body = buildBody(null);
866
1065
  if (opts.dryRun) return "created";
867
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
868
- await fs4.writeFile(abs, body, "utf8");
1066
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1067
+ await fs5.writeFile(abs, body, "utf8");
869
1068
  return "created";
870
1069
  }
871
1070
  const managed = raw.includes(MANAGED_MARKER);
872
1071
  if (!managed && !opts.force) return "skipped-untracked";
873
1072
  let parsed = null;
874
1073
  try {
875
- parsed = JSON.parse(stripLeadingLineComments(raw));
1074
+ parsed = JSON.parse(stripLeadingLineComments2(raw));
876
1075
  } catch {
877
1076
  parsed = null;
878
1077
  }
@@ -880,8 +1079,8 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
880
1079
  const next = buildBody(parsed);
881
1080
  if (managed && next === raw) return "skipped";
882
1081
  if (opts.dryRun) return "updated";
883
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
884
- await fs4.writeFile(abs, next, "utf8");
1082
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1083
+ await fs5.writeFile(abs, next, "utf8");
885
1084
  return "updated";
886
1085
  }
887
1086
  function parseSetupIdeFlags(argv) {
@@ -936,6 +1135,7 @@ function summarizeOutcomes(outcomes) {
936
1135
  }
937
1136
  async function runSetupIdeFiles(o) {
938
1137
  const outcomes = {};
1138
+ let cursorGlobalMcp;
939
1139
  const repoRoot = await findRepoRoot(o.cwd);
940
1140
  if (!repoRoot) {
941
1141
  return {
@@ -955,21 +1155,62 @@ description: MemoraOne MCP \u2014 IDE agent instructions
955
1155
 
956
1156
  ` + cursorRuleBody();
957
1157
  if (o.targets.cursor) {
958
- outcomes[".cursor/mcp.json"] = await writeIdeMcpJson(
959
- repoRoot,
960
- ".cursor/mcp.json",
961
- buildCursorMcpJsonBody,
962
- {
963
- force: o.force,
964
- dryRun: o.dryRun
965
- }
966
- );
1158
+ const detection = await detectCursorGlobalMcpConfig({
1159
+ homeDir: o.homeDir,
1160
+ explicitPath: o.cursorGlobalMcpConfigPath
1161
+ });
1162
+ if (!detection.ok) {
1163
+ return {
1164
+ exitCode: 1,
1165
+ repoRoot,
1166
+ outcomes,
1167
+ error: `${detection.error}
1168
+ ${detection.candidates.join("\n ")}`
1169
+ };
1170
+ }
1171
+ let npxPath;
1172
+ if (o.npxPathOverride !== void 0) {
1173
+ npxPath = o.npxPathOverride;
1174
+ } else {
1175
+ npxPath = await resolveNpxPath();
1176
+ }
1177
+ if (!npxPath) {
1178
+ return {
1179
+ exitCode: 1,
1180
+ repoRoot,
1181
+ outcomes,
1182
+ error: "[setup-ide-files] Could not resolve a working npx executable. Install Node.js/npm or ensure npx is on PATH before configuring Cursor global MCP."
1183
+ };
1184
+ }
967
1185
  outcomes[".cursor/rules/memoraone-mcp.mdc"] = await writeManagedMarkdown(
968
1186
  repoRoot,
969
1187
  ".cursor/rules/memoraone-mcp.mdc",
970
1188
  cursorContent,
971
1189
  { force: o.force, dryRun: o.dryRun }
972
1190
  );
1191
+ try {
1192
+ const globalSetup = await setupCursorGlobalMcpConfig({
1193
+ configPath: detection.path,
1194
+ npxPath,
1195
+ dryRun: o.dryRun
1196
+ });
1197
+ cursorGlobalMcp = {
1198
+ configPath: detection.path,
1199
+ outcome: globalSetup.outcome,
1200
+ npxPath,
1201
+ backupPath: globalSetup.backupPath
1202
+ };
1203
+ outcomes[`cursor-global:${detection.path}`] = globalSetup.outcome;
1204
+ } catch (err) {
1205
+ const message = err instanceof Error ? err.message : String(err);
1206
+ return {
1207
+ exitCode: 1,
1208
+ repoRoot,
1209
+ outcomes,
1210
+ cursorGlobalMcp: { configPath: detection.path, outcome: "skipped", npxPath },
1211
+ error: message
1212
+ };
1213
+ }
973
1214
  }
974
1215
  if (o.targets.vscode) {
975
1216
  outcomes[".vscode/mcp.json"] = await writeIdeMcpJson(
@@ -996,7 +1237,7 @@ description: MemoraOne MCP \u2014 IDE agent instructions
996
1237
  { force: o.force, dryRun: o.dryRun }
997
1238
  );
998
1239
  }
999
- return { exitCode: 0, repoRoot, outcomes };
1240
+ return { exitCode: 0, repoRoot, outcomes, cursorGlobalMcp };
1000
1241
  }
1001
1242
  async function cliSetupIdeFiles(argv) {
1002
1243
  const { targets, force, dryRun, noGitignore, cleanup, unknown } = parseSetupIdeFlags(argv);
@@ -1013,11 +1254,18 @@ async function cliSetupIdeFiles(argv) {
1013
1254
  });
1014
1255
  if (result.error) {
1015
1256
  console.error(result.error);
1257
+ if (result.repoRoot) {
1258
+ console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
1259
+ }
1260
+ summarizeOutcomes(result.outcomes);
1016
1261
  return result.exitCode;
1017
1262
  }
1018
1263
  if (result.repoRoot) {
1019
1264
  console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
1020
1265
  }
1266
+ if (targets.cursor && result.cursorGlobalMcp) {
1267
+ logCursorGlobalMcpCliSummary(result.cursorGlobalMcp, dryRun);
1268
+ }
1021
1269
  summarizeOutcomes(result.outcomes);
1022
1270
  if (dryRun) {
1023
1271
  console.log("[setup-ide-files] Dry run: no files written.");
@@ -1081,8 +1329,8 @@ if (args[0] === "cleanup") {
1081
1329
  const raw = process.env.WORKSPACE_FOLDER_PATHS;
1082
1330
  const parts = [];
1083
1331
  if (raw !== void 0 && raw.trim() !== "") {
1084
- for (const p of raw.split(path5.delimiter).map((s) => s.trim()).filter(Boolean)) {
1085
- parts.push(path5.resolve(p));
1332
+ for (const p of raw.split(path6.delimiter).map((s) => s.trim()).filter(Boolean)) {
1333
+ parts.push(path6.resolve(p));
1086
1334
  }
1087
1335
  }
1088
1336
  parts.push(process.cwd());
@@ -1096,10 +1344,10 @@ if (args[0] === "cleanup") {
1096
1344
  }
1097
1345
  return deduped;
1098
1346
  }, connectWithRetry = function(socketPath) {
1099
- return new Promise((resolve5, reject) => {
1347
+ return new Promise((resolve6, reject) => {
1100
1348
  const tryConnect = (attempt) => {
1101
1349
  const socket = net.connect(socketPath, () => {
1102
- resolve5(socket);
1350
+ resolve6(socket);
1103
1351
  });
1104
1352
  socket.on("error", (err) => {
1105
1353
  if (attempt >= MAX_RETRIES) {
@@ -1135,7 +1383,7 @@ if (args[0] === "cleanup") {
1135
1383
  socket = await connectWithRetry(socketPath);
1136
1384
  } catch {
1137
1385
  log("daemon not running, spawning...");
1138
- const child = (0, import_node_child_process2.spawn)(
1386
+ const child = (0, import_node_child_process3.spawn)(
1139
1387
  process.execPath,
1140
1388
  buildDaemonSpawnArgs(process.argv[1], binding.projectId),
1141
1389
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoraone/mcp",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {