@strvmarv/total-recall 0.1.5 → 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/.claude-plugin/plugin.json +12 -10
- package/.mcp.json +8 -0
- package/bin/total-recall.sh +84 -0
- package/dist/defaults.toml +28 -0
- package/dist/index.js +26 -6
- package/models/all-MiniLM-L6-v2/model.onnx +3 -0
- package/models/all-MiniLM-L6-v2/tokenizer.json +1 -0
- package/models/all-MiniLM-L6-v2/tokenizer_config.json +1 -0
- package/package.json +4 -1
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "total-recall",
|
|
3
3
|
"description": "Multi-tiered memory and knowledge base with semantic search, auto-compaction, and built-in evaluation. Works across Claude Code, Copilot CLI, OpenCode, Cline, and Cursor.",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "strvmarv"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
"homepage": "https://github.com/strvmarv/total-recall",
|
|
9
|
+
"repository": "https://github.com/strvmarv/total-recall",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"memory",
|
|
13
|
+
"knowledge-base",
|
|
14
|
+
"mcp",
|
|
15
|
+
"vector-search",
|
|
16
|
+
"sqlite",
|
|
17
|
+
"embeddings"
|
|
18
|
+
]
|
|
17
19
|
}
|
package/.mcp.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# total-recall MCP server launcher
|
|
3
|
+
# Finds node in common locations even when not in PATH
|
|
4
|
+
|
|
5
|
+
find_node() {
|
|
6
|
+
# Check PATH first
|
|
7
|
+
if command -v node &>/dev/null; then
|
|
8
|
+
echo "node"
|
|
9
|
+
return 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Check nvm
|
|
13
|
+
if [ -d "$HOME/.nvm/versions/node" ]; then
|
|
14
|
+
local latest=$(ls -1d "$HOME/.nvm/versions/node"/v* 2>/dev/null | sort -V | tail -1)
|
|
15
|
+
if [ -n "$latest" ] && [ -x "$latest/bin/node" ]; then
|
|
16
|
+
echo "$latest/bin/node"
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Check fnm
|
|
22
|
+
if [ -d "$HOME/.local/share/fnm/node-versions" ]; then
|
|
23
|
+
local latest=$(ls -1d "$HOME/.local/share/fnm/node-versions"/v*/installation 2>/dev/null | sort -V | tail -1)
|
|
24
|
+
if [ -n "$latest" ] && [ -x "$latest/bin/node" ]; then
|
|
25
|
+
echo "$latest/bin/node"
|
|
26
|
+
return 0
|
|
27
|
+
fi
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Check Homebrew
|
|
31
|
+
if [ -x "/home/linuxbrew/.linuxbrew/bin/node" ]; then
|
|
32
|
+
echo "/home/linuxbrew/.linuxbrew/bin/node"
|
|
33
|
+
return 0
|
|
34
|
+
fi
|
|
35
|
+
if [ -x "/opt/homebrew/bin/node" ]; then
|
|
36
|
+
echo "/opt/homebrew/bin/node"
|
|
37
|
+
return 0
|
|
38
|
+
fi
|
|
39
|
+
if [ -x "/usr/local/bin/node" ]; then
|
|
40
|
+
echo "/usr/local/bin/node"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Check Volta
|
|
45
|
+
if [ -x "$HOME/.volta/bin/node" ]; then
|
|
46
|
+
echo "$HOME/.volta/bin/node"
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo ""
|
|
51
|
+
return 1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
NODE=$(find_node)
|
|
55
|
+
if [ -z "$NODE" ]; then
|
|
56
|
+
echo "total-recall: error: node.js not found. Install Node.js 20+ via nvm, fnm, Volta, or your package manager." >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Find the package entry point
|
|
61
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
62
|
+
PACKAGE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
63
|
+
ENTRY="$PACKAGE_DIR/dist/index.js"
|
|
64
|
+
|
|
65
|
+
# Strategy 1: Local dist/index.js (source install or npm install)
|
|
66
|
+
if [ -f "$ENTRY" ]; then
|
|
67
|
+
exec "$NODE" "$ENTRY" "$@"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Strategy 2: Global install (npm install -g @strvmarv/total-recall)
|
|
71
|
+
if command -v total-recall &>/dev/null; then
|
|
72
|
+
exec total-recall "$@"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Strategy 3: Find entry point in global node_modules
|
|
76
|
+
NODE_DIR="$(dirname "$NODE")"
|
|
77
|
+
GLOBAL_ENTRY=$("$NODE_DIR/npm" root -g 2>/dev/null)/@strvmarv/total-recall/dist/index.js
|
|
78
|
+
if [ -f "$GLOBAL_ENTRY" ]; then
|
|
79
|
+
exec "$NODE" "$GLOBAL_ENTRY" "$@"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
echo "total-recall: error: could not find dist/index.js or total-recall binary." >&2
|
|
83
|
+
echo " Run 'npm run build' (git clone) or 'npm install -g @strvmarv/total-recall'." >&2
|
|
84
|
+
exit 1
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# total-recall default configuration
|
|
2
|
+
# Copy to ~/.total-recall/config.toml to override
|
|
3
|
+
|
|
4
|
+
[tiers.hot]
|
|
5
|
+
max_entries = 50
|
|
6
|
+
token_budget = 4000
|
|
7
|
+
carry_forward_threshold = 0.7
|
|
8
|
+
|
|
9
|
+
[tiers.warm]
|
|
10
|
+
max_entries = 10000
|
|
11
|
+
retrieval_top_k = 5
|
|
12
|
+
similarity_threshold = 0.65
|
|
13
|
+
cold_decay_days = 30
|
|
14
|
+
|
|
15
|
+
[tiers.cold]
|
|
16
|
+
chunk_max_tokens = 512
|
|
17
|
+
chunk_overlap_tokens = 50
|
|
18
|
+
lazy_summary_threshold = 5
|
|
19
|
+
|
|
20
|
+
[compaction]
|
|
21
|
+
decay_half_life_hours = 168
|
|
22
|
+
warm_threshold = 0.3
|
|
23
|
+
promote_threshold = 0.7
|
|
24
|
+
warm_sweep_interval_days = 7
|
|
25
|
+
|
|
26
|
+
[embedding]
|
|
27
|
+
model = "all-MiniLM-L6-v2"
|
|
28
|
+
dimensions = 384
|
package/dist/index.js
CHANGED
|
@@ -228,9 +228,18 @@ import { writeFile } from "fs/promises";
|
|
|
228
228
|
import { join as join3 } from "path";
|
|
229
229
|
var HF_BASE_URL = "https://huggingface.co";
|
|
230
230
|
var HF_REVISION = "main";
|
|
231
|
-
function
|
|
231
|
+
function getBundledModelPath(modelName) {
|
|
232
|
+
const distDir = new URL(".", import.meta.url).pathname;
|
|
233
|
+
return join3(distDir, "..", "models", modelName);
|
|
234
|
+
}
|
|
235
|
+
function getUserModelPath(modelName) {
|
|
232
236
|
return join3(getDataDir(), "models", modelName);
|
|
233
237
|
}
|
|
238
|
+
function getModelPath(modelName) {
|
|
239
|
+
const bundled = getBundledModelPath(modelName);
|
|
240
|
+
if (isModelDownloaded(bundled)) return bundled;
|
|
241
|
+
return getUserModelPath(modelName);
|
|
242
|
+
}
|
|
234
243
|
function isModelDownloaded(modelPath) {
|
|
235
244
|
if (!existsSync3(modelPath)) return false;
|
|
236
245
|
try {
|
|
@@ -253,12 +262,23 @@ async function validateDownload(modelPath) {
|
|
|
253
262
|
}
|
|
254
263
|
}
|
|
255
264
|
async function downloadModel(modelName) {
|
|
256
|
-
const modelPath =
|
|
265
|
+
const modelPath = getUserModelPath(modelName);
|
|
257
266
|
mkdirSync2(modelPath, { recursive: true });
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
267
|
+
const fileUrls = [
|
|
268
|
+
{
|
|
269
|
+
file: "model.onnx",
|
|
270
|
+
url: `${HF_BASE_URL}/sentence-transformers/${modelName}/resolve/${HF_REVISION}/onnx/model.onnx`
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
file: "tokenizer.json",
|
|
274
|
+
url: `${HF_BASE_URL}/sentence-transformers/${modelName}/resolve/${HF_REVISION}/tokenizer.json`
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
file: "tokenizer_config.json",
|
|
278
|
+
url: `${HF_BASE_URL}/sentence-transformers/${modelName}/resolve/${HF_REVISION}/tokenizer_config.json`
|
|
279
|
+
}
|
|
280
|
+
];
|
|
281
|
+
for (const { file, url } of fileUrls) {
|
|
262
282
|
const dest = join3(modelPath, file);
|
|
263
283
|
const response = await fetch(url);
|
|
264
284
|
if (!response.ok) {
|