@prom.codes/memory-mcp 0.4.1 → 0.5.1
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 +347 -50
- 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;
|
|
@@ -999,6 +1178,79 @@ function delay(ms) {
|
|
|
999
1178
|
return new Promise((r) => setTimeout(r, ms));
|
|
1000
1179
|
}
|
|
1001
1180
|
|
|
1181
|
+
// dist/rewrite.js
|
|
1182
|
+
var SYSTEM_PROMPT2 = "You help search an AI agent's long-term memory of a software project and its conversations. Given a question, write ONE short hypothetical memory entry (1\u20132 sentences, plain statements) that \u2014 if it existed \u2014 would directly answer it. Use concrete nouns, names and likely phrasings a developer would store. Do NOT answer that you don't know, do NOT add preamble or quotes \u2014 output only the hypothetical statement.";
|
|
1183
|
+
var OpenAICompatRewriter = class {
|
|
1184
|
+
name;
|
|
1185
|
+
model;
|
|
1186
|
+
#url;
|
|
1187
|
+
#apiKey;
|
|
1188
|
+
#maxRetries;
|
|
1189
|
+
#retryBaseMs;
|
|
1190
|
+
#maxTokens;
|
|
1191
|
+
#temperature;
|
|
1192
|
+
#fetch;
|
|
1193
|
+
constructor(opts) {
|
|
1194
|
+
this.name = opts.name;
|
|
1195
|
+
this.model = opts.model;
|
|
1196
|
+
this.#url = `${opts.baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
1197
|
+
this.#apiKey = opts.apiKey;
|
|
1198
|
+
this.#maxRetries = opts.maxRetries ?? 2;
|
|
1199
|
+
this.#retryBaseMs = opts.retryBaseMs ?? 400;
|
|
1200
|
+
this.#maxTokens = opts.maxTokens ?? 160;
|
|
1201
|
+
this.#temperature = opts.temperature ?? 0;
|
|
1202
|
+
this.#fetch = opts.fetchImpl ?? fetch;
|
|
1203
|
+
}
|
|
1204
|
+
async rewrite(query, opts) {
|
|
1205
|
+
const trimmed = query.trim();
|
|
1206
|
+
if (trimmed === "")
|
|
1207
|
+
return [];
|
|
1208
|
+
const n = Math.max(1, opts?.n ?? 1);
|
|
1209
|
+
const body = JSON.stringify({
|
|
1210
|
+
model: this.model,
|
|
1211
|
+
temperature: this.#temperature,
|
|
1212
|
+
max_tokens: this.#maxTokens,
|
|
1213
|
+
n,
|
|
1214
|
+
messages: [
|
|
1215
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
1216
|
+
{ role: "user", content: `Question: ${trimmed}` }
|
|
1217
|
+
]
|
|
1218
|
+
});
|
|
1219
|
+
const headers = { "content-type": "application/json" };
|
|
1220
|
+
if (this.#apiKey !== void 0 && this.#apiKey !== "") {
|
|
1221
|
+
headers.authorization = `Bearer ${this.#apiKey}`;
|
|
1222
|
+
}
|
|
1223
|
+
for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {
|
|
1224
|
+
try {
|
|
1225
|
+
const res = await this.#fetch(this.#url, {
|
|
1226
|
+
method: "POST",
|
|
1227
|
+
headers,
|
|
1228
|
+
body,
|
|
1229
|
+
...opts?.signal ? { signal: opts.signal } : {}
|
|
1230
|
+
});
|
|
1231
|
+
if (res.status === 429 || res.status >= 500) {
|
|
1232
|
+
} else if (!res.ok) {
|
|
1233
|
+
return [];
|
|
1234
|
+
} else {
|
|
1235
|
+
const json = await res.json();
|
|
1236
|
+
const out = [];
|
|
1237
|
+
for (const c of json.choices ?? []) {
|
|
1238
|
+
const t = (c.message?.content ?? "").trim();
|
|
1239
|
+
if (t !== "")
|
|
1240
|
+
out.push(t.slice(0, 1e3));
|
|
1241
|
+
}
|
|
1242
|
+
return out;
|
|
1243
|
+
}
|
|
1244
|
+
} catch {
|
|
1245
|
+
}
|
|
1246
|
+
if (attempt < this.#maxRetries) {
|
|
1247
|
+
await new Promise((r) => setTimeout(r, this.#retryBaseMs * 2 ** attempt));
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return [];
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1002
1254
|
// dist/sqlite.js
|
|
1003
1255
|
import { randomUUID } from "node:crypto";
|
|
1004
1256
|
import { mkdirSync } from "node:fs";
|
|
@@ -1227,6 +1479,7 @@ var SqliteMemoryBackend = class {
|
|
|
1227
1479
|
db;
|
|
1228
1480
|
embedder;
|
|
1229
1481
|
reranker;
|
|
1482
|
+
rewriter;
|
|
1230
1483
|
/** Record ids whose vector is missing/stale, awaiting a batched embed. */
|
|
1231
1484
|
pendingEmbed = /* @__PURE__ */ new Set();
|
|
1232
1485
|
closed = false;
|
|
@@ -1242,6 +1495,7 @@ var SqliteMemoryBackend = class {
|
|
|
1242
1495
|
this.db.exec(`INSERT INTO agent_memory_fts (agent_memory_fts) VALUES ('rebuild')`);
|
|
1243
1496
|
this.embedder = opts.embedder;
|
|
1244
1497
|
this.reranker = opts.reranker;
|
|
1498
|
+
this.rewriter = opts.rewriter;
|
|
1245
1499
|
if (this.embedder !== void 0)
|
|
1246
1500
|
this.queueUnembedded();
|
|
1247
1501
|
}
|
|
@@ -1343,11 +1597,12 @@ var SqliteMemoryBackend = class {
|
|
|
1343
1597
|
return [];
|
|
1344
1598
|
const finalLimit = input.limit ?? 20;
|
|
1345
1599
|
const poolLimit = Math.max(finalLimit * 4, 40);
|
|
1346
|
-
const
|
|
1600
|
+
const channelInput = await this.applyRewrite(input);
|
|
1601
|
+
const ftsHits = this.ftsSearch(channelInput, poolLimit);
|
|
1347
1602
|
let vecHits = [];
|
|
1348
1603
|
if (this.embedder !== void 0) {
|
|
1349
1604
|
try {
|
|
1350
|
-
vecHits = await this.vectorSearch(
|
|
1605
|
+
vecHits = await this.vectorSearch(channelInput, poolLimit);
|
|
1351
1606
|
} catch {
|
|
1352
1607
|
vecHits = [];
|
|
1353
1608
|
}
|
|
@@ -1366,6 +1621,24 @@ var SqliteMemoryBackend = class {
|
|
|
1366
1621
|
const reranked = input.rerank === false ? pool : await this.rerankPool(input.query, pool, finalLimit);
|
|
1367
1622
|
return reranked.slice(0, finalLimit);
|
|
1368
1623
|
}
|
|
1624
|
+
/**
|
|
1625
|
+
* M4: rewrite the query for the retrieval channels (HyDE concat). Returns the
|
|
1626
|
+
* input unchanged when no rewriter is configured or it errors/empties.
|
|
1627
|
+
*/
|
|
1628
|
+
async applyRewrite(input) {
|
|
1629
|
+
if (this.rewriter === void 0 || input.rewrite === false)
|
|
1630
|
+
return input;
|
|
1631
|
+
try {
|
|
1632
|
+
const docs = await this.rewriter.rewrite(input.query, { n: 1 });
|
|
1633
|
+
const hyp = docs[0]?.trim();
|
|
1634
|
+
if (hyp)
|
|
1635
|
+
return { ...input, query: `${input.query}
|
|
1636
|
+
|
|
1637
|
+
${hyp}` };
|
|
1638
|
+
} catch {
|
|
1639
|
+
}
|
|
1640
|
+
return input;
|
|
1641
|
+
}
|
|
1369
1642
|
/**
|
|
1370
1643
|
* Reorder a first-stage pool with the cross-encoder reranker, scoring each
|
|
1371
1644
|
* candidate's `key + value` jointly against the query. Returns the pool
|
|
@@ -1601,7 +1874,7 @@ function projectIdFor(workspaceRoot) {
|
|
|
1601
1874
|
return createHash("sha256").update(abs).digest("hex").slice(0, 16);
|
|
1602
1875
|
}
|
|
1603
1876
|
function defaultMemoryDbPath() {
|
|
1604
|
-
return
|
|
1877
|
+
return join2(homedir2(), ".prometheus", "memory.db");
|
|
1605
1878
|
}
|
|
1606
1879
|
function intEnv(env, name, def) {
|
|
1607
1880
|
const raw = env[name];
|
|
@@ -1752,6 +2025,57 @@ function discoverMemoryExtractor(env) {
|
|
|
1752
2025
|
}
|
|
1753
2026
|
throw new Error(`unknown PROMETHEUS_MEMORY_EXTRACT_PROVIDER="${forced}" (expected "none", "mistral", "openai", or "generic")`);
|
|
1754
2027
|
}
|
|
2028
|
+
function discoverMemoryRewriter(env) {
|
|
2029
|
+
const forced = (env.PROMETHEUS_MEMORY_REWRITE_PROVIDER ?? "none").toLowerCase();
|
|
2030
|
+
if (forced === "" || forced === "none")
|
|
2031
|
+
return { id: "none", provider: null };
|
|
2032
|
+
if (forced === "mistral") {
|
|
2033
|
+
const apiKey = env.MISTRAL_API_KEY;
|
|
2034
|
+
if (apiKey === void 0 || apiKey === "") {
|
|
2035
|
+
throw new Error('PROMETHEUS_MEMORY_REWRITE_PROVIDER="mistral" requires MISTRAL_API_KEY.');
|
|
2036
|
+
}
|
|
2037
|
+
return {
|
|
2038
|
+
id: "mistral",
|
|
2039
|
+
provider: new OpenAICompatRewriter({
|
|
2040
|
+
name: "mistral-rewrite",
|
|
2041
|
+
model: env.PROMETHEUS_MEMORY_REWRITE_MODEL ?? "mistral-small-latest",
|
|
2042
|
+
baseUrl: env.MISTRAL_BASE_URL ?? "https://api.mistral.ai/v1",
|
|
2043
|
+
apiKey
|
|
2044
|
+
})
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
if (forced === "openai") {
|
|
2048
|
+
const apiKey = env.OPENAI_API_KEY;
|
|
2049
|
+
if (apiKey === void 0 || apiKey === "") {
|
|
2050
|
+
throw new Error('PROMETHEUS_MEMORY_REWRITE_PROVIDER="openai" requires OPENAI_API_KEY.');
|
|
2051
|
+
}
|
|
2052
|
+
return {
|
|
2053
|
+
id: "openai",
|
|
2054
|
+
provider: new OpenAICompatRewriter({
|
|
2055
|
+
name: "openai-rewrite",
|
|
2056
|
+
model: env.PROMETHEUS_MEMORY_REWRITE_MODEL ?? "gpt-4o-mini",
|
|
2057
|
+
baseUrl: env.OPENAI_BASE_URL ?? "https://api.openai.com/v1",
|
|
2058
|
+
apiKey
|
|
2059
|
+
})
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2062
|
+
if (forced === "generic" || forced === "openai-compat") {
|
|
2063
|
+
const baseUrl = env.PROMETHEUS_MEMORY_REWRITE_ENDPOINT;
|
|
2064
|
+
if (baseUrl === void 0 || baseUrl === "") {
|
|
2065
|
+
throw new Error(`PROMETHEUS_MEMORY_REWRITE_PROVIDER="${forced}" requires PROMETHEUS_MEMORY_REWRITE_ENDPOINT.`);
|
|
2066
|
+
}
|
|
2067
|
+
return {
|
|
2068
|
+
id: "generic",
|
|
2069
|
+
provider: new OpenAICompatRewriter({
|
|
2070
|
+
name: env.PROMETHEUS_MEMORY_REWRITE_NAME ?? "generic-rewrite",
|
|
2071
|
+
model: env.PROMETHEUS_MEMORY_REWRITE_MODEL ?? "default",
|
|
2072
|
+
baseUrl,
|
|
2073
|
+
...env.PROMETHEUS_MEMORY_REWRITE_API_KEY ? { apiKey: env.PROMETHEUS_MEMORY_REWRITE_API_KEY } : {}
|
|
2074
|
+
})
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
throw new Error(`unknown PROMETHEUS_MEMORY_REWRITE_PROVIDER="${forced}" (expected "none", "mistral", "openai", or "generic")`);
|
|
2078
|
+
}
|
|
1755
2079
|
function composeFromEnv(opts) {
|
|
1756
2080
|
const env = opts.env;
|
|
1757
2081
|
const override = (opts.workspaceRootOverride ?? "").trim();
|
|
@@ -1765,9 +2089,11 @@ function composeFromEnv(opts) {
|
|
|
1765
2089
|
const { id: embedderId, embedder } = discoverMemoryEmbedder(env);
|
|
1766
2090
|
const { id: rerankerId, provider: reranker } = discoverMemoryReranker(env);
|
|
1767
2091
|
const { id: extractorId, provider: extractor } = discoverMemoryExtractor(env);
|
|
2092
|
+
const { id: rewriterId, provider: rewriter } = discoverMemoryRewriter(env);
|
|
1768
2093
|
const backend = new SqliteMemoryBackend(dbPath, {
|
|
1769
2094
|
...embedder !== void 0 ? { embedder } : {},
|
|
1770
|
-
...reranker !== null ? { reranker } : {}
|
|
2095
|
+
...reranker !== null ? { reranker } : {},
|
|
2096
|
+
...rewriter !== null ? { rewriter } : {}
|
|
1771
2097
|
});
|
|
1772
2098
|
return {
|
|
1773
2099
|
backend,
|
|
@@ -1781,12 +2107,14 @@ function composeFromEnv(opts) {
|
|
|
1781
2107
|
rerankerId,
|
|
1782
2108
|
extractor,
|
|
1783
2109
|
extractorId,
|
|
2110
|
+
rewriter,
|
|
2111
|
+
rewriterId,
|
|
1784
2112
|
close: () => backend.close()
|
|
1785
2113
|
};
|
|
1786
2114
|
}
|
|
1787
2115
|
|
|
1788
2116
|
// dist/roots.js
|
|
1789
|
-
import { fileURLToPath } from "node:url";
|
|
2117
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1790
2118
|
async function rootFromClient(server, timeoutMs = 2500) {
|
|
1791
2119
|
let supportsRoots = false;
|
|
1792
2120
|
try {
|
|
@@ -1807,7 +2135,7 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
1807
2135
|
const uri = typeof r?.uri === "string" ? r.uri : "";
|
|
1808
2136
|
if (uri.startsWith("file://")) {
|
|
1809
2137
|
try {
|
|
1810
|
-
return
|
|
2138
|
+
return fileURLToPath2(uri);
|
|
1811
2139
|
} catch {
|
|
1812
2140
|
}
|
|
1813
2141
|
}
|
|
@@ -1818,38 +2146,6 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
1818
2146
|
// dist/server.js
|
|
1819
2147
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1820
2148
|
|
|
1821
|
-
// ../shared/dist/types.js
|
|
1822
|
-
var GRAMMAR_LANGUAGE_IDS = [
|
|
1823
|
-
"typescript",
|
|
1824
|
-
"tsx",
|
|
1825
|
-
"javascript",
|
|
1826
|
-
"python",
|
|
1827
|
-
"php",
|
|
1828
|
-
"go",
|
|
1829
|
-
"rust",
|
|
1830
|
-
"java",
|
|
1831
|
-
"csharp",
|
|
1832
|
-
"c",
|
|
1833
|
-
"cpp",
|
|
1834
|
-
"ruby",
|
|
1835
|
-
"kotlin",
|
|
1836
|
-
"html"
|
|
1837
|
-
];
|
|
1838
|
-
var DOCUMENT_LANGUAGE_IDS = [
|
|
1839
|
-
"markdown",
|
|
1840
|
-
"text",
|
|
1841
|
-
"json",
|
|
1842
|
-
"yaml",
|
|
1843
|
-
"toml"
|
|
1844
|
-
];
|
|
1845
|
-
var LANGUAGE_IDS = [
|
|
1846
|
-
...GRAMMAR_LANGUAGE_IDS,
|
|
1847
|
-
...DOCUMENT_LANGUAGE_IDS
|
|
1848
|
-
];
|
|
1849
|
-
|
|
1850
|
-
// ../shared/dist/index.js
|
|
1851
|
-
var PROMETHEUS_VERSION = "0.1.0";
|
|
1852
|
-
|
|
1853
2149
|
// dist/tools.js
|
|
1854
2150
|
import { z } from "zod";
|
|
1855
2151
|
|
|
@@ -1970,8 +2266,8 @@ function assertNoSecrets(text) {
|
|
|
1970
2266
|
|
|
1971
2267
|
// dist/setup.js
|
|
1972
2268
|
import { existsSync } from "node:fs";
|
|
1973
|
-
import { mkdir as
|
|
1974
|
-
import { dirname as dirname2, join as
|
|
2269
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2270
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
1975
2271
|
var MEMORY_RUNTIMES = [
|
|
1976
2272
|
"claude-code",
|
|
1977
2273
|
"cursor",
|
|
@@ -2015,13 +2311,13 @@ alwaysApply: true
|
|
|
2015
2311
|
var TARGETS = {
|
|
2016
2312
|
"claude-code": { relPath: "CLAUDE.md", mode: "block", detect: "CLAUDE.md" },
|
|
2017
2313
|
cursor: {
|
|
2018
|
-
relPath:
|
|
2314
|
+
relPath: join4(".cursor", "rules", "prometheus-memory.mdc"),
|
|
2019
2315
|
mode: "file",
|
|
2020
2316
|
fileContent: CURSOR_FRONTMATTER + withMarkers(RULE_BLOCK) + "\n",
|
|
2021
2317
|
detect: ".cursor"
|
|
2022
2318
|
},
|
|
2023
2319
|
augment: {
|
|
2024
|
-
relPath:
|
|
2320
|
+
relPath: join4(".augment", "rules", "prometheus-memory.md"),
|
|
2025
2321
|
mode: "file",
|
|
2026
2322
|
fileContent: withMarkers(RULE_BLOCK) + "\n",
|
|
2027
2323
|
detect: ".augment"
|
|
@@ -2029,7 +2325,7 @@ var TARGETS = {
|
|
|
2029
2325
|
agents: { relPath: "AGENTS.md", mode: "block", detect: "AGENTS.md" }
|
|
2030
2326
|
};
|
|
2031
2327
|
function detectRuntimes(workspaceRoot) {
|
|
2032
|
-
const found = MEMORY_RUNTIMES.filter((rt) => existsSync(
|
|
2328
|
+
const found = MEMORY_RUNTIMES.filter((rt) => existsSync(join4(workspaceRoot, TARGETS[rt].detect)));
|
|
2033
2329
|
return found.length > 0 ? found : ["agents"];
|
|
2034
2330
|
}
|
|
2035
2331
|
function upsertBlock(existing, block) {
|
|
@@ -2044,15 +2340,15 @@ function upsertBlock(existing, block) {
|
|
|
2044
2340
|
}
|
|
2045
2341
|
async function installRuntime(workspaceRoot, runtime) {
|
|
2046
2342
|
const target = TARGETS[runtime];
|
|
2047
|
-
const absPath =
|
|
2343
|
+
const absPath = join4(workspaceRoot, target.relPath);
|
|
2048
2344
|
const exists = existsSync(absPath);
|
|
2049
|
-
const before = exists ? await
|
|
2345
|
+
const before = exists ? await readFile3(absPath, "utf-8") : "";
|
|
2050
2346
|
const after = target.mode === "file" ? target.fileContent : upsertBlock(before, RULE_BLOCK);
|
|
2051
2347
|
if (exists && before === after) {
|
|
2052
2348
|
return { runtime, path: absPath, action: "unchanged" };
|
|
2053
2349
|
}
|
|
2054
|
-
await
|
|
2055
|
-
await
|
|
2350
|
+
await mkdir3(dirname2(absPath), { recursive: true });
|
|
2351
|
+
await writeFile3(absPath, after, "utf-8");
|
|
2056
2352
|
return { runtime, path: absPath, action: exists ? "updated" : "created" };
|
|
2057
2353
|
}
|
|
2058
2354
|
|
|
@@ -2414,6 +2710,7 @@ async function main() {
|
|
|
2414
2710
|
const explicitRoot = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
|
|
2415
2711
|
const claudeRoot = (env.CLAUDE_PROJECT_DIR ?? "").trim();
|
|
2416
2712
|
const eagerVia = explicitRoot !== "" ? "PROMETHEUS_WORKSPACE_ROOT" : claudeRoot !== "" ? "CLAUDE_PROJECT_DIR" : null;
|
|
2713
|
+
void maybeNotifyUpdate(import.meta.url, env);
|
|
2417
2714
|
const transport = new StdioServerTransport();
|
|
2418
2715
|
const server = new McpServer2(SERVER_IDENTITY, {
|
|
2419
2716
|
capabilities: { tools: {} },
|
|
@@ -2438,7 +2735,7 @@ async function main() {
|
|
|
2438
2735
|
env,
|
|
2439
2736
|
...override !== void 0 && override !== "" ? { workspaceRootOverride: override } : {}
|
|
2440
2737
|
});
|
|
2441
|
-
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}
|
|
2738
|
+
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}
|
|
2442
2739
|
`);
|
|
2443
2740
|
registerTools(server, composed);
|
|
2444
2741
|
};
|