persisted-memory 1.0.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/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/cli/generate-summary.d.ts +1 -0
- package/dist/cli/generate-summary.js +13 -0
- package/dist/cli/generate-summary.js.map +1 -0
- package/dist/cli/viewer.d.ts +1 -0
- package/dist/cli/viewer.js +4 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/embeddings/ollama.d.ts +3 -0
- package/dist/embeddings/ollama.js +63 -0
- package/dist/embeddings/ollama.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/search/hybrid.d.ts +8 -0
- package/dist/search/hybrid.js +54 -0
- package/dist/search/hybrid.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +399 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/knowledge-graph.d.ts +32 -0
- package/dist/storage/knowledge-graph.js +259 -0
- package/dist/storage/knowledge-graph.js.map +1 -0
- package/dist/storage/lance-store.d.ts +21 -0
- package/dist/storage/lance-store.js +288 -0
- package/dist/storage/lance-store.js.map +1 -0
- package/dist/storage/markdown-store.d.ts +7 -0
- package/dist/storage/markdown-store.js +63 -0
- package/dist/storage/markdown-store.js.map +1 -0
- package/dist/storage/types.d.ts +19 -0
- package/dist/storage/types.js +13 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/utils/chunking.d.ts +1 -0
- package/dist/utils/chunking.js +55 -0
- package/dist/utils/chunking.js.map +1 -0
- package/dist/utils/privacy.d.ts +13 -0
- package/dist/utils/privacy.js +23 -0
- package/dist/utils/privacy.js.map +1 -0
- package/dist/utils/project.d.ts +3 -0
- package/dist/utils/project.js +11 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/summarize.d.ts +12 -0
- package/dist/utils/summarize.js +123 -0
- package/dist/utils/summarize.js.map +1 -0
- package/dist/viewer/index.html +328 -0
- package/dist/viewer/server.d.ts +1 -0
- package/dist/viewer/server.js +203 -0
- package/dist/viewer/server.js.map +1 -0
- package/hooks/on-post-tool.sh +17 -0
- package/hooks/on-pre-compact.sh +20 -0
- package/hooks/on-session-end.sh +46 -0
- package/hooks/on-session-start.sh +14 -0
- package/hooks/on-stop.sh +6 -0
- package/package.json +60 -0
- package/scripts/install.sh +125 -0
- package/scripts/uninstall.sh +59 -0
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "persisted-memory",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Persistent memory system for Claude Code via MCP — dual-write to Markdown + LanceDB with hybrid semantic search",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"persisted-memory": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"!dist/__tests__",
|
|
14
|
+
"hooks",
|
|
15
|
+
"scripts",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"claude",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"memory",
|
|
24
|
+
"persistent-memory",
|
|
25
|
+
"vector-search",
|
|
26
|
+
"lancedb",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"ai",
|
|
29
|
+
"llm"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/saharat/persisted-memory"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"author": "saharat",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20.0.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc && cp src/viewer/index.html dist/viewer/index.html",
|
|
42
|
+
"dev": "tsc --watch",
|
|
43
|
+
"viewer": "node dist/cli/viewer.js",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"test:coverage": "vitest run --coverage"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@lancedb/lancedb": "^0.26.2",
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
51
|
+
"apache-arrow": "18.1.0",
|
|
52
|
+
"zod": "^4.3.6"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^20",
|
|
56
|
+
"@vitest/coverage-v8": "^3.1.0",
|
|
57
|
+
"typescript": "^5.6",
|
|
58
|
+
"vitest": "^3.1.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
HOOKS_DIR="$SCRIPT_DIR/hooks"
|
|
6
|
+
SETTINGS_FILE="$HOME/.claude/settings.json"
|
|
7
|
+
|
|
8
|
+
echo "=== Persisted Memory — Install ==="
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# 1. Build
|
|
12
|
+
echo "Building persisted-memory..."
|
|
13
|
+
cd "$SCRIPT_DIR"
|
|
14
|
+
yarn install --immutable 2>/dev/null || yarn install
|
|
15
|
+
yarn build
|
|
16
|
+
echo " Build complete."
|
|
17
|
+
echo ""
|
|
18
|
+
|
|
19
|
+
# 2. Register MCP server (user-level)
|
|
20
|
+
echo "Registering MCP server (user-level)..."
|
|
21
|
+
claude mcp add --scope user memory -- node "$SCRIPT_DIR/dist/index.js"
|
|
22
|
+
echo " MCP server registered."
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# 3. Make hook scripts executable
|
|
26
|
+
echo "Making hook scripts executable..."
|
|
27
|
+
chmod +x "$HOOKS_DIR"/*.sh
|
|
28
|
+
echo ""
|
|
29
|
+
|
|
30
|
+
# 4. Merge hooks into ~/.claude/settings.json
|
|
31
|
+
echo "Registering hooks in $SETTINGS_FILE..."
|
|
32
|
+
|
|
33
|
+
# Ensure settings file exists
|
|
34
|
+
mkdir -p "$HOME/.claude"
|
|
35
|
+
if [ ! -f "$SETTINGS_FILE" ]; then
|
|
36
|
+
echo '{}' > "$SETTINGS_FILE"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
node -e "
|
|
40
|
+
const fs = require('fs');
|
|
41
|
+
const settingsPath = '$SETTINGS_FILE';
|
|
42
|
+
const hooksDir = '$HOOKS_DIR';
|
|
43
|
+
|
|
44
|
+
let settings;
|
|
45
|
+
try {
|
|
46
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
47
|
+
} catch {
|
|
48
|
+
settings = {};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
settings.hooks = settings.hooks || {};
|
|
52
|
+
|
|
53
|
+
// Define our hooks with a marker so we can identify them later
|
|
54
|
+
const MARKER = 'persisted-memory';
|
|
55
|
+
|
|
56
|
+
const hookDefs = {
|
|
57
|
+
SessionStart: {
|
|
58
|
+
hooks: [{ type: 'command', command: 'bash ' + hooksDir + '/on-session-start.sh' }]
|
|
59
|
+
},
|
|
60
|
+
PreCompact: {
|
|
61
|
+
hooks: [{ type: 'command', command: 'bash ' + hooksDir + '/on-pre-compact.sh' }]
|
|
62
|
+
},
|
|
63
|
+
PostToolUse: {
|
|
64
|
+
matcher: 'Edit|Write',
|
|
65
|
+
hooks: [{ type: 'command', command: 'bash ' + hooksDir + '/on-post-tool.sh' }]
|
|
66
|
+
},
|
|
67
|
+
Stop: {
|
|
68
|
+
hooks: [{ type: 'command', command: 'bash ' + hooksDir + '/on-stop.sh' }]
|
|
69
|
+
},
|
|
70
|
+
SessionEnd: {
|
|
71
|
+
hooks: [{ type: 'command', command: 'bash ' + hooksDir + '/on-session-end.sh' }]
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
for (const [event, def] of Object.entries(hookDefs)) {
|
|
76
|
+
if (!settings.hooks[event]) {
|
|
77
|
+
settings.hooks[event] = [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Remove any existing persisted-memory hooks (idempotent)
|
|
81
|
+
settings.hooks[event] = settings.hooks[event].filter(
|
|
82
|
+
entry => !JSON.stringify(entry).includes('persisted_memory')
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Add our hook
|
|
86
|
+
settings.hooks[event].push(def);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
90
|
+
console.log(' Hooks registered successfully.');
|
|
91
|
+
"
|
|
92
|
+
|
|
93
|
+
# 5. Add user-level CLAUDE.md instructions
|
|
94
|
+
CLAUDE_MD="$HOME/.claude/CLAUDE.md"
|
|
95
|
+
MEMORY_BLOCK="## Persistent Memory System
|
|
96
|
+
- Persistent memory is enabled for all projects via MCP server \"memory\"
|
|
97
|
+
- After context compaction, key context is preserved in \`.claude/memory/\`
|
|
98
|
+
- Use \`memory_search\` to recall past decisions, patterns, and context
|
|
99
|
+
- Use \`memory_store\` to explicitly save important decisions (type: \"decision\", importance: \"high\")
|
|
100
|
+
- Use \`memory_recall\` for a specific topic (e.g., \"authentication flow\")
|
|
101
|
+
- Use \`memory_status\` to check memory stats and Ollama availability
|
|
102
|
+
- Memory data lives at \`<project>/.claude/memory/\` — Markdown files are the source of truth"
|
|
103
|
+
|
|
104
|
+
if [ -f "$CLAUDE_MD" ]; then
|
|
105
|
+
if ! grep -q "Persistent Memory System" "$CLAUDE_MD"; then
|
|
106
|
+
echo "" >> "$CLAUDE_MD"
|
|
107
|
+
echo "$MEMORY_BLOCK" >> "$CLAUDE_MD"
|
|
108
|
+
echo " Added memory instructions to $CLAUDE_MD"
|
|
109
|
+
else
|
|
110
|
+
echo " Memory instructions already in $CLAUDE_MD"
|
|
111
|
+
fi
|
|
112
|
+
else
|
|
113
|
+
echo "$MEMORY_BLOCK" > "$CLAUDE_MD"
|
|
114
|
+
echo " Created $CLAUDE_MD with memory instructions"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
echo ""
|
|
118
|
+
echo "=== Installation complete! ==="
|
|
119
|
+
echo ""
|
|
120
|
+
echo " MCP server: node $SCRIPT_DIR/dist/index.js"
|
|
121
|
+
echo " Memory data: <project>/.claude/memory/"
|
|
122
|
+
echo ""
|
|
123
|
+
echo " Add to your project .gitignore: .claude/memory/.lance/"
|
|
124
|
+
echo ""
|
|
125
|
+
echo " Restart Claude Code to activate."
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
SETTINGS_FILE="$HOME/.claude/settings.json"
|
|
6
|
+
|
|
7
|
+
echo "=== Persisted Memory — Uninstall ==="
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# 1. Remove MCP server
|
|
11
|
+
echo "Removing MCP server registration..."
|
|
12
|
+
claude mcp remove --scope user memory 2>/dev/null || echo " (not registered)"
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
# 2. Remove hooks from settings.json
|
|
16
|
+
echo "Removing hooks from $SETTINGS_FILE..."
|
|
17
|
+
if [ -f "$SETTINGS_FILE" ]; then
|
|
18
|
+
node -e "
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const settingsPath = '$SETTINGS_FILE';
|
|
21
|
+
|
|
22
|
+
let settings;
|
|
23
|
+
try {
|
|
24
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
25
|
+
} catch {
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!settings.hooks) process.exit(0);
|
|
30
|
+
|
|
31
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
32
|
+
if (Array.isArray(settings.hooks[event])) {
|
|
33
|
+
settings.hooks[event] = settings.hooks[event].filter(
|
|
34
|
+
entry => !JSON.stringify(entry).includes('persisted_memory')
|
|
35
|
+
);
|
|
36
|
+
// Remove empty arrays
|
|
37
|
+
if (settings.hooks[event].length === 0) {
|
|
38
|
+
delete settings.hooks[event];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Remove hooks key if empty
|
|
44
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
45
|
+
delete settings.hooks;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
49
|
+
console.log(' Hooks removed.');
|
|
50
|
+
"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
echo ""
|
|
54
|
+
echo "=== Uninstall complete! ==="
|
|
55
|
+
echo ""
|
|
56
|
+
echo " Note: Per-project memory data at <project>/.claude/memory/ is preserved."
|
|
57
|
+
echo " Delete manually if no longer needed."
|
|
58
|
+
echo ""
|
|
59
|
+
echo " Restart Claude Code to deactivate."
|