@memoraone/mcp 0.1.28 → 0.1.30

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 +785 -63
  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.30",
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 path7 = __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_process4 = require("child_process");
73
73
 
74
74
  // src/socketPaths.ts
75
75
  var os = __toESM(require("os"), 1);
@@ -292,8 +292,9 @@ 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 fs6 = __toESM(require("fs/promises"), 1);
296
+ var os4 = __toESM(require("os"), 1);
297
+ var path6 = __toESM(require("path"), 1);
297
298
 
298
299
  // src/cleanup.ts
299
300
  var fs3 = __toESM(require("fs/promises"), 1);
@@ -685,13 +686,648 @@ async function cliCleanup(argv) {
685
686
  return result.exitCode;
686
687
  }
687
688
 
689
+ // src/cursorGlobalMcpConfig.ts
690
+ var fs4 = __toESM(require("fs/promises"), 1);
691
+ var os2 = __toESM(require("os"), 1);
692
+ var path4 = __toESM(require("path"), 1);
693
+ var import_node_child_process2 = require("child_process");
694
+ var import_node_util2 = require("util");
695
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
696
+ function buildMemoraoneCursorMcpServer(npxPath) {
697
+ return {
698
+ command: npxPath,
699
+ args: ["-y", "@memoraone/mcp@latest"],
700
+ env: {
701
+ MEMORAONE_API_URL: "https://api.memoraone.com",
702
+ MEMORAONE_IDE_TYPE: "cursor"
703
+ }
704
+ };
705
+ }
706
+ async function pathExists(filePath) {
707
+ try {
708
+ await fs4.access(filePath);
709
+ return true;
710
+ } catch {
711
+ return false;
712
+ }
713
+ }
714
+ function stripLeadingLineComments(text) {
715
+ return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
716
+ }
717
+ function getKnownCursorGlobalMcpConfigCandidates(homeDir) {
718
+ return [path4.join(homeDir, ".cursor", "mcp.json")];
719
+ }
720
+ async function detectCursorGlobalMcpConfig(options) {
721
+ if (options?.explicitPath) {
722
+ return { ok: true, path: options.explicitPath, detectedExisting: await pathExists(options.explicitPath) };
723
+ }
724
+ const homeDir = options?.homeDir ?? os2.homedir();
725
+ const candidates = getKnownCursorGlobalMcpConfigCandidates(homeDir);
726
+ const existing = [];
727
+ for (const candidate of candidates) {
728
+ if (await pathExists(candidate)) existing.push(candidate);
729
+ }
730
+ if (existing.length > 1) {
731
+ return {
732
+ ok: false,
733
+ error: "[setup-ide-files] Multiple Cursor global MCP config paths found. Specify one explicitly.",
734
+ candidates: existing
735
+ };
736
+ }
737
+ if (existing.length === 1) {
738
+ return { ok: true, path: existing[0], detectedExisting: true };
739
+ }
740
+ const defaultPath = candidates[0];
741
+ if (!defaultPath) {
742
+ return {
743
+ ok: false,
744
+ error: "[setup-ide-files] No known Cursor global MCP config path.",
745
+ candidates: []
746
+ };
747
+ }
748
+ return { ok: true, path: defaultPath, detectedExisting: false };
749
+ }
750
+ function formatBackupTimestamp(d = /* @__PURE__ */ new Date()) {
751
+ const pad = (n) => String(n).padStart(2, "0");
752
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
753
+ }
754
+ async function isWorkingNpx(npxPath) {
755
+ try {
756
+ if (!await pathExists(npxPath)) return false;
757
+ if (process.platform !== "win32") {
758
+ try {
759
+ await fs4.access(npxPath, fs4.constants.X_OK);
760
+ } catch {
761
+ return false;
762
+ }
763
+ }
764
+ await execFileAsync2(npxPath, ["--version"], { timeout: 1e4 });
765
+ return true;
766
+ } catch {
767
+ return false;
768
+ }
769
+ }
770
+ async function resolveNpxPath() {
771
+ const npxName = process.platform === "win32" ? "npx.cmd" : "npx";
772
+ const candidates = [];
773
+ if (process.platform === "darwin") {
774
+ candidates.push("/opt/homebrew/bin/npx", "/usr/local/bin/npx");
775
+ } else if (process.platform === "linux") {
776
+ candidates.push("/usr/local/bin/npx");
777
+ }
778
+ const pathSep = process.platform === "win32" ? ";" : ":";
779
+ for (const dir of (process.env.PATH ?? "").split(pathSep)) {
780
+ if (!dir) continue;
781
+ candidates.push(path4.join(dir, npxName));
782
+ }
783
+ try {
784
+ const lookupCmd = process.platform === "win32" ? "where" : "which";
785
+ const { stdout } = await execFileAsync2(lookupCmd, [npxName], { timeout: 5e3 });
786
+ const first = stdout.trim().split(/\r?\n/).map((line) => line.trim()).find(Boolean);
787
+ if (first) candidates.unshift(first);
788
+ } catch {
789
+ }
790
+ const seen = /* @__PURE__ */ new Set();
791
+ for (const candidate of candidates) {
792
+ const abs = path4.isAbsolute(candidate) ? candidate : path4.resolve(candidate);
793
+ const key = process.platform === "win32" ? abs.toLowerCase() : abs;
794
+ if (seen.has(key)) continue;
795
+ seen.add(key);
796
+ if (await isWorkingNpx(abs)) return abs;
797
+ }
798
+ return null;
799
+ }
800
+ function mergeCursorGlobalMcpConfigObject(existing, npxPath) {
801
+ const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
802
+ const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
803
+ mcpServers.memoraone = buildMemoraoneCursorMcpServer(npxPath);
804
+ return { ...base, mcpServers };
805
+ }
806
+ function memoraoneServerMatches(server, npxPath) {
807
+ if (!server || typeof server !== "object") return false;
808
+ const s = server;
809
+ if (s.command !== npxPath) return false;
810
+ if (!Array.isArray(s.args) || s.args.length !== 2) return false;
811
+ if (s.args[0] !== "-y" || s.args[1] !== "@memoraone/mcp@latest") return false;
812
+ const env = s.env;
813
+ if (!env || typeof env !== "object") return false;
814
+ const e = env;
815
+ return e.MEMORAONE_API_URL === "https://api.memoraone.com" && e.MEMORAONE_IDE_TYPE === "cursor";
816
+ }
817
+ function validateCursorGlobalMcpConfig(parsed, npxPath) {
818
+ if (!parsed || typeof parsed !== "object") {
819
+ throw new Error("[setup-ide-files] Cursor global MCP config must be a JSON object.");
820
+ }
821
+ const mcpServers = parsed.mcpServers;
822
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
823
+ throw new Error("[setup-ide-files] Cursor global MCP config missing mcpServers object.");
824
+ }
825
+ const memoraone = mcpServers.memoraone;
826
+ if (!memoraoneServerMatches(memoraone, npxPath)) {
827
+ throw new Error(
828
+ "[setup-ide-files] Cursor global MCP config mcpServers.memoraone is missing or invalid."
829
+ );
830
+ }
831
+ }
832
+ async function setupCursorGlobalMcpConfig(options) {
833
+ const { configPath, npxPath, dryRun } = options;
834
+ const existed = await pathExists(configPath);
835
+ let existing = null;
836
+ if (existed) {
837
+ const raw = await fs4.readFile(configPath, "utf8");
838
+ try {
839
+ existing = JSON.parse(stripLeadingLineComments(raw));
840
+ } catch {
841
+ throw new Error(
842
+ `[setup-ide-files] Invalid JSON in Cursor global MCP config: ${configPath}`
843
+ );
844
+ }
845
+ }
846
+ const merged = mergeCursorGlobalMcpConfigObject(existing, npxPath);
847
+ const body = JSON.stringify(merged, null, 2) + "\n";
848
+ if (existed) {
849
+ const currentMemoraone = existing && typeof existing.mcpServers === "object" && existing.mcpServers !== null && !Array.isArray(existing.mcpServers) ? existing.mcpServers.memoraone : void 0;
850
+ if (memoraoneServerMatches(currentMemoraone, npxPath)) {
851
+ return { outcome: "skipped" };
852
+ }
853
+ }
854
+ if (dryRun) {
855
+ return { outcome: existed ? "updated" : "created" };
856
+ }
857
+ let backupPath;
858
+ if (existed) {
859
+ backupPath = `${configPath}.backup-${formatBackupTimestamp()}`;
860
+ await fs4.copyFile(configPath, backupPath);
861
+ }
862
+ await fs4.mkdir(path4.dirname(configPath), { recursive: true });
863
+ await fs4.writeFile(configPath, body, "utf8");
864
+ const verifyRaw = await fs4.readFile(configPath, "utf8");
865
+ const verifyParsed = JSON.parse(stripLeadingLineComments(verifyRaw));
866
+ validateCursorGlobalMcpConfig(verifyParsed, npxPath);
867
+ return { outcome: existed ? "updated" : "created", backupPath };
868
+ }
869
+ function logCursorGlobalMcpCliSummary(info, dryRun) {
870
+ const { configPath, npxPath, backupPath, outcome } = info;
871
+ console.log(`[setup-ide-files] Cursor global MCP config: ${configPath}`);
872
+ console.log(`[setup-ide-files] Resolved npx: ${npxPath}`);
873
+ if (backupPath) {
874
+ console.log(`[setup-ide-files] Cursor global MCP config backup: ${backupPath}`);
875
+ }
876
+ if (outcome === "created") {
877
+ console.log(
878
+ dryRun ? `[setup-ide-files] Cursor global MCP config would be created: ${configPath}` : `[setup-ide-files] Cursor global MCP config created: ${configPath}`
879
+ );
880
+ } else if (outcome === "updated") {
881
+ console.log(
882
+ dryRun ? `[setup-ide-files] Cursor global MCP config would be updated: ${configPath}` : `[setup-ide-files] Cursor global MCP config updated: ${configPath}`
883
+ );
884
+ } else if (outcome === "skipped") {
885
+ console.log(`[setup-ide-files] Cursor global MCP config unchanged: ${configPath}`);
886
+ }
887
+ console.log(
888
+ "[setup-ide-files] Repo-level .cursor/mcp.json was not created or modified."
889
+ );
890
+ console.log(
891
+ "[setup-ide-files] Fully quit Cursor and reopen this repo for MCP changes to take effect."
892
+ );
893
+ }
894
+
895
+ // src/jetbrainsMcpConfig.ts
896
+ var fs5 = __toESM(require("fs/promises"), 1);
897
+ var os3 = __toESM(require("os"), 1);
898
+ var path5 = __toESM(require("path"), 1);
899
+ var import_node_child_process3 = require("child_process");
900
+
901
+ // src/configUtils.ts
902
+ var DEV_API_URL = "http://localhost:3001";
903
+
904
+ // src/jetbrainsMcpConfig.ts
905
+ var PROD_API_URL = "https://api.memoraone.com";
906
+ var JETBRAINS_DEBUG_ENV_VARS = [
907
+ "MEMORAONE_DEBUG_INIT",
908
+ "MEMORAONE_DEBUG_MINIMAL_TOOLS",
909
+ "MEMORAONE_DEBUG_MINIMAL_INITIALIZE",
910
+ "MEMORAONE_DEBUG_DIRECT_STDIO"
911
+ ];
912
+ function stripLeadingLineComments2(text) {
913
+ return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
914
+ }
915
+ async function pathExists2(filePath) {
916
+ try {
917
+ await fs5.access(filePath);
918
+ return true;
919
+ } catch {
920
+ return false;
921
+ }
922
+ }
923
+ function formatJetBrainsBackupTimestamp(d = /* @__PURE__ */ new Date()) {
924
+ const pad = (n) => String(n).padStart(2, "0");
925
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
926
+ }
927
+ function getJetBrainsGlobalMcpConfigPath(homeDir) {
928
+ return path5.join(homeDir, ".ai", "mcp", "mcp.json");
929
+ }
930
+ function getJetBrainsProjectMcpConfigPaths(repoRoot) {
931
+ return [
932
+ { kind: "project-ai", path: path5.join(repoRoot, ".ai", "mcp", "mcp.json") },
933
+ { kind: "project-ij", path: path5.join(repoRoot, ".ij", "mcp", "mcp.json") }
934
+ ];
935
+ }
936
+ function getKnownJetBrainsMcpConfigLocations(homeDir, repoRoot) {
937
+ return [
938
+ { kind: "global", path: getJetBrainsGlobalMcpConfigPath(homeDir) },
939
+ ...getJetBrainsProjectMcpConfigPaths(repoRoot)
940
+ ];
941
+ }
942
+ async function isZeroByteConfigFile(filePath) {
943
+ if (!await pathExists2(filePath)) return false;
944
+ const stat2 = await fs5.stat(filePath);
945
+ return stat2.size === 0;
946
+ }
947
+ function buildMemoraoneJetBrainsMcpServer(options) {
948
+ const env = {
949
+ MEMORAONE_API_URL: options.devMode ? DEV_API_URL : PROD_API_URL,
950
+ MEMORAONE_IDE_TYPE: "jetbrains",
951
+ MEMORAONE_M1_PATH: options.m1Path
952
+ };
953
+ if (options.devMode) {
954
+ env.MEMORAONE_DEV_MODE = "1";
955
+ }
956
+ return {
957
+ command: options.command,
958
+ args: options.args,
959
+ env
960
+ };
961
+ }
962
+ function mergeJetBrainsMcpConfigObject(existing, memoraone) {
963
+ const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
964
+ const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
965
+ mcpServers.memoraone = memoraone;
966
+ return { ...base, mcpServers };
967
+ }
968
+ function memoraoneServerMatches2(server, expected) {
969
+ if (!server || typeof server !== "object") return false;
970
+ const s = server;
971
+ if (s.command !== expected.command) return false;
972
+ if (!Array.isArray(s.args) || s.args.length !== expected.args.length) return false;
973
+ for (let i = 0; i < expected.args.length; i += 1) {
974
+ if (s.args[i] !== expected.args[i]) return false;
975
+ }
976
+ const env = s.env;
977
+ if (!env || typeof env !== "object") return false;
978
+ const e = env;
979
+ for (const [key, value] of Object.entries(expected.env)) {
980
+ if (e[key] !== value) return false;
981
+ }
982
+ for (const debugKey of JETBRAINS_DEBUG_ENV_VARS) {
983
+ if (debugKey in e) return false;
984
+ }
985
+ return true;
986
+ }
987
+ function validateJetBrainsMcpConfig(parsed, expected) {
988
+ if (!parsed || typeof parsed !== "object") {
989
+ throw new Error("[setup-ide-files] JetBrains MCP config must be a JSON object.");
990
+ }
991
+ const mcpServers = parsed.mcpServers;
992
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
993
+ throw new Error("[setup-ide-files] JetBrains MCP config missing mcpServers object.");
994
+ }
995
+ const memoraone = mcpServers.memoraone;
996
+ if (!memoraoneServerMatches2(memoraone, expected)) {
997
+ throw new Error(
998
+ "[setup-ide-files] JetBrains MCP config mcpServers.memoraone is missing or invalid."
999
+ );
1000
+ }
1001
+ }
1002
+ async function readJsonConfig(filePath) {
1003
+ const raw = await fs5.readFile(filePath, "utf8");
1004
+ if (raw.trim() === "") return null;
1005
+ return JSON.parse(stripLeadingLineComments2(raw));
1006
+ }
1007
+ async function backupConfigFile(filePath) {
1008
+ const backupPath = `${filePath}.bak-${formatJetBrainsBackupTimestamp()}`;
1009
+ await fs5.copyFile(filePath, backupPath);
1010
+ return backupPath;
1011
+ }
1012
+ async function repairZeroByteConfigFile(filePath, dryRun) {
1013
+ if (!await isZeroByteConfigFile(filePath)) {
1014
+ return { repaired: false };
1015
+ }
1016
+ if (dryRun) {
1017
+ return { repaired: true, backupPath: `${filePath}.bak-<timestamp>` };
1018
+ }
1019
+ const backupPath = await backupConfigFile(filePath);
1020
+ await fs5.unlink(filePath);
1021
+ return { repaired: true, backupPath };
1022
+ }
1023
+ function configHasMemoraone(parsed) {
1024
+ if (!parsed) return false;
1025
+ const mcpServers = parsed.mcpServers;
1026
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) return false;
1027
+ return Boolean(mcpServers.memoraone);
1028
+ }
1029
+ async function removeMemoraoneFromProjectConfig(options) {
1030
+ const { configPath, dryRun } = options;
1031
+ if (!await pathExists2(configPath)) {
1032
+ return { changed: false };
1033
+ }
1034
+ let parsed = null;
1035
+ try {
1036
+ parsed = await readJsonConfig(configPath);
1037
+ } catch {
1038
+ return { changed: false };
1039
+ }
1040
+ if (!configHasMemoraone(parsed)) {
1041
+ return { changed: false };
1042
+ }
1043
+ if (dryRun) {
1044
+ return { changed: true, backupPath: `${configPath}.bak-<timestamp>` };
1045
+ }
1046
+ const backupPath = await backupConfigFile(configPath);
1047
+ const mcpServers = parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null && !Array.isArray(parsed.mcpServers) ? { ...parsed.mcpServers } : {};
1048
+ delete mcpServers.memoraone;
1049
+ const hasOtherServers = Object.keys(mcpServers).length > 0;
1050
+ if (!hasOtherServers) {
1051
+ await fs5.unlink(configPath);
1052
+ return { changed: true, backupPath };
1053
+ }
1054
+ const next = { ...parsed, mcpServers };
1055
+ await fs5.mkdir(path5.dirname(configPath), { recursive: true });
1056
+ await fs5.writeFile(configPath, JSON.stringify(next, null, 2) + "\n", "utf8");
1057
+ return { changed: true, backupPath };
1058
+ }
1059
+ async function resolveLocalCliPathAsync() {
1060
+ const here = process.argv[1] ? path5.dirname(path5.resolve(process.argv[1])) : process.cwd();
1061
+ const candidates = [
1062
+ path5.join(here, "cli.cjs"),
1063
+ path5.join(here, "..", "dist", "cli.cjs"),
1064
+ path5.join(here, "..", "..", "dist", "cli.cjs")
1065
+ ];
1066
+ for (const candidate of candidates) {
1067
+ if (await pathExists2(candidate)) {
1068
+ return path5.resolve(candidate);
1069
+ }
1070
+ }
1071
+ return null;
1072
+ }
1073
+ async function buildJetBrainsMemoraoneServer(options) {
1074
+ if (options.devMode) {
1075
+ let cliPath = options.cliPathOverride;
1076
+ if (cliPath === void 0) {
1077
+ cliPath = await resolveLocalCliPathAsync();
1078
+ }
1079
+ if (!cliPath) {
1080
+ throw new Error(
1081
+ "[setup-ide-files] Dev mode requires a built CLI at packages/mcp/dist/cli.cjs. Run pnpm build first."
1082
+ );
1083
+ }
1084
+ return buildMemoraoneJetBrainsMcpServer({
1085
+ command: process.execPath,
1086
+ args: [cliPath],
1087
+ m1Path: options.m1Path,
1088
+ devMode: true
1089
+ });
1090
+ }
1091
+ let npxPath = options.npxPathOverride;
1092
+ if (npxPath === void 0) {
1093
+ npxPath = await resolveNpxPath();
1094
+ }
1095
+ if (!npxPath) {
1096
+ throw new Error(
1097
+ "[setup-ide-files] Could not resolve a working npx executable. Install Node.js/npm or ensure npx is on PATH before configuring JetBrains MCP."
1098
+ );
1099
+ }
1100
+ return buildMemoraoneJetBrainsMcpServer({
1101
+ command: npxPath,
1102
+ args: ["-y", "@memoraone/mcp@latest"],
1103
+ m1Path: options.m1Path,
1104
+ devMode: false
1105
+ });
1106
+ }
1107
+ async function verifyJetBrainsMcpHandshake(options) {
1108
+ const timeoutMs = options.timeoutMs ?? 15e3;
1109
+ const { server } = options;
1110
+ return new Promise((resolve7) => {
1111
+ let settled = false;
1112
+ const finish = (ok, detail) => {
1113
+ if (settled) return;
1114
+ settled = true;
1115
+ clearTimeout(timer);
1116
+ try {
1117
+ child.kill();
1118
+ } catch {
1119
+ }
1120
+ resolve7({ ok, detail });
1121
+ };
1122
+ const child = (0, import_node_child_process3.spawn)(server.command, [...server.args], {
1123
+ env: { ...process.env, ...server.env },
1124
+ stdio: ["pipe", "pipe", "pipe"]
1125
+ });
1126
+ let buffer = "";
1127
+ let initializeOk = false;
1128
+ let toolsListOk = false;
1129
+ let nextId = 1;
1130
+ const send = (method, params) => {
1131
+ const msg = JSON.stringify({ jsonrpc: "2.0", id: nextId, method, params }) + "\n";
1132
+ nextId += 1;
1133
+ child.stdin?.write(msg);
1134
+ };
1135
+ const timer = setTimeout(() => {
1136
+ finish(false, `handshake timed out after ${timeoutMs}ms`);
1137
+ }, timeoutMs);
1138
+ child.stdout?.on("data", (chunk) => {
1139
+ buffer += chunk.toString("utf8");
1140
+ const lines = buffer.split("\n");
1141
+ buffer = lines.pop() ?? "";
1142
+ for (const line of lines) {
1143
+ if (!line.trim()) continue;
1144
+ let msg;
1145
+ try {
1146
+ msg = JSON.parse(line);
1147
+ } catch {
1148
+ continue;
1149
+ }
1150
+ if (msg.id === 1 && msg.result) {
1151
+ initializeOk = true;
1152
+ send("notifications/initialized", {});
1153
+ send("tools/list", {});
1154
+ }
1155
+ if (msg.id === 2 && msg.result) {
1156
+ toolsListOk = true;
1157
+ finish(true, "initialize OK; tools/list OK");
1158
+ }
1159
+ if (msg.error) {
1160
+ finish(false, `JSON-RPC error: ${JSON.stringify(msg.error)}`);
1161
+ }
1162
+ }
1163
+ });
1164
+ child.on("error", (err) => {
1165
+ finish(false, `spawn error: ${String(err)}`);
1166
+ });
1167
+ child.on("exit", (code) => {
1168
+ if (!settled) {
1169
+ if (initializeOk && toolsListOk) {
1170
+ finish(true, "initialize OK; tools/list OK");
1171
+ } else {
1172
+ finish(
1173
+ false,
1174
+ `process exited code=${code ?? "null"} (initialize=${initializeOk}, tools/list=${toolsListOk})`
1175
+ );
1176
+ }
1177
+ }
1178
+ });
1179
+ send("initialize", {
1180
+ protocolVersion: "2024-11-05",
1181
+ capabilities: {},
1182
+ clientInfo: { name: "memoraone-setup", version: "1.0.0" }
1183
+ });
1184
+ });
1185
+ }
1186
+ async function setupJetBrainsMcpConfig(options) {
1187
+ const homeDir = options.homeDir ?? os3.homedir();
1188
+ const globalPath = options.globalConfigPath ?? getJetBrainsGlobalMcpConfigPath(homeDir);
1189
+ const m1Path = path5.join(path5.resolve(options.repoRoot), "memoraone.m1");
1190
+ const repairActions = [];
1191
+ const allLocations = getKnownJetBrainsMcpConfigLocations(homeDir, options.repoRoot);
1192
+ for (const location of allLocations) {
1193
+ if (await pathExists2(location.path)) {
1194
+ repairActions.push({ type: "found-config", location });
1195
+ }
1196
+ }
1197
+ for (const location of allLocations) {
1198
+ const zeroByte = await repairZeroByteConfigFile(location.path, options.dryRun);
1199
+ if (zeroByte.repaired) {
1200
+ repairActions.push({
1201
+ type: "repaired-zero-byte",
1202
+ path: location.path,
1203
+ backupPath: zeroByte.backupPath ?? `${location.path}.bak-<timestamp>`
1204
+ });
1205
+ }
1206
+ }
1207
+ const memoraone = await buildJetBrainsMemoraoneServer({
1208
+ m1Path,
1209
+ devMode: options.devMode,
1210
+ npxPathOverride: options.npxPathOverride,
1211
+ cliPathOverride: options.cliPathOverride
1212
+ });
1213
+ for (const location of getJetBrainsProjectMcpConfigPaths(options.repoRoot)) {
1214
+ const removal = await removeMemoraoneFromProjectConfig({
1215
+ configPath: location.path,
1216
+ dryRun: options.dryRun
1217
+ });
1218
+ if (removal.changed) {
1219
+ if (removal.backupPath) {
1220
+ repairActions.push({
1221
+ type: "backed-up-conflicting-project-config",
1222
+ path: location.path,
1223
+ backupPath: removal.backupPath
1224
+ });
1225
+ }
1226
+ repairActions.push({ type: "removed-project-memoraone", path: location.path });
1227
+ }
1228
+ }
1229
+ const existed = await pathExists2(globalPath);
1230
+ let existing = null;
1231
+ if (existed) {
1232
+ try {
1233
+ existing = await readJsonConfig(globalPath);
1234
+ } catch {
1235
+ if (options.dryRun) {
1236
+ existing = null;
1237
+ } else {
1238
+ const backupPath2 = await backupConfigFile(globalPath);
1239
+ repairActions.push({
1240
+ type: "repaired-zero-byte",
1241
+ path: globalPath,
1242
+ backupPath: backupPath2
1243
+ });
1244
+ await fs5.unlink(globalPath);
1245
+ existing = null;
1246
+ }
1247
+ }
1248
+ }
1249
+ const merged = mergeJetBrainsMcpConfigObject(existing, memoraone);
1250
+ const body = JSON.stringify(merged, null, 2) + "\n";
1251
+ if (existed && existing) {
1252
+ const currentMemoraone = existing.mcpServers && typeof existing.mcpServers === "object" && !Array.isArray(existing.mcpServers) ? existing.mcpServers.memoraone : void 0;
1253
+ if (memoraoneServerMatches2(currentMemoraone, memoraone)) {
1254
+ repairActions.push({ type: "wrote-global-config", path: globalPath, outcome: "skipped" });
1255
+ return { outcome: "skipped", repairActions, memoraone };
1256
+ }
1257
+ }
1258
+ if (options.dryRun) {
1259
+ const outcome2 = existed ? "updated" : "created";
1260
+ repairActions.push({ type: "wrote-global-config", path: globalPath, outcome: outcome2 });
1261
+ return { outcome: outcome2, repairActions, memoraone };
1262
+ }
1263
+ let backupPath;
1264
+ if (existed) {
1265
+ backupPath = await backupConfigFile(globalPath);
1266
+ }
1267
+ await fs5.mkdir(path5.dirname(globalPath), { recursive: true });
1268
+ await fs5.writeFile(globalPath, body, "utf8");
1269
+ const verifyRaw = await fs5.readFile(globalPath, "utf8");
1270
+ const verifyParsed = JSON.parse(stripLeadingLineComments2(verifyRaw));
1271
+ validateJetBrainsMcpConfig(verifyParsed, memoraone);
1272
+ const outcome = existed ? "updated" : "created";
1273
+ repairActions.push({ type: "wrote-global-config", path: globalPath, outcome });
1274
+ let verifyOk;
1275
+ let verifyDetail;
1276
+ if (options.verify !== false) {
1277
+ const verify = await verifyJetBrainsMcpHandshake({ server: memoraone });
1278
+ verifyOk = verify.ok;
1279
+ verifyDetail = verify.detail;
1280
+ repairActions.push({ type: "verify-handshake", ok: verify.ok, detail: verify.detail });
1281
+ }
1282
+ return { outcome, backupPath, repairActions, verifyOk, verifyDetail, memoraone };
1283
+ }
1284
+ function logJetBrainsMcpCliSummary(info, dryRun) {
1285
+ for (const action of info.repairActions) {
1286
+ if (action.type === "found-config") {
1287
+ console.log(`[setup-ide-files] Found JetBrains MCP config (${action.location.kind}): ${action.location.path}`);
1288
+ } else if (action.type === "repaired-zero-byte") {
1289
+ console.log(`[setup-ide-files] Repaired zero-byte MCP config: ${action.path}`);
1290
+ console.log(`[setup-ide-files] Backup: ${action.backupPath}`);
1291
+ } else if (action.type === "backed-up-conflicting-project-config") {
1292
+ console.log(`[setup-ide-files] Backed up conflicting project MCP config: ${action.path}`);
1293
+ console.log(`[setup-ide-files] Backup: ${action.backupPath}`);
1294
+ } else if (action.type === "removed-project-memoraone") {
1295
+ console.log(`[setup-ide-files] Removed project-scoped memoraone definition: ${action.path}`);
1296
+ } else if (action.type === "verify-handshake") {
1297
+ if (action.ok) {
1298
+ console.log(`[setup-ide-files] MCP handshake verification: ${action.detail}`);
1299
+ } else {
1300
+ console.log(`[setup-ide-files] MCP handshake verification skipped/failed: ${action.detail}`);
1301
+ }
1302
+ }
1303
+ }
1304
+ const prefix = dryRun ? "would be " : "";
1305
+ if (info.outcome === "created") {
1306
+ console.log(`[setup-ide-files] JetBrains global MCP config ${prefix}created: ${info.activeConfigPath}`);
1307
+ } else if (info.outcome === "updated") {
1308
+ console.log(`[setup-ide-files] JetBrains global MCP config ${prefix}updated: ${info.activeConfigPath}`);
1309
+ } else {
1310
+ console.log(`[setup-ide-files] JetBrains global MCP config unchanged: ${info.activeConfigPath}`);
1311
+ }
1312
+ if (info.backupPath) {
1313
+ console.log(`[setup-ide-files] JetBrains global MCP config backup: ${info.backupPath}`);
1314
+ }
1315
+ if (info.npxPath) {
1316
+ console.log(`[setup-ide-files] Resolved npx: ${info.npxPath}`);
1317
+ }
1318
+ console.log(`[setup-ide-files] Final active JetBrains MCP config: ${info.activeConfigPath}`);
1319
+ console.log(
1320
+ "[setup-ide-files] Fully quit JetBrains IDE and reopen this repo for MCP changes to take effect."
1321
+ );
1322
+ }
1323
+
688
1324
  // src/setupIdeFiles.ts
689
1325
  var MANAGED_MARKER = "<!-- MemoraOne managed IDE helper -->";
690
1326
  var GITIGNORE_MEMORAONE_COMMENT = "# MemoraOne local project binding / API key";
691
1327
  var GITIGNORE_MEMORAONE_ENTRY = "memoraone.m1";
692
- function buildMemoraoneMcpServer(ideType) {
1328
+ function buildMemoraoneMcpServer(ideType, command = "npx") {
693
1329
  return {
694
- command: "npx",
1330
+ command,
695
1331
  args: ["-y", "@memoraone/mcp@latest"],
696
1332
  env: {
697
1333
  MEMORAONE_API_URL: "https://api.memoraone.com",
@@ -700,15 +1336,15 @@ function buildMemoraoneMcpServer(ideType) {
700
1336
  };
701
1337
  }
702
1338
  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)) {
1339
+ const normRoot = path6.resolve(repoRoot) + path6.sep;
1340
+ const normPath = path6.resolve(absPath);
1341
+ if (normPath !== path6.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
706
1342
  throw new Error(`[setup-ide-files] Refusing to write outside repo root: ${absPath}`);
707
1343
  }
708
1344
  }
709
- async function pathExists(filePath) {
1345
+ async function pathExists3(filePath) {
710
1346
  try {
711
- await fs4.access(filePath);
1347
+ await fs6.access(filePath);
712
1348
  return true;
713
1349
  } catch {
714
1350
  return false;
@@ -729,12 +1365,12 @@ ${GITIGNORE_MEMORAONE_ENTRY}
729
1365
  }
730
1366
  async function ensureGitignoreMemoraone(repoRoot, opts) {
731
1367
  if (opts.noGitignore) return "skipped";
732
- const abs = path4.join(repoRoot, ".gitignore");
1368
+ const abs = path6.join(repoRoot, ".gitignore");
733
1369
  assertUnderRepoRoot(repoRoot, abs);
734
1370
  let prior = "";
735
1371
  let existed = false;
736
1372
  try {
737
- prior = await fs4.readFile(abs, "utf8");
1373
+ prior = await fs6.readFile(abs, "utf8");
738
1374
  existed = true;
739
1375
  } catch (err) {
740
1376
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
@@ -745,25 +1381,25 @@ async function ensureGitignoreMemoraone(repoRoot, opts) {
745
1381
  const separator = existed && prior.length > 0 ? prior.endsWith("\n") ? "\n" : "\n\n" : "";
746
1382
  const next = (existed ? prior : "") + separator + block;
747
1383
  if (opts.dryRun) return existed ? "updated" : "created";
748
- await fs4.writeFile(abs, next, "utf8");
1384
+ await fs6.writeFile(abs, next, "utf8");
749
1385
  return existed ? "updated" : "created";
750
1386
  }
751
1387
  async function findRepoRoot(startDir) {
752
- let current = path4.resolve(startDir);
753
- const root = path4.parse(current).root;
1388
+ let current = path6.resolve(startDir);
1389
+ const root = path6.parse(current).root;
754
1390
  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)) {
1391
+ const gitPath = path6.join(current, ".git");
1392
+ const m1Path = path6.join(current, "memoraone.m1");
1393
+ if (await pathExists3(gitPath) || await pathExists3(m1Path)) {
758
1394
  return current;
759
1395
  }
760
1396
  if (current === root) {
761
1397
  return null;
762
1398
  }
763
- current = path4.dirname(current);
1399
+ current = path6.dirname(current);
764
1400
  }
765
1401
  }
766
- function stripLeadingLineComments(text) {
1402
+ function stripLeadingLineComments3(text) {
767
1403
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
768
1404
  }
769
1405
  function cursorRuleBody() {
@@ -813,50 +1449,43 @@ function buildVscodeMcpJsonBody(existing) {
813
1449
  const merged = { ...base, servers };
814
1450
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
815
1451
  }
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
1452
  async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
824
- const abs = path4.join(repoRoot, relPath);
1453
+ const abs = path6.join(repoRoot, relPath);
825
1454
  assertUnderRepoRoot(repoRoot, abs);
826
1455
  let prior = "";
827
1456
  let existed = false;
828
1457
  try {
829
- prior = await fs4.readFile(abs, "utf8");
1458
+ prior = await fs6.readFile(abs, "utf8");
830
1459
  existed = true;
831
1460
  } catch (err) {
832
1461
  if (err?.code !== "ENOENT") throw err;
833
1462
  }
834
1463
  if (!existed) {
835
1464
  if (opts.dryRun) return "created";
836
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
837
- await fs4.writeFile(abs, fullContent, "utf8");
1465
+ await fs6.mkdir(path6.dirname(abs), { recursive: true });
1466
+ await fs6.writeFile(abs, fullContent, "utf8");
838
1467
  return "created";
839
1468
  }
840
1469
  if (prior.includes(MANAGED_MARKER)) {
841
1470
  if (prior === fullContent) return "skipped";
842
1471
  if (opts.dryRun) return "updated";
843
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
844
- await fs4.writeFile(abs, fullContent, "utf8");
1472
+ await fs6.mkdir(path6.dirname(abs), { recursive: true });
1473
+ await fs6.writeFile(abs, fullContent, "utf8");
845
1474
  return "updated";
846
1475
  }
847
1476
  if (!opts.force) return "skipped-untracked";
848
1477
  if (opts.dryRun) return "updated";
849
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
850
- await fs4.writeFile(abs, fullContent, "utf8");
1478
+ await fs6.mkdir(path6.dirname(abs), { recursive: true });
1479
+ await fs6.writeFile(abs, fullContent, "utf8");
851
1480
  return "updated";
852
1481
  }
853
1482
  async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
854
- const abs = path4.join(repoRoot, relPath);
1483
+ const abs = path6.join(repoRoot, relPath);
855
1484
  assertUnderRepoRoot(repoRoot, abs);
856
1485
  let raw = "";
857
1486
  let existed = false;
858
1487
  try {
859
- raw = await fs4.readFile(abs, "utf8");
1488
+ raw = await fs6.readFile(abs, "utf8");
860
1489
  existed = true;
861
1490
  } catch (err) {
862
1491
  if (err?.code !== "ENOENT") throw err;
@@ -864,15 +1493,15 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
864
1493
  if (!existed) {
865
1494
  const body = buildBody(null);
866
1495
  if (opts.dryRun) return "created";
867
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
868
- await fs4.writeFile(abs, body, "utf8");
1496
+ await fs6.mkdir(path6.dirname(abs), { recursive: true });
1497
+ await fs6.writeFile(abs, body, "utf8");
869
1498
  return "created";
870
1499
  }
871
1500
  const managed = raw.includes(MANAGED_MARKER);
872
1501
  if (!managed && !opts.force) return "skipped-untracked";
873
1502
  let parsed = null;
874
1503
  try {
875
- parsed = JSON.parse(stripLeadingLineComments(raw));
1504
+ parsed = JSON.parse(stripLeadingLineComments3(raw));
876
1505
  } catch {
877
1506
  parsed = null;
878
1507
  }
@@ -880,8 +1509,8 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
880
1509
  const next = buildBody(parsed);
881
1510
  if (managed && next === raw) return "skipped";
882
1511
  if (opts.dryRun) return "updated";
883
- await fs4.mkdir(path4.dirname(abs), { recursive: true });
884
- await fs4.writeFile(abs, next, "utf8");
1512
+ await fs6.mkdir(path6.dirname(abs), { recursive: true });
1513
+ await fs6.writeFile(abs, next, "utf8");
885
1514
  return "updated";
886
1515
  }
887
1516
  function parseSetupIdeFlags(argv) {
@@ -893,6 +1522,8 @@ function parseSetupIdeFlags(argv) {
893
1522
  let dryRun = false;
894
1523
  let noGitignore = false;
895
1524
  let cleanup = false;
1525
+ let devMode = false;
1526
+ let repair = false;
896
1527
  const unknown = [];
897
1528
  for (const a of argv) {
898
1529
  if (a === "--cursor") cursor = true;
@@ -903,6 +1534,8 @@ function parseSetupIdeFlags(argv) {
903
1534
  else if (a === "--dry-run") dryRun = true;
904
1535
  else if (a === "--no-gitignore") noGitignore = true;
905
1536
  else if (a === "--cleanup") cleanup = true;
1537
+ else if (a === "--dev") devMode = true;
1538
+ else if (a === "--repair") repair = true;
906
1539
  else if (a.startsWith("-")) unknown.push(a);
907
1540
  }
908
1541
  const specific = cursor || vscode || jetbrains;
@@ -912,7 +1545,7 @@ function parseSetupIdeFlags(argv) {
912
1545
  } else {
913
1546
  targets = { cursor, vscode, jetbrains };
914
1547
  }
915
- return { targets, force, dryRun, noGitignore, cleanup, unknown };
1548
+ return { targets, force, dryRun, noGitignore, cleanup, devMode, repair, unknown };
916
1549
  }
917
1550
  function summarizeOutcomes(outcomes) {
918
1551
  const created = [];
@@ -936,6 +1569,8 @@ function summarizeOutcomes(outcomes) {
936
1569
  }
937
1570
  async function runSetupIdeFiles(o) {
938
1571
  const outcomes = {};
1572
+ let cursorGlobalMcp;
1573
+ let jetbrainsMcp;
939
1574
  const repoRoot = await findRepoRoot(o.cwd);
940
1575
  if (!repoRoot) {
941
1576
  return {
@@ -955,21 +1590,62 @@ description: MemoraOne MCP \u2014 IDE agent instructions
955
1590
 
956
1591
  ` + cursorRuleBody();
957
1592
  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
- );
1593
+ const detection = await detectCursorGlobalMcpConfig({
1594
+ homeDir: o.homeDir,
1595
+ explicitPath: o.cursorGlobalMcpConfigPath
1596
+ });
1597
+ if (!detection.ok) {
1598
+ return {
1599
+ exitCode: 1,
1600
+ repoRoot,
1601
+ outcomes,
1602
+ error: `${detection.error}
1603
+ ${detection.candidates.join("\n ")}`
1604
+ };
1605
+ }
1606
+ let npxPath;
1607
+ if (o.npxPathOverride !== void 0) {
1608
+ npxPath = o.npxPathOverride;
1609
+ } else {
1610
+ npxPath = await resolveNpxPath();
1611
+ }
1612
+ if (!npxPath) {
1613
+ return {
1614
+ exitCode: 1,
1615
+ repoRoot,
1616
+ outcomes,
1617
+ 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."
1618
+ };
1619
+ }
967
1620
  outcomes[".cursor/rules/memoraone-mcp.mdc"] = await writeManagedMarkdown(
968
1621
  repoRoot,
969
1622
  ".cursor/rules/memoraone-mcp.mdc",
970
1623
  cursorContent,
971
1624
  { force: o.force, dryRun: o.dryRun }
972
1625
  );
1626
+ try {
1627
+ const globalSetup = await setupCursorGlobalMcpConfig({
1628
+ configPath: detection.path,
1629
+ npxPath,
1630
+ dryRun: o.dryRun
1631
+ });
1632
+ cursorGlobalMcp = {
1633
+ configPath: detection.path,
1634
+ outcome: globalSetup.outcome,
1635
+ npxPath,
1636
+ backupPath: globalSetup.backupPath
1637
+ };
1638
+ outcomes[`cursor-global:${detection.path}`] = globalSetup.outcome;
1639
+ } catch (err) {
1640
+ const message = err instanceof Error ? err.message : String(err);
1641
+ return {
1642
+ exitCode: 1,
1643
+ repoRoot,
1644
+ outcomes,
1645
+ cursorGlobalMcp: { configPath: detection.path, outcome: "skipped", npxPath },
1646
+ error: message
1647
+ };
1648
+ }
973
1649
  }
974
1650
  if (o.targets.vscode) {
975
1651
  outcomes[".vscode/mcp.json"] = await writeIdeMcpJson(
@@ -995,11 +1671,45 @@ description: MemoraOne MCP \u2014 IDE agent instructions
995
1671
  copilotAndJetBrainsBody("MemoraOne MCP \u2014 JetBrains AI Assistant"),
996
1672
  { force: o.force, dryRun: o.dryRun }
997
1673
  );
1674
+ try {
1675
+ const homeDir = o.jetbrainsHomeDir ?? os4.homedir();
1676
+ const activePath = o.jetbrainsGlobalMcpConfigPath ?? getJetBrainsGlobalMcpConfigPath(homeDir);
1677
+ const jetbrainsSetup = await setupJetBrainsMcpConfig({
1678
+ homeDir,
1679
+ repoRoot,
1680
+ globalConfigPath: activePath,
1681
+ dryRun: o.dryRun,
1682
+ devMode: o.devMode,
1683
+ repair: o.repair ?? false,
1684
+ verify: o.verifyHandshake ?? !o.dryRun,
1685
+ npxPathOverride: o.npxPathOverride,
1686
+ cliPathOverride: o.cliPathOverride
1687
+ });
1688
+ jetbrainsMcp = {
1689
+ activeConfigPath: activePath,
1690
+ outcome: jetbrainsSetup.outcome,
1691
+ npxPath: jetbrainsSetup.memoraone?.command,
1692
+ backupPath: jetbrainsSetup.backupPath,
1693
+ repairActions: jetbrainsSetup.repairActions,
1694
+ verifyOk: jetbrainsSetup.verifyOk,
1695
+ verifyDetail: jetbrainsSetup.verifyDetail
1696
+ };
1697
+ outcomes[`jetbrains-global:${activePath}`] = jetbrainsSetup.outcome;
1698
+ } catch (err) {
1699
+ const message = err instanceof Error ? err.message : String(err);
1700
+ return {
1701
+ exitCode: 1,
1702
+ repoRoot,
1703
+ outcomes,
1704
+ cursorGlobalMcp,
1705
+ error: message
1706
+ };
1707
+ }
998
1708
  }
999
- return { exitCode: 0, repoRoot, outcomes };
1709
+ return { exitCode: 0, repoRoot, outcomes, cursorGlobalMcp, jetbrainsMcp };
1000
1710
  }
1001
1711
  async function cliSetupIdeFiles(argv) {
1002
- const { targets, force, dryRun, noGitignore, cleanup, unknown } = parseSetupIdeFlags(argv);
1712
+ const { targets, force, dryRun, noGitignore, cleanup, devMode, repair, unknown } = parseSetupIdeFlags(argv);
1003
1713
  if (unknown.length) {
1004
1714
  console.error(`[setup-ide-files] Unknown option(s): ${unknown.join(", ")}`);
1005
1715
  return 1;
@@ -1009,15 +1719,27 @@ async function cliSetupIdeFiles(argv) {
1009
1719
  targets,
1010
1720
  force,
1011
1721
  dryRun,
1012
- noGitignore
1722
+ noGitignore,
1723
+ devMode,
1724
+ repair
1013
1725
  });
1014
1726
  if (result.error) {
1015
1727
  console.error(result.error);
1728
+ if (result.repoRoot) {
1729
+ console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
1730
+ }
1731
+ summarizeOutcomes(result.outcomes);
1016
1732
  return result.exitCode;
1017
1733
  }
1018
1734
  if (result.repoRoot) {
1019
1735
  console.log(`[setup-ide-files] Repo root: ${result.repoRoot}`);
1020
1736
  }
1737
+ if (targets.cursor && result.cursorGlobalMcp) {
1738
+ logCursorGlobalMcpCliSummary(result.cursorGlobalMcp, dryRun);
1739
+ }
1740
+ if (targets.jetbrains && result.jetbrainsMcp) {
1741
+ logJetBrainsMcpCliSummary(result.jetbrainsMcp, dryRun);
1742
+ }
1021
1743
  summarizeOutcomes(result.outcomes);
1022
1744
  if (dryRun) {
1023
1745
  console.log("[setup-ide-files] Dry run: no files written.");
@@ -1054,7 +1776,7 @@ if (args.includes("--version") || args.includes("-v")) {
1054
1776
  }
1055
1777
  if (args.includes("--help") || args.includes("-h")) {
1056
1778
  console.log(
1057
- "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]\n memoraone-mcp cleanup [--project-id <uuid>] [--ide cursor|copilot-vscode|jetbrains] [--dry-run] [--all-projects] [--yes]"
1779
+ "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]"
1058
1780
  );
1059
1781
  process.exit(0);
1060
1782
  }
@@ -1081,8 +1803,8 @@ if (args[0] === "cleanup") {
1081
1803
  const raw = process.env.WORKSPACE_FOLDER_PATHS;
1082
1804
  const parts = [];
1083
1805
  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));
1806
+ for (const p of raw.split(path7.delimiter).map((s) => s.trim()).filter(Boolean)) {
1807
+ parts.push(path7.resolve(p));
1086
1808
  }
1087
1809
  }
1088
1810
  parts.push(process.cwd());
@@ -1096,10 +1818,10 @@ if (args[0] === "cleanup") {
1096
1818
  }
1097
1819
  return deduped;
1098
1820
  }, connectWithRetry = function(socketPath) {
1099
- return new Promise((resolve5, reject) => {
1821
+ return new Promise((resolve7, reject) => {
1100
1822
  const tryConnect = (attempt) => {
1101
1823
  const socket = net.connect(socketPath, () => {
1102
- resolve5(socket);
1824
+ resolve7(socket);
1103
1825
  });
1104
1826
  socket.on("error", (err) => {
1105
1827
  if (attempt >= MAX_RETRIES) {
@@ -1135,7 +1857,7 @@ if (args[0] === "cleanup") {
1135
1857
  socket = await connectWithRetry(socketPath);
1136
1858
  } catch {
1137
1859
  log("daemon not running, spawning...");
1138
- const child = (0, import_node_child_process2.spawn)(
1860
+ const child = (0, import_node_child_process4.spawn)(
1139
1861
  process.execPath,
1140
1862
  buildDaemonSpawnArgs(process.argv[1], binding.projectId),
1141
1863
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoraone/mcp",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {