@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.
- package/dist/cli.cjs +452 -252
- 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.
|
|
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((
|
|
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,
|
|
858
|
+
async function requestJson(baseUrl, method, path21, options = {}) {
|
|
859
859
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
860
|
-
const url = `${baseUrl.replace(/\/+$/, "")}${
|
|
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((
|
|
1532
|
-
this.waiters.push(
|
|
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
|
|
1606
|
-
var
|
|
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
|
|
1613
|
+
var fs10 = __toESM(require("fs/promises"), 1);
|
|
1614
1614
|
var os4 = __toESM(require("os"), 1);
|
|
1615
|
-
var
|
|
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
|
|
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] =
|
|
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",
|
|
2007
|
+
args: ["-y", memoraoneNpmPackageSpec(channel)],
|
|
1832
2008
|
env: env2
|
|
1833
2009
|
};
|
|
1834
2010
|
}
|
|
1835
|
-
async function
|
|
2011
|
+
async function pathExists2(filePath) {
|
|
1836
2012
|
try {
|
|
1837
|
-
await
|
|
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 [
|
|
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
|
|
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
|
|
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
|
|
2061
|
+
if (!await pathExists2(npxPath)) return false;
|
|
1886
2062
|
if (process.platform !== "win32") {
|
|
1887
2063
|
try {
|
|
1888
|
-
await
|
|
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(
|
|
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 =
|
|
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]
|
|
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
|
|
2145
|
+
return path14.join(repoRoot, ".cursor", "mcp.json");
|
|
1968
2146
|
}
|
|
1969
2147
|
async function readCursorMcpConfigObject(configPath) {
|
|
1970
2148
|
try {
|
|
1971
|
-
const raw = await
|
|
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
|
|
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
|
|
2172
|
+
await fs10.unlink(configPath);
|
|
1995
2173
|
return { changed: true, backupPath };
|
|
1996
2174
|
}
|
|
1997
2175
|
const next = { ...parsed2, mcpServers };
|
|
1998
|
-
await
|
|
1999
|
-
await
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
2391
|
+
const resolvedRoot = path15.resolve(workspaceRoot);
|
|
2214
2392
|
const baseDir = getMcpBaseDir();
|
|
2215
2393
|
let entries;
|
|
2216
2394
|
try {
|
|
2217
|
-
entries = await
|
|
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 =
|
|
2408
|
+
const socketPath = path15.join(baseDir, name);
|
|
2231
2409
|
const record = readBindingSidecarRecord(socketPath);
|
|
2232
2410
|
if (!record?.workspaceRoot) continue;
|
|
2233
|
-
if (
|
|
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 ?
|
|
2420
|
+
const resolvedRoot = workspaceRoot ? path15.resolve(workspaceRoot) : null;
|
|
2243
2421
|
const filtered = [];
|
|
2244
2422
|
for (const socketPath of socketPaths) {
|
|
2245
|
-
const
|
|
2246
|
-
if (isLegacySocketFilename(
|
|
2247
|
-
if (isSocketFilenameForProjectAndIde(
|
|
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(
|
|
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 &&
|
|
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
|
|
2446
|
+
await fs11.unlink(socketPath);
|
|
2269
2447
|
try {
|
|
2270
|
-
await
|
|
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([
|
|
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(
|
|
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((
|
|
2830
|
+
return new Promise((resolve17, reject) => {
|
|
2653
2831
|
const tryConnect = (attempt) => {
|
|
2654
|
-
connect2(socketPath).then(
|
|
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((
|
|
2771
|
-
const socket = net.connect(socketPath, () =>
|
|
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
|
|
3213
|
+
var path17 = __toESM(require("path"), 1);
|
|
3214
|
+
var import_node_crypto5 = require("crypto");
|
|
3036
3215
|
|
|
3037
3216
|
// src/jetbrainsMcpConfig.ts
|
|
3038
|
-
var
|
|
3217
|
+
var fs12 = __toESM(require("fs/promises"), 1);
|
|
3039
3218
|
var os5 = __toESM(require("os"), 1);
|
|
3040
|
-
var
|
|
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
|
|
3251
|
+
async function pathExists3(filePath) {
|
|
3073
3252
|
try {
|
|
3074
|
-
await
|
|
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
|
|
3264
|
+
return path16.join(homeDir, ".ai", "mcp", "mcp.json");
|
|
3086
3265
|
}
|
|
3087
3266
|
function getJetBrainsProjectMcpConfigPaths(repoRoot) {
|
|
3088
3267
|
return [
|
|
3089
|
-
{ kind: "project-ai", path:
|
|
3090
|
-
{ kind: "project-ij", path:
|
|
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
|
|
3101
|
-
const stat4 = await
|
|
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:
|
|
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]:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
3413
|
+
await fs12.unlink(configPath);
|
|
3212
3414
|
return { changed: true, backupPath };
|
|
3213
3415
|
}
|
|
3214
3416
|
const next = { ...parsed2, mcpServers };
|
|
3215
|
-
await
|
|
3216
|
-
await
|
|
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] ?
|
|
3422
|
+
const here = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
|
|
3221
3423
|
const candidates = [
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
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
|
|
3228
|
-
return
|
|
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
|
-
|
|
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",
|
|
3468
|
+
args: ["-y", memoraoneNpmPackageSpec(channel)],
|
|
3264
3469
|
workspaceRoot: options.workspaceRoot,
|
|
3265
|
-
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
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
|
|
3430
|
-
await
|
|
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] =
|
|
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",
|
|
3937
|
+
args: ["-y", memoraoneNpmPackageSpec(channel)],
|
|
3809
3938
|
env: env2
|
|
3810
3939
|
};
|
|
3811
3940
|
}
|
|
3812
3941
|
function assertUnderRepoRoot(repoRoot, absPath) {
|
|
3813
|
-
const normRoot =
|
|
3814
|
-
const normPath =
|
|
3815
|
-
if (normPath !==
|
|
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 =
|
|
3832
|
-
const root =
|
|
3960
|
+
let current = path17.resolve(startDir);
|
|
3961
|
+
const root = path17.parse(current).root;
|
|
3833
3962
|
while (true) {
|
|
3834
|
-
const gitPath =
|
|
3835
|
-
const m1Path =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
4105
|
+
let parsed2;
|
|
3950
4106
|
try {
|
|
3951
4107
|
parsed2 = JSON.parse(stripLeadingLineComments3(raw));
|
|
3952
4108
|
} catch {
|
|
3953
|
-
|
|
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
|
|
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
|
|
4056
|
-
if (o.apiUrl) return
|
|
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
|
|
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 =
|
|
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 !== "" ?
|
|
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
|
|
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 (
|
|
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
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
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
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
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
|
-
//
|
|
4447
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
4905
|
+
let current = path19.resolve(start);
|
|
4721
4906
|
while (true) {
|
|
4722
|
-
const gitPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 ${
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
}
|