coding-friend-cli 1.34.1 → 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 (35) hide show
  1. package/README.md +1 -0
  2. package/dist/chunk-2DTXVMPQ.js +26 -0
  3. package/dist/{chunk-DHH6SRXV.js → chunk-57EGAXYI.js} +3 -2
  4. package/dist/{chunk-AZ6AK5M4.js → chunk-B2NFXRFP.js} +12 -2
  5. package/dist/{chunk-QCKIBJF6.js → chunk-C5YWESSF.js} +2 -6
  6. package/dist/chunk-E5J24GD5.js +190 -0
  7. package/dist/{chunk-G4QGJEV7.js → chunk-H5TXJZD7.js} +6 -6
  8. package/dist/{chunk-FAANBGCB.js → chunk-L53RNEV3.js} +116 -73
  9. package/dist/{chunk-DMJCO6LJ.js → chunk-RLUNNJWJ.js} +2 -1
  10. package/dist/{chunk-LXZ47XCD.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/{config-44VQBNMS.js → config-HTQAALMA.js} +181 -120
  14. package/dist/{dev-QXVERU42.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-6IBKKCPA.js → host-HKA4OHBM.js} +3 -3
  18. package/dist/index.js +38 -34
  19. package/dist/{init-KY3ZPEWP.js → init-YM7YEEGK.js} +153 -85
  20. package/dist/{install-22BLHQ6D.js → install-VYZSTXN6.js} +8 -8
  21. package/dist/{mcp-OGZAZZRF.js → mcp-7MO2MCLE.js} +69 -66
  22. package/dist/{mcp-serve-learn-UNW6VH5M.js → mcp-serve-learn-OKVC5WV3.js} +19 -3
  23. package/dist/{memory-JM45DEIX.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-RCEE6P35.js → session-M4KRQ4VU.js} +2 -2
  27. package/dist/{status-NMSVOSC4.js → status-2XM5OZDR.js} +19 -14
  28. package/dist/{statusline-GKVAX7GR.js → statusline-VFIA7OS2.js} +3 -3
  29. package/dist/{uninstall-6ZJRS2H4.js → uninstall-QKEC3O64.js} +6 -6
  30. package/dist/{update-P5ZR2JVQ.js → update-IV4Y3T72.js} +6 -6
  31. package/package.json +1 -1
  32. package/dist/chunk-CZDXMFEZ.js +0 -118
  33. package/dist/chunk-FI5HEQ43.js +0 -85
  34. package/dist/{chunk-Z5Q533UG.js → chunk-HPNRQYLM.js} +3 -3
  35. 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-G4QGJEV7.js";
4
+ } from "./chunk-H5TXJZD7.js";
5
5
  import {
6
6
  getInstalledVersion
7
- } from "./chunk-LXZ47XCD.js";
8
- import "./chunk-DHH6SRXV.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-CZDXMFEZ.js";
6
1
  import {
7
2
  ensureMemoryBuilt,
8
3
  printMemoryMcpConfig
9
- } from "./chunk-FAANBGCB.js";
4
+ } from "./chunk-L53RNEV3.js";
10
5
  import {
6
+ checkLearnMcpHealth,
7
+ checkMemoryMcpHealth,
11
8
  detectMemoryMcpState,
9
+ printHealthSection,
12
10
  warnStaleMcpJson
13
- } from "./chunk-FI5HEQ43.js";
14
- import "./chunk-QCKIBJF6.js";
11
+ } from "./chunk-E5J24GD5.js";
12
+ import {
13
+ listMdFilesRecursive
14
+ } from "./chunk-2DTXVMPQ.js";
15
+ import {
16
+ isLearnMcpRegistered,
17
+ registerLearnMcp
18
+ } from "./chunk-WSUYLIYX.js";
15
19
  import {
16
- resolveDocsDir,
20
+ getMemoryMcpStatus,
21
+ writeMemoryMcpEntry
22
+ } from "./chunk-C5YWESSF.js";
23
+ import {
24
+ resolveLearnDir,
17
25
  resolveMemoryDir
18
- } from "./chunk-AZ6AK5M4.js";
26
+ } from "./chunk-B2NFXRFP.js";
19
27
  import {
20
28
  getLibPath
21
29
  } from "./chunk-RZRT7NGT.js";
22
- import "./chunk-DHH6SRXV.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 });
@@ -105,8 +76,13 @@ async function mcpCommand(path) {
105
76
  log.success("Done.");
106
77
  }
107
78
  console.log();
108
- 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
+ );
109
84
  console.log();
85
+ const learnDirJson = JSON.stringify(learnDir);
110
86
  console.log(`{
111
87
  "mcpServers": {
112
88
  "coding-friend-learn": {
@@ -115,26 +91,53 @@ async function mcpCommand(path) {
115
91
  "-y",
116
92
  "coding-friend-cli",
117
93
  "mcp-serve-learn",
118
- "${docsDir}"
94
+ ${learnDirJson}
119
95
  ]
120
96
  }
121
97
  }
122
98
  }`);
123
99
  console.log();
124
- log.dim(
125
- "Available tools & resources: https://cf.dinhanhthi.com/docs/cli/cf-mcp/"
126
- );
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
+ }
127
117
  console.log();
128
- const localMcpPath = join(process.cwd(), ".mcp.json");
129
118
  const learnMcpDistPath = join(learnMcpDir, "dist", "index.js");
130
119
  const learnHealth = await checkLearnMcpHealth({
131
- readMcpJson: () => readJson(localMcpPath),
120
+ checkRegistered: isLearnMcpRegistered,
132
121
  pathExists: existsSync,
133
122
  listMdFiles: listMdFilesRecursive,
134
- docsDir,
123
+ docsDir: learnDir,
135
124
  learnMcpDistPath
136
125
  });
137
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();
138
141
  await printMemoryMcp();
139
142
  }
140
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-FAANBGCB.js";
17
- import "./chunk-FI5HEQ43.js";
18
- import "./chunk-QCKIBJF6.js";
19
- import "./chunk-AZ6AK5M4.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-DHH6SRXV.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-AZ6AK5M4.js";
4
- import "./chunk-DHH6SRXV.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-CZDXMFEZ.js";
6
- import "./chunk-FI5HEQ43.js";
7
- import "./chunk-QCKIBJF6.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-AZ6AK5M4.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-G4QGJEV7.js";
25
+ } from "./chunk-H5TXJZD7.js";
22
26
  import {
23
27
  getInstalledVersion
24
- } from "./chunk-LXZ47XCD.js";
25
- import "./chunk-DHH6SRXV.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-LXZ47XCD.js";
11
+ } from "./chunk-WNTMKIKC.js";
12
12
  import {
13
13
  ALL_COMPONENT_IDS
14
- } from "./chunk-DHH6SRXV.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-G4QGJEV7.js";
8
- import "./chunk-LXZ47XCD.js";
9
- import "./chunk-DHH6SRXV.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.1",
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,118 +0,0 @@
1
- import {
2
- detectMemoryMcpState
3
- } from "./chunk-FI5HEQ43.js";
4
-
5
- // src/lib/mcp-health.ts
6
- async function checkMemoryMcpHealth(deps) {
7
- const checks = [];
8
- const mcpJson = deps.readMcpJson();
9
- const state = detectMemoryMcpState(mcpJson, deps.pathExists);
10
- if (state.kind === "npx") {
11
- checks.push({ label: "Config (.mcp.json)", ok: true });
12
- } else if (state.kind === "none") {
13
- checks.push({
14
- label: "Config (.mcp.json)",
15
- ok: false,
16
- detail: "coding-friend-memory not configured",
17
- fix: 'Run "cf memory mcp" to add the MCP entry'
18
- });
19
- } else {
20
- const detail = state.kind === "stale" ? `Stale path: ${state.path}` : `Absolute path (legacy): ${state.path}`;
21
- checks.push({
22
- label: "Config (.mcp.json)",
23
- ok: false,
24
- detail,
25
- fix: 'Run "cf memory mcp" to update to the npx format'
26
- });
27
- }
28
- const distExists = deps.pathExists(deps.memoryDistPath);
29
- checks.push({
30
- label: "Package built",
31
- ok: distExists,
32
- ...distExists ? {} : {
33
- detail: "cf-memory not built",
34
- fix: 'Run "cf memory init" to build'
35
- }
36
- });
37
- let daemonRunning = false;
38
- let daemonCheckError;
39
- try {
40
- daemonRunning = await deps.isDaemonRunning();
41
- } catch (err) {
42
- daemonCheckError = err instanceof Error ? err.message : String(err);
43
- }
44
- checks.push({
45
- label: "Daemon status",
46
- ok: daemonRunning,
47
- ...daemonRunning ? {} : {
48
- warn: true,
49
- detail: daemonCheckError ? `check failed: ${daemonCheckError}` : "stopped (starts automatically on MCP connect)"
50
- }
51
- });
52
- const ok = checks.every((c) => c.ok || c.warn === true);
53
- return { checks, ok };
54
- }
55
- async function checkLearnMcpHealth(deps) {
56
- const checks = [];
57
- const mcpJson = deps.readMcpJson();
58
- const servers = mcpJson?.mcpServers;
59
- const hasEntry = servers != null && typeof servers === "object" && !Array.isArray(servers) && "coding-friend-learn" in servers;
60
- checks.push({
61
- label: "Config (.mcp.json)",
62
- ok: hasEntry,
63
- ...hasEntry ? {} : {
64
- detail: "coding-friend-learn not configured",
65
- fix: 'Run "cf mcp" to print the config snippet and add it'
66
- }
67
- });
68
- const distExists = deps.pathExists(deps.learnMcpDistPath);
69
- checks.push({
70
- label: "Package built",
71
- ok: distExists,
72
- ...distExists ? {} : {
73
- detail: "learn-mcp not built",
74
- fix: 'Run "cf mcp" to install and build'
75
- }
76
- });
77
- const mdFiles = deps.listMdFiles(deps.docsDir);
78
- const hasDocs = mdFiles.length > 0;
79
- checks.push({
80
- label: "Docs directory",
81
- ok: hasDocs,
82
- ...hasDocs ? {} : {
83
- detail: `No .md files found in ${deps.docsDir}`,
84
- fix: 'Run "/cf-learn" to generate docs'
85
- }
86
- });
87
- const ok = checks.every((c) => c.ok || c.warn === true);
88
- return { checks, ok };
89
- }
90
-
91
- // src/lib/fs-utils.ts
92
- import { readdirSync } from "fs";
93
- import { join } from "path";
94
- function listMdFilesRecursive(dir, maxDepth = 15) {
95
- try {
96
- const results = [];
97
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
98
- if (entry.isDirectory()) {
99
- if (maxDepth > 0) {
100
- results.push(
101
- ...listMdFilesRecursive(join(dir, entry.name), maxDepth - 1)
102
- );
103
- }
104
- } else if (entry.name.endsWith(".md") && entry.name !== "README.md") {
105
- results.push(entry.name);
106
- }
107
- }
108
- return results;
109
- } catch {
110
- return [];
111
- }
112
- }
113
-
114
- export {
115
- checkMemoryMcpHealth,
116
- checkLearnMcpHealth,
117
- listMdFilesRecursive
118
- };
@@ -1,85 +0,0 @@
1
- import {
2
- writeMemoryMcpEntry
3
- } from "./chunk-QCKIBJF6.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
- };