coding-friend-cli 1.36.4 → 1.38.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/README.md +8 -3
- package/dist/{chunk-GZT3YPAP.js → chunk-32UAW3NX.js} +1 -1
- package/dist/chunk-5QCGEPQO.js +238 -0
- package/dist/{chunk-YIXAQ4R2.js → chunk-6NXZKAOV.js} +1 -1
- package/dist/{chunk-XHP3EBR3.js → chunk-776ZY62N.js} +112 -4
- package/dist/{chunk-N4WZWRCI.js → chunk-BXSCYGWE.js} +85 -37
- package/dist/{chunk-AK6RMCAC.js → chunk-CGEMETKQ.js} +44 -30
- package/dist/{chunk-XEKQW4RN.js → chunk-ETTZRJ55.js} +1 -1
- package/dist/{chunk-IKLMHJH6.js → chunk-GIH6E7GJ.js} +62 -1
- package/dist/{chunk-56YJWGAN.js → chunk-ONG4KRYP.js} +60 -47
- package/dist/{chunk-X2H7JJMR.js → chunk-PLSJW7QJ.js} +29 -1
- package/dist/{chunk-O5ZKLFSL.js → chunk-RCE4OWNX.js} +1 -1
- package/dist/{chunk-K4WSC62G.js → chunk-RFNKPAJW.js} +42 -2
- package/dist/{clean-Q4VU662V.js → clean-YWEMYDE5.js} +3 -2
- package/dist/{config-CTTHWJH5.js → config-NG7SICM4.js} +15 -27
- package/dist/{dev-IGHMMEP4.js → dev-PTBNMKZT.js} +3 -3
- package/dist/{disable-HL5OEURT.js → disable-MO7AXYYF.js} +20 -3
- package/dist/{enable-CZIOCKKJ.js → enable-4GXLQEHD.js} +20 -3
- package/dist/{guide-CO2V4ZLZ.js → guide-HCR43LJN.js} +1 -1
- package/dist/{host-NCJMUSME.js → host-EV6QIVTI.js} +3 -3
- package/dist/index.js +62 -48
- package/dist/{init-UABKVDVT.js → init-KYE5CJMW.js} +135 -17
- package/dist/{install-R2HDM3N4.js → install-XAFQY5YF.js} +80 -5
- package/dist/{learn-K64AUUFB.js → learn-MC4VDHZH.js} +2 -2
- package/dist/{mcp-OMQFSJP4.js → mcp-FV6YX3ZT.js} +24 -24
- package/dist/{mcp-serve-3FEPFVVQ.js → mcp-serve-PXREYQRZ.js} +10 -1
- package/dist/{mcp-serve-learn-OF3ZJUJC.js → mcp-serve-learn-UVXIDOEZ.js} +1 -1
- package/dist/{memory-Y6GNALG3.js → memory-DF7OUOTV.js} +7 -7
- package/dist/{permission-I3OFJUYA.js → permission-VISPGMUK.js} +38 -4
- package/dist/{permissions-J46VP6US.js → permissions-2SBACQHV.js} +2 -2
- package/dist/{session-Q2DLQPYP.js → session-QK6OZO3X.js} +3 -2
- package/dist/{status-ML4XEDYL.js → status-FVFTJ6GS.js} +18 -14
- package/dist/{statusline-KKFJPTI7.js → statusline-AOZHEQSV.js} +2 -2
- package/dist/{uninstall-ASLHT3MH.js → uninstall-MF6FRUBO.js} +64 -3
- package/dist/{update-DIOH45TE.js → update-QNUCSDSA.js} +7 -4
- package/dist/{update-check-25SCLHZO.js → update-check-7LKJLJPM.js} +1 -1
- package/lib/cf-memory/src/backends/sqlite/index.ts +142 -85
- package/lib/cf-memory/src/lib/claude-md.ts +82 -70
- package/lib/cf-memory/src/lib/status-frame.ts +2 -2
- package/lib/cf-memory/src/tools/delete.ts +1 -1
- package/lib/cf-memory/src/tools/store.ts +6 -6
- package/lib/cf-memory/src/tools/update.ts +5 -11
- package/package.json +32 -4
- package/lib/cf-memory/README.md +0 -317
- package/lib/cf-memory/src/__tests__/claude-md.test.ts +0 -343
- package/lib/cf-memory/src/__tests__/daemon-client.test.ts +0 -146
- package/lib/cf-memory/src/__tests__/daemon-e2e.test.ts +0 -223
- package/lib/cf-memory/src/__tests__/daemon.test.ts +0 -407
- package/lib/cf-memory/src/__tests__/dedup.test.ts +0 -103
- package/lib/cf-memory/src/__tests__/embeddings.test.ts +0 -292
- package/lib/cf-memory/src/__tests__/lazy-install.test.ts +0 -210
- package/lib/cf-memory/src/__tests__/markdown-backend.test.ts +0 -450
- package/lib/cf-memory/src/__tests__/migration.test.ts +0 -255
- package/lib/cf-memory/src/__tests__/migrations.test.ts +0 -288
- package/lib/cf-memory/src/__tests__/minisearch-backend.test.ts +0 -262
- package/lib/cf-memory/src/__tests__/ollama.test.ts +0 -48
- package/lib/cf-memory/src/__tests__/project-id.test.ts +0 -43
- package/lib/cf-memory/src/__tests__/schema.test.ts +0 -128
- package/lib/cf-memory/src/__tests__/search.test.ts +0 -115
- package/lib/cf-memory/src/__tests__/status-frame.test.ts +0 -136
- package/lib/cf-memory/src/__tests__/temporal-decay.test.ts +0 -54
- package/lib/cf-memory/src/__tests__/tier.test.ts +0 -367
- package/lib/cf-memory/src/__tests__/tools.test.ts +0 -83
- package/lib/cf-memory/vitest.config.ts +0 -7
- package/lib/learn-host/.prettierignore +0 -4
- package/lib/learn-host/.prettierrc +0 -8
- package/lib/learn-host/README.md +0 -113
- package/lib/learn-host/eslint.config.mjs +0 -6
- package/lib/learn-mcp/README.md +0 -187
- package/lib/learn-mcp/src/__tests__/docs.test.ts +0 -117
- package/lib/learn-mcp/vitest.config.ts +0 -8
|
@@ -2,22 +2,23 @@ import {
|
|
|
2
2
|
checkMemoryMcpHealth,
|
|
3
3
|
printHealthSection,
|
|
4
4
|
warnStaleMcpJson
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
getMemoryMcpStatus,
|
|
8
|
-
memoryConfigMenu,
|
|
9
|
-
writeMemoryMcpEntry
|
|
10
|
-
} from "./chunk-N4WZWRCI.js";
|
|
5
|
+
} from "./chunk-ONG4KRYP.js";
|
|
11
6
|
import {
|
|
12
7
|
loadConfig,
|
|
13
8
|
resolveMemoryDir
|
|
14
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RFNKPAJW.js";
|
|
10
|
+
import {
|
|
11
|
+
getMemoryMcpStatus,
|
|
12
|
+
isMemoryMcpRegistered,
|
|
13
|
+
memoryConfigMenu,
|
|
14
|
+
registerMemoryMcp
|
|
15
|
+
} from "./chunk-BXSCYGWE.js";
|
|
15
16
|
import {
|
|
16
17
|
getLibPath
|
|
17
18
|
} from "./chunk-RZRT7NGT.js";
|
|
18
19
|
import {
|
|
19
20
|
showConfigHint
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GIH6E7GJ.js";
|
|
21
22
|
import {
|
|
22
23
|
run,
|
|
23
24
|
runWithStderr
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
import {
|
|
30
31
|
globalConfigPath,
|
|
31
32
|
localConfigPath
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
33
34
|
import {
|
|
34
35
|
log,
|
|
35
36
|
printBanner
|
|
@@ -103,11 +104,17 @@ async function refreshMemoryAfterUpdate() {
|
|
|
103
104
|
log.warn('Memory server build failed \u2014 run "cf memory status" to retry.');
|
|
104
105
|
}
|
|
105
106
|
} catch {
|
|
106
|
-
log.warn(
|
|
107
|
+
log.warn(
|
|
108
|
+
'Could not refresh memory server \u2014 run "cf memory status" to retry.'
|
|
109
|
+
);
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
function printMemoryMcpConfig(memoryDir) {
|
|
110
|
-
console.log(
|
|
113
|
+
console.log(
|
|
114
|
+
chalk.dim(
|
|
115
|
+
"For non-Claude-Code MCP clients only (Claude Code is already set up via the user-scope registration above) \u2014 add this to that client's config:"
|
|
116
|
+
)
|
|
117
|
+
);
|
|
111
118
|
console.log();
|
|
112
119
|
console.log(`{
|
|
113
120
|
"mcpServers": {
|
|
@@ -127,8 +134,8 @@ function printMemoryMcpConfig(memoryDir) {
|
|
|
127
134
|
"Available tools & resources: https://cf.dinhanhthi.com/docs/cli/cf-mcp/"
|
|
128
135
|
);
|
|
129
136
|
console.log();
|
|
130
|
-
log.
|
|
131
|
-
"Note:
|
|
137
|
+
log.dim(
|
|
138
|
+
"Note: this explicit path is needed only for clients that can't set CLAUDE_PROJECT_DIR. Claude Code resolves the project automatically and needs no manual config."
|
|
132
139
|
);
|
|
133
140
|
console.log();
|
|
134
141
|
}
|
|
@@ -189,17 +196,25 @@ async function memoryStatusCommand() {
|
|
|
189
196
|
log.info(`Embedding: ${chalk.cyan(model)} ${chalk.dim(`(${provider})`)}`);
|
|
190
197
|
}
|
|
191
198
|
const mcpStatus = getMemoryMcpStatus();
|
|
192
|
-
if (mcpStatus.
|
|
199
|
+
if (mcpStatus.userScope && mcpStatus.scope === "local") {
|
|
200
|
+
log.info(
|
|
201
|
+
`MCP: ${chalk.green("registered")} ${chalk.dim("(user scope)")} ${chalk.yellow('\u26A0 project .mcp.json shadows user-scope server \u2014 run "cf update" to clean up')}`
|
|
202
|
+
);
|
|
203
|
+
} else if (mcpStatus.userScope) {
|
|
193
204
|
log.info(
|
|
194
|
-
`MCP: ${chalk.green("
|
|
205
|
+
`MCP: ${chalk.green("registered")} ${chalk.dim("(user scope)")}`
|
|
206
|
+
);
|
|
207
|
+
} else if (mcpStatus.configured && mcpStatus.scope === "local") {
|
|
208
|
+
log.info(
|
|
209
|
+
`MCP: ${chalk.yellow("configured")} ${chalk.dim('(local .mcp.json \u2014 run "cf mcp" to migrate to user scope)')}`
|
|
195
210
|
);
|
|
196
211
|
} else if (mcpStatus.configured && mcpStatus.scope === "global") {
|
|
197
212
|
log.info(
|
|
198
|
-
`MCP: ${chalk.
|
|
213
|
+
`MCP: ${chalk.yellow("configured")} ${chalk.dim('(global ~/.claude/.mcp.json \u2014 run "cf mcp" to migrate to user scope)')} ${chalk.yellow("\u26A0 global config uses a fixed path \u2014 only works for one project")}`
|
|
199
214
|
);
|
|
200
215
|
} else {
|
|
201
216
|
log.info(
|
|
202
|
-
`MCP: ${chalk.dim("not
|
|
217
|
+
`MCP: ${chalk.dim("not registered")} ${chalk.dim('(run "cf mcp" to register at user scope)')}`
|
|
203
218
|
);
|
|
204
219
|
}
|
|
205
220
|
const autoCapture = config.memory?.autoCapture ?? false;
|
|
@@ -500,13 +515,13 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
500
515
|
const config = loadConfig();
|
|
501
516
|
const resolvedTier = config.memory?.tier ?? "auto";
|
|
502
517
|
if (resolvedTier === "markdown") {
|
|
503
|
-
await setupMemoryMcp(
|
|
518
|
+
await setupMemoryMcp();
|
|
504
519
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
505
520
|
printInitDone();
|
|
506
521
|
return;
|
|
507
522
|
}
|
|
508
523
|
if (resolvedTier === "lite") {
|
|
509
|
-
await setupMemoryMcp(
|
|
524
|
+
await setupMemoryMcp();
|
|
510
525
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
511
526
|
printInitDone();
|
|
512
527
|
return;
|
|
@@ -514,7 +529,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
514
529
|
const depsOk = await ensureSqliteDepsIfNeeded(mcpDir);
|
|
515
530
|
if (!depsOk) return;
|
|
516
531
|
if (!existsSync(memoryDir)) {
|
|
517
|
-
await setupMemoryMcp(
|
|
532
|
+
await setupMemoryMcp();
|
|
518
533
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
519
534
|
printInitDone();
|
|
520
535
|
return;
|
|
@@ -522,7 +537,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
522
537
|
const docCount = countMdFiles(memoryDir);
|
|
523
538
|
if (docCount === 0) {
|
|
524
539
|
log.info("No existing memories to import.");
|
|
525
|
-
await setupMemoryMcp(
|
|
540
|
+
await setupMemoryMcp();
|
|
526
541
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
527
542
|
printInitDone();
|
|
528
543
|
return;
|
|
@@ -544,7 +559,7 @@ async function memoryInitWizard(memoryDir, mcpDir) {
|
|
|
544
559
|
} finally {
|
|
545
560
|
await backend.close();
|
|
546
561
|
}
|
|
547
|
-
await setupMemoryMcp(
|
|
562
|
+
await setupMemoryMcp();
|
|
548
563
|
console.log();
|
|
549
564
|
console.log('\u{1F389} Memory initialized! Run "cf memory status" to verify.');
|
|
550
565
|
log.info(
|
|
@@ -561,15 +576,14 @@ function printInitDone() {
|
|
|
561
576
|
` Documentation: ${chalk.cyan("https://cf.dinhanhthi.com/docs/cli/cf-memory/")}`
|
|
562
577
|
);
|
|
563
578
|
}
|
|
564
|
-
async function setupMemoryMcp(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
log.info(`MCP: ${chalk.green("already configured")} in .mcp.json`);
|
|
579
|
+
async function setupMemoryMcp() {
|
|
580
|
+
if (isMemoryMcpRegistered()) {
|
|
581
|
+
log.info("coding-friend-memory: already registered (user scope)");
|
|
568
582
|
return;
|
|
569
583
|
}
|
|
570
|
-
|
|
571
|
-
log.
|
|
572
|
-
"
|
|
584
|
+
registerMemoryMcp();
|
|
585
|
+
log.success(
|
|
586
|
+
"Registered coding-friend-memory (user scope). Restart Claude Code to activate."
|
|
573
587
|
);
|
|
574
588
|
}
|
|
575
589
|
async function memoryInitCommand() {
|
|
@@ -853,7 +867,7 @@ async function memoryMcpCommand() {
|
|
|
853
867
|
const memoryDir = getMemoryDir();
|
|
854
868
|
const mcpDir = getLibPath("cf-memory");
|
|
855
869
|
ensureMemoryBuilt(mcpDir);
|
|
856
|
-
warnStaleMcpJson(
|
|
870
|
+
warnStaleMcpJson();
|
|
857
871
|
printMemoryMcpConfig(memoryDir);
|
|
858
872
|
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
859
873
|
const memoryDistPath = join(mcpDir, "dist", "index.js");
|
|
@@ -7,11 +7,62 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
globalConfigPath,
|
|
9
9
|
localConfigPath
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
11
11
|
import {
|
|
12
12
|
log
|
|
13
13
|
} from "./chunk-NREZK463.js";
|
|
14
14
|
|
|
15
|
+
// src/lib/host.ts
|
|
16
|
+
var CODEX_MIN_VERSION = "0.130.0";
|
|
17
|
+
function resolveHost(opts = {}) {
|
|
18
|
+
const agent = opts.agent?.trim().toLowerCase();
|
|
19
|
+
const codexAlias = opts.codex === true;
|
|
20
|
+
if (agent && agent !== "claude" && agent !== "codex") {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Unsupported agent "${opts.agent}". Use "claude" or "codex".`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (codexAlias && agent === "claude") {
|
|
26
|
+
throw new Error("Use either --agent claude or --codex, not both.");
|
|
27
|
+
}
|
|
28
|
+
if (codexAlias) return "codex";
|
|
29
|
+
if (agent === "codex") return "codex";
|
|
30
|
+
return "claude";
|
|
31
|
+
}
|
|
32
|
+
function getCodexMinVersion() {
|
|
33
|
+
return CODEX_MIN_VERSION;
|
|
34
|
+
}
|
|
35
|
+
function checkCodexVersion() {
|
|
36
|
+
const min = getCodexMinVersion();
|
|
37
|
+
const output = run("codex", ["--version"]);
|
|
38
|
+
const actual = output ? extractVersion(output) : void 0;
|
|
39
|
+
return {
|
|
40
|
+
ok: actual ? compareVersions(actual, min) >= 0 : false,
|
|
41
|
+
actual,
|
|
42
|
+
min
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function extractVersion(input) {
|
|
46
|
+
return input.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
|
|
47
|
+
}
|
|
48
|
+
function compareVersions(a, b) {
|
|
49
|
+
const left = parseVersion(a);
|
|
50
|
+
const right = parseVersion(b);
|
|
51
|
+
for (let i = 0; i < 3; i += 1) {
|
|
52
|
+
if (left[i] > right[i]) return 1;
|
|
53
|
+
if (left[i] < right[i]) return -1;
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
function parseVersion(version) {
|
|
58
|
+
const parts = version.split(".").map((part) => Number.parseInt(part, 10));
|
|
59
|
+
return [
|
|
60
|
+
Number.isFinite(parts[0]) ? parts[0] : 0,
|
|
61
|
+
Number.isFinite(parts[1]) ? parts[1] : 0,
|
|
62
|
+
Number.isFinite(parts[2]) ? parts[2] : 0
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
15
66
|
// src/lib/prompt-utils.ts
|
|
16
67
|
import { select, Separator } from "@inquirer/prompts";
|
|
17
68
|
import { existsSync } from "fs";
|
|
@@ -80,6 +131,14 @@ async function resolveScope(opts, message) {
|
|
|
80
131
|
}
|
|
81
132
|
return askPluginScope(message);
|
|
82
133
|
}
|
|
134
|
+
function resolveHostFlags(opts) {
|
|
135
|
+
try {
|
|
136
|
+
return { host: resolveHost(opts) };
|
|
137
|
+
} catch (err) {
|
|
138
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
83
142
|
function showConfigHint() {
|
|
84
143
|
console.log(chalk.dim("Config files:"));
|
|
85
144
|
console.log(chalk.dim(" Global: ~/.coding-friend/config.json"));
|
|
@@ -173,10 +232,12 @@ function applyDocsDirChange(newValue, oldValue, scope, subfolders = []) {
|
|
|
173
232
|
}
|
|
174
233
|
|
|
175
234
|
export {
|
|
235
|
+
checkCodexVersion,
|
|
176
236
|
BACK,
|
|
177
237
|
injectBackChoice,
|
|
178
238
|
askScope,
|
|
179
239
|
resolveScope,
|
|
240
|
+
resolveHostFlags,
|
|
180
241
|
showConfigHint,
|
|
181
242
|
getScopeLabel,
|
|
182
243
|
formatScopeLabel,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
isMemoryMcpRegistered
|
|
3
|
+
} from "./chunk-BXSCYGWE.js";
|
|
4
4
|
import {
|
|
5
5
|
readJson
|
|
6
6
|
} from "./chunk-5UVDWG5L.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { existsSync } from "fs";
|
|
13
13
|
import { join } from "path";
|
|
14
14
|
import chalk from "chalk";
|
|
15
|
-
function warnStaleMcpJson(
|
|
15
|
+
function warnStaleMcpJson() {
|
|
16
16
|
const localMcpPath = join(process.cwd(), ".mcp.json");
|
|
17
17
|
if (!existsSync(localMcpPath)) return;
|
|
18
18
|
const mcpJson = readJson(localMcpPath);
|
|
@@ -23,39 +23,35 @@ function warnStaleMcpJson(memoryDir) {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const state = detectMemoryMcpState(mcpJson, existsSync);
|
|
26
|
-
if (state.kind === "stale"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
);
|
|
57
|
-
console.log();
|
|
58
|
-
}
|
|
26
|
+
if (state.kind === "stale") {
|
|
27
|
+
console.log(
|
|
28
|
+
chalk.yellow(`\u26A0 Stale MCP config detected in .mcp.json`)
|
|
29
|
+
);
|
|
30
|
+
console.log(chalk.dim(` Path no longer exists: ${state.path}`));
|
|
31
|
+
console.log(
|
|
32
|
+
chalk.dim(
|
|
33
|
+
` This project-scope coding-friend-memory entry shadows the global (user-scope) memory server.`
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
console.log(
|
|
37
|
+
chalk.dim(` Run "cf update" to remove it automatically.`)
|
|
38
|
+
);
|
|
39
|
+
console.log();
|
|
40
|
+
} else if (state.kind === "legacy-valid") {
|
|
41
|
+
console.log(
|
|
42
|
+
chalk.cyan(
|
|
43
|
+
`\u2139 .mcp.json has a project-scope coding-friend-memory entry.`
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
console.log(
|
|
47
|
+
chalk.dim(
|
|
48
|
+
` This shadows the global (user-scope) memory server (Claude Code precedence: local > project > user).`
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
console.log(
|
|
52
|
+
chalk.dim(` Run "cf update" to remove it automatically.`)
|
|
53
|
+
);
|
|
54
|
+
console.log();
|
|
59
55
|
}
|
|
60
56
|
}
|
|
61
57
|
function detectMemoryMcpState(mcpJson, pathExists) {
|
|
@@ -102,24 +98,41 @@ function printHealthSection(result) {
|
|
|
102
98
|
}
|
|
103
99
|
async function checkMemoryMcpHealth(deps) {
|
|
104
100
|
const checks = [];
|
|
101
|
+
const checkRegistered = deps.isRegistered ?? isMemoryMcpRegistered;
|
|
102
|
+
const registered = checkRegistered();
|
|
103
|
+
checks.push({
|
|
104
|
+
label: "Registered (user scope)",
|
|
105
|
+
ok: registered,
|
|
106
|
+
...registered ? {} : {
|
|
107
|
+
detail: "coding-friend-memory not registered",
|
|
108
|
+
fix: 'Run "cf mcp" to register'
|
|
109
|
+
}
|
|
110
|
+
});
|
|
105
111
|
const mcpJson = deps.readMcpJson();
|
|
106
112
|
const state = detectMemoryMcpState(mcpJson, deps.pathExists);
|
|
107
|
-
if (state.kind === "
|
|
108
|
-
checks.push({
|
|
109
|
-
|
|
113
|
+
if (state.kind === "stale") {
|
|
114
|
+
checks.push({
|
|
115
|
+
label: "Project .mcp.json",
|
|
116
|
+
ok: false,
|
|
117
|
+
warn: true,
|
|
118
|
+
detail: `Stale entry shadows user-scope server (path missing: ${state.path})`,
|
|
119
|
+
fix: 'Run "cf update" to remove it automatically'
|
|
120
|
+
});
|
|
121
|
+
} else if (state.kind === "legacy-valid") {
|
|
110
122
|
checks.push({
|
|
111
|
-
label: "
|
|
123
|
+
label: "Project .mcp.json",
|
|
112
124
|
ok: false,
|
|
113
|
-
|
|
114
|
-
|
|
125
|
+
warn: true,
|
|
126
|
+
detail: `Legacy absolute-path entry shadows user-scope server`,
|
|
127
|
+
fix: 'Run "cf update" to migrate to the user-scope registration'
|
|
115
128
|
});
|
|
116
|
-
} else {
|
|
117
|
-
const detail = state.kind === "stale" ? `Stale path: ${state.path}` : `Absolute path (legacy): ${state.path}`;
|
|
129
|
+
} else if (state.kind === "npx") {
|
|
118
130
|
checks.push({
|
|
119
|
-
label: "
|
|
131
|
+
label: "Project .mcp.json",
|
|
120
132
|
ok: false,
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
warn: true,
|
|
134
|
+
detail: "Project-scope npx entry shadows user-scope server",
|
|
135
|
+
fix: 'Run "cf update" to remove it automatically'
|
|
123
136
|
});
|
|
124
137
|
}
|
|
125
138
|
const distExists = deps.pathExists(deps.memoryDistPath);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/lib/paths.ts
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { resolve, join, isAbsolute } from "path";
|
|
4
|
+
var CODEX_MARKETPLACE_NAME = "coding-friend-marketplace";
|
|
5
|
+
var CODEX_PLUGIN_NAME = "coding-friend";
|
|
4
6
|
function resolvePath(p, base = process.cwd()) {
|
|
5
7
|
if (isAbsolute(p)) return p;
|
|
6
8
|
if (p.startsWith("~/")) return join(homedir(), p.slice(2));
|
|
@@ -77,6 +79,29 @@ function claudeProjectsDir() {
|
|
|
77
79
|
function claudeSessionDir(encodedPath) {
|
|
78
80
|
return join(claudeProjectsDir(), encodedPath);
|
|
79
81
|
}
|
|
82
|
+
function codexConfigDir() {
|
|
83
|
+
const env = process.env.CODEX_HOME?.trim();
|
|
84
|
+
if (!env) return join(homedir(), ".codex");
|
|
85
|
+
if (env === "~") return homedir();
|
|
86
|
+
if (env.startsWith("~/")) return join(homedir(), env.slice(2));
|
|
87
|
+
return env;
|
|
88
|
+
}
|
|
89
|
+
function codexConfigTomlPath() {
|
|
90
|
+
return join(codexConfigDir(), "config.toml");
|
|
91
|
+
}
|
|
92
|
+
function codexPluginsCacheDir() {
|
|
93
|
+
return join(codexConfigDir(), "plugins", "cache");
|
|
94
|
+
}
|
|
95
|
+
function codexInstalledPluginsPath() {
|
|
96
|
+
return join(
|
|
97
|
+
codexPluginsCacheDir(),
|
|
98
|
+
CODEX_MARKETPLACE_NAME,
|
|
99
|
+
CODEX_PLUGIN_NAME
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
function codexAgentsDir() {
|
|
103
|
+
return join(codexConfigDir(), "agents");
|
|
104
|
+
}
|
|
80
105
|
|
|
81
106
|
export {
|
|
82
107
|
resolvePath,
|
|
@@ -95,5 +120,8 @@ export {
|
|
|
95
120
|
globalConfigDir,
|
|
96
121
|
memoryDepsDir,
|
|
97
122
|
encodeProjectPath,
|
|
98
|
-
claudeSessionDir
|
|
123
|
+
claudeSessionDir,
|
|
124
|
+
codexConfigTomlPath,
|
|
125
|
+
codexInstalledPluginsPath,
|
|
126
|
+
codexAgentsDir
|
|
99
127
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CONFIG
|
|
3
3
|
} from "./chunk-3WIZA5OZ.js";
|
|
4
|
+
import {
|
|
5
|
+
run
|
|
6
|
+
} from "./chunk-EVGXUDX4.js";
|
|
4
7
|
import {
|
|
5
8
|
readJson
|
|
6
9
|
} from "./chunk-5UVDWG5L.js";
|
|
@@ -8,13 +11,37 @@ import {
|
|
|
8
11
|
globalConfigPath,
|
|
9
12
|
localConfigPath,
|
|
10
13
|
resolvePath
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
12
15
|
import {
|
|
13
16
|
log
|
|
14
17
|
} from "./chunk-NREZK463.js";
|
|
15
18
|
|
|
16
19
|
// src/lib/config.ts
|
|
20
|
+
import { resolve as resolve2, isAbsolute } from "path";
|
|
17
21
|
import { z } from "zod";
|
|
22
|
+
|
|
23
|
+
// src/lib/project-root.ts
|
|
24
|
+
import { resolve } from "path";
|
|
25
|
+
function resolveMainRepoRoot(baseDir) {
|
|
26
|
+
const gitCommonDir = run("git", ["-C", baseDir, "rev-parse", "--git-common-dir"]);
|
|
27
|
+
if (!gitCommonDir) {
|
|
28
|
+
return resolve(baseDir);
|
|
29
|
+
}
|
|
30
|
+
if (gitCommonDir === ".git") {
|
|
31
|
+
return resolve(baseDir);
|
|
32
|
+
}
|
|
33
|
+
if (gitCommonDir.endsWith("/.git")) {
|
|
34
|
+
const candidate = gitCommonDir.slice(0, -5);
|
|
35
|
+
return resolve(baseDir, candidate);
|
|
36
|
+
}
|
|
37
|
+
const topLevel = run("git", ["-C", baseDir, "rev-parse", "--show-toplevel"]);
|
|
38
|
+
if (topLevel) {
|
|
39
|
+
return resolve(baseDir, topLevel);
|
|
40
|
+
}
|
|
41
|
+
return resolve(baseDir);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/lib/config.ts
|
|
18
45
|
function deepMerge(base, override) {
|
|
19
46
|
const result = { ...base };
|
|
20
47
|
for (const key of Object.keys(override)) {
|
|
@@ -80,6 +107,7 @@ var ConfigSchema = z.strictObject({
|
|
|
80
107
|
memory: MemoryConfigSchema.optional(),
|
|
81
108
|
review: ReviewConfigSchema.optional(),
|
|
82
109
|
autoApprove: z.boolean().optional(),
|
|
110
|
+
autoApproveCodex: z.boolean().optional(),
|
|
83
111
|
autoApproveIgnore: z.array(z.string()).optional(),
|
|
84
112
|
autoApproveAllowExtra: z.array(z.string()).optional(),
|
|
85
113
|
disableGUIPlan: z.boolean().optional(),
|
|
@@ -94,6 +122,7 @@ var KNOWN_KEYS = [
|
|
|
94
122
|
"memory",
|
|
95
123
|
"review",
|
|
96
124
|
"autoApprove",
|
|
125
|
+
"autoApproveCodex",
|
|
97
126
|
"autoApproveIgnore",
|
|
98
127
|
"autoApproveAllowExtra",
|
|
99
128
|
"disableGUIPlan",
|
|
@@ -213,10 +242,21 @@ function resolveMemoryDir(explicitPath) {
|
|
|
213
242
|
}
|
|
214
243
|
return resolvePath("docs/memory");
|
|
215
244
|
}
|
|
245
|
+
function resolveProjectMemoryDir(baseDir) {
|
|
246
|
+
const root = resolveMainRepoRoot(baseDir);
|
|
247
|
+
const configPath = resolve2(root, ".coding-friend", "config.json");
|
|
248
|
+
const config = readJson(configPath);
|
|
249
|
+
const docsDir = config?.docsDir ?? "docs";
|
|
250
|
+
if (isAbsolute(docsDir)) {
|
|
251
|
+
return resolve2(docsDir, "memory");
|
|
252
|
+
}
|
|
253
|
+
return resolve2(root, docsDir, "memory");
|
|
254
|
+
}
|
|
216
255
|
|
|
217
256
|
export {
|
|
218
257
|
sanitizeRawConfig,
|
|
219
258
|
loadConfig,
|
|
220
259
|
resolveLearnDir,
|
|
221
|
-
resolveMemoryDir
|
|
260
|
+
resolveMemoryDir,
|
|
261
|
+
resolveProjectMemoryDir
|
|
222
262
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig,
|
|
3
3
|
resolveMemoryDir
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RFNKPAJW.js";
|
|
5
5
|
import "./chunk-3WIZA5OZ.js";
|
|
6
|
+
import "./chunk-EVGXUDX4.js";
|
|
6
7
|
import "./chunk-5UVDWG5L.js";
|
|
7
8
|
import {
|
|
8
9
|
resolvePath
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
10
11
|
import {
|
|
11
12
|
log,
|
|
12
13
|
printBanner
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAllRules,
|
|
3
3
|
getExistingRules
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RCE4OWNX.js";
|
|
5
5
|
import {
|
|
6
6
|
listMdFilesRecursive
|
|
7
7
|
} from "./chunk-2DTXVMPQ.js";
|
|
8
8
|
import {
|
|
9
9
|
registerLearnMcp,
|
|
10
10
|
unregisterLearnMcp
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
memoryConfigMenu
|
|
14
|
-
} from "./chunk-N4WZWRCI.js";
|
|
11
|
+
} from "./chunk-6NXZKAOV.js";
|
|
15
12
|
import {
|
|
16
13
|
resolveLearnDir
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-RZRT7NGT.js";
|
|
14
|
+
} from "./chunk-RFNKPAJW.js";
|
|
19
15
|
import {
|
|
20
16
|
findStatuslineHookPath,
|
|
21
17
|
getCurrentAccountEmail,
|
|
@@ -26,7 +22,7 @@ import {
|
|
|
26
22
|
saveStatuslineConfig,
|
|
27
23
|
selectStatuslineComponents,
|
|
28
24
|
writeStatuslineSettings
|
|
29
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-ETTZRJ55.js";
|
|
30
26
|
import {
|
|
31
27
|
ALL_COMPONENT_IDS,
|
|
32
28
|
DEFAULT_CONFIG
|
|
@@ -36,6 +32,10 @@ import {
|
|
|
36
32
|
hasShellCompletion,
|
|
37
33
|
removeShellCompletion
|
|
38
34
|
} from "./chunk-667NMPN4.js";
|
|
35
|
+
import {
|
|
36
|
+
memoryConfigMenu
|
|
37
|
+
} from "./chunk-BXSCYGWE.js";
|
|
38
|
+
import "./chunk-RZRT7NGT.js";
|
|
39
39
|
import {
|
|
40
40
|
BACK,
|
|
41
41
|
applyDocsDirChange,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
getScopeLabel,
|
|
46
46
|
injectBackChoice,
|
|
47
47
|
showConfigHint
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-GIH6E7GJ.js";
|
|
49
49
|
import "./chunk-EVGXUDX4.js";
|
|
50
50
|
import {
|
|
51
51
|
mergeJson,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
globalConfigPath,
|
|
59
59
|
localConfigPath,
|
|
60
60
|
resolvePath
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
62
62
|
import {
|
|
63
63
|
log,
|
|
64
64
|
printBanner
|
|
@@ -448,11 +448,7 @@ async function editDisableGUIPlan(globalCfg, localCfg) {
|
|
|
448
448
|
writeToScope(scope, { disableGUIPlan: value });
|
|
449
449
|
}
|
|
450
450
|
async function editGuiPlanFormat(globalCfg, localCfg) {
|
|
451
|
-
const currentValue = getMergedValue(
|
|
452
|
-
"guiPlanFormat",
|
|
453
|
-
globalCfg,
|
|
454
|
-
localCfg
|
|
455
|
-
);
|
|
451
|
+
const currentValue = getMergedValue("guiPlanFormat", globalCfg, localCfg);
|
|
456
452
|
if (currentValue !== void 0) {
|
|
457
453
|
log.dim(`Current: ${currentValue}`);
|
|
458
454
|
}
|
|
@@ -476,16 +472,8 @@ async function planDocsSubMenu() {
|
|
|
476
472
|
while (true) {
|
|
477
473
|
const globalCfg = readJson(globalConfigPath());
|
|
478
474
|
const localCfg = readJson(localConfigPath());
|
|
479
|
-
const disableVal = getMergedValue(
|
|
480
|
-
|
|
481
|
-
globalCfg,
|
|
482
|
-
localCfg
|
|
483
|
-
);
|
|
484
|
-
const formatVal = getMergedValue(
|
|
485
|
-
"guiPlanFormat",
|
|
486
|
-
globalCfg,
|
|
487
|
-
localCfg
|
|
488
|
-
);
|
|
475
|
+
const disableVal = getMergedValue("disableGUIPlan", globalCfg, localCfg);
|
|
476
|
+
const formatVal = getMergedValue("guiPlanFormat", globalCfg, localCfg);
|
|
489
477
|
const choice = await select({
|
|
490
478
|
message: "Plan docs settings:",
|
|
491
479
|
choices: injectBackChoice(
|
|
@@ -553,7 +541,7 @@ async function editAutoApprove(globalCfg, localCfg) {
|
|
|
553
541
|
if (scope === "back") return;
|
|
554
542
|
writeToScope(scope, { autoApprove: value });
|
|
555
543
|
if (value) {
|
|
556
|
-
const { runDangerousRulesAudit } = await import("./permissions-
|
|
544
|
+
const { runDangerousRulesAudit } = await import("./permissions-2SBACQHV.js");
|
|
557
545
|
await runDangerousRulesAudit(
|
|
558
546
|
[
|
|
559
547
|
claudeProjectSettingsPath(),
|
|
@@ -749,7 +737,7 @@ async function editPermissions() {
|
|
|
749
737
|
)
|
|
750
738
|
});
|
|
751
739
|
if (choice === BACK) return;
|
|
752
|
-
const { permissionCommand } = await import("./permission-
|
|
740
|
+
const { permissionCommand } = await import("./permission-VISPGMUK.js");
|
|
753
741
|
switch (choice) {
|
|
754
742
|
case "interactive":
|
|
755
743
|
await permissionCommand({});
|