memory-pulse 0.1.1 → 0.1.3
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/README.md +4 -0
- package/package.json +4 -3
- package/server.mjs +48 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# memory-pulse
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/memory-pulse)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://github.com/t-crew/memory-pulse)
|
|
6
|
+
|
|
3
7
|
Causal project memory for coding agents — built for the thing MCP memory
|
|
4
8
|
servers usually get wrong: **the cost of having it installed.**
|
|
5
9
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-pulse",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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": {
|
|
7
|
-
"memory-pulse": "
|
|
7
|
+
"memory-pulse": "server.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"server.mjs",
|
|
@@ -32,5 +32,6 @@
|
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=18"
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
|
+
"mcpName": "io.github.t-crew/memory-pulse"
|
|
36
37
|
}
|
package/server.mjs
CHANGED
|
@@ -63,7 +63,10 @@ function appendEvent({ cause, effect, note, kind, tags, pinned }) {
|
|
|
63
63
|
if (Array.isArray(tags) && tags.length) event.tags = tags;
|
|
64
64
|
if (pinned) event.pinned = true;
|
|
65
65
|
appendFileSync(path, JSON.stringify(event) + "\n");
|
|
66
|
-
|
|
66
|
+
// Echo the canonical stored event back. A shell-quoting accident once ate a
|
|
67
|
+
// word from a note SILENTLY; the caller must be able to see what the ledger
|
|
68
|
+
// actually holds without re-reading the file.
|
|
69
|
+
return { written: true, t, ledger: path, stored: event };
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
// ------------------------------------------------------------------- api ----
|
|
@@ -187,7 +190,7 @@ async function dispatch(msg) {
|
|
|
187
190
|
return ok(id, {
|
|
188
191
|
protocolVersion: SUPPORTED.includes(wanted) ? wanted : SUPPORTED[0],
|
|
189
192
|
capabilities: { tools: {} },
|
|
190
|
-
serverInfo: { name: "memory-pulse", version: "0.1.
|
|
193
|
+
serverInfo: { name: "memory-pulse", version: "0.1.3" },
|
|
191
194
|
});
|
|
192
195
|
}
|
|
193
196
|
if (method === "notifications/initialized" || method === "initialized") return;
|
|
@@ -205,6 +208,45 @@ async function dispatch(msg) {
|
|
|
205
208
|
if (id !== undefined) fail(id, -32601, `method not found: ${method}`);
|
|
206
209
|
}
|
|
207
210
|
|
|
211
|
+
// ------------------------------------------------------------------ cli ----
|
|
212
|
+
// `npx memory-pulse brief` — print the re-entry brief and exit. Built for
|
|
213
|
+
// SessionStart hooks: SILENT no-op (exit 0) when the project has no ledger,
|
|
214
|
+
// so installing the hook never adds noise to projects that don't use this.
|
|
215
|
+
async function cliBrief() {
|
|
216
|
+
const { events } = readEvents();
|
|
217
|
+
if (!events.length) return;
|
|
218
|
+
try {
|
|
219
|
+
const out = await callApi("/v1/pulse", { events, tier: process.env.MEMORY_PULSE_BRIEF_TIER || "brief" });
|
|
220
|
+
if (out.text) process.stdout.write(out.text + "\n");
|
|
221
|
+
} catch (e) {
|
|
222
|
+
// A dead network must not break session start — say so in one line.
|
|
223
|
+
process.stdout.write(`memory-pulse: brief unavailable (${String(e?.message ?? e).split(".")[0]})\n`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// `npx memory-pulse install-hook` — make re-entry automatic: a Claude Code
|
|
228
|
+
// SessionStart hook that runs the brief. Idempotent; merges, never clobbers.
|
|
229
|
+
function cliInstallHook() {
|
|
230
|
+
const home = process.env.MEMORY_PULSE_SETTINGS_DIR || join(process.env.HOME || "", ".claude");
|
|
231
|
+
const file = join(home, "settings.json");
|
|
232
|
+
let settings = {};
|
|
233
|
+
if (existsSync(file)) {
|
|
234
|
+
try { settings = JSON.parse(readFileSync(file, "utf8")); }
|
|
235
|
+
catch { console.error(`refusing to touch ${file}: it is not valid JSON`); process.exit(1); }
|
|
236
|
+
}
|
|
237
|
+
const CMD = "npx -y memory-pulse brief";
|
|
238
|
+
settings.hooks = settings.hooks || {};
|
|
239
|
+
const list = (settings.hooks.SessionStart = settings.hooks.SessionStart || []);
|
|
240
|
+
const present = JSON.stringify(list).includes(CMD);
|
|
241
|
+
if (present) { console.log("hook already installed — nothing to do"); return; }
|
|
242
|
+
list.push({ hooks: [{ type: "command", command: CMD }] });
|
|
243
|
+
mkdirSync(home, { recursive: true });
|
|
244
|
+
writeFileSync(file, JSON.stringify(settings, null, 2) + "\n");
|
|
245
|
+
console.log(`installed SessionStart hook in ${file}`);
|
|
246
|
+
console.log("Every Claude Code session now re-enters through the ledger automatically.");
|
|
247
|
+
console.log("Remove it any time by deleting the memory-pulse entry from hooks.SessionStart.");
|
|
248
|
+
}
|
|
249
|
+
|
|
208
250
|
// Importable for tests; the transport runs only when this file is the entry
|
|
209
251
|
// point. Compared by REALPATH, not by name: npm invokes the bin through a
|
|
210
252
|
// .bin/memory-pulse symlink, and a basename comparison silently failed there —
|
|
@@ -215,6 +257,10 @@ try {
|
|
|
215
257
|
isMain = Boolean(process.argv[1]) && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
216
258
|
} catch { /* argv[1] missing or unreadable — we are being imported */ }
|
|
217
259
|
if (isMain) {
|
|
260
|
+
const sub = process.argv[2];
|
|
261
|
+
if (sub === "brief") { await cliBrief(); process.exit(0); }
|
|
262
|
+
if (sub === "install-hook") { cliInstallHook(); process.exit(0); }
|
|
263
|
+
if (sub && sub !== "serve") { console.error(`unknown command: ${sub} (try: brief, install-hook)`); process.exit(1); }
|
|
218
264
|
process.stderr.write(`memory-pulse: ledger ${ledgerPath()} — api ${API}\n`);
|
|
219
265
|
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
220
266
|
// In-flight calls are drained before exit. Exiting the moment stdin closes
|