claude-mem-lite 6.29.2 → 6.29.3
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 +9 -11
- package/README.zh-CN.md +18 -14
- package/adopt-content.mjs +1 -1
- package/claudemd.mjs +2 -3
- package/cli/common.mjs +7 -2
- package/commands/adopt.md +5 -5
- package/commands/bug.md +3 -3
- package/commands/lesson.md +3 -3
- package/commands/mem.md +2 -2
- package/commands/update.md +2 -2
- package/commands/verify.md +2 -4
- package/hook-context.mjs +2 -2
- package/lib/activity.mjs +1 -1
- package/lib/get-core.mjs +2 -2
- package/lib/maintain-core.mjs +11 -1
- package/lib/quiet-scope.mjs +1 -1
- package/lib/save-nudge.mjs +6 -3
- package/lib/stats-quality.mjs +2 -1
- package/mem-cli.mjs +6 -5
- package/memdir.mjs +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/search-scoring.mjs +6 -6
- package/server.mjs +5 -4
- package/tool-schemas.mjs +2 -2
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"plugins": [
|
|
10
10
|
{
|
|
11
11
|
"name": "claude-mem-lite",
|
|
12
|
-
"version": "6.29.
|
|
12
|
+
"version": "6.29.3",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"homepage": "https://github.com/sdsrss/claude-mem-lite",
|
|
15
15
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. FTS5 BM25 keyword 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)."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "6.29.
|
|
3
|
+
"version": "6.29.3",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. FTS5 BM25 keyword 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
|
@@ -124,7 +124,7 @@ How claude-mem-lite differs from the major neighbors in the LLM-memory space (ve
|
|
|
124
124
|
<br>Original behaviour and the measurements behind it via explicit keywords or FTS5 term overlap. **The `/clear` and `/compact` arm fires since v5.4.0** (R10-P1-1); before that it had never once written a row — `session_handoffs` on the maintainer's install held 4 `exit` rows and **0** `clear` rows. Two host facts settled it, both measured rather than assumed. (1) `Stop` runs at the end of every assistant *turn*, not once per session, and it deleted the session file that SessionStart reads to learn which session just ended — so the branch was unreachable, and mem sessions were minted per turn (58 prompts over 16 host sessions produced 56 mem sessions and 56 summary rows, 2026-09-07). (2) Claude Code **rotates its session id across `/clear`**: of 21 real transcripts, 12 carry a `/clear` command record, and in 12/12 that record's timestamp precedes its own file's first record by ~0.1s — the command is issued in the old session and replayed into a new file under a new id. So `Stop` no longer deletes the file, SessionStart asks the host's `source` (`startup`/`clear`/`compact`/`resume`) instead of guessing from the file, and the handoff's prompt lookup falls back to the unscoped set when the new session's id matches none. Revert path: `CLAUDE_MEM_LEGACY_STOP_UNLINK=1`
|
|
125
125
|
- **Git-SHA continuation anchor** (v2.31.0) -- Handoff rows include `git_sha_at_handoff`; any handoff matching the current `HEAD` counts as continuation regardless of TTL. Code state is a stronger continuation signal than wall-clock time
|
|
126
126
|
- **Startup dashboard** (v2.31.0) -- SessionStart hook aggregates `git status` + `~/.claude/tasks/*.json` + `~/.claude/plans/*.md` + most-recent exit handoff + recent event count into a single structured block injected via `hookSpecificOutput.additionalContext`
|
|
127
|
-
- **Activity namespace** (v2.31.0) -- Dedicated `events` table + FTS5 for non-memdir types (`bugfix`, `lesson`, `bug`, `discovery`, `refactor`, `feature`, `observation`, `decision`) that don't compete with `WHAT_NOT_TO_SAVE` semantics on the observations table. CLI: `claude-mem-lite activity save|search|recent|show`. `hook-llm` routes non-memdir summary types through `persistHaikuSummary` so upgrades from observations→events are atomic. (v3.39: the `/lesson` and `/bug` slash commands were redirected from this events table to searchable **observations** — `mem_search` never read the events table, so explicit saves were unfindable; the events table remains the auto-capture activity log.)
|
|
127
|
+
- **Activity namespace** (v2.31.0) -- Dedicated `events` table + FTS5 for non-memdir types (`bugfix`, `lesson`, `bug`, `discovery`, `refactor`, `feature`, `observation`, `decision`) that don't compete with `WHAT_NOT_TO_SAVE` semantics on the observations table. CLI: `claude-mem-lite activity save|search|recent|show`. `hook-llm` routes non-memdir summary types through `persistHaikuSummary` so upgrades from observations→events are atomic. (v3.39: the `/lesson` and `/claude-mem-lite:bug` slash commands were redirected from this events table to searchable **observations** — `mem_search` never read the events table, so explicit saves were unfindable; the events table remains the auto-capture activity log.)
|
|
128
128
|
- **In-place observation updates** -- `mem_update` tool modifies existing observations atomically (field update + FTS text rebuild in one transaction), preserving original IDs and references
|
|
129
129
|
- **Bulk export** -- `mem_export` tool exports observations as JSON or JSONL, with project/type/date filtering and 1000-row pagination cap with batch guidance
|
|
130
130
|
- **FTS integrity management** -- `mem_fts_check` tool verifies FTS5 index health or rebuilds indexes on demand, useful after database recovery or when search results seem wrong
|
|
@@ -165,7 +165,7 @@ is still outside it gets a message naming both sides of the mismatch instead of
|
|
|
165
165
|
|
|
166
166
|
Plugin mode manages its own hooks/runtime. On session start it only **checks and reports** new claude-mem-lite versions; it does **not** self-overwrite plugin files in place. Update plugin-mode installs through Claude's plugin workflow.
|
|
167
167
|
|
|
168
|
-
> **The plugin install is complete on its own** — hooks, MCP tools, and the bundled slash commands (`/mem`, `/lesson`, `/bug`, `/adopt`) all run from the plugin with no second step. The slash commands invoke the bundled CLI by an absolute path resolved from the plugin directory (`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`), so they work without anything on your `PATH`. A global `claude-mem-lite` **shell** command (for running queries yourself in a terminal) is **optional** — `npm i -g claude-mem-lite` — and is a *separate* npm install: the plugin's auto-update does **not** refresh it, so re-run `npm i -g claude-mem-lite@latest` if you want that shell command kept in sync. You do **not** need it for the plugin to be fully functional.
|
|
168
|
+
> **The plugin install is complete on its own** — hooks, MCP tools, and the bundled slash commands (`/mem`, `/lesson`, `/claude-mem-lite:bug`, `/adopt`) all run from the plugin with no second step. The slash commands invoke the bundled CLI by an absolute path resolved from the plugin directory (`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`), so they work without anything on your `PATH`. A global `claude-mem-lite` **shell** command (for running queries yourself in a terminal) is **optional** — `npm i -g claude-mem-lite` — and is a *separate* npm install: the plugin's auto-update does **not** refresh it, so re-run `npm i -g claude-mem-lite@latest` if you want that shell command kept in sync. You do **not** need it for the plugin to be fully functional.
|
|
169
169
|
|
|
170
170
|
> **Auto-adopt no longer adds its block to your project's `CLAUDE.md` (next release after 6.19.4).** On every SessionStart the plugin delivers its steering text — the trigger table that boosts Claude's proactive use of `mem_recall` / `mem_save`. In a git repository that does not already carry the block it keeps a managed block in `CLAUDE.local.md` at the repository root (Claude Code loads that file like `CLAUDE.md`, also in subagents that load project instructions; the built-in Explore and Plan agents load none) and adds the file to the repository's `.git/info/exclude` unless your ignore rules already cover it, so git does not list or commit it; you get a **one-time notice** the first time it is written. Claude Code reads instruction files before the plugin's startup hook runs, so the session that creates the file gets the text added to its context instead, once (its subagents do not see it). Where Claude Code reads an `AGENTS.md` as the project's instructions, it stops reading it once a `CLAUDE.md` or `CLAUDE.local.md` exists in the session's directory or above, so there nothing is written and the text is **injected** (subagents do not see it), with a one-time notice that names that `AGENTS.md`. With `CLAUDE_MEM_RULES_STEERING=1` the block goes to `.claude/rules/claude-mem-lite.md` at the repository root instead — excluded from git the same way, loaded by Claude Code as project instructions, also in subagents that load project instructions, and it leaves `AGENTS.md` loading — with its own one-time notice; it is not the default because in a pre-registered A/B it did not beat injection by the bar set in advance (`docs/audits/20261006-d212-ab.md`). Outside git, in a repository rooted at `$HOME`, where `CLAUDE.local.md` is tracked or a symbolic link, or where the repository root is an npm package that `npm publish` would ship it with (no `"private": true`, no `files` list leaving it out, and without one no `.npmignore` naming it), nothing is written and the text is **injected** into each session's context, with a one-time notice suggesting `/adopt` (not at `$HOME`). With the variable set, the same holds where the rules file cannot be written (a symbolic link on its path, a tracked or foreign file of that name, an npm package that would ship it). The notice beside an `AGENTS.md` names it, why there is no file, and the ways to a file that keep it loading, each only where it works: Project instructions = `claude-md-and-agents-md` in `/config`, after which `CLAUDE.local.md` is written (not where `CLAUDE.local.md` is refused too: a package root, or a file you removed), and `/adopt`, whose `CLAUDE.md` imports the `AGENTS.md` beside it (not offered when an `AGENTS.md` above that directory or in a subdirectory would stop loading). The detail file the block points at lives in the plugin's data directory, named with a `~/` path. `.git/info/exclude` is read by git only: docker build contexts, archives and other packagers can pick `CLAUDE.local.md` or the rules file up (a publishable npm package root does not keep `CLAUDE.local.md`: a block written before is taken out at the next session start; in a project whose `AGENTS.md` it would switch off, the block comes out and is injected, or, with `CLAUDE_MEM_RULES_STEERING=1`, moves to the rules file where that can be written). Earlier versions added the block to your project's own `<cwd>/CLAUDE.md` (a file that is normally committed) plus a `<cwd>/.claude/plugin_claude_mem_lite.md` detail file, unasked, in every project you opened; those projects keep the block, and the first session of this version refreshes it because the text changed — to move one to the local file, run `claude-mem-lite unadopt` there and commit the removal. Why not inject everywhere: in our sandbox evaluation (one project, Claude Opus 5.5) the agent made 1.5 proactive memory saves per 8-session run with injected steering against 5.25 with the block in `CLAUDE.local.md` or `CLAUDE.md`, and subagents never saw injected text. It applies regardless of install path (npm, npx, `/plugin`, manual); silence these notices with `MEM_NO_ADOPT_HINT=1`.
|
|
171
171
|
>
|
|
@@ -684,9 +684,9 @@ have not allowed, and routing the same action through Bash would sidestep it.
|
|
|
684
684
|
/mem timeline <query> # Browse timeline around a match
|
|
685
685
|
/mem browse # Tier-grouped memory dashboard
|
|
686
686
|
/mem <query> # Shorthand for search
|
|
687
|
-
/lesson <text> # Save a non-obvious lesson
|
|
688
|
-
/bug <text>
|
|
689
|
-
/verify
|
|
687
|
+
/lesson <text> # Save a non-obvious lesson as a searchable observation
|
|
688
|
+
/claude-mem-lite:bug <text> # Log a known bug + repro steps as a searchable observation
|
|
689
|
+
/claude-mem-lite:verify # Check memories against the current code; correct stale ones after you approve
|
|
690
690
|
```
|
|
691
691
|
|
|
692
692
|
### Efficient Search Workflow
|
|
@@ -701,12 +701,10 @@ have not allowed, and routing the same action through Bash would sidestep it.
|
|
|
701
701
|
|
|
702
702
|
Opt-in mechanism that installs a slug-scoped managed block into the project's
|
|
703
703
|
own `CLAUDE.md` (plus an on-demand detail doc under `.claude/`) so Claude Code
|
|
704
|
-
loads the plugin's MCP-tool triggers as **project instructions
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
instructions) rather than polluting `MEMORY.md`, which is reserved for the user's
|
|
709
|
-
own memories. The pre-v3.13 scheme wrote into `MEMORY.md`; it is migrated away
|
|
704
|
+
loads the plugin's MCP-tool triggers as **project instructions**, delivered in a
|
|
705
|
+
message after the system prompt. Steering lives in `CLAUDE.md` (the canonical home
|
|
706
|
+
for project instructions) rather than in the memdir `MEMORY.md`, which is reserved
|
|
707
|
+
for the user's own memories. The pre-v3.13 scheme wrote into `MEMORY.md`; it is migrated away
|
|
710
708
|
automatically on the next SessionStart.
|
|
711
709
|
|
|
712
710
|
```bash
|
package/README.zh-CN.md
CHANGED
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
- **插件缓存 hook 自愈** -- Claude Code runtime 从 `~/.claude/plugins/cache/<mp>/<plugin>/<ver>/hooks/hooks.json` 读取插件 hook,而非 marketplace 源。当 `install.mjs` 写入 `settings.json` 的 hooks 与残留 cache `hooks.json` 同时存在(例如曾装过 marketplace 版本,或插件被 Claude Code 自动升级重建 cache),runtime 会注册两套 hook → 每次 SessionStart / UserPromptSubmit 都触发两份。`install.mjs` 和 `hook-update.mjs` 现在会清理每个 cache 版本目录下的 `hooks.json`;`hook.mjs session-start` 每次启动自愈(通过 `hasInstallManagedHooks` 门控,不影响纯插件模式用户);`install.mjs status` 会报告 cache 污染状况(自 v2.31.1 / v2.31.2 起)。
|
|
96
96
|
- **Git-SHA 延续锚点**(v2.31.0)-- handoff 记录包含 `git_sha_at_handoff` 字段,任何匹配当前 `HEAD` 的 handoff 都视为延续会话,不受 TTL 限制。代码状态比时钟时间更能反映上下文延续。
|
|
97
97
|
- **启动面板**(v2.31.0)-- SessionStart hook 将 `git status` + `~/.claude/tasks/*.json` + `~/.claude/plans/*.md` + 最近 /exit 交接 + 最近事件数聚合为一个结构化块,通过 `hookSpecificOutput.additionalContext` 注入。
|
|
98
|
-
- **活动命名空间**(v2.31.0)-- 为非 memdir 类型(`bugfix` / `lesson` / `bug` / `discovery` / `refactor` / `feature` / `observation` / `decision`)启用独立的 `events` 表 + FTS5,与 observations 表的 `WHAT_NOT_TO_SAVE` 语义解耦。CLI:`claude-mem-lite activity save|search|recent|show`。`hook-llm` 通过 `persistHaikuSummary` 路由非 memdir 摘要,observations → events 升级路径是事务原子的。(v3.39:`/lesson`、`/bug` 斜杠命令已从此 events 表重定向到可搜索的 **observations**——`mem_search` 从不读 events 表,显式保存因此搜不到;events 表仍作自动捕获活动日志。)
|
|
98
|
+
- **活动命名空间**(v2.31.0)-- 为非 memdir 类型(`bugfix` / `lesson` / `bug` / `discovery` / `refactor` / `feature` / `observation` / `decision`)启用独立的 `events` 表 + FTS5,与 observations 表的 `WHAT_NOT_TO_SAVE` 语义解耦。CLI:`claude-mem-lite activity save|search|recent|show`。`hook-llm` 通过 `persistHaikuSummary` 路由非 memdir 摘要,observations → events 升级路径是事务原子的。(v3.39:`/lesson`、`/claude-mem-lite:bug` 斜杠命令已从此 events 表重定向到可搜索的 **observations**——`mem_search` 从不读 events 表,显式保存因此搜不到;events 表仍作自动捕获活动日志。)
|
|
99
99
|
|
|
100
100
|
## 平台支持
|
|
101
101
|
|
|
@@ -129,7 +129,7 @@ v5.1.0 到 v6.1.0 之间,`package.json` 声明的是 `os: ["darwin", "linux"]`
|
|
|
129
129
|
|
|
130
130
|
插件模式会管理自己的运行时与钩子。SessionStart 时它现在只会**检查并提示**新版本,不会直接覆盖插件目录中的文件。插件模式请通过 Claude 的插件更新流程完成升级。
|
|
131
131
|
|
|
132
|
-
> **插件安装本身即完整** —— hooks、MCP 工具、以及捆绑的 slash 命令(`/mem`、`/lesson`、`/bug`、`/adopt`)全部从插件内运行,无需第二步。slash 命令以从插件目录解析出的绝对路径调用捆绑 CLI(`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`),因此不依赖 `PATH` 上的任何东西。全局 `claude-mem-lite` **shell** 命令(用于你自己在终端里跑查询)是**可选**的 —— `npm i -g claude-mem-lite` —— 且是**独立**的 npm 安装:插件的自动更新**不会**刷新它,想保持同步就重新跑 `npm i -g claude-mem-lite@latest`。插件要完整工作**并不需要**它。
|
|
132
|
+
> **插件安装本身即完整** —— hooks、MCP 工具、以及捆绑的 slash 命令(`/mem`、`/lesson`、`/claude-mem-lite:bug`、`/adopt`)全部从插件内运行,无需第二步。slash 命令以从插件目录解析出的绝对路径调用捆绑 CLI(`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`),因此不依赖 `PATH` 上的任何东西。全局 `claude-mem-lite` **shell** 命令(用于你自己在终端里跑查询)是**可选**的 —— `npm i -g claude-mem-lite` —— 且是**独立**的 npm 安装:插件的自动更新**不会**刷新它,想保持同步就重新跑 `npm i -g claude-mem-lite@latest`。插件要完整工作**并不需要**它。
|
|
133
133
|
|
|
134
134
|
### 方式二:npx(一行命令)
|
|
135
135
|
|
|
@@ -533,9 +533,9 @@ README 和 `docs/ARCHITECTURE.md` 都钉在它上面。)
|
|
|
533
533
|
/mem timeline <query> # 围绕匹配结果浏览时间线
|
|
534
534
|
/mem browse # 分层记忆仪表盘
|
|
535
535
|
/mem <query> # search 的简写
|
|
536
|
-
/lesson <text> #
|
|
537
|
-
/bug <text>
|
|
538
|
-
/verify
|
|
536
|
+
/lesson <text> # 把非显而易见的经验存为可搜索的 observation
|
|
537
|
+
/claude-mem-lite:bug <text> # 把已知 bug + 复现步骤记为可搜索的 observation
|
|
538
|
+
/claude-mem-lite:verify # 对照当前代码核查记忆;你确认后才改正过期的记忆
|
|
539
539
|
```
|
|
540
540
|
|
|
541
541
|
### 高效搜索工作流
|
|
@@ -548,10 +548,11 @@ README 和 `docs/ARCHITECTURE.md` 都钉在它上面。)
|
|
|
548
548
|
|
|
549
549
|
### Invited Memory(邀请式记忆,v2.32+)
|
|
550
550
|
|
|
551
|
-
Opt-in
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
551
|
+
Opt-in 机制——在项目自己的 `CLAUDE.md` 里写入一个按 slug 限定的托管块(外加 `.claude/` 下
|
|
552
|
+
按需读取的详情文档),让 Claude Code 把插件的 MCP 工具触发规则作为**项目指令**加载(在系统
|
|
553
|
+
提示之后的一条消息里送达)。引导放在 `CLAUDE.md`(项目指令的正规位置),不去占用 memdir 里
|
|
554
|
+
留给用户自己记忆的 `MEMORY.md`。v3.13 之前的方案写入
|
|
555
|
+
`MEMORY.md`;下一次 SessionStart 会自动迁走。
|
|
555
556
|
|
|
556
557
|
```bash
|
|
557
558
|
claude-mem-lite adopt # 当前项目注入
|
|
@@ -566,16 +567,19 @@ claude-mem-lite unadopt # 移除 CLAUDE.md 托管块和详情文档
|
|
|
566
567
|
Slash 命令 `/adopt` 和 `/unadopt` 是上述 CLI 的包装。
|
|
567
568
|
|
|
568
569
|
**Adopt 后会发生什么:**
|
|
569
|
-
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
570
|
+
- `<cwd>/CLAUDE.md` 新增一段 `<!-- claude-mem-lite:begin v1 -->…<!-- claude-mem-lite:end -->`
|
|
571
|
+
包裹、带独立 `## claude-mem-lite — persistent memory` 标题的托管块,内含指向
|
|
572
|
+
`mem_recall` / `mem_save` / `mem_defer` 及其关键参数的触发表。只管理这一段,`CLAUDE.md`
|
|
573
|
+
其余内容原样保留,可与其他插件(如 `code-graph-mcp`)的托管块共存于同一文件。
|
|
574
|
+
- 生成 `<cwd>/.claude/plugin_claude_mem_lite.md` 详情文件(不自动加载;`CLAUDE.md` 托管块
|
|
575
|
+
指向它时按需读取)。出货内容变化(版本升级或模板变更)时托管块自动刷新,除非设
|
|
576
|
+
`CLAUDE_MEM_NO_TEMPLATE_REFRESH=1`。
|
|
573
577
|
- 保守 hook 层自动瘦身:MCP server instructions 去掉 `WHEN TO USE` 段,
|
|
574
578
|
SessionStart 注入去掉 `File Lessons` / `Key Context`。`#ID` 引用与 `Recent`
|
|
575
579
|
表保留,`mem_get` 仍可随时展开。
|
|
576
580
|
|
|
577
581
|
**什么时候生效?**
|
|
578
|
-
-
|
|
582
|
+
- `CLAUDE.md` 托管块和 hook 层瘦身(`File Lessons` / `Key Context` / lesson
|
|
579
583
|
后缀)**下一次 SessionStart** 生效(adopt 的项目下任一新会话)。
|
|
580
584
|
- MCP server instructions 是**服务启动时构建一次**,MCP 协议无 "push" 机制,
|
|
581
585
|
所以 `WHEN TO USE` / `Decision rules` 两段的瘦身**只在 Claude Code 重启后**
|
package/adopt-content.mjs
CHANGED
|
@@ -159,7 +159,7 @@ PreToolUse hook 在你 Read / Edit / Write 文件前已自动 \`mem_recall\` 该
|
|
|
159
159
|
|
|
160
160
|
| 场景 | CLI |
|
|
161
161
|
|------|-----|
|
|
162
|
-
| 清理过期记忆 | \`${CLI} maintain scan
|
|
162
|
+
| 清理过期记忆 | \`${CLI} maintain scan\` 预览;清理本身交给用户启动的 \`/claude-mem-lite:update\` |
|
|
163
163
|
| 深度优化(Haiku) | \`${CLI} optimize\`(默认 preview;\`--run\` 执行,\`--task re-enrich,normalize,cluster-merge,smart-compress\`) |
|
|
164
164
|
| 压缩旧条目 | \`${CLI} compress\`(默认 preview;\`--execute\` 执行,\`--age-days N\`) |
|
|
165
165
|
| FTS5 索引检查 / 重建 | \`${CLI} fts-check <check\\|rebuild>\` |
|
package/claudemd.mjs
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
// project-tree managed block at <cwd>/CLAUDE.md plus an on-demand detail doc
|
|
3
3
|
// at <cwd>/.claude/plugin_<slug>.md.
|
|
4
4
|
//
|
|
5
|
-
// Why here and not memdir.mjs:
|
|
6
|
-
// memory-dir MEMORY.md
|
|
7
|
-
// canonical home for project instructions) — seeding MEMORY.md just pollutes an
|
|
5
|
+
// Why here and not memdir.mjs: steering belongs in CLAUDE.md (the canonical home
|
|
6
|
+
// for project instructions) — seeding the memory-dir MEMORY.md just pollutes an
|
|
8
7
|
// index meant for the user's own memories. This module mirrors the design
|
|
9
8
|
// shipped by the sibling code-graph-mcp plugin (claude-plugin/scripts/adopt.js)
|
|
10
9
|
// and the oh-my-claudecode versioned `<!-- :begin vN -->` managed-block pattern.
|
package/cli/common.mjs
CHANGED
|
@@ -596,11 +596,16 @@ export function obsFieldLabel(field) {
|
|
|
596
596
|
* 2026-08-14 A4). Say what the rows are and what deletes them — and say nothing about
|
|
597
597
|
* compression, which is a different sentinel with a different lifecycle.
|
|
598
598
|
*
|
|
599
|
+
* purge_stale deletes only the queued rows older than its retain window (D#450), so the line
|
|
600
|
+
* also gives the number a purge at the default window deletes now.
|
|
601
|
+
*
|
|
599
602
|
* @param {number} n stats.pendingPurge
|
|
603
|
+
* @param {number} due stats.pendingPurgeDue
|
|
604
|
+
* @param {number} retainDays the default retain window `due` was counted at
|
|
600
605
|
* @returns {string} the full indented line, identical on both surfaces.
|
|
601
606
|
*/
|
|
602
|
-
export function formatPendingPurgeLine(n) {
|
|
603
|
-
return ` Pending purge (idle-marked): ${n} (rows maintenance queued: hidden and still idle 7 days later, or queued by an earlier version — purge_stale deletes
|
|
607
|
+
export function formatPendingPurgeLine(n, due, retainDays) {
|
|
608
|
+
return ` Pending purge (idle-marked): ${n} (rows maintenance queued: hidden and still idle 7 days later, or queued by an earlier version — purge_stale deletes those older than its retain window: ${due} at the default ${retainDays} days)`;
|
|
604
609
|
}
|
|
605
610
|
|
|
606
611
|
/**
|
package/commands/adopt.md
CHANGED
|
@@ -6,10 +6,10 @@ description: "Use when: user asks to put the claude-mem-lite steering block into
|
|
|
6
6
|
# /adopt
|
|
7
7
|
|
|
8
8
|
Install the claude-mem-lite **steering block** into the current project's
|
|
9
|
-
`CLAUDE.md` (the canonical home for project instructions —
|
|
10
|
-
|
|
11
|
-
`MEMORY.md`: that index belongs to the user's own
|
|
12
|
-
|
|
9
|
+
`CLAUDE.md` (the canonical home for project instructions — Claude Code loads it
|
|
10
|
+
into every session, in a message after the system prompt). It does not go
|
|
11
|
+
in the project's memory-dir `MEMORY.md`: that index belongs to the user's own
|
|
12
|
+
memories.
|
|
13
13
|
|
|
14
14
|
Auto-adopt does not add the block to `CLAUDE.md`: in a git repository it keeps the same block
|
|
15
15
|
in `CLAUDE.local.md` at the repository root, excluded from git through `.git/info/exclude`.
|
|
@@ -74,7 +74,7 @@ doc). Other plugins' blocks (e.g. `code-graph-mcp:*`) and your own prose survive
|
|
|
74
74
|
Adoption does NOT remove the hook-based injection (SessionStart context,
|
|
75
75
|
UserPromptSubmit related-memory). Those remain as fallback. Post-adopt the MCP
|
|
76
76
|
`WHEN TO USE` section + the `File Lessons` / `Key Context` sections auto-trim,
|
|
77
|
-
since the CLAUDE.md block already carries the triggers
|
|
77
|
+
since the CLAUDE.md block already carries the triggers.
|
|
78
78
|
|
|
79
79
|
## Restart caveat for the MCP-instructions trim
|
|
80
80
|
|
package/commands/bug.md
CHANGED
|
@@ -3,7 +3,7 @@ name: bug
|
|
|
3
3
|
description: "Use when: logging a known bug + repro steps you can't fix right now. Writes a searchable observation (findable via mem_search + surfaced by recall hooks; still NOT memdir). Skip for bugs you're actively fixing in the current turn — just fix them."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /bug
|
|
6
|
+
# /claude-mem-lite:bug
|
|
7
7
|
|
|
8
8
|
Record a known bug + reproduction steps. Writes a searchable **observation**
|
|
9
9
|
(`type=bugfix`, description in `lesson_learned`) so future sessions can find it
|
|
@@ -59,5 +59,5 @@ Confirm to user with: `Bug logged: #<id>`.
|
|
|
59
59
|
|
|
60
60
|
## Examples
|
|
61
61
|
|
|
62
|
-
- `/bug intermittent test flake when DB is under load --repro "run pnpm test -- --retry=0; fails ~1 in 20 runs when CPU is busy"`.
|
|
63
|
-
- `/bug --file src/auth.mjs --severity high "session refresh drops the X-Forwarded-For header"` — no repro steps, just a high-severity note.
|
|
62
|
+
- `/claude-mem-lite:bug intermittent test flake when DB is under load --repro "run pnpm test -- --retry=0; fails ~1 in 20 runs when CPU is busy"`.
|
|
63
|
+
- `/claude-mem-lite:bug --file src/auth.mjs --severity high "session refresh drops the X-Forwarded-For header"` — no repro steps, just a high-severity note.
|
package/commands/lesson.md
CHANGED
|
@@ -8,9 +8,9 @@ description: "Use when: capturing a non-obvious lesson/gotcha/workaround after a
|
|
|
8
8
|
Record a lesson / gotcha / workaround. Writes a searchable **observation**
|
|
9
9
|
(`type=discovery` with the text as `lesson_learned`) so future sessions can
|
|
10
10
|
find it via `mem_search` and the PreToolUse recall hooks surface it on the
|
|
11
|
-
relevant files. Does NOT touch memdir — so lessons never end up in the
|
|
12
|
-
|
|
13
|
-
rules on what not to save there.
|
|
11
|
+
relevant files. Does NOT touch memdir — so lessons never end up in the
|
|
12
|
+
auto-memory index Claude Code loads into every session, and do not conflict with
|
|
13
|
+
Claude Code's auto-memory rules on what not to save there.
|
|
14
14
|
|
|
15
15
|
## When to use
|
|
16
16
|
|
package/commands/mem.md
CHANGED
|
@@ -30,8 +30,8 @@ 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 `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain scan` via Bash
|
|
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**; the CLI rejects anything outside that range, so `/mem cleanup 3d` cannot be honoured — say so rather than silently substituting the default.
|
|
33
|
+
- `/mem cleanup` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain scan` via Bash and report the pending purge and stale counts to the user. Then run the purge command below without `--confirm` first: it prints how many rows it would delete and deletes nothing. If that count is 0, tell the user nothing is old enough to purge yet and stop. Otherwise report that count, not the scan's pending count, which includes rows too recent to purge. Ask for confirmation, and if confirmed run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain execute --ops purge_stale --confirm` via Bash. **`--confirm` is required and is not optional politeness:** without it the command prints 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 both purge runs to only purge items older than N days. **`--retain-days` must be between 7 and 365**; the CLI rejects anything outside that range, so `/mem cleanup 3d` cannot be honoured — say so rather than silently substituting the default.
|
|
35
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
|
|
package/commands/update.md
CHANGED
|
@@ -22,9 +22,9 @@ Run each command below via Bash; the CLI reaches the maintenance operations whet
|
|
|
22
22
|
|
|
23
23
|
1. Run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain scan` to analyze maintenance candidates
|
|
24
24
|
2. Report scan results to the user (duplicates, stale items, broken items, boostable items, **pending purge** items)
|
|
25
|
-
3. **If pending purge items > 0**: first run the purge command below without `--confirm`: it prints how many rows it would delete and deletes nothing.
|
|
25
|
+
3. **If pending purge items > 0**: first run the purge command below without `--confirm`: it prints how many rows it would delete and deletes nothing. If that count is 0, tell the user nothing is old enough to purge yet and go on to the next step. Otherwise report that count to the user and ask for confirmation. If confirmed, run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain execute --ops purge_stale --confirm`. **`--confirm` is required:** without it the command prints a dry-run preview and deletes nothing while still succeeding, so you would report a purge that never happened. User may optionally add `--retain-days N` (default 30, allowed range 7–365) to both runs to control how many days of data to keep; the CLI rejects a value outside that range, so tell the user instead of substituting the default. Do NOT purge without explicit user confirmation. The purge comes before the next step on purpose: decay there queues more rows for purge, and those wait for a later run instead of joining the purge the user approved.
|
|
26
26
|
4. Run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain execute` to apply safe automatic changes — with no `--ops` it runs the default set: cleanup, decay, boost, then demote_pinned (left out when `CLAUDE_MEM_SKIP_DEMOTE_PINNED=1`)
|
|
27
|
-
5. If duplicates were found in scan, review them and run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain execute --ops dedup --merge-ids keepId:removeId,...` — keep the more important/recent observation in each pair. Groups are comma-separated and the first id in each is kept (`10:11,20:21:22`). For pairs similar enough to merge without review the scan prints a ready-
|
|
27
|
+
5. If duplicates were found in scan, review them and run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" maintain execute --ops dedup --merge-ids keepId:removeId,...` — keep the more important/recent observation in each pair. Groups are comma-separated and the first id in each is kept (`10:11,20:21:22`). For pairs similar enough to merge without review the scan prints a ready-to-run command after `Ready-to-use:`; run it as printed
|
|
28
28
|
6. Run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" compress --execute` for old low-value observations (without `--execute` it only previews)
|
|
29
29
|
|
|
30
30
|
### Phase 2: Summary
|
package/commands/verify.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: verify
|
|
3
|
-
description: "Use when: the user explicitly asks to verify, audit or correct their stored memories against the current code (e.g. \"check my memories for stale ones\", /verify). You check each memory with read-only repo tools and propose corrections; nothing is written until the user approves the exact plan. Not for routine recall or saving."
|
|
3
|
+
description: "Use when: the user explicitly asks to verify, audit or correct their stored memories against the current code (e.g. \"check my memories for stale ones\", /claude-mem-lite:verify). You check each memory with read-only repo tools and propose corrections; nothing is written until the user approves the exact plan. Not for routine recall or saving."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /verify — check memories against the code, then correct the stale ones
|
|
6
|
+
# /claude-mem-lite:verify — check memories against the code, then correct the stale ones
|
|
7
7
|
|
|
8
8
|
Memories go stale: a bug recorded as open gets fixed, a measurement gets retracted, a
|
|
9
9
|
mechanism is replaced. Measured on 118 live memories across 7 repos, ~10% were STALE and
|
|
@@ -12,8 +12,6 @@ this — cheap single-shot models misjudged it (precision 0.36) and model-writte
|
|
|
12
12
|
were false in 28 of 72 cases. What works is YOU reading the code: you propose, the user
|
|
13
13
|
approves the exact plan, and `verify-apply` is the only thing that writes.
|
|
14
14
|
|
|
15
|
-
(If another plugin also defines `/verify`, this one is `/claude-mem-lite:verify`.)
|
|
16
|
-
|
|
17
15
|
## Arguments
|
|
18
16
|
|
|
19
17
|
- `--from <YYYY-MM-DD>`: only memories saved on or after this date (default: all live).
|
package/hook-context.mjs
CHANGED
|
@@ -690,8 +690,8 @@ export function buildSessionContextLines(
|
|
|
690
690
|
|
|
691
691
|
// Phase A (QUIET_HOOKS) + Phase D (adopted sentinel): drop descriptive
|
|
692
692
|
// File Lessons / Key Context sections when the user has opted into low-noise
|
|
693
|
-
// hooks OR adopted invited-memory (
|
|
694
|
-
//
|
|
693
|
+
// hooks OR adopted invited-memory (the steering block carries the triggers
|
|
694
|
+
// in the project's instructions). The Recent table still fires so #IDs
|
|
695
695
|
// remain reachable via mem_get. The collector sees only rows that survive
|
|
696
696
|
// BOTH the quiet gate and the per-section slice — rendered rows, nothing else.
|
|
697
697
|
const quiet = effectiveQuiet();
|
package/lib/activity.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Pure functions over the events table. No I/O beyond the passed-in db handle.
|
|
3
3
|
//
|
|
4
4
|
// Activity events are NOT memdir-compatible types; they live here precisely
|
|
5
|
-
// so they don't pollute the
|
|
5
|
+
// so they don't pollute the auto-memory index Claude Code loads into every session.
|
|
6
6
|
|
|
7
7
|
import { sanitizeFtsQuery } from '../utils.mjs';
|
|
8
8
|
import { eventSearchTerms } from '../nlp.mjs';
|
package/lib/get-core.mjs
CHANGED
|
@@ -177,10 +177,10 @@ export function supersededNotice(row) {
|
|
|
177
177
|
// String markers written by /verify (lib/verify-apply-core.mjs). Named, because "auto-dedup
|
|
178
178
|
// or merge" would send a reader looking for a duplicate that does not exist.
|
|
179
179
|
if (row.superseded_by === 'verify-retired') {
|
|
180
|
-
return '⚠ RETRACTED — retired by /verify as out of date, with no replacement. The fields below are the withdrawn version.';
|
|
180
|
+
return '⚠ RETRACTED — retired by /claude-mem-lite:verify as out of date, with no replacement. The fields below are the withdrawn version.';
|
|
181
181
|
}
|
|
182
182
|
if (row.superseded_by === 'verify-undone') {
|
|
183
|
-
return '⚠ RETRACTED — a /verify correction withdrawn by its undo; the original it replaced is live again. The fields below are the withdrawn version.';
|
|
183
|
+
return '⚠ RETRACTED — a /claude-mem-lite:verify correction withdrawn by its undo; the original it replaced is live again. The fields below are the withdrawn version.';
|
|
184
184
|
}
|
|
185
185
|
return '⚠ RETRACTED — superseded (auto-dedup or merge). The fields below are the withdrawn version.';
|
|
186
186
|
}
|
package/lib/maintain-core.mjs
CHANGED
|
@@ -34,6 +34,8 @@ import { DAY_MS } from './time-constants.mjs';
|
|
|
34
34
|
import { snapshotDb } from './db-backup.mjs';
|
|
35
35
|
import { isTransientPath } from './bash-file-targets.mjs';
|
|
36
36
|
export const STALE_AGE_MS = 30 * DAY_MS;
|
|
37
|
+
/** Days of pending-purge rows purge_stale keeps when the caller names no retain window. */
|
|
38
|
+
export const DEFAULT_RETAIN_DAYS = 30;
|
|
37
39
|
export const OP_CAP = 1000;
|
|
38
40
|
export const SCAN_LIMIT = 500;
|
|
39
41
|
export const DUPLICATE_LIMIT = 50;
|
|
@@ -896,6 +898,13 @@ export function maintenanceStats(db, { projectFilter, baseParams, staleAge }) {
|
|
|
896
898
|
WHERE compressed_into = ${COMPRESSED_PENDING_PURGE} AND ${NOT_EXPLICIT_SAVE_SQL} ${projectFilter}`,
|
|
897
899
|
)
|
|
898
900
|
.get(...baseParams);
|
|
901
|
+
// D#450: purge_stale deletes only the queued rows older than its retain window, so the count
|
|
902
|
+
// above can exceed what a purge removes. Say how many a purge at the default window would.
|
|
903
|
+
const pendingPurgeDue = purgeStalePreview(
|
|
904
|
+
db,
|
|
905
|
+
{ projectFilter, baseParams },
|
|
906
|
+
Date.now() - DEFAULT_RETAIN_DAYS * DAY_MS,
|
|
907
|
+
).candidates;
|
|
899
908
|
// D12: rows maintenance has hidden and will queue once they stay idle through the grace.
|
|
900
909
|
// Without this line a decay run that hid 3 rows read "Total active: 0 … Pending purge: 0".
|
|
901
910
|
const hidden = db
|
|
@@ -916,6 +925,7 @@ export function maintenanceStats(db, { projectFilter, baseParams, staleAge }) {
|
|
|
916
925
|
return {
|
|
917
926
|
...stats,
|
|
918
927
|
pendingPurge: pendingPurge.count,
|
|
928
|
+
pendingPurgeDue,
|
|
919
929
|
hidden: hidden.count,
|
|
920
930
|
explicitToShowAgain: explicitToShowAgain.count,
|
|
921
931
|
};
|
|
@@ -987,7 +997,7 @@ export function runMaintainOps(
|
|
|
987
997
|
ctx,
|
|
988
998
|
ops,
|
|
989
999
|
{
|
|
990
|
-
retainDays =
|
|
1000
|
+
retainDays = DEFAULT_RETAIN_DAYS,
|
|
991
1001
|
retainCutoff,
|
|
992
1002
|
confirmed = false,
|
|
993
1003
|
mergeGroups = null,
|
package/lib/quiet-scope.mjs
CHANGED
|
@@ -25,7 +25,7 @@ export function isQuietHooks() {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Phase D (v2.32.1+) → v3.13: if the current project has adopted our steering,
|
|
28
|
-
// the contract
|
|
28
|
+
// the contract already loads with the project's instructions — so hook +
|
|
29
29
|
// MCP-instruction output can also go quiet. v3.13 moved that contract from the
|
|
30
30
|
// memory-dir MEMORY.md sentinel to the project CLAUDE.md managed block, so check
|
|
31
31
|
// the new scheme first and keep the legacy memdir sentinel as a fallback (an
|
package/lib/save-nudge.mjs
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
// (optimizeRun wide/aliases re-enrich) stays the safety net for saves that ignore it.
|
|
8
8
|
//
|
|
9
9
|
// Shared by server.mjs (mem_save) and mem-cli.mjs (cmdSave) — one gate, two phrasings,
|
|
10
|
-
// no twin drift.
|
|
10
|
+
// no twin drift. Both name the CLI by its path (D#448): mem_update is left out of tools/list,
|
|
11
|
+
// so the model cannot call it, and a plugin install has no `claude-mem-lite` on PATH.
|
|
12
|
+
import { CLI_INVOKE } from '../cli-path.mjs';
|
|
13
|
+
|
|
11
14
|
const NUDGE_TYPES = new Set(['bugfix', 'decision']);
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -18,6 +21,6 @@ export function buildLessonNudge({ type, id, lessonCaptured, surface }) {
|
|
|
18
21
|
if (lessonCaptured || !NUDGE_TYPES.has(type)) return '';
|
|
19
22
|
const what = type === 'decision' ? 'constraint + tradeoff' : 'root cause + fix';
|
|
20
23
|
return surface === 'cli'
|
|
21
|
-
? `\n[mem] ⚠ ${type} #${id} saved without a lesson — capture the ${what} while it's fresh:
|
|
22
|
-
: ` ⚠ Saved without lesson_learned — a ${type} is worth keeping only with its lesson. Capture it now:
|
|
24
|
+
? `\n[mem] ⚠ ${type} #${id} saved without a lesson — capture the ${what} while it's fresh: ${CLI_INVOKE} update ${id} --lesson "<${what}>"`
|
|
25
|
+
: ` ⚠ Saved without lesson_learned — a ${type} is worth keeping only with its lesson. Capture it now: ${CLI_INVOKE} update ${id} --lesson "<${what}>"`;
|
|
23
26
|
}
|
package/lib/stats-quality.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { truncate } from '../format-utils.mjs';
|
|
|
9
9
|
import { COMPRESSED_PENDING_PURGE } from '../utils.mjs';
|
|
10
10
|
|
|
11
11
|
import { DAY_MS } from './time-constants.mjs';
|
|
12
|
+
import { CLI_INVOKE } from '../cli-path.mjs';
|
|
12
13
|
// v3.42 F7: noise/low-signal ratios must divide by the LIVE (non-compressed) observation
|
|
13
14
|
// count, NOT the all-rows total. Both numerators (lowVal, lowSignalTitle) already exclude
|
|
14
15
|
// compressed rows (`compressed_into = 0`); dividing by an all-inclusive denominator
|
|
@@ -222,7 +223,7 @@ export function formatQualityReport(data) {
|
|
|
222
223
|
const purgeGap = (purgeNum - 10).toFixed(1);
|
|
223
224
|
const purgeStatus = purgeNum <= 10 ? '✅' : purgeNum <= 30 ? '🟡' : '🔴';
|
|
224
225
|
lines.push(
|
|
225
|
-
` ${purgeStatus} Pending purge ≤ 10% → currently ${purgePct}% (${purgeRow.pending_purge}/${purgeRow.compressed}) (gap ${purgeGap >= 0 ? '+' : ''}${purgeGap}pp)${purgeNum > 10 ?
|
|
226
|
+
` ${purgeStatus} Pending purge ≤ 10% → currently ${purgePct}% (${purgeRow.pending_purge}/${purgeRow.compressed}) (gap ${purgeGap >= 0 ? '+' : ''}${purgeGap}pp)${purgeNum > 10 ? ` — preview: ${CLI_INVOKE} maintain execute --ops purge_stale (add --confirm to delete the rows it counts)` : ''}`,
|
|
226
227
|
);
|
|
227
228
|
}
|
|
228
229
|
|
package/mem-cli.mjs
CHANGED
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
PINNED_INJ_THRESHOLD,
|
|
64
64
|
resolveDefaultMaintainOps,
|
|
65
65
|
ALL_MAINTAIN_OPS,
|
|
66
|
+
DEFAULT_RETAIN_DAYS,
|
|
66
67
|
} from './lib/maintain-core.mjs';
|
|
67
68
|
// snapshotDb left with maintain-core: the pre-maintain snapshot is part of the op ORDER
|
|
68
69
|
// (it must see the pre-existing pending rows), so it moved into runMaintainOps (P1-5).
|
|
@@ -2773,7 +2774,7 @@ function cmdMaintain(db, args) {
|
|
|
2773
2774
|
` Pinned-but-uncited (inj>=${PINNED_INJ_THRESHOLD}, cited=0, above floor): ${stats.pinned} — floored by the default maintain set since v3.76.0, no lesson → 1, lesson → 2 (opt out: CLAUDE_MEM_SKIP_DEMOTE_PINNED=1)`,
|
|
2774
2775
|
);
|
|
2775
2776
|
out(formatHiddenLine(stats.hidden));
|
|
2776
|
-
out(formatPendingPurgeLine(stats.pendingPurge));
|
|
2777
|
+
out(formatPendingPurgeLine(stats.pendingPurge, stats.pendingPurgeDue, DEFAULT_RETAIN_DAYS));
|
|
2777
2778
|
if (stats.explicitToShowAgain > 0)
|
|
2778
2779
|
out(
|
|
2779
2780
|
` Explicit saves an earlier release hid (the next execute that runs decay — the default set does — shows them again): ${stats.explicitToShowAgain}`,
|
|
@@ -2796,7 +2797,7 @@ function cmdMaintain(db, args) {
|
|
|
2796
2797
|
const remove = keep === d.a ? d.b : d.a;
|
|
2797
2798
|
return `${keep.id}:${remove.id}`;
|
|
2798
2799
|
});
|
|
2799
|
-
out(` Ready-to-use:
|
|
2800
|
+
out(` Ready-to-use: ${CLI_INVOKE} maintain execute --ops dedup --merge-ids ${mergeIds.join(',')}`);
|
|
2800
2801
|
}
|
|
2801
2802
|
|
|
2802
2803
|
if (manualReview.length > 0) {
|
|
@@ -2832,7 +2833,7 @@ function cmdMaintain(db, args) {
|
|
|
2832
2833
|
// whole command atomically. The old code validated inside db.transaction() with a bare
|
|
2833
2834
|
// `return`, so an earlier op (cleanup hard-delete / decay / boost) had already mutated and
|
|
2834
2835
|
// the transaction COMMITTED despite the exit-1 error (audit MED-2 atomicity).
|
|
2835
|
-
let retainDays =
|
|
2836
|
+
let retainDays = DEFAULT_RETAIN_DAYS;
|
|
2836
2837
|
if (ops.includes('purge_stale') && flags['retain-days'] !== undefined) {
|
|
2837
2838
|
// Number + isInteger (not parseInt) so "7.5"/"30x" are rejected rather than silently
|
|
2838
2839
|
// truncated — parity with the mem_maintain zod .int().min(7).max(365) bound.
|
|
@@ -3383,7 +3384,7 @@ Commands:
|
|
|
3383
3384
|
--project P Override the restored project for every row
|
|
3384
3385
|
--dry-run Preview what would be restored without writing
|
|
3385
3386
|
|
|
3386
|
-
verify-apply <file> Apply agent-verified memory corrections (/verify writes these).
|
|
3387
|
+
verify-apply <file> Apply agent-verified memory corrections (/claude-mem-lite:verify writes these).
|
|
3387
3388
|
Dry run by default: prints the changes and a plan digest.
|
|
3388
3389
|
--apply Back up the target rows, apply in one transaction, read back
|
|
3389
3390
|
--digest D Required with --apply: the digest the approved dry run printed
|
|
@@ -3476,7 +3477,7 @@ Commands:
|
|
|
3476
3477
|
|
|
3477
3478
|
Valid types: bugfix, lesson, bug, discovery, refactor, feature, observation, decision
|
|
3478
3479
|
--files (plural, comma-split) preferred; --file (singular) kept for back-compat.
|
|
3479
|
-
Use /lesson or /bug slash commands for faster capture (T8).
|
|
3480
|
+
Use /lesson or /claude-mem-lite:bug slash commands for faster capture (T8).
|
|
3480
3481
|
|
|
3481
3482
|
adopt Put the claude-mem-lite managed block into this project's
|
|
3482
3483
|
CLAUDE.md (normally committed, so the team gets it) + a
|
package/memdir.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Claude Code memdir at ~/.claude/projects/<encoded>/memory/.
|
|
3
3
|
//
|
|
4
4
|
// The public API lets a plugin install a single sentinel-wrapped line into
|
|
5
|
-
// MEMORY.md (
|
|
5
|
+
// MEMORY.md (loaded by Claude Code at the start of every session) plus an
|
|
6
6
|
// on-demand `plugin_<slug>.md` detail file. Writes are idempotent, hash-guarded
|
|
7
7
|
// against manual user edits, and capped by a 180-line budget so the injection
|
|
8
8
|
// block never gets truncated by Claude Code's 200-line MEMORY.md cap.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "6.29.
|
|
3
|
+
"version": "6.29.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "claude-mem-lite",
|
|
9
|
-
"version": "6.29.
|
|
9
|
+
"version": "6.29.3",
|
|
10
10
|
"os": [
|
|
11
11
|
"darwin",
|
|
12
12
|
"linux",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "6.29.
|
|
3
|
+
"version": "6.29.3",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. FTS5 BM25 keyword 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
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
package/search-scoring.mjs
CHANGED
|
@@ -33,8 +33,8 @@ import { PINNED_INJ_THRESHOLD } from './lib/maintain-core.mjs';
|
|
|
33
33
|
// ─── MCP Server Instructions Builder ───────────────────────────────────────
|
|
34
34
|
// Phase A (v2.31.3+): when quiet=true, drops WHEN-TO-USE proactive-trigger and
|
|
35
35
|
// Decision-rules sections; keeps the irreducible CLI/MCP tool list. Intended
|
|
36
|
-
// for users who adopted invited-memory (
|
|
37
|
-
// triggers
|
|
36
|
+
// for users who adopted invited-memory (the steering block carries the same
|
|
37
|
+
// triggers). Default false preserves v2.31.2 behavior.
|
|
38
38
|
// The CLI-vs-MCP round-trip routing rule lives in BASE (not VERBOSE) on purpose:
|
|
39
39
|
// it must reach adopted (quiet) projects too, where tool-heavy sessions defer the
|
|
40
40
|
// mem_* tools behind ToolSearch (CLI via Bash = 1 model round-trip; ToolSearch +
|
|
@@ -73,10 +73,10 @@ const INSTRUCTIONS_VERBOSE = [
|
|
|
73
73
|
' • "what happened recently?" → mem_recent (NOT search with empty query)',
|
|
74
74
|
' • "what do we know about file.mjs?" → mem_recall (NOT grep + manual search)',
|
|
75
75
|
' • "show me around observation #42" → mem_timeline (NOT mem_get + manual navigation)',
|
|
76
|
-
' • "clean up old/duplicate memories" →
|
|
77
|
-
' • "is the search index healthy?" →
|
|
78
|
-
' • "overview of memory tiers" →
|
|
79
|
-
' • "export for backup" →
|
|
76
|
+
' • "clean up old/duplicate memories" → CLI `maintain scan` to preview; the cleanup itself is /claude-mem-lite:update, which the user starts (NOT deleting rows one by one)',
|
|
77
|
+
' • "is the search index healthy?" → CLI `fts-check check` (NOT manual COUNT queries)',
|
|
78
|
+
' • "overview of memory tiers" → CLI `browse` (NOT mem_search + manual grouping)',
|
|
79
|
+
' • "export for backup" → CLI `export` (NOT manual SELECT queries)',
|
|
80
80
|
];
|
|
81
81
|
|
|
82
82
|
export function buildServerInstructions(quiet = false) {
|
package/server.mjs
CHANGED
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
STALE_AGE_MS,
|
|
56
56
|
resolveDefaultMaintainOps,
|
|
57
57
|
DEFAULT_MAINTAIN_OPS,
|
|
58
|
+
DEFAULT_RETAIN_DAYS,
|
|
58
59
|
} from './lib/maintain-core.mjs';
|
|
59
60
|
// snapshotDb left with maintain-core: the pre-maintain snapshot is part of the op ORDER
|
|
60
61
|
// (it must see the pre-existing pending rows), so it moved into runMaintainOps (P1-5).
|
|
@@ -534,7 +535,7 @@ function formatSearchOutput(
|
|
|
534
535
|
// skipped the branch on the reasoning that it "never renders the label" — true of
|
|
535
536
|
// the label, false of the echo.
|
|
536
537
|
if (expanded !== args.query) hint.push(`Searched as: ${queryLabel(expanded)}`);
|
|
537
|
-
hint.push('Tip: check spelling, try broader terms, or use
|
|
538
|
+
hint.push('Tip: check spelling, try broader terms, or use mem_recent to see what is stored.');
|
|
538
539
|
}
|
|
539
540
|
}
|
|
540
541
|
return { content: [{ type: 'text', text: hint.join('\n') }] };
|
|
@@ -1742,7 +1743,7 @@ server.registerTool(
|
|
|
1742
1743
|
` Decayable (imp>1, never accessed or injected, past the stale age): ${stats.decayable}`,
|
|
1743
1744
|
` Boostable (accessed>3, imp<3): ${stats.boostable}`,
|
|
1744
1745
|
formatHiddenLine(stats.hidden),
|
|
1745
|
-
formatPendingPurgeLine(stats.pendingPurge),
|
|
1746
|
+
formatPendingPurgeLine(stats.pendingPurge, stats.pendingPurgeDue, DEFAULT_RETAIN_DAYS),
|
|
1746
1747
|
...(stats.explicitToShowAgain > 0
|
|
1747
1748
|
? [
|
|
1748
1749
|
` Explicit saves an earlier release hid (the next execute that runs decay — the default set does — shows them again): ${stats.explicitToShowAgain}`,
|
|
@@ -1825,8 +1826,8 @@ server.registerTool(
|
|
|
1825
1826
|
// preview tells the caller to type next. Before the extraction this block rendered
|
|
1826
1827
|
// `inj>=8` as a literal while the CLI twin interpolated PINNED_INJ_THRESHOLD.
|
|
1827
1828
|
const results = runMaintainOps(db, mctx, ops, {
|
|
1828
|
-
retainDays: args.retain_days ??
|
|
1829
|
-
retainCutoff: Date.now() - (args.retain_days ??
|
|
1829
|
+
retainDays: args.retain_days ?? DEFAULT_RETAIN_DAYS,
|
|
1830
|
+
retainCutoff: Date.now() - (args.retain_days ?? DEFAULT_RETAIN_DAYS) * DAY_MS,
|
|
1830
1831
|
confirmed: purgeConfirmed,
|
|
1831
1832
|
mergeGroups: args.merge_ids || null,
|
|
1832
1833
|
mergeIdsProvided: Boolean(args.merge_ids),
|
package/tool-schemas.mjs
CHANGED
|
@@ -780,7 +780,7 @@ export const tools = [
|
|
|
780
780
|
'\n' +
|
|
781
781
|
'DO NOT use when:\n' +
|
|
782
782
|
' - You only want one record (use mem_get)\n' +
|
|
783
|
-
' - You have no anchor in mind and are just browsing (use mem_recent
|
|
783
|
+
' - You have no anchor in mind and are just browsing (use mem_recent)\n' +
|
|
784
784
|
' - The sequence is obvious from commit history (use git log)\n' +
|
|
785
785
|
' - You want "recent activity around X" (use mem_recent or mem_search sort="time")\n' +
|
|
786
786
|
'\n' +
|
|
@@ -802,7 +802,7 @@ export const tools = [
|
|
|
802
802
|
'DO NOT use when:\n' +
|
|
803
803
|
' - You have not seen the ID referenced anywhere (use mem_search first)\n' +
|
|
804
804
|
' - You only need title/type — that is already in the search result line\n' +
|
|
805
|
-
' - You are speculatively paging through IDs (use mem_recent
|
|
805
|
+
' - You are speculatively paging through IDs (use mem_recent)\n' +
|
|
806
806
|
'\n' +
|
|
807
807
|
'USE when:\n' +
|
|
808
808
|
' - Hook-injected context shows #NN and you need the full narrative/lesson\n' +
|