coding-friend-cli 1.33.1 → 1.34.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,6 +1,6 @@
1
1
  import {
2
2
  resolveMemoryDir
3
- } from "./chunk-LK6HFD35.js";
3
+ } from "./chunk-AZ6AK5M4.js";
4
4
  import {
5
5
  getLibPath
6
6
  } from "./chunk-RZRT7NGT.js";
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  memoryConfigMenu
3
- } from "./chunk-NZKIYVIK.js";
3
+ } from "./chunk-QCKIBJF6.js";
4
+ import "./chunk-AZ6AK5M4.js";
5
+ import "./chunk-RZRT7NGT.js";
4
6
  import {
5
7
  findStatuslineHookPath,
6
8
  getCurrentAccountEmail,
@@ -11,11 +13,11 @@ import {
11
13
  saveStatuslineConfig,
12
14
  selectStatuslineComponents,
13
15
  writeStatuslineSettings
14
- } from "./chunk-XOHLBLN2.js";
16
+ } from "./chunk-LXZ47XCD.js";
15
17
  import {
16
18
  ALL_COMPONENT_IDS,
17
19
  DEFAULT_CONFIG
18
- } from "./chunk-OYPOADCX.js";
20
+ } from "./chunk-DHH6SRXV.js";
19
21
  import {
20
22
  ensureShellCompletion,
21
23
  hasShellCompletion,
@@ -411,68 +413,6 @@ async function editAutoApprove(globalCfg, localCfg) {
411
413
  log.dim("Docs: https://cf.dinhanhthi.com/docs/reference/auto-approve/");
412
414
  }
413
415
  }
414
- function buildCodexConfig(input2) {
415
- return {
416
- enabled: input2.enabled,
417
- modes: input2.modes,
418
- effort: input2.effort
419
- };
420
- }
421
- async function editCodex(globalCfg, localCfg) {
422
- const current = localCfg?.codex ?? globalCfg?.codex;
423
- const defaults = DEFAULT_CONFIG.codex;
424
- if (current !== void 0) {
425
- log.dim(
426
- `Current: enabled=${current.enabled}, modes=${(current.modes ?? []).join(",") || "(none)"}, effort=${current.effort}`
427
- );
428
- }
429
- const enabled = await confirm({
430
- message: "Enable Codex as 6th specialist in /cf-review? (requires `codex` CLI in PATH)",
431
- default: current?.enabled ?? defaults.enabled
432
- });
433
- const modes = await checkbox({
434
- message: "Which review modes should Codex run in?",
435
- choices: [
436
- { name: "QUICK (\u22643 files, \u226450 lines)", value: "QUICK" },
437
- { name: "STANDARD (4\u201310 files or 51\u2013300 lines)", value: "STANDARD" },
438
- {
439
- name: "DEEP (>10 files, >300 lines, or sensitive paths)",
440
- value: "DEEP"
441
- }
442
- ],
443
- default: current?.modes ?? defaults.modes
444
- });
445
- if (modes.length === 0) {
446
- log.dim(
447
- "Warning: no modes selected \u2014 Codex will never run. Select at least one mode."
448
- );
449
- }
450
- const effort = await select({
451
- message: "Codex reasoning effort level:",
452
- choices: [
453
- { name: "minimal \u2014 fastest, least thorough", value: "minimal" },
454
- { name: "low", value: "low" },
455
- { name: "medium (default)", value: "medium" },
456
- { name: "high", value: "high" },
457
- { name: "xhigh \u2014 slowest, most thorough", value: "xhigh" }
458
- ],
459
- default: current?.effort ?? defaults.effort
460
- });
461
- const scope = await askScope();
462
- if (scope === "back") return;
463
- const codexCfg = buildCodexConfig({ enabled, modes, effort });
464
- writeToScope(scope, { codex: codexCfg });
465
- if (enabled) {
466
- log.dim(
467
- "Tip: make sure `codex` CLI is installed \u2014 `npm install -g @openai/codex`"
468
- );
469
- log.dim(
470
- "Docs: https://cf.dinhanhthi.com/docs/configuration/config-json/#codex"
471
- );
472
- } else {
473
- log.dim("Codex disabled.");
474
- }
475
- }
476
416
  async function editStatusline() {
477
417
  const hookResult = findStatuslineHookPath();
478
418
  if (!hookResult) {
@@ -686,8 +626,6 @@ async function configCommand() {
686
626
  globalCfg,
687
627
  localCfg
688
628
  );
689
- const codexScope = getScopeLabel("codex", globalCfg, localCfg);
690
- const codexEnabled = getMergedValue("codex", globalCfg, localCfg)?.enabled;
691
629
  const statuslineStatus = isStatuslineConfigured() ? chalk.green("configured") : chalk.yellow("not configured");
692
630
  const completionStatus = hasShellCompletion() ? chalk.green("installed") : chalk.yellow("not installed");
693
631
  const projectRules = getExistingRules(claudeLocalSettingsPath());
@@ -728,11 +666,6 @@ async function configCommand() {
728
666
  value: "autoApprove",
729
667
  description: " Auto-approve safe tool calls, block destructive ones, prompt for ambiguous"
730
668
  },
731
- {
732
- name: `Codex cross-engine review ${formatScopeLabel(codexScope)}${codexEnabled !== void 0 ? ` (${codexEnabled ? "enabled" : "disabled"})` : ""}`,
733
- value: "codex",
734
- description: " Enable OpenAI Codex as 6th specialist in /cf-review (opt-in)"
735
- },
736
669
  {
737
670
  name: `Statusline (${statuslineStatus})`,
738
671
  value: "statusline",
@@ -776,9 +709,6 @@ async function configCommand() {
776
709
  case "autoApprove":
777
710
  await editAutoApprove(globalCfg, localCfg);
778
711
  break;
779
- case "codex":
780
- await editCodex(globalCfg, localCfg);
781
- break;
782
712
  case "statusline":
783
713
  await editStatusline();
784
714
  break;
@@ -795,9 +725,6 @@ async function configCommand() {
795
725
  console.log();
796
726
  }
797
727
  }
798
-
799
728
  export {
800
- buildCodexConfig,
801
- editCodex,
802
729
  configCommand
803
730
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureStatusline
3
- } from "./chunk-XOHLBLN2.js";
4
- import "./chunk-OYPOADCX.js";
3
+ } from "./chunk-LXZ47XCD.js";
4
+ import "./chunk-DHH6SRXV.js";
5
5
  import {
6
6
  ensureShellCompletion
7
7
  } from "./chunk-DMJCO6LJ.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  resolveDocsDir
3
- } from "./chunk-LK6HFD35.js";
3
+ } from "./chunk-AZ6AK5M4.js";
4
4
  import {
5
5
  getLibPath
6
6
  } from "./chunk-RZRT7NGT.js";
7
- import "./chunk-OYPOADCX.js";
7
+ import "./chunk-DHH6SRXV.js";
8
8
  import "./chunk-TWKNGPBO.js";
9
9
  import {
10
10
  run,
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ program.name("cf").description(
14
14
  "coding-friend CLI \u2014 host learning docs, setup MCP, init projects"
15
15
  ).version(pkg.version, "-v, --version");
16
16
  program.command("install").description("Install the Coding Friend plugin into Claude Code").option("--user", "Install at user scope (all projects)").option("--global", "Install at user scope (all projects)").option("--project", "Install at project scope (shared via git)").option("--local", "Install at local scope (this machine only)").action(async (opts) => {
17
- const { installCommand } = await import("./install-FKL6WLIG.js");
17
+ const { installCommand } = await import("./install-22BLHQ6D.js");
18
18
  await installCommand(opts);
19
19
  });
20
20
  program.command("uninstall").description("Uninstall the Coding Friend plugin from Claude Code").option("--user", "Uninstall from user scope (all projects)").option("--global", "Uninstall from user scope (all projects)").option("--project", "Uninstall from project scope").option("--local", "Uninstall from local scope").action(async (opts) => {
@@ -30,19 +30,19 @@ 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-HS4EXSXW.js");
33
+ const { initCommand } = await import("./init-KY3ZPEWP.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-2OJTBZU2.js");
37
+ const { configCommand } = await import("./config-44VQBNMS.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-Y4N4PI4N.js");
41
+ const { hostCommand } = await import("./host-6IBKKCPA.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-BD2K7OL6.js");
45
+ const { mcpCommand } = await import("./mcp-OGZAZZRF.js");
46
46
  await mcpCommand(path);
47
47
  });
48
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) => {
@@ -61,15 +61,15 @@ program.command("permission").description("Manage Claude Code permission rules f
61
61
  await permissionCommand(opts);
62
62
  });
63
63
  program.command("statusline").description("Setup coding-friend statusline in Claude Code").action(async () => {
64
- const { statuslineCommand } = await import("./statusline-MLLKBHHR.js");
64
+ const { statuslineCommand } = await import("./statusline-GKVAX7GR.js");
65
65
  await statuslineCommand();
66
66
  });
67
67
  program.command("update").description("Update coding-friend plugin, CLI, and statusline").option("--cli", "Update only the CLI (npm package)").option("--plugin", "Update only the Claude Code plugin").option("--statusline", "Update only the statusline").option("--user", "Update plugin at user scope (all projects)").option("--global", "Update plugin at user scope (all projects)").option("--project", "Update plugin at project scope").option("--local", "Update plugin at local scope").action(async (opts) => {
68
- const { updateCommand } = await import("./update-G5HZINBK.js");
68
+ const { updateCommand } = await import("./update-P5ZR2JVQ.js");
69
69
  await updateCommand(opts);
70
70
  });
71
71
  program.command("status").description("Show comprehensive Coding Friend status").action(async () => {
72
- const { statusCommand } = await import("./status-V2A7RSSM.js");
72
+ const { statusCommand } = await import("./status-NMSVOSC4.js");
73
73
  await statusCommand();
74
74
  });
75
75
  var session = program.command("session").description("Save and load Claude Code sessions across machines");
@@ -84,11 +84,11 @@ session.command("save").description("Save current Claude Code session to sync fo
84
84
  "-s, --session-id <id>",
85
85
  "session UUID to save (default: auto-detect newest)"
86
86
  ).option("-l, --label <label>", "label for this session").action(async (opts) => {
87
- const { sessionSaveCommand } = await import("./session-RHXTVNRU.js");
87
+ const { sessionSaveCommand } = await import("./session-RCEE6P35.js");
88
88
  await sessionSaveCommand(opts);
89
89
  });
90
90
  session.command("load").description("Load a saved session from sync folder").action(async () => {
91
- const { sessionLoadCommand } = await import("./session-RHXTVNRU.js");
91
+ const { sessionLoadCommand } = await import("./session-RCEE6P35.js");
92
92
  await sessionLoadCommand();
93
93
  });
94
94
  var memory = program.command("memory").description("AI memory system \u2014 store and search project knowledge");
@@ -108,43 +108,43 @@ Memory subcommands:
108
108
  memory mcp Show MCP server setup instructions`
109
109
  );
110
110
  memory.command("status").description("Show memory system status").action(async () => {
111
- const { memoryStatusCommand } = await import("./memory-FZMACIGE.js");
111
+ const { memoryStatusCommand } = await import("./memory-JM45DEIX.js");
112
112
  await memoryStatusCommand();
113
113
  });
114
114
  memory.command("search").description("Search memories by query").argument("<query>", "search query").action(async (query) => {
115
- const { memorySearchCommand } = await import("./memory-FZMACIGE.js");
115
+ const { memorySearchCommand } = await import("./memory-JM45DEIX.js");
116
116
  await memorySearchCommand(query);
117
117
  });
118
118
  memory.command("list").description(
119
119
  "List memories in current project, or all projects with --projects"
120
120
  ).option("--projects", "List all project databases with size and metadata").action(async (opts) => {
121
- const { memoryListCommand } = await import("./memory-FZMACIGE.js");
121
+ const { memoryListCommand } = await import("./memory-JM45DEIX.js");
122
122
  await memoryListCommand(opts);
123
123
  });
124
124
  memory.command("init").description(
125
125
  "Initialize memory system \u2014 interactive wizard (first time) or config menu"
126
126
  ).action(async () => {
127
- const { memoryInitCommand } = await import("./memory-FZMACIGE.js");
127
+ const { memoryInitCommand } = await import("./memory-JM45DEIX.js");
128
128
  await memoryInitCommand();
129
129
  });
130
130
  memory.command("config").description("Configure memory system settings").action(async () => {
131
- const { memoryConfigCommand } = await import("./memory-FZMACIGE.js");
131
+ const { memoryConfigCommand } = await import("./memory-JM45DEIX.js");
132
132
  await memoryConfigCommand();
133
133
  });
134
134
  memory.command("start-daemon").description("Start the memory daemon (Tier 2 \u2014 MiniSearch)").action(async () => {
135
- const { memoryStartDaemonCommand } = await import("./memory-FZMACIGE.js");
135
+ const { memoryStartDaemonCommand } = await import("./memory-JM45DEIX.js");
136
136
  await memoryStartDaemonCommand();
137
137
  });
138
138
  memory.command("stop-daemon").description("Stop the memory daemon").action(async () => {
139
- const { memoryStopDaemonCommand } = await import("./memory-FZMACIGE.js");
139
+ const { memoryStopDaemonCommand } = await import("./memory-JM45DEIX.js");
140
140
  await memoryStopDaemonCommand();
141
141
  });
142
142
  memory.command("rebuild").description("Rebuild the daemon search index").action(async () => {
143
- const { memoryRebuildCommand } = await import("./memory-FZMACIGE.js");
143
+ const { memoryRebuildCommand } = await import("./memory-JM45DEIX.js");
144
144
  await memoryRebuildCommand();
145
145
  });
146
146
  memory.command("mcp").description("Show MCP server setup instructions").action(async () => {
147
- const { memoryMcpCommand } = await import("./memory-FZMACIGE.js");
147
+ const { memoryMcpCommand } = await import("./memory-JM45DEIX.js");
148
148
  await memoryMcpCommand();
149
149
  });
150
150
  memory.command("rm").description("Remove a project database").option("--project-id <id>", "Project ID to remove").option("--all", "Remove all project databases").option(
@@ -152,7 +152,7 @@ memory.command("rm").description("Remove a project database").option("--project-
152
152
  "Remove orphaned projects (source dir missing or 0 memories)"
153
153
  ).action(
154
154
  async (opts) => {
155
- const { memoryRmCommand } = await import("./memory-FZMACIGE.js");
155
+ const { memoryRmCommand } = await import("./memory-JM45DEIX.js");
156
156
  await memoryRmCommand(opts);
157
157
  }
158
158
  );
@@ -178,35 +178,35 @@ Dev subcommands:
178
178
  dev update [path] Update local dev plugin to latest version`
179
179
  );
180
180
  dev.command("on").description("Switch to local plugin source").argument("[path]", "path to local coding-friend repo (default: cwd)").action(async (path) => {
181
- const { devOnCommand } = await import("./dev-S6VZUD33.js");
181
+ const { devOnCommand } = await import("./dev-QXVERU42.js");
182
182
  await devOnCommand(path);
183
183
  });
184
184
  dev.command("off").description("Switch back to remote marketplace").action(async () => {
185
- const { devOffCommand } = await import("./dev-S6VZUD33.js");
185
+ const { devOffCommand } = await import("./dev-QXVERU42.js");
186
186
  await devOffCommand();
187
187
  });
188
188
  dev.command("status").description("Show current dev mode").action(async () => {
189
- const { devStatusCommand } = await import("./dev-S6VZUD33.js");
189
+ const { devStatusCommand } = await import("./dev-QXVERU42.js");
190
190
  await devStatusCommand();
191
191
  });
192
192
  dev.command("sync").description(
193
193
  "Copy local source files to plugin cache (no version bump needed)"
194
194
  ).action(async () => {
195
- const { devSyncCommand } = await import("./dev-S6VZUD33.js");
195
+ const { devSyncCommand } = await import("./dev-QXVERU42.js");
196
196
  await devSyncCommand();
197
197
  });
198
198
  dev.command("restart").description("Reinstall local dev plugin (off + on)").argument(
199
199
  "[path]",
200
200
  "path to local coding-friend repo (default: saved path or cwd)"
201
201
  ).action(async (path) => {
202
- const { devRestartCommand } = await import("./dev-S6VZUD33.js");
202
+ const { devRestartCommand } = await import("./dev-QXVERU42.js");
203
203
  await devRestartCommand(path);
204
204
  });
205
205
  dev.command("update").description("Update local dev plugin to latest version (off + on)").argument(
206
206
  "[path]",
207
207
  "path to local coding-friend repo (default: saved path or cwd)"
208
208
  ).action(async (path) => {
209
- const { devUpdateCommand } = await import("./dev-S6VZUD33.js");
209
+ const { devUpdateCommand } = await import("./dev-QXVERU42.js");
210
210
  await devUpdateCommand(path);
211
211
  });
212
212
  program.hook("postAction", async () => {
@@ -1,15 +1,13 @@
1
- import {
2
- editCodex
3
- } from "./chunk-OV4AUDXL.js";
4
1
  import {
5
2
  ensureMemoryBuilt,
6
3
  isMemoryInitialized,
7
4
  memoryInitWizard
8
- } from "./chunk-G2P43ZK2.js";
5
+ } from "./chunk-FAANBGCB.js";
6
+ import "./chunk-FI5HEQ43.js";
9
7
  import {
10
8
  memoryConfigMenu
11
- } from "./chunk-NZKIYVIK.js";
12
- import "./chunk-LK6HFD35.js";
9
+ } from "./chunk-QCKIBJF6.js";
10
+ import "./chunk-AZ6AK5M4.js";
13
11
  import {
14
12
  getLibPath
15
13
  } from "./chunk-RZRT7NGT.js";
@@ -23,10 +21,10 @@ import {
23
21
  saveStatuslineConfig,
24
22
  selectStatuslineComponents,
25
23
  writeStatuslineSettings
26
- } from "./chunk-XOHLBLN2.js";
24
+ } from "./chunk-LXZ47XCD.js";
27
25
  import {
28
26
  DEFAULT_CONFIG
29
- } from "./chunk-OYPOADCX.js";
27
+ } from "./chunk-DHH6SRXV.js";
30
28
  import {
31
29
  ensureShellCompletion,
32
30
  hasShellCompletion
@@ -744,8 +742,6 @@ async function initMenu(gitAvailable) {
744
742
  globalCfg,
745
743
  localCfg
746
744
  );
747
- const codexScope = getScopeLabel("codex", globalCfg, localCfg);
748
- const codexEnabled = getMergedValue("codex", globalCfg, localCfg)?.enabled;
749
745
  const projectRules = getExistingRules(claudeLocalSettingsPath());
750
746
  const userRules = getExistingRules(claudeSettingsPath());
751
747
  const allRules = getAllRules();
@@ -797,11 +793,6 @@ async function initMenu(gitAvailable) {
797
793
  value: "autoApprove",
798
794
  description: " Auto-approve safe tool calls, block destructive ones, prompt for ambiguous"
799
795
  },
800
- {
801
- name: `Codex cross-engine review ${formatScopeLabel(codexScope)}${codexEnabled !== void 0 ? ` (${codexEnabled ? "enabled" : "disabled"})` : ""}`,
802
- value: "codex",
803
- description: " Enable OpenAI Codex as 6th specialist in /cf-review (opt-in)"
804
- },
805
796
  {
806
797
  name: `Permissions (${permissionStatus} rules)`,
807
798
  value: "permissions",
@@ -870,9 +861,6 @@ async function initMenu(gitAvailable) {
870
861
  }
871
862
  break;
872
863
  }
873
- case "codex":
874
- await editCodex(globalCfg, localCfg);
875
- break;
876
864
  case "permissions": {
877
865
  const learnCfg = localCfg?.learn ?? globalCfg?.learn;
878
866
  const learnOutputDir = learnCfg?.outputDir || `${docsDir}/learn`;
@@ -1013,7 +1001,7 @@ async function initCommand() {
1013
1001
  console.log();
1014
1002
  log.congrats("Setup complete!");
1015
1003
  log.dim(
1016
- "Available commands: /cf-ask, /cf-plan, /cf-fix, /cf-commit, /cf-review, /cf-review-out, /cf-review-in, /cf-ship, /cf-optimize, /cf-scan, /cf-remember, /cf-learn, /cf-teach, /cf-research, /cf-session, /cf-warm, /cf-help"
1004
+ "Available commands: /cf-ask, /cf-plan, /cf-design, /cf-fix, /cf-commit, /cf-review, /cf-review-out, /cf-review-in, /cf-ship, /cf-optimize, /cf-scan, /cf-remember, /cf-learn, /cf-teach, /cf-research, /cf-session, /cf-warm, /cf-help"
1017
1005
  );
1018
1006
  }
1019
1007
  export {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getLatestVersion,
3
3
  semverCompare
4
- } from "./chunk-UGTNIFBH.js";
4
+ } from "./chunk-G4QGJEV7.js";
5
5
  import {
6
6
  getInstalledVersion
7
- } from "./chunk-XOHLBLN2.js";
8
- import "./chunk-OYPOADCX.js";
7
+ } from "./chunk-LXZ47XCD.js";
8
+ import "./chunk-DHH6SRXV.js";
9
9
  import {
10
10
  ensureShellCompletion
11
11
  } from "./chunk-DMJCO6LJ.js";
@@ -1,18 +1,25 @@
1
1
  import {
2
- detectMemoryMcpState,
2
+ checkLearnMcpHealth,
3
+ checkMemoryMcpHealth,
4
+ listMdFilesRecursive
5
+ } from "./chunk-CZDXMFEZ.js";
6
+ import {
3
7
  ensureMemoryBuilt,
4
- printMemoryMcpConfig,
8
+ printMemoryMcpConfig
9
+ } from "./chunk-FAANBGCB.js";
10
+ import {
11
+ detectMemoryMcpState,
5
12
  warnStaleMcpJson
6
- } from "./chunk-G2P43ZK2.js";
7
- import "./chunk-NZKIYVIK.js";
13
+ } from "./chunk-FI5HEQ43.js";
14
+ import "./chunk-QCKIBJF6.js";
8
15
  import {
9
16
  resolveDocsDir,
10
17
  resolveMemoryDir
11
- } from "./chunk-LK6HFD35.js";
18
+ } from "./chunk-AZ6AK5M4.js";
12
19
  import {
13
20
  getLibPath
14
21
  } from "./chunk-RZRT7NGT.js";
15
- import "./chunk-OYPOADCX.js";
22
+ import "./chunk-DHH6SRXV.js";
16
23
  import "./chunk-Z5Q533UG.js";
17
24
  import "./chunk-TWKNGPBO.js";
18
25
  import {
@@ -22,7 +29,9 @@ import {
22
29
  log,
23
30
  printBanner
24
31
  } from "./chunk-NREZK463.js";
25
- import "./chunk-5UVDWG5L.js";
32
+ import {
33
+ readJson
34
+ } from "./chunk-5UVDWG5L.js";
26
35
 
27
36
  // src/commands/mcp.ts
28
37
  import { existsSync, readdirSync } from "fs";
@@ -39,10 +48,28 @@ function countMdFiles(dir) {
39
48
  }
40
49
  return count;
41
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
+ }
42
69
  async function mcpCommand(path) {
43
70
  warnStaleMcpJson(resolveMemoryDir());
44
71
  const docsDir = resolveDocsDir(path);
45
- const mcpDir = getLibPath("learn-mcp");
72
+ const learnMcpDir = getLibPath("learn-mcp");
46
73
  if (!existsSync(docsDir)) {
47
74
  log.error(`Docs folder not found: ${docsDir}`);
48
75
  log.dim("Run /cf-learn first to generate some docs.");
@@ -57,18 +84,20 @@ async function mcpCommand(path) {
57
84
  printBanner("\u{1F4DA} Learn MCP");
58
85
  log.info(`Docs folder: ${chalk.cyan(docsDir)}`);
59
86
  log.info(`Found: ${chalk.green(docCount)} docs`);
60
- if (!existsSync(join(mcpDir, "node_modules"))) {
87
+ if (!existsSync(join(learnMcpDir, "node_modules"))) {
61
88
  log.step("Installing MCP server dependencies (one-time setup)...");
62
- const result = run("npm", ["install", "--silent"], { cwd: mcpDir });
89
+ const result = run("npm", ["install", "--silent"], { cwd: learnMcpDir });
63
90
  if (result === null) {
64
91
  log.error("Failed to install dependencies");
65
92
  process.exit(1);
66
93
  }
67
94
  log.success("Done.");
68
95
  }
69
- if (!existsSync(join(mcpDir, "dist"))) {
96
+ if (!existsSync(join(learnMcpDir, "dist"))) {
70
97
  log.step("Building MCP server...");
71
- const result = run("npm", ["run", "build", "--silent"], { cwd: mcpDir });
98
+ const result = run("npm", ["run", "build", "--silent"], {
99
+ cwd: learnMcpDir
100
+ });
72
101
  if (result === null) {
73
102
  log.error("Failed to build MCP server");
74
103
  process.exit(1);
@@ -96,9 +125,19 @@ async function mcpCommand(path) {
96
125
  "Available tools & resources: https://cf.dinhanhthi.com/docs/cli/cf-mcp/"
97
126
  );
98
127
  console.log();
99
- printMemoryMcp();
128
+ const localMcpPath = join(process.cwd(), ".mcp.json");
129
+ const learnMcpDistPath = join(learnMcpDir, "dist", "index.js");
130
+ const learnHealth = await checkLearnMcpHealth({
131
+ readMcpJson: () => readJson(localMcpPath),
132
+ pathExists: existsSync,
133
+ listMdFiles: listMdFilesRecursive,
134
+ docsDir,
135
+ learnMcpDistPath
136
+ });
137
+ printHealthSection(learnHealth);
138
+ await printMemoryMcp();
100
139
  }
101
- function printMemoryMcp() {
140
+ async function printMemoryMcp() {
102
141
  const memoryDir = resolveMemoryDir();
103
142
  let mcpDir;
104
143
  try {
@@ -115,8 +154,24 @@ function printMemoryMcp() {
115
154
  log.info(`Memory dir: ${chalk.cyan(memoryDir)}`);
116
155
  console.log();
117
156
  printMemoryMcpConfig(memoryDir);
157
+ const localMcpPath = join(process.cwd(), ".mcp.json");
158
+ const memoryDistPath = join(mcpDir, "dist", "index.js");
159
+ let isDaemonRunning = async () => false;
160
+ try {
161
+ const proc = await import(join(mcpDir, "dist/daemon/process.js"));
162
+ isDaemonRunning = proc.isDaemonRunning;
163
+ } catch {
164
+ }
165
+ const memoryHealth = await checkMemoryMcpHealth({
166
+ readMcpJson: () => readJson(localMcpPath),
167
+ pathExists: existsSync,
168
+ isDaemonRunning,
169
+ memoryDistPath
170
+ });
171
+ printHealthSection(memoryHealth);
118
172
  }
119
173
  export {
120
174
  detectMemoryMcpState,
121
- mcpCommand
175
+ mcpCommand,
176
+ printHealthSection
122
177
  };
@@ -13,11 +13,12 @@ import {
13
13
  memoryStatusCommand,
14
14
  memoryStopDaemonCommand,
15
15
  printMemoryMcpConfig
16
- } from "./chunk-G2P43ZK2.js";
17
- import "./chunk-NZKIYVIK.js";
18
- import "./chunk-LK6HFD35.js";
16
+ } from "./chunk-FAANBGCB.js";
17
+ import "./chunk-FI5HEQ43.js";
18
+ import "./chunk-QCKIBJF6.js";
19
+ import "./chunk-AZ6AK5M4.js";
19
20
  import "./chunk-RZRT7NGT.js";
20
- import "./chunk-OYPOADCX.js";
21
+ import "./chunk-DHH6SRXV.js";
21
22
  import "./chunk-Z5Q533UG.js";
22
23
  import "./chunk-TWKNGPBO.js";
23
24
  import "./chunk-EVGXUDX4.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-LK6HFD35.js";
4
- import "./chunk-OYPOADCX.js";
3
+ } from "./chunk-AZ6AK5M4.js";
4
+ import "./chunk-DHH6SRXV.js";
5
5
  import {
6
6
  claudeSessionDir,
7
7
  encodeProjectPath,