coding-friend-cli 1.21.1 → 1.23.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 (40) hide show
  1. package/dist/{chunk-PDVSGGH6.js → chunk-2ETE7NEL.js} +32 -28
  2. package/dist/{chunk-PYTEAC6K.js → chunk-DMJCO6LJ.js} +1 -1
  3. package/dist/{chunk-3KXYEC2T.js → chunk-LTHJTWJ6.js} +82 -3
  4. package/dist/chunk-NREZK463.js +41 -0
  5. package/dist/{chunk-BIX7AJU3.js → chunk-O4CNZB5H.js} +1 -1
  6. package/dist/{memory-27ZSRPM7.js → chunk-WCSNAEOF.js} +155 -73
  7. package/dist/{config-5I3XJEEL.js → config-5DKOGWWJ.js} +9 -14
  8. package/dist/{dev-4A5CTBGK.js → dev-S7S3SFKI.js} +19 -18
  9. package/dist/{disable-FNMRPUO7.js → disable-V7OLXEUH.js} +2 -2
  10. package/dist/{enable-HUKTMK5U.js → enable-OLHRKZCV.js} +2 -2
  11. package/dist/{host-V5O3PDCF.js → host-RR6FT7AX.js} +7 -6
  12. package/dist/index.js +31 -31
  13. package/dist/{init-3XMC6YJI.js → init-6B2OHKFX.js} +22 -40
  14. package/dist/{install-5ZBHH2OM.js → install-BURZ5QEM.js} +7 -6
  15. package/dist/mcp-CB4PUUES.js +156 -0
  16. package/dist/memory-TJZNGTOA.js +37 -0
  17. package/dist/{permission-BEC6YZQA.js → permission-QIJLEMJ6.js} +4 -3
  18. package/dist/postinstall.js +2 -2
  19. package/dist/{session-ZDJ2APGL.js → session-IECOM63R.js} +1 -1
  20. package/dist/{status-F6WASK7N.js → status-ZZRJ3VGF.js} +7 -7
  21. package/dist/{statusline-AISH77XP.js → statusline-YL44XYGF.js} +4 -3
  22. package/dist/{uninstall-RJ6SBB76.js → uninstall-OXWRPWYF.js} +7 -6
  23. package/dist/{update-536C3YG7.js → update-6N7EASFT.js} +4 -4
  24. package/dist/{update-check-L5TNWT2J.js → update-check-XSETLRVR.js} +1 -1
  25. package/lib/cf-memory/README.md +4 -1
  26. package/lib/cf-memory/package.json +0 -1
  27. package/lib/cf-memory/src/__tests__/daemon-client.test.ts +146 -0
  28. package/lib/cf-memory/src/daemon/process.ts +7 -0
  29. package/lib/cf-memory/src/index.ts +21 -2
  30. package/lib/cf-memory/src/lib/daemon-client.ts +54 -3
  31. package/lib/cf-memory/src/lib/tier.ts +27 -3
  32. package/lib/learn-host/package.json +0 -1
  33. package/lib/learn-mcp/package.json +0 -1
  34. package/lib/learn-mcp/src/index.ts +8 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-W5CD7WTX.js +0 -15
  37. package/dist/mcp-U34LFD34.js +0 -106
  38. package/lib/cf-memory/CHANGELOG.md +0 -42
  39. package/lib/learn-host/CHANGELOG.md +0 -35
  40. package/lib/learn-mcp/CHANGELOG.md +0 -16
@@ -4,19 +4,20 @@ import {
4
4
  editMemoryDaemonTimeout,
5
5
  editMemoryEmbedding,
6
6
  editMemoryTier,
7
- memoryConfigMenu
8
- } from "./chunk-3KXYEC2T.js";
7
+ getMemoryMcpStatus,
8
+ memoryConfigMenu,
9
+ writeMemoryMcpEntry
10
+ } from "./chunk-LTHJTWJ6.js";
11
+ import {
12
+ getLibPath
13
+ } from "./chunk-RZRT7NGT.js";
9
14
  import {
10
15
  loadConfig,
11
16
  resolveMemoryDir
12
17
  } from "./chunk-SIQJPT47.js";
13
- import {
14
- getLibPath
15
- } from "./chunk-RZRT7NGT.js";
16
- import "./chunk-PRIH34UB.js";
17
18
  import {
18
19
  showConfigHint
19
- } from "./chunk-BIX7AJU3.js";
20
+ } from "./chunk-O4CNZB5H.js";
20
21
  import {
21
22
  run,
22
23
  runWithStderr
@@ -29,8 +30,9 @@ import {
29
30
  localConfigPath
30
31
  } from "./chunk-DO6FV6BL.js";
31
32
  import {
32
- log
33
- } from "./chunk-W5CD7WTX.js";
33
+ log,
34
+ printBanner
35
+ } from "./chunk-NREZK463.js";
34
36
 
35
37
  // src/commands/memory.ts
36
38
  import { existsSync, readdirSync, statSync, rmSync } from "fs";
@@ -62,7 +64,7 @@ function truncateError(text) {
62
64
  const skipped = lines.length - 28;
63
65
  return [...head, ` ... (${skipped} lines omitted) ...`, ...tail].join("\n");
64
66
  }
65
- function ensureBuilt(mcpDir) {
67
+ function ensureMemoryBuilt(mcpDir) {
66
68
  if (!existsSync(join(mcpDir, "node_modules"))) {
67
69
  log.step("Installing memory server dependencies (one-time setup)...");
68
70
  const result = runWithStderr("npm", ["install"], { cwd: mcpDir });
@@ -84,6 +86,77 @@ function ensureBuilt(mcpDir) {
84
86
  log.success("Done.");
85
87
  }
86
88
  }
89
+ function printMemoryMcpConfig(serverPath, memoryDir) {
90
+ console.log(chalk.dim("Add this to your MCP client config:"));
91
+ console.log();
92
+ console.log(
93
+ chalk.yellow.bold("--- Claude Code (.mcp.json in project root) ---")
94
+ );
95
+ console.log(`
96
+ {
97
+ "mcpServers": {
98
+ "coding-friend-memory": {
99
+ "command": "node",
100
+ "args": ["${serverPath}", "${memoryDir}"]
101
+ }
102
+ }
103
+ }`);
104
+ console.log();
105
+ console.log(
106
+ chalk.yellow.bold(
107
+ "--- Claude Desktop / Claude Chat (claude_desktop_config.json) ---"
108
+ )
109
+ );
110
+ console.log(`
111
+ {
112
+ "mcpServers": {
113
+ "coding-friend-memory": {
114
+ "command": "node",
115
+ "args": ["${serverPath}", "${memoryDir}"]
116
+ }
117
+ }
118
+ }`);
119
+ console.log();
120
+ console.log(chalk.yellow.bold("--- Generic MCP client ---"));
121
+ console.log(`
122
+ Server command: node ${serverPath} ${memoryDir}
123
+ Transport: stdio`);
124
+ console.log();
125
+ console.log(chalk.yellow.bold("--- Available tools ---"));
126
+ console.log();
127
+ console.log(
128
+ ` ${chalk.white("memory_store")} ${chalk.dim("Store a new memory")}`
129
+ );
130
+ console.log(
131
+ ` ${chalk.white("memory_search")} ${chalk.dim("Search memories (keyword match)")}`
132
+ );
133
+ console.log(
134
+ ` ${chalk.white("memory_retrieve")} ${chalk.dim("Get a specific memory by ID")}`
135
+ );
136
+ console.log(
137
+ ` ${chalk.white("memory_list")} ${chalk.dim("List memories with filtering")}`
138
+ );
139
+ console.log(
140
+ ` ${chalk.white("memory_update")} ${chalk.dim("Update existing memory")}`
141
+ );
142
+ console.log(
143
+ ` ${chalk.white("memory_delete")} ${chalk.dim("Delete a memory")}`
144
+ );
145
+ console.log();
146
+ console.log(chalk.yellow.bold("--- Resources ---"));
147
+ console.log();
148
+ console.log(
149
+ ` ${chalk.white("memory://index")} ${chalk.dim("Browse all memories")}`
150
+ );
151
+ console.log(
152
+ ` ${chalk.white("memory://stats")} ${chalk.dim("Storage statistics")}`
153
+ );
154
+ console.log();
155
+ log.warn(
156
+ "Note: The memory path is project-specific. Use local .mcp.json (per project), not global ~/.claude/.mcp.json."
157
+ );
158
+ console.log();
159
+ }
87
160
  function formatUptime(seconds) {
88
161
  if (seconds < 60) return `${Math.round(seconds)}s`;
89
162
  if (seconds < 3600) return `${Math.round(seconds / 60)}m`;
@@ -93,7 +166,7 @@ async function memoryStatusCommand() {
93
166
  const memoryDir = getMemoryDir();
94
167
  const docCount = countMdFiles(memoryDir);
95
168
  const mcpDir = getLibPath("cf-memory");
96
- ensureBuilt(mcpDir);
169
+ ensureMemoryBuilt(mcpDir);
97
170
  const { isDaemonRunning, getDaemonInfo } = await import(join(mcpDir, "dist/daemon/process.js"));
98
171
  const { areSqliteDepsAvailable } = await import(join(mcpDir, "dist/lib/lazy-install.js"));
99
172
  const sqliteAvailable = areSqliteDepsAvailable();
@@ -107,7 +180,7 @@ async function memoryStatusCommand() {
107
180
  } else {
108
181
  tierLabel = chalk.cyan("Tier 3 (Markdown)");
109
182
  }
110
- console.log("=== \u{1F9E0} Coding Friend Memory ===");
183
+ printBanner("\u{1F9E0} Coding Friend Memory");
111
184
  console.log();
112
185
  log.info(`Tier: ${tierLabel}`);
113
186
  log.info(`Memory dir: ${chalk.cyan(memoryDir)}`);
@@ -140,6 +213,20 @@ async function memoryStatusCommand() {
140
213
  const model = embeddingConfig.model ?? (provider === "ollama" ? "all-minilm:l6-v2" : "Xenova/all-MiniLM-L6-v2");
141
214
  log.info(`Embedding: ${chalk.cyan(model)} ${chalk.dim(`(${provider})`)}`);
142
215
  }
216
+ const mcpStatus = getMemoryMcpStatus();
217
+ if (mcpStatus.configured && mcpStatus.scope === "local") {
218
+ log.info(
219
+ `MCP: ${chalk.green("configured")} ${chalk.dim("(local .mcp.json)")}`
220
+ );
221
+ } else if (mcpStatus.configured && mcpStatus.scope === "global") {
222
+ 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")}`
224
+ );
225
+ } else {
226
+ log.info(
227
+ `MCP: ${chalk.dim("not configured")} ${chalk.dim('(run "cf memory init" or add manually via "cf memory mcp")')}`
228
+ );
229
+ }
143
230
  const autoCapture = config.memory?.autoCapture ?? false;
144
231
  log.info(
145
232
  `Auto-capture: ${autoCapture ? chalk.green("on") : chalk.dim("off")}`
@@ -165,7 +252,7 @@ async function memorySearchCommand(query) {
165
252
  process.exit(1);
166
253
  }
167
254
  const mcpDir = getLibPath("cf-memory");
168
- ensureBuilt(mcpDir);
255
+ ensureMemoryBuilt(mcpDir);
169
256
  const result = run(
170
257
  "node",
171
258
  [
@@ -205,7 +292,7 @@ async function memoryListCommand(opts) {
205
292
  return;
206
293
  }
207
294
  const mcpDir = getLibPath("cf-memory");
208
- ensureBuilt(mcpDir);
295
+ ensureMemoryBuilt(mcpDir);
209
296
  const result = run(
210
297
  "node",
211
298
  [
@@ -246,7 +333,7 @@ async function memoryListCommand(opts) {
246
333
  async function memoryStartDaemonCommand() {
247
334
  const memoryDir = getMemoryDir();
248
335
  const mcpDir = getLibPath("cf-memory");
249
- ensureBuilt(mcpDir);
336
+ ensureMemoryBuilt(mcpDir);
250
337
  const { isDaemonRunning, getDaemonInfo, spawnDaemon } = await import(join(mcpDir, "dist/daemon/process.js"));
251
338
  if (await isDaemonRunning()) {
252
339
  const info = getDaemonInfo();
@@ -256,7 +343,8 @@ async function memoryStartDaemonCommand() {
256
343
  log.step("Starting memory daemon...");
257
344
  const config = loadConfig();
258
345
  const embedding = config.memory?.embedding;
259
- const result = await spawnDaemon(memoryDir, embedding);
346
+ const idleTimeoutMs = config.memory?.daemon?.idleTimeout;
347
+ const result = await spawnDaemon(memoryDir, embedding, { idleTimeoutMs });
260
348
  if (result) {
261
349
  log.success(`Daemon started (PID ${result.pid})`);
262
350
  log.info(`Watching ${chalk.cyan(memoryDir)} for changes`);
@@ -267,7 +355,7 @@ async function memoryStartDaemonCommand() {
267
355
  }
268
356
  async function memoryStopDaemonCommand() {
269
357
  const mcpDir = getLibPath("cf-memory");
270
- ensureBuilt(mcpDir);
358
+ ensureMemoryBuilt(mcpDir);
271
359
  const { stopDaemon, isDaemonRunning } = await import(join(mcpDir, "dist/daemon/process.js"));
272
360
  if (!await isDaemonRunning()) {
273
361
  log.info("Daemon is not running.");
@@ -284,7 +372,7 @@ async function memoryStopDaemonCommand() {
284
372
  async function memoryRebuildCommand() {
285
373
  const memoryDir = getMemoryDir();
286
374
  const mcpDir = getLibPath("cf-memory");
287
- ensureBuilt(mcpDir);
375
+ ensureMemoryBuilt(mcpDir);
288
376
  const { areSqliteDepsAvailable } = await import(join(mcpDir, "dist/lib/lazy-install.js"));
289
377
  if (areSqliteDepsAvailable()) {
290
378
  log.step("Rebuilding SQLite index + embeddings...");
@@ -345,7 +433,6 @@ function getDbPath(memoryDir) {
345
433
  return null;
346
434
  }
347
435
  }
348
- var em = chalk.hex("#10b981");
349
436
  async function ensureSqliteDepsIfNeeded(mcpDir) {
350
437
  const config = loadConfig();
351
438
  const tier = config.memory?.tier ?? "auto";
@@ -369,10 +456,38 @@ async function ensureSqliteDepsIfNeeded(mcpDir) {
369
456
  log.success("Dependencies installed.");
370
457
  return true;
371
458
  }
459
+ async function setupMemoryMcp(memoryDir, mcpDir) {
460
+ const mcpStatus = getMemoryMcpStatus();
461
+ if (mcpStatus.configured && mcpStatus.scope === "local") {
462
+ log.info(`MCP: ${chalk.green("already configured")} in .mcp.json`);
463
+ return;
464
+ }
465
+ console.log();
466
+ log.step("MCP setup");
467
+ log.dim(
468
+ "The Memory MCP connects Claude Code to the memory system so skills can store and search memories."
469
+ );
470
+ const addMcp = await confirm({
471
+ message: "Add coding-friend-memory to .mcp.json?",
472
+ default: true
473
+ });
474
+ if (!addMcp) {
475
+ log.dim('Skipped. Run "cf memory mcp" anytime to get the config.');
476
+ return;
477
+ }
478
+ const serverPath = join(mcpDir, "dist", "index.js");
479
+ if (!existsSync(serverPath)) {
480
+ log.warn(
481
+ "cf-memory not built yet. Run `cf memory mcp` after building to get the config."
482
+ );
483
+ return;
484
+ }
485
+ writeMemoryMcpEntry(serverPath, memoryDir);
486
+ }
372
487
  async function memoryInitCommand() {
373
488
  const memoryDir = getMemoryDir();
374
489
  const mcpDir = getLibPath("cf-memory");
375
- ensureBuilt(mcpDir);
490
+ ensureMemoryBuilt(mcpDir);
376
491
  const dbExists = getDbPath(memoryDir) !== null;
377
492
  if (dbExists) {
378
493
  console.log();
@@ -386,12 +501,7 @@ async function memoryInitCommand() {
386
501
  return;
387
502
  }
388
503
  console.log();
389
- console.log(em(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
390
- console.log(
391
- em(" \u2502 ") + "\u{1F9E0}" + em(" ") + chalk.bold.white("Memory Setup") + em(" \u2502")
392
- );
393
- console.log(em(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
394
- console.log(em(" \u2570\u2500\u25B8"));
504
+ printBanner("\u{1F9E0} Memory Setup");
395
505
  console.log();
396
506
  showConfigHint();
397
507
  log.step("Step 1/5: Search tier");
@@ -427,12 +537,14 @@ async function memoryInitCommand() {
427
537
  const config = loadConfig();
428
538
  const tier = config.memory?.tier ?? "auto";
429
539
  if (tier === "markdown") {
540
+ await setupMemoryMcp(memoryDir, mcpDir);
430
541
  log.success(
431
542
  'Memory initialized with Tier 3 (markdown). Run "cf memory status" to verify.'
432
543
  );
433
544
  return;
434
545
  }
435
546
  if (tier === "lite") {
547
+ await setupMemoryMcp(memoryDir, mcpDir);
436
548
  log.success(
437
549
  'Memory initialized. Run "cf memory start-daemon" to enable Tier 2 search.'
438
550
  );
@@ -444,12 +556,14 @@ async function memoryInitCommand() {
444
556
  log.info(
445
557
  "No memory directory found. Memories will be indexed as they're created."
446
558
  );
559
+ await setupMemoryMcp(memoryDir, mcpDir);
447
560
  log.success('Memory initialized. Run "cf memory status" to verify.');
448
561
  return;
449
562
  }
450
563
  const docCount = countMdFiles(memoryDir);
451
564
  if (docCount === 0) {
452
565
  log.info("No existing memories to import.");
566
+ await setupMemoryMcp(memoryDir, mcpDir);
453
567
  log.success('Memory initialized. Run "cf memory status" to verify.');
454
568
  return;
455
569
  }
@@ -470,6 +584,7 @@ async function memoryInitCommand() {
470
584
  } finally {
471
585
  await backend.close();
472
586
  }
587
+ await setupMemoryMcp(memoryDir, mcpDir);
473
588
  console.log();
474
589
  log.success('Memory initialized! Run "cf memory status" to verify.');
475
590
  log.info(
@@ -478,12 +593,7 @@ async function memoryInitCommand() {
478
593
  }
479
594
  async function memoryConfigCommand() {
480
595
  console.log();
481
- console.log(em(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
482
- console.log(
483
- em(" \u2502 ") + "\u{1F9E0}" + em(" ") + chalk.bold.white("Memory Config") + em(" \u2502")
484
- );
485
- console.log(em(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
486
- console.log(em(" \u2570\u2500\u25B8"));
596
+ printBanner("\u{1F9E0} Memory Config");
487
597
  console.log();
488
598
  showConfigHint();
489
599
  await memoryConfigMenu({ exitLabel: "Done" });
@@ -569,7 +679,7 @@ function getProjectInfo(projectDir, projectId, mcpDir, knownSourceDir) {
569
679
  async function memoryListProjectsCommand() {
570
680
  const baseDir = getProjectsBaseDir();
571
681
  const mcpDir = getLibPath("cf-memory");
572
- ensureBuilt(mcpDir);
682
+ ensureMemoryBuilt(mcpDir);
573
683
  if (!existsSync(baseDir)) {
574
684
  log.info("No memory projects found.");
575
685
  log.dim('Run "cf memory init" in a project to create one.');
@@ -623,7 +733,7 @@ async function memoryRmCommand(opts) {
623
733
  }
624
734
  if (opts.prune) {
625
735
  const mcpDir = getLibPath("cf-memory");
626
- ensureBuilt(mcpDir);
736
+ ensureMemoryBuilt(mcpDir);
627
737
  const dirs = readdirSync(baseDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
628
738
  const orphaned = [];
629
739
  for (const id of dirs) {
@@ -740,50 +850,22 @@ async function memoryRmCommand(opts) {
740
850
  async function memoryMcpCommand() {
741
851
  const memoryDir = getMemoryDir();
742
852
  const mcpDir = getLibPath("cf-memory");
743
- ensureBuilt(mcpDir);
853
+ ensureMemoryBuilt(mcpDir);
744
854
  const serverPath = join(mcpDir, "dist", "index.js");
745
- console.log(`Add this to your MCP client config:
746
-
747
- --- Claude Desktop / Claude Chat (claude_desktop_config.json) ---
748
-
749
- {
750
- "mcpServers": {
751
- "coding-friend-memory": {
752
- "command": "node",
753
- "args": ["${serverPath}", "${memoryDir}"]
754
- }
755
- }
855
+ printMemoryMcpConfig(serverPath, memoryDir);
756
856
  }
757
857
 
758
- --- Generic MCP client ---
759
-
760
- Server command: node ${serverPath} ${memoryDir}
761
- Transport: stdio
762
-
763
- --- Available tools ---
764
-
765
- memory_store Store a new memory
766
- memory_search Search memories (keyword match)
767
- memory_retrieve Get a specific memory by ID
768
- memory_list List memories with filtering
769
- memory_update Update existing memory
770
- memory_delete Delete a memory
771
-
772
- --- Resources ---
773
-
774
- memory://index Browse all memories
775
- memory://stats Storage statistics
776
- `);
777
- }
778
858
  export {
779
- memoryConfigCommand,
780
- memoryInitCommand,
859
+ ensureMemoryBuilt,
860
+ printMemoryMcpConfig,
861
+ memoryStatusCommand,
862
+ memorySearchCommand,
781
863
  memoryListCommand,
782
- memoryMcpCommand,
864
+ memoryStartDaemonCommand,
865
+ memoryStopDaemonCommand,
783
866
  memoryRebuildCommand,
867
+ memoryInitCommand,
868
+ memoryConfigCommand,
784
869
  memoryRmCommand,
785
- memorySearchCommand,
786
- memoryStartDaemonCommand,
787
- memoryStatusCommand,
788
- memoryStopDaemonCommand
870
+ memoryMcpCommand
789
871
  };
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  memoryConfigMenu
3
- } from "./chunk-3KXYEC2T.js";
3
+ } from "./chunk-LTHJTWJ6.js";
4
4
  import {
5
5
  getAllRules,
6
6
  getExistingRules
7
7
  } from "./chunk-HEBLANJO.js";
8
8
  import "./chunk-RZRT7NGT.js";
9
+ import "./chunk-SIQJPT47.js";
9
10
  import {
10
11
  findStatuslineHookPath,
11
12
  isStatuslineConfigured,
@@ -21,7 +22,7 @@ import {
21
22
  ensureShellCompletion,
22
23
  hasShellCompletion,
23
24
  removeShellCompletion
24
- } from "./chunk-PYTEAC6K.js";
25
+ } from "./chunk-DMJCO6LJ.js";
25
26
  import {
26
27
  BACK,
27
28
  applyDocsDirChange,
@@ -31,7 +32,7 @@ import {
31
32
  getScopeLabel,
32
33
  injectBackChoice,
33
34
  showConfigHint
34
- } from "./chunk-BIX7AJU3.js";
35
+ } from "./chunk-O4CNZB5H.js";
35
36
  import {
36
37
  run
37
38
  } from "./chunk-EVGXUDX4.js";
@@ -47,8 +48,9 @@ import {
47
48
  resolvePath
48
49
  } from "./chunk-DO6FV6BL.js";
49
50
  import {
50
- log
51
- } from "./chunk-W5CD7WTX.js";
51
+ log,
52
+ printBanner
53
+ } from "./chunk-NREZK463.js";
52
54
 
53
55
  // src/commands/config.ts
54
56
  import { checkbox, confirm, input, select } from "@inquirer/prompts";
@@ -542,7 +544,7 @@ async function editPermissions() {
542
544
  )
543
545
  });
544
546
  if (choice === BACK) return;
545
- const { permissionCommand } = await import("./permission-BEC6YZQA.js");
547
+ const { permissionCommand } = await import("./permission-QIJLEMJ6.js");
546
548
  switch (choice) {
547
549
  case "interactive":
548
550
  await permissionCommand({});
@@ -555,16 +557,9 @@ async function editPermissions() {
555
557
  break;
556
558
  }
557
559
  }
558
- var em = chalk.hex("#10b981");
559
560
  async function configCommand() {
560
561
  console.log();
561
- console.log(em(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
562
- console.log(
563
- em(" \u2502 ") + "\u2726" + em(" ") + chalk.bold.white("Coding Friend") + em(" \u2726 \u2502")
564
- );
565
- console.log(em(" \u2502 ") + chalk.dim("Config") + em(" \u2502"));
566
- console.log(em(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
567
- console.log(em(" \u2570\u2500\u25B8"));
562
+ printBanner("\u2728 Coding Friend Config \u2728");
568
563
  console.log();
569
564
  showConfigHint();
570
565
  while (true) {
@@ -8,7 +8,7 @@ import {
8
8
  import "./chunk-PRIH34UB.js";
9
9
  import {
10
10
  ensureShellCompletion
11
- } from "./chunk-PYTEAC6K.js";
11
+ } from "./chunk-DMJCO6LJ.js";
12
12
  import {
13
13
  commandExists,
14
14
  run
@@ -23,8 +23,9 @@ import {
23
23
  pluginCachePath
24
24
  } from "./chunk-DO6FV6BL.js";
25
25
  import {
26
- log
27
- } from "./chunk-W5CD7WTX.js";
26
+ log,
27
+ printBanner
28
+ } from "./chunk-NREZK463.js";
28
29
 
29
30
  // src/commands/dev.ts
30
31
  import {
@@ -88,12 +89,12 @@ async function devOnCommand(path) {
88
89
  return;
89
90
  }
90
91
  const version = getLocalPluginVersion(localPath);
91
- const versionLabel = version ? ` ${chalk.dim(`(v${version})`)}` : "";
92
- console.log(
93
- `
94
- === ${chalk.green("Switching to local dev mode")}${versionLabel} ===
95
- `
96
- );
92
+ const versionLabel = version ? ` (v${version})` : "";
93
+ console.log();
94
+ printBanner(`Switching to local dev mode${versionLabel}`, {
95
+ color: chalk.green
96
+ });
97
+ console.log();
97
98
  log.info(`Local path: ${chalk.cyan(localPath)}`);
98
99
  if (isPluginInstalled()) {
99
100
  if (!runClaude(
@@ -145,11 +146,11 @@ async function devOffCommand() {
145
146
  return;
146
147
  }
147
148
  if (!ensureClaude()) return;
148
- console.log(
149
- `
150
- === ${chalk.yellow("Switching back to remote marketplace")} ===
151
- `
152
- );
149
+ console.log();
150
+ printBanner("Switching back to remote marketplace", {
151
+ color: chalk.yellow
152
+ });
153
+ console.log();
153
154
  if (isPluginInstalled()) {
154
155
  if (!runClaude(
155
156
  ["plugin", "uninstall", PLUGIN_ID],
@@ -265,10 +266,10 @@ async function devReinstall(path, label) {
265
266
  if (!ensureClaude()) return;
266
267
  const localPath = path ?? state?.localPath;
267
268
  const version = localPath ? getLocalPluginVersion(localPath) : null;
268
- const versionLabel = version ? ` ${chalk.dim(`(v${version})`)}` : "";
269
- console.log(`
270
- === ${chalk.cyan(label)}${versionLabel} ===
271
- `);
269
+ const bannerTitle = version ? `${label} (v${version})` : label;
270
+ console.log();
271
+ printBanner(bannerTitle, { color: chalk.cyan });
272
+ console.log();
272
273
  if (state) {
273
274
  await devOffCommand();
274
275
  console.log();
@@ -4,13 +4,13 @@ import {
4
4
  } from "./chunk-5UEY7HQX.js";
5
5
  import {
6
6
  resolveScope
7
- } from "./chunk-BIX7AJU3.js";
7
+ } from "./chunk-O4CNZB5H.js";
8
8
  import "./chunk-EVGXUDX4.js";
9
9
  import "./chunk-5UVDWG5L.js";
10
10
  import "./chunk-DO6FV6BL.js";
11
11
  import {
12
12
  log
13
- } from "./chunk-W5CD7WTX.js";
13
+ } from "./chunk-NREZK463.js";
14
14
 
15
15
  // src/commands/disable.ts
16
16
  import chalk from "chalk";
@@ -4,13 +4,13 @@ import {
4
4
  } from "./chunk-5UEY7HQX.js";
5
5
  import {
6
6
  resolveScope
7
- } from "./chunk-BIX7AJU3.js";
7
+ } from "./chunk-O4CNZB5H.js";
8
8
  import "./chunk-EVGXUDX4.js";
9
9
  import "./chunk-5UVDWG5L.js";
10
10
  import "./chunk-DO6FV6BL.js";
11
11
  import {
12
12
  log
13
- } from "./chunk-W5CD7WTX.js";
13
+ } from "./chunk-NREZK463.js";
14
14
 
15
15
  // src/commands/enable.ts
16
16
  import chalk from "chalk";
@@ -1,9 +1,9 @@
1
- import {
2
- resolveDocsDir
3
- } from "./chunk-SIQJPT47.js";
4
1
  import {
5
2
  getLibPath
6
3
  } from "./chunk-RZRT7NGT.js";
4
+ import {
5
+ resolveDocsDir
6
+ } from "./chunk-SIQJPT47.js";
7
7
  import "./chunk-PRIH34UB.js";
8
8
  import {
9
9
  run,
@@ -12,8 +12,9 @@ import {
12
12
  import "./chunk-5UVDWG5L.js";
13
13
  import "./chunk-DO6FV6BL.js";
14
14
  import {
15
- log
16
- } from "./chunk-W5CD7WTX.js";
15
+ log,
16
+ printBanner
17
+ } from "./chunk-NREZK463.js";
17
18
 
18
19
  // src/commands/host.ts
19
20
  import { existsSync, readdirSync } from "fs";
@@ -50,7 +51,7 @@ async function hostCommand(path, opts) {
50
51
  process.exit(1);
51
52
  }
52
53
  const catCount = countCategories(docsDir);
53
- console.log("=== \u{1F33F} Coding Friend Host \u{1F33F} ===");
54
+ printBanner("\u2728 Coding Friend Host \u2728");
54
55
  log.info(`Docs folder: ${docsDir}`);
55
56
  log.info(`Found: ${docCount} docs in ${catCount} categories`);
56
57
  console.log();