@memoraone/mcp 0.1.36 → 0.1.37

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 +452 -252
  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.36",
33
+ version: "0.1.37",
34
34
  type: "module",
35
35
  main: "dist/index.cjs",
36
36
  bin: {
@@ -366,7 +366,7 @@ async function acquireLocalLock(lockName, options = {}) {
366
366
  `[memoraone-mcp] Failed to acquire lock ${lockName} after ${maxRetries} retries`
367
367
  );
368
368
  }
369
- await new Promise((resolve16) => setTimeout(resolve16, retryDelayMs));
369
+ await new Promise((resolve17) => setTimeout(resolve17, retryDelayMs));
370
370
  continue;
371
371
  }
372
372
  throw err;
@@ -855,9 +855,9 @@ var MemoraOneHttpError = class extends Error {
855
855
  };
856
856
 
857
857
  // src/localState/localConnectClient.ts
858
- async function requestJson(baseUrl, method, path20, options = {}) {
858
+ async function requestJson(baseUrl, method, path21, options = {}) {
859
859
  const fetchImpl = options.fetchImpl ?? fetch;
860
- const url = `${baseUrl.replace(/\/+$/, "")}${path20.startsWith("/") ? path20 : `/${path20}`}`;
860
+ const url = `${baseUrl.replace(/\/+$/, "")}${path21.startsWith("/") ? path21 : `/${path21}`}`;
861
861
  const res = await fetchImpl(url, {
862
862
  method,
863
863
  headers: {
@@ -1528,8 +1528,8 @@ var StdioLineReader = class {
1528
1528
  if (this.closed) {
1529
1529
  return null;
1530
1530
  }
1531
- return new Promise((resolve16) => {
1532
- this.waiters.push(resolve16);
1531
+ return new Promise((resolve17) => {
1532
+ this.waiters.push(resolve17);
1533
1533
  });
1534
1534
  }
1535
1535
  /** Re-queue lines read during an intermediate protocol step (e.g. roots/list) for the main bridge loop. */
@@ -1602,17 +1602,17 @@ async function requestClientRootsListUris(options) {
1602
1602
  }
1603
1603
 
1604
1604
  // src/cleanup.ts
1605
- var fs10 = __toESM(require("fs/promises"), 1);
1606
- var path13 = __toESM(require("path"), 1);
1605
+ var fs11 = __toESM(require("fs/promises"), 1);
1606
+ var path15 = __toESM(require("path"), 1);
1607
1607
  var readline2 = __toESM(require("readline/promises"), 1);
1608
1608
  var import_node_child_process3 = require("child_process");
1609
1609
  var import_node_util3 = require("util");
1610
1610
  var import_node_process = require("process");
1611
1611
 
1612
1612
  // src/cursorGlobalMcpConfig.ts
1613
- var fs9 = __toESM(require("fs/promises"), 1);
1613
+ var fs10 = __toESM(require("fs/promises"), 1);
1614
1614
  var os4 = __toESM(require("os"), 1);
1615
- var path12 = __toESM(require("path"), 1);
1615
+ var path14 = __toESM(require("path"), 1);
1616
1616
  var import_node_child_process2 = require("child_process");
1617
1617
  var import_node_util2 = require("util");
1618
1618
 
@@ -1787,19 +1787,194 @@ async function resolveBindingFromInitializeParams(params, options = {}) {
1787
1787
  });
1788
1788
  }
1789
1789
 
1790
+ // src/packageExecutionMode.ts
1791
+ var path13 = __toESM(require("path"), 1);
1792
+
1793
+ // src/resolveBuiltCliPath.ts
1794
+ var fs9 = __toESM(require("fs/promises"), 1);
1795
+ var path12 = __toESM(require("path"), 1);
1796
+ var MONOREPO_CLI_REL = path12.join("packages", "mcp", "dist", "cli.cjs");
1797
+ async function pathExists(filePath) {
1798
+ try {
1799
+ await fs9.access(filePath);
1800
+ return true;
1801
+ } catch {
1802
+ return false;
1803
+ }
1804
+ }
1805
+ async function findMonorepoCliFrom(startDir) {
1806
+ let current = path12.resolve(startDir);
1807
+ const root = path12.parse(current).root;
1808
+ while (true) {
1809
+ const candidate = path12.join(current, MONOREPO_CLI_REL);
1810
+ if (await pathExists(candidate)) {
1811
+ return path12.resolve(candidate);
1812
+ }
1813
+ if (current === root) break;
1814
+ current = path12.dirname(current);
1815
+ }
1816
+ return null;
1817
+ }
1818
+ async function resolveFromRunningScript() {
1819
+ if (!process.argv[1]) return null;
1820
+ const script = path12.resolve(process.argv[1]);
1821
+ const base = path12.basename(script);
1822
+ if ((base === "cli.cjs" || base === "cli.ts" || base === "memoraone-mcp.cjs") && await pathExists(script)) {
1823
+ return script;
1824
+ }
1825
+ const here = path12.dirname(script);
1826
+ const candidates = [
1827
+ path12.join(here, "cli.cjs"),
1828
+ path12.join(here, "..", "dist", "cli.cjs"),
1829
+ path12.join(here, "..", "..", "dist", "cli.cjs")
1830
+ ];
1831
+ for (const candidate of candidates) {
1832
+ if (await pathExists(candidate)) {
1833
+ return path12.resolve(candidate);
1834
+ }
1835
+ }
1836
+ return null;
1837
+ }
1838
+ async function resolveBuiltCliPathAsync(options) {
1839
+ const preferRunning = options?.preferRunningScript !== false;
1840
+ if (preferRunning) {
1841
+ const fromRunning = await resolveFromRunningScript();
1842
+ if (fromRunning) return fromRunning;
1843
+ }
1844
+ const searchDirs = [];
1845
+ if (options?.searchFrom !== void 0) {
1846
+ const dirs = Array.isArray(options.searchFrom) ? options.searchFrom : [options.searchFrom];
1847
+ searchDirs.push(...dirs);
1848
+ }
1849
+ searchDirs.push(process.cwd());
1850
+ const seen = /* @__PURE__ */ new Set();
1851
+ for (const dir of searchDirs) {
1852
+ const key = path12.resolve(dir);
1853
+ if (seen.has(key)) continue;
1854
+ seen.add(key);
1855
+ const found = await findMonorepoCliFrom(key);
1856
+ if (found) return found;
1857
+ }
1858
+ if (!preferRunning) {
1859
+ return resolveFromRunningScript();
1860
+ }
1861
+ return null;
1862
+ }
1863
+
1864
+ // src/packageExecutionMode.ts
1865
+ var PROD_API_URL = "https://api.memoraone.com";
1866
+ var STAGING_API_URL = "https://memora-api-staging-phbtrzocjq-uk.a.run.app";
1867
+ var STAGING_API_URL_PREFIX = "https://memora-api-staging-";
1868
+ function normalizeApiUrl(url) {
1869
+ return url.trim().replace(/\/+$/, "");
1870
+ }
1871
+ function memoraoneNpmPackageSpec(channel) {
1872
+ return channel === "staging" ? "@memoraone/mcp@staging" : "@memoraone/mcp@latest";
1873
+ }
1874
+ function isMemoraoneNpmPackageSpec(value) {
1875
+ return value === "@memoraone/mcp@staging" || value === "@memoraone/mcp@latest";
1876
+ }
1877
+ function npmPackageChannelFromEnvironment(environment) {
1878
+ return environment === "staging" ? "staging" : "latest";
1879
+ }
1880
+ function cursorEnvironmentFromPackageExecutionMode(mode) {
1881
+ if (mode.kind === "local") return "local";
1882
+ return mode.channel === "staging" ? "staging" : "production";
1883
+ }
1884
+ function npmPackageChannelFromApiUrl(apiUrl) {
1885
+ if (!apiUrl) return "latest";
1886
+ const normalized = normalizeApiUrl(apiUrl);
1887
+ if (normalized === STAGING_API_URL || normalized.startsWith(STAGING_API_URL_PREFIX)) {
1888
+ return "staging";
1889
+ }
1890
+ if (normalized === PROD_API_URL) return "latest";
1891
+ return "latest";
1892
+ }
1893
+ function looksLikeLocalMonorepoCliPath(scriptPath) {
1894
+ const normalized = scriptPath.replace(/\\/g, "/");
1895
+ if (normalized.includes("/node_modules/@memoraone/mcp/")) return false;
1896
+ if (normalized.includes("/.npm/_npx/")) return false;
1897
+ if (normalized.includes("/_npx/")) return false;
1898
+ const base = path13.basename(normalized);
1899
+ if (base === "cli.ts" || base === "cli.cjs" || base === "memoraone-mcp.cjs") {
1900
+ if (normalized.includes("/packages/mcp/dist/") || normalized.includes("/packages/mcp/dist-bin/") || normalized.includes("/packages/mcp/src/")) {
1901
+ return true;
1902
+ }
1903
+ }
1904
+ return false;
1905
+ }
1906
+ function looksLikePublishedPackagePath(scriptPath) {
1907
+ const normalized = scriptPath.replace(/\\/g, "/");
1908
+ return normalized.includes("/node_modules/@memoraone/mcp/") || normalized.includes("/.npm/_npx/") || /\/_npx\//.test(normalized);
1909
+ }
1910
+ function channelFromEnv(env2) {
1911
+ const explicit = env2.MEMORAONE_NPM_CHANNEL?.trim().toLowerCase() || env2.npm_config_tag?.trim().toLowerCase();
1912
+ if (explicit === "staging") return "staging";
1913
+ if (explicit === "latest") return "latest";
1914
+ return void 0;
1915
+ }
1916
+ async function resolvePackageExecutionMode(options = {}) {
1917
+ if (options.executionMode) return options.executionMode;
1918
+ const env2 = options.env ?? process.env;
1919
+ const scriptPath = options.scriptPath !== void 0 ? options.scriptPath : process.argv[1] ? path13.resolve(process.argv[1]) : null;
1920
+ if (scriptPath && looksLikePublishedPackagePath(scriptPath)) {
1921
+ const channel2 = channelFromEnv(env2) ?? npmPackageChannelFromApiUrl(options.apiUrl);
1922
+ return { kind: "published", channel: channel2 };
1923
+ }
1924
+ if (scriptPath && looksLikeLocalMonorepoCliPath(scriptPath)) {
1925
+ return { kind: "local", cliPath: scriptPath };
1926
+ }
1927
+ if (options.cliPath) {
1928
+ return { kind: "local", cliPath: path13.resolve(options.cliPath) };
1929
+ }
1930
+ const resolveCli = options.resolveBuiltCliPath ?? resolveBuiltCliPathAsync;
1931
+ const builtCli = await resolveCli();
1932
+ if (builtCli && looksLikeLocalMonorepoCliPath(builtCli) && !(scriptPath && looksLikePublishedPackagePath(scriptPath))) {
1933
+ return { kind: "local", cliPath: builtCli };
1934
+ }
1935
+ const channel = channelFromEnv(env2) ?? npmPackageChannelFromApiUrl(options.apiUrl);
1936
+ return { kind: "published", channel };
1937
+ }
1938
+ function setupOptionsFromPackageExecutionMode(mode) {
1939
+ if (mode.kind === "local") {
1940
+ return {
1941
+ cursorEnvironment: "local",
1942
+ devMode: true,
1943
+ npmPackageChannel: "latest",
1944
+ cursorLocalCliPathOverride: mode.cliPath,
1945
+ cliPathOverride: mode.cliPath
1946
+ };
1947
+ }
1948
+ return {
1949
+ cursorEnvironment: cursorEnvironmentFromPackageExecutionMode(mode),
1950
+ devMode: false,
1951
+ npmPackageChannel: mode.channel,
1952
+ cursorLocalCliPathOverride: null,
1953
+ cliPathOverride: null
1954
+ };
1955
+ }
1956
+ function formatIdeSetupRepairHint(workspaceRoot, mode) {
1957
+ if (mode.kind === "local") {
1958
+ return `Repair with (no new connect code): node ${mode.cliPath} setup-ide-files --all --local --dev --force --workspace-root ${workspaceRoot}`;
1959
+ }
1960
+ const spec = memoraoneNpmPackageSpec(mode.channel);
1961
+ const stagingFlag = mode.channel === "staging" ? " --staging" : "";
1962
+ return `Repair with (no new connect code): npx -y ${spec} setup-ide-files --all${stagingFlag} --force --workspace-root ${workspaceRoot}`;
1963
+ }
1964
+
1790
1965
  // src/cursorGlobalMcpConfig.ts
1791
1966
  var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
1792
1967
  var MEMORAONE_PROD_API_URL = "https://api.memoraone.com";
1793
1968
  var MEMORAONE_LOCAL_API_URL = "http://localhost:3001";
1794
1969
  var MEMORAONE_STAGING_API_URL = "https://memora-api-staging-phbtrzocjq-uk.a.run.app";
1795
1970
  var MEMORAONE_STAGING_API_URL_PREFIX = "https://memora-api-staging-";
1796
- function normalizeApiUrl(url) {
1971
+ function normalizeApiUrl2(url) {
1797
1972
  return url.trim().replace(/\/+$/, "");
1798
1973
  }
1799
1974
  function resolveIdeApiUrl(options) {
1975
+ if (options.apiUrl) return normalizeApiUrl2(options.apiUrl);
1800
1976
  if (options.environment === "staging") return MEMORAONE_STAGING_API_URL;
1801
1977
  if (options.environment === "production") return MEMORAONE_PROD_API_URL;
1802
- if (options.apiUrl) return normalizeApiUrl(options.apiUrl);
1803
1978
  return MEMORAONE_LOCAL_API_URL;
1804
1979
  }
1805
1980
  function buildMemoraoneCursorMcpServer(options) {
@@ -1811,7 +1986,7 @@ function buildMemoraoneCursorMcpServer(options) {
1811
1986
  MEMORAONE_IDE_TYPE: "cursor"
1812
1987
  };
1813
1988
  if (options.workspaceRoot !== void 0) {
1814
- env2[MEMORAONE_WORKSPACE_ROOT_ENV] = path12.resolve(options.workspaceRoot);
1989
+ env2[MEMORAONE_WORKSPACE_ROOT_ENV] = path14.resolve(options.workspaceRoot);
1815
1990
  }
1816
1991
  if (options.environment === "local") {
1817
1992
  if (!options.cliPath) {
@@ -1826,15 +2001,16 @@ function buildMemoraoneCursorMcpServer(options) {
1826
2001
  if (!options.npxPath) {
1827
2002
  throw new Error("[setup-ide-files] Cursor MCP config requires a resolved npx path.");
1828
2003
  }
2004
+ const channel = options.npmPackageChannel ?? npmPackageChannelFromEnvironment(options.environment);
1829
2005
  return {
1830
2006
  command: options.npxPath,
1831
- args: ["-y", "@memoraone/mcp@latest"],
2007
+ args: ["-y", memoraoneNpmPackageSpec(channel)],
1832
2008
  env: env2
1833
2009
  };
1834
2010
  }
1835
- async function pathExists(filePath) {
2011
+ async function pathExists2(filePath) {
1836
2012
  try {
1837
- await fs9.access(filePath);
2013
+ await fs10.access(filePath);
1838
2014
  return true;
1839
2015
  } catch {
1840
2016
  return false;
@@ -1844,17 +2020,17 @@ function stripLeadingLineComments(text) {
1844
2020
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
1845
2021
  }
1846
2022
  function getKnownCursorGlobalMcpConfigCandidates(homeDir) {
1847
- return [path12.join(homeDir, ".cursor", "mcp.json")];
2023
+ return [path14.join(homeDir, ".cursor", "mcp.json")];
1848
2024
  }
1849
2025
  async function detectCursorGlobalMcpConfig(options) {
1850
2026
  if (options?.explicitPath) {
1851
- return { ok: true, path: options.explicitPath, detectedExisting: await pathExists(options.explicitPath) };
2027
+ return { ok: true, path: options.explicitPath, detectedExisting: await pathExists2(options.explicitPath) };
1852
2028
  }
1853
2029
  const homeDir = options?.homeDir ?? os4.homedir();
1854
2030
  const candidates = getKnownCursorGlobalMcpConfigCandidates(homeDir);
1855
2031
  const existing = [];
1856
2032
  for (const candidate of candidates) {
1857
- if (await pathExists(candidate)) existing.push(candidate);
2033
+ if (await pathExists2(candidate)) existing.push(candidate);
1858
2034
  }
1859
2035
  if (existing.length > 1) {
1860
2036
  return {
@@ -1882,10 +2058,10 @@ function formatBackupTimestamp(d = /* @__PURE__ */ new Date()) {
1882
2058
  }
1883
2059
  async function isWorkingNpx(npxPath) {
1884
2060
  try {
1885
- if (!await pathExists(npxPath)) return false;
2061
+ if (!await pathExists2(npxPath)) return false;
1886
2062
  if (process.platform !== "win32") {
1887
2063
  try {
1888
- await fs9.access(npxPath, fs9.constants.X_OK);
2064
+ await fs10.access(npxPath, fs10.constants.X_OK);
1889
2065
  } catch {
1890
2066
  return false;
1891
2067
  }
@@ -1907,7 +2083,7 @@ async function resolveNpxPath() {
1907
2083
  const pathSep = process.platform === "win32" ? ";" : ":";
1908
2084
  for (const dir of (process.env.PATH ?? "").split(pathSep)) {
1909
2085
  if (!dir) continue;
1910
- candidates.push(path12.join(dir, npxName));
2086
+ candidates.push(path14.join(dir, npxName));
1911
2087
  }
1912
2088
  try {
1913
2089
  const lookupCmd = process.platform === "win32" ? "where" : "which";
@@ -1918,7 +2094,7 @@ async function resolveNpxPath() {
1918
2094
  }
1919
2095
  const seen = /* @__PURE__ */ new Set();
1920
2096
  for (const candidate of candidates) {
1921
- const abs = path12.isAbsolute(candidate) ? candidate : path12.resolve(candidate);
2097
+ const abs = path14.isAbsolute(candidate) ? candidate : path14.resolve(candidate);
1922
2098
  const key = process.platform === "win32" ? abs.toLowerCase() : abs;
1923
2099
  if (seen.has(key)) continue;
1924
2100
  seen.add(key);
@@ -1930,12 +2106,14 @@ function mergeCursorRepoMcpConfigObject(existing, writeOptions) {
1930
2106
  const environment = writeOptions.environment ?? "production";
1931
2107
  const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
1932
2108
  const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
2109
+ delete mcpServers.memoraone;
1933
2110
  mcpServers.memoraone = buildMemoraoneCursorMcpServer({
1934
2111
  environment,
1935
2112
  npxPath: writeOptions.npxPath,
1936
2113
  cliPath: writeOptions.cliPath,
1937
2114
  workspaceRoot: writeOptions.repoRoot,
1938
- apiUrl: writeOptions.apiUrl
2115
+ apiUrl: writeOptions.apiUrl,
2116
+ npmPackageChannel: writeOptions.npmPackageChannel
1939
2117
  });
1940
2118
  return { ...base, mcpServers };
1941
2119
  }
@@ -1949,7 +2127,7 @@ function isManagedMemoraoneCursorServer(server) {
1949
2127
  if (!server || typeof server !== "object") return false;
1950
2128
  const s = server;
1951
2129
  if (!Array.isArray(s.args) || s.args.length !== 2) return false;
1952
- if (s.args[0] !== "-y" || s.args[1] !== "@memoraone/mcp@latest") return false;
2130
+ if (s.args[0] !== "-y" || !isMemoraoneNpmPackageSpec(s.args[1])) return false;
1953
2131
  const env2 = s.env;
1954
2132
  if (!env2 || typeof env2 !== "object") return false;
1955
2133
  return memoraoneEnvMatchesManagedCleanupShape(env2);
@@ -1964,11 +2142,11 @@ function memoraoneEnvMatchesManagedCleanupShape(env2) {
1964
2142
  return env2.MEMORAONE_IDE_TYPE === "cursor" && isMemoraoneManagedApiUrl(env2.MEMORAONE_API_URL);
1965
2143
  }
1966
2144
  function getCursorRepoMcpConfigPath(repoRoot) {
1967
- return path12.join(repoRoot, ".cursor", "mcp.json");
2145
+ return path14.join(repoRoot, ".cursor", "mcp.json");
1968
2146
  }
1969
2147
  async function readCursorMcpConfigObject(configPath) {
1970
2148
  try {
1971
- const raw = await fs9.readFile(configPath, "utf8");
2149
+ const raw = await fs10.readFile(configPath, "utf8");
1972
2150
  return JSON.parse(stripLeadingLineComments(raw));
1973
2151
  } catch (err) {
1974
2152
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
@@ -1986,21 +2164,21 @@ async function removeMemoraoneFromCursorGlobalConfig(options) {
1986
2164
  return { changed: true, backupPath: `${configPath}.backup-<timestamp>` };
1987
2165
  }
1988
2166
  const backupPath = `${configPath}.backup-${formatBackupTimestamp()}`;
1989
- await fs9.copyFile(configPath, backupPath);
2167
+ await fs10.copyFile(configPath, backupPath);
1990
2168
  const mcpServers = typeof parsed2.mcpServers === "object" && parsed2.mcpServers !== null && !Array.isArray(parsed2.mcpServers) ? { ...parsed2.mcpServers } : {};
1991
2169
  delete mcpServers.memoraone;
1992
2170
  const hasOtherServers = Object.keys(mcpServers).length > 0;
1993
2171
  if (!hasOtherServers) {
1994
- await fs9.unlink(configPath);
2172
+ await fs10.unlink(configPath);
1995
2173
  return { changed: true, backupPath };
1996
2174
  }
1997
2175
  const next = { ...parsed2, mcpServers };
1998
- await fs9.mkdir(path12.dirname(configPath), { recursive: true });
1999
- await fs9.writeFile(configPath, JSON.stringify(next, null, 2) + "\n", "utf8");
2176
+ await fs10.mkdir(path14.dirname(configPath), { recursive: true });
2177
+ await fs10.writeFile(configPath, JSON.stringify(next, null, 2) + "\n", "utf8");
2000
2178
  return { changed: true, backupPath };
2001
2179
  }
2002
2180
  async function auditCursorMcpConfig(options) {
2003
- const repoRoot = path12.resolve(options?.repoRoot ?? process.cwd());
2181
+ const repoRoot = path14.resolve(options?.repoRoot ?? process.cwd());
2004
2182
  const repoConfigPath = getCursorRepoMcpConfigPath(repoRoot);
2005
2183
  const globalDetection = await detectCursorGlobalMcpConfig({
2006
2184
  homeDir: options?.homeDir,
@@ -2177,7 +2355,7 @@ async function defaultListSocketPaths(projectId) {
2177
2355
  const baseDir = getMcpBaseDir();
2178
2356
  let entries;
2179
2357
  try {
2180
- entries = await fs10.readdir(baseDir);
2358
+ entries = await fs11.readdir(baseDir);
2181
2359
  } catch (err) {
2182
2360
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
2183
2361
  if (code === "ENOENT") {
@@ -2190,7 +2368,7 @@ async function defaultListSocketPaths(projectId) {
2190
2368
  if (!name.endsWith(".sock") || !isMemoraoneSocketFilename(name)) {
2191
2369
  continue;
2192
2370
  }
2193
- const socketPath = path13.join(baseDir, name);
2371
+ const socketPath = path15.join(baseDir, name);
2194
2372
  if (projectId === null) {
2195
2373
  paths.push(socketPath);
2196
2374
  continue;
@@ -2210,11 +2388,11 @@ async function defaultListSocketPaths(projectId) {
2210
2388
  return paths.sort();
2211
2389
  }
2212
2390
  async function defaultListSocketPathsForWorkspaceRoot(workspaceRoot) {
2213
- const resolvedRoot = path13.resolve(workspaceRoot);
2391
+ const resolvedRoot = path15.resolve(workspaceRoot);
2214
2392
  const baseDir = getMcpBaseDir();
2215
2393
  let entries;
2216
2394
  try {
2217
- entries = await fs10.readdir(baseDir);
2395
+ entries = await fs11.readdir(baseDir);
2218
2396
  } catch (err) {
2219
2397
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
2220
2398
  if (code === "ENOENT") {
@@ -2227,10 +2405,10 @@ async function defaultListSocketPathsForWorkspaceRoot(workspaceRoot) {
2227
2405
  if (!name.endsWith(".sock") || !isHashSocketFilename(name)) {
2228
2406
  continue;
2229
2407
  }
2230
- const socketPath = path13.join(baseDir, name);
2408
+ const socketPath = path15.join(baseDir, name);
2231
2409
  const record = readBindingSidecarRecord(socketPath);
2232
2410
  if (!record?.workspaceRoot) continue;
2233
- if (path13.resolve(record.workspaceRoot) === resolvedRoot) {
2411
+ if (path15.resolve(record.workspaceRoot) === resolvedRoot) {
2234
2412
  paths.push(socketPath);
2235
2413
  }
2236
2414
  }
@@ -2239,21 +2417,21 @@ async function defaultListSocketPathsForWorkspaceRoot(workspaceRoot) {
2239
2417
  async function filterSocketPathsByIdeForCleanup(socketPaths, projectId, ide, workspaceRoot) {
2240
2418
  if (ide === void 0) return socketPaths;
2241
2419
  const normalizedProjectId = projectId.trim().toLowerCase();
2242
- const resolvedRoot = workspaceRoot ? path13.resolve(workspaceRoot) : null;
2420
+ const resolvedRoot = workspaceRoot ? path15.resolve(workspaceRoot) : null;
2243
2421
  const filtered = [];
2244
2422
  for (const socketPath of socketPaths) {
2245
- const basename8 = path13.basename(socketPath);
2246
- if (isLegacySocketFilename(basename8)) {
2247
- if (isSocketFilenameForProjectAndIde(basename8, normalizedProjectId, ide)) {
2423
+ const basename11 = path15.basename(socketPath);
2424
+ if (isLegacySocketFilename(basename11)) {
2425
+ if (isSocketFilenameForProjectAndIde(basename11, normalizedProjectId, ide)) {
2248
2426
  filtered.push(socketPath);
2249
2427
  }
2250
2428
  continue;
2251
2429
  }
2252
- if (isHashSocketFilename(basename8)) {
2430
+ if (isHashSocketFilename(basename11)) {
2253
2431
  const record = readBindingSidecarRecord(socketPath);
2254
2432
  if (!record || record.ideType !== ide) continue;
2255
2433
  const sameProject = record.projectId.trim().toLowerCase() === normalizedProjectId;
2256
- const sameWorkspace = resolvedRoot !== null && path13.resolve(record.workspaceRoot) === resolvedRoot;
2434
+ const sameWorkspace = resolvedRoot !== null && path15.resolve(record.workspaceRoot) === resolvedRoot;
2257
2435
  if (sameProject || sameWorkspace) {
2258
2436
  filtered.push(socketPath);
2259
2437
  }
@@ -2265,9 +2443,9 @@ async function defaultKillProcess(pid) {
2265
2443
  process.kill(pid, "SIGTERM");
2266
2444
  }
2267
2445
  async function defaultRemoveSocket(socketPath) {
2268
- await fs10.unlink(socketPath);
2446
+ await fs11.unlink(socketPath);
2269
2447
  try {
2270
- await fs10.unlink(bindingSidecarPath(socketPath));
2448
+ await fs11.unlink(bindingSidecarPath(socketPath));
2271
2449
  } catch {
2272
2450
  }
2273
2451
  }
@@ -2285,7 +2463,7 @@ async function defaultConfirm(message) {
2285
2463
  }
2286
2464
  async function resolveCleanupTarget(cwd2) {
2287
2465
  try {
2288
- const binding = await resolveAuthoritativeBinding([path13.resolve(cwd2)]);
2466
+ const binding = await resolveAuthoritativeBinding([path15.resolve(cwd2)]);
2289
2467
  return {
2290
2468
  workspaceRoot: binding.workspaceRoot,
2291
2469
  repositoryBindingId: binding.repositoryBindingId,
@@ -2463,7 +2641,7 @@ async function runCleanup(opts) {
2463
2641
  projectIds.add(proc.projectId);
2464
2642
  }
2465
2643
  for (const socketPath of socketPaths) {
2466
- const id = extractProjectIdFromSocketFilename(path13.basename(socketPath));
2644
+ const id = extractProjectIdFromSocketFilename(path15.basename(socketPath));
2467
2645
  if (id) {
2468
2646
  projectIds.add(id);
2469
2647
  continue;
@@ -2649,9 +2827,9 @@ function summarizeJsonRpcMethod(line) {
2649
2827
  }
2650
2828
  }
2651
2829
  function connectWithRetry(socketPath, log, maxRetries, retryDelayMs, connect2) {
2652
- return new Promise((resolve16, reject) => {
2830
+ return new Promise((resolve17, reject) => {
2653
2831
  const tryConnect = (attempt) => {
2654
- connect2(socketPath).then(resolve16).catch((err) => {
2832
+ connect2(socketPath).then(resolve17).catch((err) => {
2655
2833
  if (attempt >= maxRetries) {
2656
2834
  reject(err);
2657
2835
  return;
@@ -2767,8 +2945,8 @@ var BridgeDaemonRouter = class {
2767
2945
  this.maxRetries = options.maxRetries ?? 5;
2768
2946
  this.retryDelayMs = options.retryDelayMs ?? 200;
2769
2947
  this.lineReader = options.lineReader ?? null;
2770
- this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve16, reject) => {
2771
- const socket = net.connect(socketPath, () => resolve16(socket));
2948
+ this.connectImpl = options.connect ?? ((socketPath) => new Promise((resolve17, reject) => {
2949
+ const socket = net.connect(socketPath, () => resolve17(socket));
2772
2950
  socket.on("error", reject);
2773
2951
  }));
2774
2952
  this.spawnDaemonImpl = options.spawnDaemon ?? (async (binding) => {
@@ -3032,12 +3210,14 @@ async function runBridgeProxy(options) {
3032
3210
  // src/setupIdeFiles.ts
3033
3211
  var fs13 = __toESM(require("fs/promises"), 1);
3034
3212
  var os6 = __toESM(require("os"), 1);
3035
- var path16 = __toESM(require("path"), 1);
3213
+ var path17 = __toESM(require("path"), 1);
3214
+ var import_node_crypto5 = require("crypto");
3036
3215
 
3037
3216
  // src/jetbrainsMcpConfig.ts
3038
- var fs11 = __toESM(require("fs/promises"), 1);
3217
+ var fs12 = __toESM(require("fs/promises"), 1);
3039
3218
  var os5 = __toESM(require("os"), 1);
3040
- var path14 = __toESM(require("path"), 1);
3219
+ var path16 = __toESM(require("path"), 1);
3220
+ var import_node_crypto4 = require("crypto");
3041
3221
  var import_node_child_process5 = require("child_process");
3042
3222
 
3043
3223
  // src/configUtils.ts
@@ -3059,7 +3239,6 @@ function resolveApiUrl(env2) {
3059
3239
  }
3060
3240
 
3061
3241
  // src/jetbrainsMcpConfig.ts
3062
- var PROD_API_URL = "https://api.memoraone.com";
3063
3242
  var JETBRAINS_DEBUG_ENV_VARS = [
3064
3243
  "MEMORAONE_DEBUG_INIT",
3065
3244
  "MEMORAONE_DEBUG_MINIMAL_TOOLS",
@@ -3069,9 +3248,9 @@ var JETBRAINS_DEBUG_ENV_VARS = [
3069
3248
  function stripLeadingLineComments2(text) {
3070
3249
  return text.split("\n").filter((line) => !/^\s*\/\//.test(line)).join("\n");
3071
3250
  }
3072
- async function pathExists2(filePath) {
3251
+ async function pathExists3(filePath) {
3073
3252
  try {
3074
- await fs11.access(filePath);
3253
+ await fs12.access(filePath);
3075
3254
  return true;
3076
3255
  } catch {
3077
3256
  return false;
@@ -3082,12 +3261,12 @@ function formatJetBrainsBackupTimestamp(d = /* @__PURE__ */ new Date()) {
3082
3261
  return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
3083
3262
  }
3084
3263
  function getJetBrainsGlobalMcpConfigPath(homeDir) {
3085
- return path14.join(homeDir, ".ai", "mcp", "mcp.json");
3264
+ return path16.join(homeDir, ".ai", "mcp", "mcp.json");
3086
3265
  }
3087
3266
  function getJetBrainsProjectMcpConfigPaths(repoRoot) {
3088
3267
  return [
3089
- { kind: "project-ai", path: path14.join(repoRoot, ".ai", "mcp", "mcp.json") },
3090
- { kind: "project-ij", path: path14.join(repoRoot, ".ij", "mcp", "mcp.json") }
3268
+ { kind: "project-ai", path: path16.join(repoRoot, ".ai", "mcp", "mcp.json") },
3269
+ { kind: "project-ij", path: path16.join(repoRoot, ".ij", "mcp", "mcp.json") }
3091
3270
  ];
3092
3271
  }
3093
3272
  function getKnownJetBrainsMcpConfigLocations(homeDir, repoRoot) {
@@ -3097,17 +3276,21 @@ function getKnownJetBrainsMcpConfigLocations(homeDir, repoRoot) {
3097
3276
  ];
3098
3277
  }
3099
3278
  async function isZeroByteConfigFile(filePath) {
3100
- if (!await pathExists2(filePath)) return false;
3101
- const stat4 = await fs11.stat(filePath);
3279
+ if (!await pathExists3(filePath)) return false;
3280
+ const stat4 = await fs12.stat(filePath);
3102
3281
  return stat4.size === 0;
3103
3282
  }
3104
3283
  function buildMemoraoneJetBrainsMcpServer(options) {
3284
+ const environment = options.environment ?? (options.devMode ? "local" : "production");
3105
3285
  const env2 = {
3106
- MEMORAONE_API_URL: options.devMode ? options.apiUrl ? normalizeApiUrl(options.apiUrl) : DEV_API_URL : PROD_API_URL,
3286
+ MEMORAONE_API_URL: resolveIdeApiUrl({
3287
+ environment,
3288
+ apiUrl: options.apiUrl ?? (environment === "local" ? DEV_API_URL : void 0)
3289
+ }),
3107
3290
  MEMORAONE_IDE_TYPE: "jetbrains",
3108
- [MEMORAONE_WORKSPACE_ROOT_ENV]: path14.resolve(options.workspaceRoot)
3291
+ [MEMORAONE_WORKSPACE_ROOT_ENV]: path16.resolve(options.workspaceRoot)
3109
3292
  };
3110
- if (options.devMode) {
3293
+ if (environment === "local" || options.devMode) {
3111
3294
  env2.MEMORAONE_DEV_MODE = "1";
3112
3295
  }
3113
3296
  if ("MEMORAONE_M1_PATH" in env2 || "MEMORAONE_API_KEY" in env2) {
@@ -3122,9 +3305,28 @@ function buildMemoraoneJetBrainsMcpServer(options) {
3122
3305
  function mergeJetBrainsMcpConfigObject(existing, memoraone) {
3123
3306
  const base = existing && typeof existing === "object" ? { ...existing } : { mcpServers: {} };
3124
3307
  const mcpServers = typeof base.mcpServers === "object" && base.mcpServers !== null && !Array.isArray(base.mcpServers) ? { ...base.mcpServers } : {};
3308
+ delete mcpServers.memoraone;
3125
3309
  mcpServers.memoraone = memoraone;
3126
3310
  return { ...base, mcpServers };
3127
3311
  }
3312
+ async function writeJetBrainsMcpJsonAtomic(filePath, content) {
3313
+ const dir = path16.dirname(filePath);
3314
+ await fs12.mkdir(dir, { recursive: true });
3315
+ const tmpPath = path16.join(
3316
+ dir,
3317
+ `.${path16.basename(filePath)}.${process.pid}.${(0, import_node_crypto4.randomBytes)(8).toString("hex")}.tmp`
3318
+ );
3319
+ try {
3320
+ await fs12.writeFile(tmpPath, content, "utf8");
3321
+ await fs12.rename(tmpPath, filePath);
3322
+ } catch (err) {
3323
+ try {
3324
+ await fs12.unlink(tmpPath);
3325
+ } catch {
3326
+ }
3327
+ throw err;
3328
+ }
3329
+ }
3128
3330
  function memoraoneServerMatches(server, expected) {
3129
3331
  if (!server || typeof server !== "object") return false;
3130
3332
  const s = server;
@@ -3160,13 +3362,13 @@ function validateJetBrainsMcpConfig(parsed2, expected) {
3160
3362
  }
3161
3363
  }
3162
3364
  async function readJsonConfig(filePath) {
3163
- const raw = await fs11.readFile(filePath, "utf8");
3365
+ const raw = await fs12.readFile(filePath, "utf8");
3164
3366
  if (raw.trim() === "") return null;
3165
3367
  return JSON.parse(stripLeadingLineComments2(raw));
3166
3368
  }
3167
3369
  async function backupConfigFile(filePath) {
3168
3370
  const backupPath = `${filePath}.bak-${formatJetBrainsBackupTimestamp()}`;
3169
- await fs11.copyFile(filePath, backupPath);
3371
+ await fs12.copyFile(filePath, backupPath);
3170
3372
  return backupPath;
3171
3373
  }
3172
3374
  async function repairZeroByteConfigFile(filePath, dryRun) {
@@ -3177,7 +3379,7 @@ async function repairZeroByteConfigFile(filePath, dryRun) {
3177
3379
  return { repaired: true, backupPath: `${filePath}.bak-<timestamp>` };
3178
3380
  }
3179
3381
  const backupPath = await backupConfigFile(filePath);
3180
- await fs11.unlink(filePath);
3382
+ await fs12.unlink(filePath);
3181
3383
  return { repaired: true, backupPath };
3182
3384
  }
3183
3385
  function configHasMemoraone(parsed2) {
@@ -3188,7 +3390,7 @@ function configHasMemoraone(parsed2) {
3188
3390
  }
3189
3391
  async function removeMemoraoneFromProjectConfig(options) {
3190
3392
  const { configPath, dryRun } = options;
3191
- if (!await pathExists2(configPath)) {
3393
+ if (!await pathExists3(configPath)) {
3192
3394
  return { changed: false };
3193
3395
  }
3194
3396
  let parsed2 = null;
@@ -3208,30 +3410,31 @@ async function removeMemoraoneFromProjectConfig(options) {
3208
3410
  delete mcpServers.memoraone;
3209
3411
  const hasOtherServers = Object.keys(mcpServers).length > 0;
3210
3412
  if (!hasOtherServers) {
3211
- await fs11.unlink(configPath);
3413
+ await fs12.unlink(configPath);
3212
3414
  return { changed: true, backupPath };
3213
3415
  }
3214
3416
  const next = { ...parsed2, mcpServers };
3215
- await fs11.mkdir(path14.dirname(configPath), { recursive: true });
3216
- await fs11.writeFile(configPath, JSON.stringify(next, null, 2) + "\n", "utf8");
3417
+ await fs12.mkdir(path16.dirname(configPath), { recursive: true });
3418
+ await fs12.writeFile(configPath, JSON.stringify(next, null, 2) + "\n", "utf8");
3217
3419
  return { changed: true, backupPath };
3218
3420
  }
3219
3421
  async function resolveLocalCliPathAsync() {
3220
- const here = process.argv[1] ? path14.dirname(path14.resolve(process.argv[1])) : process.cwd();
3422
+ const here = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
3221
3423
  const candidates = [
3222
- path14.join(here, "cli.cjs"),
3223
- path14.join(here, "..", "dist", "cli.cjs"),
3224
- path14.join(here, "..", "..", "dist", "cli.cjs")
3424
+ path16.join(here, "cli.cjs"),
3425
+ path16.join(here, "..", "dist", "cli.cjs"),
3426
+ path16.join(here, "..", "..", "dist", "cli.cjs")
3225
3427
  ];
3226
3428
  for (const candidate of candidates) {
3227
- if (await pathExists2(candidate)) {
3228
- return path14.resolve(candidate);
3429
+ if (await pathExists3(candidate)) {
3430
+ return path16.resolve(candidate);
3229
3431
  }
3230
3432
  }
3231
3433
  return null;
3232
3434
  }
3233
3435
  async function buildJetBrainsMemoraoneServer(options) {
3234
- if (options.devMode) {
3436
+ const environment = options.environment ?? (options.devMode ? "local" : "production");
3437
+ if (environment === "local" || options.devMode) {
3235
3438
  let cliPath = options.cliPathOverride;
3236
3439
  if (cliPath === void 0) {
3237
3440
  cliPath = await resolveLocalCliPathAsync();
@@ -3245,6 +3448,7 @@ async function buildJetBrainsMemoraoneServer(options) {
3245
3448
  command: process.execPath,
3246
3449
  args: [cliPath],
3247
3450
  workspaceRoot: options.workspaceRoot,
3451
+ environment: "local",
3248
3452
  devMode: true,
3249
3453
  apiUrl: options.apiUrl
3250
3454
  });
@@ -3258,17 +3462,20 @@ async function buildJetBrainsMemoraoneServer(options) {
3258
3462
  "[setup-ide-files] Could not resolve a working npx executable. Install Node.js/npm or ensure npx is on PATH before configuring JetBrains MCP."
3259
3463
  );
3260
3464
  }
3465
+ const channel = options.npmPackageChannel ?? npmPackageChannelFromEnvironment(environment);
3261
3466
  return buildMemoraoneJetBrainsMcpServer({
3262
3467
  command: npxPath,
3263
- args: ["-y", "@memoraone/mcp@latest"],
3468
+ args: ["-y", memoraoneNpmPackageSpec(channel)],
3264
3469
  workspaceRoot: options.workspaceRoot,
3265
- devMode: false
3470
+ environment,
3471
+ devMode: false,
3472
+ apiUrl: options.apiUrl
3266
3473
  });
3267
3474
  }
3268
3475
  async function verifyJetBrainsMcpHandshake(options) {
3269
3476
  const timeoutMs = options.timeoutMs ?? 15e3;
3270
3477
  const { server } = options;
3271
- return new Promise((resolve16) => {
3478
+ return new Promise((resolve17) => {
3272
3479
  let settled = false;
3273
3480
  const finish = (ok, detail) => {
3274
3481
  if (settled) return;
@@ -3278,7 +3485,7 @@ async function verifyJetBrainsMcpHandshake(options) {
3278
3485
  child.kill();
3279
3486
  } catch {
3280
3487
  }
3281
- resolve16({ ok, detail });
3488
+ resolve17({ ok, detail });
3282
3489
  };
3283
3490
  const child = (0, import_node_child_process5.spawn)(server.command, [...server.args], {
3284
3491
  env: { ...process.env, ...server.env },
@@ -3347,11 +3554,11 @@ async function verifyJetBrainsMcpHandshake(options) {
3347
3554
  async function setupJetBrainsMcpConfig(options) {
3348
3555
  const homeDir = options.homeDir ?? os5.homedir();
3349
3556
  const globalPath = options.globalConfigPath ?? getJetBrainsGlobalMcpConfigPath(homeDir);
3350
- const workspaceRoot = path14.resolve(options.repoRoot);
3557
+ const workspaceRoot = path16.resolve(options.repoRoot);
3351
3558
  const repairActions = [];
3352
3559
  const allLocations = getKnownJetBrainsMcpConfigLocations(homeDir, options.repoRoot);
3353
3560
  for (const location of allLocations) {
3354
- if (await pathExists2(location.path)) {
3561
+ if (await pathExists3(location.path)) {
3355
3562
  repairActions.push({ type: "found-config", location });
3356
3563
  }
3357
3564
  }
@@ -3368,6 +3575,8 @@ async function setupJetBrainsMcpConfig(options) {
3368
3575
  const memoraone = await buildJetBrainsMemoraoneServer({
3369
3576
  workspaceRoot,
3370
3577
  devMode: options.devMode,
3578
+ environment: options.environment,
3579
+ npmPackageChannel: options.npmPackageChannel,
3371
3580
  apiUrl: options.apiUrl,
3372
3581
  npxPathOverride: options.npxPathOverride,
3373
3582
  cliPathOverride: options.cliPathOverride
@@ -3388,24 +3597,15 @@ async function setupJetBrainsMcpConfig(options) {
3388
3597
  repairActions.push({ type: "removed-project-memoraone", path: location.path });
3389
3598
  }
3390
3599
  }
3391
- const existed = await pathExists2(globalPath);
3600
+ const existed = await pathExists3(globalPath);
3392
3601
  let existing = null;
3393
3602
  if (existed) {
3394
3603
  try {
3395
3604
  existing = await readJsonConfig(globalPath);
3396
3605
  } catch {
3397
- if (options.dryRun) {
3398
- existing = null;
3399
- } else {
3400
- const backupPath2 = await backupConfigFile(globalPath);
3401
- repairActions.push({
3402
- type: "repaired-zero-byte",
3403
- path: globalPath,
3404
- backupPath: backupPath2
3405
- });
3406
- await fs11.unlink(globalPath);
3407
- existing = null;
3408
- }
3606
+ throw new Error(
3607
+ `[setup-ide-files] Invalid JSON in shared JetBrains MCP config (file preserved, not modified): ${globalPath}. Fix or remove the file, then re-run setup-ide-files.`
3608
+ );
3409
3609
  }
3410
3610
  }
3411
3611
  const merged = mergeJetBrainsMcpConfigObject(existing, memoraone);
@@ -3426,9 +3626,8 @@ async function setupJetBrainsMcpConfig(options) {
3426
3626
  if (existed) {
3427
3627
  backupPath = await backupConfigFile(globalPath);
3428
3628
  }
3429
- await fs11.mkdir(path14.dirname(globalPath), { recursive: true });
3430
- await fs11.writeFile(globalPath, body, "utf8");
3431
- const verifyRaw = await fs11.readFile(globalPath, "utf8");
3629
+ await writeJetBrainsMcpJsonAtomic(globalPath, body);
3630
+ const verifyRaw = await fs12.readFile(globalPath, "utf8");
3432
3631
  const verifyParsed = JSON.parse(stripLeadingLineComments2(verifyRaw));
3433
3632
  validateJetBrainsMcpConfig(verifyParsed, memoraone);
3434
3633
  const outcome = existed ? "updated" : "created";
@@ -3483,77 +3682,6 @@ function logJetBrainsMcpCliSummary(info, dryRun) {
3483
3682
  );
3484
3683
  }
3485
3684
 
3486
- // src/resolveBuiltCliPath.ts
3487
- var fs12 = __toESM(require("fs/promises"), 1);
3488
- var path15 = __toESM(require("path"), 1);
3489
- var MONOREPO_CLI_REL = path15.join("packages", "mcp", "dist", "cli.cjs");
3490
- async function pathExists3(filePath) {
3491
- try {
3492
- await fs12.access(filePath);
3493
- return true;
3494
- } catch {
3495
- return false;
3496
- }
3497
- }
3498
- async function findMonorepoCliFrom(startDir) {
3499
- let current = path15.resolve(startDir);
3500
- const root = path15.parse(current).root;
3501
- while (true) {
3502
- const candidate = path15.join(current, MONOREPO_CLI_REL);
3503
- if (await pathExists3(candidate)) {
3504
- return path15.resolve(candidate);
3505
- }
3506
- if (current === root) break;
3507
- current = path15.dirname(current);
3508
- }
3509
- return null;
3510
- }
3511
- async function resolveFromRunningScript() {
3512
- if (!process.argv[1]) return null;
3513
- const script = path15.resolve(process.argv[1]);
3514
- const base = path15.basename(script);
3515
- if ((base === "cli.cjs" || base === "cli.ts" || base === "memoraone-mcp.cjs") && await pathExists3(script)) {
3516
- return script;
3517
- }
3518
- const here = path15.dirname(script);
3519
- const candidates = [
3520
- path15.join(here, "cli.cjs"),
3521
- path15.join(here, "..", "dist", "cli.cjs"),
3522
- path15.join(here, "..", "..", "dist", "cli.cjs")
3523
- ];
3524
- for (const candidate of candidates) {
3525
- if (await pathExists3(candidate)) {
3526
- return path15.resolve(candidate);
3527
- }
3528
- }
3529
- return null;
3530
- }
3531
- async function resolveBuiltCliPathAsync(options) {
3532
- const preferRunning = options?.preferRunningScript !== false;
3533
- if (preferRunning) {
3534
- const fromRunning = await resolveFromRunningScript();
3535
- if (fromRunning) return fromRunning;
3536
- }
3537
- const searchDirs = [];
3538
- if (options?.searchFrom !== void 0) {
3539
- const dirs = Array.isArray(options.searchFrom) ? options.searchFrom : [options.searchFrom];
3540
- searchDirs.push(...dirs);
3541
- }
3542
- searchDirs.push(process.cwd());
3543
- const seen = /* @__PURE__ */ new Set();
3544
- for (const dir of searchDirs) {
3545
- const key = path15.resolve(dir);
3546
- if (seen.has(key)) continue;
3547
- seen.add(key);
3548
- const found = await findMonorepoCliFrom(key);
3549
- if (found) return found;
3550
- }
3551
- if (!preferRunning) {
3552
- return resolveFromRunningScript();
3553
- }
3554
- return null;
3555
- }
3556
-
3557
3685
  // src/openCursorMcpSettings.ts
3558
3686
  var import_node_child_process6 = require("child_process");
3559
3687
  var readline4 = __toESM(require("readline/promises"), 1);
@@ -3795,7 +3923,7 @@ function buildMemoraoneMcpServer(ideType, options = {}) {
3795
3923
  throw new Error("[setup-ide-files] Local VS Code MCP config requires a built CLI path.");
3796
3924
  }
3797
3925
  if (options.workspaceRoot !== void 0) {
3798
- env2[MEMORAONE_WORKSPACE_ROOT_ENV] = path16.resolve(options.workspaceRoot);
3926
+ env2[MEMORAONE_WORKSPACE_ROOT_ENV] = path17.resolve(options.workspaceRoot);
3799
3927
  }
3800
3928
  return {
3801
3929
  command: "node",
@@ -3803,16 +3931,17 @@ function buildMemoraoneMcpServer(ideType, options = {}) {
3803
3931
  env: env2
3804
3932
  };
3805
3933
  }
3934
+ const channel = options.npmPackageChannel ?? npmPackageChannelFromEnvironment(environment);
3806
3935
  return {
3807
3936
  command: options.command ?? "npx",
3808
- args: ["-y", "@memoraone/mcp@latest"],
3937
+ args: ["-y", memoraoneNpmPackageSpec(channel)],
3809
3938
  env: env2
3810
3939
  };
3811
3940
  }
3812
3941
  function assertUnderRepoRoot(repoRoot, absPath) {
3813
- const normRoot = path16.resolve(repoRoot) + path16.sep;
3814
- const normPath = path16.resolve(absPath);
3815
- if (normPath !== path16.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
3942
+ const normRoot = path17.resolve(repoRoot) + path17.sep;
3943
+ const normPath = path17.resolve(absPath);
3944
+ if (normPath !== path17.resolve(repoRoot) && !normPath.startsWith(normRoot)) {
3816
3945
  throw new Error(`[setup-ide-files] Refusing to write outside repo root: ${absPath}`);
3817
3946
  }
3818
3947
  }
@@ -3828,18 +3957,18 @@ async function ensureGitignoreMemoraone(_repoRoot, _opts) {
3828
3957
  return "skipped";
3829
3958
  }
3830
3959
  async function findRepoRoot(startDir) {
3831
- let current = path16.resolve(startDir);
3832
- const root = path16.parse(current).root;
3960
+ let current = path17.resolve(startDir);
3961
+ const root = path17.parse(current).root;
3833
3962
  while (true) {
3834
- const gitPath = path16.join(current, ".git");
3835
- const m1Path = path16.join(current, "memoraone.m1");
3963
+ const gitPath = path17.join(current, ".git");
3964
+ const m1Path = path17.join(current, "memoraone.m1");
3836
3965
  if (await pathExists4(gitPath) || await pathExists4(m1Path)) {
3837
3966
  return current;
3838
3967
  }
3839
3968
  if (current === root) {
3840
3969
  return null;
3841
3970
  }
3842
- current = path16.dirname(current);
3971
+ current = path17.dirname(current);
3843
3972
  }
3844
3973
  }
3845
3974
  function stripLeadingLineComments3(text) {
@@ -3888,16 +4017,44 @@ function mcpJsonHeader() {
3888
4017
  function buildVscodeMcpJsonBody(existing, options = {}) {
3889
4018
  const base = existing && typeof existing === "object" ? { ...existing } : { servers: {} };
3890
4019
  const servers = typeof base.servers === "object" && base.servers !== null && !Array.isArray(base.servers) ? { ...base.servers } : {};
4020
+ delete servers.memoraone;
3891
4021
  servers.memoraone = buildMemoraoneMcpServer("copilot-vscode", options);
3892
4022
  const merged = { ...base, servers };
3893
4023
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
3894
4024
  }
4025
+ async function writeSharedMcpJsonAtomic(filePath, content) {
4026
+ const dir = path17.dirname(filePath);
4027
+ await fs13.mkdir(dir, { recursive: true });
4028
+ const tmpPath = path17.join(
4029
+ dir,
4030
+ `.${path17.basename(filePath)}.${process.pid}.${(0, import_node_crypto5.randomBytes)(8).toString("hex")}.tmp`
4031
+ );
4032
+ try {
4033
+ await fs13.writeFile(tmpPath, content, "utf8");
4034
+ await fs13.rename(tmpPath, filePath);
4035
+ } catch (err) {
4036
+ try {
4037
+ await fs13.unlink(tmpPath);
4038
+ } catch {
4039
+ }
4040
+ throw err;
4041
+ }
4042
+ }
4043
+ var SharedMcpJsonParseError = class extends Error {
4044
+ constructor(configPath) {
4045
+ super(
4046
+ `[setup-ide-files] Invalid JSON in shared MCP config (file preserved, not modified): ${configPath}. Fix or remove the file, then re-run setup-ide-files.`
4047
+ );
4048
+ this.name = "SharedMcpJsonParseError";
4049
+ this.configPath = configPath;
4050
+ }
4051
+ };
3895
4052
  function buildCursorMcpJsonBody(existing, writeOptions) {
3896
4053
  const merged = mergeCursorRepoMcpConfigObject(existing, writeOptions);
3897
4054
  return mcpJsonHeader() + JSON.stringify(merged, null, 2) + "\n";
3898
4055
  }
3899
4056
  async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
3900
- const abs = path16.join(repoRoot, relPath);
4057
+ const abs = path17.join(repoRoot, relPath);
3901
4058
  assertUnderRepoRoot(repoRoot, abs);
3902
4059
  let prior = "";
3903
4060
  let existed = false;
@@ -3909,25 +4066,25 @@ async function writeManagedMarkdown(repoRoot, relPath, fullContent, opts) {
3909
4066
  }
3910
4067
  if (!existed) {
3911
4068
  if (opts.dryRun) return "created";
3912
- await fs13.mkdir(path16.dirname(abs), { recursive: true });
4069
+ await fs13.mkdir(path17.dirname(abs), { recursive: true });
3913
4070
  await fs13.writeFile(abs, fullContent, "utf8");
3914
4071
  return "created";
3915
4072
  }
3916
4073
  if (prior.includes(MANAGED_MARKER)) {
3917
4074
  if (prior === fullContent) return "skipped";
3918
4075
  if (opts.dryRun) return "updated";
3919
- await fs13.mkdir(path16.dirname(abs), { recursive: true });
4076
+ await fs13.mkdir(path17.dirname(abs), { recursive: true });
3920
4077
  await fs13.writeFile(abs, fullContent, "utf8");
3921
4078
  return "updated";
3922
4079
  }
3923
4080
  if (!opts.force) return "skipped-untracked";
3924
4081
  if (opts.dryRun) return "updated";
3925
- await fs13.mkdir(path16.dirname(abs), { recursive: true });
4082
+ await fs13.mkdir(path17.dirname(abs), { recursive: true });
3926
4083
  await fs13.writeFile(abs, fullContent, "utf8");
3927
4084
  return "updated";
3928
4085
  }
3929
4086
  async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
3930
- const abs = path16.join(repoRoot, relPath);
4087
+ const abs = path17.join(repoRoot, relPath);
3931
4088
  assertUnderRepoRoot(repoRoot, abs);
3932
4089
  let raw = "";
3933
4090
  let existed = false;
@@ -3940,24 +4097,24 @@ async function writeIdeMcpJson(repoRoot, relPath, buildBody, opts) {
3940
4097
  if (!existed) {
3941
4098
  const body = buildBody(null);
3942
4099
  if (opts.dryRun) return "created";
3943
- await fs13.mkdir(path16.dirname(abs), { recursive: true });
3944
- await fs13.writeFile(abs, body, "utf8");
4100
+ await writeSharedMcpJsonAtomic(abs, body);
3945
4101
  return "created";
3946
4102
  }
3947
4103
  const managed = raw.includes(MANAGED_MARKER);
3948
4104
  if (!managed && !opts.force) return "skipped-untracked";
3949
- let parsed2 = null;
4105
+ let parsed2;
3950
4106
  try {
3951
4107
  parsed2 = JSON.parse(stripLeadingLineComments3(raw));
3952
4108
  } catch {
3953
- parsed2 = null;
4109
+ throw new SharedMcpJsonParseError(abs);
4110
+ }
4111
+ if (!parsed2 || typeof parsed2 !== "object" || Array.isArray(parsed2)) {
4112
+ throw new SharedMcpJsonParseError(abs);
3954
4113
  }
3955
- if (!parsed2 && !opts.force) return "skipped-untracked";
3956
4114
  const next = buildBody(parsed2);
3957
4115
  if (managed && next === raw) return "skipped";
3958
4116
  if (opts.dryRun) return "updated";
3959
- await fs13.mkdir(path16.dirname(abs), { recursive: true });
3960
- await fs13.writeFile(abs, next, "utf8");
4117
+ await writeSharedMcpJsonAtomic(abs, next);
3961
4118
  return "updated";
3962
4119
  }
3963
4120
  function parseSetupIdeFlags(argv) {
@@ -4052,18 +4209,17 @@ function parseSetupIdeFlags(argv) {
4052
4209
  flagError
4053
4210
  };
4054
4211
  }
4055
- async function resolveSetupApiUrl(o, repoRoot, localOrDev) {
4056
- if (o.apiUrl) return normalizeApiUrl(o.apiUrl);
4057
- if (!localOrDev) return void 0;
4212
+ async function resolveSetupApiUrl(o, repoRoot) {
4213
+ if (o.apiUrl) return normalizeApiUrl2(o.apiUrl);
4058
4214
  const binding = await findBindingRecordByWorkspaceRoot(repoRoot, o.homeDir);
4059
- if (binding?.apiUrl) return normalizeApiUrl(binding.apiUrl);
4215
+ if (binding?.apiUrl) return normalizeApiUrl2(binding.apiUrl);
4060
4216
  return void 0;
4061
4217
  }
4062
4218
  async function persistBindingApiUrl(repoRoot, apiUrl, homeDir, dryRun) {
4063
4219
  if (dryRun) return;
4064
4220
  const binding = await findBindingRecordByWorkspaceRoot(repoRoot, homeDir);
4065
4221
  if (!binding) return;
4066
- const normalized = normalizeApiUrl(apiUrl);
4222
+ const normalized = normalizeApiUrl2(apiUrl);
4067
4223
  if (binding.apiUrl === normalized) return;
4068
4224
  await writeBindingRecord(
4069
4225
  {
@@ -4238,7 +4394,7 @@ async function runSetupIdeFiles(o) {
4238
4394
  const outcomes = {};
4239
4395
  let cursorMcp;
4240
4396
  let jetbrainsMcp;
4241
- const repoRoot = o.workspaceRoot !== void 0 && o.workspaceRoot !== "" ? path16.resolve(o.workspaceRoot) : await findRepoRoot(o.cwd);
4397
+ const repoRoot = o.workspaceRoot !== void 0 && o.workspaceRoot !== "" ? path17.resolve(o.workspaceRoot) : await findRepoRoot(o.cwd);
4242
4398
  if (!repoRoot) {
4243
4399
  return {
4244
4400
  exitCode: 1,
@@ -4274,12 +4430,13 @@ async function runSetupIdeFiles(o) {
4274
4430
  });
4275
4431
  const cursorEnvironment = o.cursorEnvironment ?? "production";
4276
4432
  const localOrDev = cursorEnvironment === "local" || Boolean(o.devMode);
4277
- const resolvedApiUrl2 = await resolveSetupApiUrl(o, repoRoot, localOrDev);
4433
+ const npmPackageChannel = o.npmPackageChannel ?? npmPackageChannelFromEnvironment(cursorEnvironment);
4434
+ const resolvedApiUrl2 = await resolveSetupApiUrl(o, repoRoot);
4278
4435
  const effectiveApiUrl = resolveIdeApiUrl({
4279
4436
  environment: localOrDev ? "local" : cursorEnvironment,
4280
4437
  apiUrl: resolvedApiUrl2
4281
4438
  });
4282
- if (localOrDev && !o.dryRun) {
4439
+ if (!o.dryRun && resolvedApiUrl2) {
4283
4440
  await persistBindingApiUrl(repoRoot, effectiveApiUrl, o.homeDir, o.dryRun);
4284
4441
  }
4285
4442
  const cursorContent = `---
@@ -4324,7 +4481,8 @@ description: MemoraOne MCP \u2014 IDE agent instructions
4324
4481
  npxPath: npxPath ?? void 0,
4325
4482
  cliPath,
4326
4483
  repoRoot,
4327
- apiUrl: resolvedApiUrl2
4484
+ apiUrl: resolvedApiUrl2,
4485
+ npmPackageChannel
4328
4486
  };
4329
4487
  outcomes[".cursor/rules/memoraone-mcp.mdc"] = await writeManagedMarkdown(
4330
4488
  repoRoot,
@@ -4332,12 +4490,22 @@ description: MemoraOne MCP \u2014 IDE agent instructions
4332
4490
  cursorContent,
4333
4491
  { force: o.force, dryRun: o.dryRun }
4334
4492
  );
4335
- outcomes[".cursor/mcp.json"] = await writeIdeMcpJson(
4336
- repoRoot,
4337
- ".cursor/mcp.json",
4338
- (existing) => buildCursorMcpJsonBody(existing, cursorWriteOptions),
4339
- { force: o.force, dryRun: o.dryRun }
4340
- );
4493
+ try {
4494
+ outcomes[".cursor/mcp.json"] = await writeIdeMcpJson(
4495
+ repoRoot,
4496
+ ".cursor/mcp.json",
4497
+ (existing) => buildCursorMcpJsonBody(existing, cursorWriteOptions),
4498
+ { force: o.force, dryRun: o.dryRun }
4499
+ );
4500
+ } catch (err) {
4501
+ const message = err instanceof Error ? err.message : String(err);
4502
+ return {
4503
+ exitCode: 1,
4504
+ repoRoot,
4505
+ outcomes,
4506
+ error: message
4507
+ };
4508
+ }
4341
4509
  const repoConfigPath = getCursorRepoMcpConfigPath(repoRoot);
4342
4510
  const repoOutcome = outcomes[".cursor/mcp.json"] ?? "skipped";
4343
4511
  let globalConfigPath;
@@ -4386,7 +4554,7 @@ description: MemoraOne MCP \u2014 IDE agent instructions
4386
4554
  };
4387
4555
  }
4388
4556
  if (o.targets.vscode) {
4389
- const vscodeEnvironment = localOrDev ? "local" : "production";
4557
+ const vscodeEnvironment = localOrDev ? "local" : cursorEnvironment === "staging" ? "staging" : "production";
4390
4558
  let vscodeCliPath;
4391
4559
  if (vscodeEnvironment === "local") {
4392
4560
  let resolvedCliPath = o.cursorLocalCliPathOverride;
@@ -4407,20 +4575,32 @@ description: MemoraOne MCP \u2014 IDE agent instructions
4407
4575
  }
4408
4576
  vscodeCliPath = resolvedCliPath;
4409
4577
  }
4410
- outcomes[".vscode/mcp.json"] = await writeIdeMcpJson(
4411
- repoRoot,
4412
- ".vscode/mcp.json",
4413
- (existing) => buildVscodeMcpJsonBody(existing, {
4414
- environment: vscodeEnvironment,
4415
- apiUrl: resolvedApiUrl2,
4416
- cliPath: vscodeCliPath,
4417
- workspaceRoot: vscodeEnvironment === "local" ? repoRoot : void 0
4418
- }),
4419
- {
4420
- force: o.force,
4421
- dryRun: o.dryRun
4422
- }
4423
- );
4578
+ try {
4579
+ outcomes[".vscode/mcp.json"] = await writeIdeMcpJson(
4580
+ repoRoot,
4581
+ ".vscode/mcp.json",
4582
+ (existing) => buildVscodeMcpJsonBody(existing, {
4583
+ environment: vscodeEnvironment,
4584
+ apiUrl: resolvedApiUrl2,
4585
+ cliPath: vscodeCliPath,
4586
+ workspaceRoot: vscodeEnvironment === "local" ? repoRoot : void 0,
4587
+ npmPackageChannel
4588
+ }),
4589
+ {
4590
+ force: o.force,
4591
+ dryRun: o.dryRun
4592
+ }
4593
+ );
4594
+ } catch (err) {
4595
+ const message = err instanceof Error ? err.message : String(err);
4596
+ return {
4597
+ exitCode: 1,
4598
+ repoRoot,
4599
+ outcomes,
4600
+ cursorMcp,
4601
+ error: message
4602
+ };
4603
+ }
4424
4604
  outcomes[".github/copilot-instructions.md"] = await writeManagedMarkdown(
4425
4605
  repoRoot,
4426
4606
  ".github/copilot-instructions.md",
@@ -4443,8 +4623,11 @@ description: MemoraOne MCP \u2014 IDE agent instructions
4443
4623
  repoRoot,
4444
4624
  globalConfigPath: activePath,
4445
4625
  dryRun: o.dryRun,
4446
- // Connect/local repair passes --dev so JetBrains gets the same backend URL + local CLI.
4447
- devMode: o.devMode,
4626
+ // Local dogfood: --dev / local environment node + built CLI.
4627
+ // Published staging/production: npx + channel-specific package spec.
4628
+ devMode: localOrDev,
4629
+ environment: localOrDev ? "local" : cursorEnvironment,
4630
+ npmPackageChannel,
4448
4631
  apiUrl: resolvedApiUrl2,
4449
4632
  repair: o.repair ?? false,
4450
4633
  verify: o.verifyHandshake ?? !o.dryRun,
@@ -4511,6 +4694,7 @@ async function cliSetupIdeFiles(argv, options = {}) {
4511
4694
  stdinIsTty,
4512
4695
  env: env2
4513
4696
  });
4697
+ const cursorEnvironment = cursorEnvironmentFromFlags(local, staging);
4514
4698
  const result = await runSetupIdeFiles({
4515
4699
  cwd: cwd2,
4516
4700
  workspaceRoot,
@@ -4520,7 +4704,8 @@ async function cliSetupIdeFiles(argv, options = {}) {
4520
4704
  noGitignore: options.setupOverrides?.noGitignore ?? noGitignore,
4521
4705
  devMode,
4522
4706
  repair,
4523
- cursorEnvironment: cursorEnvironmentFromFlags(local, staging),
4707
+ cursorEnvironment,
4708
+ npmPackageChannel: npmPackageChannelFromEnvironment(cursorEnvironment),
4524
4709
  apiUrl,
4525
4710
  ...options.setupOverrides
4526
4711
  });
@@ -4591,16 +4776,16 @@ async function cliSetupIdeFiles(argv, options = {}) {
4591
4776
  }
4592
4777
 
4593
4778
  // src/localState/connectCommand.ts
4594
- var path19 = __toESM(require("path"), 1);
4779
+ var path20 = __toESM(require("path"), 1);
4595
4780
  var os7 = __toESM(require("os"), 1);
4596
4781
 
4597
4782
  // src/config.ts
4598
4783
  var process2 = __toESM(require("process"), 1);
4599
4784
  var fs14 = __toESM(require("fs"), 1);
4600
- var path17 = __toESM(require("path"), 1);
4785
+ var path18 = __toESM(require("path"), 1);
4601
4786
  var dotenv = __toESM(require("dotenv"), 1);
4602
4787
  var import_v4 = require("zod/v4");
4603
- var dotenvPath = path17.resolve(process2.cwd(), ".env");
4788
+ var dotenvPath = path18.resolve(process2.cwd(), ".env");
4604
4789
  if (fs14.existsSync(dotenvPath)) {
4605
4790
  try {
4606
4791
  dotenv.config({ path: dotenvPath });
@@ -4669,7 +4854,7 @@ var config2 = {
4669
4854
 
4670
4855
  // src/repoFingerprint.ts
4671
4856
  var fs15 = __toESM(require("fs"), 1);
4672
- var path18 = __toESM(require("path"), 1);
4857
+ var path19 = __toESM(require("path"), 1);
4673
4858
  var crypto2 = __toESM(require("crypto"), 1);
4674
4859
  var parseBooleanFlag3 = (value) => {
4675
4860
  if (!value) {
@@ -4708,7 +4893,7 @@ var resolveGitDir = (gitPath) => {
4708
4893
  const match = content.match(/^gitdir:\s*(.+)$/m);
4709
4894
  if (match) {
4710
4895
  const gitDir = match[1].trim();
4711
- return path18.resolve(path18.dirname(gitPath), gitDir);
4896
+ return path19.resolve(path19.dirname(gitPath), gitDir);
4712
4897
  }
4713
4898
  }
4714
4899
  } catch {
@@ -4717,16 +4902,16 @@ var resolveGitDir = (gitPath) => {
4717
4902
  return null;
4718
4903
  };
4719
4904
  var findGitRoot = (start) => {
4720
- let current = path18.resolve(start);
4905
+ let current = path19.resolve(start);
4721
4906
  while (true) {
4722
- const gitPath = path18.join(current, ".git");
4907
+ const gitPath = path19.join(current, ".git");
4723
4908
  if (fs15.existsSync(gitPath)) {
4724
4909
  const gitDir = resolveGitDir(gitPath);
4725
4910
  if (gitDir) {
4726
4911
  return { gitRoot: current, gitDir };
4727
4912
  }
4728
4913
  }
4729
- const parent = path18.dirname(current);
4914
+ const parent = path19.dirname(current);
4730
4915
  if (parent === current) {
4731
4916
  break;
4732
4917
  }
@@ -4735,7 +4920,7 @@ var findGitRoot = (start) => {
4735
4920
  return null;
4736
4921
  };
4737
4922
  var readOriginRemote = (gitDir) => {
4738
- const configPath = path18.join(gitDir, "config");
4923
+ const configPath = path19.join(gitDir, "config");
4739
4924
  try {
4740
4925
  const content = fs15.readFileSync(configPath, "utf8");
4741
4926
  const lines = content.split(/\r?\n/);
@@ -4761,7 +4946,7 @@ var readOriginRemote = (gitDir) => {
4761
4946
  function resolveRepoFingerprint(cwd2) {
4762
4947
  const found = findGitRoot(cwd2);
4763
4948
  if (!found) {
4764
- const fallbackPath = path18.resolve(cwd2);
4949
+ const fallbackPath = path19.resolve(cwd2);
4765
4950
  const fingerprint2 = sha256(fallbackPath);
4766
4951
  debugLog(`repo fingerprint=${fingerprint2} source=path-fallback`);
4767
4952
  return {
@@ -4783,7 +4968,7 @@ function resolveRepoFingerprint(cwd2) {
4783
4968
  source: "git-remote"
4784
4969
  };
4785
4970
  }
4786
- const fingerprint = sha256(path18.resolve(gitRoot));
4971
+ const fingerprint = sha256(path19.resolve(gitRoot));
4787
4972
  debugLog(`repo fingerprint=${fingerprint} source=path-fallback`);
4788
4973
  return {
4789
4974
  fingerprint,
@@ -4809,16 +4994,32 @@ function normalizeGitRemote(remoteUrl) {
4809
4994
  normalized = normalized.replace(/\/+$/, "");
4810
4995
  return normalized.toLowerCase() || null;
4811
4996
  }
4812
- function formatIdeSetupRepairHint(workspaceRoot, cliPath) {
4813
- const cli = cliPath ?? "<path-to-packages/mcp/dist/cli.cjs>";
4814
- return `Repair with (no new connect code): node ${cli} setup-ide-files --all --local --dev --force --workspace-root ${workspaceRoot}`;
4815
- }
4816
4997
  async function runConnectCommand(options) {
4817
4998
  const code = normalizeConnectCode(options.code);
4818
- const cwd2 = path19.resolve(options.cwd ?? process.cwd());
4999
+ const cwd2 = path20.resolve(options.cwd ?? process.cwd());
4819
5000
  const apiUrl = (options.apiUrl ?? config2.apiUrl).replace(/\/+$/, "");
4820
5001
  const homeDir = options.homeDir ?? os7.homedir();
4821
5002
  const environment = "local";
5003
+ const executionMode = await resolvePackageExecutionMode({
5004
+ executionMode: options.executionMode,
5005
+ // Only honor an explicit caller cliPath; never auto-resolve before mode detection
5006
+ // (published installs must not be forced into local monorepo mode).
5007
+ cliPath: options.cliPath,
5008
+ apiUrl,
5009
+ scriptPath: options.scriptPath,
5010
+ env: options.env,
5011
+ resolveBuiltCliPath: resolveBuiltCliPathAsync
5012
+ });
5013
+ let resolvedMode = executionMode;
5014
+ if (resolvedMode.kind === "local" && !resolvedMode.cliPath) {
5015
+ const cliPath = await resolveBuiltCliPathAsync();
5016
+ if (!cliPath) {
5017
+ throw new Error(
5018
+ "[memoraone-mcp] Local connect requires a built CLI at packages/mcp/dist/cli.cjs. Run pnpm build first."
5019
+ );
5020
+ }
5021
+ resolvedMode = { kind: "local", cliPath };
5022
+ }
4822
5023
  const ensured = await ensureRepositoryBindingForRoot(cwd2, {
4823
5024
  homeDir,
4824
5025
  identityDeps: options.identityDeps,
@@ -4826,7 +5027,7 @@ async function runConnectCommand(options) {
4826
5027
  });
4827
5028
  if (ensured.legacyM1WarningPath) {
4828
5029
  process.stderr.write(
4829
- `[memoraone-mcp] warning: ignoring legacy ${path19.basename(ensured.legacyM1WarningPath)} at ${ensured.legacyM1WarningPath} (credentials and binding are package-managed)
5030
+ `[memoraone-mcp] warning: ignoring legacy ${path20.basename(ensured.legacyM1WarningPath)} at ${ensured.legacyM1WarningPath} (credentials and binding are package-managed)
4830
5031
  `
4831
5032
  );
4832
5033
  }
@@ -4902,7 +5103,7 @@ async function runConnectCommand(options) {
4902
5103
  if (options.configureIdes !== false) {
4903
5104
  const targets = { cursor: true, vscode: true, jetbrains: true };
4904
5105
  const setup = options.setupIdeFiles ?? runSetupIdeFiles;
4905
- const cliPath = options.cliPath !== void 0 ? options.cliPath : await resolveBuiltCliPathAsync();
5106
+ const modeSetup = setupOptionsFromPackageExecutionMode(resolvedMode);
4906
5107
  let setupResult;
4907
5108
  try {
4908
5109
  setupResult = await setup({
@@ -4915,12 +5116,9 @@ async function runConnectCommand(options) {
4915
5116
  noGitignore: true,
4916
5117
  skipDaemonCleanup: true,
4917
5118
  homeDir,
4918
- cursorEnvironment: "local",
4919
- devMode: true,
4920
- // Propagate the same backend endpoint used for redeem into all IDE configs.
5119
+ // Propagate the redeemed binding API URL (backend only — not execution mode).
4921
5120
  apiUrl,
4922
- cursorLocalCliPathOverride: cliPath,
4923
- cliPathOverride: cliPath,
5121
+ ...modeSetup,
4924
5122
  ...options.setupIdeOptions
4925
5123
  });
4926
5124
  } catch (err) {
@@ -4934,7 +5132,7 @@ async function runConnectCommand(options) {
4934
5132
  }
4935
5133
  if (setupResult.exitCode !== 0) {
4936
5134
  const detail = setupResult.error ?? "unknown IDE setup error";
4937
- const repair = formatIdeSetupRepairHint(cwd2, cliPath);
5135
+ const repair = formatIdeSetupRepairHint(cwd2, resolvedMode);
4938
5136
  return {
4939
5137
  exitCode: 1,
4940
5138
  repositoryBindingId: ensured.repositoryBindingId,
@@ -4944,6 +5142,7 @@ async function runConnectCommand(options) {
4944
5142
  createdBinding: ensured.created,
4945
5143
  legacyM1WarningPath: ensured.legacyM1WarningPath,
4946
5144
  ideSetupError: detail,
5145
+ executionMode: resolvedMode,
4947
5146
  message: `Repository connection exists for binding ${ensured.repositoryBindingId} (project ${redeemed.project_id}), but IDE configuration failed: ${detail}. Credentials and binding were kept. ${repair}`
4948
5147
  };
4949
5148
  }
@@ -4956,6 +5155,7 @@ async function runConnectCommand(options) {
4956
5155
  recovered: redeemed.recovered,
4957
5156
  createdBinding: ensured.created,
4958
5157
  legacyM1WarningPath: ensured.legacyM1WarningPath,
5158
+ executionMode: resolvedMode,
4959
5159
  message: baseSuccess
4960
5160
  };
4961
5161
  }