coding-friend-cli 1.22.0 → 1.24.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/dist/{chunk-PDVSGGH6.js → chunk-2ETE7NEL.js} +32 -28
  2. package/dist/{chunk-PYTEAC6K.js → chunk-DMJCO6LJ.js} +1 -1
  3. package/dist/{chunk-LCABODSZ.js → chunk-LTHJTWJ6.js} +2 -2
  4. package/dist/chunk-NREZK463.js +41 -0
  5. package/dist/{chunk-BIX7AJU3.js → chunk-O4CNZB5H.js} +1 -1
  6. package/dist/{chunk-TPLH46BH.js → chunk-WCSNAEOF.js} +58 -46
  7. package/dist/{config-K2S23A5R.js → config-6Z4XX5HW.js} +35 -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-E644BDZK.js → host-RR6FT7AX.js} +4 -3
  12. package/dist/index.js +31 -31
  13. package/dist/{init-FMPOE2MN.js → init-UOKYZJ53.js} +39 -19
  14. package/dist/{install-5ZBHH2OM.js → install-BURZ5QEM.js} +7 -6
  15. package/dist/{mcp-SQWZXF5Q.js → mcp-CB4PUUES.js} +55 -32
  16. package/dist/{memory-7WLVIFAZ.js → memory-TJZNGTOA.js} +4 -4
  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-CGYNNMYF.js → status-ZZRJ3VGF.js} +4 -4
  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 +1 -1
  26. package/lib/cf-memory/package.json +0 -1
  27. package/lib/cf-memory/src/index.ts +8 -1
  28. package/lib/learn-host/package.json +0 -1
  29. package/lib/learn-mcp/package.json +0 -1
  30. package/lib/learn-mcp/src/index.ts +8 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-W5CD7WTX.js +0 -15
  33. package/lib/cf-memory/CHANGELOG.md +0 -48
  34. package/lib/learn-host/CHANGELOG.md +0 -35
  35. package/lib/learn-mcp/CHANGELOG.md +0 -16
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-TRIALFOQ.js";
5
5
  import {
6
6
  ensureShellCompletion
7
- } from "./chunk-PYTEAC6K.js";
7
+ } from "./chunk-DMJCO6LJ.js";
8
8
  import {
9
9
  resolveScope
10
- } from "./chunk-BIX7AJU3.js";
10
+ } from "./chunk-O4CNZB5H.js";
11
11
  import {
12
12
  commandExists,
13
13
  run,
@@ -21,8 +21,9 @@ import {
21
21
  claudeSettingsPath
22
22
  } from "./chunk-DO6FV6BL.js";
23
23
  import {
24
- log
25
- } from "./chunk-W5CD7WTX.js";
24
+ log,
25
+ printBanner
26
+ } from "./chunk-NREZK463.js";
26
27
 
27
28
  // src/commands/update.ts
28
29
  import { readFileSync } from "fs";
@@ -85,7 +86,7 @@ function getStatuslineVersion() {
85
86
  const match = sl.command.match(
86
87
  /coding-friend-marketplace\/coding-friend\/([^/]+)\//
87
88
  );
88
- return match?.[1] ?? null;
89
+ return match?.[1]?.replace(/^v/, "") ?? null;
89
90
  }
90
91
  async function updateCommand(opts) {
91
92
  const updateAll = !opts.cli && !opts.plugin && !opts.statusline;
@@ -99,26 +100,38 @@ async function updateCommand(opts) {
99
100
  } else if (doPlugin && !hasScopeFlag) {
100
101
  scope = "user";
101
102
  }
102
- console.log("=== \u{1F33F} Coding Friend Update \u{1F33F} ===");
103
+ printBanner("\u2728 Coding Friend Update \u2728");
103
104
  console.log();
104
105
  const currentVersion = getInstalledVersion();
105
106
  const latestVersion = getLatestVersion();
106
107
  const statuslineVersion = getStatuslineVersion();
107
108
  const cliVersion = getCliVersion();
108
109
  const latestCliVersion = getLatestCliVersion();
109
- log.info(
110
- `Plugin version: ${currentVersion ? `v${currentVersion}` : chalk.yellow("not found")}`
111
- );
112
- log.info(
113
- `Latest plugin version: ${latestVersion ? chalk.green(`v${latestVersion}`) : chalk.yellow("unknown (cannot reach GitHub)")}`
114
- );
115
- log.info(`CLI version: v${cliVersion}`);
116
- log.info(
117
- `Latest CLI version: ${latestCliVersion ? chalk.green(`v${latestCliVersion}`) : chalk.yellow("unknown (cannot reach npm)")}`
118
- );
119
- log.info(
120
- `Statusline version: ${statuslineVersion ? chalk.green(`v${statuslineVersion}`) : chalk.yellow("not configured")}`
121
- );
110
+ const VERSION_COL = 13;
111
+ const pad = (label, width) => ` ${label}${" ".repeat(Math.max(1, width - label.length))}`;
112
+ const versionLine = (label, current, latest) => {
113
+ const padded = pad(label, VERSION_COL);
114
+ if (!current) return `${padded}${chalk.dim("not installed")}`;
115
+ if (!latest)
116
+ return `${padded}${current} ${chalk.dim("(latest unavailable)")}`;
117
+ const cmp = semverCompare(
118
+ current.replace(/^v/, ""),
119
+ latest.replace(/^v/, "")
120
+ );
121
+ const indicator = cmp >= 0 ? chalk.green("\u2714 up to date") : chalk.yellow("\u26A0 update available");
122
+ return `${padded}${current} \u2192 ${latest} ${indicator}`;
123
+ };
124
+ console.log(versionLine("Plugin", currentVersion, latestVersion));
125
+ console.log(versionLine("CLI", cliVersion, latestCliVersion));
126
+ if (statuslineVersion) {
127
+ console.log(
128
+ versionLine("Statusline", statuslineVersion, currentVersion ?? null)
129
+ );
130
+ } else {
131
+ console.log(
132
+ `${pad("Statusline", VERSION_COL)}${chalk.dim("not configured")}`
133
+ );
134
+ }
122
135
  console.log();
123
136
  if (doPlugin) {
124
137
  if (!latestVersion) {
@@ -132,9 +145,6 @@ async function updateCommand(opts) {
132
145
  } else {
133
146
  const cmp = semverCompare(currentVersion, latestVersion);
134
147
  if (cmp === 0) {
135
- log.success(
136
- `Plugin already on the latest version (${chalk.green(`v${latestVersion}`)}).`
137
- );
138
148
  } else if (cmp > 0) {
139
149
  log.info(
140
150
  `Plugin is ahead of latest release (local: ${chalk.cyan(`v${currentVersion}`)}, latest: v${latestVersion}). Skipping.`
@@ -214,9 +224,6 @@ async function updateCommand(opts) {
214
224
  } else {
215
225
  const cmp = semverCompare(cliVersion, latestCliVersion);
216
226
  if (cmp === 0) {
217
- log.success(
218
- `CLI already on the latest version (${chalk.green(`v${latestCliVersion}`)}).`
219
- );
220
227
  } else if (cmp > 0) {
221
228
  log.info(
222
229
  `CLI is ahead of latest release (local: ${chalk.cyan(`v${cliVersion}`)}, latest: v${latestCliVersion}). Skipping.`
@@ -242,12 +249,9 @@ async function updateCommand(opts) {
242
249
  }
243
250
  }
244
251
  if (doStatusline) {
245
- log.step("Updating statusline...");
246
252
  const updatedVersion = ensureStatusline();
247
253
  if (updatedVersion) {
248
254
  log.success(`Statusline updated to ${chalk.green(`v${updatedVersion}`)}`);
249
- } else {
250
- log.dim("Statusline already up-to-date.");
251
255
  }
252
256
  }
253
257
  ensureShellCompletion({ silent: false });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  log
3
- } from "./chunk-W5CD7WTX.js";
3
+ } from "./chunk-NREZK463.js";
4
4
 
5
5
  // src/lib/shell-completion.ts
6
6
  import {
@@ -9,7 +9,7 @@ import {
9
9
  askScope,
10
10
  formatScopeLabel,
11
11
  injectBackChoice
12
- } from "./chunk-BIX7AJU3.js";
12
+ } from "./chunk-O4CNZB5H.js";
13
13
  import {
14
14
  mergeJson,
15
15
  readJson,
@@ -21,7 +21,7 @@ import {
21
21
  } from "./chunk-DO6FV6BL.js";
22
22
  import {
23
23
  log
24
- } from "./chunk-W5CD7WTX.js";
24
+ } from "./chunk-NREZK463.js";
25
25
 
26
26
  // src/lib/memory-prompts.ts
27
27
  import { existsSync } from "fs";
@@ -0,0 +1,41 @@
1
+ // src/lib/log.ts
2
+ import chalk from "chalk";
3
+ var log = {
4
+ info: (msg) => console.log(chalk.blue("\u2139"), msg),
5
+ success: (msg) => console.log(chalk.green("\u2714"), msg),
6
+ congrats: (msg) => console.log(chalk.green("\u{1F389}"), msg),
7
+ warn: (msg) => console.log(chalk.yellow("\u26A0"), msg),
8
+ error: (msg) => console.log(chalk.red("\u2716"), msg),
9
+ step: (msg) => console.log(chalk.cyan("\u2192"), msg),
10
+ dim: (msg) => console.log(chalk.dim(msg))
11
+ };
12
+ function visualWidth(str) {
13
+ const emojiRe = /\p{Emoji_Presentation}|\p{Emoji}\uFE0F|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Regional_Indicator}{2}|[#*0-9]\uFE0F?\u20E3/gu;
14
+ let width = 0;
15
+ let lastIndex = 0;
16
+ for (const m of str.matchAll(emojiRe)) {
17
+ width += m.index - lastIndex;
18
+ width += 2;
19
+ lastIndex = m.index + m[0].length;
20
+ }
21
+ width += str.length - lastIndex;
22
+ return width;
23
+ }
24
+ function printBanner(title, opts = {}) {
25
+ const colorFn = opts.color ?? chalk.green;
26
+ const padding = 3;
27
+ const pad = " ".repeat(padding);
28
+ const inner = `${pad}${title}${pad}`;
29
+ const vw = visualWidth(inner);
30
+ const top = `\u250C${"\u2500".repeat(vw)}\u2510`;
31
+ const mid = `\u2502${inner}\u2502`;
32
+ const bot = `\u2514${"\u2500".repeat(vw)}\u2518`;
33
+ console.log(colorFn(top));
34
+ console.log(colorFn(mid));
35
+ console.log(colorFn(bot));
36
+ }
37
+
38
+ export {
39
+ log,
40
+ printBanner
41
+ };
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-DO6FV6BL.js";
11
11
  import {
12
12
  log
13
- } from "./chunk-W5CD7WTX.js";
13
+ } from "./chunk-NREZK463.js";
14
14
 
15
15
  // src/lib/prompt-utils.ts
16
16
  import { select, Separator } from "@inquirer/prompts";
@@ -7,7 +7,7 @@ import {
7
7
  getMemoryMcpStatus,
8
8
  memoryConfigMenu,
9
9
  writeMemoryMcpEntry
10
- } from "./chunk-LCABODSZ.js";
10
+ } from "./chunk-LTHJTWJ6.js";
11
11
  import {
12
12
  getLibPath
13
13
  } from "./chunk-RZRT7NGT.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-SIQJPT47.js";
18
18
  import {
19
19
  showConfigHint
20
- } from "./chunk-BIX7AJU3.js";
20
+ } from "./chunk-O4CNZB5H.js";
21
21
  import {
22
22
  run,
23
23
  runWithStderr
@@ -30,8 +30,9 @@ import {
30
30
  localConfigPath
31
31
  } from "./chunk-DO6FV6BL.js";
32
32
  import {
33
- log
34
- } from "./chunk-W5CD7WTX.js";
33
+ log,
34
+ printBanner
35
+ } from "./chunk-NREZK463.js";
35
36
 
36
37
  // src/commands/memory.ts
37
38
  import { existsSync, readdirSync, statSync, rmSync } from "fs";
@@ -86,10 +87,12 @@ function ensureMemoryBuilt(mcpDir) {
86
87
  }
87
88
  }
88
89
  function printMemoryMcpConfig(serverPath, memoryDir) {
89
- console.log(`Add this to your MCP client config:
90
-
91
- --- Claude Code (.mcp.json in project root) ---
92
-
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(`
93
96
  {
94
97
  "mcpServers": {
95
98
  "coding-friend-memory": {
@@ -97,10 +100,14 @@ function printMemoryMcpConfig(serverPath, memoryDir) {
97
100
  "args": ["${serverPath}", "${memoryDir}"]
98
101
  }
99
102
  }
100
- }
101
-
102
- --- Claude Desktop / Claude Chat (claude_desktop_config.json) ---
103
-
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(`
104
111
  {
105
112
  "mcpServers": {
106
113
  "coding-friend-memory": {
@@ -108,27 +115,43 @@ function printMemoryMcpConfig(serverPath, memoryDir) {
108
115
  "args": ["${serverPath}", "${memoryDir}"]
109
116
  }
110
117
  }
111
- }
112
-
113
- --- Generic MCP client ---
114
-
118
+ }`);
119
+ console.log();
120
+ console.log(chalk.yellow.bold("--- Generic MCP client ---"));
121
+ console.log(`
115
122
  Server command: node ${serverPath} ${memoryDir}
116
- Transport: stdio
117
-
118
- --- Available tools ---
119
-
120
- memory_store Store a new memory
121
- memory_search Search memories (keyword match)
122
- memory_retrieve Get a specific memory by ID
123
- memory_list List memories with filtering
124
- memory_update Update existing memory
125
- memory_delete Delete a memory
126
-
127
- --- Resources ---
128
-
129
- memory://index Browse all memories
130
- memory://stats Storage statistics
131
- `);
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();
132
155
  log.warn(
133
156
  "Note: The memory path is project-specific. Use local .mcp.json (per project), not global ~/.claude/.mcp.json."
134
157
  );
@@ -157,7 +180,7 @@ async function memoryStatusCommand() {
157
180
  } else {
158
181
  tierLabel = chalk.cyan("Tier 3 (Markdown)");
159
182
  }
160
- console.log("=== \u{1F9E0} Coding Friend Memory ===");
183
+ printBanner("\u{1F9E0} Coding Friend Memory");
161
184
  console.log();
162
185
  log.info(`Tier: ${tierLabel}`);
163
186
  log.info(`Memory dir: ${chalk.cyan(memoryDir)}`);
@@ -410,7 +433,6 @@ function getDbPath(memoryDir) {
410
433
  return null;
411
434
  }
412
435
  }
413
- var em = chalk.hex("#10b981");
414
436
  async function ensureSqliteDepsIfNeeded(mcpDir) {
415
437
  const config = loadConfig();
416
438
  const tier = config.memory?.tier ?? "auto";
@@ -479,12 +501,7 @@ async function memoryInitCommand() {
479
501
  return;
480
502
  }
481
503
  console.log();
482
- 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"));
483
- console.log(
484
- em(" \u2502 ") + "\u{1F9E0}" + em(" ") + chalk.bold.white("Memory Setup") + em(" \u2502")
485
- );
486
- 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"));
487
- console.log(em(" \u2570\u2500\u25B8"));
504
+ printBanner("\u{1F9E0} Memory Setup");
488
505
  console.log();
489
506
  showConfigHint();
490
507
  log.step("Step 1/5: Search tier");
@@ -576,12 +593,7 @@ async function memoryInitCommand() {
576
593
  }
577
594
  async function memoryConfigCommand() {
578
595
  console.log();
579
- 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"));
580
- console.log(
581
- em(" \u2502 ") + "\u{1F9E0}" + em(" ") + chalk.bold.white("Memory Config") + em(" \u2502")
582
- );
583
- 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"));
584
- console.log(em(" \u2570\u2500\u25B8"));
596
+ printBanner("\u{1F9E0} Memory Config");
585
597
  console.log();
586
598
  showConfigHint();
587
599
  await memoryConfigMenu({ exitLabel: "Done" });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  memoryConfigMenu
3
- } from "./chunk-LCABODSZ.js";
3
+ } from "./chunk-LTHJTWJ6.js";
4
4
  import {
5
5
  getAllRules,
6
6
  getExistingRules
@@ -22,7 +22,7 @@ import {
22
22
  ensureShellCompletion,
23
23
  hasShellCompletion,
24
24
  removeShellCompletion
25
- } from "./chunk-PYTEAC6K.js";
25
+ } from "./chunk-DMJCO6LJ.js";
26
26
  import {
27
27
  BACK,
28
28
  applyDocsDirChange,
@@ -32,7 +32,7 @@ import {
32
32
  getScopeLabel,
33
33
  injectBackChoice,
34
34
  showConfigHint
35
- } from "./chunk-BIX7AJU3.js";
35
+ } from "./chunk-O4CNZB5H.js";
36
36
  import {
37
37
  run
38
38
  } from "./chunk-EVGXUDX4.js";
@@ -48,8 +48,9 @@ import {
48
48
  resolvePath
49
49
  } from "./chunk-DO6FV6BL.js";
50
50
  import {
51
- log
52
- } from "./chunk-W5CD7WTX.js";
51
+ log,
52
+ printBanner
53
+ } from "./chunk-NREZK463.js";
53
54
 
54
55
  // src/commands/config.ts
55
56
  import { checkbox, confirm, input, select } from "@inquirer/prompts";
@@ -378,6 +379,19 @@ async function learnSubMenu() {
378
379
  }
379
380
  }
380
381
  }
382
+ async function editAutoApprove(globalCfg, localCfg) {
383
+ const currentValue = getMergedValue("autoApprove", globalCfg, localCfg);
384
+ if (currentValue !== void 0) {
385
+ log.dim(`Current: ${currentValue}`);
386
+ }
387
+ const value = await confirm({
388
+ message: "Enable auto-approve? (auto-approves safe tool calls, blocks destructive ones, prompts for ambiguous)",
389
+ default: currentValue ?? false
390
+ });
391
+ const scope = await askScope();
392
+ if (scope === "back") return;
393
+ writeToScope(scope, { autoApprove: value });
394
+ }
381
395
  async function editStatusline() {
382
396
  const hookResult = findStatuslineHookPath();
383
397
  if (!hookResult) {
@@ -543,7 +557,7 @@ async function editPermissions() {
543
557
  )
544
558
  });
545
559
  if (choice === BACK) return;
546
- const { permissionCommand } = await import("./permission-BEC6YZQA.js");
560
+ const { permissionCommand } = await import("./permission-QIJLEMJ6.js");
547
561
  switch (choice) {
548
562
  case "interactive":
549
563
  await permissionCommand({});
@@ -556,16 +570,9 @@ async function editPermissions() {
556
570
  break;
557
571
  }
558
572
  }
559
- var em = chalk.hex("#10b981");
560
573
  async function configCommand() {
561
574
  console.log();
562
- 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"));
563
- console.log(
564
- em(" \u2502 ") + "\u2726" + em(" ") + chalk.bold.white("Coding Friend") + em(" \u2726 \u2502")
565
- );
566
- console.log(em(" \u2502 ") + chalk.dim("Config") + em(" \u2502"));
567
- 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"));
568
- console.log(em(" \u2570\u2500\u25B8"));
575
+ printBanner("\u2728 Coding Friend Config \u2728");
569
576
  console.log();
570
577
  showConfigHint();
571
578
  while (true) {
@@ -577,6 +584,12 @@ async function configCommand() {
577
584
  const langVal = getMergedValue("language", globalCfg, localCfg);
578
585
  const learnScope = getScopeLabel("learn", globalCfg, localCfg);
579
586
  const memoryScope = getScopeLabel("memory", globalCfg, localCfg);
587
+ const autoApproveScope = getScopeLabel("autoApprove", globalCfg, localCfg);
588
+ const autoApproveVal = getMergedValue(
589
+ "autoApprove",
590
+ globalCfg,
591
+ localCfg
592
+ );
580
593
  const statuslineStatus = isStatuslineConfigured() ? chalk.green("configured") : chalk.yellow("not configured");
581
594
  const completionStatus = hasShellCompletion() ? chalk.green("installed") : chalk.yellow("not installed");
582
595
  const projectRules = getExistingRules(claudeLocalSettingsPath());
@@ -612,6 +625,11 @@ async function configCommand() {
612
625
  value: "memory",
613
626
  description: " Tier, auto-capture, auto-start, embedding provider, daemon timeout"
614
627
  },
628
+ {
629
+ name: `Auto-approve ${formatScopeLabel(autoApproveScope)}${autoApproveVal !== void 0 ? ` (${autoApproveVal})` : ""}`,
630
+ value: "autoApprove",
631
+ description: " Auto-approve safe tool calls, block destructive ones, prompt for ambiguous"
632
+ },
615
633
  {
616
634
  name: `Statusline (${statuslineStatus})`,
617
635
  value: "statusline",
@@ -652,6 +670,9 @@ async function configCommand() {
652
670
  case "memory":
653
671
  await memoryConfigMenu();
654
672
  break;
673
+ case "autoApprove":
674
+ await editAutoApprove(globalCfg, localCfg);
675
+ break;
655
676
  case "statusline":
656
677
  await editStatusline();
657
678
  break;
@@ -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";
@@ -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();