coding-friend-cli 1.34.0 → 1.35.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.
Files changed (36) hide show
  1. package/README.md +1 -0
  2. package/dist/chunk-2DTXVMPQ.js +26 -0
  3. package/dist/{chunk-OYPOADCX.js → chunk-57EGAXYI.js} +3 -3
  4. package/dist/{chunk-K6EDQGDN.js → chunk-B2NFXRFP.js} +17 -12
  5. package/dist/{chunk-3UIH5U3Y.js → chunk-C5YWESSF.js} +2 -6
  6. package/dist/chunk-E5J24GD5.js +190 -0
  7. package/dist/{chunk-UGTNIFBH.js → chunk-H5TXJZD7.js} +6 -6
  8. package/dist/{chunk-5X3JZKYW.js → chunk-L53RNEV3.js} +116 -73
  9. package/dist/{chunk-DMJCO6LJ.js → chunk-RLUNNJWJ.js} +2 -1
  10. package/dist/{chunk-XOHLBLN2.js → chunk-WNTMKIKC.js} +1 -1
  11. package/dist/chunk-WSUYLIYX.js +61 -0
  12. package/dist/clean-67ACB4OS.js +95 -0
  13. package/dist/{chunk-CXG6I6ZF.js → config-HTQAALMA.js} +182 -194
  14. package/dist/{dev-S6VZUD33.js → dev-PFUF67SH.js} +7 -7
  15. package/dist/{disable-ZWQVU3QZ.js → disable-CDOM7SSI.js} +2 -2
  16. package/dist/{enable-NXP6APNI.js → enable-SF7742UR.js} +2 -2
  17. package/dist/{host-Y3WIXDSS.js → host-HKA4OHBM.js} +3 -3
  18. package/dist/index.js +38 -34
  19. package/dist/{init-WDFYY5MM.js → init-YM7YEEGK.js} +154 -99
  20. package/dist/{install-FKL6WLIG.js → install-VYZSTXN6.js} +8 -8
  21. package/dist/{mcp-J4SD646S.js → mcp-7MO2MCLE.js} +72 -67
  22. package/dist/{mcp-serve-learn-UNW6VH5M.js → mcp-serve-learn-OKVC5WV3.js} +19 -3
  23. package/dist/{memory-RLZR7XQY.js → memory-XALEMWQF.js} +7 -7
  24. package/dist/{permission-DNW7DE24.js → permission-C5R3LMZQ.js} +2 -2
  25. package/dist/postinstall.js +1 -1
  26. package/dist/{session-6WQGKIRG.js → session-M4KRQ4VU.js} +2 -2
  27. package/dist/{status-BX2SVBBW.js → status-2XM5OZDR.js} +19 -14
  28. package/dist/{statusline-MLLKBHHR.js → statusline-VFIA7OS2.js} +3 -3
  29. package/dist/{uninstall-6ZJRS2H4.js → uninstall-QKEC3O64.js} +6 -6
  30. package/dist/{update-G5HZINBK.js → update-IV4Y3T72.js} +6 -6
  31. package/package.json +1 -1
  32. package/dist/chunk-AYIREX73.js +0 -85
  33. package/dist/chunk-TVAY4OQL.js +0 -118
  34. package/dist/config-MCEQOLE5.js +0 -22
  35. package/dist/{chunk-Z5Q533UG.js → chunk-HPNRQYLM.js} +3 -3
  36. package/dist/{update-check-5SCD2JR2.js → update-check-BPCQ25AR.js} +3 -3
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  getLatestVersion,
3
3
  semverCompare
4
- } from "./chunk-UGTNIFBH.js";
4
+ } from "./chunk-H5TXJZD7.js";
5
5
  import {
6
6
  getInstalledVersion
7
- } from "./chunk-XOHLBLN2.js";
8
- import "./chunk-OYPOADCX.js";
7
+ } from "./chunk-WNTMKIKC.js";
8
+ import "./chunk-57EGAXYI.js";
9
9
  import {
10
10
  ensureShellCompletion
11
- } from "./chunk-DMJCO6LJ.js";
11
+ } from "./chunk-RLUNNJWJ.js";
12
12
  import {
13
13
  enableMarketplaceAutoUpdate,
14
14
  isMarketplaceRegistered,
@@ -16,14 +16,14 @@ import {
16
16
  } from "./chunk-R6HDMRYL.js";
17
17
  import {
18
18
  resolveScope
19
- } from "./chunk-Z5Q533UG.js";
20
- import {
21
- devStatePath
22
- } from "./chunk-TWKNGPBO.js";
19
+ } from "./chunk-HPNRQYLM.js";
23
20
  import {
24
21
  commandExists,
25
22
  run
26
23
  } from "./chunk-EVGXUDX4.js";
24
+ import {
25
+ devStatePath
26
+ } from "./chunk-TWKNGPBO.js";
27
27
  import {
28
28
  log,
29
29
  printBanner
@@ -1,30 +1,40 @@
1
- import {
2
- checkLearnMcpHealth,
3
- checkMemoryMcpHealth,
4
- listMdFilesRecursive
5
- } from "./chunk-TVAY4OQL.js";
6
1
  import {
7
2
  ensureMemoryBuilt,
8
3
  printMemoryMcpConfig
9
- } from "./chunk-5X3JZKYW.js";
4
+ } from "./chunk-L53RNEV3.js";
10
5
  import {
6
+ checkLearnMcpHealth,
7
+ checkMemoryMcpHealth,
11
8
  detectMemoryMcpState,
9
+ printHealthSection,
12
10
  warnStaleMcpJson
13
- } from "./chunk-AYIREX73.js";
14
- import "./chunk-3UIH5U3Y.js";
11
+ } from "./chunk-E5J24GD5.js";
12
+ import {
13
+ listMdFilesRecursive
14
+ } from "./chunk-2DTXVMPQ.js";
15
15
  import {
16
- resolveDocsDir,
16
+ isLearnMcpRegistered,
17
+ registerLearnMcp
18
+ } from "./chunk-WSUYLIYX.js";
19
+ import {
20
+ getMemoryMcpStatus,
21
+ writeMemoryMcpEntry
22
+ } from "./chunk-C5YWESSF.js";
23
+ import {
24
+ resolveLearnDir,
17
25
  resolveMemoryDir
18
- } from "./chunk-K6EDQGDN.js";
26
+ } from "./chunk-B2NFXRFP.js";
19
27
  import {
20
28
  getLibPath
21
29
  } from "./chunk-RZRT7NGT.js";
22
- import "./chunk-OYPOADCX.js";
23
- import "./chunk-Z5Q533UG.js";
24
- import "./chunk-TWKNGPBO.js";
30
+ import "./chunk-57EGAXYI.js";
31
+ import "./chunk-HPNRQYLM.js";
25
32
  import {
26
33
  run
27
34
  } from "./chunk-EVGXUDX4.js";
35
+ import {
36
+ globalConfigPath
37
+ } from "./chunk-TWKNGPBO.js";
28
38
  import {
29
39
  log,
30
40
  printBanner
@@ -34,56 +44,17 @@ import {
34
44
  } from "./chunk-5UVDWG5L.js";
35
45
 
36
46
  // src/commands/mcp.ts
37
- import { existsSync, readdirSync } from "fs";
47
+ import { confirm } from "@inquirer/prompts";
48
+ import { existsSync } from "fs";
38
49
  import { join } from "path";
39
50
  import chalk from "chalk";
40
- function countMdFiles(dir) {
41
- let count = 0;
42
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
43
- if (entry.isDirectory()) {
44
- count += countMdFiles(join(dir, entry.name));
45
- } else if (entry.name.endsWith(".md") && entry.name !== "README.md") {
46
- count++;
47
- }
48
- }
49
- return count;
50
- }
51
- function printHealthSection(result) {
52
- console.log(chalk.dim("\u2500\u2500\u2500 Health Check \u2500\u2500\u2500"));
53
- for (const check of result.checks) {
54
- if (check.ok) {
55
- console.log(chalk.green(` \u2713 ${check.label}`));
56
- } else if (check.warn) {
57
- const detail = check.detail ? `: ${check.detail}` : "";
58
- console.log(chalk.yellow(` \u26A0 ${check.label}${detail}`));
59
- } else {
60
- const detail = check.detail ? `: ${check.detail}` : "";
61
- console.log(chalk.red(` \u2717 ${check.label}${detail}`));
62
- if (check.fix) {
63
- console.log(chalk.dim(` \u2192 ${check.fix}`));
64
- }
65
- }
66
- }
67
- console.log();
68
- }
69
- async function mcpCommand(path) {
51
+ async function mcpCommand() {
70
52
  warnStaleMcpJson(resolveMemoryDir());
71
- const docsDir = resolveDocsDir(path);
53
+ const globalCfg = readJson(globalConfigPath());
54
+ const learnDir = resolveLearnDir(globalCfg);
72
55
  const learnMcpDir = getLibPath("learn-mcp");
73
- if (!existsSync(docsDir)) {
74
- log.error(`Docs folder not found: ${docsDir}`);
75
- log.dim("Run /cf-learn first to generate some docs.");
76
- process.exit(1);
77
- }
78
- const docCount = countMdFiles(docsDir);
79
- if (docCount === 0) {
80
- log.error(`No .md files found in ${docsDir}`);
81
- log.dim("Run /cf-learn first to generate some docs.");
82
- process.exit(1);
83
- }
84
56
  printBanner("\u{1F4DA} Learn MCP");
85
- log.info(`Docs folder: ${chalk.cyan(docsDir)}`);
86
- log.info(`Found: ${chalk.green(docCount)} docs`);
57
+ log.info(`Learn folder: ${chalk.cyan(learnDir)}`);
87
58
  if (!existsSync(join(learnMcpDir, "node_modules"))) {
88
59
  log.step("Installing MCP server dependencies (one-time setup)...");
89
60
  const result = run("npm", ["install", "--silent"], { cwd: learnMcpDir });
@@ -95,7 +66,9 @@ async function mcpCommand(path) {
95
66
  }
96
67
  if (!existsSync(join(learnMcpDir, "dist"))) {
97
68
  log.step("Building MCP server...");
98
- const result = run("npm", ["run", "build", "--silent"], { cwd: learnMcpDir });
69
+ const result = run("npm", ["run", "build", "--silent"], {
70
+ cwd: learnMcpDir
71
+ });
99
72
  if (result === null) {
100
73
  log.error("Failed to build MCP server");
101
74
  process.exit(1);
@@ -103,8 +76,13 @@ async function mcpCommand(path) {
103
76
  log.success("Done.");
104
77
  }
105
78
  console.log();
106
- console.log(chalk.dim("Add this to your MCP client config:"));
79
+ console.log(
80
+ chalk.dim(
81
+ "Add this to your MCP client config (for non-Claude-Code clients):"
82
+ )
83
+ );
107
84
  console.log();
85
+ const learnDirJson = JSON.stringify(learnDir);
108
86
  console.log(`{
109
87
  "mcpServers": {
110
88
  "coding-friend-learn": {
@@ -113,26 +91,53 @@ async function mcpCommand(path) {
113
91
  "-y",
114
92
  "coding-friend-cli",
115
93
  "mcp-serve-learn",
116
- "${docsDir}"
94
+ ${learnDirJson}
117
95
  ]
118
96
  }
119
97
  }
120
98
  }`);
121
99
  console.log();
122
- log.dim(
123
- "Available tools & resources: https://cf.dinhanhthi.com/docs/cli/cf-mcp/"
124
- );
100
+ log.dim("See full docs: https://cf.dinhanhthi.com/docs/cli/cf-mcp/");
101
+ console.log();
102
+ if (globalCfg?.learn?.disabled) {
103
+ log.dim("coding-friend-learn: skipped (disabled in global config)");
104
+ } else if (isLearnMcpRegistered()) {
105
+ log.dim("coding-friend-learn: already registered");
106
+ log.dim(
107
+ " (If it points to an old path, run: claude mcp remove --scope user coding-friend-learn && cf mcp)"
108
+ );
109
+ } else {
110
+ const registered = registerLearnMcp(learnDir);
111
+ if (registered) {
112
+ log.success(
113
+ "Added coding-friend-learn (user scope). Restart Claude Code to activate."
114
+ );
115
+ }
116
+ }
125
117
  console.log();
126
- const localMcpPath = join(process.cwd(), ".mcp.json");
127
118
  const learnMcpDistPath = join(learnMcpDir, "dist", "index.js");
128
119
  const learnHealth = await checkLearnMcpHealth({
129
- readMcpJson: () => readJson(localMcpPath),
120
+ checkRegistered: isLearnMcpRegistered,
130
121
  pathExists: existsSync,
131
122
  listMdFiles: listMdFilesRecursive,
132
- docsDir,
123
+ docsDir: learnDir,
133
124
  learnMcpDistPath
134
125
  });
135
126
  printHealthSection(learnHealth);
127
+ const memoryMcpStatus = getMemoryMcpStatus();
128
+ if (memoryMcpStatus.configured) {
129
+ log.dim("coding-friend-memory: already in .mcp.json");
130
+ } else {
131
+ const addMemoryMcp = await confirm({
132
+ message: "coding-friend-memory not found in this project's .mcp.json. Add it now? (project-scoped \u2014 writes to .mcp.json)",
133
+ default: true
134
+ });
135
+ if (addMemoryMcp) {
136
+ const memoryDir = resolveMemoryDir();
137
+ writeMemoryMcpEntry(memoryDir);
138
+ }
139
+ }
140
+ console.log();
136
141
  await printMemoryMcp();
137
142
  }
138
143
  async function printMemoryMcp() {
@@ -4,13 +4,19 @@ import {
4
4
  import {
5
5
  runWithStderr
6
6
  } from "./chunk-EVGXUDX4.js";
7
+ import {
8
+ globalConfigPath
9
+ } from "./chunk-TWKNGPBO.js";
7
10
  import {
8
11
  log
9
12
  } from "./chunk-NREZK463.js";
13
+ import {
14
+ readJson
15
+ } from "./chunk-5UVDWG5L.js";
10
16
 
11
17
  // src/commands/mcp-serve-learn.ts
12
18
  import { spawn } from "child_process";
13
- import { existsSync, statSync } from "fs";
19
+ import { existsSync, mkdirSync, statSync } from "fs";
14
20
  import { join } from "path";
15
21
  function ensureLearnBuilt(mcpDir) {
16
22
  if (!existsSync(join(mcpDir, "node_modules"))) {
@@ -35,8 +41,18 @@ function ensureLearnBuilt(mcpDir) {
35
41
  }
36
42
  }
37
43
  async function mcpServeLearnCommand(docsDir) {
38
- if (!existsSync(docsDir) || !statSync(docsDir).isDirectory()) {
39
- log.error(`Docs directory not found: ${docsDir}`);
44
+ const globalCfg = readJson(globalConfigPath());
45
+ if (globalCfg?.learn?.disabled) {
46
+ log.warn(
47
+ "CF Learn is disabled (learn.disabled = true in ~/.coding-friend/config.json). MCP server not started."
48
+ );
49
+ process.exit(0);
50
+ return;
51
+ }
52
+ if (!existsSync(docsDir)) {
53
+ mkdirSync(docsDir, { recursive: true });
54
+ } else if (!statSync(docsDir).isDirectory()) {
55
+ log.error(`Path exists but is not a directory: ${docsDir}`);
40
56
  process.exit(1);
41
57
  return;
42
58
  }
@@ -13,15 +13,15 @@ import {
13
13
  memoryStatusCommand,
14
14
  memoryStopDaemonCommand,
15
15
  printMemoryMcpConfig
16
- } from "./chunk-5X3JZKYW.js";
17
- import "./chunk-AYIREX73.js";
18
- import "./chunk-3UIH5U3Y.js";
19
- import "./chunk-K6EDQGDN.js";
16
+ } from "./chunk-L53RNEV3.js";
17
+ import "./chunk-E5J24GD5.js";
18
+ import "./chunk-C5YWESSF.js";
19
+ import "./chunk-B2NFXRFP.js";
20
20
  import "./chunk-RZRT7NGT.js";
21
- import "./chunk-OYPOADCX.js";
22
- import "./chunk-Z5Q533UG.js";
23
- import "./chunk-TWKNGPBO.js";
21
+ import "./chunk-57EGAXYI.js";
22
+ import "./chunk-HPNRQYLM.js";
24
23
  import "./chunk-EVGXUDX4.js";
24
+ import "./chunk-TWKNGPBO.js";
25
25
  import "./chunk-NREZK463.js";
26
26
  import "./chunk-5UVDWG5L.js";
27
27
  export {
@@ -3,7 +3,8 @@ import {
3
3
  formatScopeLabel,
4
4
  getMergedValue,
5
5
  getScopeLabel
6
- } from "./chunk-Z5Q533UG.js";
6
+ } from "./chunk-HPNRQYLM.js";
7
+ import "./chunk-EVGXUDX4.js";
7
8
  import {
8
9
  claudeLocalSettingsPath,
9
10
  claudeProjectSettingsPath,
@@ -11,7 +12,6 @@ import {
11
12
  globalConfigPath,
12
13
  localConfigPath
13
14
  } from "./chunk-TWKNGPBO.js";
14
- import "./chunk-EVGXUDX4.js";
15
15
  import {
16
16
  log,
17
17
  printBanner
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ensureShellCompletion
4
- } from "./chunk-DMJCO6LJ.js";
4
+ } from "./chunk-RLUNNJWJ.js";
5
5
  import "./chunk-NREZK463.js";
6
6
 
7
7
  // src/postinstall.ts
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-K6EDQGDN.js";
4
- import "./chunk-OYPOADCX.js";
3
+ } from "./chunk-B2NFXRFP.js";
4
+ import "./chunk-57EGAXYI.js";
5
5
  import {
6
6
  claudeSessionDir,
7
7
  encodeProjectPath,
@@ -1,15 +1,19 @@
1
1
  import {
2
2
  checkLearnMcpHealth,
3
- checkMemoryMcpHealth,
3
+ checkMemoryMcpHealth
4
+ } from "./chunk-E5J24GD5.js";
5
+ import {
4
6
  listMdFilesRecursive
5
- } from "./chunk-TVAY4OQL.js";
6
- import "./chunk-AYIREX73.js";
7
- import "./chunk-3UIH5U3Y.js";
7
+ } from "./chunk-2DTXVMPQ.js";
8
+ import {
9
+ isLearnMcpRegistered
10
+ } from "./chunk-WSUYLIYX.js";
11
+ import "./chunk-C5YWESSF.js";
8
12
  import {
9
- resolveDocsDir,
13
+ resolveLearnDir,
10
14
  resolveMemoryDir,
11
15
  sanitizeRawConfig
12
- } from "./chunk-K6EDQGDN.js";
16
+ } from "./chunk-B2NFXRFP.js";
13
17
  import {
14
18
  getLibPath
15
19
  } from "./chunk-RZRT7NGT.js";
@@ -18,24 +22,24 @@ import {
18
22
  getLatestCliVersion,
19
23
  getLatestVersion,
20
24
  semverCompare
21
- } from "./chunk-UGTNIFBH.js";
25
+ } from "./chunk-H5TXJZD7.js";
22
26
  import {
23
27
  getInstalledVersion
24
- } from "./chunk-XOHLBLN2.js";
25
- import "./chunk-OYPOADCX.js";
26
- import "./chunk-DMJCO6LJ.js";
28
+ } from "./chunk-WNTMKIKC.js";
29
+ import "./chunk-57EGAXYI.js";
30
+ import "./chunk-RLUNNJWJ.js";
27
31
  import {
28
32
  detectPluginScope,
29
33
  isPluginDisabled
30
34
  } from "./chunk-R6HDMRYL.js";
31
- import "./chunk-Z5Q533UG.js";
35
+ import "./chunk-HPNRQYLM.js";
36
+ import "./chunk-EVGXUDX4.js";
32
37
  import {
33
38
  claudeSettingsPath,
34
39
  devStatePath,
35
40
  globalConfigPath,
36
41
  localConfigPath
37
42
  } from "./chunk-TWKNGPBO.js";
38
- import "./chunk-EVGXUDX4.js";
39
43
  import "./chunk-NREZK463.js";
40
44
  import {
41
45
  getExistingRules
@@ -266,9 +270,10 @@ async function statusCommand() {
266
270
  } catch {
267
271
  }
268
272
  const learnMcpDistPath = learnMcpDir ? join(learnMcpDir, "dist", "index.js") : "/unavailable";
269
- const docsDir = resolveDocsDir();
273
+ const globalCfg = readJson(globalConfigPath());
274
+ const docsDir = resolveLearnDir(globalCfg);
270
275
  const learnHealth = await checkLearnMcpHealth({
271
- readMcpJson: () => readJson(localMcpPath),
276
+ checkRegistered: isLearnMcpRegistered,
272
277
  pathExists: existsSync,
273
278
  listMdFiles: listMdFilesRecursive,
274
279
  docsDir,
@@ -8,14 +8,14 @@ import {
8
8
  saveStatuslineConfig,
9
9
  selectStatuslineComponents,
10
10
  writeStatuslineSettings
11
- } from "./chunk-XOHLBLN2.js";
11
+ } from "./chunk-WNTMKIKC.js";
12
12
  import {
13
13
  ALL_COMPONENT_IDS
14
- } from "./chunk-OYPOADCX.js";
15
- import "./chunk-TWKNGPBO.js";
14
+ } from "./chunk-57EGAXYI.js";
16
15
  import {
17
16
  commandExists
18
17
  } from "./chunk-EVGXUDX4.js";
18
+ import "./chunk-TWKNGPBO.js";
19
19
  import {
20
20
  log,
21
21
  printBanner
@@ -1,14 +1,18 @@
1
1
  import {
2
2
  hasShellCompletion,
3
3
  removeShellCompletion
4
- } from "./chunk-DMJCO6LJ.js";
4
+ } from "./chunk-RLUNNJWJ.js";
5
5
  import {
6
6
  isMarketplaceRegistered,
7
7
  isPluginInstalled
8
8
  } from "./chunk-R6HDMRYL.js";
9
9
  import {
10
10
  resolveScope
11
- } from "./chunk-Z5Q533UG.js";
11
+ } from "./chunk-HPNRQYLM.js";
12
+ import {
13
+ commandExists,
14
+ run
15
+ } from "./chunk-EVGXUDX4.js";
12
16
  import {
13
17
  claudeSettingsPath,
14
18
  devStatePath,
@@ -17,10 +21,6 @@ import {
17
21
  marketplaceClonePath,
18
22
  memoryDepsDir
19
23
  } from "./chunk-TWKNGPBO.js";
20
- import {
21
- commandExists,
22
- run
23
- } from "./chunk-EVGXUDX4.js";
24
24
  import {
25
25
  log,
26
26
  printBanner
@@ -4,13 +4,13 @@ import {
4
4
  getLatestVersion,
5
5
  semverCompare,
6
6
  updateCommand
7
- } from "./chunk-UGTNIFBH.js";
8
- import "./chunk-XOHLBLN2.js";
9
- import "./chunk-OYPOADCX.js";
10
- import "./chunk-DMJCO6LJ.js";
11
- import "./chunk-Z5Q533UG.js";
12
- import "./chunk-TWKNGPBO.js";
7
+ } from "./chunk-H5TXJZD7.js";
8
+ import "./chunk-WNTMKIKC.js";
9
+ import "./chunk-57EGAXYI.js";
10
+ import "./chunk-RLUNNJWJ.js";
11
+ import "./chunk-HPNRQYLM.js";
13
12
  import "./chunk-EVGXUDX4.js";
13
+ import "./chunk-TWKNGPBO.js";
14
14
  import "./chunk-NREZK463.js";
15
15
  import "./chunk-5UVDWG5L.js";
16
16
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-friend-cli",
3
- "version": "1.34.0",
3
+ "version": "1.35.0",
4
4
  "description": "CLI for coding-friend — host learning docs, setup MCP server, initialize projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,85 +0,0 @@
1
- import {
2
- writeMemoryMcpEntry
3
- } from "./chunk-3UIH5U3Y.js";
4
- import {
5
- log
6
- } from "./chunk-NREZK463.js";
7
- import {
8
- readJson
9
- } from "./chunk-5UVDWG5L.js";
10
-
11
- // src/lib/mcp-state.ts
12
- import { existsSync } from "fs";
13
- import { join } from "path";
14
- import chalk from "chalk";
15
- function warnStaleMcpJson(memoryDir) {
16
- const localMcpPath = join(process.cwd(), ".mcp.json");
17
- if (!existsSync(localMcpPath)) return;
18
- const mcpJson = readJson(localMcpPath);
19
- if (mcpJson === null) {
20
- log.warn(
21
- ".mcp.json exists but could not be parsed \u2014 check for syntax errors."
22
- );
23
- return;
24
- }
25
- const state = detectMemoryMcpState(mcpJson, existsSync);
26
- if (state.kind === "stale" || state.kind === "legacy-valid") {
27
- if (memoryDir) {
28
- writeMemoryMcpEntry(memoryDir);
29
- if (state.kind === "stale") {
30
- log.success(
31
- "Auto-updated stale .mcp.json to version-stable npx format."
32
- );
33
- } else {
34
- log.success("Updated .mcp.json to version-stable npx format.");
35
- }
36
- console.log();
37
- } else if (state.kind === "stale") {
38
- console.log(
39
- chalk.yellow(`\u26A0 Stale MCP config detected in .mcp.json`)
40
- );
41
- console.log(chalk.dim(` Path no longer exists: ${state.path}`));
42
- console.log(
43
- chalk.dim(` Run "cf memory mcp" to update to the new format.`)
44
- );
45
- console.log();
46
- } else {
47
- console.log(
48
- chalk.cyan(
49
- `\u2139 .mcp.json uses an absolute path for coding-friend-memory.`
50
- )
51
- );
52
- console.log(
53
- chalk.dim(
54
- ` Consider running "cf memory mcp" to switch to the version-stable format.`
55
- )
56
- );
57
- console.log();
58
- }
59
- }
60
- }
61
- function detectMemoryMcpState(mcpJson, pathExists) {
62
- if (!mcpJson) return { kind: "none" };
63
- const servers = mcpJson.mcpServers;
64
- if (!servers) return { kind: "none" };
65
- const entry = servers["coding-friend-memory"];
66
- if (!entry) return { kind: "none" };
67
- const command = entry.command;
68
- if (!command) return { kind: "none" };
69
- if (command === "npx") return { kind: "npx" };
70
- if (command === "node") {
71
- const args = entry.args;
72
- const serverPath = args?.[0];
73
- if (!serverPath) return { kind: "none" };
74
- if (!pathExists(serverPath)) {
75
- return { kind: "stale", path: serverPath };
76
- }
77
- return { kind: "legacy-valid", path: serverPath };
78
- }
79
- return { kind: "none" };
80
- }
81
-
82
- export {
83
- warnStaleMcpJson,
84
- detectMemoryMcpState
85
- };