claude-mem-lite 2.31.0 → 2.31.1
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/hook.mjs +16 -0
- package/install.mjs +44 -5
- package/package.json +1 -1
package/hook.mjs
CHANGED
|
@@ -32,6 +32,7 @@ import { searchRelevantMemories } from './hook-memory.mjs';
|
|
|
32
32
|
import { buildAndSaveHandoff, detectContinuationIntent, renderHandoffInjection, extractUnfinishedSummary } from './hook-handoff.mjs';
|
|
33
33
|
import { checkForUpdate } from './hook-update.mjs';
|
|
34
34
|
import { handleLLMOptimize } from './hook-optimize.mjs';
|
|
35
|
+
import { clearPluginCacheHooks, hasInstallManagedHooks } from './plugin-cache-guard.mjs';
|
|
35
36
|
import { SKIP_TOOLS, SKIP_PREFIXES } from './skip-tools.mjs';
|
|
36
37
|
import { getVocabulary } from './tfidf.mjs';
|
|
37
38
|
|
|
@@ -397,6 +398,21 @@ async function handleStop() {
|
|
|
397
398
|
// ─── SessionStart Handler + CLAUDE.md Persistence (Tier 1 A, E) ─────────────
|
|
398
399
|
|
|
399
400
|
async function handleSessionStart() {
|
|
401
|
+
// Plugin cache self-heal: Claude Code auto-updates the marketplace plugin can
|
|
402
|
+
// re-populate cache/<ver>/hooks/hooks.json, reintroducing duplicate hook
|
|
403
|
+
// registration alongside install.mjs-managed settings.json entries. Silently
|
|
404
|
+
// clear — gated by hasInstallManagedHooks to avoid breaking plugin-only users.
|
|
405
|
+
try {
|
|
406
|
+
if (hasInstallManagedHooks()) {
|
|
407
|
+
const cleared = clearPluginCacheHooks({
|
|
408
|
+
reason: 'Auto-healed by hook.mjs session-start — install.mjs-managed hooks active in settings.json',
|
|
409
|
+
});
|
|
410
|
+
if (cleared.length > 0) {
|
|
411
|
+
debugLog('DEBUG', 'session-start', `auto-healed stale plugin cache hooks.json in version(s): ${cleared.join(', ')}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} catch (e) { debugCatch(e, 'session-start-cache-heal'); }
|
|
415
|
+
|
|
400
416
|
// Read CC real session_id from hook stdin — used to scope handoff rows so parallel
|
|
401
417
|
// sessions for the same project don't clobber each other (see docs/bug.txt).
|
|
402
418
|
let ccSessionId = null;
|
package/install.mjs
CHANGED
|
@@ -26,6 +26,7 @@ const PLUGIN_KEY = `claude-mem-lite@${MARKETPLACE_KEY}`;
|
|
|
26
26
|
const NPM_INSTALL_CMD = 'npm install --omit=dev --no-audit --no-fund';
|
|
27
27
|
|
|
28
28
|
import { RESOURCE_METADATA } from './install-metadata.mjs';
|
|
29
|
+
import { scanPluginCacheHookPollution } from './plugin-cache-guard.mjs';
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Derive invocation_name from resource name when metadata doesn't provide one.
|
|
@@ -205,6 +206,7 @@ async function install() {
|
|
|
205
206
|
'cli.mjs', 'server.mjs', 'server-internals.mjs', 'tool-schemas.mjs',
|
|
206
207
|
'hook.mjs', 'hook-shared.mjs', 'hook-llm.mjs', 'hook-memory.mjs', 'skip-tools.mjs',
|
|
207
208
|
'hook-semaphore.mjs', 'hook-episode.mjs', 'hook-context.mjs', 'hook-handoff.mjs', 'hook-update.mjs', 'hook-optimize.mjs',
|
|
209
|
+
'plugin-cache-guard.mjs',
|
|
208
210
|
'haiku-client.mjs', 'utils.mjs', 'schema.mjs', 'package.json', 'package-lock.json', 'skill.md',
|
|
209
211
|
'registry.mjs', 'registry-scanner.mjs', 'registry-indexer.mjs',
|
|
210
212
|
'registry-retriever.mjs', 'resource-discovery.mjs',
|
|
@@ -401,18 +403,43 @@ async function install() {
|
|
|
401
403
|
}
|
|
402
404
|
} catch (e) { warn(`Marketplace hooks dedup: ${e.message}`); }
|
|
403
405
|
|
|
404
|
-
// Sync launch.mjs to plugin cache — ensures MCP server loads dev code via symlink detection
|
|
406
|
+
// Sync launch.mjs to plugin cache — ensures MCP server loads dev code via symlink detection.
|
|
407
|
+
// ALSO clear cached hooks.json in every version dir — Claude Code runtime reads hooks from
|
|
408
|
+
// ~/.claude/plugins/cache/<mp>/<plugin>/<ver>/hooks/hooks.json, NOT from the marketplace source.
|
|
409
|
+
// Clearing only the marketplace source (above) leaves stale cache copies that double-register
|
|
410
|
+
// hooks alongside install.mjs-written settings.json entries.
|
|
405
411
|
try {
|
|
406
412
|
const cacheBase = join(homedir(), '.claude', 'plugins', 'cache', MARKETPLACE_KEY, 'claude-mem-lite');
|
|
407
413
|
if (existsSync(cacheBase)) {
|
|
408
414
|
const srcLaunch = join(PROJECT_DIR, 'scripts', 'launch.mjs');
|
|
415
|
+
let clearedHooks = 0;
|
|
409
416
|
for (const ver of readdirSync(cacheBase)) {
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
417
|
+
const verDir = join(cacheBase, ver);
|
|
418
|
+
|
|
419
|
+
// Sync launch.mjs
|
|
420
|
+
if (existsSync(join(verDir, 'scripts'))) {
|
|
421
|
+
try { copyFileSync(srcLaunch, join(verDir, 'scripts', 'launch.mjs')); } catch {}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Clear cached hooks.json (runtime reads here, not marketplace source)
|
|
425
|
+
const cachedHooksPath = join(verDir, 'hooks', 'hooks.json');
|
|
426
|
+
if (existsSync(cachedHooksPath)) {
|
|
427
|
+
try {
|
|
428
|
+
const h = JSON.parse(readFileSync(cachedHooksPath, 'utf8'));
|
|
429
|
+
if (h.hooks && Object.keys(h.hooks).length > 0) {
|
|
430
|
+
writeFileSync(cachedHooksPath, JSON.stringify({
|
|
431
|
+
description: h.description || 'claude-mem-lite hooks',
|
|
432
|
+
_note: `Hooks managed by install.mjs in settings.json — cache hooks.json cleared to prevent duplicate registration (cache ver: ${ver})`,
|
|
433
|
+
hooks: {}
|
|
434
|
+
}, null, 2) + '\n');
|
|
435
|
+
clearedHooks++;
|
|
436
|
+
}
|
|
437
|
+
} catch { /* silent — never block install on one bad cache entry */ }
|
|
413
438
|
}
|
|
414
439
|
}
|
|
415
|
-
|
|
440
|
+
const parts = ['launch.mjs synced (dev mode MCP routing)'];
|
|
441
|
+
if (clearedHooks > 0) parts.push(`${clearedHooks} stale hooks.json cleared`);
|
|
442
|
+
ok(`Plugin cache: ${parts.join('; ')}`);
|
|
416
443
|
}
|
|
417
444
|
} catch (e) { warn(`Plugin cache sync: ${e.message}`); }
|
|
418
445
|
}
|
|
@@ -962,6 +989,18 @@ async function status() {
|
|
|
962
989
|
fail('Hooks: not configured');
|
|
963
990
|
}
|
|
964
991
|
|
|
992
|
+
// Plugin cache pollution: populated hooks.json in cache AND install.mjs-managed
|
|
993
|
+
// settings.json hooks → runtime registers both → duplicate firing.
|
|
994
|
+
const polluted = scanPluginCacheHookPollution();
|
|
995
|
+
if (polluted.length > 0 && hasHooks) {
|
|
996
|
+
fail(`Plugin cache: stale hooks.json in version(s) ${polluted.join(', ')} — duplicate firing alongside settings.json (run 'install' to auto-clear)`);
|
|
997
|
+
} else if (polluted.length > 0) {
|
|
998
|
+
// plugin-only mode (no settings.json hooks) — cache hooks.json is the sole source, expected
|
|
999
|
+
ok(`Plugin cache: ${polluted.length} version(s) with hooks.json (plugin-only mode)`);
|
|
1000
|
+
} else if (pluginEnabled || hasHooks) {
|
|
1001
|
+
ok('Plugin cache: no stale hooks.json (no duplicate firing)');
|
|
1002
|
+
}
|
|
1003
|
+
|
|
965
1004
|
// Database
|
|
966
1005
|
if (existsSync(DB_PATH)) {
|
|
967
1006
|
try {
|