@prom.codes/memory-mcp 0.15.1 → 0.15.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 +75 -9
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -2688,7 +2688,8 @@ var SqliteMemoryBackend = class {
2688
2688
  const rows = this.db.prepare(sql).all(...params);
2689
2689
  const resolved = resolveScopeChain(rows.map(rowToRecord), query.chain);
2690
2690
  const deduped = this.dedupeRecords(resolved);
2691
- const limited = query.limit !== void 0 ? deduped.slice(0, query.limit) : deduped;
2691
+ const offset = query.offset ?? 0;
2692
+ const limited = query.limit !== void 0 ? deduped.slice(offset, offset + query.limit) : deduped.slice(offset);
2692
2693
  const bump = this.db.prepare(`UPDATE agent_memory SET use_count = use_count + 1 WHERE id = ?`);
2693
2694
  for (const rec of limited) {
2694
2695
  bump.run(rec.id);
@@ -3984,8 +3985,10 @@ function weave(records, options = {}) {
3984
3985
 
3985
3986
  // dist/tools.js
3986
3987
  var MAX_LIMIT = 100;
3987
- var DEFAULT_READ_LIMIT = 50;
3988
+ var DEFAULT_READ_LIMIT = 25;
3988
3989
  var MAX_VALUE_CHARS = 64 * 1024;
3990
+ var RECORDS_TOKEN_BUDGET = 5e3;
3991
+ var MAX_VALUE_CHARS_IN_VIEW = 4e3;
3989
3992
  function textResult(payload) {
3990
3993
  return {
3991
3994
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
@@ -4009,6 +4012,52 @@ function recordToJson(rec) {
4009
4012
  updatedAt: rec.updatedAt
4010
4013
  };
4011
4014
  }
4015
+ function recordToJsonPreview(rec, maxValueChars) {
4016
+ const view = recordToJson(rec);
4017
+ if (rec.value.length > maxValueChars) {
4018
+ const omitted = rec.value.length - maxValueChars;
4019
+ view.value = `${rec.value.slice(0, maxValueChars)}
4020
+ \u2026[+${omitted} chars omitted \u2014 use \`search\` for the full value]`;
4021
+ view.valueTruncated = true;
4022
+ view.valueChars = rec.value.length;
4023
+ }
4024
+ return view;
4025
+ }
4026
+ function boundRecordsForResult(records) {
4027
+ const views = [];
4028
+ let valuesPreviewed = 0;
4029
+ let tokens = 0;
4030
+ let overBudget = false;
4031
+ for (const rec of records) {
4032
+ const view = recordToJsonPreview(rec, MAX_VALUE_CHARS_IN_VIEW);
4033
+ if (view.valueTruncated === true)
4034
+ valuesPreviewed += 1;
4035
+ const cost = estimateTokens(JSON.stringify(view));
4036
+ if (views.length > 0 && tokens + cost > RECORDS_TOKEN_BUDGET) {
4037
+ overBudget = true;
4038
+ break;
4039
+ }
4040
+ views.push(view);
4041
+ tokens += cost;
4042
+ }
4043
+ return { views, shown: views.length, fetched: records.length, valuesPreviewed, overBudget };
4044
+ }
4045
+ function boundedRecordsNote(b, opts) {
4046
+ if (!b.overBudget && b.valuesPreviewed === 0 && b.fetched < opts.limit)
4047
+ return void 0;
4048
+ const parts = [];
4049
+ if (b.overBudget) {
4050
+ parts.push(`Showing ${b.shown} of ${b.fetched} fetched records \u2014 the result was trimmed to stay under the token budget. The \`woven\` block already carries the highest-value facts within its own cap.`);
4051
+ }
4052
+ if (b.valuesPreviewed > 0) {
4053
+ parts.push(`${b.valuesPreviewed} value(s) previewed to ${MAX_VALUE_CHARS_IN_VIEW} chars.`);
4054
+ }
4055
+ if (b.fetched >= opts.limit) {
4056
+ parts.push(`More records may exist beyond limit=${opts.limit}.`);
4057
+ }
4058
+ parts.push(`To see more: narrow with \`types\`, page with \`offset\` (e.g. offset=${(opts.offset ?? 0) + b.shown}), raise \`limit\`, or use \`search\` for specific facts.`);
4059
+ return parts.join(" ");
4060
+ }
4012
4061
  function clampLimit(limit, def) {
4013
4062
  if (limit === void 0)
4014
4063
  return def;
@@ -4026,7 +4075,9 @@ var scopeEnum = z.enum(MEMORY_SCOPES);
4026
4075
  var typeEnum = z.enum(MEMORY_TYPES);
4027
4076
  var readInput = {
4028
4077
  types: z.array(typeEnum).min(1).optional(),
4029
- limit: z.number().int().positive().max(MAX_LIMIT).optional()
4078
+ limit: z.number().int().positive().max(MAX_LIMIT).optional(),
4079
+ /** Skip the first N resolved records — page through large memory sets. */
4080
+ offset: z.number().int().nonnegative().optional()
4030
4081
  };
4031
4082
  var writeInput = {
4032
4083
  scope: scopeEnum.optional(),
@@ -4113,19 +4164,23 @@ function registerTools(server, source, hooks = {}) {
4113
4164
  }));
4114
4165
  reg("read", {
4115
4166
  title: "Recall agent memory",
4116
- 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.",
4167
+ 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). The `records` array is bounded to a token budget; a `note` explains how to page (`offset`) or narrow (`types`, `search`) when trimmed. Call this at the START of a session or task to recall what earlier sessions learned.",
4117
4168
  inputSchema: readInput
4118
4169
  }, async (args) => {
4119
4170
  const deps = await ready();
4120
4171
  const { backend, workspaceRoot, projectId, projectName } = deps;
4121
4172
  const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
4122
4173
  const limit = clampLimit(args.limit, DEFAULT_READ_LIMIT);
4174
+ const offset = args.offset ?? 0;
4123
4175
  const sync = mirrorToFiles ? await syncProjectFiles(backend, { projectId, workspaceRoot }) : { synced: 0, pruned: 0, skipped: [] };
4124
4176
  const records = await backend.read({
4125
4177
  chain: defaultScopeChain(projectId),
4126
4178
  types: args.types,
4127
- limit
4179
+ limit,
4180
+ offset
4128
4181
  });
4182
+ const bounded = boundRecordsForResult(records);
4183
+ const note = boundedRecordsNote(bounded, { limit, offset });
4129
4184
  return textResult({
4130
4185
  projectId,
4131
4186
  projectName,
@@ -4133,7 +4188,12 @@ function registerTools(server, source, hooks = {}) {
4133
4188
  projectFilesPruned: sync.pruned,
4134
4189
  ...sync.skipped.length > 0 ? { skippedFiles: sync.skipped } : {},
4135
4190
  woven: weave(records),
4136
- records: records.map(recordToJson)
4191
+ recordsShown: bounded.shown,
4192
+ recordsFetched: bounded.fetched,
4193
+ limit,
4194
+ offset,
4195
+ ...note !== void 0 ? { note } : {},
4196
+ records: bounded.views
4137
4197
  });
4138
4198
  });
4139
4199
  reg("write", {
@@ -4285,11 +4345,17 @@ ${f.value}`);
4285
4345
  keyContains: args.keyContains,
4286
4346
  limit
4287
4347
  });
4348
+ const bounded = boundRecordsForResult(records);
4349
+ const note = boundedRecordsNote(bounded, { limit });
4288
4350
  return textResult({
4289
4351
  projectId,
4290
4352
  projectName,
4291
4353
  dbPath,
4292
- records: records.map(recordToJson)
4354
+ recordsShown: bounded.shown,
4355
+ recordsFetched: bounded.fetched,
4356
+ limit,
4357
+ ...note !== void 0 ? { note } : {},
4358
+ records: bounded.views
4293
4359
  });
4294
4360
  });
4295
4361
  reg("delete", {
@@ -4433,7 +4499,7 @@ ${f.value}`);
4433
4499
  embeddingsError = err instanceof Error ? err.message : String(err);
4434
4500
  }
4435
4501
  }
4436
- const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.15.1", { isDevBuild: false });
4502
+ const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.15.2", { isDevBuild: false });
4437
4503
  let recorder;
4438
4504
  try {
4439
4505
  const scopes = ["project-local", "project", "user"];
@@ -4515,7 +4581,7 @@ ${f.value}`);
4515
4581
  // dist/server.js
4516
4582
  var SERVER_IDENTITY = {
4517
4583
  name: "prometheus-memory-mcp",
4518
- version: "0.15.1",
4584
+ version: "0.15.2",
4519
4585
  title: "prom.codes Memory"
4520
4586
  };
4521
4587
  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.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prom.codes/memory-mcp",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "prom.codes Memory — persistent, local-first agent memory as an MCP server.",
5
5
  "type": "module",
6
6
  "bin": {