@prom.codes/memory-mcp 0.5.0 → 0.6.0
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/bin.js +268 -49
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -4,10 +4,189 @@
|
|
|
4
4
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
|
|
7
|
+
// ../shared/dist/types.js
|
|
8
|
+
var GRAMMAR_LANGUAGE_IDS = [
|
|
9
|
+
"typescript",
|
|
10
|
+
"tsx",
|
|
11
|
+
"javascript",
|
|
12
|
+
"python",
|
|
13
|
+
"php",
|
|
14
|
+
"go",
|
|
15
|
+
"rust",
|
|
16
|
+
"java",
|
|
17
|
+
"csharp",
|
|
18
|
+
"c",
|
|
19
|
+
"cpp",
|
|
20
|
+
"ruby",
|
|
21
|
+
"kotlin",
|
|
22
|
+
"html"
|
|
23
|
+
];
|
|
24
|
+
var DOCUMENT_LANGUAGE_IDS = [
|
|
25
|
+
"markdown",
|
|
26
|
+
"text",
|
|
27
|
+
"json",
|
|
28
|
+
"yaml",
|
|
29
|
+
"toml"
|
|
30
|
+
];
|
|
31
|
+
var LANGUAGE_IDS = [
|
|
32
|
+
...GRAMMAR_LANGUAGE_IDS,
|
|
33
|
+
...DOCUMENT_LANGUAGE_IDS
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ../shared/dist/update-check.js
|
|
37
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
38
|
+
import { homedir } from "node:os";
|
|
39
|
+
import { join } from "node:path";
|
|
40
|
+
import { fileURLToPath } from "node:url";
|
|
41
|
+
async function packageIdentity(binImportMetaUrl) {
|
|
42
|
+
try {
|
|
43
|
+
const binPath = fileURLToPath(binImportMetaUrl);
|
|
44
|
+
const pkgPath = join(binPath, "..", "..", "package.json");
|
|
45
|
+
const raw = await readFile(pkgPath, "utf8");
|
|
46
|
+
const parsed = JSON.parse(raw);
|
|
47
|
+
if (typeof parsed.name !== "string" || typeof parsed.version !== "string") {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return { name: parsed.name, version: parsed.version };
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function maybeNotifyUpdate(binImportMetaUrl, env = process.env) {
|
|
56
|
+
try {
|
|
57
|
+
const id = await packageIdentity(binImportMetaUrl);
|
|
58
|
+
if (id === null)
|
|
59
|
+
return;
|
|
60
|
+
await checkForUpdate({ name: id.name, version: id.version, env });
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
65
|
+
var DEFAULT_TIMEOUT_MS = 1500;
|
|
66
|
+
var OPT_OUT_RE = /^(1|true|yes|on)$/i;
|
|
67
|
+
function parseSemver(v) {
|
|
68
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(v.trim());
|
|
69
|
+
if (m === null)
|
|
70
|
+
return null;
|
|
71
|
+
return {
|
|
72
|
+
core: [Number(m[1]), Number(m[2]), Number(m[3])],
|
|
73
|
+
pre: m[4] ?? null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function isNewerVersion(latest, current) {
|
|
77
|
+
const a = parseSemver(latest);
|
|
78
|
+
const b = parseSemver(current);
|
|
79
|
+
if (a === null || b === null)
|
|
80
|
+
return false;
|
|
81
|
+
for (let i = 0; i < 3; i++) {
|
|
82
|
+
if (a.core[i] > b.core[i])
|
|
83
|
+
return true;
|
|
84
|
+
if (a.core[i] < b.core[i])
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (a.pre === null && b.pre !== null)
|
|
88
|
+
return true;
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function cachePath(dir, name) {
|
|
92
|
+
const safe = name.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
93
|
+
return join(dir, `.update-check-${safe}.json`);
|
|
94
|
+
}
|
|
95
|
+
async function readCache(path2) {
|
|
96
|
+
try {
|
|
97
|
+
const raw = await readFile(path2, "utf8");
|
|
98
|
+
const parsed = JSON.parse(raw);
|
|
99
|
+
if (typeof parsed.checkedAt !== "number")
|
|
100
|
+
return null;
|
|
101
|
+
return {
|
|
102
|
+
checkedAt: parsed.checkedAt,
|
|
103
|
+
latest: typeof parsed.latest === "string" ? parsed.latest : null
|
|
104
|
+
};
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function writeCache(path2, data) {
|
|
110
|
+
try {
|
|
111
|
+
await writeFile(path2, JSON.stringify(data), "utf8");
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function fetchLatest(name, fetchImpl, timeoutMs) {
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
118
|
+
timer.unref?.();
|
|
119
|
+
try {
|
|
120
|
+
const url = `https://registry.npmjs.org/${name.replace("/", "%2F")}/latest`;
|
|
121
|
+
const res = await fetchImpl(url, {
|
|
122
|
+
signal: controller.signal,
|
|
123
|
+
headers: { accept: "application/vnd.npm.install-v1+json" }
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok)
|
|
126
|
+
return null;
|
|
127
|
+
const body = await res.json();
|
|
128
|
+
return typeof body.version === "string" ? body.version : null;
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
} finally {
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function checkForUpdate(options) {
|
|
136
|
+
const { name, version, env = process.env, log = (line) => process.stderr.write(line), fetch: fetchImpl = globalThis.fetch, cacheDir = join(homedir(), ".prometheus"), cacheTtlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS, force = false } = options;
|
|
137
|
+
const base = {
|
|
138
|
+
latest: null,
|
|
139
|
+
current: version
|
|
140
|
+
};
|
|
141
|
+
if (OPT_OUT_RE.test(env.PROMETHEUS_NO_UPDATE_CHECK ?? "")) {
|
|
142
|
+
return { ...base, checked: false, updateAvailable: false, reason: "opted-out" };
|
|
143
|
+
}
|
|
144
|
+
if (parseSemver(version) === null || version === "0.0.0") {
|
|
145
|
+
return { ...base, checked: false, updateAvailable: false, reason: "invalid-version" };
|
|
146
|
+
}
|
|
147
|
+
if (typeof fetchImpl !== "function") {
|
|
148
|
+
return { ...base, checked: false, updateAvailable: false, reason: "error" };
|
|
149
|
+
}
|
|
150
|
+
const file = cachePath(cacheDir, name);
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
if (!force) {
|
|
153
|
+
const cached = await readCache(file);
|
|
154
|
+
if (cached !== null && now - cached.checkedAt < cacheTtlMs) {
|
|
155
|
+
const updateAvailable2 = cached.latest !== null && isNewerVersion(cached.latest, version);
|
|
156
|
+
if (updateAvailable2)
|
|
157
|
+
notify(log, name, version, cached.latest);
|
|
158
|
+
return {
|
|
159
|
+
...base,
|
|
160
|
+
latest: cached.latest,
|
|
161
|
+
checked: false,
|
|
162
|
+
updateAvailable: updateAvailable2,
|
|
163
|
+
reason: "throttled"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
await mkdir(cacheDir, { recursive: true }).catch(() => void 0);
|
|
168
|
+
const latest = await fetchLatest(name, fetchImpl, timeoutMs);
|
|
169
|
+
await writeCache(file, { checkedAt: now, latest });
|
|
170
|
+
if (latest === null) {
|
|
171
|
+
return { ...base, checked: true, updateAvailable: false, reason: "error" };
|
|
172
|
+
}
|
|
173
|
+
const updateAvailable = isNewerVersion(latest, version);
|
|
174
|
+
if (updateAvailable)
|
|
175
|
+
notify(log, name, version, latest);
|
|
176
|
+
return { ...base, latest, checked: true, updateAvailable };
|
|
177
|
+
}
|
|
178
|
+
function notify(log, name, current, latest) {
|
|
179
|
+
log(`${name}: a newer version (${latest}) is available \u2014 you are on ${current}. npx users get it automatically on the next restart; for a global install run \`npm update -g ${name}\`. (Set PROMETHEUS_NO_UPDATE_CHECK=1 to silence.)
|
|
180
|
+
`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ../shared/dist/index.js
|
|
184
|
+
var PROMETHEUS_VERSION = "0.1.0";
|
|
185
|
+
|
|
7
186
|
// dist/composition.js
|
|
8
187
|
import { createHash } from "node:crypto";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
|
-
import { basename, join, resolve } from "node:path";
|
|
188
|
+
import { homedir as homedir2 } from "node:os";
|
|
189
|
+
import { basename, join as join2, resolve } from "node:path";
|
|
11
190
|
|
|
12
191
|
// ../embeddings-openai-compat/dist/index.js
|
|
13
192
|
var DEFAULT_BATCH = 96;
|
|
@@ -1128,6 +1307,45 @@ function reciprocalRankFusion(lists, options = {}) {
|
|
|
1128
1307
|
return options.limit !== void 0 && options.limit >= 0 ? merged.slice(0, options.limit) : merged;
|
|
1129
1308
|
}
|
|
1130
1309
|
|
|
1310
|
+
// dist/temporal.js
|
|
1311
|
+
var RRF_K = 60;
|
|
1312
|
+
var DEFAULT_TEMPORAL_WEIGHT = 2;
|
|
1313
|
+
var RECENT_RE = /\b(latest|most[\s-]?recent|recently|recent|current|currently|now|nowadays|today|newest|up[\s-]?to[\s-]?date|so far)\b/i;
|
|
1314
|
+
var EARLIEST_RE = /\b(earliest|oldest|first|initial|initially|original|originally|at the (?:very )?(?:start|beginning)|back then)\b/i;
|
|
1315
|
+
function detectTemporalIntent(query) {
|
|
1316
|
+
if (query === "")
|
|
1317
|
+
return null;
|
|
1318
|
+
const recent = RECENT_RE.test(query);
|
|
1319
|
+
const earliest = EARLIEST_RE.test(query);
|
|
1320
|
+
if (recent === earliest)
|
|
1321
|
+
return null;
|
|
1322
|
+
return { direction: recent ? "recent" : "earliest" };
|
|
1323
|
+
}
|
|
1324
|
+
function parseTimestamp(iso) {
|
|
1325
|
+
if (iso === null || iso === void 0 || iso === "")
|
|
1326
|
+
return null;
|
|
1327
|
+
const ms = Date.parse(iso);
|
|
1328
|
+
return Number.isFinite(ms) ? ms : null;
|
|
1329
|
+
}
|
|
1330
|
+
function applyTemporalRanking(hits, intent, getTimestampMs, weight = DEFAULT_TEMPORAL_WEIGHT) {
|
|
1331
|
+
if (hits.length <= 1 || weight <= 0)
|
|
1332
|
+
return [...hits];
|
|
1333
|
+
const stamped = hits.map((hit, index) => ({ hit, index, ts: getTimestampMs(hit) })).filter((x) => x.ts !== null);
|
|
1334
|
+
if (stamped.length <= 1)
|
|
1335
|
+
return [...hits];
|
|
1336
|
+
const byTime = [...stamped].sort((a, b) => intent.direction === "recent" ? b.ts - a.ts : a.ts - b.ts);
|
|
1337
|
+
const tempRank = /* @__PURE__ */ new Map();
|
|
1338
|
+
byTime.forEach((x, rank) => tempRank.set(x.index, rank));
|
|
1339
|
+
const scored = hits.map((hit, index) => {
|
|
1340
|
+
const posScore = 1 / (RRF_K + index);
|
|
1341
|
+
const tr = tempRank.get(index);
|
|
1342
|
+
const tempScore = tr === void 0 ? 0 : 1 / (RRF_K + tr);
|
|
1343
|
+
return { hit, index, score: posScore + weight * tempScore };
|
|
1344
|
+
});
|
|
1345
|
+
scored.sort((a, b) => b.score - a.score || a.index - b.index);
|
|
1346
|
+
return scored.map((s) => s.hit);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1131
1349
|
// dist/types.js
|
|
1132
1350
|
var MEMORY_SCOPES = [
|
|
1133
1351
|
"system",
|
|
@@ -1301,6 +1519,8 @@ var SqliteMemoryBackend = class {
|
|
|
1301
1519
|
embedder;
|
|
1302
1520
|
reranker;
|
|
1303
1521
|
rewriter;
|
|
1522
|
+
temporalEnabled;
|
|
1523
|
+
temporalWeight;
|
|
1304
1524
|
/** Record ids whose vector is missing/stale, awaiting a batched embed. */
|
|
1305
1525
|
pendingEmbed = /* @__PURE__ */ new Set();
|
|
1306
1526
|
closed = false;
|
|
@@ -1317,6 +1537,8 @@ var SqliteMemoryBackend = class {
|
|
|
1317
1537
|
this.embedder = opts.embedder;
|
|
1318
1538
|
this.reranker = opts.reranker;
|
|
1319
1539
|
this.rewriter = opts.rewriter;
|
|
1540
|
+
this.temporalEnabled = opts.temporal?.enabled ?? false;
|
|
1541
|
+
this.temporalWeight = opts.temporal?.weight ?? DEFAULT_TEMPORAL_WEIGHT;
|
|
1320
1542
|
if (this.embedder !== void 0)
|
|
1321
1543
|
this.queueUnembedded();
|
|
1322
1544
|
}
|
|
@@ -1440,7 +1662,20 @@ var SqliteMemoryBackend = class {
|
|
|
1440
1662
|
], { limit: poolLimit }).map((f) => f.payload);
|
|
1441
1663
|
}
|
|
1442
1664
|
const reranked = input.rerank === false ? pool : await this.rerankPool(input.query, pool, finalLimit);
|
|
1443
|
-
|
|
1665
|
+
const temporalOn = input.temporal ?? this.temporalEnabled;
|
|
1666
|
+
const ordered = temporalOn ? this.applyTemporal(input.query, reranked) : reranked;
|
|
1667
|
+
return ordered.slice(0, finalLimit);
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* M5: blend the current order with a timestamp order when the query expresses
|
|
1671
|
+
* a clear temporal direction. Uses `updatedAt` (falls back to `createdAt`) as
|
|
1672
|
+
* the record's time. No-op when no intent is detected.
|
|
1673
|
+
*/
|
|
1674
|
+
applyTemporal(query, hits) {
|
|
1675
|
+
const intent = detectTemporalIntent(query);
|
|
1676
|
+
if (intent === null)
|
|
1677
|
+
return hits;
|
|
1678
|
+
return applyTemporalRanking(hits, intent, (h) => parseTimestamp(h.record.updatedAt) ?? parseTimestamp(h.record.createdAt), this.temporalWeight);
|
|
1444
1679
|
}
|
|
1445
1680
|
/**
|
|
1446
1681
|
* M4: rewrite the query for the retrieval channels (HyDE concat). Returns the
|
|
@@ -1695,7 +1930,7 @@ function projectIdFor(workspaceRoot) {
|
|
|
1695
1930
|
return createHash("sha256").update(abs).digest("hex").slice(0, 16);
|
|
1696
1931
|
}
|
|
1697
1932
|
function defaultMemoryDbPath() {
|
|
1698
|
-
return
|
|
1933
|
+
return join2(homedir2(), ".prometheus", "memory.db");
|
|
1699
1934
|
}
|
|
1700
1935
|
function intEnv(env, name, def) {
|
|
1701
1936
|
const raw = env[name];
|
|
@@ -1897,6 +2132,18 @@ function discoverMemoryRewriter(env) {
|
|
|
1897
2132
|
}
|
|
1898
2133
|
throw new Error(`unknown PROMETHEUS_MEMORY_REWRITE_PROVIDER="${forced}" (expected "none", "mistral", "openai", or "generic")`);
|
|
1899
2134
|
}
|
|
2135
|
+
function discoverMemoryTemporal(env) {
|
|
2136
|
+
const raw = (env.PROMETHEUS_MEMORY_TEMPORAL ?? "off").toLowerCase();
|
|
2137
|
+
const enabled = raw === "on" || raw === "1" || raw === "true" || raw === "yes";
|
|
2138
|
+
const rawWeight = env.PROMETHEUS_MEMORY_TEMPORAL_WEIGHT;
|
|
2139
|
+
let weight = DEFAULT_TEMPORAL_WEIGHT;
|
|
2140
|
+
if (rawWeight !== void 0 && rawWeight !== "") {
|
|
2141
|
+
const n = Number.parseFloat(rawWeight);
|
|
2142
|
+
if (Number.isFinite(n) && n >= 0)
|
|
2143
|
+
weight = n;
|
|
2144
|
+
}
|
|
2145
|
+
return { enabled, weight };
|
|
2146
|
+
}
|
|
1900
2147
|
function composeFromEnv(opts) {
|
|
1901
2148
|
const env = opts.env;
|
|
1902
2149
|
const override = (opts.workspaceRootOverride ?? "").trim();
|
|
@@ -1911,10 +2158,12 @@ function composeFromEnv(opts) {
|
|
|
1911
2158
|
const { id: rerankerId, provider: reranker } = discoverMemoryReranker(env);
|
|
1912
2159
|
const { id: extractorId, provider: extractor } = discoverMemoryExtractor(env);
|
|
1913
2160
|
const { id: rewriterId, provider: rewriter } = discoverMemoryRewriter(env);
|
|
2161
|
+
const temporal = discoverMemoryTemporal(env);
|
|
1914
2162
|
const backend = new SqliteMemoryBackend(dbPath, {
|
|
1915
2163
|
...embedder !== void 0 ? { embedder } : {},
|
|
1916
2164
|
...reranker !== null ? { reranker } : {},
|
|
1917
|
-
...rewriter !== null ? { rewriter } : {}
|
|
2165
|
+
...rewriter !== null ? { rewriter } : {},
|
|
2166
|
+
temporal
|
|
1918
2167
|
});
|
|
1919
2168
|
return {
|
|
1920
2169
|
backend,
|
|
@@ -1930,12 +2179,13 @@ function composeFromEnv(opts) {
|
|
|
1930
2179
|
extractorId,
|
|
1931
2180
|
rewriter,
|
|
1932
2181
|
rewriterId,
|
|
2182
|
+
temporalEnabled: temporal.enabled,
|
|
1933
2183
|
close: () => backend.close()
|
|
1934
2184
|
};
|
|
1935
2185
|
}
|
|
1936
2186
|
|
|
1937
2187
|
// dist/roots.js
|
|
1938
|
-
import { fileURLToPath } from "node:url";
|
|
2188
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1939
2189
|
async function rootFromClient(server, timeoutMs = 2500) {
|
|
1940
2190
|
let supportsRoots = false;
|
|
1941
2191
|
try {
|
|
@@ -1956,7 +2206,7 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
1956
2206
|
const uri = typeof r?.uri === "string" ? r.uri : "";
|
|
1957
2207
|
if (uri.startsWith("file://")) {
|
|
1958
2208
|
try {
|
|
1959
|
-
return
|
|
2209
|
+
return fileURLToPath2(uri);
|
|
1960
2210
|
} catch {
|
|
1961
2211
|
}
|
|
1962
2212
|
}
|
|
@@ -1967,38 +2217,6 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
1967
2217
|
// dist/server.js
|
|
1968
2218
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1969
2219
|
|
|
1970
|
-
// ../shared/dist/types.js
|
|
1971
|
-
var GRAMMAR_LANGUAGE_IDS = [
|
|
1972
|
-
"typescript",
|
|
1973
|
-
"tsx",
|
|
1974
|
-
"javascript",
|
|
1975
|
-
"python",
|
|
1976
|
-
"php",
|
|
1977
|
-
"go",
|
|
1978
|
-
"rust",
|
|
1979
|
-
"java",
|
|
1980
|
-
"csharp",
|
|
1981
|
-
"c",
|
|
1982
|
-
"cpp",
|
|
1983
|
-
"ruby",
|
|
1984
|
-
"kotlin",
|
|
1985
|
-
"html"
|
|
1986
|
-
];
|
|
1987
|
-
var DOCUMENT_LANGUAGE_IDS = [
|
|
1988
|
-
"markdown",
|
|
1989
|
-
"text",
|
|
1990
|
-
"json",
|
|
1991
|
-
"yaml",
|
|
1992
|
-
"toml"
|
|
1993
|
-
];
|
|
1994
|
-
var LANGUAGE_IDS = [
|
|
1995
|
-
...GRAMMAR_LANGUAGE_IDS,
|
|
1996
|
-
...DOCUMENT_LANGUAGE_IDS
|
|
1997
|
-
];
|
|
1998
|
-
|
|
1999
|
-
// ../shared/dist/index.js
|
|
2000
|
-
var PROMETHEUS_VERSION = "0.1.0";
|
|
2001
|
-
|
|
2002
2220
|
// dist/tools.js
|
|
2003
2221
|
import { z } from "zod";
|
|
2004
2222
|
|
|
@@ -2119,8 +2337,8 @@ function assertNoSecrets(text) {
|
|
|
2119
2337
|
|
|
2120
2338
|
// dist/setup.js
|
|
2121
2339
|
import { existsSync } from "node:fs";
|
|
2122
|
-
import { mkdir as
|
|
2123
|
-
import { dirname as dirname2, join as
|
|
2340
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2341
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
2124
2342
|
var MEMORY_RUNTIMES = [
|
|
2125
2343
|
"claude-code",
|
|
2126
2344
|
"cursor",
|
|
@@ -2164,13 +2382,13 @@ alwaysApply: true
|
|
|
2164
2382
|
var TARGETS = {
|
|
2165
2383
|
"claude-code": { relPath: "CLAUDE.md", mode: "block", detect: "CLAUDE.md" },
|
|
2166
2384
|
cursor: {
|
|
2167
|
-
relPath:
|
|
2385
|
+
relPath: join4(".cursor", "rules", "prometheus-memory.mdc"),
|
|
2168
2386
|
mode: "file",
|
|
2169
2387
|
fileContent: CURSOR_FRONTMATTER + withMarkers(RULE_BLOCK) + "\n",
|
|
2170
2388
|
detect: ".cursor"
|
|
2171
2389
|
},
|
|
2172
2390
|
augment: {
|
|
2173
|
-
relPath:
|
|
2391
|
+
relPath: join4(".augment", "rules", "prometheus-memory.md"),
|
|
2174
2392
|
mode: "file",
|
|
2175
2393
|
fileContent: withMarkers(RULE_BLOCK) + "\n",
|
|
2176
2394
|
detect: ".augment"
|
|
@@ -2178,7 +2396,7 @@ var TARGETS = {
|
|
|
2178
2396
|
agents: { relPath: "AGENTS.md", mode: "block", detect: "AGENTS.md" }
|
|
2179
2397
|
};
|
|
2180
2398
|
function detectRuntimes(workspaceRoot) {
|
|
2181
|
-
const found = MEMORY_RUNTIMES.filter((rt) => existsSync(
|
|
2399
|
+
const found = MEMORY_RUNTIMES.filter((rt) => existsSync(join4(workspaceRoot, TARGETS[rt].detect)));
|
|
2182
2400
|
return found.length > 0 ? found : ["agents"];
|
|
2183
2401
|
}
|
|
2184
2402
|
function upsertBlock(existing, block) {
|
|
@@ -2193,15 +2411,15 @@ function upsertBlock(existing, block) {
|
|
|
2193
2411
|
}
|
|
2194
2412
|
async function installRuntime(workspaceRoot, runtime) {
|
|
2195
2413
|
const target = TARGETS[runtime];
|
|
2196
|
-
const absPath =
|
|
2414
|
+
const absPath = join4(workspaceRoot, target.relPath);
|
|
2197
2415
|
const exists = existsSync(absPath);
|
|
2198
|
-
const before = exists ? await
|
|
2416
|
+
const before = exists ? await readFile3(absPath, "utf-8") : "";
|
|
2199
2417
|
const after = target.mode === "file" ? target.fileContent : upsertBlock(before, RULE_BLOCK);
|
|
2200
2418
|
if (exists && before === after) {
|
|
2201
2419
|
return { runtime, path: absPath, action: "unchanged" };
|
|
2202
2420
|
}
|
|
2203
|
-
await
|
|
2204
|
-
await
|
|
2421
|
+
await mkdir3(dirname2(absPath), { recursive: true });
|
|
2422
|
+
await writeFile3(absPath, after, "utf-8");
|
|
2205
2423
|
return { runtime, path: absPath, action: exists ? "updated" : "created" };
|
|
2206
2424
|
}
|
|
2207
2425
|
|
|
@@ -2563,6 +2781,7 @@ async function main() {
|
|
|
2563
2781
|
const explicitRoot = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
|
|
2564
2782
|
const claudeRoot = (env.CLAUDE_PROJECT_DIR ?? "").trim();
|
|
2565
2783
|
const eagerVia = explicitRoot !== "" ? "PROMETHEUS_WORKSPACE_ROOT" : claudeRoot !== "" ? "CLAUDE_PROJECT_DIR" : null;
|
|
2784
|
+
void maybeNotifyUpdate(import.meta.url, env);
|
|
2566
2785
|
const transport = new StdioServerTransport();
|
|
2567
2786
|
const server = new McpServer2(SERVER_IDENTITY, {
|
|
2568
2787
|
capabilities: { tools: {} },
|
|
@@ -2587,7 +2806,7 @@ async function main() {
|
|
|
2587
2806
|
env,
|
|
2588
2807
|
...override !== void 0 && override !== "" ? { workspaceRootOverride: override } : {}
|
|
2589
2808
|
});
|
|
2590
|
-
process.stderr.write(`prometheus-memory-mcp: workspace=${composed.workspaceRoot} (via ${via}) project=${composed.projectName} (${composed.projectId}) db=${composed.dbPath} embed=${composed.embedderId}${composed.embeddingsEnabled ? "" : " (keyword-only)"} rerank=${composed.rerankerId} extract=${composed.extractorId} rewrite=${composed.rewriterId}
|
|
2809
|
+
process.stderr.write(`prometheus-memory-mcp: workspace=${composed.workspaceRoot} (via ${via}) project=${composed.projectName} (${composed.projectId}) db=${composed.dbPath} embed=${composed.embedderId}${composed.embeddingsEnabled ? "" : " (keyword-only)"} rerank=${composed.rerankerId} extract=${composed.extractorId} rewrite=${composed.rewriterId} temporal=${composed.temporalEnabled ? "on" : "off"}
|
|
2591
2810
|
`);
|
|
2592
2811
|
registerTools(server, composed);
|
|
2593
2812
|
};
|