coding-friend-cli 1.37.0 → 1.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- 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-DP6DFQ4G.js → chunk-BXSCYGWE.js} +2 -2
- package/dist/{chunk-W6D3J5DX.js → chunk-CGEMETKQ.js} +8 -6
- package/dist/{chunk-XEKQW4RN.js → chunk-ETTZRJ55.js} +1 -1
- package/dist/{chunk-IKLMHJH6.js → chunk-GIH6E7GJ.js} +62 -1
- package/dist/{chunk-6S7352JG.js → chunk-ONG4KRYP.js} +1 -1
- package/dist/{chunk-X2H7JJMR.js → chunk-PLSJW7QJ.js} +29 -1
- package/dist/{chunk-O5ZKLFSL.js → chunk-RCE4OWNX.js} +1 -1
- package/dist/{chunk-PI4P34KF.js → chunk-RFNKPAJW.js} +3 -1
- package/dist/{chunk-676YCW6T.js → chunk-XAYWGZQT.js} +101 -8
- package/dist/{clean-WEYQZB34.js → clean-YWEMYDE5.js} +2 -2
- package/dist/{config-ZMR2AOBB.js → config-NG7SICM4.js} +12 -24
- 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-SSRI4JZV.js → host-EV6QIVTI.js} +2 -2
- package/dist/index.js +59 -47
- package/dist/{init-6MFQWPOP.js → init-KYE5CJMW.js} +115 -12
- package/dist/{install-37NN4CQH.js → install-3YEPLDMD.js} +79 -6
- package/dist/{learn-OPH3CI67.js → learn-MC4VDHZH.js} +2 -2
- package/dist/{mcp-DWKVMNC7.js → mcp-FV6YX3ZT.js} +7 -7
- package/dist/{mcp-serve-5GODJ4DJ.js → mcp-serve-PXREYQRZ.js} +2 -2
- package/dist/{mcp-serve-learn-OF3ZJUJC.js → mcp-serve-learn-UVXIDOEZ.js} +1 -1
- package/dist/{memory-TRDLADUM.js → memory-DF7OUOTV.js} +6 -6
- package/dist/{permission-I3OFJUYA.js → permission-VISPGMUK.js} +38 -4
- package/dist/{permissions-J46VP6US.js → permissions-2SBACQHV.js} +2 -2
- package/dist/{session-S4WKA4P5.js → session-QK6OZO3X.js} +2 -2
- package/dist/{status-YZEOUX46.js → status-6HQRVZKR.js} +11 -10
- package/dist/{statusline-KKFJPTI7.js → statusline-AOZHEQSV.js} +2 -2
- package/dist/{uninstall-AVA3J554.js → uninstall-MF6FRUBO.js} +51 -4
- package/dist/{update-Q3ACCK4Z.js → update-SMWXKJ3R.js} +6 -5
- package/dist/{update-check-25SCLHZO.js → update-check-7LKJLJPM.js} +1 -1
- 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__/sqlite-lazy-db.test.ts +0 -213
- 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 -388
- 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
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# coding-friend-cli
|
|
2
2
|
|
|
3
|
-
CLI companion for the [coding-friend](https://github.com/dinhanhthi/coding-friend) plugin — a lean toolkit for disciplined engineering workflows with Claude Code.
|
|
3
|
+
CLI companion for the [coding-friend](https://github.com/dinhanhthi/coding-friend) plugin — a lean toolkit for disciplined engineering workflows with Claude Code and Codex CLI.
|
|
4
4
|
|
|
5
5
|
## Plugin without the CLI?
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ Everything else (every skill, every agent, every hook except the three OPTIONAL
|
|
|
23
23
|
|
|
24
24
|
- Node.js >= 20
|
|
25
25
|
- npm (included with Node.js, but on some Linux distros you may need to install it separately)
|
|
26
|
-
- The [coding-friend plugin](https://github.com/dinhanhthi/coding-friend) installed in Claude Code
|
|
26
|
+
- The [coding-friend plugin](https://github.com/dinhanhthi/coding-friend) installed in Claude Code or Codex CLI
|
|
27
27
|
|
|
28
28
|
### Additional requirements for `cf memory init`
|
|
29
29
|
|
|
@@ -56,12 +56,14 @@ cf install --user # Install at user scope (all projects)
|
|
|
56
56
|
cf install --global # Same as --user
|
|
57
57
|
cf install --project # Install at project scope (shared via git)
|
|
58
58
|
cf install --local # Install at local scope (this machine only)
|
|
59
|
+
cf install --agent codex # Register/install Coding Friend for Codex CLI
|
|
59
60
|
# 💡 Safe to run multiple times (idempotent).
|
|
60
61
|
cf uninstall # Uninstall plugin (interactive scope chooser)
|
|
61
62
|
cf uninstall --user # Uninstall from user scope (full cleanup)
|
|
62
63
|
cf uninstall --global # Same as --user
|
|
63
64
|
cf uninstall --project # Uninstall from project scope only
|
|
64
65
|
cf uninstall --local # Uninstall from local scope only
|
|
66
|
+
cf uninstall --agent codex # Disable Coding Friend in Codex CLI
|
|
65
67
|
# 💡 Interactive — asks for confirmation before acting.
|
|
66
68
|
cf disable # Disable plugin (interactive scope chooser)
|
|
67
69
|
cf disable --user # Disable at user scope (all projects)
|
|
@@ -75,6 +77,7 @@ cf enable --global # Same as --user
|
|
|
75
77
|
cf enable --project # Enable at project scope
|
|
76
78
|
cf enable --local # Enable at local scope
|
|
77
79
|
cf init # Initialize workspace (interactive)
|
|
80
|
+
cf init --agent codex # Initialize workspace for Codex CLI
|
|
78
81
|
# 💡 You can run this anywhere, anytime.
|
|
79
82
|
cf config # Manage Coding Friend configuration (interactive menu)
|
|
80
83
|
# 💡 Edit docsDir, language, learn settings, and more.
|
|
@@ -89,6 +92,7 @@ cf permission # Manage Claude Code permission rules (interactive)
|
|
|
89
92
|
cf permission --all # Apply all recommended permissions without prompts
|
|
90
93
|
cf permission --user # Save to user-level settings (~/.claude/settings.json)
|
|
91
94
|
cf permission --project # Save to project-level settings (.claude/settings.local.json)
|
|
95
|
+
cf permission --agent codex --enable-auto-approve
|
|
92
96
|
cf permission --all --user # Apply all recommended permissions to user settings
|
|
93
97
|
cf statusline # Setup coding-friend statusline
|
|
94
98
|
cf update # Update plugin + CLI + statusline
|
|
@@ -97,6 +101,7 @@ cf update # Update plugin + CLI + statusline
|
|
|
97
101
|
cf update --cli # Update only the CLI (npm package)
|
|
98
102
|
cf update --plugin # Update only the Claude Code plugin
|
|
99
103
|
cf update --statusline # Update only the statusline
|
|
104
|
+
cf update --agent codex # Update Codex marketplace/plugin cache
|
|
100
105
|
cf update --project # Update plugin at project scope
|
|
101
106
|
cf update --local # Update plugin at local scope
|
|
102
107
|
cf dev on [path] # Switch to local plugin source for development
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
codexAgentsDir,
|
|
3
|
+
codexConfigTomlPath,
|
|
4
|
+
codexInstalledPluginsPath
|
|
5
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
6
|
+
|
|
7
|
+
// src/lib/codex-config.ts
|
|
8
|
+
import {
|
|
9
|
+
copyFileSync,
|
|
10
|
+
existsSync,
|
|
11
|
+
mkdirSync,
|
|
12
|
+
readdirSync,
|
|
13
|
+
readFileSync,
|
|
14
|
+
rmSync,
|
|
15
|
+
writeFileSync
|
|
16
|
+
} from "fs";
|
|
17
|
+
import { basename, dirname, join, resolve } from "path";
|
|
18
|
+
var CODEX_MARKETPLACE_NAME = "coding-friend-marketplace";
|
|
19
|
+
var CODEX_PLUGIN_NAME = "coding-friend";
|
|
20
|
+
var CODEX_PLUGIN_ID = `${CODEX_PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
21
|
+
var CODEX_PLUGIN_TABLE = `plugins."${CODEX_PLUGIN_ID}"`;
|
|
22
|
+
var CODEX_MEMORY_MCP_TABLE = "mcp_servers.coding-friend-memory";
|
|
23
|
+
function readToml(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
return readFileSync(filePath, "utf8");
|
|
26
|
+
} catch {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function writeToml(filePath, content) {
|
|
31
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
32
|
+
writeFileSync(filePath, content.endsWith("\n") ? content : `${content}
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
function tomlString(value) {
|
|
36
|
+
return JSON.stringify(value);
|
|
37
|
+
}
|
|
38
|
+
function tableHeader(tableName) {
|
|
39
|
+
return `[${tableName}]`;
|
|
40
|
+
}
|
|
41
|
+
function findTableRange(lines, header) {
|
|
42
|
+
const start = lines.findIndex((line) => line.trim() === header);
|
|
43
|
+
if (start === -1) return null;
|
|
44
|
+
let end = lines.length;
|
|
45
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
46
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[index])) {
|
|
47
|
+
end = index;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { start, end };
|
|
52
|
+
}
|
|
53
|
+
function replaceTable(content, tableName, body) {
|
|
54
|
+
const header = tableHeader(tableName);
|
|
55
|
+
const lines = content.split(/\n/);
|
|
56
|
+
const range = findTableRange(lines, header);
|
|
57
|
+
const nextBlock = [header, ...body];
|
|
58
|
+
if (range) {
|
|
59
|
+
lines.splice(range.start, range.end - range.start, ...nextBlock);
|
|
60
|
+
return `${lines.join("\n").replace(/\n*$/, "")}
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
const prefix = content.replace(/\n*$/, "");
|
|
64
|
+
return `${prefix}${prefix ? "\n\n" : ""}${nextBlock.join("\n")}
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
function upsertTableKey(content, tableName, key, valueLine) {
|
|
68
|
+
const header = tableHeader(tableName);
|
|
69
|
+
const lines = content.split(/\n/);
|
|
70
|
+
const range = findTableRange(lines, header);
|
|
71
|
+
if (!range) {
|
|
72
|
+
return replaceTable(content, tableName, [valueLine]);
|
|
73
|
+
}
|
|
74
|
+
const keyPattern = new RegExp(`^\\s*${key}\\s*=`);
|
|
75
|
+
let replaced = false;
|
|
76
|
+
for (let index = range.start + 1; index < range.end; index += 1) {
|
|
77
|
+
if (keyPattern.test(lines[index])) {
|
|
78
|
+
lines[index] = valueLine;
|
|
79
|
+
replaced = true;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!replaced) {
|
|
84
|
+
lines.splice(range.end, 0, valueLine);
|
|
85
|
+
}
|
|
86
|
+
return `${lines.join("\n").replace(/\n*$/, "")}
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
function getTable(content, tableName) {
|
|
90
|
+
const lines = content.split(/\n/);
|
|
91
|
+
const range = findTableRange(lines, tableHeader(tableName));
|
|
92
|
+
if (!range) return [];
|
|
93
|
+
return lines.slice(range.start + 1, range.end);
|
|
94
|
+
}
|
|
95
|
+
function isCodexMarketplaceRegistered(configPath = codexConfigTomlPath()) {
|
|
96
|
+
return readToml(configPath).split(/\n/).some(
|
|
97
|
+
(line) => line.trim() === tableHeader(`marketplaces.${CODEX_MARKETPLACE_NAME}`)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
function setCodexPluginEnabled(enabled, configPath = codexConfigTomlPath()) {
|
|
101
|
+
const content = readToml(configPath);
|
|
102
|
+
writeToml(
|
|
103
|
+
configPath,
|
|
104
|
+
upsertTableKey(
|
|
105
|
+
content,
|
|
106
|
+
CODEX_PLUGIN_TABLE,
|
|
107
|
+
"enabled",
|
|
108
|
+
`enabled = ${enabled ? "true" : "false"}`
|
|
109
|
+
)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function isCodexPluginDisabled(configPath = codexConfigTomlPath()) {
|
|
113
|
+
const table = getTable(readToml(configPath), CODEX_PLUGIN_TABLE);
|
|
114
|
+
return table.some((line) => /^\s*enabled\s*=\s*false\s*(?:#.*)?$/.test(line));
|
|
115
|
+
}
|
|
116
|
+
function removeTable(content, tableName) {
|
|
117
|
+
const lines = content.split(/\n/);
|
|
118
|
+
const range = findTableRange(lines, tableHeader(tableName));
|
|
119
|
+
if (!range) return content;
|
|
120
|
+
let start = range.start;
|
|
121
|
+
while (start > 0 && lines[start - 1].trim() === "") start -= 1;
|
|
122
|
+
lines.splice(start, range.end - start);
|
|
123
|
+
return `${lines.join("\n").replace(/\n*$/, "")}
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
function removeCodexMemoryMcpConfig(configPath = codexConfigTomlPath()) {
|
|
127
|
+
const content = readToml(configPath);
|
|
128
|
+
const next = removeTable(content, CODEX_MEMORY_MCP_TABLE);
|
|
129
|
+
if (next === content) return false;
|
|
130
|
+
writeToml(configPath, next);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
function removeDeployedCodexAgents(targetDir = codexAgentsDir()) {
|
|
134
|
+
if (!existsSync(targetDir)) return 0;
|
|
135
|
+
let removed = 0;
|
|
136
|
+
for (const entry of readdirSync(targetDir, { withFileTypes: true })) {
|
|
137
|
+
if (!entry.isFile() || !/^cf-.*\.toml$/.test(entry.name)) continue;
|
|
138
|
+
rmSync(join(targetDir, entry.name));
|
|
139
|
+
removed += 1;
|
|
140
|
+
}
|
|
141
|
+
return removed;
|
|
142
|
+
}
|
|
143
|
+
function writeCodexMemoryMcpConfig(memoryDir, configPath = codexConfigTomlPath()) {
|
|
144
|
+
const content = readToml(configPath);
|
|
145
|
+
writeToml(
|
|
146
|
+
configPath,
|
|
147
|
+
replaceTable(content, CODEX_MEMORY_MCP_TABLE, [
|
|
148
|
+
'command = "npx"',
|
|
149
|
+
`args = ["-y", "coding-friend-cli", "mcp-serve", ${tomlString(memoryDir)}]`
|
|
150
|
+
])
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
function writeCodexAgentLimits(configPath = codexConfigTomlPath()) {
|
|
154
|
+
const content = readToml(configPath);
|
|
155
|
+
writeToml(
|
|
156
|
+
configPath,
|
|
157
|
+
upsertTableKey(content, "agents", "max_depth", "max_depth = 2")
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function trustCodexProject(projectPath = process.cwd(), configPath = codexConfigTomlPath()) {
|
|
161
|
+
const tableName = `projects.${tomlString(projectPath)}`;
|
|
162
|
+
const content = readToml(configPath);
|
|
163
|
+
writeToml(
|
|
164
|
+
configPath,
|
|
165
|
+
upsertTableKey(
|
|
166
|
+
content,
|
|
167
|
+
tableName,
|
|
168
|
+
"trust_level",
|
|
169
|
+
'trust_level = "trusted"'
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
function generatedCodexAgentsDir(repoRoot = process.cwd()) {
|
|
174
|
+
return resolve(repoRoot, "plugin-codex", "agents");
|
|
175
|
+
}
|
|
176
|
+
function compareVersions(a, b) {
|
|
177
|
+
const left = a.split(".").map((part) => Number.parseInt(part, 10));
|
|
178
|
+
const right = b.split(".").map((part) => Number.parseInt(part, 10));
|
|
179
|
+
for (let index = 0; index < 3; index += 1) {
|
|
180
|
+
const diff = (left[index] || 0) - (right[index] || 0);
|
|
181
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
182
|
+
}
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
function latestCodexInstalledPluginDir(pluginRoot = codexInstalledPluginsPath()) {
|
|
186
|
+
const directManifest = join(pluginRoot, ".codex-plugin", "plugin.json");
|
|
187
|
+
if (existsSync(directManifest)) return pluginRoot;
|
|
188
|
+
if (!existsSync(pluginRoot)) return null;
|
|
189
|
+
const versions = readdirSync(pluginRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter(
|
|
190
|
+
(version) => existsSync(join(pluginRoot, version, ".codex-plugin", "plugin.json"))
|
|
191
|
+
).sort(compareVersions).reverse();
|
|
192
|
+
return versions[0] ? join(pluginRoot, versions[0]) : null;
|
|
193
|
+
}
|
|
194
|
+
function getCodexInstalledVersion(pluginRoot = codexInstalledPluginsPath()) {
|
|
195
|
+
const pluginDir = latestCodexInstalledPluginDir(pluginRoot);
|
|
196
|
+
if (!pluginDir) return null;
|
|
197
|
+
try {
|
|
198
|
+
const manifest = JSON.parse(
|
|
199
|
+
readFileSync(join(pluginDir, ".codex-plugin", "plugin.json"), "utf8")
|
|
200
|
+
);
|
|
201
|
+
return manifest.version ?? basename(pluginDir);
|
|
202
|
+
} catch {
|
|
203
|
+
return basename(pluginDir);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function findCodexAgentSourceDir(repoRoot = process.cwd()) {
|
|
207
|
+
const generated = generatedCodexAgentsDir(repoRoot);
|
|
208
|
+
if (existsSync(generated)) return generated;
|
|
209
|
+
const installedPluginDir = latestCodexInstalledPluginDir();
|
|
210
|
+
const installedAgents = installedPluginDir ? join(installedPluginDir, "agents") : null;
|
|
211
|
+
return installedAgents && existsSync(installedAgents) ? installedAgents : null;
|
|
212
|
+
}
|
|
213
|
+
function deployCodexAgents(sourceDir, targetDir = codexAgentsDir()) {
|
|
214
|
+
if (!existsSync(sourceDir)) return 0;
|
|
215
|
+
mkdirSync(targetDir, { recursive: true });
|
|
216
|
+
let copied = 0;
|
|
217
|
+
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
218
|
+
if (!entry.isFile() || !entry.name.endsWith(".toml")) continue;
|
|
219
|
+
copyFileSync(join(sourceDir, entry.name), join(targetDir, entry.name));
|
|
220
|
+
copied += 1;
|
|
221
|
+
}
|
|
222
|
+
return copied;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export {
|
|
226
|
+
CODEX_MARKETPLACE_NAME,
|
|
227
|
+
isCodexMarketplaceRegistered,
|
|
228
|
+
setCodexPluginEnabled,
|
|
229
|
+
isCodexPluginDisabled,
|
|
230
|
+
removeCodexMemoryMcpConfig,
|
|
231
|
+
removeDeployedCodexAgents,
|
|
232
|
+
writeCodexMemoryMcpConfig,
|
|
233
|
+
writeCodexAgentLimits,
|
|
234
|
+
trustCodexProject,
|
|
235
|
+
getCodexInstalledVersion,
|
|
236
|
+
findCodexAgentSourceDir,
|
|
237
|
+
deployCodexAgents
|
|
238
|
+
};
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
askScope,
|
|
7
7
|
formatScopeLabel,
|
|
8
8
|
injectBackChoice
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GIH6E7GJ.js";
|
|
10
10
|
import {
|
|
11
11
|
runWithStderr
|
|
12
12
|
} from "./chunk-EVGXUDX4.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
claudeConfigDir,
|
|
20
20
|
globalConfigPath,
|
|
21
21
|
localConfigPath
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
23
23
|
import {
|
|
24
24
|
log
|
|
25
25
|
} from "./chunk-NREZK463.js";
|
|
@@ -2,23 +2,23 @@ import {
|
|
|
2
2
|
checkMemoryMcpHealth,
|
|
3
3
|
printHealthSection,
|
|
4
4
|
warnStaleMcpJson
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ONG4KRYP.js";
|
|
6
6
|
import {
|
|
7
7
|
loadConfig,
|
|
8
8
|
resolveMemoryDir
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RFNKPAJW.js";
|
|
10
10
|
import {
|
|
11
11
|
getMemoryMcpStatus,
|
|
12
12
|
isMemoryMcpRegistered,
|
|
13
13
|
memoryConfigMenu,
|
|
14
14
|
registerMemoryMcp
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BXSCYGWE.js";
|
|
16
16
|
import {
|
|
17
17
|
getLibPath
|
|
18
18
|
} from "./chunk-RZRT7NGT.js";
|
|
19
19
|
import {
|
|
20
20
|
showConfigHint
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GIH6E7GJ.js";
|
|
22
22
|
import {
|
|
23
23
|
run,
|
|
24
24
|
runWithStderr
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
globalConfigPath,
|
|
32
32
|
localConfigPath
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
34
34
|
import {
|
|
35
35
|
log,
|
|
36
36
|
printBanner
|
|
@@ -104,7 +104,9 @@ async function refreshMemoryAfterUpdate() {
|
|
|
104
104
|
log.warn('Memory server build failed \u2014 run "cf memory status" to retry.');
|
|
105
105
|
}
|
|
106
106
|
} catch {
|
|
107
|
-
log.warn(
|
|
107
|
+
log.warn(
|
|
108
|
+
'Could not refresh memory server \u2014 run "cf memory status" to retry.'
|
|
109
|
+
);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
function printMemoryMcpConfig(memoryDir) {
|
|
@@ -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,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
|
};
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
globalConfigPath,
|
|
12
12
|
localConfigPath,
|
|
13
13
|
resolvePath
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PLSJW7QJ.js";
|
|
15
15
|
import {
|
|
16
16
|
log
|
|
17
17
|
} from "./chunk-NREZK463.js";
|
|
@@ -107,6 +107,7 @@ var ConfigSchema = z.strictObject({
|
|
|
107
107
|
memory: MemoryConfigSchema.optional(),
|
|
108
108
|
review: ReviewConfigSchema.optional(),
|
|
109
109
|
autoApprove: z.boolean().optional(),
|
|
110
|
+
autoApproveCodex: z.boolean().optional(),
|
|
110
111
|
autoApproveIgnore: z.array(z.string()).optional(),
|
|
111
112
|
autoApproveAllowExtra: z.array(z.string()).optional(),
|
|
112
113
|
disableGUIPlan: z.boolean().optional(),
|
|
@@ -121,6 +122,7 @@ var KNOWN_KEYS = [
|
|
|
121
122
|
"memory",
|
|
122
123
|
"review",
|
|
123
124
|
"autoApprove",
|
|
125
|
+
"autoApproveCodex",
|
|
124
126
|
"autoApproveIgnore",
|
|
125
127
|
"autoApproveAllowExtra",
|
|
126
128
|
"disableGUIPlan",
|