coding-friend-cli 1.31.3 → 1.32.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.
@@ -1,20 +1,19 @@
1
1
  import {
2
2
  editMemoryAutoCapture,
3
3
  editMemoryAutoStart,
4
- editMemoryDaemonTimeout,
5
4
  editMemoryEmbedding,
6
5
  editMemoryTier,
7
6
  getMemoryMcpStatus,
8
7
  memoryConfigMenu,
9
8
  writeMemoryMcpEntry
10
- } from "./chunk-YMCAGIYB.js";
11
- import {
12
- getLibPath
13
- } from "./chunk-RZRT7NGT.js";
9
+ } from "./chunk-5W7ZOVDU.js";
14
10
  import {
15
11
  loadConfig,
16
12
  resolveMemoryDir
17
- } from "./chunk-65S7Q5PW.js";
13
+ } from "./chunk-GTX6I57V.js";
14
+ import {
15
+ getLibPath
16
+ } from "./chunk-RZRT7NGT.js";
18
17
  import {
19
18
  showConfigHint
20
19
  } from "./chunk-HPNRQYLM.js";
@@ -35,17 +34,74 @@ import {
35
34
  } from "./chunk-5UVDWG5L.js";
36
35
 
37
36
  // src/commands/memory.ts
38
- import { existsSync, readdirSync, statSync, rmSync } from "fs";
39
- import { join, resolve, sep } from "path";
37
+ import { existsSync as existsSync2, readdirSync, statSync, rmSync } from "fs";
38
+ import { join as join2, resolve, sep } from "path";
40
39
  import { homedir } from "os";
41
40
  import { confirm } from "@inquirer/prompts";
41
+
42
+ // src/lib/mcp-state.ts
43
+ import { existsSync } from "fs";
44
+ import { join } from "path";
42
45
  import chalk from "chalk";
46
+ function warnStaleMcpJson(memoryDir) {
47
+ const localMcpPath = join(process.cwd(), ".mcp.json");
48
+ if (!existsSync(localMcpPath)) return;
49
+ const mcpJson = readJson(localMcpPath);
50
+ if (mcpJson === null) {
51
+ log.warn(".mcp.json exists but could not be parsed \u2014 check for syntax errors.");
52
+ return;
53
+ }
54
+ const state = detectMemoryMcpState(mcpJson, existsSync);
55
+ if (state.kind === "stale" || state.kind === "legacy-valid") {
56
+ if (memoryDir) {
57
+ writeMemoryMcpEntry(memoryDir);
58
+ if (state.kind === "stale") {
59
+ log.success("Auto-updated stale .mcp.json to version-stable npx format.");
60
+ } else {
61
+ log.success("Updated .mcp.json to version-stable npx format.");
62
+ }
63
+ console.log();
64
+ } else if (state.kind === "stale") {
65
+ console.log(chalk.yellow(`\u26A0 Stale MCP config detected in .mcp.json`));
66
+ console.log(chalk.dim(` Path no longer exists: ${state.path}`));
67
+ console.log(chalk.dim(` Run "cf memory mcp" to update to the new format.`));
68
+ console.log();
69
+ } else {
70
+ console.log(chalk.cyan(`\u2139 .mcp.json uses an absolute path for coding-friend-memory.`));
71
+ console.log(chalk.dim(` Consider running "cf memory mcp" to switch to the version-stable format.`));
72
+ console.log();
73
+ }
74
+ }
75
+ }
76
+ function detectMemoryMcpState(mcpJson, pathExists) {
77
+ if (!mcpJson) return { kind: "none" };
78
+ const servers = mcpJson.mcpServers;
79
+ if (!servers) return { kind: "none" };
80
+ const entry = servers["coding-friend-memory"];
81
+ if (!entry) return { kind: "none" };
82
+ const command = entry.command;
83
+ if (!command) return { kind: "none" };
84
+ if (command === "npx") return { kind: "npx" };
85
+ if (command === "node") {
86
+ const args = entry.args;
87
+ const serverPath = args?.[0];
88
+ if (!serverPath) return { kind: "none" };
89
+ if (!pathExists(serverPath)) {
90
+ return { kind: "stale", path: serverPath };
91
+ }
92
+ return { kind: "legacy-valid", path: serverPath };
93
+ }
94
+ return { kind: "none" };
95
+ }
96
+
97
+ // src/commands/memory.ts
98
+ import chalk2 from "chalk";
43
99
  function countMdFiles(dir) {
44
- if (!existsSync(dir)) return 0;
100
+ if (!existsSync2(dir)) return 0;
45
101
  let count = 0;
46
102
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
47
103
  if (entry.isDirectory()) {
48
- count += countMdFiles(join(dir, entry.name));
104
+ count += countMdFiles(join2(dir, entry.name));
49
105
  } else if (entry.name.endsWith(".md") && entry.name !== "README.md") {
50
106
  count++;
51
107
  }
@@ -65,7 +121,7 @@ function truncateError(text) {
65
121
  return [...head, ` ... (${skipped} lines omitted) ...`, ...tail].join("\n");
66
122
  }
67
123
  function ensureMemoryBuilt(mcpDir) {
68
- if (!existsSync(join(mcpDir, "node_modules"))) {
124
+ if (!existsSync2(join2(mcpDir, "node_modules"))) {
69
125
  log.step("Installing memory server dependencies (one-time setup)...");
70
126
  const result = runWithStderr("npm", ["install"], { cwd: mcpDir });
71
127
  if (result.exitCode !== 0) {
@@ -75,7 +131,7 @@ function ensureMemoryBuilt(mcpDir) {
75
131
  }
76
132
  log.success("Done.");
77
133
  }
78
- if (!existsSync(join(mcpDir, "dist"))) {
134
+ if (!existsSync2(join2(mcpDir, "dist"))) {
79
135
  log.step("Building memory server...");
80
136
  const result = runWithStderr("npm", ["run", "build"], { cwd: mcpDir });
81
137
  if (result.exitCode !== 0) {
@@ -87,23 +143,23 @@ function ensureMemoryBuilt(mcpDir) {
87
143
  }
88
144
  }
89
145
  function printMemoryMcpConfig(serverPath, memoryDir) {
90
- console.log(chalk.dim("Add this to your MCP client config:"));
146
+ console.log(chalk2.dim("Add this to your MCP client config:"));
91
147
  console.log();
92
148
  console.log(
93
- chalk.yellow.bold("--- Claude Code (.mcp.json in project root) ---")
149
+ chalk2.yellow.bold("--- Claude Code (.mcp.json in project root) ---")
94
150
  );
95
151
  console.log(`
96
152
  {
97
153
  "mcpServers": {
98
154
  "coding-friend-memory": {
99
- "command": "node",
100
- "args": ["${serverPath}", "${memoryDir}"]
155
+ "command": "npx",
156
+ "args": ["-y", "coding-friend-cli", "mcp-serve", "${memoryDir}"]
101
157
  }
102
158
  }
103
159
  }`);
104
160
  console.log();
105
161
  console.log(
106
- chalk.yellow.bold(
162
+ chalk2.yellow.bold(
107
163
  "--- Claude Desktop / Claude Chat (claude_desktop_config.json) ---"
108
164
  )
109
165
  );
@@ -117,39 +173,39 @@ function printMemoryMcpConfig(serverPath, memoryDir) {
117
173
  }
118
174
  }`);
119
175
  console.log();
120
- console.log(chalk.yellow.bold("--- Generic MCP client ---"));
176
+ console.log(chalk2.yellow.bold("--- Generic MCP client ---"));
121
177
  console.log(`
122
178
  Server command: node ${serverPath} ${memoryDir}
123
179
  Transport: stdio`);
124
180
  console.log();
125
- console.log(chalk.yellow.bold("--- Available tools ---"));
181
+ console.log(chalk2.yellow.bold("--- Available tools ---"));
126
182
  console.log();
127
183
  console.log(
128
- ` ${chalk.white("memory_store")} ${chalk.dim("Store a new memory")}`
184
+ ` ${chalk2.white("memory_store")} ${chalk2.dim("Store a new memory")}`
129
185
  );
130
186
  console.log(
131
- ` ${chalk.white("memory_search")} ${chalk.dim("Search memories (keyword match)")}`
187
+ ` ${chalk2.white("memory_search")} ${chalk2.dim("Search memories (keyword match)")}`
132
188
  );
133
189
  console.log(
134
- ` ${chalk.white("memory_retrieve")} ${chalk.dim("Get a specific memory by ID")}`
190
+ ` ${chalk2.white("memory_retrieve")} ${chalk2.dim("Get a specific memory by ID")}`
135
191
  );
136
192
  console.log(
137
- ` ${chalk.white("memory_list")} ${chalk.dim("List memories with filtering")}`
193
+ ` ${chalk2.white("memory_list")} ${chalk2.dim("List memories with filtering")}`
138
194
  );
139
195
  console.log(
140
- ` ${chalk.white("memory_update")} ${chalk.dim("Update existing memory")}`
196
+ ` ${chalk2.white("memory_update")} ${chalk2.dim("Update existing memory")}`
141
197
  );
142
198
  console.log(
143
- ` ${chalk.white("memory_delete")} ${chalk.dim("Delete a memory")}`
199
+ ` ${chalk2.white("memory_delete")} ${chalk2.dim("Delete a memory")}`
144
200
  );
145
201
  console.log();
146
- console.log(chalk.yellow.bold("--- Resources ---"));
202
+ console.log(chalk2.yellow.bold("--- Resources ---"));
147
203
  console.log();
148
204
  console.log(
149
- ` ${chalk.white("memory://index")} ${chalk.dim("Browse all memories")}`
205
+ ` ${chalk2.white("memory://index")} ${chalk2.dim("Browse all memories")}`
150
206
  );
151
207
  console.log(
152
- ` ${chalk.white("memory://stats")} ${chalk.dim("Storage statistics")}`
208
+ ` ${chalk2.white("memory://stats")} ${chalk2.dim("Storage statistics")}`
153
209
  );
154
210
  console.log();
155
211
  log.warn(
@@ -167,43 +223,43 @@ async function memoryStatusCommand() {
167
223
  const docCount = countMdFiles(memoryDir);
168
224
  const mcpDir = getLibPath("cf-memory");
169
225
  ensureMemoryBuilt(mcpDir);
170
- const { isDaemonRunning, getDaemonInfo } = await import(join(mcpDir, "dist/daemon/process.js"));
171
- const { areSqliteDepsAvailable } = await import(join(mcpDir, "dist/lib/lazy-install.js"));
226
+ const { isDaemonRunning, getDaemonInfo } = await import(join2(mcpDir, "dist/daemon/process.js"));
227
+ const { areSqliteDepsAvailable } = await import(join2(mcpDir, "dist/lib/lazy-install.js"));
172
228
  const sqliteAvailable = areSqliteDepsAvailable();
173
229
  const running = await isDaemonRunning();
174
230
  const daemonInfo = getDaemonInfo();
175
231
  let tierLabel;
176
232
  if (sqliteAvailable) {
177
- tierLabel = chalk.cyan("Tier 1 (SQLite + Hybrid)");
233
+ tierLabel = chalk2.cyan("Tier 1 (SQLite + Hybrid)");
178
234
  } else if (running) {
179
- tierLabel = chalk.cyan("Tier 2 (MiniSearch + Daemon)");
235
+ tierLabel = chalk2.cyan("Tier 2 (MiniSearch + Daemon)");
180
236
  } else {
181
- tierLabel = chalk.cyan("Tier 3 (Markdown)");
237
+ tierLabel = chalk2.cyan("Tier 3 (Markdown)");
182
238
  }
183
239
  printBanner("\u{1F9E0} Coding Friend Memory");
184
240
  console.log();
185
241
  log.info(`Tier: ${tierLabel}`);
186
- log.info(`Memory dir: ${chalk.cyan(memoryDir)}`);
187
- log.info(`Memories in this dir: ${chalk.green(String(docCount))}`);
242
+ log.info(`Memory dir: ${chalk2.cyan(memoryDir)}`);
243
+ log.info(`Memories in this dir: ${chalk2.green(String(docCount))}`);
188
244
  if (running && daemonInfo) {
189
245
  const uptime = (Date.now() - daemonInfo.startedAt) / 1e3;
190
246
  log.info(
191
- `Daemon: ${chalk.green("running")} (PID ${daemonInfo.pid}, uptime ${formatUptime(uptime)}) ${chalk.dim('Turn it off by "cf memory stop-daemon"')}`
247
+ `Daemon: ${chalk2.green("running")} (PID ${daemonInfo.pid}, uptime ${formatUptime(uptime)}) ${chalk2.dim('Turn it off by "cf memory stop-daemon"')}`
192
248
  );
193
249
  } else if (sqliteAvailable) {
194
250
  log.info(
195
- `Daemon: ${chalk.dim("stopped")} ${chalk.dim("(not needed \u2014 Tier 1 uses SQLite directly)")}`
251
+ `Daemon: ${chalk2.dim("stopped")} ${chalk2.dim("(not needed \u2014 Tier 1 uses SQLite directly)")}`
196
252
  );
197
253
  } else {
198
254
  log.info(
199
- `Daemon: ${chalk.dim("stopped")} ${chalk.dim('(run "cf memory start-daemon" for Tier 2 search)')}`
255
+ `Daemon: ${chalk2.dim("stopped")} ${chalk2.dim('(run "cf memory start-daemon" for Tier 2 search)')}`
200
256
  );
201
257
  }
202
258
  if (sqliteAvailable) {
203
- log.info(`SQLite deps: ${chalk.green("installed")}`);
259
+ log.info(`SQLite deps: ${chalk2.green("installed")}`);
204
260
  } else {
205
261
  log.info(
206
- `SQLite deps: ${chalk.dim("not installed")} (run "cf memory init" to enable Tier 1)`
262
+ `SQLite deps: ${chalk2.dim("not installed")} (run "cf memory init" to enable Tier 1)`
207
263
  );
208
264
  }
209
265
  const config = loadConfig();
@@ -211,33 +267,33 @@ async function memoryStatusCommand() {
211
267
  if (embeddingConfig?.provider || embeddingConfig?.model) {
212
268
  const provider = embeddingConfig.provider ?? "transformers";
213
269
  const model = embeddingConfig.model ?? (provider === "ollama" ? "all-minilm:l6-v2" : "Xenova/all-MiniLM-L6-v2");
214
- log.info(`Embedding: ${chalk.cyan(model)} ${chalk.dim(`(${provider})`)}`);
270
+ log.info(`Embedding: ${chalk2.cyan(model)} ${chalk2.dim(`(${provider})`)}`);
215
271
  }
216
272
  const mcpStatus = getMemoryMcpStatus();
217
273
  if (mcpStatus.configured && mcpStatus.scope === "local") {
218
274
  log.info(
219
- `MCP: ${chalk.green("configured")} ${chalk.dim("(local .mcp.json)")}`
275
+ `MCP: ${chalk2.green("configured")} ${chalk2.dim("(local .mcp.json)")}`
220
276
  );
221
277
  } else if (mcpStatus.configured && mcpStatus.scope === "global") {
222
278
  log.info(
223
- `MCP: ${chalk.green("configured")} ${chalk.dim("(global ~/.claude/.mcp.json)")} ${chalk.yellow("\u26A0 global config uses a fixed path \u2014 only works for one project")}`
279
+ `MCP: ${chalk2.green("configured")} ${chalk2.dim("(global ~/.claude/.mcp.json)")} ${chalk2.yellow("\u26A0 global config uses a fixed path \u2014 only works for one project")}`
224
280
  );
225
281
  } else {
226
282
  log.info(
227
- `MCP: ${chalk.dim("not configured in this project")} ${chalk.dim('(run "cf memory init" or add manually via "cf memory mcp")')}`
283
+ `MCP: ${chalk2.dim("not configured in this project")} ${chalk2.dim('(run "cf memory init" or add manually via "cf memory mcp")')}`
228
284
  );
229
285
  }
230
286
  const autoCapture = config.memory?.autoCapture ?? false;
231
287
  log.info(
232
- `Auto-capture: ${autoCapture ? chalk.green("on") : chalk.dim("off")}`
288
+ `Auto-capture: ${autoCapture ? chalk2.green("on") : chalk2.dim("off")}`
233
289
  );
234
- if (existsSync(memoryDir)) {
290
+ if (existsSync2(memoryDir)) {
235
291
  const categories = readdirSync(memoryDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => {
236
- const catCount = countMdFiles(join(memoryDir, d.name));
292
+ const catCount = countMdFiles(join2(memoryDir, d.name));
237
293
  return `${d.name} (${catCount})`;
238
294
  }).filter((s) => !s.endsWith("(0)"));
239
295
  if (categories.length > 0) {
240
- log.info(`Categories: ${chalk.dim(categories.join(", "))}`);
296
+ log.info(`Categories: ${chalk2.dim(categories.join(", "))}`);
241
297
  }
242
298
  }
243
299
  console.log();
@@ -246,7 +302,7 @@ async function memoryStatusCommand() {
246
302
  }
247
303
  async function memorySearchCommand(query) {
248
304
  const memoryDir = getMemoryDir();
249
- if (!existsSync(memoryDir)) {
305
+ if (!existsSync2(memoryDir)) {
250
306
  log.error(`Memory dir not found: ${memoryDir}`);
251
307
  log.dim("Run `cf init` to create project folders.");
252
308
  process.exit(1);
@@ -258,7 +314,7 @@ async function memorySearchCommand(query) {
258
314
  [
259
315
  "-e",
260
316
  `
261
- import { MarkdownBackend } from ${JSON.stringify(join(mcpDir, "dist/backends/markdown.js"))};
317
+ import { MarkdownBackend } from ${JSON.stringify(join2(mcpDir, "dist/backends/markdown.js"))};
262
318
  const backend = new MarkdownBackend(${JSON.stringify(memoryDir)});
263
319
  const results = await backend.search({ query: process.env.CF_SEARCH_QUERY, limit: 10 });
264
320
  for (const r of results) {
@@ -281,7 +337,7 @@ async function memoryListCommand(opts) {
281
337
  return memoryListProjectsCommand();
282
338
  }
283
339
  const memoryDir = getMemoryDir();
284
- if (!existsSync(memoryDir)) {
340
+ if (!existsSync2(memoryDir)) {
285
341
  log.info(`No memory directory found at: ${memoryDir}`);
286
342
  log.dim(
287
343
  "This folder has no memories yet. Use --projects to list all project databases."
@@ -298,7 +354,7 @@ async function memoryListCommand(opts) {
298
354
  [
299
355
  "-e",
300
356
  `
301
- import { MarkdownBackend } from ${JSON.stringify(join(mcpDir, "dist/backends/markdown.js"))};
357
+ import { MarkdownBackend } from ${JSON.stringify(join2(mcpDir, "dist/backends/markdown.js"))};
302
358
  const backend = new MarkdownBackend(${JSON.stringify(memoryDir)});
303
359
  const metas = await backend.list({});
304
360
  if (metas.length === 0) { console.log("No memories found."); process.exit(0); }
@@ -334,7 +390,7 @@ async function memoryStartDaemonCommand() {
334
390
  const memoryDir = getMemoryDir();
335
391
  const mcpDir = getLibPath("cf-memory");
336
392
  ensureMemoryBuilt(mcpDir);
337
- const { isDaemonRunning, getDaemonInfo, spawnDaemon } = await import(join(mcpDir, "dist/daemon/process.js"));
393
+ const { isDaemonRunning, getDaemonInfo, spawnDaemon } = await import(join2(mcpDir, "dist/daemon/process.js"));
338
394
  if (await isDaemonRunning()) {
339
395
  const info = getDaemonInfo();
340
396
  log.info(`Daemon already running (PID ${info?.pid})`);
@@ -343,11 +399,10 @@ async function memoryStartDaemonCommand() {
343
399
  log.step("Starting memory daemon...");
344
400
  const config = loadConfig();
345
401
  const embedding = config.memory?.embedding;
346
- const idleTimeoutMs = config.memory?.daemon?.idleTimeout;
347
- const result = await spawnDaemon(memoryDir, embedding, { idleTimeoutMs });
402
+ const result = await spawnDaemon(memoryDir, embedding, {});
348
403
  if (result) {
349
404
  log.success(`Daemon started (PID ${result.pid})`);
350
- log.info(`Watching ${chalk.cyan(memoryDir)} for changes`);
405
+ log.info(`Watching ${chalk2.cyan(memoryDir)} for changes`);
351
406
  } else {
352
407
  log.error("Daemon did not start within 3 seconds");
353
408
  process.exit(1);
@@ -356,7 +411,7 @@ async function memoryStartDaemonCommand() {
356
411
  async function memoryStopDaemonCommand() {
357
412
  const mcpDir = getLibPath("cf-memory");
358
413
  ensureMemoryBuilt(mcpDir);
359
- const { stopDaemon, isDaemonRunning } = await import(join(mcpDir, "dist/daemon/process.js"));
414
+ const { stopDaemon, isDaemonRunning } = await import(join2(mcpDir, "dist/daemon/process.js"));
360
415
  if (!await isDaemonRunning()) {
361
416
  log.info("Daemon is not running.");
362
417
  return;
@@ -373,10 +428,10 @@ async function memoryRebuildCommand() {
373
428
  const memoryDir = getMemoryDir();
374
429
  const mcpDir = getLibPath("cf-memory");
375
430
  ensureMemoryBuilt(mcpDir);
376
- const { areSqliteDepsAvailable } = await import(join(mcpDir, "dist/lib/lazy-install.js"));
431
+ const { areSqliteDepsAvailable } = await import(join2(mcpDir, "dist/lib/lazy-install.js"));
377
432
  if (areSqliteDepsAvailable()) {
378
433
  log.step("Rebuilding SQLite index + embeddings...");
379
- const { SqliteBackend } = await import(join(mcpDir, "dist/backends/sqlite/index.js"));
434
+ const { SqliteBackend } = await import(join2(mcpDir, "dist/backends/sqlite/index.js"));
380
435
  const config = loadConfig();
381
436
  const embedding = config.memory?.embedding;
382
437
  const opts = embedding ? { embedding, skipVec: false } : { skipVec: false };
@@ -386,7 +441,7 @@ async function memoryRebuildCommand() {
386
441
  const stats = await backend.stats();
387
442
  log.success(`Rebuilt: ${stats.total} memories indexed.`);
388
443
  if (backend.isVecEnabled()) {
389
- log.info(`Vector search: ${chalk.green("enabled")}`);
444
+ log.info(`Vector search: ${chalk2.green("enabled")}`);
390
445
  }
391
446
  if (!backend.isRebuildNeeded()) {
392
447
  log.info("Embedding dimensions: up to date");
@@ -396,14 +451,14 @@ async function memoryRebuildCommand() {
396
451
  }
397
452
  return;
398
453
  }
399
- const { isDaemonRunning, getDaemonPaths } = await import(join(mcpDir, "dist/daemon/process.js"));
454
+ const { isDaemonRunning, getDaemonPaths } = await import(join2(mcpDir, "dist/daemon/process.js"));
400
455
  if (!await isDaemonRunning()) {
401
456
  log.info("No SQLite deps and daemon not running. Nothing to rebuild.");
402
457
  log.dim("Install Tier 1 deps: cf memory init");
403
458
  log.dim("Or start the daemon: cf memory start-daemon");
404
459
  return;
405
460
  }
406
- const { DaemonClient } = await import(join(mcpDir, "dist/lib/daemon-client.js"));
461
+ const { DaemonClient } = await import(join2(mcpDir, "dist/lib/daemon-client.js"));
407
462
  const paths = getDaemonPaths();
408
463
  const client = new DaemonClient(paths.socketPath);
409
464
  log.step("Rebuilding search index via daemon...");
@@ -420,7 +475,7 @@ function getDbPath(memoryDir) {
420
475
  const stripped = resolved.replace(/\/docs\/memory$/, "").replace(/\/memory$/, "");
421
476
  const id = stripped.replace(/\//g, "-");
422
477
  const home = homedir();
423
- const dbPath = join(
478
+ const dbPath = join2(
424
479
  home,
425
480
  ".coding-friend",
426
481
  "memory",
@@ -428,7 +483,7 @@ function getDbPath(memoryDir) {
428
483
  id,
429
484
  "db.sqlite"
430
485
  );
431
- return existsSync(dbPath) ? dbPath : null;
486
+ return existsSync2(dbPath) ? dbPath : null;
432
487
  } catch {
433
488
  return null;
434
489
  }
@@ -437,7 +492,7 @@ async function ensureSqliteDepsIfNeeded(mcpDir) {
437
492
  const config = loadConfig();
438
493
  const tier = config.memory?.tier ?? "auto";
439
494
  if (tier === "markdown" || tier === "lite") return true;
440
- const { ensureDeps, areSqliteDepsAvailable } = await import(join(mcpDir, "dist/lib/lazy-install.js"));
495
+ const { ensureDeps, areSqliteDepsAvailable } = await import(join2(mcpDir, "dist/lib/lazy-install.js"));
441
496
  if (areSqliteDepsAvailable()) return true;
442
497
  log.step("Installing SQLite dependencies...");
443
498
  const installed = await ensureDeps({
@@ -466,36 +521,30 @@ function isMemoryInitialized() {
466
521
  return getDbPath(memoryDir) !== null;
467
522
  }
468
523
  async function memoryInitWizard(memoryDir, mcpDir) {
469
- log.step("Step 1/5: Search tier");
524
+ log.step("Step 1/4: Search tier");
470
525
  await editMemoryTier(
471
526
  readJson(globalConfigPath()),
472
527
  readJson(localConfigPath())
473
528
  );
474
529
  console.log();
475
- log.step("Step 2/5: Embedding provider");
530
+ log.step("Step 2/4: Embedding provider");
476
531
  await editMemoryEmbedding(
477
532
  readJson(globalConfigPath()),
478
533
  readJson(localConfigPath())
479
534
  );
480
535
  console.log();
481
- log.step("Step 3/5: Auto-capture");
536
+ log.step("Step 3/4: Auto-capture");
482
537
  await editMemoryAutoCapture(
483
538
  readJson(globalConfigPath()),
484
539
  readJson(localConfigPath())
485
540
  );
486
541
  console.log();
487
- log.step("Step 4/5: Auto-start daemon");
542
+ log.step("Step 4/4: Auto-start daemon");
488
543
  await editMemoryAutoStart(
489
544
  readJson(globalConfigPath()),
490
545
  readJson(localConfigPath())
491
546
  );
492
547
  console.log();
493
- log.step("Step 5/5: Daemon idle timeout");
494
- await editMemoryDaemonTimeout(
495
- readJson(globalConfigPath()),
496
- readJson(localConfigPath())
497
- );
498
- console.log();
499
548
  const config = loadConfig();
500
549
  const tier = config.memory?.tier ?? "auto";
501
550
  if (tier === "markdown") {
@@ -514,7 +563,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
514
563
  }
515
564
  const depsOk = await ensureSqliteDepsIfNeeded(mcpDir);
516
565
  if (!depsOk) return;
517
- if (!existsSync(memoryDir)) {
566
+ if (!existsSync2(memoryDir)) {
518
567
  log.info(
519
568
  "No memory directory found. Memories will be indexed as they're created."
520
569
  );
@@ -530,7 +579,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
530
579
  return;
531
580
  }
532
581
  log.step(`Importing ${docCount} existing memories into SQLite...`);
533
- const { SqliteBackend } = await import(join(mcpDir, "dist/backends/sqlite/index.js"));
582
+ const { SqliteBackend } = await import(join2(mcpDir, "dist/backends/sqlite/index.js"));
534
583
  const embedding = config.memory?.embedding;
535
584
  const backend = new SqliteBackend(memoryDir, {
536
585
  skipVec: false,
@@ -541,7 +590,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
541
590
  const stats = await backend.stats();
542
591
  log.success(`Imported ${stats.total} memories. DB: ${backend.getDbPath()}`);
543
592
  log.info(
544
- `Vector search: ${backend.isVecEnabled() ? chalk.green("enabled") : chalk.dim("disabled (sqlite-vec not available)")}`
593
+ `Vector search: ${backend.isVecEnabled() ? chalk2.green("enabled") : chalk2.dim("disabled (sqlite-vec not available)")}`
545
594
  );
546
595
  } finally {
547
596
  await backend.close();
@@ -550,13 +599,13 @@ async function memoryInitWizard(memoryDir, mcpDir) {
550
599
  console.log();
551
600
  log.success('Memory initialized! Run "cf memory status" to verify.');
552
601
  log.info(
553
- `Tip: Run ${chalk.cyan("/cf-scan")} in Claude Code to populate memory with project knowledge.`
602
+ `Tip: Run ${chalk2.cyan("/cf-scan")} in Claude Code to populate memory with project knowledge.`
554
603
  );
555
604
  }
556
- async function setupMemoryMcp(memoryDir, mcpDir) {
605
+ async function setupMemoryMcp(memoryDir, _mcpDir) {
557
606
  const mcpStatus = getMemoryMcpStatus();
558
607
  if (mcpStatus.configured && mcpStatus.scope === "local") {
559
- log.info(`MCP: ${chalk.green("already configured")} in .mcp.json`);
608
+ log.info(`MCP: ${chalk2.green("already configured")} in .mcp.json`);
560
609
  return;
561
610
  }
562
611
  console.log();
@@ -572,14 +621,7 @@ async function setupMemoryMcp(memoryDir, mcpDir) {
572
621
  log.dim('Skipped. Run "cf memory mcp" anytime to get the config.');
573
622
  return;
574
623
  }
575
- const serverPath = join(mcpDir, "dist", "index.js");
576
- if (!existsSync(serverPath)) {
577
- log.warn(
578
- "cf-memory not built yet. Run `cf memory mcp` after building to get the config."
579
- );
580
- return;
581
- }
582
- writeMemoryMcpEntry(serverPath, memoryDir);
624
+ writeMemoryMcpEntry(memoryDir);
583
625
  }
584
626
  async function memoryInitCommand() {
585
627
  const memoryDir = getMemoryDir();
@@ -612,7 +654,7 @@ async function memoryConfigCommand() {
612
654
  }
613
655
  function getProjectsBaseDir() {
614
656
  const home = homedir();
615
- return join(home, ".coding-friend", "memory", "projects");
657
+ return join2(home, ".coding-friend", "memory", "projects");
616
658
  }
617
659
  function formatSize(bytes) {
618
660
  if (bytes < 1024) return `${bytes} B`;
@@ -630,9 +672,9 @@ function formatDate(raw) {
630
672
  }
631
673
  function dirSize(dir) {
632
674
  let total = 0;
633
- if (!existsSync(dir)) return 0;
675
+ if (!existsSync2(dir)) return 0;
634
676
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
635
- const p = join(dir, entry.name);
677
+ const p = join2(dir, entry.name);
636
678
  if (entry.isFile()) {
637
679
  total += statSync(p).size;
638
680
  } else if (entry.isDirectory()) {
@@ -642,7 +684,7 @@ function dirSize(dir) {
642
684
  return total;
643
685
  }
644
686
  function getProjectInfo(projectDir, projectId, mcpDir, knownSourceDir) {
645
- const dbPath = join(projectDir, "db.sqlite");
687
+ const dbPath = join2(projectDir, "db.sqlite");
646
688
  const size = dirSize(projectDir);
647
689
  const info = {
648
690
  id: projectId,
@@ -651,7 +693,7 @@ function getProjectInfo(projectDir, projectId, mcpDir, knownSourceDir) {
651
693
  size,
652
694
  lastUpdated: null
653
695
  };
654
- if (!existsSync(dbPath)) return info;
696
+ if (!existsSync2(dbPath)) return info;
655
697
  try {
656
698
  const backfillDir = knownSourceDir ? JSON.stringify(knownSourceDir) : "null";
657
699
  const result = run(
@@ -692,7 +734,7 @@ async function memoryListProjectsCommand() {
692
734
  const baseDir = getProjectsBaseDir();
693
735
  const mcpDir = getLibPath("cf-memory");
694
736
  ensureMemoryBuilt(mcpDir);
695
- if (!existsSync(baseDir)) {
737
+ if (!existsSync2(baseDir)) {
696
738
  log.info("No memory projects found.");
697
739
  log.dim('Run "cf memory init" in a project to create one.');
698
740
  return;
@@ -703,35 +745,35 @@ async function memoryListProjectsCommand() {
703
745
  return;
704
746
  }
705
747
  const currentMemoryDir = resolve(getMemoryDir());
706
- const { projectId } = await import(join(mcpDir, "dist/backends/sqlite/index.js"));
748
+ const { projectId } = await import(join2(mcpDir, "dist/backends/sqlite/index.js"));
707
749
  const currentProjectId = projectId(currentMemoryDir);
708
750
  log.step(`Scanning ${dirs.length} project(s)...
709
751
  `);
710
752
  const projects = [];
711
753
  for (const id of dirs) {
712
754
  const knownDir = id === currentProjectId ? currentMemoryDir : void 0;
713
- projects.push(getProjectInfo(join(baseDir, id), id, mcpDir, knownDir));
755
+ projects.push(getProjectInfo(join2(baseDir, id), id, mcpDir, knownDir));
714
756
  }
715
757
  projects.sort((a, b) => b.size - a.size);
716
758
  const totalSize = projects.reduce((sum, p) => sum + p.size, 0);
717
759
  const idxW = String(projects.length).length;
718
760
  const header = `${"#".padStart(idxW)} ${"SIZE".padStart(10)} ${"MEMS".padStart(4)} ${"PROJECT ID".padEnd(12)} ${"UPDATED".padEnd(16)} PATH`;
719
- console.log(chalk.bold(header));
720
- console.log(chalk.dim("-".repeat(header.length + 10)));
761
+ console.log(chalk2.bold(header));
762
+ console.log(chalk2.dim("-".repeat(header.length + 10)));
721
763
  projects.forEach((p, i) => {
722
- const idx = chalk.dim(String(i + 1).padStart(idxW));
723
- const sizeStr = chalk.yellow(formatSize(p.size).padStart(10));
724
- const memCount = chalk.green(String(p.memories).padStart(4));
725
- const idStr = chalk.cyan(p.id.padEnd(12));
726
- const dateStr = p.lastUpdated ? formatDate(p.lastUpdated).padEnd(16) : chalk.dim("n/a".padEnd(16));
727
- const pathStr = p.sourceDir ? chalk.dim(p.sourceDir) : chalk.dim("(unknown)");
764
+ const idx = chalk2.dim(String(i + 1).padStart(idxW));
765
+ const sizeStr = chalk2.yellow(formatSize(p.size).padStart(10));
766
+ const memCount = chalk2.green(String(p.memories).padStart(4));
767
+ const idStr = chalk2.cyan(p.id.padEnd(12));
768
+ const dateStr = p.lastUpdated ? formatDate(p.lastUpdated).padEnd(16) : chalk2.dim("n/a".padEnd(16));
769
+ const pathStr = p.sourceDir ? chalk2.dim(p.sourceDir) : chalk2.dim("(unknown)");
728
770
  console.log(
729
771
  `${idx} ${sizeStr} ${memCount} ${idStr} ${dateStr} ${pathStr}`
730
772
  );
731
773
  });
732
774
  console.log();
733
775
  console.log(
734
- chalk.bold(
776
+ chalk2.bold(
735
777
  `Total: ${projects.length} project(s), ${formatSize(totalSize)}`
736
778
  )
737
779
  );
@@ -739,7 +781,7 @@ async function memoryListProjectsCommand() {
739
781
  }
740
782
  async function memoryRmCommand(opts) {
741
783
  const baseDir = getProjectsBaseDir();
742
- if (!existsSync(baseDir)) {
784
+ if (!existsSync2(baseDir)) {
743
785
  log.info("No memory projects found. Nothing to remove.");
744
786
  return;
745
787
  }
@@ -749,9 +791,9 @@ async function memoryRmCommand(opts) {
749
791
  const dirs = readdirSync(baseDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
750
792
  const orphaned = [];
751
793
  for (const id of dirs) {
752
- const projectDir = join(baseDir, id);
794
+ const projectDir = join2(baseDir, id);
753
795
  const info = getProjectInfo(projectDir, id, mcpDir);
754
- if (info.sourceDir && !existsSync(info.sourceDir)) {
796
+ if (info.sourceDir && !existsSync2(info.sourceDir)) {
755
797
  orphaned.push({
756
798
  id,
757
799
  reason: `source dir missing: ${info.sourceDir}`,
@@ -775,7 +817,7 @@ async function memoryRmCommand(opts) {
775
817
  );
776
818
  console.log();
777
819
  for (const o of orphaned) {
778
- console.log(` ${chalk.cyan(o.id)} ${chalk.dim(o.reason)}`);
820
+ console.log(` ${chalk2.cyan(o.id)} ${chalk2.dim(o.reason)}`);
779
821
  }
780
822
  console.log();
781
823
  const ok = await confirm({
@@ -787,7 +829,7 @@ async function memoryRmCommand(opts) {
787
829
  return;
788
830
  }
789
831
  for (const o of orphaned) {
790
- rmSync(join(baseDir, o.id), { recursive: true, force: true });
832
+ rmSync(join2(baseDir, o.id), { recursive: true, force: true });
791
833
  }
792
834
  log.success(
793
835
  `Deleted ${orphaned.length} orphaned project(s) (${formatSize(totalSize)}).`
@@ -803,7 +845,7 @@ async function memoryRmCommand(opts) {
803
845
  return;
804
846
  }
805
847
  const totalSize = dirs.reduce(
806
- (sum, d) => sum + dirSize(join(baseDir, d.name)),
848
+ (sum, d) => sum + dirSize(join2(baseDir, d.name)),
807
849
  0
808
850
  );
809
851
  log.warn(
@@ -820,19 +862,19 @@ async function memoryRmCommand(opts) {
820
862
  return;
821
863
  }
822
864
  for (const d of dirs) {
823
- rmSync(join(baseDir, d.name), { recursive: true, force: true });
865
+ rmSync(join2(baseDir, d.name), { recursive: true, force: true });
824
866
  }
825
867
  log.success(`Deleted ${dirs.length} project database(s).`);
826
868
  return;
827
869
  }
828
870
  if (opts.projectId) {
829
- const projectDir = join(baseDir, opts.projectId);
871
+ const projectDir = join2(baseDir, opts.projectId);
830
872
  const resolved = resolve(projectDir);
831
873
  if (!resolved.startsWith(resolve(baseDir) + sep)) {
832
874
  log.error("Invalid project ID.");
833
875
  process.exit(1);
834
876
  }
835
- if (!existsSync(projectDir)) {
877
+ if (!existsSync2(projectDir)) {
836
878
  log.error(`Project "${opts.projectId}" not found.`);
837
879
  log.dim('Run "cf memory list --projects" to see available projects.');
838
880
  process.exit(1);
@@ -863,11 +905,14 @@ async function memoryMcpCommand() {
863
905
  const memoryDir = getMemoryDir();
864
906
  const mcpDir = getLibPath("cf-memory");
865
907
  ensureMemoryBuilt(mcpDir);
866
- const serverPath = join(mcpDir, "dist", "index.js");
908
+ warnStaleMcpJson(memoryDir);
909
+ const serverPath = join2(mcpDir, "dist", "index.js");
867
910
  printMemoryMcpConfig(serverPath, memoryDir);
868
911
  }
869
912
 
870
913
  export {
914
+ warnStaleMcpJson,
915
+ detectMemoryMcpState,
871
916
  ensureMemoryBuilt,
872
917
  printMemoryMcpConfig,
873
918
  memoryStatusCommand,
@@ -1,9 +1,9 @@
1
+ import {
2
+ resolveMemoryDir
3
+ } from "./chunk-GTX6I57V.js";
1
4
  import {
2
5
  getLibPath
3
6
  } from "./chunk-RZRT7NGT.js";
4
- import {
5
- resolveMemoryDir
6
- } from "./chunk-65S7Q5PW.js";
7
7
  import {
8
8
  BACK,
9
9
  askScope,
@@ -24,7 +24,6 @@ import {
24
24
  } from "./chunk-5UVDWG5L.js";
25
25
 
26
26
  // src/lib/memory-prompts.ts
27
- import { existsSync } from "fs";
28
27
  import { homedir } from "os";
29
28
  import { confirm, input, select } from "@inquirer/prompts";
30
29
  import chalk from "chalk";
@@ -219,31 +218,7 @@ async function editMemoryEmbedding(globalCfg, localCfg) {
219
218
  if (ollamaUrl) embedding.ollamaUrl = ollamaUrl;
220
219
  writeMemoryField(scope, "embedding", embedding);
221
220
  }
222
- async function editMemoryDaemonTimeout(globalCfg, localCfg) {
223
- const currentDaemon = getMergedMemoryValue("daemon", globalCfg, localCfg);
224
- const currentMs = currentDaemon?.idleTimeout;
225
- const currentMin = currentMs !== void 0 ? currentMs / 6e4 : void 0;
226
- if (currentMin !== void 0) {
227
- log.dim(`Current: ${currentMin} minutes`);
228
- }
229
- const value = await input({
230
- message: "Daemon idle timeout (minutes, 0 = no timeout):",
231
- default: String(currentMin ?? 0),
232
- validate: (val) => {
233
- const n = Number(val);
234
- if (isNaN(n) || n < 0)
235
- return "Must be 0 (no timeout) or a positive number";
236
- return true;
237
- }
238
- });
239
- const scope = await askScope();
240
- if (scope === "back") return;
241
- writeMemoryField(scope, "daemon", {
242
- ...currentDaemon,
243
- idleTimeout: Number(value) * 6e4
244
- });
245
- }
246
- function writeMemoryMcpEntry(serverPath, memoryDir) {
221
+ function writeMemoryMcpEntry(memoryDir) {
247
222
  const mcpPath = join(process.cwd(), ".mcp.json");
248
223
  const existing = readJson(mcpPath) ?? {};
249
224
  const servers = existing.mcpServers ?? {};
@@ -252,8 +227,8 @@ function writeMemoryMcpEntry(serverPath, memoryDir) {
252
227
  mcpServers: {
253
228
  ...servers,
254
229
  "coding-friend-memory": {
255
- command: "node",
256
- args: [serverPath, memoryDir]
230
+ command: "npx",
231
+ args: ["-y", "coding-friend-cli", "mcp-serve", memoryDir]
257
232
  }
258
233
  }
259
234
  });
@@ -285,24 +260,8 @@ async function editMemoryMcp() {
285
260
  });
286
261
  if (!reconfigure) return;
287
262
  }
288
- let mcpDir;
289
- try {
290
- mcpDir = getLibPath("cf-memory");
291
- } catch {
292
- log.warn(
293
- "cf-memory package not found. Install the CLI first: npm i -g coding-friend-cli"
294
- );
295
- return;
296
- }
297
- const serverPath = join(mcpDir, "dist", "index.js");
298
- if (!existsSync(serverPath)) {
299
- log.warn(
300
- 'cf-memory not built yet. Run "cf memory mcp" after building to get the config.'
301
- );
302
- return;
303
- }
304
263
  const memoryDir = resolveMemoryDir();
305
- writeMemoryMcpEntry(serverPath, memoryDir);
264
+ writeMemoryMcpEntry(memoryDir);
306
265
  }
307
266
  async function memoryConfigMenu(opts) {
308
267
  while (true) {
@@ -340,8 +299,6 @@ async function memoryConfigMenu(opts) {
340
299
  globalCfg,
341
300
  localCfg
342
301
  );
343
- const daemonScope = getMemoryFieldScope("daemon", globalCfg, localCfg);
344
- const daemonVal = getMergedMemoryValue("daemon", globalCfg, localCfg);
345
302
  const embeddingLabel = embeddingVal?.provider ? embeddingVal.model ? `${embeddingVal.model} (${embeddingVal.provider})` : embeddingVal.provider : "";
346
303
  const mcpStatus = getMemoryMcpStatus();
347
304
  const mcpLabel = mcpStatus.configured ? mcpStatus.scope === "local" ? chalk.green("configured") + chalk.dim(" (.mcp.json)") : chalk.green("configured") + chalk.dim(" (global)") + " " + chalk.yellow("\u26A0") : chalk.dim("not configured");
@@ -365,10 +322,6 @@ async function memoryConfigMenu(opts) {
365
322
  name: `Embedding ${formatScopeLabel(embeddingScope)}${embeddingLabel ? ` (${embeddingLabel})` : ""}`,
366
323
  value: "embedding"
367
324
  },
368
- {
369
- name: `Daemon timeout ${formatScopeLabel(daemonScope)}${daemonVal?.idleTimeout ? ` (${daemonVal.idleTimeout / 6e4}min)` : ""}`,
370
- value: "daemon"
371
- },
372
325
  {
373
326
  name: `MCP setup (${mcpLabel})`,
374
327
  value: "mcp"
@@ -391,9 +344,6 @@ async function memoryConfigMenu(opts) {
391
344
  case "embedding":
392
345
  await editMemoryEmbedding(globalCfg, localCfg);
393
346
  break;
394
- case "daemon":
395
- await editMemoryDaemonTimeout(globalCfg, localCfg);
396
- break;
397
347
  case "mcp":
398
348
  await editMemoryMcp();
399
349
  break;
@@ -406,7 +356,6 @@ export {
406
356
  editMemoryAutoCapture,
407
357
  editMemoryAutoStart,
408
358
  editMemoryEmbedding,
409
- editMemoryDaemonTimeout,
410
359
  writeMemoryMcpEntry,
411
360
  getMemoryMcpStatus,
412
361
  memoryConfigMenu
@@ -58,9 +58,6 @@ var StatuslineConfigSchema = z.object({
58
58
  });
59
59
  var MemoryConfigSchema = z.object({
60
60
  tier: z.enum(["auto", "full", "lite", "markdown"]).optional(),
61
- daemon: z.object({
62
- idleTimeout: z.number().optional()
63
- }).optional(),
64
61
  embedding: z.object({
65
62
  provider: z.enum(["transformers", "ollama"]).optional(),
66
63
  model: z.string().optional(),
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  memoryConfigMenu
3
- } from "./chunk-YMCAGIYB.js";
3
+ } from "./chunk-5W7ZOVDU.js";
4
+ import "./chunk-GTX6I57V.js";
4
5
  import "./chunk-RZRT7NGT.js";
5
- import "./chunk-65S7Q5PW.js";
6
6
  import {
7
7
  findStatuslineHookPath,
8
8
  getCurrentAccountEmail,
@@ -659,7 +659,7 @@ async function configCommand() {
659
659
  {
660
660
  name: `Memory settings ${formatScopeLabel(memoryScope)}`,
661
661
  value: "memory",
662
- description: " Tier, auto-capture, auto-start, embedding provider, daemon timeout"
662
+ description: " Tier, auto-capture, auto-start, embedding provider"
663
663
  },
664
664
  {
665
665
  name: `Auto-approve ${formatScopeLabel(autoApproveScope)}${autoApproveVal !== void 0 ? ` (${autoApproveVal})` : ""}`,
@@ -1,9 +1,9 @@
1
+ import {
2
+ resolveDocsDir
3
+ } from "./chunk-GTX6I57V.js";
1
4
  import {
2
5
  getLibPath
3
6
  } from "./chunk-RZRT7NGT.js";
4
- import {
5
- resolveDocsDir
6
- } from "./chunk-65S7Q5PW.js";
7
7
  import "./chunk-DHH6SRXV.js";
8
8
  import {
9
9
  run,
package/dist/index.js CHANGED
@@ -30,21 +30,25 @@ program.command("enable").description("Re-enable the Coding Friend plugin").opti
30
30
  await enableCommand(opts);
31
31
  });
32
32
  program.command("init").description("Initialize coding-friend in current project").action(async () => {
33
- const { initCommand } = await import("./init-W55DKHKZ.js");
33
+ const { initCommand } = await import("./init-3UITY4LD.js");
34
34
  await initCommand();
35
35
  });
36
36
  program.command("config").description("Manage Coding Friend configuration").action(async () => {
37
- const { configCommand } = await import("./config-OLEUUS32.js");
37
+ const { configCommand } = await import("./config-FUEEFM5N.js");
38
38
  await configCommand();
39
39
  });
40
40
  program.command("host").description("Build and serve learning docs as a static website").argument("[path]", "path to docs folder").option("-p, --port <port>", "port number", "3333").action(async (path, opts) => {
41
- const { hostCommand } = await import("./host-DTWSRS2U.js");
41
+ const { hostCommand } = await import("./host-RNYPAE4D.js");
42
42
  await hostCommand(path, opts);
43
43
  });
44
44
  program.command("mcp").description("Setup MCP server for learning docs").argument("[path]", "path to docs folder").action(async (path) => {
45
- const { mcpCommand } = await import("./mcp-JL2EUJBT.js");
45
+ const { mcpCommand } = await import("./mcp-LJ5NX6XE.js");
46
46
  await mcpCommand(path);
47
47
  });
48
+ program.command("mcp-serve").description("Start the cf-memory MCP server (used internally by npx)").argument("<memoryDir>", "path to memory directory").action(async (memoryDir) => {
49
+ const { mcpServeCommand } = await import("./mcp-serve-3FEPFVVQ.js");
50
+ await mcpServeCommand(memoryDir);
51
+ });
48
52
  program.command("permission").description("Manage Claude Code permission rules for Coding Friend").option("--all", "Apply all recommended permissions without prompts").option("--user", "Save to user-level settings (~/.claude/settings.json)").option(
49
53
  "--project",
50
54
  "Save to project-level settings (.claude/settings.local.json)"
@@ -61,7 +65,7 @@ program.command("update").description("Update coding-friend plugin, CLI, and sta
61
65
  await updateCommand(opts);
62
66
  });
63
67
  program.command("status").description("Show comprehensive Coding Friend status").action(async () => {
64
- const { statusCommand } = await import("./status-CYAKIHFW.js");
68
+ const { statusCommand } = await import("./status-FU5GR3MP.js");
65
69
  await statusCommand();
66
70
  });
67
71
  var session = program.command("session").description("Save and load Claude Code sessions across machines");
@@ -76,11 +80,11 @@ session.command("save").description("Save current Claude Code session to sync fo
76
80
  "-s, --session-id <id>",
77
81
  "session UUID to save (default: auto-detect newest)"
78
82
  ).option("-l, --label <label>", "label for this session").action(async (opts) => {
79
- const { sessionSaveCommand } = await import("./session-COIV2PO5.js");
83
+ const { sessionSaveCommand } = await import("./session-FMC2MG6C.js");
80
84
  await sessionSaveCommand(opts);
81
85
  });
82
86
  session.command("load").description("Load a saved session from sync folder").action(async () => {
83
- const { sessionLoadCommand } = await import("./session-COIV2PO5.js");
87
+ const { sessionLoadCommand } = await import("./session-FMC2MG6C.js");
84
88
  await sessionLoadCommand();
85
89
  });
86
90
  var memory = program.command("memory").description("AI memory system \u2014 store and search project knowledge");
@@ -100,43 +104,43 @@ Memory subcommands:
100
104
  memory mcp Show MCP server setup instructions`
101
105
  );
102
106
  memory.command("status").description("Show memory system status").action(async () => {
103
- const { memoryStatusCommand } = await import("./memory-VOLXT5SX.js");
107
+ const { memoryStatusCommand } = await import("./memory-2ZD4WU3S.js");
104
108
  await memoryStatusCommand();
105
109
  });
106
110
  memory.command("search").description("Search memories by query").argument("<query>", "search query").action(async (query) => {
107
- const { memorySearchCommand } = await import("./memory-VOLXT5SX.js");
111
+ const { memorySearchCommand } = await import("./memory-2ZD4WU3S.js");
108
112
  await memorySearchCommand(query);
109
113
  });
110
114
  memory.command("list").description(
111
115
  "List memories in current project, or all projects with --projects"
112
116
  ).option("--projects", "List all project databases with size and metadata").action(async (opts) => {
113
- const { memoryListCommand } = await import("./memory-VOLXT5SX.js");
117
+ const { memoryListCommand } = await import("./memory-2ZD4WU3S.js");
114
118
  await memoryListCommand(opts);
115
119
  });
116
120
  memory.command("init").description(
117
121
  "Initialize memory system \u2014 interactive wizard (first time) or config menu"
118
122
  ).action(async () => {
119
- const { memoryInitCommand } = await import("./memory-VOLXT5SX.js");
123
+ const { memoryInitCommand } = await import("./memory-2ZD4WU3S.js");
120
124
  await memoryInitCommand();
121
125
  });
122
126
  memory.command("config").description("Configure memory system settings").action(async () => {
123
- const { memoryConfigCommand } = await import("./memory-VOLXT5SX.js");
127
+ const { memoryConfigCommand } = await import("./memory-2ZD4WU3S.js");
124
128
  await memoryConfigCommand();
125
129
  });
126
130
  memory.command("start-daemon").description("Start the memory daemon (Tier 2 \u2014 MiniSearch)").action(async () => {
127
- const { memoryStartDaemonCommand } = await import("./memory-VOLXT5SX.js");
131
+ const { memoryStartDaemonCommand } = await import("./memory-2ZD4WU3S.js");
128
132
  await memoryStartDaemonCommand();
129
133
  });
130
134
  memory.command("stop-daemon").description("Stop the memory daemon").action(async () => {
131
- const { memoryStopDaemonCommand } = await import("./memory-VOLXT5SX.js");
135
+ const { memoryStopDaemonCommand } = await import("./memory-2ZD4WU3S.js");
132
136
  await memoryStopDaemonCommand();
133
137
  });
134
138
  memory.command("rebuild").description("Rebuild the daemon search index").action(async () => {
135
- const { memoryRebuildCommand } = await import("./memory-VOLXT5SX.js");
139
+ const { memoryRebuildCommand } = await import("./memory-2ZD4WU3S.js");
136
140
  await memoryRebuildCommand();
137
141
  });
138
142
  memory.command("mcp").description("Show MCP server setup instructions").action(async () => {
139
- const { memoryMcpCommand } = await import("./memory-VOLXT5SX.js");
143
+ const { memoryMcpCommand } = await import("./memory-2ZD4WU3S.js");
140
144
  await memoryMcpCommand();
141
145
  });
142
146
  memory.command("rm").description("Remove a project database").option("--project-id <id>", "Project ID to remove").option("--all", "Remove all project databases").option(
@@ -144,7 +148,7 @@ memory.command("rm").description("Remove a project database").option("--project-
144
148
  "Remove orphaned projects (source dir missing or 0 memories)"
145
149
  ).action(
146
150
  async (opts) => {
147
- const { memoryRmCommand } = await import("./memory-VOLXT5SX.js");
151
+ const { memoryRmCommand } = await import("./memory-2ZD4WU3S.js");
148
152
  await memoryRmCommand(opts);
149
153
  }
150
154
  );
@@ -2,14 +2,14 @@ import {
2
2
  ensureMemoryBuilt,
3
3
  isMemoryInitialized,
4
4
  memoryInitWizard
5
- } from "./chunk-ZEROY3CW.js";
5
+ } from "./chunk-355AR2X5.js";
6
6
  import {
7
7
  memoryConfigMenu
8
- } from "./chunk-YMCAGIYB.js";
8
+ } from "./chunk-5W7ZOVDU.js";
9
+ import "./chunk-GTX6I57V.js";
9
10
  import {
10
11
  getLibPath
11
12
  } from "./chunk-RZRT7NGT.js";
12
- import "./chunk-65S7Q5PW.js";
13
13
  import {
14
14
  findStatuslineHookPath,
15
15
  getCurrentAccountEmail,
@@ -1,15 +1,17 @@
1
1
  import {
2
+ detectMemoryMcpState,
2
3
  ensureMemoryBuilt,
3
- printMemoryMcpConfig
4
- } from "./chunk-ZEROY3CW.js";
5
- import "./chunk-YMCAGIYB.js";
6
- import {
7
- getLibPath
8
- } from "./chunk-RZRT7NGT.js";
4
+ printMemoryMcpConfig,
5
+ warnStaleMcpJson
6
+ } from "./chunk-355AR2X5.js";
7
+ import "./chunk-5W7ZOVDU.js";
9
8
  import {
10
9
  resolveDocsDir,
11
10
  resolveMemoryDir
12
- } from "./chunk-65S7Q5PW.js";
11
+ } from "./chunk-GTX6I57V.js";
12
+ import {
13
+ getLibPath
14
+ } from "./chunk-RZRT7NGT.js";
13
15
  import "./chunk-DHH6SRXV.js";
14
16
  import "./chunk-HPNRQYLM.js";
15
17
  import {
@@ -38,6 +40,7 @@ function countMdFiles(dir) {
38
40
  return count;
39
41
  }
40
42
  async function mcpCommand(path) {
43
+ warnStaleMcpJson(resolveMemoryDir());
41
44
  const docsDir = resolveDocsDir(path);
42
45
  const mcpDir = getLibPath("learn-mcp");
43
46
  if (!existsSync(docsDir)) {
@@ -152,5 +155,6 @@ function printMemoryMcp() {
152
155
  printMemoryMcpConfig(serverPath, memoryDir);
153
156
  }
154
157
  export {
158
+ detectMemoryMcpState,
155
159
  mcpCommand
156
160
  };
@@ -0,0 +1,27 @@
1
+ import {
2
+ getLibPath
3
+ } from "./chunk-RZRT7NGT.js";
4
+ import {
5
+ log
6
+ } from "./chunk-NREZK463.js";
7
+
8
+ // src/commands/mcp-serve.ts
9
+ import { spawn } from "child_process";
10
+ import { join } from "path";
11
+ async function mcpServeCommand(memoryDir) {
12
+ const mcpDir = getLibPath("cf-memory");
13
+ const serverPath = join(mcpDir, "dist", "index.js");
14
+ const child = spawn("node", [serverPath, memoryDir], {
15
+ stdio: "inherit"
16
+ });
17
+ child.on("error", (err) => {
18
+ log.error(`Failed to start memory MCP server: ${err.message}`);
19
+ process.exit(1);
20
+ });
21
+ child.on("exit", (code) => {
22
+ process.exit(code ?? 0);
23
+ });
24
+ }
25
+ export {
26
+ mcpServeCommand
27
+ };
@@ -13,10 +13,10 @@ import {
13
13
  memoryStatusCommand,
14
14
  memoryStopDaemonCommand,
15
15
  printMemoryMcpConfig
16
- } from "./chunk-ZEROY3CW.js";
17
- import "./chunk-YMCAGIYB.js";
16
+ } from "./chunk-355AR2X5.js";
17
+ import "./chunk-5W7ZOVDU.js";
18
+ import "./chunk-GTX6I57V.js";
18
19
  import "./chunk-RZRT7NGT.js";
19
- import "./chunk-65S7Q5PW.js";
20
20
  import "./chunk-DHH6SRXV.js";
21
21
  import "./chunk-HPNRQYLM.js";
22
22
  import "./chunk-EVGXUDX4.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-65S7Q5PW.js";
3
+ } from "./chunk-GTX6I57V.js";
4
4
  import "./chunk-DHH6SRXV.js";
5
5
  import {
6
6
  claudeSessionDir,
@@ -1,9 +1,9 @@
1
+ import {
2
+ resolveMemoryDir
3
+ } from "./chunk-GTX6I57V.js";
1
4
  import {
2
5
  getLibPath
3
6
  } from "./chunk-RZRT7NGT.js";
4
- import {
5
- resolveMemoryDir
6
- } from "./chunk-65S7Q5PW.js";
7
7
  import {
8
8
  getCliVersion,
9
9
  getLatestCliVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-friend-cli",
3
- "version": "1.31.3",
3
+ "version": "1.32.1",
4
4
  "description": "CLI for coding-friend — host learning docs, setup MCP server, initialize projects",
5
5
  "type": "module",
6
6
  "bin": {