memory-pulse 0.2.0 → 0.2.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/package.json +1 -1
- package/server.mjs +18 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-pulse",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Causal memory for coding agents that costs ~670 tokens, not your context window. Four MCP tools: re-enter a project, recall what caused what, record findings, run code against memory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/server.mjs
CHANGED
|
@@ -52,18 +52,18 @@ function readEvents() {
|
|
|
52
52
|
return { path, events };
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// The engine's
|
|
55
|
+
// The engine's memory-safety checks, mirrored so a refusal happens
|
|
56
56
|
// before the write. Keep in step with the engine; the engine is authoritative.
|
|
57
57
|
const INSTRUCTION_PATTERNS = [
|
|
58
|
-
["
|
|
59
|
-
["
|
|
60
|
-
["
|
|
61
|
-
["
|
|
62
|
-
["
|
|
63
|
-
["
|
|
64
|
-
["
|
|
65
|
-
["
|
|
66
|
-
["
|
|
58
|
+
["protect-instructions", /\b(ignore|disregard|forget)\b[^.\n]{0,40}\b(previous|prior|above|all|earlier)\b[^.\n]{0,20}\b(instructions?|rules?|prompts?)\b/i],
|
|
59
|
+
["protect-role", /\byou are now\b|\bfrom now on,? you\b|\bact as (an?|the) (system|admin|developer)\b/i],
|
|
60
|
+
["protect-boundaries", /<\/?\s*(system|assistant|tool|user|human|developer)\s*>|\[(system|assistant|tool)\s*:?\s*\]/i],
|
|
61
|
+
["protect-configuration", /\b(reveal|print|show|dump)\b[^.\n]{0,30}\b(system prompt|hidden prompt|your instructions)\b/i],
|
|
62
|
+
["protect-execution", /\b(run|execute|paste)\b[^.\n]{0,25}\b(this|the following)\b[^.\n]{0,15}\b(command|script|shell|code)\b/i],
|
|
63
|
+
["protect-installs", /\b(curl|wget)\b[^\n]{0,120}\|\s*(sudo\s+)?(sh|bash|zsh)\b/i],
|
|
64
|
+
["protect-data", /\b(rm\s+-rf\s+[\/~]|drop\s+table|truncate\s+table|format\s+c:)/i],
|
|
65
|
+
["protect-credentials", /\b(send|post|upload|exfiltrat\w*|leak|forward|email)\b[^.\n]{0,40}\b(api[\s_-]?keys?|secrets?|tokens?|passwords?|credentials?)\b[^.\n]{0,40}\b(to|via|at)\b[^.\n]{0,4}(https?:\/\/|[\w.-]+@[\w.-]+\b|this\b|the following\b|that (address|url|endpoint|server)\b|me\b)|\b(send|give|show|tell) me\b[^.\n]{0,30}\b(api[\s_-]?keys?|secrets?|tokens?|passwords?|credentials?)\b/i ],
|
|
66
|
+
["protect-transparency", /\b(do not|don't|never)\b[^.\n]{0,20}\b(tell|show|mention|reveal)\b[^.\n]{0,20}\b(the )?(user|human|operator)\b/i],
|
|
67
67
|
];
|
|
68
68
|
export function instructionLike(text) {
|
|
69
69
|
if (typeof text !== "string" || !text) return [];
|
|
@@ -129,7 +129,10 @@ const fmtK = (n) => (n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : n >= 10
|
|
|
129
129
|
export function telemetryFooter(c) {
|
|
130
130
|
const k = c?.counters;
|
|
131
131
|
if (!k || !k.calls) return "";
|
|
132
|
-
|
|
132
|
+
// Quarantine is printed on its own line by the brief; the footer carries
|
|
133
|
+
// the drift reasons that are actually about the ledger changing.
|
|
134
|
+
const reasons = (c.drift?.reasons ?? []).filter((r) => !/quarantined/.test(r));
|
|
135
|
+
const drift = reasons.length ? ` · ⚠ drift: ${reasons.join("; ")}` : "";
|
|
133
136
|
return `— memory-pulse · ${k.pulse} re-entries · ${k.correctionsSurfaced} corrections surfaced · ~${fmtK(k.tokensSavedEst)} tokens saved (est., signed)${drift}`;
|
|
134
137
|
}
|
|
135
138
|
|
|
@@ -154,8 +157,10 @@ function writeMemoryKey(k) {
|
|
|
154
157
|
writeFileSync(memoryKeyPath(), JSON.stringify(k));
|
|
155
158
|
// The ledger is the source of truth; the key is a rebuildable cache and
|
|
156
159
|
// has no business in version control.
|
|
160
|
+
// Only in the default layout: a custom ledger directory is the user's to
|
|
161
|
+
// manage, and this client does not leave files in it uninvited.
|
|
157
162
|
const gi = join(dir, ".gitignore");
|
|
158
|
-
if (!existsSync(gi)) writeFileSync(gi, "memory.rain\n");
|
|
163
|
+
if (dir.endsWith(".memory-pulse") && !existsSync(gi)) writeFileSync(gi, "memory.rain\n");
|
|
159
164
|
} catch { /* a read-only checkout must not break a read call */ }
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -325,7 +330,7 @@ async function dispatch(msg) {
|
|
|
325
330
|
return ok(id, {
|
|
326
331
|
protocolVersion: SUPPORTED.includes(wanted) ? wanted : SUPPORTED[0],
|
|
327
332
|
capabilities: { tools: {} },
|
|
328
|
-
serverInfo: { name: "memory-pulse", version: "0.2.
|
|
333
|
+
serverInfo: { name: "memory-pulse", version: "0.2.1" },
|
|
329
334
|
});
|
|
330
335
|
}
|
|
331
336
|
if (method === "notifications/initialized" || method === "initialized") return;
|