claude-mem-lite 4.0.3 → 5.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.
Files changed (49) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +0 -49
  4. package/README.zh-CN.md +0 -48
  5. package/adopt-content.mjs +0 -1
  6. package/cli/common.mjs +0 -17
  7. package/cli.mjs +19 -3
  8. package/commands/update.md +4 -11
  9. package/format-utils.mjs +0 -21
  10. package/hook-context.mjs +6 -1
  11. package/hook-handoff.mjs +9 -0
  12. package/hook-update.mjs +37 -12
  13. package/hook.mjs +5 -29
  14. package/hooks/hooks.json +0 -10
  15. package/install.mjs +24 -666
  16. package/lib/doctor-drift.mjs +0 -1
  17. package/lib/fast-summary.mjs +11 -0
  18. package/lib/frontmatter.mjs +1 -2
  19. package/lib/hook-prune.mjs +133 -0
  20. package/lib/hook-stdin.mjs +1 -1
  21. package/lib/hook-telemetry.mjs +1 -1
  22. package/lib/metrics.mjs +2 -2
  23. package/lib/shard-gc.mjs +11 -7
  24. package/mem-cli.mjs +2 -423
  25. package/nlp.mjs +1 -1
  26. package/npm-shrinkwrap.json +2 -2
  27. package/package.json +3 -15
  28. package/schema.mjs +0 -1
  29. package/scripts/hook-launcher.mjs +2 -2
  30. package/scripts/prompt-search-utils.mjs +0 -30
  31. package/scripts/user-prompt-search.js +3 -125
  32. package/server.mjs +11 -449
  33. package/source-files.mjs +11 -28
  34. package/synonyms.mjs +2 -1
  35. package/tool-schemas.mjs +0 -80
  36. package/utils.mjs +5 -13
  37. package/commands/tools.md +0 -67
  38. package/install-metadata.mjs +0 -2193
  39. package/lib/registry-core.mjs +0 -264
  40. package/registry/preinstalled.json +0 -2419
  41. package/registry-enricher.mjs +0 -124
  42. package/registry-github.mjs +0 -86
  43. package/registry-importer.mjs +0 -569
  44. package/registry-recommend.mjs +0 -503
  45. package/registry-retriever.mjs +0 -611
  46. package/registry-scanner.mjs +0 -261
  47. package/registry.mjs +0 -665
  48. package/resource-discovery.mjs +0 -199
  49. package/scripts/pre-skill-bridge.js +0 -146
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "claude-mem-lite",
13
- "version": "4.0.3",
13
+ "version": "5.0.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": "4.0.3",
3
+ "version": "5.0.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
@@ -105,7 +105,6 @@ 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
- - **Resource registry** -- Indexes installed skills and agents with FTS5 search, composite scoring, and invocation tracking; searchable via `mem_registry` MCP tool
109
108
  - **Unified resource discovery** -- Shared filesystem traversal layer (`resource-discovery.mjs`) used by both runtime scanner and offline indexer, supporting flat directories, plugin nesting, and loose `.md` files
110
109
  - **Domain synonym expansion** -- Registry search queries expand to domain synonyms (e.g., "fix" → debug, bugfix, troubleshoot, diagnose, repair)
111
110
  - **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
@@ -121,7 +120,6 @@ How claude-mem-lite differs from the major neighbors in the LLM-memory space (ve
121
120
  - **Configurable LLM model** -- Switch between Haiku (fast/cheap) and Sonnet (deeper analysis) via `CLAUDE_MEM_MODEL` env var
122
121
  - **DB auto-recovery** -- Detects and cleans corrupted WAL/SHM files on startup; periodic WAL checkpoints prevent unbounded growth
123
122
  - **Schema auto-migration** -- Idempotent `ALTER TABLE` migrations run on every startup, safely adding new columns and indexes without data loss
124
- - **Exploration bonus** -- New resources in the registry get a fair chance in composite ranking; zombie resources (high recommend, zero adopt) are penalized in scoring
125
123
  - **LLM concurrency control** -- File-based semaphore limits background workers to 2 concurrent LLM calls, preventing resource contention
126
124
  - **stdin overflow protection** -- Hook input truncated at 256KB with regex-based action salvage for oversized tool outputs
127
125
  - **Cross-session handoff** -- Captures session state (request, completed work, next steps, key files) on `/clear` or `/exit`, then injects context when the next session detects continuation intent via explicit keywords or FTS5 term overlap
@@ -224,7 +222,6 @@ rm -rf ~/claude-mem-lite/ # pre-v0.5 unhidden (if not auto-moved)
224
222
  ```
225
223
  ~/.claude-mem-lite/
226
224
  claude-mem-lite.db # SQLite database — memory (WAL mode)
227
- resource-registry.db # SQLite database — skill/agent registry
228
225
  runtime/
229
226
  session-<project> # Active session state
230
227
  ep-<project>.json # Episode buffer
@@ -274,8 +271,6 @@ surface — reach them through the CLI column in the second table.
274
271
  | `mem_export` | `claude-mem-lite export` | JSON / JSONL dump, filters by project, type, date. |
275
272
  | `mem_fts_check` | `claude-mem-lite fts-check <check\|rebuild>` | FTS5 integrity + rebuild. |
276
273
  | `mem_browse` | `claude-mem-lite browse` | Tier-grouped dashboard (working / active / archive). |
277
- | `mem_registry` | `claude-mem-lite registry <action>` | List / search / import / remove skills + agents. |
278
- | `mem_use` | _MCP only_ | Load a skill / agent from the registry by name. |
279
274
 
280
275
  ### Skill Commands (in Claude Code chat)
281
276
 
@@ -472,29 +467,6 @@ Stop
472
467
  -> Spawn LLM summary worker (poll-based wait)
473
468
  ```
474
469
 
475
- ### Resource Registry
476
-
477
- The resource registry (`registry.mjs`, `registry-retriever.mjs`) indexes installed skills and agents into a searchable FTS5 database. Unlike the previous proactive dispatch system, the registry is now on-demand — it's reachable via the `claude-mem-lite registry` CLI (primary path for Claude Code since v2.34.0 hides the `mem_registry` MCP tool from `tools/list`) or by direct `tools/call mem_registry` for MCP clients that know the name.
478
-
479
- ```
480
- Registry pipeline:
481
- -> registry-scanner.mjs discovers skills/agents on filesystem
482
- -> resource-discovery.mjs handles flat dirs, plugin nesting, loose .md files
483
- -> registry-indexer.mjs indexes content into FTS5 with metadata
484
- -> registry-retriever.mjs provides BM25-ranked search with synonym expansion
485
- -> mem_registry MCP tool exposes search/list/stats/import/remove/reindex actions
486
-
487
- Smart invocation (three layers):
488
- L1 auto-load: UserPromptSubmit matches managed skill name in prompt
489
- -> Loads content with path="~/.claude-mem-lite/managed/.../SKILL.md"
490
- -> Guides: Read("path") or mem_use(name="..."), never Skill()
491
- L2 bridge: PreToolUse hook intercepts Skill("name") for managed resources
492
- -> Outputs content, prevents native handler failure
493
- L3 explicit: mem_use(name="...") loads full content with reload path
494
- Search: managed resources → Read(path), native plugins → Skill("full:name")
495
- ```
496
-
497
- Composite scoring for search results: BM25 relevance (40%) + repo stars (15%) + success rate (15%) + adoption rate (10%) + freshness (10%) + exploration bonus (10%). Domain filtering ensures platform-specific resources (iOS, Go, Rust) only surface for matching projects.
498
470
 
499
471
  ### Episode Encoding
500
472
 
@@ -656,12 +628,6 @@ claude-mem-lite/
656
628
  format-utils.mjs # String formatting: truncate, typeIcon, date/time/week formatting
657
629
  hash-utils.mjs # MinHash signatures, Jaccard similarity for dedup
658
630
  bash-utils.mjs # Bash output significance detection: errors, tests, builds, deploys
659
- # Resource registry
660
- registry.mjs # Resource registry DB: schema, CRUD, FTS5, invocation tracking
661
- registry-retriever.mjs # FTS5 retrieval with synonym expansion and composite scoring
662
- registry-indexer.mjs # Resource indexing pipeline
663
- registry-scanner.mjs # Filesystem scanner: reads content + hashes, delegates discovery
664
- resource-discovery.mjs # Shared discovery layer: flat dirs, plugin nesting, loose .md files
665
631
  haiku-client.mjs # Unified Haiku LLM wrapper: direct API or CLI fallback
666
632
  # Install & config
667
633
  install.mjs # CLI installer: setup, uninstall, status, doctor (npx/git clone mode)
@@ -809,18 +775,6 @@ claude-mem-lite.
809
775
  | `CLAUDE_MEM_NO_TEMPLATE_REFRESH` | `1` stops SessionStart from refreshing the adopted `CLAUDE.md` managed block when the shipped template changes. | _(refreshes)_ |
810
776
  | `MEM_QUIET_HOOKS` | See Core above — the broadest injection-volume switch. | _(disabled)_ |
811
777
 
812
- ### Registry import bounds
813
-
814
- `registry import-url` pulls from a third-party repository, so it is bounded. Entries past a
815
- bound are refused, not truncated, and the refusal is printed with the import result. Set any
816
- of these to `0` for the pre-v3.98 unlimited behavior; an unparseable or negative value keeps
817
- the default rather than removing the bound.
818
-
819
- | Variable | Description | Default |
820
- |----------|-------------|---------|
821
- | `CLAUDE_MEM_IMPORT_MAX_ITEMS` | Max skills/agents imported from one repository. | `200` |
822
- | `CLAUDE_MEM_IMPORT_MAX_FILE_BYTES` | Max size of a single `SKILL.md`/`AGENT.md`. Oversized entries are skipped; the rest still import. | `2097152` (2 MB) |
823
- | `CLAUDE_MEM_IMPORT_MAX_TOTAL_BYTES` | Byte budget for one import run. Exhausting it stops the walk and books the remainder as refused. | `52428800` (50 MB) |
824
778
 
825
779
  ### Retrieval tuning
826
780
 
@@ -840,7 +794,6 @@ benchmark and A/B harness are calibrated against — changing them invalidates t
840
794
  | `CLAUDE_MEM_ERROR_RECALL_BM25_MIN` | Relevance floor for the error-recall surface (memories injected after a failed Bash command). **Off by default.** Setting it to `10.5` (the calibrated value) makes the surface stay silent when its best-matching memory is not actually about the failure — the whole set is dropped, never trimmed row-by-row. **It is a real trade, not a free win:** measured on a live database at that threshold, injections fall ~37% and ~39% of firings go silent, concentrated in projects with few memories. Off by default because nothing shows the dropped rows were noise. Explore with `node benchmark/error-recall-suite.mjs --sweep`. | `0` (off) |
841
795
  | `CLAUDE_MEM_ERROR_RECALL_RERANK` | `off` restores the flat keyword ordering of the error-recall surface. **On by default**, and unlike the floor above it removes nothing: memories that share only the failed command's vocabulary are demoted below memories that mention the failure itself, and when a project has none of the latter the result is unchanged. Measured on a live database over 52 real failing commands × 15 projects: the lead memory matched no error term in 42.3% of firings before, 21.5% after, with the injected row count identical. | _(on)_ |
842
796
  | `CLAUDE_MEM_ERROR_RECALL_ON_FAILURE` | `off` stops the plugin from recalling memories when a Bash command **fails at the host level**. On by default. Claude Code delivers failed tool calls to a separate `PostToolUseFailure` hook event, so before this the surface only ever saw commands that exited `0` while printing error-ish text — a genuinely failing build recalled nothing. Denials from your own guardrails (sandbox, policy hooks, declined permission prompts) and commands you interrupted are never recalled for. | _(on)_ |
843
- | `CLAUDE_MEM_REGISTRY_CONFINE` | `off` lets registry enrichment read a resource whose `local_path` lies outside the managed data directory. **On by default.** Enrichment reads the file at `resources.local_path` and sends it to an LLM; the confinement check used to guard one of the four code paths that do this (`mem_registry(action="enrich")`) and not the other three, so `enrich <name>`, `enrich --all` and `import --enrich` read any path the row happened to hold. All four are gated now. Turn it off only if you deliberately registered resources outside `CLAUDE_MEM_DIR` and want them enriched; only `off` disables it — case-insensitively and ignoring surrounding whitespace — so a typo leaves the guard on. | _(on)_ |
844
797
  | `CLAUDE_MEM_UPS_IDENTIFIER_BYPASS` | `0` disables the bypass that lets an exact identifier match skip the score floors. | _(on)_ |
845
798
  | `CLAUDE_MEM_UPS_PROMPT_FALLBACK_LIMIT` | How many past-prompt rows the fallback arm may return. | `1` |
846
799
  | `MEM_COVERAGE_THRESHOLD` | Fraction of query terms a memory must cover to qualify (∈ [0,1]). | `0.4` |
@@ -885,7 +838,6 @@ what is already stored — only whether new work runs.
885
838
  | `CLAUDE_MEM_SKIP_MARKER_GC` | Skip the runtime-marker sweep. | _(runs)_ |
886
839
  | `CLAUDE_MEM_SKIP_UPDATE` | Skip the 24h auto-update check against GitHub Releases. | _(runs)_ |
887
840
  | `CLAUDE_MEM_SKIP_SIG_VERIFY` | Skip Ed25519 signature verification of a downloaded update. **Escape hatch — leaves updates unauthenticated.** | _(verifies)_ |
888
- | `CLAUDE_MEM_SKIP_REPOS` | Skip skill/agent registry seeding during install. | _(seeds)_ |
889
841
  | `CLAUDE_MEM_NO_LESSON_RETRY` | `1` disables the one-shot retry that re-asks for a missing `lesson_learned`. | _(retries)_ |
890
842
  | `CLAUDE_MEM_FLUSH_TIMEOUT` | Seconds the Stop hook waits for pending episode flushes. | `15` |
891
843
  | `CLAUDE_MEM_BACKUP_BUDGET_MB` | Disk budget for backup snapshots; the next maintain/save evicts oldest snapshots past the 7-day undo grace. | `256` |
@@ -897,7 +849,6 @@ and names can change between releases.
897
849
 
898
850
  | Variable | Description | Default |
899
851
  |----------|-------------|---------|
900
- | `CLAUDE_MEM_RECOMMEND_MODE` | Skill-recommendation engine: `shadow` (log would-be recommendations, inject nothing) or `off`. **`live` is parsed but not implemented** — live injection is Phase 2. Setting it runs shadow and prints one warning to stderr per process; `claude-mem-lite doctor` also reports it as an inert flag. | `shadow` |
901
852
  | `CLAUDE_MEM_TASK_IMPERATIVE` | `on`/`1` injects the single most relevant lesson at prompt position under an imperative template. | _(off)_ |
902
853
  | `CLAUDE_MEM_SUBAGENT_INJECT` | Dispatch-time memory injection for subagents. | _(off)_ |
903
854
  | `CLAUDE_MEM_SALIENCE` | Selects a comprehension-bridge arm (`bridge`, `bind`); unset = current default behavior. | _(unset)_ |
package/README.zh-CN.md CHANGED
@@ -81,8 +81,6 @@
81
81
  - **原子写入** -- 所有文件写入(episode、CLAUDE.md)使用 write-to-tmp + rename 防止崩溃时损坏
82
82
  - **健壮锁机制** -- PID 感知的锁文件,自动清理过期(>30s)或孤儿(PID 已死)锁
83
83
  - **过期会话清理** -- 活跃超过 24 小时的会话在下次启动时自动标记为 abandoned
84
- - **智能调用** -- 三层调用系统:L1 自动加载(UserPromptSubmit 匹配 skill 名注入内容 + `Read()` 路径),L2 Bridge(PreToolUse 拦截 `Skill()` 误调),L3 显式调用(`mem_use` MCP 工具)。managed 资源用 `Read("~/.claude-mem-lite/managed/.../SKILL.md")`,原生插件用 `Skill("full:name")`
85
- - **资源注册表** -- 对已安装的 skill 和 agent 建立 FTS5 索引,支持复合评分和调用追踪。搜索结果区分 managed(Read 路径)vs native(Skill 全名)调用方式
86
84
  - **统一资源发现** -- 共享文件系统遍历层(`resource-discovery.mjs`),运行时扫描器和离线索引器共用,支持扁平目录、插件嵌套和松散 `.md` 文件
87
85
  - **领域同义词扩展** -- 注册表搜索查询自动扩展领域同义词(如 "修复" → fix, debug, bugfix, repair, error)
88
86
  - **持久化冷却机制** -- 5 分钟跨会话冷却 + 同会话去重,避免重复推荐 skill 自动加载
@@ -188,7 +186,6 @@ rm -rf ~/claude-mem-lite/ # v0.5 前的非隐藏目录(如未自动迁移)
188
186
  ```
189
187
  ~/.claude-mem-lite/
190
188
  claude-mem-lite.db # SQLite 数据库 — 记忆(WAL 模式)
191
- resource-registry.db # SQLite 数据库 — skill/agent 注册表
192
189
  runtime/
193
190
  session-<project> # 活跃会话状态
194
191
  ep-<project>.json # Episode 缓冲区
@@ -233,8 +230,6 @@ v2.34.0 起服务端注册 17 个工具,但 `tools/list` 只暴露 6 个 **核
233
230
  | `mem_export` | `claude-mem-lite export` | JSON / JSONL 导出,支持项目/类型/日期过滤。 |
234
231
  | `mem_fts_check` | `claude-mem-lite fts-check <check\|rebuild>` | FTS5 完整性检查与重建。 |
235
232
  | `mem_browse` | `claude-mem-lite browse` | 分层仪表盘(working / active / archive)。 |
236
- | `mem_registry` | `claude-mem-lite registry <action>` | 列 / 搜索 / 导入 / 移除 skill / agent。 |
237
- | `mem_use` | _MCP only_ | 从 registry 按名载入 skill / agent。 |
238
233
 
239
234
  ### 技能命令(在 Claude Code 聊天中使用)
240
235
 
@@ -370,11 +365,6 @@ PostToolUse(每次工具执行)
370
365
  -> 为有意义的 episode 启动 LLM episode worker
371
366
  -> 错误触发回忆:搜索记忆中相关的历史修复
372
367
 
373
- PreToolUse(工具执行前)
374
- -> L2 Skill Bridge:拦截对 managed 资源的 Skill() 调用
375
- -> 匹配 managed 路径 → 输出内容 + mem_use() 提示
376
- -> 未匹配 → 静默放行到原生 handler
377
-
378
368
  UserPromptSubmit(两个并行路径)
379
369
  -> [user-prompt-search.js] 通过 FTS5 + 活跃文件上下文自动搜索记忆
380
370
  -> [user-prompt-search.js] 注入相关历史观察(按时效和重要性加权)
@@ -393,36 +383,6 @@ Stop
393
383
  -> 启动 LLM 摘要 worker(轮询等待)
394
384
  ```
395
385
 
396
- ### 智能调用系统
397
-
398
- 三层调用系统确保 managed 资源(`~/.claude-mem-lite/managed/` 中的 skill 和 agent)能被正确调用:
399
-
400
- ```
401
- L1 自动加载(UserPromptSubmit,<50ms)
402
- -> 匹配 prompt 中的 managed skill/agent 名称
403
- -> 加载 SKILL.md / {name}.md 内容
404
- -> 输出:Read("~/.claude-mem-lite/managed/.../path.md") 调用指引
405
- -> 截断时提供 mem_use(name="...") 备选
406
-
407
- L2 Bridge(PreToolUse Skill hook,<30ms)
408
- -> 拦截 Skill("name") 调用,查询 managed 注册表
409
- -> 匹配到 → 输出内容 + mem_use() 提示(防止原生 handler 报错)
410
- -> 未匹配 → 放行到原生 Skill handler
411
-
412
- L3 显式调用(mem_use MCP 工具)
413
- -> 按名称精确匹配 + FTS5 模糊回退
414
- -> 返回完整内容 + 便携路径供 Read() 重载
415
- ```
416
-
417
- **调用方式区分:**
418
-
419
- | 资源类型 | 位置 | 调用方式 |
420
- |---------|------|---------|
421
- | Managed skill | `~/.claude-mem-lite/managed/skills/` | `Read("~/.../SKILL.md")` 或 `mem_use(name="...")` |
422
- | Managed agent | `~/.claude-mem-lite/managed/agents/` | `Read("~/.../{name}.md")` 或 `mem_use(name="...", type="agent")` |
423
- | 原生插件 skill | `~/.claude/plugins/cache/` | `Skill("plugin:skill-name")` |
424
- | 用户自建 skill | `~/.claude/skills/` | `Skill("name")` |
425
-
426
386
  ### Episode 编码
427
387
 
428
388
  Episode 是一批相关操作(对同一组文件的编辑),由后台 LLM worker 处理:
@@ -548,13 +508,6 @@ claude-mem-lite/
548
508
  format-utils.mjs # 字符串格式化:截断、类型图标、日期/时间格式化
549
509
  hash-utils.mjs # MinHash 签名、Jaccard 相似度(去重用)
550
510
  bash-utils.mjs # Bash 输出显著性检测:错误、测试、构建、部署
551
- # 智能调度
552
- dispatch.mjs # 三级调度编排:快速过滤、上下文信号、FTS5、Haiku
553
- dispatch-inject.mjs # 注入模板渲染:skill/agent 推荐
554
- registry.mjs # 资源注册表 DB:schema、CRUD、FTS5、调用追踪
555
- registry-retriever.mjs # FTS5 检索:同义词扩展与复合评分
556
- registry-scanner.mjs # 文件系统扫描器:读取内容 + 哈希,委托发现层
557
- resource-discovery.mjs # 共享发现层:扁平目录、插件嵌套、松散 .md 文件
558
511
  haiku-client.mjs # 统一 Haiku LLM 封装:直连 API 或 CLI 回退
559
512
  # 安装与配置
560
513
  install.mjs # CLI 安装器:设置、卸载、状态、诊断(npx/git clone 模式)
@@ -620,7 +573,6 @@ npm run benchmark:gate # CI 门控:指标回退超过 5% 容差时失败
620
573
  | `MEM_QUIET_HOOKS` | 低噪声 hook。设为 `1` 时,SessionStart 注入去掉 `File Lessons` / `Key Context` 两节,`[mem] Related memories` 去掉 lesson 后缀,MCP server instructions 去掉 `WHEN TO USE` / `Decision rules` 两段。ID 与 `Recent` 表仍保留,`mem_get(ids=[…])` 可继续展开细节。适用于启用了 invited-memory adopt 流程或偏好最小化自动注入的用户。**v2.82.0 起此 env 不再阻挡 auto-adopt——如需关闭 auto-adopt 用 `MEM_NO_AUTO_ADOPT=1`。** | _(禁用)_ |
621
574
  | `MEM_NO_AUTO_ADOPT` | auto-adopt 全局关闭开关(v2.82.0+)。设为 `1` 阻止每次 SessionStart 在**所有**项目自动写入 `CLAUDE.md` 托管块。项目级关闭走 `claude-mem-lite adopt --disable`(写 `<memdir>/.mem-no-auto-adopt` 哨兵,存活于 marker 删除)。 | _(禁用)_ |
622
575
  | `MEM_NO_ADOPT_HINT` | 静音当前项目未 adopt 时 SessionStart 追加的那一行 "Invited-memory 未启用…" 提示。v2.82.1 起任何安装路径每次 SessionStart 都自动 adopt,所以该提示一般只在你显式 opt out(`MEM_NO_AUTO_ADOPT=1` 或 `claude-mem-lite adopt --disable`)的项目才会出现。 | _(禁用)_ |
623
- | `CLAUDE_MEM_REGISTRY_CONFINE` | 设为 `off` 允许 registry enrich 读取 `local_path` 位于托管数据目录之外的资源。**默认开启。** enrich 会读取 `resources.local_path` 指向的文件并发给 LLM;此前这道路径限制只接在四条读取路径中的一条(`mem_registry(action="enrich")`)上,`enrich <name>`、`enrich --all` 和 `import --enrich` 三条都是裸读。现在四条同门。仅当你确实把资源注册在 `CLAUDE_MEM_DIR` 之外并希望对其 enrich 时才关闭;只有精确值 `off` 会关闭它,拼错则守卫保持开启。 | _(开启)_ |
624
576
 
625
577
  ## 许可证
626
578
 
package/adopt-content.mjs CHANGED
@@ -151,7 +151,6 @@ PreToolUse hook 在你 Read / Edit / Write 文件前已自动 \`mem_recall\` 该
151
151
  | 导出 JSON/JSONL | \`${CLI} export [--format jsonl]\` |
152
152
  | 统计总量 / 健康 | \`${CLI} stats [--days 30]\` |
153
153
  | 删除 / 更新某条 | \`${CLI} delete <id>[,<id>]\` · \`${CLI} update <id> [--title ...]\` |
154
- | skill-agent registry | \`${CLI} registry <list\\|search\\|import>\` |
155
154
 
156
155
  ## CLI 速查(常用检索)
157
156
 
package/cli/common.mjs CHANGED
@@ -209,27 +209,21 @@ export const KNOWN_CLI_FLAGS = new Set([
209
209
  'age-days',
210
210
  'all',
211
211
  'anchor',
212
- 'batch',
213
212
  'before',
214
213
  'benchmark',
215
214
  'body',
216
215
  'branch',
217
- 'capability-summary',
218
- 'category',
219
216
  'closes-deferred',
220
217
  'concepts',
221
218
  'confirm',
222
219
  'days',
223
220
  'deep',
224
221
  'detail',
225
- 'domain-tags',
226
222
  'dry-run',
227
- 'enrich',
228
223
  'execute',
229
224
  'fields',
230
225
  'file',
231
226
  'files',
232
- 'floors',
233
227
  'force',
234
228
  'format',
235
229
  'from',
@@ -240,16 +234,11 @@ export const KNOWN_CLI_FLAGS = new Set([
240
234
  'importance',
241
235
  'include-compressed',
242
236
  'include-noise',
243
- 'intent-tags',
244
- 'invocation-name',
245
237
  'json',
246
238
  'key',
247
- 'keywords',
248
239
  'lesson',
249
240
  'lesson-learned',
250
241
  'limit',
251
- 'local-path',
252
- 'margins',
253
242
  'max',
254
243
  'memdir',
255
244
  'merge-ids',
@@ -265,9 +254,7 @@ export const KNOWN_CLI_FLAGS = new Set([
265
254
  'quality',
266
255
  'query',
267
256
  'reason',
268
- 'repo-url',
269
257
  'rerank',
270
- 'resource-type',
271
258
  'retain-days',
272
259
  'retry',
273
260
  'run',
@@ -279,16 +266,12 @@ export const KNOWN_CLI_FLAGS = new Set([
279
266
  'sort',
280
267
  'source',
281
268
  'status',
282
- 'sweep',
283
269
  'task',
284
- 'tech-stack',
285
270
  'text',
286
271
  'tier',
287
272
  'title',
288
273
  'to',
289
- 'trigger-patterns',
290
274
  'type',
291
- 'use-cases',
292
275
  'verbose',
293
276
  // Catalogued 2026-08-13 when suggestUnknownFlags started reporting EVERY unknown
294
277
  // flag: these are real, code-read flags that the old edit-distance gate happened to
package/cli.mjs CHANGED
@@ -18,10 +18,7 @@ const CLI_COMMANDS = new Set([
18
18
  'maintain',
19
19
  'optimize',
20
20
  'fts-check',
21
- 'registry',
22
- 'import',
23
21
  'import-jsonl',
24
- 'enrich',
25
22
  'activity',
26
23
  'adopt',
27
24
  'unadopt',
@@ -29,6 +26,10 @@ const CLI_COMMANDS = new Set([
29
26
  'defer',
30
27
  'help',
31
28
  ]);
29
+ // Removed with the skill/agent resource registry (docs/audits/20260906-145304.md).
30
+ // Kept as a named set so a stale script or muscle-memory invocation gets the reason rather
31
+ // than a bare "Unknown command" plus a misleading edit-distance suggestion.
32
+ const REMOVED_COMMANDS = new Set(['registry', 'import', 'enrich']);
32
33
  const INSTALL_COMMANDS = new Set([
33
34
  'install',
34
35
  'uninstall',
@@ -95,6 +96,21 @@ if (cmd === '--version' || cmd === '-v' || cmd === '-V' || cmd === 'version') {
95
96
  } else if (INSTALL_COMMANDS.has(cmd)) {
96
97
  const { main } = await import('./install.mjs');
97
98
  await main(process.argv.slice(2));
99
+ } else if (REMOVED_COMMANDS.has(cmd)) {
100
+ // Released-artifact discoverability signal for the skill-registry removal. Deliberately
101
+ // names NO version: this ships before the version is decided, and a hardcoded one is a
102
+ // guess in a third place (package.json and the CHANGELOG heading being the other two).
103
+ // The revert instruction is version-specific and correct, which is what a user needs.
104
+ // Deliberately NOT routed through the edit-distance suggester below: its nearest
105
+ // match for `import` is `import-jsonl`, a different feature that accepts a path
106
+ // argument, so a stale `import <github-url>` would be pointed at something that
107
+ // could plausibly run. Naming the removal is the only honest answer.
108
+ process.stderr.write(
109
+ `[mem] "${cmd}" was removed along with the skill/agent resource registry.\n` +
110
+ "[mem] Claude Code's own plugins/marketplace replace it. See CHANGELOG.md for the\n" +
111
+ '[mem] migration note; to revert, pin claude-mem-lite@4.0.4.\n',
112
+ );
113
+ process.exit(1);
98
114
  } else {
99
115
  process.stderr.write(`[mem] Unknown command: "${cmd}"\n`);
100
116
  // Suggest closest command by edit distance
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: update
3
- description: "Use when: search results seem noisy, after bulk imports, or for periodic memory/registry maintenance"
3
+ description: "Use when: search results seem noisy or for periodic memory maintenance"
4
4
  ---
5
5
 
6
- # Memory & Registry Maintenance
6
+ # Memory Maintenance
7
7
 
8
- Run intelligent maintenance on both the memory database and tool resource registry.
8
+ Run intelligent maintenance on the memory database.
9
9
 
10
10
  ## Usage
11
11
 
@@ -24,15 +24,8 @@ When the user invokes `/mem:update`, perform the following maintenance cycle:
24
24
  5. Run `mem_compress(preview=false)` for old low-value observations
25
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.
26
26
 
27
- ### Phase 2: Registry Maintenance
28
-
29
- 1. Call `mem_registry(action="stats")` to get registry overview
30
- 2. Call `mem_registry(action="reindex")` to rebuild FTS5 search index
31
- 3. Report updated stats
32
-
33
- ### Phase 3: Summary
27
+ ### Phase 2: Summary
34
28
 
35
29
  Summarize all maintenance actions taken in zh-CN:
36
30
  - Memory: observations cleaned, decayed, boosted, deduplicated, compressed
37
- - Registry: total resources, adoption rates, reindex status
38
31
  - Overall health assessment
package/format-utils.mjs CHANGED
@@ -125,27 +125,6 @@ export function neutralizeSkillDelimiters(s) {
125
125
  return defangToFixpoint(s, SKILL_BLOCK_RE);
126
126
  }
127
127
 
128
- // <skill-bridge> is the wrapper scripts/pre-skill-bridge.js puts around a managed
129
- // skill body it injects as PreToolUse additionalContext. The body comes from a
130
- // third-party repo (tools/adopt import) — an untrusted boundary — so a literal
131
- // `</skill-bridge>` inside it would close the wrapper early and spill the rest of
132
- // the payload (e.g. a forged <system-reminder>) as undelimited context (audit
133
- // 2026-08-14 M-4). Not in CONTEXT_DELIMITER_RE for the same reason <skill-loaded>
134
- // isn't: the bridge's OWN wrapper must stay live, so the defang is applied per
135
- // call site to the untrusted body only.
136
- const SKILL_BRIDGE_RE = /<\/?skill-bridge(?:\s[^>]*)?>/gi;
137
-
138
- /**
139
- * Defang a literal `<skill-bridge>` opener/closer in untrusted text that is about
140
- * to be wrapped in a real skill-bridge block. Same fixpoint treatment as the
141
- * classes above. Never apply to the wrapper itself.
142
- * @param {string} s Input string (any type; coerced)
143
- * @returns {string} Text with skill-bridge delimiters defanged
144
- */
145
- export function neutralizeSkillBridgeDelimiters(s) {
146
- return defangToFixpoint(s, SKILL_BRIDGE_RE);
147
- }
148
-
149
128
  /**
150
129
  * Render the PostToolUse error-recall hint block (hook.mjs::triggerErrorRecall).
151
130
  * The single most-relevant hit (rows[0]) that carries a lesson_learned gets its
package/hook-context.mjs CHANGED
@@ -60,11 +60,16 @@ function mdCell(s) {
60
60
 
61
61
  export function computeAdaptiveWindows(db, project) {
62
62
  const sevenDaysAgo = Date.now() - 7 * DAY_MS;
63
+ // liveObsFilterSql, not a hand-written half of it (A20260906-R8-§11.3). This COUNT is a
64
+ // POOL-SIZING input: the windows returned below are handed to the recall queries at :201 /
65
+ // :468 / :502, all three of which filter live rows. Counting a strictly larger population
66
+ // than the window is applied to inverts the documented intent — 80 superseded rows read as
67
+ // >10 obs/day and earned the TIGHTEST window (12h) for finding the few live rows left.
63
68
  const row = db
64
69
  .prepare(
65
70
  `
66
71
  SELECT COUNT(*) as c FROM observations
67
- WHERE project = ? AND created_at_epoch > ? AND COALESCE(compressed_into, 0) = 0
72
+ WHERE project = ? AND created_at_epoch > ? AND ${liveObsFilterSql('')}
68
73
  `,
69
74
  )
70
75
  .get(project, sevenDaysAgo);
package/hook-handoff.mjs CHANGED
@@ -136,6 +136,15 @@ export function buildAndSaveHandoff(db, sessionId, project, type, episodeSnapsho
136
136
  const obsWindowParams = ccWindowStart !== null ? [ccWindowStart] : [];
137
137
 
138
138
  // 2. Completed — from observations (include narrative for richer handoff)
139
+ //
140
+ // `compressed_into` ONLY, deliberately — not a half-written liveObsFilterSql. Audit
141
+ // 2026-08-14 F4 ruled on exactly this line: `completed` is the session's own history, and a
142
+ // decision a later save overturned still happened, so erasing it here would misreport the
143
+ // session. Only key_decisions (:242) is re-presented to a LATER session as standing policy,
144
+ // and that one does filter superseded_at. The scope guard is the third case of "F4 — handoff
145
+ // key_decisions excludes a retracted decision" in tests/audit-silent-20260814.test.mjs.
146
+ // Audit R8 §11.3 proposed adding the filter here from a repo-wide regex sweep of the
147
+ // predicate shape; it was rejected on this reasoning, and the guard catches it.
139
148
  const completed = db
140
149
  .prepare(
141
150
  `
package/hook-update.mjs CHANGED
@@ -7,7 +7,6 @@ import {
7
7
  readFileSync,
8
8
  writeFileSync,
9
9
  copyFileSync,
10
- cpSync,
11
10
  readdirSync,
12
11
  existsSync,
13
12
  lstatSync,
@@ -404,11 +403,11 @@ export function getCurrentVersion() {
404
403
  }
405
404
 
406
405
  // SWITCHABLE_PATHS = everything in SOURCE_FILES plus the recursive dirs that
407
- // install.mjs copies as whole subtrees (scripts, registry, node_modules). It's
406
+ // install.mjs copies as whole subtrees (scripts, node_modules). It's
408
407
  // built per-call from the *tarball's* manifest, not the locally-imported one —
409
408
  // see loadReleaseManifest comment for why.
410
409
  function buildSwitchablePaths(sourceFiles) {
411
- return [...sourceFiles, 'scripts', 'registry', 'node_modules'];
410
+ return [...sourceFiles, 'scripts', 'node_modules'];
412
411
  }
413
412
 
414
413
  // Load the SOURCE_FILES / HOOK_SCRIPT_FILES manifest from the *extracted
@@ -989,6 +988,41 @@ export async function installExtractedRelease(sourceDir, targetDir = INSTALL_DIR
989
988
  rmSync(stagingDir, { recursive: true, force: true });
990
989
  rmSync(backupDir, { recursive: true, force: true });
991
990
 
991
+ // Post-update migration: reconcile settings.json against the release we just
992
+ // swapped in. `configureHooks()` already strips stale mem entries — but its only
993
+ // caller is `install()`, and this path never runs it, while `buildSwitchablePaths`
994
+ // replaces `scripts/` wholesale. So an upgrade that REMOVES a hook script deletes
995
+ // the file and leaves settings.json pointing at it; the launcher then reports a
996
+ // broken install on every fire, for a file that is not coming back (R9 review P1-1,
997
+ // first hit by the `PreToolUse:Skill` removal). Plugin-channel installs are
998
+ // unaffected — hooks/hooks.json is replaced wholesale — so this is npm-channel only.
999
+ //
1000
+ // The reconciler lives in lib/hook-prune.mjs, not install.mjs: install.mjs already
1001
+ // imports THIS file, so importing it back would close a cycle the repo's import-graph
1002
+ // guard rejects. Failure is non-fatal — a stale entry is noisy, not broken, and must
1003
+ // never roll back an otherwise-good update.
1004
+ try {
1005
+ const settingsPath = join(homedir(), '.claude', 'settings.json');
1006
+ if (existsSync(settingsPath)) {
1007
+ const { pruneDanglingMemHooks } = await import('./lib/hook-prune.mjs');
1008
+ const before = JSON.parse(readFileSync(settingsPath, 'utf8'));
1009
+ const { settings, removed } = pruneDanglingMemHooks(before, targetDir);
1010
+ if (removed.length > 0) {
1011
+ // Through the shared writer: settings.json is user-owned config and may be a
1012
+ // symlink into a dotfiles repo, which a bare temp+rename would sever (P0-5).
1013
+ const { atomicWriteFileSync } = await import('./lib/atomic-write.mjs');
1014
+ atomicWriteFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { backup: true });
1015
+ debugLog(
1016
+ 'INFO',
1017
+ 'update',
1018
+ `pruned ${removed.length} dangling hook entr(ies): ${removed.join(', ')}`,
1019
+ );
1020
+ }
1021
+ }
1022
+ } catch (e) {
1023
+ debugCatch(e, 'pruneDanglingMemHooks');
1024
+ }
1025
+
992
1026
  // Post-update migration: clean stale global MCPs if plugin handles it.
993
1027
  // Both "mem" (legacy, pre-v2.78) and "mem-lite" (current) are purged so a
994
1028
  // user who manually ran `claude mcp add` in either era doesn't end up with
@@ -1194,15 +1228,6 @@ function copyReleaseIntoStaging(
1194
1228
  }
1195
1229
  }
1196
1230
 
1197
- // registry/ stays recursive — preinstalled.json is the only current entry
1198
- // but the directory is consumed wholesale by the registry indexer and may
1199
- // grow subtrees. Pre-v2.55 readdirSync+copyFileSync would EISDIR-throw on
1200
- // any subdir and silently roll back the entire update.
1201
- const sourceRegistry = join(sourceDir, 'registry');
1202
- if (existsSync(sourceRegistry)) {
1203
- cpSync(sourceRegistry, join(stagingDir, 'registry'), { recursive: true });
1204
- }
1205
-
1206
1231
  const stagedScripts = join(stagingDir, 'scripts');
1207
1232
  if (existsSync(stagedScripts)) {
1208
1233
  for (const sf of readdirSync(stagedScripts).filter((n) => n.endsWith('.sh'))) {
package/hook.mjs CHANGED
@@ -165,10 +165,10 @@ async function loadCacheGuard() {
165
165
  // Audit 2026-09-02 P1-8. `hook.mjs` is ONE entry point for seven events, so every static
166
166
  // import is paid by every event — PostToolUse, the highest-frequency one, was loading 85
167
167
  // modules (1.37 MB) to use a handful. The six modules below are loaded inside the handler
168
- // that needs them instead: registry-recommend, patha-exclude-meter, hook-update,
169
- // hook-optimize, adopt-cli, upgrade-banner. Measured marginal cost of the four largest,
170
- // same process: hook-update 9.4 ms, registry-recommend 5.1, hook-optimize 5.9, the rest
171
- // 0.5-2.4 each.
168
+ // that needs them instead: patha-exclude-meter, hook-update, hook-optimize, adopt-cli,
169
+ // upgrade-banner. Measured marginal cost of the largest, same process: hook-update
170
+ // 9.4 ms, hook-optimize 5.9, the rest 0.5-2.4 each. (registry-recommend, 5.1 ms, was a
171
+ // sixth entry until the skill-registry subsystem was removed — see docs/audits/20260906-145304.md.)
172
172
  //
173
173
  // A failing dynamic import lands in the dispatcher's tail catch -> recordHookError, the
174
174
  // same place a failing static import would have landed the whole process; each site keeps
@@ -642,23 +642,6 @@ async function handlePostToolUse() {
642
642
  if (SKIP_TOOLS.has(tool_name)) return;
643
643
  if (SKIP_PREFIXES.some((p) => tool_name.startsWith(p))) return;
644
644
 
645
- // Shadow skill-adoption telemetry. mem_use is pre-filtered above, so the Skill tool is
646
- // the only visible adoption signal (v1). Placed before the resp-length gate because a
647
- // skill load's response shape varies. Never throws.
648
- if (tool_name === 'Skill') {
649
- const ti = typeof tool_input === 'string' ? tryParseJson(tool_input) : tool_input || {};
650
- // hookData.session_id (CC UUID) pairs this adoption to the would-be reco from the
651
- // UserPromptSubmit hook earlier in the same session (matched precision, B1).
652
- // Lazy: only a `Skill` tool call needs this module, which is a small fraction of
653
- // PostToolUse fires.
654
- try {
655
- const { recordSkillAdoption } = await import('./registry-recommend.mjs');
656
- recordSkillAdoption('Skill', ti, inferProject(), hookData.session_id);
657
- } catch {
658
- /* telemetry only — never blocks capture */
659
- }
660
- }
661
-
662
645
  const resp = normalizeToolResponse(tool_response);
663
646
  if (!resp || resp.length < 10) return;
664
647
 
@@ -2254,14 +2237,7 @@ async function handleSessionStart() {
2254
2237
  } catch {
2255
2238
  /* best-effort */
2256
2239
  }
2257
- // Bound the shadow-recommendation log (daily JSONL shards, no GC at write time).
2258
- try {
2259
- const { gcOldShadowShards } = await import('./registry-recommend.mjs');
2260
- gcOldShadowShards();
2261
- } catch {
2262
- /* best-effort, never blocks SessionStart */
2263
- }
2264
- // Same for the opt-in metrics sink, which lives under DB_DIR. Runs even when
2240
+ // Bound the opt-in metrics sink, which lives under DB_DIR. Runs even when
2265
2241
  // metrics are disabled, so shards left by a since-toggled-off run still get pruned.
2266
2242
  try {
2267
2243
  gcOldMetricShards(DB_DIR);
package/hooks/hooks.json CHANGED
@@ -41,16 +41,6 @@
41
41
  }
42
42
  ]
43
43
  },
44
- {
45
- "matcher": "Skill",
46
- "hooks": [
47
- {
48
- "type": "command",
49
- "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-launcher.mjs\" scripts/pre-skill-bridge.js",
50
- "timeout": 3
51
- }
52
- ]
53
- },
54
44
  {
55
45
  "matcher": "Agent|Task",
56
46
  "hooks": [