claude-memory-hub 0.11.0 → 0.11.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/CHANGELOG.md +38 -0
- package/README.md +1 -0
- package/dist/cli.js +4 -4
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,44 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## [0.11.1] - 2026-04-03
|
|
9
|
+
|
|
10
|
+
Quality hardening — more tests, bugfixes, and robustness improvements for v0.11.0 features.
|
|
11
|
+
|
|
12
|
+
### Bugfixes
|
|
13
|
+
|
|
14
|
+
- **Clock skew guard** — recency decay in search ranking now uses `Math.max(0, ageMs)` to prevent negative age values when `created_at` is in the future due to clock skew. Previously could produce unpredictable scoring
|
|
15
|
+
- **Import consistency** — `uninstallCommands()` in `cli/main.ts` now uses top-level `unlinkSync` import instead of inline `require("fs").unlinkSync`. Cleaner code, consistent with rest of the file
|
|
16
|
+
|
|
17
|
+
### Testing
|
|
18
|
+
|
|
19
|
+
- **Privacy filter tests** — 35 new unit tests covering all 3 privacy layers:
|
|
20
|
+
- Layer 1: `<private>` tag stripping (single, multiple, multiline, case-insensitive, disable toggle)
|
|
21
|
+
- Layer 2: Secret detection (sk-, ghp_, gho_, Bearer, AKIA, passwords, private keys, hex secrets, short value safety, normal code safety)
|
|
22
|
+
- Layer 3: Path filtering (.env, .env.*, .pem, .key, .p12, credentials, secrets/**, private/**, Windows paths, custom paths)
|
|
23
|
+
- Custom patterns (user-defined regex, invalid pattern graceful handling)
|
|
24
|
+
- Combined layers (tags + secrets in same text)
|
|
25
|
+
- **Tokenizer tests** — 12 new unit tests for code-aware tokenizer:
|
|
26
|
+
- camelCase splitting (`getUserName` → get, user, name)
|
|
27
|
+
- PascalCase splitting (`AuthController` → auth, controller)
|
|
28
|
+
- Acronym handling (`HTMLParser` → html, parser)
|
|
29
|
+
- snake_case splitting + compound preservation (`user_auth_service` → user, auth, service, user_auth_service)
|
|
30
|
+
- File path splitting (`/src/hooks/auth.ts` → src, hooks, auth, ts)
|
|
31
|
+
- Stop word filtering (code keywords + English)
|
|
32
|
+
- Mixed code content, empty input, short tokens
|
|
33
|
+
- **Test count: 108 → 155** (+44% coverage increase)
|
|
34
|
+
|
|
35
|
+
### Files Changed
|
|
36
|
+
|
|
37
|
+
| File | Change |
|
|
38
|
+
|------|--------|
|
|
39
|
+
| `src/search/search-workflow.ts` | Clock skew guard on recency decay |
|
|
40
|
+
| `src/cli/main.ts` | Import `unlinkSync` properly |
|
|
41
|
+
| `tests/unit/privacy-filter.test.ts` | **New** — 35 tests for privacy filtering |
|
|
42
|
+
| `tests/unit/vector-search.test.ts` | +12 tokenizer edge case tests |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
8
46
|
## [0.11.0] - 2026-04-03
|
|
9
47
|
|
|
10
48
|
Privacy-first memory, smarter search, and slash commands. Three features the community asked for most.
|
package/README.md
CHANGED
|
@@ -520,6 +520,7 @@ Migration is idempotent — safe to run multiple times with zero duplicates.
|
|
|
520
520
|
| **v0.9.6** | Agent/Skill result capture, higher summary limits, IDE tag stripping, PostCompact cap, broader observation patterns (20+) |
|
|
521
521
|
| **v0.10.0** | **Full conversation capture** — all user prompts + assistant responses via transcript parsing, `messages` table with FTS5, `memory_conversation` MCP tool, conversation-enriched summaries |
|
|
522
522
|
| **v0.11.0** | **Privacy + Search + Commands** — 3-layer privacy filtering (`<private>` tags, auto secret detection, path filtering), code-aware tokenizer (camelCase/snake_case/path splitting), recency-aware ranking (7d/30d/90d decay), RRF multi-source fusion, slash commands (`/mem-search`, `/mem-status`, `/mem-save`), improved MCP tool descriptions with AUTO-USE hints |
|
|
523
|
+
| **v0.11.1** | **Quality hardening** — clock skew guard for recency ranking, import consistency fix, 47 new unit tests (privacy filter + tokenizer edge cases), test count 108 → 155 (+44%) |
|
|
523
524
|
|
|
524
525
|
See [CHANGELOG.md](CHANGELOG.md) for full details.
|
|
525
526
|
|
package/dist/cli.js
CHANGED
|
@@ -859,7 +859,7 @@ __export(exports_vector_search, {
|
|
|
859
859
|
});
|
|
860
860
|
function tokenize(text) {
|
|
861
861
|
const tokens = [];
|
|
862
|
-
const camelSplit = text.replace(/([a-
|
|
862
|
+
const camelSplit = text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
|
|
863
863
|
const words = camelSplit.toLowerCase().replace(/[^a-z0-9_./\-]/g, " ").split(/\s+/).filter(Boolean);
|
|
864
864
|
for (const word of words) {
|
|
865
865
|
if (word.includes("/") && word.length > 3) {
|
|
@@ -1223,7 +1223,7 @@ async function searchIndex(query, opts = {}, db) {
|
|
|
1223
1223
|
const now = Date.now();
|
|
1224
1224
|
const merged = [...deduped.values()].map((r) => {
|
|
1225
1225
|
let score = r.score;
|
|
1226
|
-
const ageMs = now - r.created_at;
|
|
1226
|
+
const ageMs = Math.max(0, now - r.created_at);
|
|
1227
1227
|
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
1228
1228
|
if (ageDays < 7)
|
|
1229
1229
|
score *= 1.5;
|
|
@@ -1820,7 +1820,7 @@ var init_importer = __esm(() => {
|
|
|
1820
1820
|
});
|
|
1821
1821
|
|
|
1822
1822
|
// src/cli/main.ts
|
|
1823
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync, writeFileSync, readdirSync } from "fs";
|
|
1823
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync, writeFileSync, readdirSync, unlinkSync } from "fs";
|
|
1824
1824
|
import { homedir as homedir5 } from "os";
|
|
1825
1825
|
import { join as join5, resolve, dirname } from "path";
|
|
1826
1826
|
|
|
@@ -2210,7 +2210,7 @@ function uninstallCommands() {
|
|
|
2210
2210
|
const p = join5(COMMANDS_DIR, file);
|
|
2211
2211
|
try {
|
|
2212
2212
|
if (existsSync5(p))
|
|
2213
|
-
|
|
2213
|
+
unlinkSync(p);
|
|
2214
2214
|
} catch {}
|
|
2215
2215
|
}
|
|
2216
2216
|
}
|
package/dist/index.js
CHANGED
|
@@ -15539,7 +15539,7 @@ var STOP_WORDS = new Set([
|
|
|
15539
15539
|
]);
|
|
15540
15540
|
function tokenize(text) {
|
|
15541
15541
|
const tokens = [];
|
|
15542
|
-
const camelSplit = text.replace(/([a-
|
|
15542
|
+
const camelSplit = text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
|
|
15543
15543
|
const words = camelSplit.toLowerCase().replace(/[^a-z0-9_./\-]/g, " ").split(/\s+/).filter(Boolean);
|
|
15544
15544
|
for (const word of words) {
|
|
15545
15545
|
if (word.includes("/") && word.length > 3) {
|
|
@@ -15685,7 +15685,7 @@ async function searchIndex(query, opts = {}, db) {
|
|
|
15685
15685
|
const now = Date.now();
|
|
15686
15686
|
const merged = [...deduped.values()].map((r) => {
|
|
15687
15687
|
let score = r.score;
|
|
15688
|
-
const ageMs = now - r.created_at;
|
|
15688
|
+
const ageMs = Math.max(0, now - r.created_at);
|
|
15689
15689
|
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
15690
15690
|
if (ageDays < 7)
|
|
15691
15691
|
score *= 1.5;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-memory-hub",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Persistent memory system for Claude Code. Zero API key. Zero Python. 5 hooks + MCP server + SQLite FTS5 + semantic search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|