claude-mem-lite 2.54.0 → 2.55.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/hook-update.mjs +23 -9
- package/install.mjs +34 -32
- package/package.json +1 -1
- package/scripts/setup.sh +48 -0
- package/source-files.mjs +20 -0
package/hook-update.mjs
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// Skips in dev mode (symlinked installs). Silent on network failure.
|
|
4
4
|
|
|
5
5
|
import { execSync, execFileSync } from 'node:child_process';
|
|
6
|
-
import { readFileSync, writeFileSync, copyFileSync, readdirSync, existsSync, lstatSync, mkdirSync, rmSync, renameSync } from 'node:fs';
|
|
6
|
+
import { readFileSync, writeFileSync, copyFileSync, cpSync, readdirSync, existsSync, lstatSync, mkdirSync, rmSync, renameSync } from 'node:fs';
|
|
7
7
|
import { join, dirname } from 'node:path';
|
|
8
8
|
import { tmpdir, homedir } from 'node:os';
|
|
9
9
|
import { DB_DIR } from './schema.mjs';
|
|
10
10
|
import { debugCatch, debugLog } from './utils.mjs';
|
|
11
|
-
import { SOURCE_FILES } from './source-files.mjs';
|
|
11
|
+
import { SOURCE_FILES, HOOK_SCRIPT_FILES } from './source-files.mjs';
|
|
12
12
|
|
|
13
13
|
// ── Configuration ──────────────────────────────────────────
|
|
14
14
|
const GITHUB_REPO = 'sdsrss/claude-mem-lite';
|
|
@@ -328,16 +328,30 @@ function copyReleaseIntoStaging(sourceDir, stagingDir) {
|
|
|
328
328
|
copied++;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
// scripts/ is curated to HOOK_SCRIPT_FILES — settings.json hook commands
|
|
332
|
+
// resolve only to these 5 files, and plugin mode does not consume this
|
|
333
|
+
// directory at all. Pre-v2.55 used cpSync({recursive:true}) which silently
|
|
334
|
+
// shipped dev-only files (mock-claude.mjs, extract-repos.mjs, p0-forward-probe.mjs…)
|
|
335
|
+
// from the GitHub Releases tarball into every user's data dir.
|
|
336
|
+
const stagingScripts = join(stagingDir, 'scripts');
|
|
337
|
+
const sourceScripts = join(sourceDir, 'scripts');
|
|
338
|
+
if (existsSync(sourceScripts)) {
|
|
339
|
+
mkdirSync(stagingScripts, { recursive: true });
|
|
340
|
+
for (const name of HOOK_SCRIPT_FILES) {
|
|
341
|
+
const src = join(sourceScripts, name);
|
|
342
|
+
if (existsSync(src)) copyFileSync(src, join(stagingScripts, name));
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
345
|
|
|
346
|
+
// registry/ stays recursive — preinstalled.json is the only current entry
|
|
347
|
+
// but the directory is consumed wholesale by the registry indexer and may
|
|
348
|
+
// grow subtrees. Pre-v2.55 readdirSync+copyFileSync would EISDIR-throw on
|
|
349
|
+
// any subdir and silently roll back the entire update.
|
|
350
|
+
const sourceRegistry = join(sourceDir, 'registry');
|
|
351
|
+
if (existsSync(sourceRegistry)) {
|
|
352
|
+
cpSync(sourceRegistry, join(stagingDir, 'registry'), { recursive: true });
|
|
353
|
+
}
|
|
354
|
+
|
|
341
355
|
const stagedScripts = join(stagingDir, 'scripts');
|
|
342
356
|
if (existsSync(stagedScripts)) {
|
|
343
357
|
for (const sf of readdirSync(stagedScripts).filter(n => n.endsWith('.sh'))) {
|
package/install.mjs
CHANGED
|
@@ -29,23 +29,13 @@ import { createRequire } from 'module';
|
|
|
29
29
|
|
|
30
30
|
import { RESOURCE_METADATA } from './install-metadata.mjs';
|
|
31
31
|
import { scanPluginCacheHookPollution } from './plugin-cache-guard.mjs';
|
|
32
|
-
import { SOURCE_FILES } from './source-files.mjs';
|
|
32
|
+
import { SOURCE_FILES, HOOK_SCRIPT_FILES } from './source-files.mjs';
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* dropped pre-tool-recall.js + pre-skill-bridge.js — every fresh install left
|
|
40
|
-
* settings.json pointing at non-existent files).
|
|
41
|
-
*/
|
|
42
|
-
export const HOOK_SCRIPT_FILES = [
|
|
43
|
-
'post-tool-use.sh',
|
|
44
|
-
'user-prompt-search.js',
|
|
45
|
-
'prompt-search-utils.mjs',
|
|
46
|
-
'pre-tool-recall.js',
|
|
47
|
-
'pre-skill-bridge.js',
|
|
48
|
-
];
|
|
34
|
+
// Re-export for backward compatibility — tests/install-hook-scripts.test.mjs
|
|
35
|
+
// and any external consumers still import HOOK_SCRIPT_FILES from install.mjs.
|
|
36
|
+
// The constant itself moved to source-files.mjs in v2.55 so hook-update.mjs
|
|
37
|
+
// can share it without a static cycle.
|
|
38
|
+
export { HOOK_SCRIPT_FILES };
|
|
49
39
|
|
|
50
40
|
export function copyHookScripts(srcDir, destDir) {
|
|
51
41
|
for (const name of HOOK_SCRIPT_FILES) {
|
|
@@ -349,12 +339,10 @@ async function install() {
|
|
|
349
339
|
if (existsSync(join(PROJECT_DIR, 'registry'))) {
|
|
350
340
|
symlinkSync(join(PROJECT_DIR, 'registry'), regLink);
|
|
351
341
|
}
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
symlinkSync(join(PROJECT_DIR, 'commands'), cmdLink);
|
|
357
|
-
}
|
|
342
|
+
// commands/ is intentionally NOT linked: Claude Code reads slash commands
|
|
343
|
+
// from the plugin cache (~/.claude/plugins/cache/<mp>/<plugin>/<ver>/commands/)
|
|
344
|
+
// or user-level ~/.claude/commands/, never from ~/.claude-mem-lite/commands/.
|
|
345
|
+
// Pre-v2.55 maintained a symlink/copy here that had no consumers.
|
|
358
346
|
ok('Symlinks created in ~/.claude-mem-lite/ → dev dir');
|
|
359
347
|
} else {
|
|
360
348
|
log('Installing to ~/.claude-mem-lite/...');
|
|
@@ -375,15 +363,7 @@ async function install() {
|
|
|
375
363
|
copyHookScripts(join(PROJECT_DIR, 'scripts'), scriptsDir);
|
|
376
364
|
// Ensure bash script is executable
|
|
377
365
|
try { execFileSync('chmod', ['+x', join(scriptsDir, 'post-tool-use.sh')], { stdio: 'pipe' }); } catch {}
|
|
378
|
-
//
|
|
379
|
-
const commandsDir = join(DATA_DIR, 'commands');
|
|
380
|
-
if (!existsSync(commandsDir)) mkdirSync(commandsDir, { recursive: true });
|
|
381
|
-
const commandsSrc = join(PROJECT_DIR, 'commands');
|
|
382
|
-
if (existsSync(commandsSrc)) {
|
|
383
|
-
for (const f of readdirSync(commandsSrc).filter(f => f.endsWith('.md'))) {
|
|
384
|
-
copyFileSync(join(commandsSrc, f), join(commandsDir, f));
|
|
385
|
-
}
|
|
386
|
-
}
|
|
366
|
+
// commands/ is intentionally NOT copied — see dev-mode branch above.
|
|
387
367
|
// Copy registry manifest
|
|
388
368
|
const registryDir = join(DATA_DIR, 'registry');
|
|
389
369
|
if (!existsSync(registryDir)) mkdirSync(registryDir, { recursive: true });
|
|
@@ -1614,9 +1594,10 @@ function syncVersions() {
|
|
|
1614
1594
|
const marketJson = JSON.parse(readFileSync(marketJsonPath, 'utf8'));
|
|
1615
1595
|
const plugin = marketJson.plugins?.[0];
|
|
1616
1596
|
if (plugin && plugin.version !== version) {
|
|
1597
|
+
const prev = plugin.version;
|
|
1617
1598
|
plugin.version = version;
|
|
1618
1599
|
writeFileSync(marketJsonPath, JSON.stringify(marketJson, null, 2) + '\n');
|
|
1619
|
-
ok(`marketplace.json: ${
|
|
1600
|
+
ok(`marketplace.json: ${prev} → ${version}`);
|
|
1620
1601
|
} else if (plugin) {
|
|
1621
1602
|
ok(`marketplace.json: already ${version}`);
|
|
1622
1603
|
}
|
|
@@ -1624,6 +1605,27 @@ function syncVersions() {
|
|
|
1624
1605
|
warn('marketplace.json not found');
|
|
1625
1606
|
}
|
|
1626
1607
|
|
|
1608
|
+
// Sync CLAUDE.md `**Version**: x.y.z` line — install-e2e asserts this
|
|
1609
|
+
// matches package.json so omitting it here would break CI on every release.
|
|
1610
|
+
const claudeMdPath = join(PROJECT_DIR, 'CLAUDE.md');
|
|
1611
|
+
if (existsSync(claudeMdPath)) {
|
|
1612
|
+
const orig = readFileSync(claudeMdPath, 'utf8');
|
|
1613
|
+
const versionLine = /^- \*\*Version\*\*: .+$/m;
|
|
1614
|
+
if (versionLine.test(orig)) {
|
|
1615
|
+
const patched = orig.replace(versionLine, `- **Version**: ${version}`);
|
|
1616
|
+
if (patched !== orig) {
|
|
1617
|
+
writeFileSync(claudeMdPath, patched);
|
|
1618
|
+
ok(`CLAUDE.md: → ${version}`);
|
|
1619
|
+
} else {
|
|
1620
|
+
ok(`CLAUDE.md: already ${version}`);
|
|
1621
|
+
}
|
|
1622
|
+
} else {
|
|
1623
|
+
warn('CLAUDE.md: `**Version**:` line not found — skipped');
|
|
1624
|
+
}
|
|
1625
|
+
} else {
|
|
1626
|
+
warn('CLAUDE.md not found');
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1627
1629
|
console.log('');
|
|
1628
1630
|
}
|
|
1629
1631
|
|
package/package.json
CHANGED
package/scripts/setup.sh
CHANGED
|
@@ -136,5 +136,53 @@ if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]]; then
|
|
|
136
136
|
fi
|
|
137
137
|
fi
|
|
138
138
|
|
|
139
|
+
# 9. Residue detection (plugin mode only): warn once if legacy direct-install
|
|
140
|
+
# hooks remain in ~/.claude/settings.json. A user who installed via global
|
|
141
|
+
# `claude-mem-lite install` and later switched to the marketplace plugin
|
|
142
|
+
# will run every hook twice (direct settings.json hooks AND plugin hooks)
|
|
143
|
+
# until they run `claude-mem-lite uninstall` to clear the settings.json
|
|
144
|
+
# entries. /plugin uninstall does not touch settings.json.
|
|
145
|
+
RESIDUE_MARKER="$DATA_DIR/runtime/.residue-warned-v2.55"
|
|
146
|
+
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && ! -f "$RESIDUE_MARKER" ]]; then
|
|
147
|
+
SETTINGS="$HOME/.claude/settings.json"
|
|
148
|
+
if [[ -f "$SETTINGS" ]]; then
|
|
149
|
+
SETTINGS_PATH="$SETTINGS" node -e '
|
|
150
|
+
const fs = require("fs");
|
|
151
|
+
try {
|
|
152
|
+
const raw = fs.readFileSync(process.env.SETTINGS_PATH, "utf8");
|
|
153
|
+
const data = JSON.parse(raw);
|
|
154
|
+
const hooks = data.hooks || {};
|
|
155
|
+
const events = Object.keys(hooks);
|
|
156
|
+
const found = [];
|
|
157
|
+
for (const ev of events) {
|
|
158
|
+
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
159
|
+
for (const entry of list) {
|
|
160
|
+
const inner = Array.isArray(entry?.hooks) ? entry.hooks : [];
|
|
161
|
+
for (const h of inner) {
|
|
162
|
+
const cmd = String(h?.command || "");
|
|
163
|
+
if (cmd.includes(".claude-mem-lite/") || cmd.includes("claude-mem-lite/scripts") || cmd.includes("claude-mem-lite/hook.mjs")) {
|
|
164
|
+
found.push(ev);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (found.length) {
|
|
171
|
+
process.stderr.write("\n");
|
|
172
|
+
process.stderr.write("\x1b[33m⚠\x1b[0m Legacy direct-install hooks detected in " + process.env.SETTINGS_PATH + "\n");
|
|
173
|
+
process.stderr.write(" Events with stale entries: " + [...new Set(found)].join(", ") + "\n");
|
|
174
|
+
process.stderr.write(" These will fire alongside plugin hooks (each tool call runs twice).\n");
|
|
175
|
+
process.stderr.write(" Fix: run \x1b[1mclaude-mem-lite uninstall\x1b[0m to clear settings.json,\n");
|
|
176
|
+
process.stderr.write(" then keep using the plugin install. (One-time warning.)\n\n");
|
|
177
|
+
process.exit(2);
|
|
178
|
+
}
|
|
179
|
+
} catch {}
|
|
180
|
+
' || true
|
|
181
|
+
fi
|
|
182
|
+
# Mark the warning as shown regardless of result — silence is fine if no
|
|
183
|
+
# residue, and the warning above is one-shot per data-dir.
|
|
184
|
+
touch "$RESIDUE_MARKER"
|
|
185
|
+
fi
|
|
186
|
+
|
|
139
187
|
log_ok "claude-mem-lite ready"
|
|
140
188
|
exit 0
|
package/source-files.mjs
CHANGED
|
@@ -53,3 +53,23 @@ export const SOURCE_FILES = [
|
|
|
53
53
|
'adopt-content.mjs',
|
|
54
54
|
'adopt-cli.mjs',
|
|
55
55
|
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hook scripts that direct-install (non-plugin) mode must materialize under
|
|
59
|
+
* ~/.claude-mem-lite/scripts/ — settings.json hook commands resolve to these
|
|
60
|
+
* absolute paths. Plugin mode does not consume this directory (it runs scripts
|
|
61
|
+
* from ${CLAUDE_PLUGIN_ROOT} instead).
|
|
62
|
+
*
|
|
63
|
+
* Single source of truth for both install.mjs (initial install) and
|
|
64
|
+
* hook-update.mjs (auto-update): pre-v2.55 hook-update copied the entire
|
|
65
|
+
* scripts/ tree from the GitHub Releases tarball, which silently shipped
|
|
66
|
+
* dev-only files (mock-claude.mjs, extract-repos.mjs, p0-forward-probe.mjs…)
|
|
67
|
+
* to every user's data dir on the first auto-update.
|
|
68
|
+
*/
|
|
69
|
+
export const HOOK_SCRIPT_FILES = [
|
|
70
|
+
'post-tool-use.sh',
|
|
71
|
+
'user-prompt-search.js',
|
|
72
|
+
'prompt-search-utils.mjs',
|
|
73
|
+
'pre-tool-recall.js',
|
|
74
|
+
'pre-skill-bridge.js',
|
|
75
|
+
];
|