claude-mem-lite 3.12.1 → 3.14.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-cli.mjs +150 -185
- package/adopt-content.mjs +91 -48
- package/bash-utils.mjs +8 -1
- package/claudemd.mjs +244 -0
- package/commands/adopt.md +43 -36
- package/commands/unadopt.md +25 -11
- package/hook-memory.mjs +26 -3
- package/hook-shared.mjs +13 -7
- package/hook.mjs +27 -26
- package/lib/startup-dashboard.mjs +1 -1
- package/lib/upgrade-banner.mjs +18 -7
- package/nlp.mjs +33 -6
- package/package.json +2 -1
- package/server.mjs +2 -2
- package/source-files.mjs +2 -0
- package/tier.mjs +6 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "claude-mem-lite",
|
|
13
|
-
"version": "3.
|
|
13
|
+
"version": "3.14.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.14.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-cli.mjs
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
|
-
//
|
|
2
|
-
// claude-mem-lite adopt
|
|
3
|
-
// claude-mem-lite unadopt [--all]
|
|
1
|
+
// CLAUDE.md-steering plan (v3.13): CLI handlers for
|
|
2
|
+
// claude-mem-lite adopt [--all] [--force] [--dry-run] [--status] [--disable|--enable]
|
|
3
|
+
// claude-mem-lite unadopt [--all] [--force] [--dry-run] [--status]
|
|
4
4
|
//
|
|
5
|
-
// adopt
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
5
|
+
// adopt = write the managed block into <cwd>/CLAUDE.md + drop
|
|
6
|
+
// <cwd>/.claude/plugin_claude_mem_lite.md, and migrate this project's
|
|
7
|
+
// legacy memory-dir sentinel away.
|
|
8
|
+
// unadopt = remove the CLAUDE.md block + detail doc (and clean any legacy residue).
|
|
9
|
+
//
|
|
10
|
+
// The project path is needed to write CLAUDE.md, but the per-project memdir slug
|
|
11
|
+
// (~/.claude/projects/<encoded>/) is a LOSSY encoding of the real cwd — it cannot
|
|
12
|
+
// be decoded back to a filesystem path. So `--all` cannot adopt arbitrary projects;
|
|
13
|
+
// it is redefined as a legacy-cleanup sweep (strip old memory-dir sentinels across
|
|
14
|
+
// every memdir). New-scheme adoption happens per-project on SessionStart (cwd known).
|
|
11
15
|
|
|
12
16
|
import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync, unlinkSync } from 'fs';
|
|
13
17
|
import { homedir } from 'os';
|
|
14
18
|
import { join } from 'path';
|
|
15
19
|
import {
|
|
16
|
-
memdirPath,
|
|
17
|
-
|
|
18
|
-
isAdopted, hasPluginState, readMemoryIndex,
|
|
19
|
-
UserEditedError, BudgetExceededError,
|
|
20
|
+
memdirPath, removePluginSection, removePluginDoc,
|
|
21
|
+
isAdopted as memdirIsAdopted, hasPluginState,
|
|
20
22
|
} from './memdir.mjs';
|
|
21
23
|
import {
|
|
22
|
-
|
|
24
|
+
writeManaged, removeManaged, isAdopted as claudeMdIsAdopted,
|
|
25
|
+
needsRefresh, migrateLegacyMemoryDir, hasLegacyMemdirSentinel,
|
|
26
|
+
claudeMdPath, detailDocPath,
|
|
27
|
+
} from './claudemd.mjs';
|
|
28
|
+
import {
|
|
29
|
+
PLUGIN_SLUG, CURRENT_SENTINEL_VERSION, buildClaudeMdBlock, getDetailDoc,
|
|
23
30
|
} from './adopt-content.mjs';
|
|
24
31
|
|
|
25
32
|
function log(msg) { console.log(msg); }
|
|
@@ -56,7 +63,8 @@ function hasFlag(args, flag) { return Array.isArray(args) && args.includes(flag)
|
|
|
56
63
|
// `rm ~/.claude-mem-lite/runtime/.auto-adopt-*`. Managed via
|
|
57
64
|
// `claude-mem-lite adopt --disable` / `--enable`. silentAutoAdopt checks it
|
|
58
65
|
// at entry and skips WITHOUT writing the runtime marker, so toggling
|
|
59
|
-
// `--enable` re-arms auto-adopt on the next SessionStart.
|
|
66
|
+
// `--enable` re-arms auto-adopt on the next SessionStart. Kept in the memdir
|
|
67
|
+
// (not the project tree) so it survives `unadopt` cleaning out .claude/.
|
|
60
68
|
const DISABLE_SENTINEL_BASENAME = '.mem-no-auto-adopt';
|
|
61
69
|
|
|
62
70
|
export function disableSentinelPath(memdir) {
|
|
@@ -68,97 +76,98 @@ export function isAutoAdoptDisabled(memdir) {
|
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
/**
|
|
71
|
-
* cmdAdopt — write
|
|
72
|
-
*
|
|
73
|
-
*
|
|
79
|
+
* cmdAdopt — write the CLAUDE.md managed block + detail doc for the current
|
|
80
|
+
* project, and migrate its legacy memory-dir sentinel away.
|
|
81
|
+
*
|
|
82
|
+
* `--all` does NOT adopt every project (their real paths are unrecoverable from
|
|
83
|
+
* the lossy memdir slug) — it sweeps the legacy memory-dir cleanup across all
|
|
84
|
+
* memdirs. `--status`/`--disable`/`--enable` as before.
|
|
74
85
|
*/
|
|
75
86
|
export function cmdAdopt(args = []) {
|
|
76
87
|
if (hasFlag(args, '--status')) return statusAll();
|
|
77
88
|
if (hasFlag(args, '--disable')) return cmdDisable(args);
|
|
78
89
|
if (hasFlag(args, '--enable')) return cmdEnable(args);
|
|
90
|
+
if (hasFlag(args, '--all')) return migrateAll(args);
|
|
79
91
|
|
|
80
|
-
const all = hasFlag(args, '--all');
|
|
81
92
|
const force = hasFlag(args, '--force');
|
|
82
93
|
const dryRun = hasFlag(args, '--dry-run');
|
|
94
|
+
const cwd = detectCwd();
|
|
83
95
|
|
|
84
|
-
|
|
85
|
-
? listAllMemdirs().map((m) => m.memdir)
|
|
86
|
-
: [memdirPath(detectCwd())];
|
|
87
|
-
|
|
88
|
-
if (targets.length === 0) {
|
|
89
|
-
log('[adopt] no memdirs to adopt (use without --all for current project)');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
let created = 0, updated = 0, unchanged = 0, skipped = 0, failed = 0;
|
|
94
|
-
for (const memdir of targets) {
|
|
95
|
-
const r = adoptOne(memdir, { force, dryRun, all });
|
|
96
|
-
if (r.action === 'created') created++;
|
|
97
|
-
else if (r.action === 'updated') updated++;
|
|
98
|
-
else if (r.action === 'unchanged') unchanged++;
|
|
99
|
-
else if (r.action === 'skipped') skipped++;
|
|
100
|
-
else if (r.action === 'dry-run') unchanged++;
|
|
101
|
-
else failed++;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
log('');
|
|
105
|
-
log(`[adopt] ${targets.length} target(s): ${created} created, ${updated} updated, ${unchanged} unchanged, ${skipped} skipped, ${failed} failed`);
|
|
106
|
-
if (failed > 0) process.exitCode = 1;
|
|
96
|
+
adoptOne(cwd, { force, dryRun });
|
|
107
97
|
}
|
|
108
98
|
|
|
109
|
-
function adoptOne(
|
|
110
|
-
const
|
|
99
|
+
function adoptOne(cwd, { force, dryRun }) {
|
|
100
|
+
const block = buildClaudeMdBlock();
|
|
101
|
+
const doc = getDetailDoc();
|
|
111
102
|
const version = CURRENT_SENTINEL_VERSION;
|
|
112
103
|
|
|
113
104
|
if (dryRun) {
|
|
114
|
-
log(`[adopt --dry-run] ${
|
|
115
|
-
log(`
|
|
116
|
-
log(` detail
|
|
105
|
+
log(`[adopt --dry-run] ${cwd}`);
|
|
106
|
+
log(` CLAUDE.md block: ${claudeMdPath(cwd)} (${block.length} chars, ${version})`);
|
|
107
|
+
log(` detail doc: ${detailDocPath(cwd, PLUGIN_SLUG)} (${doc.length} chars)`);
|
|
108
|
+
if (hasLegacyMemdirSentinel(cwd, PLUGIN_SLUG)) {
|
|
109
|
+
log(` legacy migrate: would strip memory-dir sentinel @ ${memdirPath(cwd)}`);
|
|
110
|
+
}
|
|
117
111
|
return { action: 'dry-run' };
|
|
118
112
|
}
|
|
119
113
|
|
|
120
114
|
try {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
const mig = migrateLegacyMemoryDir(cwd, PLUGIN_SLUG, { force });
|
|
116
|
+
const r = writeManaged(cwd, { slug: PLUGIN_SLUG, version, block, doc });
|
|
117
|
+
const migNote = mig.action === 'removed' ? ' (+migrated legacy memdir)' : '';
|
|
118
|
+
log(`[adopt] ${cwd} → ${r.action}${migNote}`);
|
|
124
119
|
return r;
|
|
125
120
|
} catch (e) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return { action: 'skipped' };
|
|
129
|
-
}
|
|
130
|
-
if (e instanceof UserEditedError) {
|
|
131
|
-
log(`[adopt] ${memdir} → refused: ${e.message}`);
|
|
132
|
-
log('[adopt] pass --force to overwrite, or edit/uninstall manually.');
|
|
133
|
-
return { action: 'failed' };
|
|
134
|
-
}
|
|
135
|
-
if (e instanceof BudgetExceededError) {
|
|
136
|
-
log(`[adopt] ${memdir} → failed: ${e.message}`);
|
|
137
|
-
return { action: 'failed' };
|
|
138
|
-
}
|
|
139
|
-
log(`[adopt] ${memdir} → error: ${e.message}`);
|
|
121
|
+
log(`[adopt] ${cwd} → error: ${e.message}`);
|
|
122
|
+
process.exitCode = 1;
|
|
140
123
|
return { action: 'failed' };
|
|
141
124
|
}
|
|
142
125
|
}
|
|
143
126
|
|
|
144
127
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
128
|
+
* migrateAll — `claude-mem-lite adopt --all`: legacy-cleanup sweep. Strips the
|
|
129
|
+
* old memory-dir sentinel + detail doc from every memdir. Does NOT write any
|
|
130
|
+
* CLAUDE.md block (target paths are unrecoverable) — that happens per-project on
|
|
131
|
+
* the next SessionStart. Respects the foreign-content guard unless --force.
|
|
132
|
+
*/
|
|
133
|
+
function migrateAll(args) {
|
|
134
|
+
const force = hasFlag(args, '--force');
|
|
135
|
+
const dryRun = hasFlag(args, '--dry-run');
|
|
136
|
+
const dirs = listAllMemdirs();
|
|
137
|
+
if (dirs.length === 0) { log('[adopt --all] no memdirs found'); return; }
|
|
138
|
+
|
|
139
|
+
let removed = 0, absent = 0, skipped = 0;
|
|
140
|
+
for (const { projectSlug, memdir } of dirs) {
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
const has = memdirIsAdopted(memdir, PLUGIN_SLUG);
|
|
143
|
+
const action = !has ? 'absent'
|
|
144
|
+
: (hasPluginState(memdir, PLUGIN_SLUG) || force) ? 'would-remove' : 'would-skip-foreign';
|
|
145
|
+
log(`[adopt --all --dry-run] ${projectSlug} → ${action}`);
|
|
146
|
+
if (action === 'would-remove') removed++;
|
|
147
|
+
else if (action === 'would-skip-foreign') skipped++;
|
|
148
|
+
else absent++;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const r = removePluginSection(memdir, PLUGIN_SLUG, { force });
|
|
152
|
+
if (r.action === 'removed') { removePluginDoc(memdir, PLUGIN_SLUG); removed++; }
|
|
153
|
+
else if (r.action === 'skipped-foreign') skipped++;
|
|
154
|
+
else absent++;
|
|
155
|
+
}
|
|
156
|
+
log('');
|
|
157
|
+
log(`[adopt --all] legacy memory-dir cleanup over ${dirs.length} project(s): ${removed} cleaned, ${skipped} skipped-foreign, ${absent} none.`);
|
|
158
|
+
log('[adopt --all] CLAUDE.md adoption is per-project — it runs automatically on each project\'s next SessionStart.');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* silentAutoAdopt — SessionStart idempotent sync (migration vehicle).
|
|
160
163
|
*
|
|
161
|
-
*
|
|
164
|
+
* Called every plugin-mode SessionStart (NOT gated by the one-shot marker, so
|
|
165
|
+
* existing users whose marker predates v3.13 still migrate). Order:
|
|
166
|
+
* 1. respect per-project `.mem-no-auto-adopt` opt-out → skip.
|
|
167
|
+
* 2. migrate legacy memory-dir sentinel away (idempotent; no-op once gone).
|
|
168
|
+
* 3. adopt the CLAUDE.md scheme if absent; else refresh if shipped content
|
|
169
|
+
* drifted (unless CLAUDE_MEM_NO_TEMPLATE_REFRESH=1).
|
|
170
|
+
* Silent: never logs, never throws. Returns { ok, action, reason } for debugLog.
|
|
162
171
|
*/
|
|
163
172
|
export function silentAutoAdopt({ cwd, markerDir, markerKey }) {
|
|
164
173
|
const memdir = memdirPath(cwd);
|
|
@@ -166,27 +175,26 @@ export function silentAutoAdopt({ cwd, markerDir, markerKey }) {
|
|
|
166
175
|
if (isAutoAdoptDisabled(memdir)) {
|
|
167
176
|
return { ok: true, action: 'disabled', reason: 'disabled-by-sentinel' };
|
|
168
177
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
migrateLegacyMemoryDir(cwd, PLUGIN_SLUG);
|
|
179
|
+
|
|
180
|
+
const block = buildClaudeMdBlock();
|
|
181
|
+
const doc = getDetailDoc();
|
|
182
|
+
const version = CURRENT_SENTINEL_VERSION;
|
|
183
|
+
|
|
184
|
+
let action = 'already-adopted';
|
|
185
|
+
if (!claudeMdIsAdopted(cwd, PLUGIN_SLUG)) {
|
|
186
|
+
writeManaged(cwd, { slug: PLUGIN_SLUG, version, block, doc });
|
|
187
|
+
action = 'adopted';
|
|
188
|
+
} else if (process.env.CLAUDE_MEM_NO_TEMPLATE_REFRESH !== '1'
|
|
189
|
+
&& needsRefresh(cwd, { slug: PLUGIN_SLUG, version, block, doc })) {
|
|
190
|
+
writeManaged(cwd, { slug: PLUGIN_SLUG, version, block, doc });
|
|
191
|
+
action = 'refreshed';
|
|
172
192
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
version: CURRENT_SENTINEL_VERSION,
|
|
176
|
-
contentLine: getIndexLine(),
|
|
177
|
-
force: false,
|
|
178
|
-
});
|
|
179
|
-
writePluginDoc(memdir, PLUGIN_SLUG, getDetailDoc());
|
|
180
|
-
writeMarker(markerDir, markerKey);
|
|
181
|
-
return { ok: true, action: 'adopted' };
|
|
193
|
+
if (markerDir && markerKey) writeMarker(markerDir, markerKey);
|
|
194
|
+
return { ok: true, action };
|
|
182
195
|
} catch (e) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
try { writeMarker(markerDir, markerKey); } catch { /* marker best-effort */ }
|
|
186
|
-
const reason = e instanceof UserEditedError ? 'user-edited'
|
|
187
|
-
: e instanceof BudgetExceededError ? 'budget-exceeded'
|
|
188
|
-
: 'error';
|
|
189
|
-
return { ok: false, action: 'skipped', reason, err: e };
|
|
196
|
+
try { if (markerDir && markerKey) writeMarker(markerDir, markerKey); } catch { /* best-effort */ }
|
|
197
|
+
return { ok: false, action: 'skipped', reason: 'error', err: e };
|
|
190
198
|
}
|
|
191
199
|
}
|
|
192
200
|
|
|
@@ -202,13 +210,8 @@ export function hasAutoAdoptMarker(markerDir, markerKey) {
|
|
|
202
210
|
|
|
203
211
|
/**
|
|
204
212
|
* cmdDisable — `claude-mem-lite adopt --disable [--all]`.
|
|
205
|
-
*
|
|
206
213
|
* Writes `<memdir>/.mem-no-auto-adopt` so SessionStart auto-adopt skips this
|
|
207
|
-
* project permanently.
|
|
208
|
-
* a no-op. Does NOT remove an existing sentinel — pair with `unadopt` if you
|
|
209
|
-
* want both. The two operations are deliberately separate:
|
|
210
|
-
* - `unadopt` = "remove the contract now"
|
|
211
|
-
* - `adopt --disable` = "and don't auto-write it back"
|
|
214
|
+
* project permanently. Does NOT remove an existing block — pair with `unadopt`.
|
|
212
215
|
*/
|
|
213
216
|
function cmdDisable(args) {
|
|
214
217
|
const all = hasFlag(args, '--all');
|
|
@@ -216,10 +219,7 @@ function cmdDisable(args) {
|
|
|
216
219
|
? listAllMemdirs().map((m) => m.memdir)
|
|
217
220
|
: [memdirPath(detectCwd())];
|
|
218
221
|
|
|
219
|
-
if (targets.length === 0) {
|
|
220
|
-
log('[adopt --disable] no memdirs found');
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
222
|
+
if (targets.length === 0) { log('[adopt --disable] no memdirs found'); return; }
|
|
223
223
|
|
|
224
224
|
let disabled = 0, already = 0;
|
|
225
225
|
for (const memdir of targets) {
|
|
@@ -234,17 +234,13 @@ function cmdDisable(args) {
|
|
|
234
234
|
log(`[adopt --disable] ${memdir} → disabled`);
|
|
235
235
|
disabled++;
|
|
236
236
|
}
|
|
237
|
-
|
|
238
237
|
log('');
|
|
239
238
|
log(`[adopt --disable] ${targets.length} target(s): ${disabled} newly disabled, ${already} already disabled`);
|
|
240
239
|
}
|
|
241
240
|
|
|
242
241
|
/**
|
|
243
|
-
* cmdEnable — `claude-mem-lite adopt --enable [--all]`.
|
|
244
|
-
*
|
|
245
|
-
* Removes the `<memdir>/.mem-no-auto-adopt` sentinel so the next SessionStart
|
|
246
|
-
* can auto-adopt again. Idempotent. Does NOT trigger an immediate adoption —
|
|
247
|
-
* run plain `claude-mem-lite adopt` if you want that now.
|
|
242
|
+
* cmdEnable — `claude-mem-lite adopt --enable [--all]`. Removes the
|
|
243
|
+
* `.mem-no-auto-adopt` sentinel so the next SessionStart can auto-adopt again.
|
|
248
244
|
*/
|
|
249
245
|
function cmdEnable(args) {
|
|
250
246
|
const all = hasFlag(args, '--all');
|
|
@@ -252,10 +248,7 @@ function cmdEnable(args) {
|
|
|
252
248
|
? listAllMemdirs().map((m) => m.memdir)
|
|
253
249
|
: [memdirPath(detectCwd())];
|
|
254
250
|
|
|
255
|
-
if (targets.length === 0) {
|
|
256
|
-
log('[adopt --enable] no memdirs found');
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
251
|
+
if (targets.length === 0) { log('[adopt --enable] no memdirs found'); return; }
|
|
259
252
|
|
|
260
253
|
let enabled = 0, absent = 0;
|
|
261
254
|
for (const memdir of targets) {
|
|
@@ -269,56 +262,48 @@ function cmdEnable(args) {
|
|
|
269
262
|
log(`[adopt --enable] ${memdir} → enabled`);
|
|
270
263
|
enabled++;
|
|
271
264
|
}
|
|
272
|
-
|
|
273
265
|
log('');
|
|
274
266
|
log(`[adopt --enable] ${targets.length} target(s): ${enabled} re-enabled, ${absent} not-disabled`);
|
|
275
267
|
}
|
|
276
268
|
|
|
269
|
+
/**
|
|
270
|
+
* statusAll — report the current project's new-scheme adoption, plus a sweep of
|
|
271
|
+
* how many memdirs still carry the legacy sentinel (i.e. await migration).
|
|
272
|
+
*/
|
|
277
273
|
function statusAll() {
|
|
274
|
+
const cwd = detectCwd();
|
|
275
|
+
const adoptedHere = claudeMdIsAdopted(cwd, PLUGIN_SLUG);
|
|
276
|
+
log('[adopt --status] current project:');
|
|
277
|
+
log(` cwd: ${cwd}`);
|
|
278
|
+
log(` CLAUDE.md: ${adoptedHere ? `✓ adopted (${CURRENT_SENTINEL_VERSION})` : '✗ not adopted'}`);
|
|
279
|
+
if (hasLegacyMemdirSentinel(cwd, PLUGIN_SLUG)) {
|
|
280
|
+
log(' legacy: ⚠ memory-dir sentinel still present (migrates on next SessionStart, or run `adopt`)');
|
|
281
|
+
}
|
|
282
|
+
|
|
278
283
|
const dirs = listAllMemdirs();
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const isAdoptedHere = isAdopted(memdir, PLUGIN_SLUG);
|
|
284
|
-
const isDisabledHere = isAutoAdoptDisabled(memdir);
|
|
285
|
-
if (isAdoptedHere) {
|
|
286
|
-
const idx = readMemoryIndex(memdir, PLUGIN_SLUG);
|
|
287
|
-
const suffix = isDisabledHere ? ' [auto-adopt disabled]' : '';
|
|
288
|
-
log(` ✓ ${projectSlug} (${idx.version})${suffix}`);
|
|
289
|
-
adopted++;
|
|
290
|
-
if (isDisabledHere) disabled++;
|
|
291
|
-
} else if (isDisabledHere) {
|
|
292
|
-
log(` ✗ ${projectSlug} (auto-adopt disabled, no sentinel)`);
|
|
293
|
-
disabled++;
|
|
294
|
-
}
|
|
284
|
+
let legacy = 0, disabled = 0;
|
|
285
|
+
for (const { memdir } of dirs) {
|
|
286
|
+
if (memdirIsAdopted(memdir, PLUGIN_SLUG)) legacy++;
|
|
287
|
+
if (isAutoAdoptDisabled(memdir)) disabled++;
|
|
295
288
|
}
|
|
296
289
|
log('');
|
|
297
|
-
log(`[adopt --status] ${
|
|
290
|
+
log(`[adopt --status] scanned ${dirs.length} memdir(s): ${legacy} with legacy sentinel (await migration), ${disabled} auto-adopt-disabled.`);
|
|
291
|
+
if (legacy > 0) log('[adopt --status] run `claude-mem-lite adopt --all` to sweep legacy memory-dir sentinels now.');
|
|
298
292
|
|
|
299
|
-
// Gating snapshot — helps debug "why didn't auto-adopt fire?"
|
|
300
293
|
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT ? 'set' : 'unset';
|
|
301
294
|
const noAutoAdopt = process.env.MEM_NO_AUTO_ADOPT === '1' ? '1 (opt-out)' : 'unset';
|
|
302
295
|
log('');
|
|
303
|
-
log('Auto-adopt gates (next SessionStart
|
|
304
|
-
log(` CLAUDE_PLUGIN_ROOT = ${pluginRoot} (
|
|
296
|
+
log('Auto-adopt gates (next SessionStart fires only if these pass):');
|
|
297
|
+
log(` CLAUDE_PLUGIN_ROOT = ${pluginRoot} (any install path is consent; gate is the per-project opt-out below)`);
|
|
305
298
|
log(` MEM_NO_AUTO_ADOPT = ${noAutoAdopt} (global escape hatch)`);
|
|
306
299
|
log('Per-project opt-out: `claude-mem-lite adopt --disable` (run --enable to re-arm).');
|
|
307
300
|
}
|
|
308
301
|
|
|
309
302
|
/**
|
|
310
|
-
* cmdUnadopt —
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* --all Operate on every memdir under ~/.claude/projects/*\/memory/
|
|
315
|
-
* --status Read-only: list currently-adopted memdirs (mirrors `adopt --status`).
|
|
316
|
-
* --dry-run Preview what would be removed; no filesystem writes.
|
|
317
|
-
*
|
|
318
|
-
* Pre-fix history: unrecognized flags (e.g. `--status` extrapolated from `adopt --status`,
|
|
319
|
-
* or `--dry-run` extrapolated from `adopt --dry-run`) were silently ignored and the
|
|
320
|
-
* destructive default ran anyway, removing the sentinel block when the user expected
|
|
321
|
-
* a read-only probe.
|
|
303
|
+
* cmdUnadopt — remove the CLAUDE.md managed block + detail doc for the current
|
|
304
|
+
* project, and clean any legacy memory-dir residue. `--all` sweeps the legacy
|
|
305
|
+
* memory-dir cleanup across every memdir (CLAUDE.md blocks for other projects
|
|
306
|
+
* can't be located from the lossy slug). Idempotent: exit code stays 0.
|
|
322
307
|
*/
|
|
323
308
|
export function cmdUnadopt(args = []) {
|
|
324
309
|
if (hasFlag(args, '--status')) return statusAll();
|
|
@@ -326,41 +311,21 @@ export function cmdUnadopt(args = []) {
|
|
|
326
311
|
const all = hasFlag(args, '--all');
|
|
327
312
|
const dryRun = hasFlag(args, '--dry-run');
|
|
328
313
|
const force = hasFlag(args, '--force');
|
|
329
|
-
const targets = all
|
|
330
|
-
? listAllMemdirs().map((m) => m.memdir)
|
|
331
|
-
: [memdirPath(detectCwd())];
|
|
332
314
|
|
|
333
|
-
if (
|
|
334
|
-
log('[unadopt] no memdirs found');
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
315
|
+
if (all) return migrateAll(['--all', ...(force ? ['--force'] : []), ...(dryRun ? ['--dry-run'] : [])]);
|
|
337
316
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
log(`[unadopt --dry-run] ${memdir} → ${action}`);
|
|
347
|
-
if (action === 'would-remove') removed++;
|
|
348
|
-
else if (action === 'would-skip-foreign') skipped++;
|
|
349
|
-
else absent++;
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
const r = removePluginSection(memdir, PLUGIN_SLUG, { force });
|
|
353
|
-
if (r.action === 'removed') { removePluginDoc(memdir, PLUGIN_SLUG); removed++; }
|
|
354
|
-
else if (r.action === 'skipped-foreign') skipped++;
|
|
355
|
-
else absent++;
|
|
356
|
-
log(`[unadopt] ${memdir} → ${r.action}`);
|
|
317
|
+
const cwd = detectCwd();
|
|
318
|
+
if (dryRun) {
|
|
319
|
+
const blockState = claudeMdIsAdopted(cwd, PLUGIN_SLUG) ? 'would-remove CLAUDE.md block + detail doc' : 'no CLAUDE.md block';
|
|
320
|
+
const legacy = hasLegacyMemdirSentinel(cwd, PLUGIN_SLUG) ? 'would-clean legacy memory-dir sentinel' : 'no legacy residue';
|
|
321
|
+
log(`[unadopt --dry-run] ${cwd}`);
|
|
322
|
+
log(` ${blockState}`);
|
|
323
|
+
log(` ${legacy}`);
|
|
324
|
+
return;
|
|
357
325
|
}
|
|
358
326
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
log('');
|
|
364
|
-
const verb = dryRun ? 'would remove' : 'removed';
|
|
365
|
-
log(`[unadopt${dryRun ? ' --dry-run' : ''}] ${targets.length} target(s): ${removed} ${verb}, ${skipped} skipped-foreign, ${absent} absent`);
|
|
327
|
+
const r = removeManaged(cwd, PLUGIN_SLUG);
|
|
328
|
+
const mig = migrateLegacyMemoryDir(cwd, PLUGIN_SLUG, { force });
|
|
329
|
+
const migNote = mig.action === 'removed' ? ' (+cleaned legacy memdir)' : '';
|
|
330
|
+
log(`[unadopt] ${cwd} → ${r.action}${migNote}`);
|
|
366
331
|
}
|