claude-mem-lite 5.0.0 → 5.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +18 -23
- package/README.zh-CN.md +24 -26
- package/commands/mem.md +3 -3
- package/commands/update.md +1 -1
- package/haiku-client.mjs +36 -5
- package/hash-utils.mjs +21 -0
- package/hook-episode.mjs +7 -1
- package/hook-optimize.mjs +103 -50
- package/hook-shared.mjs +8 -2
- package/hook-update.mjs +19 -2
- package/hook.mjs +16 -0
- package/install.mjs +76 -12
- package/lib/atomic-write.mjs +16 -0
- package/lib/deferred-work.mjs +7 -3
- package/lib/get-core.mjs +27 -1
- package/lib/install-shape.mjs +45 -4
- package/lib/maintain-core.mjs +9 -0
- package/lib/proc-lock.mjs +111 -13
- package/lib/proxy-fetch.mjs +26 -2
- package/lib/scrub-record.mjs +8 -0
- package/lib/tmp-fixture-sweep.mjs +9 -0
- package/mem-cli.mjs +44 -11
- package/npm-shrinkwrap.json +6 -2
- package/package.json +7 -2
- package/project-utils.mjs +43 -15
- package/schema.mjs +112 -49
- package/scripts/hook-launcher.mjs +7 -1
- package/scripts/setup.sh +5 -0
- package/secret-scrub.mjs +32 -3
- package/server.mjs +8 -2
- package/source-files.mjs +1 -1
- package/tool-schemas.mjs +23 -11
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "claude-mem-lite",
|
|
13
|
-
"version": "5.
|
|
13
|
+
"version": "5.1.0",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark)."
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "sdsrss"
|
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ How claude-mem-lite differs from the major neighbors in the LLM-memory space (ve
|
|
|
75
75
|
|
|
76
76
|
## Features
|
|
77
77
|
|
|
78
|
-
- **Automatic capture** -- Hooks into Claude Code lifecycle (PostToolUse,
|
|
78
|
+
- **Automatic capture** -- Hooks into the Claude Code lifecycle (SessionStart, PreCompact, PreToolUse, PostToolUse, PostToolUseFailure, Stop, UserPromptSubmit — the seven events in `hooks/hooks.json`) to record observations without manual effort
|
|
79
79
|
- **Hybrid search** -- FTS5 BM25 + TF-IDF vector cosine similarity, merged via Reciprocal Rank Fusion (RRF). FTS5 handles keyword matching; 512-dim TF-IDF vectors capture semantic similarity for recall beyond exact terms
|
|
80
80
|
- **Timeline browsing** -- Navigate observations chronologically with anchor-based context windows
|
|
81
81
|
- **Episode batching** -- Groups related file operations into coherent episodes before LLM encoding
|
|
@@ -105,14 +105,12 @@ How claude-mem-lite differs from the major neighbors in the LLM-memory space (ve
|
|
|
105
105
|
- **Atomic writes** -- All file writes (episodes, CLAUDE.md) use write-to-tmp + rename to prevent corruption on crash
|
|
106
106
|
- **Robust locking** -- PID-aware lock files with automatic stale/orphan cleanup (>30s timeout or dead PID)
|
|
107
107
|
- **Stale session cleanup** -- Sessions active for >24h are automatically marked as abandoned on next start
|
|
108
|
-
- **
|
|
109
|
-
- **Domain synonym expansion** -- Registry search queries expand to domain synonyms (e.g., "fix" → debug, bugfix, troubleshoot, diagnose, repair)
|
|
108
|
+
- **Domain synonym expansion** -- Search queries expand to domain synonyms (e.g., "fix" → debug, bugfix, troubleshoot, diagnose, repair)
|
|
110
109
|
- **Multi-provider LLM mode** -- Provider priority `ANTHROPIC_API_KEY` (direct Anthropic API) → `OPENROUTER_API_KEY` (OpenRouter, OpenAI-compatible — point it at any model via `OPENROUTER_MODEL`) → `claude -p` CLI fallback when no key is set
|
|
111
110
|
- **Lesson-learned indexing** -- `lesson_learned` field indexed in FTS5 with weight 8, making past debugging insights directly searchable
|
|
112
111
|
- **Cross-source normalization** -- `mem_search` normalizes scores across observations, sessions, and prompts before merging, preventing any source from dominating results
|
|
113
112
|
- **Exponential recency decay** -- Type-differentiated half-lives (decisions: 90d, discoveries: 60d, bugfixes: 14d, changes: 7d) consistently applied in all ranking paths
|
|
114
113
|
- **Prompt-time memory injection** -- UserPromptSubmit hook automatically searches and injects relevant past observations with recency and importance weighting
|
|
115
|
-
- **Smart skill invocation** -- Auto-loaded and searched managed skills/agents include portable `~` paths with `Read()` guidance; native plugin skills recommend `Skill("full:name")`; prevents `Skill()` misuse for managed resources that aren't registered with Claude Code's native handler
|
|
116
114
|
- **Dual injection dedup** -- `user-prompt-search.js` and `handleUserPrompt` coordinate via temp file to prevent duplicate memory injection
|
|
117
115
|
- **Plugin cache hook self-heal** -- Claude Code runtime reads plugin hooks from `~/.claude/plugins/cache/<mp>/<plugin>/<ver>/hooks/hooks.json`, not from the marketplace source. When `install.mjs`-managed `settings.json` hooks coexist with a stale cache `hooks.json` (e.g. from a previous marketplace install or a plugin auto-update), the runtime registers hooks twice → every session start / user prompt fires twice. `install.mjs` and `hook-update.mjs` now clear cache `hooks.json` in every version dir, and `hook.mjs session-start` self-heals on every session (gated by `hasInstallManagedHooks` so plugin-only users are not affected). `install.mjs status` reports cache pollution state (since v2.31.1/2.31.2).
|
|
118
116
|
- **Result-dedup cooldown** -- User-prompt memory injection uses result-overlap detection (>80% ID overlap → skip) instead of time-based cooldown, allowing topic switches within seconds while preventing redundant injections
|
|
@@ -188,8 +186,8 @@ Source files stay in the cloned repo. Update via `git pull && node install.mjs i
|
|
|
188
186
|
### What happens during installation
|
|
189
187
|
|
|
190
188
|
1. **Install dependencies** -- `npm install --omit=dev` (compiles native `better-sqlite3`)
|
|
191
|
-
2. **Register MCP server** -- `mem-lite` server with
|
|
192
|
-
3. **Configure hooks** -- `PostToolUse`, `
|
|
189
|
+
2. **Register MCP server** -- `mem-lite` server with 18 tools (9 core exposed via `tools/list` + 9 hidden-but-callable; see the Usage section for the full table). The pre-v2.78 generic server name `mem` is renamed to `mem-lite` for namespace hygiene; the tool names themselves (`mem_search`, `mem_recall`, ...) are unchanged.
|
|
190
|
+
3. **Configure hooks** -- all seven lifecycle events: `SessionStart`, `PreCompact`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `Stop`, `UserPromptSubmit`
|
|
193
191
|
4. **Create data directory** -- `~/.claude-mem-lite/` (hidden) for database, runtime, and managed resource files
|
|
194
192
|
5. **Auto-migrate** -- If `~/.claude-mem/` (original claude-mem) or `~/claude-mem-lite/` (pre-v0.5 unhidden) exists, migrates database and runtime files to `~/.claude-mem-lite/`, preserving the original untouched
|
|
195
193
|
6. **Initialize database** -- SQLite with WAL mode, FTS5 indexes created on first server start
|
|
@@ -228,8 +226,6 @@ rm -rf ~/claude-mem-lite/ # pre-v0.5 unhidden (if not auto-moved)
|
|
|
228
226
|
ep-flush-*.json # Flushed episodes awaiting processing
|
|
229
227
|
reads-<project>.txt # Read file paths (collected on flush)
|
|
230
228
|
managed/
|
|
231
|
-
skills/ # Standalone skills: {name}/SKILL.md
|
|
232
|
-
agents/ # Agent plugins: {group}/agents/{name}.md + skills/*/SKILL.md
|
|
233
229
|
repos/ # Shallow-cloned source repos
|
|
234
230
|
```
|
|
235
231
|
|
|
@@ -237,11 +233,14 @@ rm -rf ~/claude-mem-lite/ # pre-v0.5 unhidden (if not auto-moved)
|
|
|
237
233
|
|
|
238
234
|
### MCP Tools (used automatically by Claude)
|
|
239
235
|
|
|
240
|
-
As of v2.70.0, the server registers
|
|
241
|
-
tools appear in `tools/list`. The
|
|
236
|
+
As of v2.70.0, the server registers 18 tools in total but only the 9 **core**
|
|
237
|
+
tools appear in `tools/list`. The 9 **hidden** tools remain callable at the
|
|
242
238
|
protocol layer (`tools/call` by exact name still routes normally); they're
|
|
243
|
-
omitted from the list response so Claude Code sessions don't load
|
|
244
|
-
tool schemas at startup.
|
|
239
|
+
omitted from the list response so Claude Code sessions don't load 9 extra
|
|
240
|
+
tool schemas at startup. (It read 20 / 11 until v5.0.0 removed the two skill-registry
|
|
241
|
+
tools — `tool-schemas.mjs` is the source of truth, and
|
|
242
|
+
`tests/tool-count-docs.test.mjs` now holds this paragraph, both README tool tables,
|
|
243
|
+
`README.zh-CN.md`, `llms.txt` and `docs/ARCHITECTURE.md` to it.) Hidden tools are the maintenance / admin / browser
|
|
245
244
|
surface — reach them through the CLI column in the second table.
|
|
246
245
|
|
|
247
246
|
**Core (9, exposed to Claude Code)**
|
|
@@ -258,7 +257,7 @@ surface — reach them through the CLI column in the second table.
|
|
|
258
257
|
| `mem_defer_list` | List open deferred items for the current project. |
|
|
259
258
|
| `mem_defer_drop` | Drop a deferred item without fixing it; requires a `reason` for the audit trail. |
|
|
260
259
|
|
|
261
|
-
**Hidden-but-callable (
|
|
260
|
+
**Hidden-but-callable (9, CLI-routed)**
|
|
262
261
|
|
|
263
262
|
| Tool | CLI equivalent | Notes |
|
|
264
263
|
|------|----------------|-------|
|
|
@@ -452,9 +451,6 @@ UserPromptSubmit (two parallel paths)
|
|
|
452
451
|
-> [user-prompt-search.js] Auto-search memory via FTS5 + active file context
|
|
453
452
|
-> [user-prompt-search.js] Inject relevant past observations with recency/importance weighting
|
|
454
453
|
-> [user-prompt-search.js] Write injected IDs to temp file for dedup
|
|
455
|
-
-> [user-prompt-search.js] L1 skill auto-load: match managed skill names in prompt
|
|
456
|
-
-> Load content with portable ~ path + Read() guidance
|
|
457
|
-
-> source="managed-skill|managed-agent", path="~/.claude-mem-lite/managed/..."
|
|
458
454
|
-> [hook.mjs handleUserPrompt] Capture user prompt text to user_prompts table
|
|
459
455
|
-> [hook.mjs handleUserPrompt] Increment session prompt counter
|
|
460
456
|
-> [hook.mjs handleUserPrompt] Handoff: detect continuation intent → inject previous session context
|
|
@@ -547,7 +543,7 @@ Shows MCP registration, hook configuration, plugin disabled state, and database
|
|
|
547
543
|
|
|
548
544
|
### Recovery (stuck install / hook errors)
|
|
549
545
|
|
|
550
|
-
If you see `ERR_MODULE_NOT_FOUND` on PreToolUse:Read/Edit
|
|
546
|
+
If you see `ERR_MODULE_NOT_FOUND` on PreToolUse:Read/Edit hooks, or `claude-mem-lite` commands crash with import errors, you're likely hit by a partial auto-update — the updater copied new scripts but missed a sibling `lib/*` file, breaking the hook chain (and the next auto-update that would have healed it).
|
|
551
547
|
|
|
552
548
|
**v2.84.0+** ships a `repair` subcommand that re-syncs from the latest GitHub release:
|
|
553
549
|
|
|
@@ -636,12 +632,11 @@ claude-mem-lite/
|
|
|
636
632
|
scripts/
|
|
637
633
|
setup.sh # Setup hook: npm install + migration (hidden dir + old dir)
|
|
638
634
|
post-tool-use.sh # Bash pre-filter: skips noise in ~5ms, tracks Read paths
|
|
639
|
-
user-prompt-search.js # UserPromptSubmit hook: auto-search memory
|
|
640
|
-
pre-skill-bridge.js # PreToolUse hook: L2 skill bridge for managed resources
|
|
635
|
+
user-prompt-search.js # UserPromptSubmit hook: auto-search memory on user prompts
|
|
641
636
|
pre-tool-recall.js # PreToolUse hook: file lesson recall before Edit/Write
|
|
637
|
+
post-tool-recall.js # PostToolUse hook: error recall after a failed tool call
|
|
638
|
+
pre-agent-inject.sh # PreToolUse hook: context for spawned agents
|
|
642
639
|
prompt-search-utils.mjs # Shared logic: skip patterns, intent detection, name matching
|
|
643
|
-
convert-commands.mjs # Converts command .md → SKILL.md in managed plugins
|
|
644
|
-
index-managed.mjs # Offline indexer for managed resources
|
|
645
640
|
# Test & benchmark (dev only)
|
|
646
641
|
tests/ # Unit, property, integration, contract, E2E, pipeline tests
|
|
647
642
|
benchmark/ # BM25 search quality benchmarks + CI gate
|
|
@@ -765,7 +760,7 @@ claude-mem-lite.
|
|
|
765
760
|
|
|
766
761
|
| Variable | Description | Default |
|
|
767
762
|
|----------|-------------|---------|
|
|
768
|
-
| `CLAUDE_MEM_ALL_TOOLS` | `1` exposes all
|
|
763
|
+
| `CLAUDE_MEM_ALL_TOOLS` | `1` exposes all 18 MCP tools in `tools/list` instead of the 9 core ones (pre-v2.34.0 behavior). The 9 hidden tools stay callable by exact name either way. | _(9 core)_ |
|
|
769
764
|
| `CLAUDE_MEM_FILE_INTEL` | `0` disables the file-intel block injected before `Read` (past observations about the file you are about to open). | _(on)_ |
|
|
770
765
|
| `CLAUDE_MEM_FILE_INTEL_MIN_TOKENS` | Files smaller than this stay silent — file-intel only pays for itself on large files. | `800` |
|
|
771
766
|
| `CLAUDE_MEM_REREAD_GUARD` | `0` disables the warning when the same file is read twice in a session. Never fires on `offset`/`limit` paging. | _(on)_ |
|
|
@@ -835,7 +830,7 @@ what is already stored — only whether new work runs.
|
|
|
835
830
|
| `CLAUDE_MEM_SKIP_MAINTAIN` | Skip the 24h auto-maintain pass (decay, purge, backup). | _(runs)_ |
|
|
836
831
|
| `CLAUDE_MEM_SKIP_OPTIMIZE` | Skip the LLM optimization pass (re-enrich, normalize, cluster-merge). | _(runs)_ |
|
|
837
832
|
| `CLAUDE_MEM_SKIP_AUTO_DEDUP_FUZZY` | Skip the MinHash near-duplicate pass, keeping exact dedup. | _(runs)_ |
|
|
838
|
-
| `CLAUDE_MEM_SKIP_MARKER_GC` | Skip the runtime-marker sweep. | _(runs)_ |
|
|
833
|
+
| `CLAUDE_MEM_SKIP_MARKER_GC` | Skip the runtime-marker sweep. **Must be exactly `1`** — unlike the other `CLAUDE_MEM_SKIP_*` flags, which accept any truthy value, this one compares against the string `1`. That is deliberate: a truthy check makes `=0` mean "skip", which is the opposite of what anyone typing it intends. | _(runs)_ |
|
|
839
834
|
| `CLAUDE_MEM_SKIP_UPDATE` | Skip the 24h auto-update check against GitHub Releases. | _(runs)_ |
|
|
840
835
|
| `CLAUDE_MEM_SKIP_SIG_VERIFY` | Skip Ed25519 signature verification of a downloaded update. **Escape hatch — leaves updates unauthenticated.** | _(verifies)_ |
|
|
841
836
|
| `CLAUDE_MEM_NO_LESSON_RETRY` | `1` disables the one-shot retry that re-asks for a missing `lesson_learned`. | _(retries)_ |
|
package/README.zh-CN.md
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
## 功能特性
|
|
56
56
|
|
|
57
|
-
- **自动捕获** -- 挂载到 Claude Code
|
|
57
|
+
- **自动捕获** -- 挂载到 Claude Code 生命周期(`hooks/hooks.json` 里的七个事件:SessionStart、PreCompact、PreToolUse、PostToolUse、PostToolUseFailure、Stop、UserPromptSubmit),无需手动操作即可记录观察
|
|
58
58
|
- **FTS5 搜索** -- 基于 BM25 排名的全文搜索,覆盖观察、会话摘要和用户提示,支持重要度加权
|
|
59
59
|
- **时间线浏览** -- 基于锚点的时间上下文窗口,按时间顺序浏览观察
|
|
60
60
|
- **Episode 批处理** -- 将相关文件操作分组为连贯的 episode,再进行 LLM 编码
|
|
@@ -81,16 +81,13 @@
|
|
|
81
81
|
- **原子写入** -- 所有文件写入(episode、CLAUDE.md)使用 write-to-tmp + rename 防止崩溃时损坏
|
|
82
82
|
- **健壮锁机制** -- PID 感知的锁文件,自动清理过期(>30s)或孤儿(PID 已死)锁
|
|
83
83
|
- **过期会话清理** -- 活跃超过 24 小时的会话在下次启动时自动标记为 abandoned
|
|
84
|
-
-
|
|
85
|
-
- **领域同义词扩展** -- 注册表搜索查询自动扩展领域同义词(如 "修复" → fix, debug, bugfix, repair, error)
|
|
86
|
-
- **持久化冷却机制** -- 5 分钟跨会话冷却 + 同会话去重,避免重复推荐 skill 自动加载
|
|
84
|
+
- **领域同义词扩展** -- 搜索查询自动扩展领域同义词(如 "修复" → fix, debug, bugfix, repair, error)
|
|
87
85
|
- **多 provider LLM 调用** -- provider 优先级 `ANTHROPIC_API_KEY`(直连 Anthropic API)→ `OPENROUTER_API_KEY`(OpenRouter,OpenAI 兼容,可用 `OPENROUTER_MODEL` 指向任意模型)→ 无 key 时回退 `claude -p` CLI
|
|
88
86
|
- **Haiku 熔断器** -- 连续 3 次 LLM 失败后,禁用 Haiku 调度 5 分钟,防止级联延迟
|
|
89
87
|
- **否定意图感知** -- 正确处理 "不要测试了,先修 bug" 等复杂提示,排除被否定的意图,支持中英文混合输入
|
|
90
88
|
- **可配置 LLM 模型** -- 通过 `CLAUDE_MEM_MODEL` 环境变量在 Haiku(快速/低成本)和 Sonnet(深度分析)之间切换
|
|
91
89
|
- **数据库自动恢复** -- 启动时检测并清理损坏的 WAL/SHM 文件;定期 WAL checkpoint 防止无限增长
|
|
92
90
|
- **Schema 自动迁移** -- 每次启动运行幂等的 `ALTER TABLE` 迁移,安全地添加新列和索引,不丢失数据
|
|
93
|
-
- **探索奖励** -- 注册表中的新资源在复合排名中获得公平机会;高推荐零采纳的"僵尸"资源被惩罚
|
|
94
91
|
- **LLM 并发控制** -- 基于文件的信号量将后台 worker 限制为 2 个并发 LLM 调用,防止资源争用
|
|
95
92
|
- **stdin 溢出保护** -- Hook 输入在 256KB 处截断,对超大工具输出使用正则挽救关键信息
|
|
96
93
|
- **跨会话交接** -- 在 `/clear` 或 `/exit` 时捕获会话状态(请求、已完成工作、后续步骤、关键文件),下次会话检测到继续意图时自动注入上下文(支持显式关键词和 FTS5 术语重叠匹配)
|
|
@@ -109,7 +106,7 @@
|
|
|
109
106
|
|
|
110
107
|
## 环境要求
|
|
111
108
|
|
|
112
|
-
- **Node.js** >=
|
|
109
|
+
- **Node.js** >= 22(v4.0.0 起:better-sqlite3 13 要求 >=22,Node 20 已于 2026-04 EOL;`package.json` 的 `engines` 是唯一事实来源)
|
|
113
110
|
- **Claude Code** CLI 已安装并配置(`claude` 命令可用)
|
|
114
111
|
- **SQLite3** 支持(由 `better-sqlite3` 提供,安装时编译)
|
|
115
112
|
- **平台**:Linux 或 macOS(参见[平台支持](#平台支持))
|
|
@@ -148,13 +145,13 @@ node install.mjs install
|
|
|
148
145
|
### 安装过程
|
|
149
146
|
|
|
150
147
|
1. **安装依赖** -- `npm install --omit=dev`(编译原生 `better-sqlite3`)
|
|
151
|
-
2. **注册 MCP 服务器** -- `mem-lite` 服务器,包含
|
|
148
|
+
2. **注册 MCP 服务器** -- `mem-lite` 服务器,包含 18 个工具(9 个核心通过 `tools/list` 暴露 + 9 个隐藏但可调;完整表见 Usage 段)。v2.78 前服务器名为通用的 `mem`,现已改名为 `mem-lite` 避免与用户其它 `.mcp.json` 冲突;工具名(`mem_search`/`mem_recall` 等)保持不变。
|
|
152
149
|
|
|
153
150
|
> **自动 adopt 会写进你的项目,且每次 SessionStart 都跑(v3.13+)。** 插件向**项目自己的 `<cwd>/CLAUDE.md`**(通常是会进 git 的文件)写入一个 slug 限定的**托管块**,外加 `<cwd>/.claude/plugin_claude_mem_lite.md` 详情文件。该块是一条提升 Claude 主动调用 `mem_recall` / `mem_save` 的 system-authority 指针;块以外的内容逐字保留,也能与其它插件的块共存于同一文件。这是**每次** SessionStart 都做的幂等同步,不只是第一次——块被删掉会重新写回,出货模板变了会刷新。**任何安装路径都生效**(npm、npx、`/plugin`、手动),**无需再手动跑 `/adopt`**。
|
|
154
151
|
>
|
|
155
152
|
> 关闭方式:项目级 `claude-mem-lite adopt --disable`(重新启用用 `--enable`);全局 `export MEM_NO_AUTO_ADOPT=1`;只冻结模板刷新用 `CLAUDE_MEM_NO_TEMPLATE_REFRESH=1`。`claude-mem-lite unadopt` 可移除托管块与详情文件。手动 `/adopt` 仍保留用于编辑后重写或 `--all` 批量场景。
|
|
156
|
-
3. **配置钩子** --
|
|
157
|
-
4. **创建数据目录** -- `~/.claude-mem-lite
|
|
153
|
+
3. **配置钩子** -- 全部七个生命周期事件:`SessionStart`、`PreCompact`、`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`Stop`、`UserPromptSubmit`
|
|
154
|
+
4. **创建数据目录** -- `~/.claude-mem-lite/`(隐藏目录),存放数据库与运行时文件
|
|
158
155
|
5. **自动迁移** -- 自动检测 `~/.claude-mem/`(原版 claude-mem)或 `~/claude-mem-lite/`(v0.5 前的非隐藏目录),将数据库和运行时文件迁移到 `~/.claude-mem-lite/`,原目录保持不变
|
|
159
156
|
6. **初始化数据库** -- SQLite WAL 模式,FTS5 索引在服务器首次启动时创建
|
|
160
157
|
|
|
@@ -192,8 +189,6 @@ rm -rf ~/claude-mem-lite/ # v0.5 前的非隐藏目录(如未自动迁移)
|
|
|
192
189
|
ep-flush-*.json # 已刷新的 episode,等待处理
|
|
193
190
|
reads-<project>.txt # Read 文件路径(刷新时收集)
|
|
194
191
|
managed/
|
|
195
|
-
skills/ # 独立 skill:{name}/SKILL.md
|
|
196
|
-
agents/ # Agent 插件:{group}/agents/{name}.md + skills/*/SKILL.md
|
|
197
192
|
repos/ # 浅克隆的源代码仓库
|
|
198
193
|
```
|
|
199
194
|
|
|
@@ -201,12 +196,16 @@ rm -rf ~/claude-mem-lite/ # v0.5 前的非隐藏目录(如未自动迁移)
|
|
|
201
196
|
|
|
202
197
|
### MCP 工具
|
|
203
198
|
|
|
204
|
-
v2.34.0
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
199
|
+
v2.34.0 起服务端只把一部分工具暴露给 `tools/list`。当前是 18 个工具,其中 9 个
|
|
200
|
+
**核心** 工具出现在列表里,另外 9 个 **隐藏** 工具仍然注册在 MCP 层(按名
|
|
201
|
+
`tools/call` 仍命中),只是不出现在列表响应里,以避免 Claude Code 会话启动时
|
|
202
|
+
多加载 9 份工具 schema。隐藏工具走下面表格的 CLI 入口。
|
|
208
203
|
|
|
209
|
-
|
|
204
|
+
(这里长期写着 17 / 6 / 11,而英文 README 写着 20 / 9 / 11 —— 两个都不对。
|
|
205
|
+
`tool-schemas.mjs` 是唯一事实来源,`tests/tool-count-docs.test.mjs` 现在把两份
|
|
206
|
+
README 和 `docs/ARCHITECTURE.md` 都钉在它上面。)
|
|
207
|
+
|
|
208
|
+
**核心(9 个,暴露给 Claude Code)**
|
|
210
209
|
|
|
211
210
|
| 工具 | 描述 |
|
|
212
211
|
|------|------|
|
|
@@ -216,8 +215,11 @@ v2.34.0 起服务端注册 17 个工具,但 `tools/list` 只暴露 6 个 **核
|
|
|
216
215
|
| `mem_timeline` | 围绕锚点按时间顺序浏览观察。 |
|
|
217
216
|
| `mem_get` | 获取指定观察 ID 的完整详情(包含重要度和关联 ID)。 |
|
|
218
217
|
| `mem_save` | 手动保存记忆/观察。 |
|
|
218
|
+
| `mem_defer` | 记录一条跨会话待办(deferred work)。 |
|
|
219
|
+
| `mem_defer_list` | 列出当前项目未关闭的待办。 |
|
|
220
|
+
| `mem_defer_drop` | 带理由地关闭一条待办。 |
|
|
219
221
|
|
|
220
|
-
**隐藏但可按名调用(
|
|
222
|
+
**隐藏但可按名调用(9 个,走 CLI)**
|
|
221
223
|
|
|
222
224
|
| 工具 | 对应 CLI | 说明 |
|
|
223
225
|
|------|----------|------|
|
|
@@ -368,9 +370,6 @@ PostToolUse(每次工具执行)
|
|
|
368
370
|
UserPromptSubmit(两个并行路径)
|
|
369
371
|
-> [user-prompt-search.js] 通过 FTS5 + 活跃文件上下文自动搜索记忆
|
|
370
372
|
-> [user-prompt-search.js] 注入相关历史观察(按时效和重要性加权)
|
|
371
|
-
-> [user-prompt-search.js] L1 Skill 自动加载:匹配 prompt 中的 managed skill 名
|
|
372
|
-
-> 加载内容 + 便携 ~ 路径 + Read() 调用指引
|
|
373
|
-
-> source="managed-skill|managed-agent", path="~/.claude-mem-lite/managed/..."
|
|
374
373
|
-> [hook.mjs] 捕获用户提示文本到 user_prompts 表
|
|
375
374
|
-> [hook.mjs] 递增会话提示计数器
|
|
376
375
|
-> [hook.mjs] 交接:检测继续意图 → 注入上一次会话上下文
|
|
@@ -430,7 +429,7 @@ npx claude-mem-lite doctor # 诊断问题
|
|
|
430
429
|
|
|
431
430
|
### 故障恢复(安装卡死 / hook 报错)
|
|
432
431
|
|
|
433
|
-
如果你看到 PreToolUse:Read/Edit
|
|
432
|
+
如果你看到 PreToolUse:Read/Edit hook 报 `ERR_MODULE_NOT_FOUND`,或者 `claude-mem-lite` 命令本身因为 import 错误崩溃,多半是被部分自动更新坑了——更新器复制了新脚本但漏了配套的 `lib/*` 文件,hook 链就此断掉(连下一次本可自愈的自动更新也跑不了)。
|
|
434
433
|
|
|
435
434
|
**v2.84.0+** 提供 `repair` 子命令,从 GitHub 最新 release 重新同步:
|
|
436
435
|
|
|
@@ -516,12 +515,11 @@ claude-mem-lite/
|
|
|
516
515
|
scripts/
|
|
517
516
|
setup.sh # Setup 钩子:npm install + 迁移(隐藏目录 + 旧目录)
|
|
518
517
|
post-tool-use.sh # Bash 预过滤器:~5ms 跳过噪声,追踪 Read 路径
|
|
519
|
-
user-prompt-search.js # UserPromptSubmit
|
|
520
|
-
pre-skill-bridge.js # PreToolUse 钩子:L2 managed skill 桥接
|
|
518
|
+
user-prompt-search.js # UserPromptSubmit 钩子:用户提问时自动搜索记忆
|
|
521
519
|
pre-tool-recall.js # PreToolUse 钩子:Edit/Write 前文件教训回忆
|
|
520
|
+
post-tool-recall.js # PostToolUse 钩子:工具失败后的错误召回
|
|
521
|
+
pre-agent-inject.sh # PreToolUse 钩子:为子代理注入上下文
|
|
522
522
|
prompt-search-utils.mjs # 共享逻辑:跳过模式、意图检测、名称匹配
|
|
523
|
-
convert-commands.mjs # 将 command .md 转换为托管插件中的 SKILL.md
|
|
524
|
-
index-managed.mjs # 托管资源离线索引器
|
|
525
523
|
# 测试和基准(仅开发)
|
|
526
524
|
tests/ # 单元、属性、集成、契约、E2E、管线测试
|
|
527
525
|
benchmark/ # BM25 搜索质量基准 + CI 门控
|
|
@@ -564,7 +562,7 @@ npm run benchmark:gate # CI 门控:指标回退超过 5% 容差时失败
|
|
|
564
562
|
|
|
565
563
|
| 变量 | 说明 | 默认值 |
|
|
566
564
|
|------|------|--------|
|
|
567
|
-
| `CLAUDE_MEM_DIR` |
|
|
565
|
+
| `CLAUDE_MEM_DIR` | 自定义数据目录。所有数据库与运行时文件均存储在此。 | `~/.claude-mem-lite/` |
|
|
568
566
|
| `CLAUDE_MEM_MODEL` | 后台 LLM 调用模型(Episode 提取、会话总结、调度)。可选 `haiku` 或 `sonnet`。 | `haiku` |
|
|
569
567
|
| `ANTHROPIC_API_KEY` | Anthropic API key。设置后所有后台 LLM 调用直连 Anthropic Messages API(带 prompt caching),优先级最高。 | _(未设 → CLI)_ |
|
|
570
568
|
| `OPENROUTER_API_KEY` | OpenRouter API key(OpenAI 兼容)。当**未设** `ANTHROPIC_API_KEY` 时用于后台 LLM 调用;两者都未设则回退到 `claude -p` CLI。 | _(未设)_ |
|
package/commands/mem.md
CHANGED
|
@@ -30,9 +30,9 @@ When the user invokes `/mem`, parse their intent:
|
|
|
30
30
|
- `/mem save <text>` → call `mem_save` MCP tool with the text as content
|
|
31
31
|
- `/mem stats` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs stats` via Bash
|
|
32
32
|
- `/mem get <ids>` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs get <ids>` via Bash
|
|
33
|
-
- `/mem cleanup` → run `mem_maintain(action="scan")`, report pending purge count and stale items to user, ask for confirmation, then run `mem_maintain(action="execute", operations=["purge_stale"])` if confirmed
|
|
34
|
-
- `/mem cleanup Nd` (e.g. `60d`) → same as above but
|
|
35
|
-
- `/mem cleanup keep Nd` (e.g. `keep 14d`) → same as above with `retain_days=N
|
|
33
|
+
- `/mem cleanup` → run `mem_maintain(action="scan")`, report pending purge count and stale items to user, ask for confirmation, then run `mem_maintain(action="execute", operations=["purge_stale"], confirm=true)` if confirmed. **`confirm=true` is required and is not optional politeness:** without it the call returns a dry-run PREVIEW and deletes nothing, while still succeeding — so you would report a cleanup that never happened.
|
|
34
|
+
- `/mem cleanup Nd` (e.g. `60d`) → same as above but add `retain_days=N` to only purge items older than N days. **`retain_days` must be between 7 and 365**; anything outside that range is rejected by the schema, so `/mem cleanup 3d` cannot be honoured — say so rather than silently substituting the default.
|
|
35
|
+
- `/mem cleanup keep Nd` (e.g. `keep 14d`) → same as above with `retain_days=N`, same 7–365 range.
|
|
36
36
|
- `/mem <query>` (no subcommand) → treat as search, run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs search <query>` via Bash
|
|
37
37
|
|
|
38
38
|
Use Bash commands first. For detailed data, use `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs get <id>` via Bash.
|
package/commands/update.md
CHANGED
|
@@ -22,7 +22,7 @@ When the user invokes `/mem:update`, perform the following maintenance cycle:
|
|
|
22
22
|
3. Call `mem_maintain(action="execute", operations=["cleanup","decay","boost"])` to apply safe automatic changes
|
|
23
23
|
4. If duplicates were found in scan, review them and call `mem_maintain(action="execute", operations=["dedup"], merge_ids=[[keepId, removeId1, ...], ...])` — keep the more important/recent observation in each pair
|
|
24
24
|
5. Run `mem_compress(preview=false)` for old low-value observations
|
|
25
|
-
6. **If pending purge items > 0**: Report the count to the user and ask for confirmation. If confirmed, call `mem_maintain(action="execute", operations=["purge_stale"])`. User may optionally specify `retain_days` (default 30) to control how many days of data to keep. Do NOT purge without explicit user confirmation.
|
|
25
|
+
6. **If pending purge items > 0**: Report the count to the user and ask for confirmation. If confirmed, call `mem_maintain(action="execute", operations=["purge_stale"], confirm=true)`. **`confirm=true` is required:** without it the call returns a dry-run preview and deletes nothing while still succeeding, so you would report a purge that never happened. User may optionally specify `retain_days` (default 30, allowed range 7–365) to control how many days of data to keep. Do NOT purge without explicit user confirmation.
|
|
26
26
|
|
|
27
27
|
### Phase 2: Summary
|
|
28
28
|
|
package/haiku-client.mjs
CHANGED
|
@@ -6,13 +6,40 @@
|
|
|
6
6
|
// overridable via OPENROUTER_MODEL
|
|
7
7
|
|
|
8
8
|
import { execFileSync, spawn } from 'child_process';
|
|
9
|
+
import { mkdirSync } from 'fs';
|
|
9
10
|
import { readFileSync } from 'fs';
|
|
10
11
|
import { join } from 'path';
|
|
11
12
|
import { randomUUID } from 'crypto';
|
|
12
13
|
import { debugLog, debugCatch, parseJsonFromLLM } from './utils.mjs';
|
|
13
14
|
import { DB_DIR } from './schema.mjs';
|
|
15
|
+
import { resolveRuntimeDir } from './lib/resolve-data-dir.mjs';
|
|
14
16
|
import { httpConnectProxyFor, postViaConnectProxy } from './lib/proxy-fetch.mjs';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* cwd for every `claude -p` spawn. R10 P2-13.
|
|
20
|
+
*
|
|
21
|
+
* This was `/tmp`, which is world-writable. Claude Code loads a project-level CLAUDE.md
|
|
22
|
+
* and .claude/settings.json from its cwd, so on a shared host ANY local account could
|
|
23
|
+
* create /tmp/CLAUDE.md and inject instructions into every episode summary, session
|
|
24
|
+
* summary and optimize call this process makes — and the CLI leg is the fallback every
|
|
25
|
+
* keyed provider failure lands on, so it is not an exotic path.
|
|
26
|
+
*
|
|
27
|
+
* The original reason for /tmp was ghost sessions in the user's /resume list, and that is
|
|
28
|
+
* already solved by --no-session-persistence on the same spawns. A private directory under
|
|
29
|
+
* the runtime dir (whose parent is 0700) keeps that property and removes the injection
|
|
30
|
+
* surface. Created lazily; if creation fails we still do not fall back to /tmp — an
|
|
31
|
+
* unwritable cwd fails the spawn loudly, which is the better failure.
|
|
32
|
+
*/
|
|
33
|
+
function cliSpawnCwd() {
|
|
34
|
+
const dir = join(resolveRuntimeDir(DB_DIR), 'cli-cwd');
|
|
35
|
+
try {
|
|
36
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
37
|
+
} catch {
|
|
38
|
+
/* already there, or unwritable — the spawn reports it */
|
|
39
|
+
}
|
|
40
|
+
return dir;
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
// ─── Model Resolution ────────────────────────────────────────────────────────
|
|
17
44
|
|
|
18
45
|
// CLI name → API model ID mapping
|
|
@@ -237,7 +264,10 @@ export async function callHaikuJSON(prompt, opts) {
|
|
|
237
264
|
|
|
238
265
|
/**
|
|
239
266
|
* Non-blocking sibling of callHaikuJSON for callers reachable from an MCP request
|
|
240
|
-
* handler
|
|
267
|
+
* handler. R10 P3-28: this used to name `mem_registry enrich / import_url` as the caller,
|
|
268
|
+
* a tool removed in v5.0.0 — read as a live example, it sent readers looking for a handler
|
|
269
|
+
* that does not exist. The REASON is what still applies to whatever calls it next: an MCP
|
|
270
|
+
* request handler must not block the server event loop. Same
|
|
241
271
|
* provider priority; the CLI leg — primary AND post-provider-failure fallback —
|
|
242
272
|
* is the async spawn, so a keyed-provider outage cannot freeze the server event
|
|
243
273
|
* loop for BG_LLM_TIMEOUT_MS (D#138 MEDIUM-3).
|
|
@@ -245,8 +275,9 @@ export async function callHaikuJSON(prompt, opts) {
|
|
|
245
275
|
* `resolveModel().cli`, NOT the literal 'haiku': despite the name, callHaikuJSON
|
|
246
276
|
* reaches the model through resolveModel() on ALL three legs (callHaikuAPI,
|
|
247
277
|
* callOpenRouterAPI, callHaikuCLI), so it honours the documented CLAUDE_MEM_MODEL
|
|
248
|
-
* knob. Pinning 'haiku' here would silently downgrade
|
|
249
|
-
*
|
|
278
|
+
* knob. Pinning 'haiku' here would silently downgrade any caller's model for every user
|
|
279
|
+
* who set CLAUDE_MEM_MODEL=sonnet — pre-tag review finding, v3.68.0, when the caller in
|
|
280
|
+
* question was registry enrichment.
|
|
250
281
|
*
|
|
251
282
|
* Defaults also mirror callHaiku (10s / 500 tokens), not callModelJSONAsync's
|
|
252
283
|
* 15s / 1000: a caller that omits opts must get the sync twin's budget.
|
|
@@ -565,7 +596,7 @@ export function execClaudeCliSync(modelName, { input, timeout }) {
|
|
|
565
596
|
encoding: 'utf8',
|
|
566
597
|
env: { ...process.env, CLAUDE_MEM_HOOK_RUNNING: '1', DISABLE_CLAUDEMD_HOOKS: '1' },
|
|
567
598
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
568
|
-
cwd:
|
|
599
|
+
cwd: cliSpawnCwd(), // private dir, not /tmp — see cliSpawnCwd (R10 P2-13)
|
|
569
600
|
};
|
|
570
601
|
const args = claudeArgs(modelName);
|
|
571
602
|
const started = Date.now();
|
|
@@ -650,7 +681,7 @@ export async function callModelCLIAsync(prompt, model, { timeout }) {
|
|
|
650
681
|
// Same headless-tax flags + flag-compat retry as callModelCLI (rationale there).
|
|
651
682
|
child = spawn(getClaudePath(), args, {
|
|
652
683
|
env: { ...process.env, CLAUDE_MEM_HOOK_RUNNING: '1', DISABLE_CLAUDEMD_HOOKS: '1' },
|
|
653
|
-
cwd:
|
|
684
|
+
cwd: cliSpawnCwd(), // private dir, not /tmp — see cliSpawnCwd (R10 P2-13)
|
|
654
685
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
655
686
|
});
|
|
656
687
|
} catch (e) {
|
package/hash-utils.mjs
CHANGED
|
@@ -53,6 +53,27 @@ export function computeMinHash(text, numHashes = 64) {
|
|
|
53
53
|
.replace(/[^a-z0-9\s]/g, ' ')
|
|
54
54
|
.split(/\s+/)
|
|
55
55
|
.filter((t) => t.length > 2);
|
|
56
|
+
// R10 P3-10: CJK fallback, and ONLY as a fallback. The tokenizer above deletes every
|
|
57
|
+
// non-ASCII character, so a title or narrative written entirely in Chinese or Japanese
|
|
58
|
+
// produced zero tokens and this returned null — and a null signature makes the row
|
|
59
|
+
// invisible to the MinHash prefilter that findDuplicates and selectFuzzyDedupeIds run,
|
|
60
|
+
// so CJK-only rows could never be deduplicated against anything.
|
|
61
|
+
//
|
|
62
|
+
// Confined to rows that get NOTHING from the ASCII path, which is the whole point.
|
|
63
|
+
// Signatures are STORED, and estimateJaccardFromMinHash compares a stored signature
|
|
64
|
+
// against a freshly computed one; widening the tokenization for text that already
|
|
65
|
+
// signs would make the entire existing corpus incomparable with everything written
|
|
66
|
+
// afterwards — dedup degrading everywhere, silently, until a full rebuild. Every text
|
|
67
|
+
// that signs today still produces the same bytes.
|
|
68
|
+
//
|
|
69
|
+
// Character bigrams rather than nlp.mjs's dictionary segmentation: this module is
|
|
70
|
+
// dependency-free on purpose, and bigrams are the standard CJK shingle for exactly this
|
|
71
|
+
// job — no vocabulary to maintain and no dependence on a dictionary that lags usage.
|
|
72
|
+
if (tokens.length === 0) {
|
|
73
|
+
for (const run of text.match(/[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u30ff]{2,}/g) || []) {
|
|
74
|
+
for (let i = 0; i + 2 <= run.length; i++) tokens.push(run.slice(i, i + 2));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
56
77
|
// Require at least 3 tokens for meaningful signature (avoids high collision on short texts)
|
|
57
78
|
if (tokens.length < 3) return null;
|
|
58
79
|
|
package/hook-episode.mjs
CHANGED
|
@@ -248,7 +248,13 @@ export function mergePendingEntries(episode) {
|
|
|
248
248
|
let files;
|
|
249
249
|
try {
|
|
250
250
|
files = readdirSync(RUNTIME_DIR)
|
|
251
|
-
.
|
|
251
|
+
// R10 P3-4: `.json.tmp` is the WRITER's in-flight temp, not a pending entry.
|
|
252
|
+
// writePendingEntry writes `pending-<ts>-<rand>.json.tmp` then renames it into place;
|
|
253
|
+
// the bare `pending-` prefix matched the temp too, this loop's JSON.parse failed on a
|
|
254
|
+
// partial file, the catch deleted it as corrupt, and the writer's rename then failed
|
|
255
|
+
// ENOENT inside its own swallowed catch. One tool entry lost, silently, every time
|
|
256
|
+
// the two raced.
|
|
257
|
+
.filter((f) => f.startsWith('pending-') && f.endsWith('.json'))
|
|
252
258
|
.sort();
|
|
253
259
|
} catch {
|
|
254
260
|
return;
|