claude-mem-lite 2.32.1 → 2.32.2
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/commands/bug.md +57 -0
- package/commands/lesson.md +53 -0
- package/hook-optimize.mjs +724 -0
- package/lib/activity.mjs +114 -0
- package/lib/doctor-benchmark.mjs +153 -0
- package/lib/git-state.mjs +38 -0
- package/lib/plan-reader.mjs +43 -0
- package/lib/startup-dashboard.mjs +113 -0
- package/lib/task-reader.mjs +149 -0
- package/package.json +11 -1
- package/plugin-cache-guard.mjs +77 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Plugin cache hook sentinel.
|
|
2
|
+
//
|
|
3
|
+
// Claude Code runtime reads plugin hooks from
|
|
4
|
+
// ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/hooks/hooks.json
|
|
5
|
+
// NOT from the marketplace source (~/.claude/plugins/marketplaces/<mp>/hooks/hooks.json).
|
|
6
|
+
//
|
|
7
|
+
// When install.mjs writes mem hooks directly into ~/.claude/settings.json, any stale
|
|
8
|
+
// cache hooks.json (e.g. left behind by a previous marketplace install or an auto-update
|
|
9
|
+
// that re-populates cache) causes double hook registration: one fires from settings.json,
|
|
10
|
+
// another from cache. This module detects and heals that state.
|
|
11
|
+
//
|
|
12
|
+
// Safe-by-default: clearPluginCacheHooks is only called when hasInstallManagedHooks()
|
|
13
|
+
// returns true, so plugin-only users (cache is the sole registration) are not affected.
|
|
14
|
+
|
|
15
|
+
import { readFileSync, writeFileSync, readdirSync, existsSync } from 'fs';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import { homedir } from 'os';
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_MARKETPLACE = 'sdsrss';
|
|
20
|
+
export const DEFAULT_PLUGIN = 'claude-mem-lite';
|
|
21
|
+
|
|
22
|
+
function cacheBaseFor(opts) {
|
|
23
|
+
const home = opts?.home || homedir();
|
|
24
|
+
const mp = opts?.marketplace || DEFAULT_MARKETPLACE;
|
|
25
|
+
const plugin = opts?.plugin || DEFAULT_PLUGIN;
|
|
26
|
+
return join(home, '.claude', 'plugins', 'cache', mp, plugin);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function scanPluginCacheHookPollution(opts) {
|
|
30
|
+
const base = cacheBaseFor(opts);
|
|
31
|
+
if (!existsSync(base)) return [];
|
|
32
|
+
const polluted = [];
|
|
33
|
+
for (const ver of readdirSync(base)) {
|
|
34
|
+
const p = join(base, ver, 'hooks', 'hooks.json');
|
|
35
|
+
if (!existsSync(p)) continue;
|
|
36
|
+
try {
|
|
37
|
+
const h = JSON.parse(readFileSync(p, 'utf8'));
|
|
38
|
+
if (h.hooks && Object.keys(h.hooks).length > 0) polluted.push(ver);
|
|
39
|
+
} catch { /* ignore unreadable cache entries */ }
|
|
40
|
+
}
|
|
41
|
+
return polluted.sort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function clearPluginCacheHooks(opts) {
|
|
45
|
+
const base = cacheBaseFor(opts);
|
|
46
|
+
if (!existsSync(base)) return [];
|
|
47
|
+
const plugin = opts?.plugin || DEFAULT_PLUGIN;
|
|
48
|
+
const reason = opts?.reason || 'Auto-cleared to prevent duplicate hook registration';
|
|
49
|
+
const cleared = [];
|
|
50
|
+
for (const ver of readdirSync(base)) {
|
|
51
|
+
const p = join(base, ver, 'hooks', 'hooks.json');
|
|
52
|
+
if (!existsSync(p)) continue;
|
|
53
|
+
try {
|
|
54
|
+
const h = JSON.parse(readFileSync(p, 'utf8'));
|
|
55
|
+
if (!h.hooks || Object.keys(h.hooks).length === 0) continue;
|
|
56
|
+
writeFileSync(p, JSON.stringify({
|
|
57
|
+
description: h.description || `${plugin} hooks`,
|
|
58
|
+
_note: `${reason} (cache ver: ${ver})`,
|
|
59
|
+
hooks: {},
|
|
60
|
+
}, null, 2) + '\n');
|
|
61
|
+
cleared.push(ver);
|
|
62
|
+
} catch { /* ignore unwritable cache entries */ }
|
|
63
|
+
}
|
|
64
|
+
return cleared.sort();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function hasInstallManagedHooks(opts) {
|
|
68
|
+
const home = opts?.home || homedir();
|
|
69
|
+
const plugin = opts?.plugin || DEFAULT_PLUGIN;
|
|
70
|
+
const settingsPath = join(home, '.claude', 'settings.json');
|
|
71
|
+
if (!existsSync(settingsPath)) return false;
|
|
72
|
+
try {
|
|
73
|
+
const s = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
74
|
+
const serialized = JSON.stringify(s.hooks || {});
|
|
75
|
+
return serialized.includes(`.${plugin}/`) || serialized.includes(`/${plugin}/`);
|
|
76
|
+
} catch { return false; }
|
|
77
|
+
}
|