@prom.codes/memory-mcp 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +57 -10
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -194,9 +194,6 @@ function isHomeOrFilesystemRoot(root) {
194
194
  return false;
195
195
  }
196
196
 
197
- // ../shared/dist/index.js
198
- var PROMETHEUS_VERSION = "0.1.0";
199
-
200
197
  // dist/composition.js
201
198
  import { createHash } from "node:crypto";
202
199
  import { homedir as homedir3 } from "node:os";
@@ -876,6 +873,7 @@ var DEFAULT_BASE2 = "https://api.prom.codes";
876
873
  var DEFAULT_NAME = "prometheus";
877
874
  var DEFAULT_MODEL2 = "prometheus";
878
875
  var DEFAULT_BATCH4 = 100;
876
+ var DEFAULT_BATCH_CHARS2 = 4e5;
879
877
  var DEFAULT_RETRIES4 = 4;
880
878
  var DEFAULT_BACKOFF4 = 250;
881
879
  function sleep4(ms, signal) {
@@ -907,6 +905,7 @@ var PrometheusRerankProvider = class {
907
905
  #apiKey;
908
906
  #url;
909
907
  #batchSize;
908
+ #maxBatchChars;
910
909
  #maxRetries;
911
910
  #retryBaseMs;
912
911
  #fetch;
@@ -924,6 +923,7 @@ var PrometheusRerankProvider = class {
924
923
  this.#apiKey = opts.apiKey;
925
924
  this.#url = `${(opts.baseUrl ?? DEFAULT_BASE2).replace(/\/+$/, "")}/rerank`;
926
925
  this.#batchSize = opts.batchSize ?? DEFAULT_BATCH4;
926
+ this.#maxBatchChars = opts.maxBatchChars ?? DEFAULT_BATCH_CHARS2;
927
927
  this.#maxRetries = opts.maxRetries ?? DEFAULT_RETRIES4;
928
928
  this.#retryBaseMs = opts.retryBaseMs ?? DEFAULT_BACKOFF4;
929
929
  this.#fetch = opts.fetch ?? fetch;
@@ -937,21 +937,44 @@ var PrometheusRerankProvider = class {
937
937
  return [];
938
938
  const all = new Array(candidates.length);
939
939
  let cursor = 0;
940
- for (let start = 0; start < candidates.length; start += this.#batchSize) {
941
- const slice = candidates.slice(start, start + this.#batchSize);
940
+ let start = 0;
941
+ while (start < candidates.length) {
942
+ const end = this.#batchEnd(query, candidates, start);
943
+ const slice = candidates.slice(start, end);
942
944
  const scored = await this.#rerankBatch(query, slice, opts?.signal);
943
945
  for (const hit of scored) {
944
946
  const globalIndex = start + hit.localIndex;
945
947
  const cand = candidates[globalIndex];
946
948
  all[cursor++] = { id: cand.id, index: globalIndex, score: hit.score };
947
949
  }
950
+ start = end;
948
951
  }
952
+ all.length = cursor;
949
953
  all.sort((a, b) => b.score - a.score);
950
954
  if (opts?.topK !== void 0 && opts.topK >= 0 && opts.topK < all.length) {
951
955
  return all.slice(0, opts.topK);
952
956
  }
953
957
  return all;
954
958
  }
959
+ /**
960
+ * Greedy batch cut honouring both the document-count cap and the
961
+ * char budget (query + documents must stay under the proxy limit).
962
+ * Always advances by at least one candidate, even if a single
963
+ * document alone exceeds the budget (the proxy applies upstream
964
+ * truncation; refusing to send it would strand the rest).
965
+ */
966
+ #batchEnd(query, candidates, start) {
967
+ let chars = query.length;
968
+ let end = start;
969
+ while (end < candidates.length && end - start < this.#batchSize) {
970
+ const len = candidates[end].text.length;
971
+ if (end > start && chars + len > this.#maxBatchChars)
972
+ break;
973
+ chars += len;
974
+ end += 1;
975
+ }
976
+ return end;
977
+ }
955
978
  async #rerankBatch(query, batch, signal) {
956
979
  const init = {
957
980
  method: "POST",
@@ -2907,14 +2930,16 @@ var setupInput = {
2907
2930
  runtimes: z.array(runtimeEnum).min(1).optional()
2908
2931
  };
2909
2932
  var emptyInput = {};
2910
- function registerTools(server, deps) {
2911
- const { backend, workspaceRoot, projectId, projectName, dbPath, extractor } = deps;
2912
- const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
2933
+ function registerTools(server, source) {
2934
+ const ready = typeof source === "function" ? source : () => Promise.resolve(source);
2913
2935
  server.registerTool("read", {
2914
2936
  title: "Recall agent memory",
2915
2937
  description: "Read agent memory for this project along the scope chain (project \u2192 workspace \u2192 tenant \u2192 system; narrowest scope wins). Syncs `.prometheus/memories/*.md` first, then returns the resolved records plus a prompt-ready `woven` markdown block (token-capped). Call this at the START of a session or task to recall what earlier sessions learned.",
2916
2938
  inputSchema: readInput
2917
2939
  }, async (args) => {
2940
+ const deps = await ready();
2941
+ const { backend, workspaceRoot, projectId, projectName } = deps;
2942
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
2918
2943
  const limit = clampLimit(args.limit, DEFAULT_READ_LIMIT);
2919
2944
  const synced = mirrorToFiles ? await syncProjectFiles(backend, { projectId, workspaceRoot }) : 0;
2920
2945
  const records = await backend.read({
@@ -2935,6 +2960,9 @@ function registerTools(server, deps) {
2935
2960
  description: "Upsert one memory record (identity: scope+type+key). Use type `semantic` for durable facts, `procedural` for how-to knowledge, `episodic` for session events, `working` for short-lived notes. Default scope `project` also mirrors the value to `.prometheus/memories/<key>.md` (git-versioned, human-editable). Values matching the secret deny-list are rejected. Call this whenever the user states a durable preference, decision, or correction worth remembering.",
2936
2961
  inputSchema: writeInput
2937
2962
  }, async (args) => {
2963
+ const deps = await ready();
2964
+ const { backend, workspaceRoot, projectId } = deps;
2965
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
2938
2966
  assertValueSize(args.value);
2939
2967
  assertNoSecrets(`${args.key}
2940
2968
  ${args.value}`);
@@ -2962,6 +2990,7 @@ ${args.value}`);
2962
2990
  description: "Session-end consolidation: `plan`/`outcome` become one episodic record (key = sessionId), `facts` become semantic upserts, `procedures` become procedural upserts. Secret-bearing payloads are rejected. Call this at the END of a session to persist what was learned.",
2963
2991
  inputSchema: captureInput
2964
2992
  }, async (args) => {
2993
+ const { backend, projectId, extractor } = await ready();
2965
2994
  const texts = [
2966
2995
  args.plan ?? "",
2967
2996
  args.outcome ?? "",
@@ -3025,6 +3054,9 @@ ${f.value}`);
3025
3054
  description: "Full-text search (FTS5) over memory keys and values within this project's scope chain, ranked by relevance. Returns matching records plus a highlighted snippet per hit. Use this when memory_read's recall is not specific enough. Does not bump useCount.",
3026
3055
  inputSchema: searchInput
3027
3056
  }, async (args) => {
3057
+ const deps = await ready();
3058
+ const { backend, workspaceRoot, projectId } = deps;
3059
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
3028
3060
  const limit = clampLimit(args.limit, 20);
3029
3061
  if (mirrorToFiles)
3030
3062
  await syncProjectFiles(backend, { projectId, workspaceRoot });
@@ -3048,6 +3080,7 @@ ${f.value}`);
3048
3080
  description: "Flat listing of this project's memory records without scope resolution \u2014 inspection/debug surface. Optional filters: scope, type, keyContains (case-insensitive substring).",
3049
3081
  inputSchema: listInput
3050
3082
  }, async (args) => {
3083
+ const { backend, projectId, projectName, dbPath } = await ready();
3051
3084
  const limit = clampLimit(args.limit, DEFAULT_READ_LIMIT);
3052
3085
  const records = await backend.list({
3053
3086
  projectId,
@@ -3068,6 +3101,9 @@ ${f.value}`);
3068
3101
  description: "Delete one memory record by identity (scope+type+key). For project-scoped semantic records the mirrored `.prometheus/memories/<key>.md` file is removed as well. Returns whether a record/file was actually removed.",
3069
3102
  inputSchema: deleteInput
3070
3103
  }, async (args) => {
3104
+ const deps = await ready();
3105
+ const { backend, workspaceRoot, projectId } = deps;
3106
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
3071
3107
  const scope = args.scope;
3072
3108
  const removed = await backend.delete({
3073
3109
  projectId,
@@ -3087,6 +3123,9 @@ ${f.value}`);
3087
3123
  description: "Idempotently install the Prometheus memory-protocol rule block into agent runtime configs in this workspace: CLAUDE.md (claude-code), .cursor/rules/prometheus-memory.mdc (cursor), .augment/rules/prometheus-memory.md (augment), AGENTS.md (agents). Without `runtimes` it auto-detects which runtimes are present (fallback: agents). Only the marked block is written \u2014 existing content is never touched. Re-running updates the block in place.",
3088
3124
  inputSchema: setupInput
3089
3125
  }, async (args) => {
3126
+ const deps = await ready();
3127
+ const { workspaceRoot } = deps;
3128
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
3090
3129
  if (!mirrorToFiles) {
3091
3130
  return textResult({
3092
3131
  workspaceRoot,
@@ -3106,6 +3145,9 @@ ${f.value}`);
3106
3145
  description: "Health check for this project's agent memory. Reports the resolved workspace root, project id, DB path, how many records are stored (total + by scope), the embedding provider with a zero-cost key-reachability probe, and which quality levers are active (rerank / rewrite / temporal). CALL THIS to confirm where memory is stored, how much is there, and whether the API key works.",
3107
3146
  inputSchema: emptyInput
3108
3147
  }, async () => {
3148
+ const deps = await ready();
3149
+ const { backend, workspaceRoot, projectId, projectName, dbPath } = deps;
3150
+ const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
3109
3151
  const stats = await backend.stats(projectId);
3110
3152
  let embeddingsReachable = null;
3111
3153
  let embeddingsError = null;
@@ -3153,7 +3195,7 @@ ${f.value}`);
3153
3195
  // dist/server.js
3154
3196
  var SERVER_IDENTITY = {
3155
3197
  name: "prometheus-memory-mcp",
3156
- version: PROMETHEUS_VERSION,
3198
+ version: "0.10.2",
3157
3199
  title: "prom.codes Memory"
3158
3200
  };
3159
3201
  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.";
@@ -3175,6 +3217,11 @@ async function main() {
3175
3217
  instructions: SERVER_INSTRUCTIONS
3176
3218
  });
3177
3219
  let composed = null;
3220
+ let composedResolve;
3221
+ const composedReady = new Promise((res) => {
3222
+ composedResolve = res;
3223
+ });
3224
+ registerTools(server, () => composedReady);
3178
3225
  const shutdown = async (signal) => {
3179
3226
  process.stderr.write(`prometheus-memory-mcp: received ${signal}, shutting down
3180
3227
  `);
@@ -3208,7 +3255,7 @@ async function main() {
3208
3255
  }).catch(() => {
3209
3256
  });
3210
3257
  }
3211
- registerTools(server, composed);
3258
+ composedResolve(composed);
3212
3259
  };
3213
3260
  if (eagerVia !== null) {
3214
3261
  boot(void 0, eagerVia);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prom.codes/memory-mcp",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "prom.codes Memory — persistent, local-first agent memory as an MCP server.",
5
5
  "type": "module",
6
6
  "bin": {