@memoraone/mcp 0.1.27 → 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 +329 -57
  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.27",
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,27 +685,236 @@ 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
- var MEMORAONE_MCP_SERVER = {
693
- command: "npx",
694
- args: ["-y", "@memoraone/mcp@latest"],
695
- env: {
696
- MEMORAONE_API_URL: "https://api.memoraone.com"
697
- }
698
- };
898
+ function buildMemoraoneMcpServer(ideType, command = "npx") {
899
+ return {
900
+ command,
901
+ args: ["-y", "@memoraone/mcp@latest"],
902
+ env: {
903
+ MEMORAONE_API_URL: "https://api.memoraone.com",
904
+ MEMORAONE_IDE_TYPE: ideType
905
+ }
906
+ };
907
+ }
699
908
  function assertUnderRepoRoot(repoRoot, absPath) {
700
- const normRoot = path4.resolve(repoRoot) + path4.sep;
701
- const normPath = path4.resolve(absPath);
702
- 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)) {
703
912
  throw new Error(`[setup-ide-files] Refusing to write outside repo root: ${absPath}`);
704
913
  }
705
914
  }
706
- async function pathExists(filePath) {
915
+ async function pathExists2(filePath) {
707
916
  try {
708
- await fs4.access(filePath);
917
+ await fs5.access(filePath);
709
918
  return true;
710
919
  } catch {
711
920
  return false;
@@ -726,12 +935,12 @@ ${GITIGNORE_MEMORAONE_ENTRY}
726
935
  }
727
936
  async function ensureGitignoreMemoraone(repoRoot, opts) {
728
937
  if (opts.noGitignore) return "skipped";
729
- const abs = path4.join(repoRoot, ".gitignore");
938
+ const abs = path5.join(repoRoot, ".gitignore");
730
939
  assertUnderRepoRoot(repoRoot, abs);
731
940
  let prior = "";
732
941
  let existed = false;
733
942
  try {
734
- prior = await fs4.readFile(abs, "utf8");
943
+ prior = await fs5.readFile(abs, "utf8");
735
944
  existed = true;
736
945
  } catch (err) {
737
946
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
@@ -742,25 +951,25 @@ async function ensureGitignoreMemoraone(repoRoot, opts) {
742
951
  const separator = existed && prior.length > 0 ? prior.endsWith("\n") ? "\n" : "\n\n" : "";
743
952
  const next = (existed ? prior : "") + separator + block;
744
953
  if (opts.dryRun) return existed ? "updated" : "created";
745
- await fs4.writeFile(abs, next, "utf8");
954
+ await fs5.writeFile(abs, next, "utf8");
746
955
  return existed ? "updated" : "created";
747
956
  }
748
957
  async function findRepoRoot(startDir) {
749
- let current = path4.resolve(startDir);
750
- const root = path4.parse(current).root;
958
+ let current = path5.resolve(startDir);
959
+ const root = path5.parse(current).root;
751
960
  while (true) {
752
- const gitPath = path4.join(current, ".git");
753
- const m1Path = path4.join(current, "memoraone.m1");
754
- 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)) {
755
964
  return current;
756
965
  }
757
966
  if (current === root) {
758
967
  return null;
759
968
  }
760
- current = path4.dirname(current);
969
+ current = path5.dirname(current);
761
970
  }
762
971
  }
763
- function stripLeadingLineComments(text) {
972
+ function stripLeadingLineComments2(text) {
764
973
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
765
974
  }
766
975
  function cursorRuleBody() {
@@ -803,75 +1012,75 @@ function mcpJsonHeader() {
803
1012
  return `// ${MANAGED_MARKER}
804
1013
  `;
805
1014
  }
806
- function buildMcpJsonBody(existing) {
1015
+ function buildVscodeMcpJsonBody(existing) {
807
1016
  const base = existing && typeof existing === "object" ? { ...existing } : { servers: {} };
808
1017
  const servers = typeof base.servers === "object" && base.servers !== null && !Array.isArray(base.servers) ? { ...base.servers } : {};
809
- servers.memoraone = { ...MEMORAONE_MCP_SERVER };
1018
+ servers.memoraone = buildMemoraoneMcpServer("copilot-vscode");
810
1019
  const merged = { ...base, servers };
811
1020
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
812
1021
  }
813
1022
  async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
814
- const abs = path4.join(repoRoot, relPath);
1023
+ const abs = path5.join(repoRoot, relPath);
815
1024
  assertUnderRepoRoot(repoRoot, abs);
816
1025
  let prior = "";
817
1026
  let existed = false;
818
1027
  try {
819
- prior = await fs4.readFile(abs, "utf8");
1028
+ prior = await fs5.readFile(abs, "utf8");
820
1029
  existed = true;
821
1030
  } catch (err) {
822
1031
  if (err?.code !== "ENOENT") throw err;
823
1032
  }
824
1033
  if (!existed) {
825
1034
  if (opts.dryRun) return "created";
826
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
827
- await fs4.writeFile(abs, fullContent, "utf8");
1035
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1036
+ await fs5.writeFile(abs, fullContent, "utf8");
828
1037
  return "created";
829
1038
  }
830
1039
  if (prior.includes(MANAGED_MARKER)) {
831
1040
  if (prior === fullContent) return "skipped";
832
1041
  if (opts.dryRun) return "updated";
833
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
834
- await fs4.writeFile(abs, fullContent, "utf8");
1042
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1043
+ await fs5.writeFile(abs, fullContent, "utf8");
835
1044
  return "updated";
836
1045
  }
837
1046
  if (!opts.force) return "skipped-untracked";
838
1047
  if (opts.dryRun) return "updated";
839
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
840
- await fs4.writeFile(abs, fullContent, "utf8");
1048
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1049
+ await fs5.writeFile(abs, fullContent, "utf8");
841
1050
  return "updated";
842
1051
  }
843
- async function writeMcpJson(repoRoot, opts) {
844
- const abs = path4.join(repoRoot, ".vscode/mcp.json");
1052
+ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
1053
+ const abs = path5.join(repoRoot, relPath);
845
1054
  assertUnderRepoRoot(repoRoot, abs);
846
1055
  let raw = "";
847
1056
  let existed = false;
848
1057
  try {
849
- raw = await fs4.readFile(abs, "utf8");
1058
+ raw = await fs5.readFile(abs, "utf8");
850
1059
  existed = true;
851
1060
  } catch (err) {
852
1061
  if (err?.code !== "ENOENT") throw err;
853
1062
  }
854
1063
  if (!existed) {
855
- const body = buildMcpJsonBody(null);
1064
+ const body = buildBody(null);
856
1065
  if (opts.dryRun) return "created";
857
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
858
- await fs4.writeFile(abs, body, "utf8");
1066
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1067
+ await fs5.writeFile(abs, body, "utf8");
859
1068
  return "created";
860
1069
  }
861
1070
  const managed = raw.includes(MANAGED_MARKER);
862
1071
  if (!managed && !opts.force) return "skipped-untracked";
863
1072
  let parsed = null;
864
1073
  try {
865
- parsed = JSON.parse(stripLeadingLineComments(raw));
1074
+ parsed = JSON.parse(stripLeadingLineComments2(raw));
866
1075
  } catch {
867
1076
  parsed = null;
868
1077
  }
869
1078
  if (!parsed && !opts.force) return "skipped-untracked";
870
- const next = buildMcpJsonBody(parsed);
1079
+ const next = buildBody(parsed);
871
1080
  if (managed && next === raw) return "skipped";
872
1081
  if (opts.dryRun) return "updated";
873
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
874
- await fs4.writeFile(abs, next, "utf8");
1082
+ await fs5.mkdir(path5.dirname(abs), { recursive: true });
1083
+ await fs5.writeFile(abs, next, "utf8");
875
1084
  return "updated";
876
1085
  }
877
1086
  function parseSetupIdeFlags(argv) {
@@ -926,6 +1135,7 @@ function summarizeOutcomes(outcomes) {
926
1135
  }
927
1136
  async function runSetupIdeFiles(o) {
928
1137
  const outcomes = {};
1138
+ let cursorGlobalMcp;
929
1139
  const repoRoot = await findRepoRoot(o.cwd);
930
1140
  if (!repoRoot) {
931
1141
  return {
@@ -945,18 +1155,73 @@ description: MemoraOne MCP \u2014 IDE agent instructions
945
1155
 
946
1156
  ` + cursorRuleBody();
947
1157
  if (o.targets.cursor) {
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
+ }
948
1185
  outcomes[".cursor/rules/memoraone-mcp.mdc"] = await writeManagedMarkdown(
949
1186
  repoRoot,
950
1187
  ".cursor/rules/memoraone-mcp.mdc",
951
1188
  cursorContent,
952
1189
  { force: o.force, dryRun: o.dryRun }
953
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
+ }
954
1214
  }
955
1215
  if (o.targets.vscode) {
956
- outcomes[".vscode/mcp.json"] = await writeMcpJson(repoRoot, {
957
- force: o.force,
958
- dryRun: o.dryRun
959
- });
1216
+ outcomes[".vscode/mcp.json"] = await writeIdeMcpJson(
1217
+ repoRoot,
1218
+ ".vscode/mcp.json",
1219
+ buildVscodeMcpJsonBody,
1220
+ {
1221
+ force: o.force,
1222
+ dryRun: o.dryRun
1223
+ }
1224
+ );
960
1225
  outcomes[".github/copilot-instructions.md"] = await writeManagedMarkdown(
961
1226
  repoRoot,
962
1227
  ".github/copilot-instructions.md",
@@ -972,7 +1237,7 @@ description: MemoraOne MCP \u2014 IDE agent instructions
972
1237
  { force: o.force, dryRun: o.dryRun }
973
1238
  );
974
1239
  }
975
- return { exitCode: 0, repoRoot, outcomes };
1240
+ return { exitCode: 0, repoRoot, outcomes, cursorGlobalMcp };
976
1241
  }
977
1242
  async function cliSetupIdeFiles(argv) {
978
1243
  const { targets, force, dryRun, noGitignore, cleanup, unknown } = parseSetupIdeFlags(argv);
@@ -989,11 +1254,18 @@ async function cliSetupIdeFiles(argv) {
989
1254
  });
990
1255
  if (result.error) {
991
1256
  console.error(result.error);
1257
+ if (result.repoRoot) {
1258
+ console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
1259
+ }
1260
+ summarizeOutcomes(result.outcomes);
992
1261
  return result.exitCode;
993
1262
  }
994
1263
  if (result.repoRoot) {
995
1264
  console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
996
1265
  }
1266
+ if (targets.cursor && result.cursorGlobalMcp) {
1267
+ logCursorGlobalMcpCliSummary(result.cursorGlobalMcp, dryRun);
1268
+ }
997
1269
  summarizeOutcomes(result.outcomes);
998
1270
  if (dryRun) {
999
1271
  console.log("[setup-ide-files] Dry run: no files written.");
@@ -1057,8 +1329,8 @@ if (args[0] === "cleanup") {
1057
1329
  const raw = process.env.WORKSPACE_FOLDER_PATHS;
1058
1330
  const parts = [];
1059
1331
  if (raw !== void 0 && raw.trim() !== "") {
1060
- for (const p of raw.split(path5.delimiter).map((s) => s.trim()).filter(Boolean)) {
1061
- 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));
1062
1334
  }
1063
1335
  }
1064
1336
  parts.push(process.cwd());
@@ -1072,10 +1344,10 @@ if (args[0] === "cleanup") {
1072
1344
  }
1073
1345
  return deduped;
1074
1346
  }, connectWithRetry = function(socketPath) {
1075
- return new Promise((resolve5, reject) => {
1347
+ return new Promise((resolve6, reject) => {
1076
1348
  const tryConnect = (attempt) => {
1077
1349
  const socket = net.connect(socketPath, () => {
1078
- resolve5(socket);
1350
+ resolve6(socket);
1079
1351
  });
1080
1352
  socket.on("error", (err) => {
1081
1353
  if (attempt >= MAX_RETRIES) {
@@ -1111,7 +1383,7 @@ if (args[0] === "cleanup") {
1111
1383
  socket = await connectWithRetry(socketPath);
1112
1384
  } catch {
1113
1385
  log("daemon not running, spawning...");
1114
- const child = (0, import_node_child_process2.spawn)(
1386
+ const child = (0, import_node_child_process3.spawn)(
1115
1387
  process.execPath,
1116
1388
  buildDaemonSpawnArgs(process.argv[1], binding.projectId),
1117
1389
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoraone/mcp",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {