claude-mem-lite 2.32.2 → 2.32.4
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 -0
- package/README.zh-CN.md +8 -0
- package/cli.mjs +1 -1
- package/commands/adopt.md +16 -0
- package/memdir.mjs +21 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -279,6 +279,15 @@ Slash commands `/adopt` and `/unadopt` wrap the same CLI.
|
|
|
279
279
|
/ `Key Context` sections. `#ID` references and the `Recent` table still fire
|
|
280
280
|
so `mem_get` remains reachable.
|
|
281
281
|
|
|
282
|
+
**When does it take effect?**
|
|
283
|
+
- The MEMORY.md sentinel and the hook-layer trim (`File Lessons` / `Key Context` /
|
|
284
|
+
lesson suffix) apply on the **next SessionStart** (any new Claude Code session
|
|
285
|
+
in the adopted project).
|
|
286
|
+
- The MCP server instructions are built once at server boot and MCP has no
|
|
287
|
+
"push" protocol — the `WHEN TO USE` / `Decision rules` trim only applies
|
|
288
|
+
after Claude Code restarts and re-spawns the mem MCP server. A single
|
|
289
|
+
`/exit` + fresh session is enough. Same caveat applies to `unadopt`.
|
|
290
|
+
|
|
282
291
|
**Safety:**
|
|
283
292
|
- Hash-guarded: editing the sentinel body yourself blocks automatic rewrites
|
|
284
293
|
unless you pass `--force`.
|
package/README.zh-CN.md
CHANGED
|
@@ -264,6 +264,14 @@ Slash 命令 `/adopt` 和 `/unadopt` 是上述 CLI 的包装。
|
|
|
264
264
|
SessionStart 注入去掉 `File Lessons` / `Key Context`。`#ID` 引用与 `Recent`
|
|
265
265
|
表保留,`mem_get` 仍可随时展开。
|
|
266
266
|
|
|
267
|
+
**什么时候生效?**
|
|
268
|
+
- MEMORY.md sentinel 和 hook 层瘦身(`File Lessons` / `Key Context` / lesson
|
|
269
|
+
后缀)**下一次 SessionStart** 生效(adopt 的项目下任一新会话)。
|
|
270
|
+
- MCP server instructions 是**服务启动时构建一次**,MCP 协议无 "push" 机制,
|
|
271
|
+
所以 `WHEN TO USE` / `Decision rules` 两段的瘦身**只在 Claude Code 重启后**
|
|
272
|
+
才生效(mem MCP 服务被重新 spawn)。`/exit` 一次再开新会话即可。`unadopt`
|
|
273
|
+
同理。
|
|
274
|
+
|
|
267
275
|
**安全性:**
|
|
268
276
|
- Hash 守护:你手动改了 sentinel 段 → 下一次 adopt 报 `UserEditedError`,
|
|
269
277
|
除非显式 `--force`。
|
package/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const CLI_COMMANDS = new Set(['search', 'recent', 'recall', 'get', 'timeline', 'save', 'stats', 'context', 'browse', 'delete', 'update', 'export', 'compress', 'maintain', 'optimize', 'fts-check', 'registry', 'import', 'enrich', 'activity', 'help']);
|
|
2
|
+
const CLI_COMMANDS = new Set(['search', 'recent', 'recall', 'get', 'timeline', 'save', 'stats', 'context', 'browse', 'delete', 'update', 'export', 'compress', 'maintain', 'optimize', 'fts-check', 'registry', 'import', 'enrich', 'activity', 'adopt', 'unadopt', 'help']);
|
|
3
3
|
const INSTALL_COMMANDS = new Set(['install', 'uninstall', 'status', 'doctor', 'cleanup', 'cleanup-hooks', 'self-update', 'release']);
|
|
4
4
|
|
|
5
5
|
const cmd = process.argv[2];
|
package/commands/adopt.md
CHANGED
|
@@ -41,4 +41,20 @@ Code versions. Post-adopt the MCP `WHEN TO USE` section + the `File Lessons` /
|
|
|
41
41
|
`Key Context` sections auto-trim since the sentinel line already carries the
|
|
42
42
|
triggers at higher authority.
|
|
43
43
|
|
|
44
|
+
## Restart required for MCP trim to take effect
|
|
45
|
+
|
|
46
|
+
The MCP server builds its instructions once at server boot and the protocol
|
|
47
|
+
has no way to push updated instructions to an already-connected Claude Code
|
|
48
|
+
session. After running `adopt`:
|
|
49
|
+
|
|
50
|
+
- The **MEMORY.md sentinel** appears on the **next SessionStart** automatically.
|
|
51
|
+
- Hook-layer trim (`File Lessons` / `Key Context` / lesson suffix) applies
|
|
52
|
+
on the next SessionStart.
|
|
53
|
+
- MCP-instructions trim (`WHEN TO USE` / `Decision rules` sections) only
|
|
54
|
+
takes effect after Claude Code itself restarts (or at least re-attaches
|
|
55
|
+
the mem MCP server). If you still see the verbose MCP instructions after
|
|
56
|
+
adopt, a `/exit` + fresh session is enough.
|
|
57
|
+
|
|
58
|
+
Same caveat applies in reverse for `/unadopt`.
|
|
59
|
+
|
|
44
60
|
!claude-mem-lite adopt $ARGUMENTS
|
package/memdir.mjs
CHANGED
|
@@ -17,6 +17,18 @@ import { createHash } from 'crypto';
|
|
|
17
17
|
const MEMORY_LINE_BUDGET = 180;
|
|
18
18
|
const SECTION_HEADER = '## 插件契约';
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* POSIX-accurate line count. `str.split('\n').length` overcounts by 1 when the
|
|
22
|
+
* file ends with a trailing newline (almost always true for markdown), which
|
|
23
|
+
* caused an off-by-one budget trip at the 180-line boundary (code review
|
|
24
|
+
* finding for v2.32.3).
|
|
25
|
+
*/
|
|
26
|
+
function countLines(raw) {
|
|
27
|
+
if (raw.length === 0) return 0;
|
|
28
|
+
const nl = (raw.match(/\n/g) || []).length;
|
|
29
|
+
return nl + (raw.endsWith('\n') ? 0 : 1);
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
export class UserEditedError extends Error {
|
|
21
33
|
constructor(message) { super(message); this.name = 'UserEditedError'; }
|
|
22
34
|
}
|
|
@@ -123,7 +135,7 @@ export function readMemoryIndex(memdir, slug) {
|
|
|
123
135
|
}
|
|
124
136
|
const raw = readFileSync(path, 'utf8');
|
|
125
137
|
const m = raw.match(sentinelRegex(slug));
|
|
126
|
-
const lineCount = raw
|
|
138
|
+
const lineCount = countLines(raw);
|
|
127
139
|
if (!m) return { exists: true, raw, lineCount, section: null, body: null, version: null };
|
|
128
140
|
return { exists: true, raw, lineCount, section: m[0], body: m[2], version: m[1] };
|
|
129
141
|
}
|
|
@@ -159,7 +171,7 @@ export function writePluginSection(memdir, { slug, version, contentLine, force =
|
|
|
159
171
|
|
|
160
172
|
if (!match) {
|
|
161
173
|
// Insert: enforce the 180-line budget so we never get truncated at 200.
|
|
162
|
-
const existingLines = raw
|
|
174
|
+
const existingLines = countLines(raw);
|
|
163
175
|
if (existingLines > MEMORY_LINE_BUDGET) {
|
|
164
176
|
throw new BudgetExceededError(
|
|
165
177
|
`MEMORY.md has ${existingLines} lines (> ${MEMORY_LINE_BUDGET}); refuse to add new sentinel section for ${slug}.`,
|
|
@@ -223,7 +235,13 @@ export function removePluginSection(memdir, slug) {
|
|
|
223
235
|
let end = match.index + match[0].length;
|
|
224
236
|
if (raw[end] === '\n') end++;
|
|
225
237
|
if (start > 0 && raw.slice(0, start).endsWith('\n\n')) start--;
|
|
226
|
-
|
|
238
|
+
let next = raw.slice(0, start) + raw.slice(end);
|
|
239
|
+
// Edge case (code review v2.32.3): when the sentinel was the first content
|
|
240
|
+
// (e.g. two invited-memory plugins coexist and we remove the earlier one),
|
|
241
|
+
// the tail can still start with a stranded blank line / doubled newlines.
|
|
242
|
+
// Normalize leading whitespace and collapse any ≥3 consecutive newlines
|
|
243
|
+
// so the remaining content looks hand-authored.
|
|
244
|
+
next = next.replace(/^\s+/, '').replace(/\n{3,}/g, '\n\n');
|
|
227
245
|
atomicWrite(path, next);
|
|
228
246
|
return { action: 'removed' };
|
|
229
247
|
}
|