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.
- package/dist/{chunk-PDVSGGH6.js → chunk-2ETE7NEL.js} +32 -28
- package/dist/{chunk-PYTEAC6K.js → chunk-DMJCO6LJ.js} +1 -1
- package/dist/{chunk-3KXYEC2T.js → chunk-LTHJTWJ6.js} +82 -3
- package/dist/chunk-NREZK463.js +41 -0
- package/dist/{chunk-BIX7AJU3.js → chunk-O4CNZB5H.js} +1 -1
- package/dist/{memory-27ZSRPM7.js → chunk-WCSNAEOF.js} +155 -73
- package/dist/{config-5I3XJEEL.js → config-5DKOGWWJ.js} +9 -14
- package/dist/{dev-4A5CTBGK.js → dev-S7S3SFKI.js} +19 -18
- package/dist/{disable-FNMRPUO7.js → disable-V7OLXEUH.js} +2 -2
- package/dist/{enable-HUKTMK5U.js → enable-OLHRKZCV.js} +2 -2
- package/dist/{host-V5O3PDCF.js → host-RR6FT7AX.js} +7 -6
- package/dist/index.js +31 -31
- package/dist/{init-3XMC6YJI.js → init-6B2OHKFX.js} +22 -40
- package/dist/{install-5ZBHH2OM.js → install-BURZ5QEM.js} +7 -6
- package/dist/mcp-CB4PUUES.js +156 -0
- package/dist/memory-TJZNGTOA.js +37 -0
- package/dist/{permission-BEC6YZQA.js → permission-QIJLEMJ6.js} +4 -3
- package/dist/postinstall.js +2 -2
- package/dist/{session-ZDJ2APGL.js → session-IECOM63R.js} +1 -1
- package/dist/{status-F6WASK7N.js → status-ZZRJ3VGF.js} +7 -7
- package/dist/{statusline-AISH77XP.js → statusline-YL44XYGF.js} +4 -3
- package/dist/{uninstall-RJ6SBB76.js → uninstall-OXWRPWYF.js} +7 -6
- package/dist/{update-536C3YG7.js → update-6N7EASFT.js} +4 -4
- package/dist/{update-check-L5TNWT2J.js → update-check-XSETLRVR.js} +1 -1
- package/lib/cf-memory/README.md +4 -1
- package/lib/cf-memory/package.json +0 -1
- package/lib/cf-memory/src/__tests__/daemon-client.test.ts +146 -0
- package/lib/cf-memory/src/daemon/process.ts +7 -0
- package/lib/cf-memory/src/index.ts +21 -2
- package/lib/cf-memory/src/lib/daemon-client.ts +54 -3
- package/lib/cf-memory/src/lib/tier.ts +27 -3
- package/lib/learn-host/package.json +0 -1
- package/lib/learn-mcp/package.json +0 -1
- package/lib/learn-mcp/src/index.ts +8 -1
- package/package.json +1 -1
- package/dist/chunk-W5CD7WTX.js +0 -15
- package/dist/mcp-U34LFD34.js +0 -106
- package/lib/cf-memory/CHANGELOG.md +0 -42
- package/lib/learn-host/CHANGELOG.md +0 -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-
|
|
7
|
+
} from "./chunk-DMJCO6LJ.js";
|
|
8
8
|
import {
|
|
9
9
|
resolveScope
|
|
10
|
-
} from "./chunk-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLibPath
|
|
3
3
|
} from "./chunk-RZRT7NGT.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveMemoryDir
|
|
6
|
+
} from "./chunk-SIQJPT47.js";
|
|
4
7
|
import {
|
|
5
8
|
BACK,
|
|
6
9
|
askScope,
|
|
7
10
|
formatScopeLabel,
|
|
8
11
|
injectBackChoice
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-O4CNZB5H.js";
|
|
10
13
|
import {
|
|
11
14
|
mergeJson,
|
|
12
|
-
readJson
|
|
15
|
+
readJson,
|
|
16
|
+
writeJson
|
|
13
17
|
} from "./chunk-5UVDWG5L.js";
|
|
14
18
|
import {
|
|
15
19
|
globalConfigPath,
|
|
@@ -17,10 +21,13 @@ import {
|
|
|
17
21
|
} from "./chunk-DO6FV6BL.js";
|
|
18
22
|
import {
|
|
19
23
|
log
|
|
20
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-NREZK463.js";
|
|
21
25
|
|
|
22
26
|
// src/lib/memory-prompts.ts
|
|
27
|
+
import { existsSync } from "fs";
|
|
28
|
+
import { homedir } from "os";
|
|
23
29
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
30
|
+
import chalk from "chalk";
|
|
24
31
|
import { join } from "path";
|
|
25
32
|
function getMemoryFieldScope(field, globalCfg, localCfg) {
|
|
26
33
|
const globalSection = globalCfg?.memory;
|
|
@@ -235,6 +242,67 @@ async function editMemoryDaemonTimeout(globalCfg, localCfg) {
|
|
|
235
242
|
idleTimeout: Number(value) * 6e4
|
|
236
243
|
});
|
|
237
244
|
}
|
|
245
|
+
function writeMemoryMcpEntry(serverPath, memoryDir) {
|
|
246
|
+
const mcpPath = join(process.cwd(), ".mcp.json");
|
|
247
|
+
const existing = readJson(mcpPath) ?? {};
|
|
248
|
+
const servers = existing.mcpServers ?? {};
|
|
249
|
+
writeJson(mcpPath, {
|
|
250
|
+
...existing,
|
|
251
|
+
mcpServers: {
|
|
252
|
+
...servers,
|
|
253
|
+
"coding-friend-memory": {
|
|
254
|
+
command: "node",
|
|
255
|
+
args: [serverPath, memoryDir]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
log.success("Added coding-friend-memory to .mcp.json");
|
|
260
|
+
}
|
|
261
|
+
function getMemoryMcpStatus() {
|
|
262
|
+
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
263
|
+
const localMcp = readJson(localMcpPath);
|
|
264
|
+
const localServers = localMcp?.mcpServers;
|
|
265
|
+
if (localServers != null && "coding-friend-memory" in localServers) {
|
|
266
|
+
return { configured: true, scope: "local" };
|
|
267
|
+
}
|
|
268
|
+
const globalMcpPath = join(homedir(), ".claude", ".mcp.json");
|
|
269
|
+
const globalMcp = readJson(globalMcpPath);
|
|
270
|
+
const globalServers = globalMcp?.mcpServers;
|
|
271
|
+
if (globalServers != null && "coding-friend-memory" in globalServers) {
|
|
272
|
+
return { configured: true, scope: "global" };
|
|
273
|
+
}
|
|
274
|
+
return { configured: false, scope: null };
|
|
275
|
+
}
|
|
276
|
+
async function editMemoryMcp() {
|
|
277
|
+
const status = getMemoryMcpStatus();
|
|
278
|
+
if (status.configured) {
|
|
279
|
+
const label = status.scope === "local" ? chalk.green("configured") + chalk.dim(" (local .mcp.json)") : chalk.green("configured") + chalk.dim(" (global ~/.claude/.mcp.json)") + " " + chalk.yellow("\u26A0 only works for one project");
|
|
280
|
+
log.info(`MCP: ${label}`);
|
|
281
|
+
const reconfigure = await confirm({
|
|
282
|
+
message: "Reconfigure Memory MCP in local .mcp.json?",
|
|
283
|
+
default: false
|
|
284
|
+
});
|
|
285
|
+
if (!reconfigure) return;
|
|
286
|
+
}
|
|
287
|
+
let mcpDir;
|
|
288
|
+
try {
|
|
289
|
+
mcpDir = getLibPath("cf-memory");
|
|
290
|
+
} catch {
|
|
291
|
+
log.warn(
|
|
292
|
+
"cf-memory package not found. Install the CLI first: npm i -g coding-friend-cli"
|
|
293
|
+
);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const serverPath = join(mcpDir, "dist", "index.js");
|
|
297
|
+
if (!existsSync(serverPath)) {
|
|
298
|
+
log.warn(
|
|
299
|
+
'cf-memory not built yet. Run "cf memory mcp" after building to get the config.'
|
|
300
|
+
);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const memoryDir = resolveMemoryDir();
|
|
304
|
+
writeMemoryMcpEntry(serverPath, memoryDir);
|
|
305
|
+
}
|
|
238
306
|
async function memoryConfigMenu(opts) {
|
|
239
307
|
while (true) {
|
|
240
308
|
const globalCfg = readJson(globalConfigPath());
|
|
@@ -274,6 +342,8 @@ async function memoryConfigMenu(opts) {
|
|
|
274
342
|
const daemonScope = getMemoryFieldScope("daemon", globalCfg, localCfg);
|
|
275
343
|
const daemonVal = getMergedMemoryValue("daemon", globalCfg, localCfg);
|
|
276
344
|
const embeddingLabel = embeddingVal?.provider ? embeddingVal.model ? `${embeddingVal.model} (${embeddingVal.provider})` : embeddingVal.provider : "";
|
|
345
|
+
const mcpStatus = getMemoryMcpStatus();
|
|
346
|
+
const mcpLabel = mcpStatus.configured ? mcpStatus.scope === "local" ? chalk.green("configured") + chalk.dim(" (.mcp.json)") : chalk.green("configured") + chalk.dim(" (global)") + " " + chalk.yellow("\u26A0") : chalk.dim("not configured");
|
|
277
347
|
const choice = await select({
|
|
278
348
|
message: "Memory settings:",
|
|
279
349
|
choices: injectBackChoice(
|
|
@@ -297,6 +367,10 @@ async function memoryConfigMenu(opts) {
|
|
|
297
367
|
{
|
|
298
368
|
name: `Daemon timeout ${formatScopeLabel(daemonScope)}${daemonVal?.idleTimeout ? ` (${daemonVal.idleTimeout / 6e4}min)` : ""}`,
|
|
299
369
|
value: "daemon"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: `MCP setup (${mcpLabel})`,
|
|
373
|
+
value: "mcp"
|
|
300
374
|
}
|
|
301
375
|
],
|
|
302
376
|
opts?.exitLabel ?? "Back"
|
|
@@ -319,6 +393,9 @@ async function memoryConfigMenu(opts) {
|
|
|
319
393
|
case "daemon":
|
|
320
394
|
await editMemoryDaemonTimeout(globalCfg, localCfg);
|
|
321
395
|
break;
|
|
396
|
+
case "mcp":
|
|
397
|
+
await editMemoryMcp();
|
|
398
|
+
break;
|
|
322
399
|
}
|
|
323
400
|
}
|
|
324
401
|
}
|
|
@@ -329,5 +406,7 @@ export {
|
|
|
329
406
|
editMemoryAutoStart,
|
|
330
407
|
editMemoryEmbedding,
|
|
331
408
|
editMemoryDaemonTimeout,
|
|
409
|
+
writeMemoryMcpEntry,
|
|
410
|
+
getMemoryMcpStatus,
|
|
332
411
|
memoryConfigMenu
|
|
333
412
|
};
|
|
@@ -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
|
+
};
|