claude-mem-lite 3.98.0 → 3.99.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/adopt-content.mjs +45 -29
- package/claudemd.mjs +16 -2
- package/lib/citation-tracker.mjs +18 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "claude-mem-lite",
|
|
13
|
-
"version": "3.
|
|
13
|
+
"version": "3.99.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": "3.
|
|
3
|
+
"version": "3.99.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/adopt-content.mjs
CHANGED
|
@@ -17,11 +17,21 @@
|
|
|
17
17
|
// memory-dir MEMORY.md sentinel also carried `v1`, but it lives in a different file
|
|
18
18
|
// and is migrated away (claudemd.migrateLegacyMemoryDir), so there is no collision.
|
|
19
19
|
|
|
20
|
-
import { CLI_INVOKE } from './cli-path.mjs';
|
|
21
|
-
|
|
22
20
|
export const PLUGIN_SLUG = 'claude-mem-lite';
|
|
23
21
|
export const CURRENT_SENTINEL_VERSION = 'v1';
|
|
24
22
|
|
|
23
|
+
// The CLI name as written into the user's project tree — deliberately NOT `CLI_INVOKE`
|
|
24
|
+
// (audit R7 P2-1). CLI_INVOKE resolves to an absolute, VERSION-PINNED path
|
|
25
|
+
// (`node /home/<user>/.claude/plugins/cache/sdsrss/claude-mem-lite/<version>/cli.mjs`), and
|
|
26
|
+
// both generators below write files the user may commit: the managed block lands in
|
|
27
|
+
// <cwd>/CLAUDE.md and the detail doc in <cwd>/.claude/, which is the standard home for
|
|
28
|
+
// project-scoped settings/commands/agents and is commonly tracked. Embedding the resolved
|
|
29
|
+
// path there rewrote the file on every plugin release (needsRefresh sees doc drift) and gave
|
|
30
|
+
// teammates a $HOME path that exists on no other machine. This module's output must be
|
|
31
|
+
// byte-identical across installs; the resolved path belongs only on runtime-generated
|
|
32
|
+
// surfaces that never touch the repo (MCP `instructions`, hook recovery lines).
|
|
33
|
+
const CLI = 'claude-mem-lite';
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* The concise managed block injected into <cwd>/CLAUDE.md (between the
|
|
27
37
|
* slug-scoped sentinels — those are added by claudemd.renderBlock, NOT here).
|
|
@@ -32,8 +42,8 @@ export const CURRENT_SENTINEL_VERSION = 'v1';
|
|
|
32
42
|
export function buildClaudeMdBlock() {
|
|
33
43
|
// Intentionally machine-stable: MCP tool names only, NO CLI_INVOKE (that
|
|
34
44
|
// resolves to an absolute path that differs per install — it would make this
|
|
35
|
-
// committed/refreshed block churn across machines). The
|
|
36
|
-
//
|
|
45
|
+
// committed/refreshed block churn across machines). The detail doc holds the
|
|
46
|
+
// full CLI table and, since R7 P2-1, is held to the same standard — see CLI above.
|
|
37
47
|
return `## claude-mem-lite — persistent memory
|
|
38
48
|
|
|
39
49
|
PreToolUse hooks already run \`mem_recall\` for past lessons before Read/Edit/Write. The calls worth making proactively:
|
|
@@ -46,7 +56,7 @@ PreToolUse hooks already run \`mem_recall\` for past lessons before Read/Edit/Wr
|
|
|
46
56
|
| Deferring to a future session | \`mem_defer({title, priority:1|2|3, detail})\`; when fixed, add \`closes_deferred=[N]\` to \`mem_save\` |
|
|
47
57
|
| Looking up past work / history | \`mem_search "keywords"\` · \`mem_recent\` · \`mem_timeline\` |
|
|
48
58
|
|
|
49
|
-
Path cost is round-trips, not milliseconds: the PreToolUse hook above already recalls (0 calls) — prefer it. For an explicit query, if these \`mem_*\` tools are deferred behind ToolSearch this session, the Bash CLI
|
|
59
|
+
Path cost is round-trips, not milliseconds: the PreToolUse hook above already recalls (0 calls) — prefer it. For an explicit query, if these \`mem_*\` tools are deferred behind ToolSearch this session, the Bash CLI \`${CLI}\` is one call vs two (ToolSearch + call); the MCP server instructions carry the absolute path to use when it is not on PATH.
|
|
50
60
|
|
|
51
61
|
Full tool + CLI tables, citation/decay rules, and save discipline → \`.claude/plugin_claude_mem_lite.md\``;
|
|
52
62
|
}
|
|
@@ -60,10 +70,16 @@ Full tool + CLI tables, citation/decay rules, and save discipline → \`.claude/
|
|
|
60
70
|
export function getDetailDoc() {
|
|
61
71
|
return `# claude-mem-lite 插件契约(完整)
|
|
62
72
|
|
|
63
|
-
> 由 \`${
|
|
73
|
+
> 由 \`${CLI} adopt\` 生成、随版本自动刷新;卸载用 \`${CLI} unadopt\`。
|
|
64
74
|
> 精炼触发表在项目 \`CLAUDE.md\` 的 \`claude-mem-lite\` 托管块里;本文件是其展开。
|
|
65
75
|
> 设计背景见 docs/CLAUDE-MD-STEERING-PLAN.md。
|
|
66
76
|
|
|
77
|
+
> **本文下方所有命令写作 \`${CLI} <cmd>\`。** 该名字只在全局装过
|
|
78
|
+
> (\`npm i -g claude-mem-lite\`)时才在 PATH 上;否则用等价的
|
|
79
|
+
> \`node <插件根目录>/cli.mjs <cmd>\`,绝对路径见本会话 MCP server 的 instructions。
|
|
80
|
+
> 本文件**刻意不写死绝对路径**:它随安装位置与版本变化,而本文件可能被提交进仓库,
|
|
81
|
+
> 写死会导致每次升版都改动该文件、且队友拿到的是只在别人机器上存在的路径。
|
|
82
|
+
|
|
67
83
|
## 被动 recall(hook 已自动跑,你只需采纳)
|
|
68
84
|
|
|
69
85
|
PreToolUse hook 在你 Read / Edit / Write 文件前已自动 \`mem_recall\` 该文件:
|
|
@@ -108,7 +124,7 @@ PreToolUse hook 在你 Read / Edit / Write 文件前已自动 \`mem_recall\` 该
|
|
|
108
124
|
lesson_learned="<一行根因+一行修法>", importance=2)\`。判据:未来改同一文件的会话看到这条能否避坑?能→存。
|
|
109
125
|
- **非显然架构决策后**(≠ 改名/挪代码)调 \`mem_save(type="decision",
|
|
110
126
|
lesson_learned="<约束+为何这样选+牺牲了什么>")\`。\`decision\` 命中率显著高于 \`change\`(当前遥测约
|
|
111
|
-
3:1,会漂移——用 \`${
|
|
127
|
+
3:1,会漂移——用 \`${CLI} stats\` 实测,别套固定倍数);方向稳健:一条好 decision 抵数条 change。
|
|
112
128
|
别注水:decision 只留给真权衡,不是风格选择。
|
|
113
129
|
- **推迟到未来会话**(≠ 在途 todo、≠ 本 PR 跟进)调
|
|
114
130
|
\`mem_defer({title, priority:1|2|3, detail:"<约束+为何推迟>"})\`。
|
|
@@ -127,45 +143,45 @@ PreToolUse hook 在你 Read / Edit / Write 文件前已自动 \`mem_recall\` 该
|
|
|
127
143
|
|
|
128
144
|
| 场景 | CLI |
|
|
129
145
|
|------|-----|
|
|
130
|
-
| 清理过期记忆 | \`${
|
|
131
|
-
| 深度优化(Haiku) | \`${
|
|
132
|
-
| 压缩旧条目 | \`${
|
|
133
|
-
| FTS5 索引检查 / 重建 | \`${
|
|
134
|
-
| tier 分组浏览 | \`${
|
|
135
|
-
| 导出 JSON/JSONL | \`${
|
|
136
|
-
| 统计总量 / 健康 | \`${
|
|
137
|
-
| 删除 / 更新某条 | \`${
|
|
138
|
-
| skill-agent registry | \`${
|
|
146
|
+
| 清理过期记忆 | \`${CLI} maintain scan --ops purge_stale\` → \`maintain execute --ops purge_stale --confirm\`(删行必须 \`--confirm\`) |
|
|
147
|
+
| 深度优化(Haiku) | \`${CLI} optimize\`(默认 preview;\`--run\` 执行,\`--task re-enrich,normalize,cluster-merge,smart-compress\`) |
|
|
148
|
+
| 压缩旧条目 | \`${CLI} compress\`(默认 preview;\`--execute\` 执行,\`--age-days N\`) |
|
|
149
|
+
| FTS5 索引检查 / 重建 | \`${CLI} fts-check <check\\|rebuild>\` |
|
|
150
|
+
| tier 分组浏览 | \`${CLI} browse [--tier active]\` |
|
|
151
|
+
| 导出 JSON/JSONL | \`${CLI} export [--format jsonl]\` |
|
|
152
|
+
| 统计总量 / 健康 | \`${CLI} stats [--days 30]\` |
|
|
153
|
+
| 删除 / 更新某条 | \`${CLI} delete <id>[,<id>]\` · \`${CLI} update <id> [--title ...]\` |
|
|
154
|
+
| skill-agent registry | \`${CLI} registry <list\\|search\\|import>\` |
|
|
139
155
|
|
|
140
156
|
## CLI 速查(常用检索)
|
|
141
157
|
|
|
142
158
|
| 命令 | 用途 |
|
|
143
159
|
|------|------|
|
|
144
|
-
| \`${
|
|
145
|
-
| \`${
|
|
146
|
-
| \`${
|
|
147
|
-
| \`${
|
|
148
|
-
| \`${
|
|
149
|
-
| \`${
|
|
160
|
+
| \`${CLI} search "query"\` | FTS5 全文搜索(默认排除低信号 \`Modified X\` 等;加 \`--include-noise\` 找文件变更记录) |
|
|
161
|
+
| \`${CLI} search "err" --type bugfix\` | 按类型过滤 |
|
|
162
|
+
| \`${CLI} recall "file.mjs"\` | 文件相关记忆 |
|
|
163
|
+
| \`${CLI} recent 5\` | 最近 5 条 |
|
|
164
|
+
| \`${CLI} get 42,43\` | 按 ID 展开 |
|
|
165
|
+
| \`${CLI} timeline --anchor 42\` | 时间线上下文 |
|
|
150
166
|
|
|
151
167
|
## CLI 速查(写入 / 记录)
|
|
152
168
|
|
|
153
|
-
写入类工具多从 \`tools/list\` 隐藏 → 只能走 CLI。下表带**硬上限**(超限直接报错,别撞了才知道);完整 flag 见 \`${
|
|
169
|
+
写入类工具多从 \`tools/list\` 隐藏 → 只能走 CLI。下表带**硬上限**(超限直接报错,别撞了才知道);完整 flag 见 \`${CLI} help\`。
|
|
154
170
|
|
|
155
171
|
| 命令 | 签名(含硬约束) |
|
|
156
172
|
|------|------------------|
|
|
157
|
-
| 存观测 | \`${
|
|
158
|
-
| 推迟工作 | \`${
|
|
159
|
-
| 改某条 | \`${
|
|
160
|
-
| 事件日志 | \`${
|
|
173
|
+
| 存观测 | \`${CLI} save "<text>" --type bugfix\\|decision --lesson "<≤500 字符>" [--importance 1-3] [--closes-deferred N]\` — \`<text>\` **必填定位参数**;\`--lesson\` 超 500 直接 fail |
|
|
174
|
+
| 推迟工作 | \`${CLI} defer add "<title ≤200>" [--priority 1\\|2\\|3] [--detail "<约束+为何推迟>"]\` — 标题 >200 挪到 \`--detail\` |
|
|
175
|
+
| 改某条 | \`${CLI} update <id> [--lesson "<≤500>"] [--title T] [--type T] [--importance 1-3] [--narrative T] [--concepts "a b c"]\` |
|
|
176
|
+
| 事件日志 | \`${CLI} activity save --type <bugfix\\|lesson\\|bug\\|discovery\\|refactor\\|feature\\|observation\\|decision> "<title>" [--body T] [--files f1,f2]\` |
|
|
161
177
|
|
|
162
178
|
\`maintain\` / \`optimize\` / \`compress\` 见上方「维护 / 管理类工具」;\`maintain --ops\` 取值 \`cleanup,decay,boost,demote_pinned,dedup,purge_stale,rebuild_vectors,vacuum\`,省略时默认 \`cleanup,decay,boost,demote_pinned\`(顺序有意义:demote_pinned 必须在 boost 之后);\`--retain-days\` ∈ [7,365]。
|
|
163
179
|
|
|
164
180
|
## 卸载 / 关闭
|
|
165
181
|
|
|
166
|
-
- \`${
|
|
182
|
+
- \`${CLI} unadopt\`:移除 CLAUDE.md 托管块 + \`.claude/plugin_claude_mem_lite.md\`;
|
|
167
183
|
CLAUDE.md 里你自己的内容(sentinel 之外)不动。
|
|
168
|
-
- 本项目永久关闭自动 adopt:\`${
|
|
184
|
+
- 本项目永久关闭自动 adopt:\`${CLI} adopt --disable\`(\`--enable\` 重新武装)。
|
|
169
185
|
- 全局禁用自动 adopt:环境变量 \`MEM_NO_AUTO_ADOPT=1\`。
|
|
170
186
|
- 关闭版本漂移自动刷新(保留你对托管块的手改):\`CLAUDE_MEM_NO_TEMPLATE_REFRESH=1\`。
|
|
171
187
|
`;
|
package/claudemd.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
//
|
|
17
17
|
// See docs/CLAUDE-MD-STEERING-PLAN.md for rationale + migration.
|
|
18
18
|
|
|
19
|
-
import { readFileSync, existsSync, unlinkSync, mkdirSync, rmdirSync, readdirSync } from 'fs';
|
|
19
|
+
import { readFileSync, existsSync, unlinkSync, mkdirSync, rmdirSync, readdirSync, lstatSync } from 'fs';
|
|
20
20
|
import { atomicWriteFileSync as atomicWrite } from './lib/atomic-write.mjs';
|
|
21
21
|
import { join } from 'path';
|
|
22
22
|
import { createHash } from 'crypto';
|
|
@@ -259,7 +259,21 @@ export function removeManaged(cwd, slug) {
|
|
|
259
259
|
// Delete the now-empty file rather than writing a 0-byte CLAUDE.md, so
|
|
260
260
|
// unadopt fully restores the pre-adopt state — mirrors the emptied-.claude/
|
|
261
261
|
// cleanup below ("unadopt leaves no trace").
|
|
262
|
-
|
|
262
|
+
//
|
|
263
|
+
// UNLESS the path is a SYMLINK (audit R7 P2-2). writeManaged reaches this file
|
|
264
|
+
// through atomicWriteFileSync, which lstats and writes THROUGH a link on purpose —
|
|
265
|
+
// that is the audit 2026-09-02 P0-5 fix, for CLAUDE.md symlinked into a dotfiles
|
|
266
|
+
// repo (chezmoi/stow/yadm). Unlinking here would delete the LINK and orphan the
|
|
267
|
+
// target, i.e. undo that invariant on the removal side. Empty it through the link
|
|
268
|
+
// instead: a 0-byte file is the lesser evil against silently rearranging the
|
|
269
|
+
// user's dotfiles. Only a regular file we can prove is ours to remove gets removed.
|
|
270
|
+
let isLink = false;
|
|
271
|
+
try {
|
|
272
|
+
isLink = lstatSync(p).isSymbolicLink();
|
|
273
|
+
} catch {
|
|
274
|
+
/* raced away → fall through to the unlink attempt, which will no-op */
|
|
275
|
+
}
|
|
276
|
+
if (raw.trim() === '' && !isLink) {
|
|
263
277
|
try {
|
|
264
278
|
unlinkSync(p);
|
|
265
279
|
} catch {
|
package/lib/citation-tracker.mjs
CHANGED
|
@@ -1065,12 +1065,30 @@ const SUBAGENT_INJECT_ID_RE = new RegExp(`^\\s{0,4}#(${OBS_ID_DIGITS})\\s+—`);
|
|
|
1065
1065
|
* Extract observation ids injected into a subagent's PROMPT by pre-agent-inject.js
|
|
1066
1066
|
* (formatSubagentContext). Only the `#NN — ` tag line counts; a body cross-reference is
|
|
1067
1067
|
* ignored. Returns numeric ids.
|
|
1068
|
+
*
|
|
1069
|
+
* TYPE-GATED (audit R7 P1-1). Without `entry.type === 'user'` this scanned assistant text
|
|
1070
|
+
* too, so a subagent that merely QUOTED the block — reviewing this code, summarizing what it
|
|
1071
|
+
* was handed — had those ids counted as injected; and since collectSubagentSurface takes a
|
|
1072
|
+
* per-file `seen ∩ said` intersection, the same quotation credited them as cited, reading
|
|
1073
|
+
* 100% on one self-reference. SURFACE_MATCHERS.task_imperative defends the identical shape by
|
|
1074
|
+
* also gating on the command, for the reason stated in its docblock; this face had nothing.
|
|
1075
|
+
* That mattered beyond metering: `sub.injected` is a citation-decay ENTRY gate (hook.mjs) and
|
|
1076
|
+
* an allow-list for bumpCitationAccess → access_count → the `boost` op → importance.
|
|
1077
|
+
*
|
|
1078
|
+
* The gate value is MEASURED, not assumed (2026-09-05, 11 real subagent transcripts): the
|
|
1079
|
+
* dispatched task prompt is the FIRST entry of each subagent file and carries `type='user'`,
|
|
1080
|
+
* `role='user'`, `isSidechain=true`; the corpus holds assistant ×1036 / attachment ×973 /
|
|
1081
|
+
* user ×668. `tool_result` blocks ride a user entry too, but carry `content` rather than
|
|
1082
|
+
* `text`, so the `x?.text` map below already contributes nothing for them — same reasoning
|
|
1083
|
+
* extractUserTypedIds states for its own scan.
|
|
1084
|
+
*
|
|
1068
1085
|
* @param {string|null|undefined} transcriptPath
|
|
1069
1086
|
* @returns {Set<number>}
|
|
1070
1087
|
*/
|
|
1071
1088
|
export function extractInjectedFromSubagentPrompt(transcriptPath) {
|
|
1072
1089
|
const ids = new Set();
|
|
1073
1090
|
for (const entry of readTranscriptEntries(transcriptPath)) {
|
|
1091
|
+
if (entry.type !== 'user') continue;
|
|
1074
1092
|
const c = entry.message?.content;
|
|
1075
1093
|
const text =
|
|
1076
1094
|
typeof c === 'string'
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.99.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "claude-mem-lite",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.99.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
12
12
|
"better-sqlite3": "^12.11.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.99.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
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|