@prom.codes/memory-mcp 0.11.0 → 0.11.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 +80 -8
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -89,6 +89,9 @@ function isNewerVersion(latest, current) {
|
|
|
89
89
|
return true;
|
|
90
90
|
return false;
|
|
91
91
|
}
|
|
92
|
+
function cachedLatestIsStale(cachedLatest, minVersion) {
|
|
93
|
+
return minVersion !== void 0 && cachedLatest !== null && isNewerVersion(minVersion, cachedLatest);
|
|
94
|
+
}
|
|
92
95
|
function cachePath(dir, name) {
|
|
93
96
|
const safe = name.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
94
97
|
return join(dir, `.update-check-${safe}.json`);
|
|
@@ -175,7 +178,7 @@ async function checkForUpdate(options) {
|
|
|
175
178
|
const now = Date.now();
|
|
176
179
|
if (!force) {
|
|
177
180
|
const cached = await readCache(file);
|
|
178
|
-
if (cached !== null && now - cached.checkedAt < cacheTtlMs) {
|
|
181
|
+
if (cached !== null && now - cached.checkedAt < cacheTtlMs && !cachedLatestIsStale(cached.latest, version)) {
|
|
179
182
|
const updateAvailable2 = cached.latest !== null && isNewerVersion(cached.latest, version);
|
|
180
183
|
if (updateAvailable2)
|
|
181
184
|
notify(log, name, version, cached.latest);
|
|
@@ -202,15 +205,16 @@ async function checkForUpdate(options) {
|
|
|
202
205
|
return { ...base, latest, checked: true, updateAvailable };
|
|
203
206
|
}
|
|
204
207
|
async function getLatestVersion(name, options = {}) {
|
|
205
|
-
const { env = process.env, fetch: fetchImpl = globalThis.fetch, cacheDir = join(homedir(), ".prometheus"), cacheTtlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
|
|
208
|
+
const { env = process.env, fetch: fetchImpl = globalThis.fetch, cacheDir = join(homedir(), ".prometheus"), cacheTtlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS, minVersion } = options;
|
|
206
209
|
const file = cachePath(cacheDir, name);
|
|
207
210
|
const cached = await readCache(file);
|
|
208
211
|
const now = Date.now();
|
|
209
|
-
|
|
212
|
+
const stale = cachedLatestIsStale(cached?.latest ?? null, minVersion);
|
|
213
|
+
if (cached !== null && cached.latest !== null && now - cached.checkedAt < cacheTtlMs && !stale) {
|
|
210
214
|
return cached.latest;
|
|
211
215
|
}
|
|
212
216
|
if (OPT_OUT_RE.test(env.PROMETHEUS_NO_UPDATE_CHECK ?? "") || typeof fetchImpl !== "function") {
|
|
213
|
-
return cached?.latest ?? null;
|
|
217
|
+
return stale ? null : cached?.latest ?? null;
|
|
214
218
|
}
|
|
215
219
|
const latest = await fetchLatest(name, fetchImpl, timeoutMs);
|
|
216
220
|
if (latest !== null) {
|
|
@@ -218,7 +222,7 @@ async function getLatestVersion(name, options = {}) {
|
|
|
218
222
|
await writeCache(file, { checkedAt: now, latest });
|
|
219
223
|
return latest;
|
|
220
224
|
}
|
|
221
|
-
return cached?.latest ?? null;
|
|
225
|
+
return stale ? null : cached?.latest ?? null;
|
|
222
226
|
}
|
|
223
227
|
function notify(log, name, current, latest) {
|
|
224
228
|
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.)
|
|
@@ -242,7 +246,8 @@ async function buildUpdateStatus(pkgName, currentVersion, options = {}) {
|
|
|
242
246
|
...options.env !== void 0 ? { env: options.env } : {},
|
|
243
247
|
...options.fetch !== void 0 ? { fetch: options.fetch } : {},
|
|
244
248
|
...options.cacheDir !== void 0 ? { cacheDir: options.cacheDir } : {},
|
|
245
|
-
timeoutMs: options.timeoutMs ?? 1500
|
|
249
|
+
timeoutMs: options.timeoutMs ?? 1500,
|
|
250
|
+
minVersion: currentVersion
|
|
246
251
|
});
|
|
247
252
|
} catch {
|
|
248
253
|
latest = null;
|
|
@@ -338,6 +343,57 @@ function startHeartbeat(options) {
|
|
|
338
343
|
};
|
|
339
344
|
}
|
|
340
345
|
|
|
346
|
+
// ../shared/dist/idle-watchdog.js
|
|
347
|
+
var DEFAULT_IDLE_EXIT_MS = 30 * 6e4;
|
|
348
|
+
var IDLE_CHECK_INTERVAL_MS = 6e4;
|
|
349
|
+
var IDLE_EXIT_ENV = "PROMETHEUS_IDLE_EXIT_MS";
|
|
350
|
+
function parseIdleExitMs(env) {
|
|
351
|
+
const raw = (env[IDLE_EXIT_ENV] ?? "").trim();
|
|
352
|
+
if (raw === "")
|
|
353
|
+
return void 0;
|
|
354
|
+
const n = Number(raw);
|
|
355
|
+
return Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
356
|
+
}
|
|
357
|
+
function createIdleWatchdog(options) {
|
|
358
|
+
const env = options.env ?? process.env;
|
|
359
|
+
const idleMs = options.idleMs ?? parseIdleExitMs(env) ?? DEFAULT_IDLE_EXIT_MS;
|
|
360
|
+
const now = options.now ?? Date.now;
|
|
361
|
+
const checkIntervalMs = options.checkIntervalMs ?? Math.max(1e3, Math.min(IDLE_CHECK_INTERVAL_MS, idleMs));
|
|
362
|
+
if (!(idleMs > 0)) {
|
|
363
|
+
return { touch() {
|
|
364
|
+
}, stop() {
|
|
365
|
+
}, idleMs: 0 };
|
|
366
|
+
}
|
|
367
|
+
let lastActivity = now();
|
|
368
|
+
let stopped = false;
|
|
369
|
+
let fired = false;
|
|
370
|
+
const timer = setInterval(() => {
|
|
371
|
+
if (stopped || fired)
|
|
372
|
+
return;
|
|
373
|
+
const idleFor = now() - lastActivity;
|
|
374
|
+
if (idleFor >= idleMs) {
|
|
375
|
+
fired = true;
|
|
376
|
+
clearInterval(timer);
|
|
377
|
+
options.onIdle(`idle for ${Math.round(idleFor / 1e3)}s with no client activity (set ${IDLE_EXIT_ENV}=0 to disable)`);
|
|
378
|
+
}
|
|
379
|
+
}, checkIntervalMs);
|
|
380
|
+
timer.unref?.();
|
|
381
|
+
return {
|
|
382
|
+
idleMs,
|
|
383
|
+
touch() {
|
|
384
|
+
if (stopped)
|
|
385
|
+
return;
|
|
386
|
+
lastActivity = now();
|
|
387
|
+
},
|
|
388
|
+
stop() {
|
|
389
|
+
if (stopped)
|
|
390
|
+
return;
|
|
391
|
+
stopped = true;
|
|
392
|
+
clearInterval(timer);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
341
397
|
// dist/composition.js
|
|
342
398
|
import { createHash } from "node:crypto";
|
|
343
399
|
import { homedir as homedir4 } from "node:os";
|
|
@@ -3315,7 +3371,7 @@ ${f.value}`);
|
|
|
3315
3371
|
embeddingsError = err instanceof Error ? err.message : String(err);
|
|
3316
3372
|
}
|
|
3317
3373
|
}
|
|
3318
|
-
const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.11.
|
|
3374
|
+
const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.11.1", { isDevBuild: false });
|
|
3319
3375
|
const summary = deps.rootIsHomeOrFsRoot ? `Memory at ${dbPath}: ${stats.total} records, but the workspace resolved to ${workspaceRoot} (home/root) \u2014 open a project folder so memories scope and mirror correctly.` : `Memory at ${dbPath}: ${stats.total} records for project "${projectName}".${update.updateAvailable === true ? ` Update available: ${update.current} \u2192 ${update.latest} (ask me to run update via the context server's update_servers tool).` : ""}`;
|
|
3320
3376
|
return textResult({
|
|
3321
3377
|
installed: true,
|
|
@@ -3351,7 +3407,7 @@ ${f.value}`);
|
|
|
3351
3407
|
// dist/server.js
|
|
3352
3408
|
var SERVER_IDENTITY = {
|
|
3353
3409
|
name: "prometheus-memory-mcp",
|
|
3354
|
-
version: "0.11.
|
|
3410
|
+
version: "0.11.1",
|
|
3355
3411
|
title: "prom.codes Memory"
|
|
3356
3412
|
};
|
|
3357
3413
|
var SERVER_INSTRUCTIONS = "Persistent agent memory for this workspace \u2014 USE IT PROACTIVELY; the user will not tell you to. Protocol:\n1. ONE-TIME: if this workspace has no Prometheus memory rule yet, call memory_setup now (idempotent) so the protocol is installed into the runtime rule files and survives future sessions. (The server also auto-installs it on startup when a project rule file already exists \u2014 memory_setup covers the rest.)\n2. SESSION START: before any non-trivial task, call memory_read to recall facts, decisions and procedures from earlier sessions.\n3. DURING WORK: when the user states a durable preference, decision, correction or project fact, store it with memory_write (semantic for facts, procedural for how-tos) \u2014 without being asked.\n4. LOOK-UP: use memory_search for keyword recall when memory_read is not specific enough.\n5. SESSION END: consolidate what was learned with memory_capture.\nCall memory_status anytime to check what is stored and whether the rule is installed. Never store secrets, API keys or credentials \u2014 such writes are rejected.";
|
|
@@ -3385,6 +3441,7 @@ async function main() {
|
|
|
3385
3441
|
registerTools(server, () => composedReady, {
|
|
3386
3442
|
onToolCall: (tool) => heartbeat.update({ lastTool: tool, lastToolCallAt: Date.now() })
|
|
3387
3443
|
});
|
|
3444
|
+
let watchdog = null;
|
|
3388
3445
|
let shuttingDown = false;
|
|
3389
3446
|
const shutdown = async (reason) => {
|
|
3390
3447
|
if (shuttingDown)
|
|
@@ -3392,6 +3449,7 @@ async function main() {
|
|
|
3392
3449
|
shuttingDown = true;
|
|
3393
3450
|
process.stderr.write(`prometheus-memory-mcp: ${reason}, shutting down
|
|
3394
3451
|
`);
|
|
3452
|
+
watchdog?.stop();
|
|
3395
3453
|
heartbeat.stop();
|
|
3396
3454
|
try {
|
|
3397
3455
|
await server.close();
|
|
@@ -3406,6 +3464,18 @@ async function main() {
|
|
|
3406
3464
|
process.stdin.once("end", () => void shutdown("stdin closed (client exited)"));
|
|
3407
3465
|
process.stdin.once("close", () => void shutdown("stdin closed (client exited)"));
|
|
3408
3466
|
server.server.onclose = () => void shutdown("transport closed (client exited)");
|
|
3467
|
+
watchdog = createIdleWatchdog({ onIdle: (reason) => void shutdown(reason), env });
|
|
3468
|
+
if (watchdog.idleMs > 0) {
|
|
3469
|
+
process.stderr.write(`prometheus-memory-mcp: idle self-exit armed (${Math.round(watchdog.idleMs / 6e4)} min of no client activity)
|
|
3470
|
+
`);
|
|
3471
|
+
}
|
|
3472
|
+
const armIdleWatch = () => {
|
|
3473
|
+
const prev = transport.onmessage?.bind(transport);
|
|
3474
|
+
transport.onmessage = ((...args) => {
|
|
3475
|
+
watchdog?.touch();
|
|
3476
|
+
prev?.(...args);
|
|
3477
|
+
});
|
|
3478
|
+
};
|
|
3409
3479
|
const boot = (override, via) => {
|
|
3410
3480
|
composed = composeFromEnv({
|
|
3411
3481
|
env,
|
|
@@ -3440,6 +3510,7 @@ async function main() {
|
|
|
3440
3510
|
if (eagerVia !== null) {
|
|
3441
3511
|
boot(void 0, eagerVia);
|
|
3442
3512
|
await server.connect(transport);
|
|
3513
|
+
armIdleWatch();
|
|
3443
3514
|
return;
|
|
3444
3515
|
}
|
|
3445
3516
|
let booted = false;
|
|
@@ -3463,6 +3534,7 @@ async function main() {
|
|
|
3463
3534
|
void resolveAndBoot();
|
|
3464
3535
|
};
|
|
3465
3536
|
await server.connect(transport);
|
|
3537
|
+
armIdleWatch();
|
|
3466
3538
|
const t = setTimeout(() => void resolveAndBoot(), 5e3);
|
|
3467
3539
|
t.unref?.();
|
|
3468
3540
|
}
|