coding-friend-cli 1.36.4 → 1.37.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/README.md +1 -1
- package/dist/{chunk-XHP3EBR3.js → chunk-676YCW6T.js} +17 -1
- package/dist/{chunk-56YJWGAN.js → chunk-6S7352JG.js} +60 -47
- package/dist/{chunk-N4WZWRCI.js → chunk-DP6DFQ4G.js} +83 -35
- package/dist/{chunk-K4WSC62G.js → chunk-PI4P34KF.js} +39 -1
- package/dist/{chunk-AK6RMCAC.js → chunk-W6D3J5DX.js} +39 -27
- package/dist/{clean-Q4VU662V.js → clean-WEYQZB34.js} +2 -1
- package/dist/{config-CTTHWJH5.js → config-ZMR2AOBB.js} +5 -5
- package/dist/{host-NCJMUSME.js → host-SSRI4JZV.js} +2 -2
- package/dist/index.js +27 -25
- package/dist/{init-UABKVDVT.js → init-6MFQWPOP.js} +24 -9
- package/dist/{install-R2HDM3N4.js → install-37NN4CQH.js} +3 -1
- package/dist/{learn-K64AUUFB.js → learn-OPH3CI67.js} +1 -1
- package/dist/{mcp-OMQFSJP4.js → mcp-DWKVMNC7.js} +21 -21
- package/dist/{mcp-serve-3FEPFVVQ.js → mcp-serve-5GODJ4DJ.js} +10 -1
- package/dist/{memory-Y6GNALG3.js → memory-TRDLADUM.js} +5 -5
- package/dist/{session-Q2DLQPYP.js → session-S4WKA4P5.js} +2 -1
- package/dist/{status-ML4XEDYL.js → status-YZEOUX46.js} +11 -8
- package/dist/{uninstall-ASLHT3MH.js → uninstall-AVA3J554.js} +14 -0
- package/dist/{update-DIOH45TE.js → update-Q3ACCK4Z.js} +3 -1
- package/lib/cf-memory/src/__tests__/sqlite-lazy-db.test.ts +213 -0
- package/lib/cf-memory/src/__tests__/tier.test.ts +22 -1
- package/lib/cf-memory/src/backends/sqlite/index.ts +142 -85
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Everything else (every skill, every agent, every hook except the three OPTIONAL
|
|
|
17
17
|
- **`node` not found** — install Node.js 20+ from <https://nodejs.org> (the CLI declares `engines.node >= 20`; older versions will refuse to install).
|
|
18
18
|
- **`EACCES` on global install** — set a user-writable global prefix: `npm config set prefix ~/.npm-global` and add `~/.npm-global/bin` to your `PATH`.
|
|
19
19
|
- **`cf` not on PATH after install** — verify with `npm root -g` and ensure that directory's `bin/` is in your `PATH`.
|
|
20
|
-
- **MCP server not appearing in Claude Code** — after install, run `cf mcp` to register
|
|
20
|
+
- **MCP server not appearing in Claude Code** — after install, run `cf mcp` to register both Learn and Memory MCP at user scope, then restart Claude Code.
|
|
21
21
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
ensureShellCompletion
|
|
7
7
|
} from "./chunk-667NMPN4.js";
|
|
8
|
+
import {
|
|
9
|
+
isMemoryMcpRegistered,
|
|
10
|
+
registerMemoryMcp,
|
|
11
|
+
removeMemoryMcpEntry
|
|
12
|
+
} from "./chunk-DP6DFQ4G.js";
|
|
8
13
|
import {
|
|
9
14
|
resolveScope
|
|
10
15
|
} from "./chunk-IKLMHJH6.js";
|
|
@@ -249,9 +254,20 @@ async function updateCommand(opts) {
|
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
if (doCli) {
|
|
252
|
-
const { refreshMemoryAfterUpdate } = await import("./memory-
|
|
257
|
+
const { refreshMemoryAfterUpdate } = await import("./memory-TRDLADUM.js");
|
|
253
258
|
await refreshMemoryAfterUpdate();
|
|
254
259
|
}
|
|
260
|
+
if (!isMemoryMcpRegistered()) {
|
|
261
|
+
registerMemoryMcp();
|
|
262
|
+
}
|
|
263
|
+
const migrationResult = removeMemoryMcpEntry();
|
|
264
|
+
if (migrationResult.removed) {
|
|
265
|
+
if (migrationResult.fileDeleted) {
|
|
266
|
+
log.success("Removed legacy project-scope coding-friend-memory from .mcp.json (file deleted \u2014 was empty).");
|
|
267
|
+
} else {
|
|
268
|
+
log.success("Removed legacy project-scope coding-friend-memory from .mcp.json");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
255
271
|
if (doStatusline) {
|
|
256
272
|
const updatedVersion = ensureStatusline();
|
|
257
273
|
if (updatedVersion) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
isMemoryMcpRegistered
|
|
3
|
+
} from "./chunk-DP6DFQ4G.js";
|
|
4
4
|
import {
|
|
5
5
|
readJson
|
|
6
6
|
} from "./chunk-5UVDWG5L.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { existsSync } from "fs";
|
|
13
13
|
import { join } from "path";
|
|
14
14
|
import chalk from "chalk";
|
|
15
|
-
function warnStaleMcpJson(
|
|
15
|
+
function warnStaleMcpJson() {
|
|
16
16
|
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
17
17
|
if (!existsSync(localMcpPath)) return;
|
|
18
18
|
const mcpJson = readJson(localMcpPath);
|
|
@@ -23,39 +23,35 @@ function warnStaleMcpJson(memoryDir) {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const state = detectMemoryMcpState(mcpJson, existsSync);
|
|
26
|
-
if (state.kind === "stale"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
);
|
|
57
|
-
console.log();
|
|
58
|
-
}
|
|
26
|
+
if (state.kind === "stale") {
|
|
27
|
+
console.log(
|
|
28
|
+
chalk.yellow(`\u26A0 Stale MCP config detected in .mcp.json`)
|
|
29
|
+
);
|
|
30
|
+
console.log(chalk.dim(` Path no longer exists: ${state.path}`));
|
|
31
|
+
console.log(
|
|
32
|
+
chalk.dim(
|
|
33
|
+
` This project-scope coding-friend-memory entry shadows the global (user-scope) memory server.`
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
console.log(
|
|
37
|
+
chalk.dim(` Run "cf update" to remove it automatically.`)
|
|
38
|
+
);
|
|
39
|
+
console.log();
|
|
40
|
+
} else if (state.kind === "legacy-valid") {
|
|
41
|
+
console.log(
|
|
42
|
+
chalk.cyan(
|
|
43
|
+
`\u2139 .mcp.json has a project-scope coding-friend-memory entry.`
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
console.log(
|
|
47
|
+
chalk.dim(
|
|
48
|
+
` This shadows the global (user-scope) memory server (Claude Code precedence: local > project > user).`
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
console.log(
|
|
52
|
+
chalk.dim(` Run "cf update" to remove it automatically.`)
|
|
53
|
+
);
|
|
54
|
+
console.log();
|
|
59
55
|
}
|
|
60
56
|
}
|
|
61
57
|
function detectMemoryMcpState(mcpJson, pathExists) {
|
|
@@ -102,24 +98,41 @@ function printHealthSection(result) {
|
|
|
102
98
|
}
|
|
103
99
|
async function checkMemoryMcpHealth(deps) {
|
|
104
100
|
const checks = [];
|
|
101
|
+
const checkRegistered = deps.isRegistered ?? isMemoryMcpRegistered;
|
|
102
|
+
const registered = checkRegistered();
|
|
103
|
+
checks.push({
|
|
104
|
+
label: "Registered (user scope)",
|
|
105
|
+
ok: registered,
|
|
106
|
+
...registered ? {} : {
|
|
107
|
+
detail: "coding-friend-memory not registered",
|
|
108
|
+
fix: 'Run "cf mcp" to register'
|
|
109
|
+
}
|
|
110
|
+
});
|
|
105
111
|
const mcpJson = deps.readMcpJson();
|
|
106
112
|
const state = detectMemoryMcpState(mcpJson, deps.pathExists);
|
|
107
|
-
if (state.kind === "
|
|
108
|
-
checks.push({
|
|
109
|
-
|
|
113
|
+
if (state.kind === "stale") {
|
|
114
|
+
checks.push({
|
|
115
|
+
label: "Project .mcp.json",
|
|
116
|
+
ok: false,
|
|
117
|
+
warn: true,
|
|
118
|
+
detail: `Stale entry shadows user-scope server (path missing: ${state.path})`,
|
|
119
|
+
fix: 'Run "cf update" to remove it automatically'
|
|
120
|
+
});
|
|
121
|
+
} else if (state.kind === "legacy-valid") {
|
|
110
122
|
checks.push({
|
|
111
|
-
label: "
|
|
123
|
+
label: "Project .mcp.json",
|
|
112
124
|
ok: false,
|
|
113
|
-
|
|
114
|
-
|
|
125
|
+
warn: true,
|
|
126
|
+
detail: `Legacy absolute-path entry shadows user-scope server`,
|
|
127
|
+
fix: 'Run "cf update" to migrate to the user-scope registration'
|
|
115
128
|
});
|
|
116
|
-
} else {
|
|
117
|
-
const detail = state.kind === "stale" ? `Stale path: ${state.path}` : `Absolute path (legacy): ${state.path}`;
|
|
129
|
+
} else if (state.kind === "npx") {
|
|
118
130
|
checks.push({
|
|
119
|
-
label: "
|
|
131
|
+
label: "Project .mcp.json",
|
|
120
132
|
ok: false,
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
warn: true,
|
|
134
|
+
detail: "Project-scope npx entry shadows user-scope server",
|
|
135
|
+
fix: 'Run "cf update" to remove it automatically'
|
|
123
136
|
});
|
|
124
137
|
}
|
|
125
138
|
const distExists = deps.pathExists(deps.memoryDistPath);
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
resolveMemoryDir
|
|
3
|
-
} from "./chunk-K4WSC62G.js";
|
|
4
1
|
import {
|
|
5
2
|
getLibPath
|
|
6
3
|
} from "./chunk-RZRT7NGT.js";
|
|
@@ -10,6 +7,9 @@ import {
|
|
|
10
7
|
formatScopeLabel,
|
|
11
8
|
injectBackChoice
|
|
12
9
|
} from "./chunk-IKLMHJH6.js";
|
|
10
|
+
import {
|
|
11
|
+
runWithStderr
|
|
12
|
+
} from "./chunk-EVGXUDX4.js";
|
|
13
13
|
import {
|
|
14
14
|
mergeJson,
|
|
15
15
|
readJson,
|
|
@@ -24,10 +24,44 @@ import {
|
|
|
24
24
|
log
|
|
25
25
|
} from "./chunk-NREZK463.js";
|
|
26
26
|
|
|
27
|
+
// src/lib/memory-mcp-register.ts
|
|
28
|
+
var MCP_NAME = "coding-friend-memory";
|
|
29
|
+
function registerMemoryMcp() {
|
|
30
|
+
const result = runWithStderr("claude", [
|
|
31
|
+
"mcp",
|
|
32
|
+
"add",
|
|
33
|
+
"--scope",
|
|
34
|
+
"user",
|
|
35
|
+
MCP_NAME,
|
|
36
|
+
"--",
|
|
37
|
+
"npx",
|
|
38
|
+
"-y",
|
|
39
|
+
"coding-friend-cli",
|
|
40
|
+
"mcp-serve"
|
|
41
|
+
]);
|
|
42
|
+
if (result.exitCode !== 0) {
|
|
43
|
+
const stderr = result.stderr ?? "";
|
|
44
|
+
if (stderr.includes("ENOENT") || stderr.includes("command not found")) {
|
|
45
|
+
log.warn(
|
|
46
|
+
`claude CLI not found \u2014 add MCP manually:
|
|
47
|
+
claude mcp add --scope user ${MCP_NAME} -- npx -y coding-friend-cli mcp-serve`
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
log.warn(`Could not register MCP: ${stderr || "unknown error"}`);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
function isMemoryMcpRegistered() {
|
|
57
|
+
const result = runWithStderr("claude", ["mcp", "get", MCP_NAME]);
|
|
58
|
+
return result.exitCode === 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
27
61
|
// src/lib/memory-prompts.ts
|
|
28
62
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
63
|
+
import { rmSync } from "fs";
|
|
29
64
|
import chalk from "chalk";
|
|
30
|
-
import { homedir } from "os";
|
|
31
65
|
import { join } from "path";
|
|
32
66
|
function getMemoryFieldScope(field, globalCfg, localCfg) {
|
|
33
67
|
const localSection = localCfg?.memory;
|
|
@@ -216,54 +250,66 @@ async function editMemoryEmbedding(globalCfg, localCfg) {
|
|
|
216
250
|
if (ollamaUrl) embedding.ollamaUrl = ollamaUrl;
|
|
217
251
|
writeMemoryField(scope, "embedding", embedding);
|
|
218
252
|
}
|
|
219
|
-
function
|
|
253
|
+
function removeMemoryMcpEntry() {
|
|
220
254
|
const mcpPath = join(process.cwd(), ".mcp.json");
|
|
221
|
-
const existing = readJson(mcpPath)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
255
|
+
const existing = readJson(mcpPath);
|
|
256
|
+
if (existing == null) {
|
|
257
|
+
return { removed: false, fileDeleted: false };
|
|
258
|
+
}
|
|
259
|
+
const servers = existing.mcpServers;
|
|
260
|
+
if (servers == null || typeof servers !== "object" || Array.isArray(servers) || !("coding-friend-memory" in servers)) {
|
|
261
|
+
return { removed: false, fileDeleted: false };
|
|
262
|
+
}
|
|
263
|
+
delete servers["coding-friend-memory"];
|
|
264
|
+
if (Object.keys(servers).length === 0) {
|
|
265
|
+
delete existing.mcpServers;
|
|
266
|
+
}
|
|
267
|
+
if (Object.keys(existing).length === 0) {
|
|
268
|
+
rmSync(mcpPath, { force: true });
|
|
269
|
+
return { removed: true, fileDeleted: true };
|
|
270
|
+
}
|
|
271
|
+
writeJson(mcpPath, existing);
|
|
272
|
+
return { removed: true, fileDeleted: false };
|
|
234
273
|
}
|
|
235
|
-
function getMemoryMcpStatus() {
|
|
274
|
+
function getMemoryMcpStatus(checkIsRegistered = isMemoryMcpRegistered) {
|
|
236
275
|
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
237
276
|
const localMcp = readJson(localMcpPath);
|
|
238
277
|
const localServers = localMcp?.mcpServers;
|
|
278
|
+
const userScope = checkIsRegistered();
|
|
279
|
+
if (userScope) {
|
|
280
|
+
const hasShadow = localServers != null && "coding-friend-memory" in localServers;
|
|
281
|
+
return {
|
|
282
|
+
configured: true,
|
|
283
|
+
scope: hasShadow ? "local" : "user",
|
|
284
|
+
userScope: true
|
|
285
|
+
};
|
|
286
|
+
}
|
|
239
287
|
if (localServers != null && "coding-friend-memory" in localServers) {
|
|
240
|
-
return { configured: true, scope: "local" };
|
|
288
|
+
return { configured: true, scope: "local", userScope: false };
|
|
241
289
|
}
|
|
242
290
|
const globalMcpPath = join(claudeConfigDir(), ".mcp.json");
|
|
243
291
|
const globalMcp = readJson(globalMcpPath);
|
|
244
292
|
const globalServers = globalMcp?.mcpServers;
|
|
245
293
|
if (globalServers != null && "coding-friend-memory" in globalServers) {
|
|
246
|
-
return { configured: true, scope: "global" };
|
|
294
|
+
return { configured: true, scope: "global", userScope: false };
|
|
247
295
|
}
|
|
248
|
-
return { configured: false, scope: null };
|
|
296
|
+
return { configured: false, scope: null, userScope: false };
|
|
249
297
|
}
|
|
250
298
|
async function editMemoryMcp() {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const globalMcpDisplay = join(claudeConfigDir(), ".mcp.json").replace(
|
|
254
|
-
homedir(),
|
|
255
|
-
"~"
|
|
256
|
-
);
|
|
257
|
-
const label = status.scope === "local" ? chalk.green("configured") + chalk.dim(" (local .mcp.json)") : chalk.green("configured") + chalk.dim(` (global ${globalMcpDisplay})`) + " " + chalk.yellow("\u26A0 only works for one project");
|
|
258
|
-
log.info(`MCP: ${label}`);
|
|
299
|
+
if (isMemoryMcpRegistered()) {
|
|
300
|
+
log.info(`MCP: ${chalk.green("registered")} (user scope)`);
|
|
259
301
|
const reconfigure = await confirm({
|
|
260
|
-
message: "
|
|
302
|
+
message: "Re-register Memory MCP (user scope)?",
|
|
261
303
|
default: false
|
|
262
304
|
});
|
|
263
305
|
if (!reconfigure) return;
|
|
264
306
|
}
|
|
265
|
-
const
|
|
266
|
-
|
|
307
|
+
const ok = registerMemoryMcp();
|
|
308
|
+
if (ok) {
|
|
309
|
+
log.success(
|
|
310
|
+
"Registered coding-friend-memory (user scope). Restart Claude Code to activate."
|
|
311
|
+
);
|
|
312
|
+
}
|
|
267
313
|
}
|
|
268
314
|
async function memoryConfigMenu(opts) {
|
|
269
315
|
while (true) {
|
|
@@ -303,7 +349,7 @@ async function memoryConfigMenu(opts) {
|
|
|
303
349
|
);
|
|
304
350
|
const embeddingLabel = embeddingVal?.provider ? embeddingVal.model ? `${embeddingVal.model} (${embeddingVal.provider})` : embeddingVal.provider : "";
|
|
305
351
|
const mcpStatus = getMemoryMcpStatus();
|
|
306
|
-
const mcpLabel = mcpStatus.
|
|
352
|
+
const mcpLabel = mcpStatus.userScope ? mcpStatus.scope === "local" ? chalk.green("registered") + chalk.dim(" (user scope)") + " " + chalk.yellow("\u26A0 shadow") : chalk.green("registered") + chalk.dim(" (user scope)") : mcpStatus.configured ? mcpStatus.scope === "local" ? chalk.yellow("configured") + chalk.dim(" (.mcp.json)") : chalk.yellow("configured") + chalk.dim(" (global)") + " " + chalk.yellow("\u26A0") : chalk.dim("not registered");
|
|
307
353
|
const choice = await select({
|
|
308
354
|
message: "Memory settings:",
|
|
309
355
|
choices: injectBackChoice(
|
|
@@ -354,7 +400,9 @@ async function memoryConfigMenu(opts) {
|
|
|
354
400
|
}
|
|
355
401
|
|
|
356
402
|
export {
|
|
357
|
-
|
|
403
|
+
registerMemoryMcp,
|
|
404
|
+
isMemoryMcpRegistered,
|
|
405
|
+
removeMemoryMcpEntry,
|
|
358
406
|
getMemoryMcpStatus,
|
|
359
407
|
memoryConfigMenu
|
|
360
408
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CONFIG
|
|
3
3
|
} from "./chunk-3WIZA5OZ.js";
|
|
4
|
+
import {
|
|
5
|
+
run
|
|
6
|
+
} from "./chunk-EVGXUDX4.js";
|
|
4
7
|
import {
|
|
5
8
|
readJson
|
|
6
9
|
} from "./chunk-5UVDWG5L.js";
|
|
@@ -14,7 +17,31 @@ import {
|
|
|
14
17
|
} from "./chunk-NREZK463.js";
|
|
15
18
|
|
|
16
19
|
// src/lib/config.ts
|
|
20
|
+
import { resolve as resolve2, isAbsolute } from "path";
|
|
17
21
|
import { z } from "zod";
|
|
22
|
+
|
|
23
|
+
// src/lib/project-root.ts
|
|
24
|
+
import { resolve } from "path";
|
|
25
|
+
function resolveMainRepoRoot(baseDir) {
|
|
26
|
+
const gitCommonDir = run("git", ["-C", baseDir, "rev-parse", "--git-common-dir"]);
|
|
27
|
+
if (!gitCommonDir) {
|
|
28
|
+
return resolve(baseDir);
|
|
29
|
+
}
|
|
30
|
+
if (gitCommonDir === ".git") {
|
|
31
|
+
return resolve(baseDir);
|
|
32
|
+
}
|
|
33
|
+
if (gitCommonDir.endsWith("/.git")) {
|
|
34
|
+
const candidate = gitCommonDir.slice(0, -5);
|
|
35
|
+
return resolve(baseDir, candidate);
|
|
36
|
+
}
|
|
37
|
+
const topLevel = run("git", ["-C", baseDir, "rev-parse", "--show-toplevel"]);
|
|
38
|
+
if (topLevel) {
|
|
39
|
+
return resolve(baseDir, topLevel);
|
|
40
|
+
}
|
|
41
|
+
return resolve(baseDir);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/lib/config.ts
|
|
18
45
|
function deepMerge(base, override) {
|
|
19
46
|
const result = { ...base };
|
|
20
47
|
for (const key of Object.keys(override)) {
|
|
@@ -213,10 +240,21 @@ function resolveMemoryDir(explicitPath) {
|
|
|
213
240
|
}
|
|
214
241
|
return resolvePath("docs/memory");
|
|
215
242
|
}
|
|
243
|
+
function resolveProjectMemoryDir(baseDir) {
|
|
244
|
+
const root = resolveMainRepoRoot(baseDir);
|
|
245
|
+
const configPath = resolve2(root, ".coding-friend", "config.json");
|
|
246
|
+
const config = readJson(configPath);
|
|
247
|
+
const docsDir = config?.docsDir ?? "docs";
|
|
248
|
+
if (isAbsolute(docsDir)) {
|
|
249
|
+
return resolve2(docsDir, "memory");
|
|
250
|
+
}
|
|
251
|
+
return resolve2(root, docsDir, "memory");
|
|
252
|
+
}
|
|
216
253
|
|
|
217
254
|
export {
|
|
218
255
|
sanitizeRawConfig,
|
|
219
256
|
loadConfig,
|
|
220
257
|
resolveLearnDir,
|
|
221
|
-
resolveMemoryDir
|
|
258
|
+
resolveMemoryDir,
|
|
259
|
+
resolveProjectMemoryDir
|
|
222
260
|
};
|
|
@@ -2,16 +2,17 @@ import {
|
|
|
2
2
|
checkMemoryMcpHealth,
|
|
3
3
|
printHealthSection,
|
|
4
4
|
warnStaleMcpJson
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
getMemoryMcpStatus,
|
|
8
|
-
memoryConfigMenu,
|
|
9
|
-
writeMemoryMcpEntry
|
|
10
|
-
} from "./chunk-N4WZWRCI.js";
|
|
5
|
+
} from "./chunk-6S7352JG.js";
|
|
11
6
|
import {
|
|
12
7
|
loadConfig,
|
|
13
8
|
resolveMemoryDir
|
|
14
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PI4P34KF.js";
|
|
10
|
+
import {
|
|
11
|
+
getMemoryMcpStatus,
|
|
12
|
+
isMemoryMcpRegistered,
|
|
13
|
+
memoryConfigMenu,
|
|
14
|
+
registerMemoryMcp
|
|
15
|
+
} from "./chunk-DP6DFQ4G.js";
|
|
15
16
|
import {
|
|
16
17
|
getLibPath
|
|
17
18
|
} from "./chunk-RZRT7NGT.js";
|
|
@@ -107,7 +108,11 @@ async function refreshMemoryAfterUpdate() {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
function printMemoryMcpConfig(memoryDir) {
|
|
110
|
-
console.log(
|
|
111
|
+
console.log(
|
|
112
|
+
chalk.dim(
|
|
113
|
+
"For non-Claude-Code MCP clients only (Claude Code is already set up via the user-scope registration above) \u2014 add this to that client's config:"
|
|
114
|
+
)
|
|
115
|
+
);
|
|
111
116
|
console.log();
|
|
112
117
|
console.log(`{
|
|
113
118
|
"mcpServers": {
|
|
@@ -127,8 +132,8 @@ function printMemoryMcpConfig(memoryDir) {
|
|
|
127
132
|
"Available tools & resources: https://cf.dinhanhthi.com/docs/cli/cf-mcp/"
|
|
128
133
|
);
|
|
129
134
|
console.log();
|
|
130
|
-
log.
|
|
131
|
-
"Note:
|
|
135
|
+
log.dim(
|
|
136
|
+
"Note: this explicit path is needed only for clients that can't set CLAUDE_PROJECT_DIR. Claude Code resolves the project automatically and needs no manual config."
|
|
132
137
|
);
|
|
133
138
|
console.log();
|
|
134
139
|
}
|
|
@@ -189,17 +194,25 @@ async function memoryStatusCommand() {
|
|
|
189
194
|
log.info(`Embedding: ${chalk.cyan(model)} ${chalk.dim(`(${provider})`)}`);
|
|
190
195
|
}
|
|
191
196
|
const mcpStatus = getMemoryMcpStatus();
|
|
192
|
-
if (mcpStatus.
|
|
197
|
+
if (mcpStatus.userScope && mcpStatus.scope === "local") {
|
|
198
|
+
log.info(
|
|
199
|
+
`MCP: ${chalk.green("registered")} ${chalk.dim("(user scope)")} ${chalk.yellow('\u26A0 project .mcp.json shadows user-scope server \u2014 run "cf update" to clean up')}`
|
|
200
|
+
);
|
|
201
|
+
} else if (mcpStatus.userScope) {
|
|
193
202
|
log.info(
|
|
194
|
-
`MCP: ${chalk.green("
|
|
203
|
+
`MCP: ${chalk.green("registered")} ${chalk.dim("(user scope)")}`
|
|
204
|
+
);
|
|
205
|
+
} else if (mcpStatus.configured && mcpStatus.scope === "local") {
|
|
206
|
+
log.info(
|
|
207
|
+
`MCP: ${chalk.yellow("configured")} ${chalk.dim('(local .mcp.json \u2014 run "cf mcp" to migrate to user scope)')}`
|
|
195
208
|
);
|
|
196
209
|
} else if (mcpStatus.configured && mcpStatus.scope === "global") {
|
|
197
210
|
log.info(
|
|
198
|
-
`MCP: ${chalk.
|
|
211
|
+
`MCP: ${chalk.yellow("configured")} ${chalk.dim('(global ~/.claude/.mcp.json \u2014 run "cf mcp" to migrate to user scope)')} ${chalk.yellow("\u26A0 global config uses a fixed path \u2014 only works for one project")}`
|
|
199
212
|
);
|
|
200
213
|
} else {
|
|
201
214
|
log.info(
|
|
202
|
-
`MCP: ${chalk.dim("not
|
|
215
|
+
`MCP: ${chalk.dim("not registered")} ${chalk.dim('(run "cf mcp" to register at user scope)')}`
|
|
203
216
|
);
|
|
204
217
|
}
|
|
205
218
|
const autoCapture = config.memory?.autoCapture ?? false;
|
|
@@ -500,13 +513,13 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
500
513
|
const config = loadConfig();
|
|
501
514
|
const resolvedTier = config.memory?.tier ?? "auto";
|
|
502
515
|
if (resolvedTier === "markdown") {
|
|
503
|
-
await setupMemoryMcp(
|
|
516
|
+
await setupMemoryMcp();
|
|
504
517
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
505
518
|
printInitDone();
|
|
506
519
|
return;
|
|
507
520
|
}
|
|
508
521
|
if (resolvedTier === "lite") {
|
|
509
|
-
await setupMemoryMcp(
|
|
522
|
+
await setupMemoryMcp();
|
|
510
523
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
511
524
|
printInitDone();
|
|
512
525
|
return;
|
|
@@ -514,7 +527,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
514
527
|
const depsOk = await ensureSqliteDepsIfNeeded(mcpDir);
|
|
515
528
|
if (!depsOk) return;
|
|
516
529
|
if (!existsSync(memoryDir)) {
|
|
517
|
-
await setupMemoryMcp(
|
|
530
|
+
await setupMemoryMcp();
|
|
518
531
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
519
532
|
printInitDone();
|
|
520
533
|
return;
|
|
@@ -522,7 +535,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
522
535
|
const docCount = countMdFiles(memoryDir);
|
|
523
536
|
if (docCount === 0) {
|
|
524
537
|
log.info("No existing memories to import.");
|
|
525
|
-
await setupMemoryMcp(
|
|
538
|
+
await setupMemoryMcp();
|
|
526
539
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
527
540
|
printInitDone();
|
|
528
541
|
return;
|
|
@@ -544,7 +557,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
544
557
|
} finally {
|
|
545
558
|
await backend.close();
|
|
546
559
|
}
|
|
547
|
-
await setupMemoryMcp(
|
|
560
|
+
await setupMemoryMcp();
|
|
548
561
|
console.log();
|
|
549
562
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
550
563
|
log.info(
|
|
@@ -561,15 +574,14 @@ function printInitDone() {
|
|
|
561
574
|
` Documentation: ${chalk.cyan("https://cf.dinhanhthi.com/docs/cli/cf-memory/")}`
|
|
562
575
|
);
|
|
563
576
|
}
|
|
564
|
-
async function setupMemoryMcp(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
log.info(`MCP: ${chalk.green("already configured")} in .mcp.json`);
|
|
577
|
+
async function setupMemoryMcp() {
|
|
578
|
+
if (isMemoryMcpRegistered()) {
|
|
579
|
+
log.info("coding-friend-memory: already registered (user scope)");
|
|
568
580
|
return;
|
|
569
581
|
}
|
|
570
|
-
|
|
571
|
-
log.
|
|
572
|
-
"
|
|
582
|
+
registerMemoryMcp();
|
|
583
|
+
log.success(
|
|
584
|
+
"Registered coding-friend-memory (user scope). Restart Claude Code to activate."
|
|
573
585
|
);
|
|
574
586
|
}
|
|
575
587
|
async function memoryInitCommand() {
|
|
@@ -853,7 +865,7 @@ async function memoryMcpCommand() {
|
|
|
853
865
|
const memoryDir = getMemoryDir();
|
|
854
866
|
const mcpDir = getLibPath("cf-memory");
|
|
855
867
|
ensureMemoryBuilt(mcpDir);
|
|
856
|
-
warnStaleMcpJson(
|
|
868
|
+
warnStaleMcpJson();
|
|
857
869
|
printMemoryMcpConfig(memoryDir);
|
|
858
870
|
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
859
871
|
const memoryDistPath = join(mcpDir, "dist", "index.js");
|
|
@@ -9,13 +9,9 @@ import {
|
|
|
9
9
|
registerLearnMcp,
|
|
10
10
|
unregisterLearnMcp
|
|
11
11
|
} from "./chunk-YIXAQ4R2.js";
|
|
12
|
-
import {
|
|
13
|
-
memoryConfigMenu
|
|
14
|
-
} from "./chunk-N4WZWRCI.js";
|
|
15
12
|
import {
|
|
16
13
|
resolveLearnDir
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-RZRT7NGT.js";
|
|
14
|
+
} from "./chunk-PI4P34KF.js";
|
|
19
15
|
import {
|
|
20
16
|
findStatuslineHookPath,
|
|
21
17
|
getCurrentAccountEmail,
|
|
@@ -36,6 +32,10 @@ import {
|
|
|
36
32
|
hasShellCompletion,
|
|
37
33
|
removeShellCompletion
|
|
38
34
|
} from "./chunk-667NMPN4.js";
|
|
35
|
+
import {
|
|
36
|
+
memoryConfigMenu
|
|
37
|
+
} from "./chunk-DP6DFQ4G.js";
|
|
38
|
+
import "./chunk-RZRT7NGT.js";
|
|
39
39
|
import {
|
|
40
40
|
BACK,
|
|
41
41
|
applyDocsDirChange,
|