project-memory-mcp 0.1.0
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 +640 -0
- package/dist/hooks/_bootstrap-context.js +99 -0
- package/dist/hooks/_bootstrap-context.js.map +1 -0
- package/dist/hooks/auto-memory.js +155 -0
- package/dist/hooks/auto-memory.js.map +1 -0
- package/dist/hooks/auto-save.js +155 -0
- package/dist/hooks/auto-save.js.map +1 -0
- package/dist/hooks/codex-notify.js +97 -0
- package/dist/hooks/codex-notify.js.map +1 -0
- package/dist/hooks/cursor.js +32 -0
- package/dist/hooks/cursor.js.map +1 -0
- package/dist/hooks/extractors.js +318 -0
- package/dist/hooks/extractors.js.map +1 -0
- package/dist/scripts/test-hooks.js +142 -0
- package/dist/scripts/test-hooks.js.map +1 -0
- package/dist/server.js +44 -0
- package/dist/server.js.map +1 -0
- package/dist/src/config.js +29 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/domain.js +52 -0
- package/dist/src/domain.js.map +1 -0
- package/dist/src/logger.js +5 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/main.js +21 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/maintenance.js +150 -0
- package/dist/src/maintenance.js.map +1 -0
- package/dist/src/runtime.js +52 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/setup.js +547 -0
- package/dist/src/setup.js.map +1 -0
- package/dist/src/storage.js +103 -0
- package/dist/src/storage.js.map +1 -0
- package/dist/src/tools.js +392 -0
- package/dist/src/tools.js.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/docs/LOCAL_SETUP.md +223 -0
- package/package.json +51 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic extractors that pull structured facts from Claude Code transcript lines.
|
|
3
|
+
* Each extractor receives an array of parsed JSONL objects (the delta) and returns
|
|
4
|
+
* candidate memory items: { type, title, content, tags }.
|
|
5
|
+
*/
|
|
6
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
7
|
+
const RE_VERSION = /\b(node|npm|python|pip|ruby|go|java|rustc|cargo|bun|deno|pnpm|yarn)\s+(-v|--version|version)\b/i;
|
|
8
|
+
const RE_VERSION_OUTPUT = /v?\d+\.\d+\.\d+/;
|
|
9
|
+
const RE_COMMIT = /git\s+commit\s.*?-m\s+["'](.+?)["']/;
|
|
10
|
+
const RE_NPM_INSTALL = /\b(npm|yarn|pnpm|bun)\s+(install|add|i)\s+(\S+)/;
|
|
11
|
+
const RE_PIP_INSTALL = /\b(pip|pip3)\s+install\s+(\S+)/;
|
|
12
|
+
const RE_CARGO_ADD = /\bcargo\s+add\s+(\S+)/;
|
|
13
|
+
/**
|
|
14
|
+
* Extract the role and content from a transcript JSONL line.
|
|
15
|
+
* Claude Code transcript lines wrap messages in various ways:
|
|
16
|
+
* - Top-level: { type: "assistant", message: { role, content } }
|
|
17
|
+
* - Progress: { type: "progress", data: { message: { type, message: { role, content } } } }
|
|
18
|
+
* - Simple: { role, content } (fallback)
|
|
19
|
+
*/
|
|
20
|
+
function normalizeRole(role) {
|
|
21
|
+
if (!role)
|
|
22
|
+
return role;
|
|
23
|
+
if (role === "model")
|
|
24
|
+
return "assistant";
|
|
25
|
+
return role;
|
|
26
|
+
}
|
|
27
|
+
function normalizeContent(content, parts) {
|
|
28
|
+
if (Array.isArray(content))
|
|
29
|
+
return content;
|
|
30
|
+
if (typeof content === "string")
|
|
31
|
+
return content;
|
|
32
|
+
if (Array.isArray(parts)) {
|
|
33
|
+
return parts
|
|
34
|
+
.map((p) => {
|
|
35
|
+
if (typeof p === "string")
|
|
36
|
+
return p;
|
|
37
|
+
if (typeof p?.text === "string")
|
|
38
|
+
return p.text;
|
|
39
|
+
return "";
|
|
40
|
+
})
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join("");
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function unwrap(line) {
|
|
47
|
+
// Direct message lines (type: "assistant" | "user")
|
|
48
|
+
if (line.message?.role) {
|
|
49
|
+
const content = normalizeContent(line.message.content, line.message.parts);
|
|
50
|
+
if (content !== null) {
|
|
51
|
+
return { role: normalizeRole(line.message.role), content };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Lines with type but no message wrapper (type: "assistant" | "user" with direct content)
|
|
55
|
+
if ((line.type === "assistant" || line.type === "user") && line.content !== undefined) {
|
|
56
|
+
const content = normalizeContent(line.content, line.parts);
|
|
57
|
+
if (content !== null) {
|
|
58
|
+
return { role: normalizeRole(line.type), content };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Progress lines (subagent tool calls/results)
|
|
62
|
+
if (line.type === "progress" && line.data?.message?.message) {
|
|
63
|
+
const inner = line.data.message.message;
|
|
64
|
+
if (inner.role && inner.content) {
|
|
65
|
+
const content = normalizeContent(inner.content, inner.parts);
|
|
66
|
+
if (content !== null) {
|
|
67
|
+
return { role: normalizeRole(inner.role), content };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Fallback: already unwrapped
|
|
72
|
+
if (line.role) {
|
|
73
|
+
const content = normalizeContent(line.content, line.parts);
|
|
74
|
+
if (content !== null) {
|
|
75
|
+
return { role: normalizeRole(line.role), content };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function bashToolCalls(lines) {
|
|
81
|
+
const results = [];
|
|
82
|
+
for (const line of lines) {
|
|
83
|
+
const msg = unwrap(line);
|
|
84
|
+
if (!msg || msg.role !== "assistant")
|
|
85
|
+
continue;
|
|
86
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
87
|
+
for (const block of content) {
|
|
88
|
+
if (block.type !== "tool_use" || block.name !== "Bash")
|
|
89
|
+
continue;
|
|
90
|
+
results.push({ id: block.id, command: block.input?.command ?? "" });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return results;
|
|
94
|
+
}
|
|
95
|
+
function toolResults(lines) {
|
|
96
|
+
const results = [];
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
const msg = unwrap(line);
|
|
99
|
+
if (!msg || msg.role !== "user")
|
|
100
|
+
continue;
|
|
101
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
102
|
+
for (const block of content) {
|
|
103
|
+
if (block.type === "tool_result") {
|
|
104
|
+
results.push({ toolUseId: block.tool_use_id, text: block.content ?? "" });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return results;
|
|
109
|
+
}
|
|
110
|
+
function resultForId(resultMap, id) {
|
|
111
|
+
return resultMap.get(id) ?? "";
|
|
112
|
+
}
|
|
113
|
+
// ── Extractor 1: Bash tool facts ─────────────────────────────────────────────
|
|
114
|
+
export function extractFromBashTools(lines) {
|
|
115
|
+
const items = [];
|
|
116
|
+
const calls = bashToolCalls(lines);
|
|
117
|
+
const resMap = new Map();
|
|
118
|
+
for (const r of toolResults(lines)) {
|
|
119
|
+
resMap.set(r.toolUseId, r.text);
|
|
120
|
+
}
|
|
121
|
+
for (const call of calls) {
|
|
122
|
+
const cmd = call.command;
|
|
123
|
+
const output = resultForId(resMap, call.id);
|
|
124
|
+
// Version detection
|
|
125
|
+
if (RE_VERSION.test(cmd)) {
|
|
126
|
+
const match = (typeof output === "string" ? output : "").match(RE_VERSION_OUTPUT);
|
|
127
|
+
if (match) {
|
|
128
|
+
const tool = cmd.match(RE_VERSION)?.[1] ?? "unknown";
|
|
129
|
+
items.push({
|
|
130
|
+
type: "fact",
|
|
131
|
+
title: `${tool} version: ${match[0]}`,
|
|
132
|
+
content: `Detected via \`${cmd.trim()}\``,
|
|
133
|
+
tags: ["version", "environment"],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Commit messages
|
|
138
|
+
const commitMatch = cmd.match(RE_COMMIT);
|
|
139
|
+
if (commitMatch) {
|
|
140
|
+
items.push({
|
|
141
|
+
type: "note",
|
|
142
|
+
title: `Commit: ${commitMatch[1].slice(0, 120)}`,
|
|
143
|
+
content: `Full command: ${cmd.trim().slice(0, 300)}`,
|
|
144
|
+
tags: ["commit"],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// npm / yarn / pnpm / bun install
|
|
148
|
+
const npmMatch = cmd.match(RE_NPM_INSTALL);
|
|
149
|
+
if (npmMatch) {
|
|
150
|
+
const pkg = npmMatch[3].replace(/^['"]|['"]$/g, "");
|
|
151
|
+
if (pkg && !pkg.startsWith("-")) {
|
|
152
|
+
items.push({
|
|
153
|
+
type: "fact",
|
|
154
|
+
title: `Added dependency: ${pkg}`,
|
|
155
|
+
content: `Installed via \`${cmd.trim().slice(0, 200)}\``,
|
|
156
|
+
tags: ["dependency"],
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// pip install
|
|
161
|
+
const pipMatch = cmd.match(RE_PIP_INSTALL);
|
|
162
|
+
if (pipMatch) {
|
|
163
|
+
const pkg = pipMatch[2].replace(/^['"]|['"]$/g, "");
|
|
164
|
+
if (pkg && !pkg.startsWith("-")) {
|
|
165
|
+
items.push({
|
|
166
|
+
type: "fact",
|
|
167
|
+
title: `Added dependency: ${pkg}`,
|
|
168
|
+
content: `Installed via \`${cmd.trim().slice(0, 200)}\``,
|
|
169
|
+
tags: ["dependency"],
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// cargo add
|
|
174
|
+
const cargoMatch = cmd.match(RE_CARGO_ADD);
|
|
175
|
+
if (cargoMatch) {
|
|
176
|
+
items.push({
|
|
177
|
+
type: "fact",
|
|
178
|
+
title: `Added dependency: ${cargoMatch[1]}`,
|
|
179
|
+
content: `Installed via \`${cmd.trim().slice(0, 200)}\``,
|
|
180
|
+
tags: ["dependency"],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return items;
|
|
185
|
+
}
|
|
186
|
+
// ── Extractor 2: Error resolutions ───────────────────────────────────────────
|
|
187
|
+
export function extractErrorResolutions(lines) {
|
|
188
|
+
const items = [];
|
|
189
|
+
const calls = bashToolCalls(lines);
|
|
190
|
+
const resMap = new Map();
|
|
191
|
+
for (const r of toolResults(lines)) {
|
|
192
|
+
resMap.set(r.toolUseId, r.text);
|
|
193
|
+
}
|
|
194
|
+
// Track errors then look for subsequent success on similar commands
|
|
195
|
+
const errors = [];
|
|
196
|
+
for (const call of calls) {
|
|
197
|
+
const output = resultForId(resMap, call.id);
|
|
198
|
+
const outStr = typeof output === "string" ? output : JSON.stringify(output ?? "");
|
|
199
|
+
// Heuristic: non-zero exit or common error strings
|
|
200
|
+
const isError = /exit code [1-9]|error:|ERR!|FAIL|fatal:/i.test(outStr);
|
|
201
|
+
const isSuccess = !isError && outStr.length > 0;
|
|
202
|
+
if (isError) {
|
|
203
|
+
const summary = outStr.slice(0, 150).split("\n")[0];
|
|
204
|
+
errors.push({ command: call.command, summary });
|
|
205
|
+
}
|
|
206
|
+
else if (isSuccess && errors.length > 0) {
|
|
207
|
+
// Check if this success relates to a prior error (same base command)
|
|
208
|
+
const baseCmd = call.command.split(/\s+/)[0];
|
|
209
|
+
const related = errors.find((e) => e.command.split(/\s+/)[0] === baseCmd);
|
|
210
|
+
if (related) {
|
|
211
|
+
items.push({
|
|
212
|
+
type: "fact",
|
|
213
|
+
title: `Resolved: ${related.summary.slice(0, 100)}`,
|
|
214
|
+
content: `Error in \`${related.command.slice(0, 120)}\` was resolved by \`${call.command.slice(0, 120)}\``,
|
|
215
|
+
tags: ["error-resolution"],
|
|
216
|
+
});
|
|
217
|
+
// Remove the matched error
|
|
218
|
+
const idx = errors.indexOf(related);
|
|
219
|
+
errors.splice(idx, 1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return items;
|
|
224
|
+
}
|
|
225
|
+
// ── Extractor 3: File change summary ─────────────────────────────────────────
|
|
226
|
+
export function extractFileChanges(lines) {
|
|
227
|
+
const files = new Set();
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
const msg = unwrap(line);
|
|
230
|
+
if (!msg || msg.role !== "assistant")
|
|
231
|
+
continue;
|
|
232
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
233
|
+
for (const block of content) {
|
|
234
|
+
if (block.type !== "tool_use")
|
|
235
|
+
continue;
|
|
236
|
+
if (block.name === "Write" || block.name === "Edit") {
|
|
237
|
+
const fp = block.input?.file_path ?? block.input?.path ?? "";
|
|
238
|
+
if (fp)
|
|
239
|
+
files.add(fp);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (files.size === 0)
|
|
244
|
+
return [];
|
|
245
|
+
const fileList = [...files].sort();
|
|
246
|
+
return [
|
|
247
|
+
{
|
|
248
|
+
type: "note",
|
|
249
|
+
title: `Files modified this session (${fileList.length})`,
|
|
250
|
+
content: fileList.join(", "),
|
|
251
|
+
tags: ["file-changes"],
|
|
252
|
+
},
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
// ── Extractor 4: Decisions / constraints / architecture from assistant text ──
|
|
256
|
+
const DECISION_PATTERNS = [
|
|
257
|
+
{ re: /\b(decided to|switched from|switched to|chose|migrated)\b/i, type: "decision" },
|
|
258
|
+
{ re: /\b(always|never|must not|must|do not)\b/i, type: "constraint" },
|
|
259
|
+
{ re: /\b(the architecture|pattern is|structure|design)\b/i, type: "architecture" },
|
|
260
|
+
{ re: /\b(uses \S+ v\d+\.\d+|running on|installed)\b/i, type: "fact" },
|
|
261
|
+
];
|
|
262
|
+
function extractTextFromContent(content) {
|
|
263
|
+
if (typeof content === "string")
|
|
264
|
+
return content;
|
|
265
|
+
if (!Array.isArray(content))
|
|
266
|
+
return "";
|
|
267
|
+
return content
|
|
268
|
+
.filter((block) => block.type === "text" && typeof block.text === "string")
|
|
269
|
+
.map((block) => block.text)
|
|
270
|
+
.join(" ");
|
|
271
|
+
}
|
|
272
|
+
function splitSentences(text) {
|
|
273
|
+
return text
|
|
274
|
+
.split(/(?<=[.!?])\s+/)
|
|
275
|
+
.map((s) => s.trim())
|
|
276
|
+
.filter((s) => s.length > 10);
|
|
277
|
+
}
|
|
278
|
+
export function extractDecisionsFromText(lines) {
|
|
279
|
+
const items = [];
|
|
280
|
+
const seen = new Set();
|
|
281
|
+
for (const line of lines) {
|
|
282
|
+
const msg = unwrap(line);
|
|
283
|
+
if (!msg || msg.role !== "assistant")
|
|
284
|
+
continue;
|
|
285
|
+
const text = extractTextFromContent(msg.content);
|
|
286
|
+
if (!text)
|
|
287
|
+
continue;
|
|
288
|
+
for (const sentence of splitSentences(text)) {
|
|
289
|
+
for (const { re, type } of DECISION_PATTERNS) {
|
|
290
|
+
if (!re.test(sentence))
|
|
291
|
+
continue;
|
|
292
|
+
const title = sentence.length > 100 ? sentence.slice(0, 100) + "…" : sentence;
|
|
293
|
+
const key = `${type}:${title}`;
|
|
294
|
+
if (seen.has(key))
|
|
295
|
+
break;
|
|
296
|
+
seen.add(key);
|
|
297
|
+
items.push({
|
|
298
|
+
type,
|
|
299
|
+
title,
|
|
300
|
+
content: sentence.slice(0, 500),
|
|
301
|
+
tags: [type],
|
|
302
|
+
});
|
|
303
|
+
break; // one match per sentence
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return items;
|
|
308
|
+
}
|
|
309
|
+
// ── Orchestrator ─────────────────────────────────────────────────────────────
|
|
310
|
+
export function extractAll(lines) {
|
|
311
|
+
return [
|
|
312
|
+
...extractFromBashTools(lines),
|
|
313
|
+
...extractErrorResolutions(lines),
|
|
314
|
+
...extractFileChanges(lines),
|
|
315
|
+
...extractDecisionsFromText(lines),
|
|
316
|
+
];
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=extractors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractors.js","sourceRoot":"","sources":["../../hooks/extractors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* End-to-end sanity tests for Claude/Gemini/Codex hook chain.
|
|
4
|
+
* Creates a small transcript, runs each hook entrypoint, and reports results.
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
const ROOT = process.cwd();
|
|
10
|
+
const TMP_DIR = "/tmp";
|
|
11
|
+
const TRANSCRIPT = join(TMP_DIR, "pm-hook-test.jsonl");
|
|
12
|
+
const CURSOR = join(ROOT, ".ai", ".auto-save-cursor.json");
|
|
13
|
+
const MEMORY = join(ROOT, ".ai", "memory.json");
|
|
14
|
+
function now() {
|
|
15
|
+
return new Date().toISOString();
|
|
16
|
+
}
|
|
17
|
+
async function ensureAiDir() {
|
|
18
|
+
await mkdir(join(ROOT, ".ai"), { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
async function writeTranscript() {
|
|
21
|
+
const lines = [
|
|
22
|
+
{
|
|
23
|
+
type: "assistant",
|
|
24
|
+
message: {
|
|
25
|
+
role: "assistant",
|
|
26
|
+
content: [{ type: "tool_use", name: "Bash", id: "1", input: { command: "node -v" } }],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "user",
|
|
31
|
+
content: [{ type: "tool_result", tool_use_id: "1", content: "v20.11.0" }],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: "assistant",
|
|
35
|
+
message: { role: "assistant", content: "Done." },
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
const raw = lines.map((l) => JSON.stringify(l)).join("\n");
|
|
39
|
+
await writeFile(TRANSCRIPT, raw);
|
|
40
|
+
}
|
|
41
|
+
async function readMemory() {
|
|
42
|
+
const raw = await readFile(MEMORY, "utf8");
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
}
|
|
45
|
+
async function readCursor() {
|
|
46
|
+
const raw = await readFile(CURSOR, "utf8");
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
function runNode(scriptPath, input, env = {}) {
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
const child = spawn("node", [scriptPath], {
|
|
52
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
53
|
+
env: { ...process.env, ...env },
|
|
54
|
+
});
|
|
55
|
+
let stderr = "";
|
|
56
|
+
child.stderr.on("data", (d) => (stderr += d.toString("utf8")));
|
|
57
|
+
child.stdin.write(input);
|
|
58
|
+
child.stdin.end();
|
|
59
|
+
child.on("close", (code) => resolve({ code, stderr }));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function runClaude() {
|
|
63
|
+
const payload = JSON.stringify({
|
|
64
|
+
session_id: `claude-test-${now()}`,
|
|
65
|
+
transcript_path: TRANSCRIPT,
|
|
66
|
+
cwd: ROOT,
|
|
67
|
+
});
|
|
68
|
+
return runNode(join(ROOT, "dist", "hooks", "auto-save.js"), payload, {
|
|
69
|
+
CLAUDE_PROJECT_DIR: ROOT,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function runGemini() {
|
|
73
|
+
const payload = JSON.stringify({
|
|
74
|
+
session_id: `gemini-test-${now()}`,
|
|
75
|
+
transcript_path: TRANSCRIPT,
|
|
76
|
+
cwd: ROOT,
|
|
77
|
+
});
|
|
78
|
+
return runNode(join(ROOT, "dist", "hooks", "auto-save.js"), payload, {
|
|
79
|
+
GEMINI_PROJECT_DIR: ROOT,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function runCodex() {
|
|
83
|
+
const payload = JSON.stringify({
|
|
84
|
+
session_id: `codex-test-${now()}`,
|
|
85
|
+
cwd: ROOT,
|
|
86
|
+
history_path: TRANSCRIPT,
|
|
87
|
+
});
|
|
88
|
+
return runNode(join(ROOT, "dist", "hooks", "codex-notify.js"), payload);
|
|
89
|
+
}
|
|
90
|
+
function printResult(name, ok, details = "") {
|
|
91
|
+
const status = ok ? "PASS" : "FAIL";
|
|
92
|
+
const line = `${status} ${name}${details ? ` - ${details}` : ""}`;
|
|
93
|
+
process.stdout.write(line + "\n");
|
|
94
|
+
}
|
|
95
|
+
async function main() {
|
|
96
|
+
await ensureAiDir();
|
|
97
|
+
await writeTranscript();
|
|
98
|
+
const claude = await runClaude();
|
|
99
|
+
const cursorAfterClaude = await readCursor();
|
|
100
|
+
printResult("Claude hook", claude.code === 0 &&
|
|
101
|
+
cursorAfterClaude.sessionId?.startsWith("claude-test-") &&
|
|
102
|
+
cursorAfterClaude.lastLineIndex === 2, claude.code !== 0 ? `exit ${claude.code}` : "cursor not updated");
|
|
103
|
+
const gemini = await runGemini();
|
|
104
|
+
const cursorAfterGemini = await readCursor();
|
|
105
|
+
printResult("Gemini hook", gemini.code === 0 &&
|
|
106
|
+
cursorAfterGemini.sessionId?.startsWith("gemini-test-") &&
|
|
107
|
+
cursorAfterGemini.lastLineIndex === 2, gemini.code !== 0 ? `exit ${gemini.code}` : "cursor not updated");
|
|
108
|
+
const codex = await runCodex();
|
|
109
|
+
const cursorAfterCodex = await readCursor();
|
|
110
|
+
printResult("Codex hook", codex.code === 0 &&
|
|
111
|
+
cursorAfterCodex.sessionId?.startsWith("codex-test-") &&
|
|
112
|
+
cursorAfterCodex.lastLineIndex === 2, codex.code !== 0 ? `exit ${codex.code}` : "cursor not updated");
|
|
113
|
+
if (claude.stderr)
|
|
114
|
+
printResult("Claude stderr", false, claude.stderr.trim());
|
|
115
|
+
if (gemini.stderr)
|
|
116
|
+
printResult("Gemini stderr", false, gemini.stderr.trim());
|
|
117
|
+
if (codex.stderr)
|
|
118
|
+
printResult("Codex stderr", false, codex.stderr.trim());
|
|
119
|
+
// Touch cursor to show it's created
|
|
120
|
+
try {
|
|
121
|
+
await readFile(CURSOR, "utf8");
|
|
122
|
+
printResult("Cursor file", true, CURSOR);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
printResult("Cursor file", false, "missing");
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const data = await readMemory();
|
|
129
|
+
const found = data.items.some((i) => (i.tags ?? []).includes("auto-hook") &&
|
|
130
|
+
typeof i.title === "string" &&
|
|
131
|
+
i.title.toLowerCase().includes("node version"));
|
|
132
|
+
printResult("Auto-hook item", found, found ? "node version" : "missing");
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
printResult("Auto-hook item", false, "memory read failed");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
main().catch((err) => {
|
|
139
|
+
printResult("Test runner", false, err?.message || "unknown error");
|
|
140
|
+
process.exit(1);
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=test-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-hooks.js","sourceRoot":"","sources":["../../scripts/test-hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Project Memory MCP Server (JSON backend) + setup utilities.
|
|
4
|
+
*/
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { main } from "./src/main.js";
|
|
7
|
+
import { log } from "./src/logger.js";
|
|
8
|
+
async function run() {
|
|
9
|
+
const [, , rawCommand] = process.argv;
|
|
10
|
+
const command = rawCommand?.toLowerCase();
|
|
11
|
+
if (!command || command === "serve") {
|
|
12
|
+
await main();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (command === "setup" || command === "configure") {
|
|
16
|
+
const { runSetup } = await import("./src/setup.js");
|
|
17
|
+
const exitCode = await runSetup(process.argv.slice(3));
|
|
18
|
+
if (typeof exitCode === "number" && exitCode !== 0) {
|
|
19
|
+
process.exitCode = exitCode;
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (command === "help" || command === "--help" || command === "-h") {
|
|
24
|
+
printUsage();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
log(`unknown command "${rawCommand}".`);
|
|
28
|
+
printUsage();
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
function printUsage() {
|
|
32
|
+
console.log(`
|
|
33
|
+
Usage:
|
|
34
|
+
project-memory-mcp Start the MCP server (default)
|
|
35
|
+
project-memory-mcp serve Explicitly start the MCP server
|
|
36
|
+
project-memory-mcp setup [...] Run the interactive CLI configuration wizard
|
|
37
|
+
project-memory-mcp help Show this message
|
|
38
|
+
`.trim());
|
|
39
|
+
}
|
|
40
|
+
run().catch((err) => {
|
|
41
|
+
log("fatal error:", err);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../server.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,KAAK,UAAU,GAAG;IAChB,MAAM,CAAC,EAAE,AAAD,EAAG,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,UAAU,EAAE,WAAW,EAAE,CAAC;IAE1C,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC9B,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnE,UAAU,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,GAAG,CAAC,oBAAoB,UAAU,IAAI,CAAC,CAAC;IACxC,UAAU,EAAE,CAAC;IACb,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;;;;;;CAMb,CAAC,IAAI,EAAE,CAAC,CAAC;AACV,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const CONFIG = {
|
|
2
|
+
serverName: "project-memory",
|
|
3
|
+
serverVersion: "0.1.0",
|
|
4
|
+
defaultRelMemoryPath: ".ai/memory.json",
|
|
5
|
+
lockTimeoutMs: 2500,
|
|
6
|
+
lockRetryDelayMs: 50,
|
|
7
|
+
lockRetryBackoff: 1.25,
|
|
8
|
+
maxLockRetryDelayMs: 250,
|
|
9
|
+
maxContentSnippetChars: 280,
|
|
10
|
+
autoCompact: {
|
|
11
|
+
enabled: true,
|
|
12
|
+
maxItems: 400,
|
|
13
|
+
archiveRelPath: ".ai/memory-archive.json",
|
|
14
|
+
summaryTitle: "Archived context (auto)",
|
|
15
|
+
summaryTag: "archive",
|
|
16
|
+
summaryMaxEntries: 20,
|
|
17
|
+
growthThreshold: 50,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export const ALLOWED_TYPES = new Set([
|
|
21
|
+
"note",
|
|
22
|
+
"decision",
|
|
23
|
+
"fact",
|
|
24
|
+
"constraint",
|
|
25
|
+
"todo",
|
|
26
|
+
"architecture",
|
|
27
|
+
"glossary",
|
|
28
|
+
]);
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAwBA,MAAM,CAAC,MAAM,MAAM,GAAW;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,OAAO;IACtB,oBAAoB,EAAE,iBAAiB;IACvC,aAAa,EAAE,IAAI;IACnB,gBAAgB,EAAE,EAAE;IACpB,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,GAAG;IACxB,sBAAsB,EAAE,GAAG;IAC3B,WAAW,EAAE;QACX,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,GAAG;QACb,cAAc,EAAE,yBAAyB;QACzC,YAAY,EAAE,yBAAyB;QACvC,UAAU,EAAE,SAAS;QACrB,iBAAiB,EAAE,EAAE;QACrB,eAAe,EAAE,EAAE;KACpB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAa;IAC/C,MAAM;IACN,UAAU;IACV,MAAM;IACN,YAAY;IACZ,MAAM;IACN,cAAc;IACd,UAAU;CACX,CAAC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { ALLOWED_TYPES, CONFIG } from "./config.js";
|
|
3
|
+
export function normalizeTags(tags) {
|
|
4
|
+
const arr = Array.isArray(tags) ? tags : [];
|
|
5
|
+
const norm = arr
|
|
6
|
+
.map((t) => String(t || "").trim().toLowerCase())
|
|
7
|
+
.filter(Boolean);
|
|
8
|
+
return Array.from(new Set(norm)).slice(0, 20);
|
|
9
|
+
}
|
|
10
|
+
export function safeSnippet(text, maxChars = CONFIG.maxContentSnippetChars) {
|
|
11
|
+
const s = String(text ?? "");
|
|
12
|
+
const trimmed = s.replace(/\s+/g, " ").trim();
|
|
13
|
+
if (trimmed.length <= maxChars)
|
|
14
|
+
return trimmed;
|
|
15
|
+
return `${trimmed.slice(0, maxChars - 1)}…`;
|
|
16
|
+
}
|
|
17
|
+
export function scoreItem(item, queryTokens, tagTokens) {
|
|
18
|
+
const hay = `${item.title || ""} ${item.content || ""}`.toLowerCase();
|
|
19
|
+
let score = 0;
|
|
20
|
+
for (const t of queryTokens) {
|
|
21
|
+
if (!t)
|
|
22
|
+
continue;
|
|
23
|
+
if (hay.includes(t))
|
|
24
|
+
score += 3;
|
|
25
|
+
}
|
|
26
|
+
const itemTags = new Set(normalizeTags(item.tags));
|
|
27
|
+
for (const t of tagTokens) {
|
|
28
|
+
if (itemTags.has(t))
|
|
29
|
+
score += 4;
|
|
30
|
+
}
|
|
31
|
+
if (item.pinned)
|
|
32
|
+
score += 2;
|
|
33
|
+
return score;
|
|
34
|
+
}
|
|
35
|
+
export function tokenize(s) {
|
|
36
|
+
return String(s || "")
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.split(/[^a-z0-9_\-]+/i)
|
|
39
|
+
.map((x) => x.trim())
|
|
40
|
+
.filter((x) => x.length >= 2)
|
|
41
|
+
.slice(0, 40);
|
|
42
|
+
}
|
|
43
|
+
export function newId(prefix) {
|
|
44
|
+
// short, stable-ish id for CLI readability
|
|
45
|
+
const id = crypto.randomUUID().replace(/-/g, "").slice(0, 12);
|
|
46
|
+
return `${prefix}_${id}`;
|
|
47
|
+
}
|
|
48
|
+
export function validateType(type) {
|
|
49
|
+
const t = String(type || "note").toLowerCase().trim();
|
|
50
|
+
return ALLOWED_TYPES.has(t) ? t : "note";
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../../src/domain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,CAAC,GAAG,IAAe;IACpC,gDAAgD;IAChD,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|