coding-friend-cli 1.39.0 → 1.40.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 +5 -0
- package/dist/{chunk-ODW27NAC.js → chunk-B44ROTV6.js} +10 -10
- package/dist/{chunk-ZGIUKUL2.js → chunk-CZW36H3D.js} +39 -7
- package/dist/{chunk-FQUIO5BW.js → chunk-E4NBTQXR.js} +13 -7
- package/dist/{chunk-IV5OPG34.js → chunk-IYBIIRH4.js} +29 -1
- package/dist/{chunk-GTOEIGDM.js → chunk-KCBMCHSA.js} +295 -44
- package/dist/{chunk-463QKRBN.js → chunk-KG6HYBGD.js} +23 -7
- package/dist/{chunk-WJHQUCOF.js → chunk-KTUPGMIV.js} +111 -15
- package/dist/{chunk-7JQZRMOG.js → chunk-NIMO4VJW.js} +37 -6
- package/dist/{chunk-OFEC6OVI.js → chunk-OBCNHQFA.js} +42 -2
- package/dist/{chunk-4CPUWHIN.js → chunk-Q2QDSYQT.js} +1 -1
- package/dist/{chunk-JSH6BMVZ.js → chunk-RG3EMZH6.js} +11 -1
- package/dist/{chunk-2EY7VVFT.js → chunk-SUYE5S2W.js} +1 -1
- package/dist/{chunk-YPW67OGP.js → chunk-TFF47F7P.js} +1 -1
- package/dist/{chunk-ZZNTNIM4.js → chunk-TN3Y75WG.js} +2 -2
- package/dist/{chunk-VMODQCSL.js → chunk-Z5XTSF7L.js} +5 -5
- package/dist/{clean-LPWEBJJ5.js → clean-PKSSS662.js} +3 -3
- package/dist/{config-VNSC2NAY.js → config-2CH4GI2L.js} +47 -26
- package/dist/{dev-NRTDUQAR.js → dev-HWKNWOZY.js} +7 -7
- package/dist/{disable-NROSQUHR.js → disable-DCGVIHKG.js} +22 -8
- package/dist/{enable-26FFJGX5.js → enable-YYWJDOYB.js} +21 -8
- package/dist/{guide-HCLEOAGR.js → guide-45EIK76P.js} +1 -1
- package/dist/{host-2JOPHLN3.js → host-GZJSMJSF.js} +7 -7
- package/dist/index.js +67 -46
- package/dist/{init-MHHII5EP.js → init-TUBWQCBQ.js} +236 -53
- package/dist/{install-OEFJLAWA.js → install-45O5ICBA.js} +68 -11
- package/dist/{learn-SSNBBDY3.js → learn-AJT7Z6F7.js} +5 -5
- package/dist/{mcp-J5VO3OH7.js → mcp-JGBZMNWL.js} +26 -13
- package/dist/{mcp-serve-55DSE2J4.js → mcp-serve-SHS5MQRW.js} +5 -5
- package/dist/{mcp-serve-learn-EDBWNL4I.js → mcp-serve-learn-HXZZ3DUI.js} +6 -6
- package/dist/{memory-CDZKWOFL.js → memory-4NVLWOFS.js} +10 -10
- package/dist/{permission-DPKPA2HU.js → permission-L5QMNMID.js} +25 -25
- package/dist/{session-YWJDLNBP.js → session-GBHL5TH3.js} +3 -3
- package/dist/{status-4WMIQL7L.js → status-KQQJNSEZ.js} +33 -15
- package/dist/{statusline-R5BNYK3H.js → statusline-B7PXP3AQ.js} +3 -3
- package/dist/{uninstall-EV7362NK.js → uninstall-6QKNGLKK.js} +38 -13
- package/dist/{update-YQBBAIIF.js → update-YJ363TBU.js} +11 -11
- package/dist/{update-check-EJSGVGO6.js → update-check-5JZUJGUM.js} +1 -1
- package/package.json +1 -1
- package/dist/permissions-HZYUVKCY.js +0 -38
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getOmpExtensionPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TN3Y75WG.js";
|
|
4
4
|
import {
|
|
5
5
|
compareVersions
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OBCNHQFA.js";
|
|
7
7
|
import {
|
|
8
8
|
readJson,
|
|
9
9
|
writeJson
|
|
10
10
|
} from "./chunk-5UVDWG5L.js";
|
|
11
11
|
import {
|
|
12
|
+
commandExists,
|
|
13
|
+
run,
|
|
14
|
+
runWithStderr
|
|
15
|
+
} from "./chunk-EVGXUDX4.js";
|
|
16
|
+
import {
|
|
17
|
+
agyConfigDir,
|
|
18
|
+
agyConfigJsonPath,
|
|
19
|
+
agyConfigRoot,
|
|
20
|
+
agyPluginDir,
|
|
21
|
+
agyPluginsDir,
|
|
22
|
+
agySourceCloneDir,
|
|
23
|
+
devStatePath,
|
|
24
|
+
marketplaceClonePath,
|
|
12
25
|
ompConfigYmlPath,
|
|
13
26
|
ompExtensionsDir,
|
|
14
27
|
ompMcpJsonPath,
|
|
@@ -17,18 +30,244 @@ import {
|
|
|
17
30
|
ompProjectExtensionsDir,
|
|
18
31
|
ompUserAgentsDir,
|
|
19
32
|
pluginCachePath
|
|
20
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-IYBIIRH4.js";
|
|
21
34
|
|
|
22
|
-
// src/lib/
|
|
35
|
+
// src/lib/agy-config.ts
|
|
23
36
|
import {
|
|
37
|
+
cpSync,
|
|
24
38
|
existsSync,
|
|
25
39
|
mkdirSync,
|
|
26
40
|
readdirSync,
|
|
27
|
-
readFileSync,
|
|
28
41
|
rmSync,
|
|
29
|
-
|
|
42
|
+
statSync
|
|
30
43
|
} from "fs";
|
|
31
44
|
import { dirname, join, resolve } from "path";
|
|
45
|
+
var PLUGIN_NAME = "coding-friend";
|
|
46
|
+
var PLUGIN_SUBDIR = "plugin-antigravity";
|
|
47
|
+
var SOURCE_REPO = "https://github.com/dinhanhthi/coding-friend";
|
|
48
|
+
var INSTALLED_VERSION_FILE = "installed_version.json";
|
|
49
|
+
var PLUGIN_JSON = "plugin.json";
|
|
50
|
+
var MCP_CONFIG = "mcp_config.json";
|
|
51
|
+
function isPlainObject(value) {
|
|
52
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53
|
+
}
|
|
54
|
+
function isDirectory(path) {
|
|
55
|
+
try {
|
|
56
|
+
return statSync(path).isDirectory();
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function pluginSourcePath(root) {
|
|
62
|
+
return join(root, PLUGIN_SUBDIR);
|
|
63
|
+
}
|
|
64
|
+
function errorMessage(error) {
|
|
65
|
+
return error instanceof Error ? error.message : String(error);
|
|
66
|
+
}
|
|
67
|
+
function countFiles(dir) {
|
|
68
|
+
let count = 0;
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
72
|
+
} catch {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
count += countFiles(join(dir, entry.name));
|
|
78
|
+
} else {
|
|
79
|
+
count += 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return count;
|
|
83
|
+
}
|
|
84
|
+
function readVersionFromPluginJson(dir) {
|
|
85
|
+
const data = readJson(join(dir, PLUGIN_JSON));
|
|
86
|
+
if (typeof data?.version !== "string") return null;
|
|
87
|
+
const version = data.version.trim();
|
|
88
|
+
return version || null;
|
|
89
|
+
}
|
|
90
|
+
function ensureAgySourceClone(cloneDir) {
|
|
91
|
+
if (!commandExists("git")) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
"git is not installed or not on PATH. Cannot clone the Antigravity plugin source from GitHub."
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (existsSync(join(cloneDir, ".git"))) {
|
|
97
|
+
const result2 = run("git", ["-C", cloneDir, "pull", "--ff-only"]);
|
|
98
|
+
if (result2 === null) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Failed to update Antigravity plugin source at ${cloneDir} (git pull --ff-only). Delete that directory and retry, or check your network.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (existsSync(cloneDir)) {
|
|
106
|
+
rmSync(cloneDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
mkdirSync(dirname(cloneDir), { recursive: true });
|
|
109
|
+
const result = run("git", ["clone", "--depth", "1", SOURCE_REPO, cloneDir]);
|
|
110
|
+
if (result === null) {
|
|
111
|
+
rmSync(cloneDir, { recursive: true, force: true });
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Failed to clone ${SOURCE_REPO} into ${cloneDir}. Check your network and that git can reach GitHub. Cannot install a partial Antigravity plugin.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function resolveAgyPluginSource() {
|
|
118
|
+
const devState = readJson(devStatePath());
|
|
119
|
+
if (typeof devState?.localPath === "string" && devState.localPath.trim()) {
|
|
120
|
+
const path2 = pluginSourcePath(resolve(devState.localPath.trim()));
|
|
121
|
+
if (isDirectory(path2)) return { path: path2, kind: "dev" };
|
|
122
|
+
}
|
|
123
|
+
const marketplacePath = pluginSourcePath(marketplaceClonePath());
|
|
124
|
+
if (isDirectory(marketplacePath)) {
|
|
125
|
+
return { path: marketplacePath, kind: "marketplace" };
|
|
126
|
+
}
|
|
127
|
+
const cloneDir = agySourceCloneDir();
|
|
128
|
+
ensureAgySourceClone(cloneDir);
|
|
129
|
+
const path = pluginSourcePath(cloneDir);
|
|
130
|
+
if (!isDirectory(path)) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Cloned coding-friend source at ${cloneDir} is missing ${PLUGIN_SUBDIR}/. Cannot install the Antigravity plugin.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return { path, kind: "clone" };
|
|
136
|
+
}
|
|
137
|
+
function deployAgyPlugin(source) {
|
|
138
|
+
const resolvedSource = resolve(source);
|
|
139
|
+
if (!isDirectory(resolvedSource)) {
|
|
140
|
+
throw new Error(`Antigravity plugin source not found: ${resolvedSource}`);
|
|
141
|
+
}
|
|
142
|
+
const target = agyPluginDir();
|
|
143
|
+
if (resolvedSource === resolve(target)) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
"Cannot deploy Antigravity plugin: source and target are the same directory."
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
mkdirSync(agyPluginsDir(), { recursive: true });
|
|
149
|
+
rmSync(target, { recursive: true, force: true });
|
|
150
|
+
try {
|
|
151
|
+
cpSync(resolvedSource, target, { recursive: true });
|
|
152
|
+
} catch (error) {
|
|
153
|
+
rmSync(target, { recursive: true, force: true });
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Failed to copy Antigravity plugin from ${resolvedSource} to ${target}: ${errorMessage(error)}`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const files = countFiles(target);
|
|
159
|
+
if (files === 0) {
|
|
160
|
+
rmSync(target, { recursive: true, force: true });
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Antigravity plugin source ${resolvedSource} copied 0 files. Refusing partial install.`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
writeJson(join(target, INSTALLED_VERSION_FILE), {
|
|
166
|
+
version: readVersionFromPluginJson(resolvedSource) ?? "unknown",
|
|
167
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
+
source: resolvedSource
|
|
169
|
+
});
|
|
170
|
+
return { files };
|
|
171
|
+
}
|
|
172
|
+
function removeAgyPlugin() {
|
|
173
|
+
const target = agyPluginDir();
|
|
174
|
+
if (target === agyConfigRoot() || target === agyConfigDir() || target === agyPluginsDir()) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
"Refusing to remove Antigravity config root; expected the coding-friend plugin directory."
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (!existsSync(target)) return;
|
|
180
|
+
rmSync(target, { recursive: true, force: true });
|
|
181
|
+
}
|
|
182
|
+
function isAgyPluginInstalled() {
|
|
183
|
+
return existsSync(join(agyPluginDir(), PLUGIN_JSON));
|
|
184
|
+
}
|
|
185
|
+
function readAgyPluginVersion() {
|
|
186
|
+
const dir = agyPluginDir();
|
|
187
|
+
const installed = readJson(
|
|
188
|
+
join(dir, INSTALLED_VERSION_FILE)
|
|
189
|
+
);
|
|
190
|
+
if (typeof installed?.version === "string" && installed.version.trim()) {
|
|
191
|
+
return installed.version.trim();
|
|
192
|
+
}
|
|
193
|
+
return readVersionFromPluginJson(dir);
|
|
194
|
+
}
|
|
195
|
+
function setAgyPluginEnabled(enabled) {
|
|
196
|
+
const filePath = agyConfigJsonPath();
|
|
197
|
+
const existing = readJson(filePath);
|
|
198
|
+
const data = isPlainObject(existing) ? { ...existing } : {};
|
|
199
|
+
const plugins = isPlainObject(data.plugins) ? { ...data.plugins } : {};
|
|
200
|
+
const entry = isPlainObject(plugins[PLUGIN_NAME]) ? { ...plugins[PLUGIN_NAME] } : {};
|
|
201
|
+
entry.enabled = enabled;
|
|
202
|
+
plugins[PLUGIN_NAME] = entry;
|
|
203
|
+
data.plugins = plugins;
|
|
204
|
+
writeJson(filePath, data);
|
|
205
|
+
}
|
|
206
|
+
function isAgyPluginEnabled() {
|
|
207
|
+
const data = readJson(agyConfigJsonPath());
|
|
208
|
+
if (!data || !isPlainObject(data.plugins)) return false;
|
|
209
|
+
const entry = data.plugins[PLUGIN_NAME];
|
|
210
|
+
return isPlainObject(entry) && entry.enabled === true;
|
|
211
|
+
}
|
|
212
|
+
function removeAgyPluginConfigEntry() {
|
|
213
|
+
const filePath = agyConfigJsonPath();
|
|
214
|
+
const existing = readJson(filePath);
|
|
215
|
+
if (!existing || !isPlainObject(existing.plugins)) return false;
|
|
216
|
+
if (!(PLUGIN_NAME in existing.plugins)) return false;
|
|
217
|
+
const plugins = { ...existing.plugins };
|
|
218
|
+
delete plugins[PLUGIN_NAME];
|
|
219
|
+
writeJson(filePath, { ...existing, plugins });
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
function mcpConfigPath() {
|
|
223
|
+
return join(agyPluginDir(), MCP_CONFIG);
|
|
224
|
+
}
|
|
225
|
+
function readAgyMcpConfig() {
|
|
226
|
+
const data = readJson(mcpConfigPath());
|
|
227
|
+
if (!data || !isPlainObject(data.mcpServers)) return null;
|
|
228
|
+
return data;
|
|
229
|
+
}
|
|
230
|
+
function writeAgyMcpEntry(name, server) {
|
|
231
|
+
const filePath = mcpConfigPath();
|
|
232
|
+
const existing = readJson(filePath);
|
|
233
|
+
const data = isPlainObject(existing) ? { ...existing } : {};
|
|
234
|
+
const mcpServers = isPlainObject(
|
|
235
|
+
data.mcpServers
|
|
236
|
+
) ? { ...data.mcpServers } : {};
|
|
237
|
+
mcpServers[name] = server;
|
|
238
|
+
data.mcpServers = mcpServers;
|
|
239
|
+
writeJson(filePath, data);
|
|
240
|
+
}
|
|
241
|
+
function removeAgyMcpEntry(name) {
|
|
242
|
+
const filePath = mcpConfigPath();
|
|
243
|
+
const existing = readJson(filePath);
|
|
244
|
+
if (!existing || !isPlainObject(existing.mcpServers)) return;
|
|
245
|
+
const mcpServers = {
|
|
246
|
+
...existing.mcpServers
|
|
247
|
+
};
|
|
248
|
+
if (!(name in mcpServers)) return;
|
|
249
|
+
delete mcpServers[name];
|
|
250
|
+
writeJson(filePath, { ...existing, mcpServers });
|
|
251
|
+
}
|
|
252
|
+
function validateAgyPlugin(dir) {
|
|
253
|
+
if (!commandExists("agy")) {
|
|
254
|
+
return { stdout: "", status: 127 };
|
|
255
|
+
}
|
|
256
|
+
const result = runWithStderr("agy", ["plugin", "validate", dir]);
|
|
257
|
+
const stdout = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
|
258
|
+
return { stdout, status: result.exitCode };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/lib/omp-config.ts
|
|
262
|
+
import {
|
|
263
|
+
existsSync as existsSync2,
|
|
264
|
+
mkdirSync as mkdirSync2,
|
|
265
|
+
readdirSync as readdirSync2,
|
|
266
|
+
readFileSync,
|
|
267
|
+
rmSync as rmSync2,
|
|
268
|
+
writeFileSync
|
|
269
|
+
} from "fs";
|
|
270
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
32
271
|
var EXTENSION_SHIM = "coding-friend.ts";
|
|
33
272
|
var MANAGED_START = "# coding-friend-managed";
|
|
34
273
|
var MANAGED_END = "# end coding-friend-managed";
|
|
@@ -47,7 +286,7 @@ var FALLBACK_CF_AGENT_NAMES = [
|
|
|
47
286
|
"cf-writer",
|
|
48
287
|
"cf-writer-deep"
|
|
49
288
|
];
|
|
50
|
-
function
|
|
289
|
+
function isPlainObject2(value) {
|
|
51
290
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
291
|
}
|
|
53
292
|
function agentsDirForScope(scope) {
|
|
@@ -105,9 +344,9 @@ function isCfAgentFile(name) {
|
|
|
105
344
|
return /^cf-.*\.md$/.test(name);
|
|
106
345
|
}
|
|
107
346
|
function listMdFiles(dir) {
|
|
108
|
-
if (!
|
|
347
|
+
if (!existsSync2(dir)) return [];
|
|
109
348
|
try {
|
|
110
|
-
return
|
|
349
|
+
return readdirSync2(dir, { withFileTypes: true }).filter(
|
|
111
350
|
(entry) => (entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md")
|
|
112
351
|
).map((entry) => entry.name).sort();
|
|
113
352
|
} catch {
|
|
@@ -128,26 +367,26 @@ function ourAgentNames(scope) {
|
|
|
128
367
|
return [...names].sort();
|
|
129
368
|
}
|
|
130
369
|
function repoPluginCandidate(repoRoot, ...parts) {
|
|
131
|
-
const direct =
|
|
132
|
-
const parent =
|
|
133
|
-
if (
|
|
134
|
-
if (
|
|
135
|
-
if (
|
|
370
|
+
const direct = resolve2(repoRoot, ...parts);
|
|
371
|
+
const parent = resolve2(repoRoot, "..", ...parts);
|
|
372
|
+
if (existsSync2(direct)) return direct;
|
|
373
|
+
if (existsSync2(parent)) return parent;
|
|
374
|
+
if (existsSync2(resolve2(repoRoot, "..", "plugin", "agents"))) return parent;
|
|
136
375
|
return direct;
|
|
137
376
|
}
|
|
138
377
|
function latestCachedPluginDir(cacheRoot = pluginCachePath()) {
|
|
139
|
-
if (!
|
|
140
|
-
if (
|
|
378
|
+
if (!existsSync2(cacheRoot)) return null;
|
|
379
|
+
if (existsSync2(join2(cacheRoot, "agents"))) return cacheRoot;
|
|
141
380
|
let dirs = [];
|
|
142
381
|
try {
|
|
143
|
-
dirs =
|
|
382
|
+
dirs = readdirSync2(cacheRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
144
383
|
} catch {
|
|
145
384
|
return null;
|
|
146
385
|
}
|
|
147
386
|
const versions = dirs.filter((name) => /^\d/.test(name)).sort(compareVersions).reverse();
|
|
148
|
-
if (versions[0]) return
|
|
387
|
+
if (versions[0]) return join2(cacheRoot, versions[0]);
|
|
149
388
|
const rest = [...dirs].sort(compareVersions).reverse();
|
|
150
|
-
return rest[0] ?
|
|
389
|
+
return rest[0] ? join2(cacheRoot, rest[0]) : null;
|
|
151
390
|
}
|
|
152
391
|
function ensureNl(content) {
|
|
153
392
|
return content === "" || content.endsWith("\n") ? content : `${content}
|
|
@@ -347,18 +586,18 @@ function removeOurDisabledAgents(content, ours) {
|
|
|
347
586
|
return writeDisabledAgents(content, remaining, false);
|
|
348
587
|
}
|
|
349
588
|
function writeTextFile(filePath, content) {
|
|
350
|
-
|
|
589
|
+
mkdirSync2(dirname2(filePath), { recursive: true });
|
|
351
590
|
writeFileSync(filePath, ensureNl(content), "utf8");
|
|
352
591
|
}
|
|
353
592
|
function readOmpMcpJson(filePath = ompMcpJsonPath()) {
|
|
354
593
|
const data = readJson(filePath);
|
|
355
|
-
if (!data || !
|
|
594
|
+
if (!data || !isPlainObject2(data.mcpServers)) return null;
|
|
356
595
|
return data;
|
|
357
596
|
}
|
|
358
597
|
function writeOmpMcpEntry(name, server, filePath = ompMcpJsonPath()) {
|
|
359
598
|
const existing = readJson(filePath);
|
|
360
|
-
const data =
|
|
361
|
-
const mcpServers =
|
|
599
|
+
const data = isPlainObject2(existing) ? { ...existing } : {};
|
|
600
|
+
const mcpServers = isPlainObject2(
|
|
362
601
|
data.mcpServers
|
|
363
602
|
) ? { ...data.mcpServers } : {};
|
|
364
603
|
mcpServers[name] = server;
|
|
@@ -367,7 +606,7 @@ function writeOmpMcpEntry(name, server, filePath = ompMcpJsonPath()) {
|
|
|
367
606
|
}
|
|
368
607
|
function removeOmpMcpEntry(name, filePath = ompMcpJsonPath()) {
|
|
369
608
|
const existing = readJson(filePath);
|
|
370
|
-
if (!existing || !
|
|
609
|
+
if (!existing || !isPlainObject2(existing.mcpServers)) return;
|
|
371
610
|
const mcpServers = {
|
|
372
611
|
...existing.mcpServers
|
|
373
612
|
};
|
|
@@ -400,13 +639,13 @@ ${normalizeAgentBody(body)}`;
|
|
|
400
639
|
}
|
|
401
640
|
function findOmpAgentSourceDir(repoRoot = process.cwd()) {
|
|
402
641
|
const repoAgents = repoPluginCandidate(repoRoot, "plugin", "agents");
|
|
403
|
-
if (
|
|
642
|
+
if (existsSync2(repoAgents)) return repoAgents;
|
|
404
643
|
const cached = latestCachedPluginDir();
|
|
405
644
|
if (!cached) return null;
|
|
406
|
-
const cachedAgents =
|
|
407
|
-
if (
|
|
408
|
-
const nested =
|
|
409
|
-
return
|
|
645
|
+
const cachedAgents = join2(cached, "agents");
|
|
646
|
+
if (existsSync2(cachedAgents)) return cachedAgents;
|
|
647
|
+
const nested = join2(cached, "plugin", "agents");
|
|
648
|
+
return existsSync2(nested) ? nested : null;
|
|
410
649
|
}
|
|
411
650
|
function deployOmpAgents(scope, options) {
|
|
412
651
|
const sourceDir = findOmpAgentSourceDir();
|
|
@@ -417,12 +656,12 @@ function deployOmpAgents(scope, options) {
|
|
|
417
656
|
const dryRun = options?.dryRun === true;
|
|
418
657
|
const targetDir = agentsDirForScope(scope);
|
|
419
658
|
let printedFirst = false;
|
|
420
|
-
if (!dryRun)
|
|
659
|
+
if (!dryRun) mkdirSync2(targetDir, { recursive: true });
|
|
421
660
|
for (const filename of files) {
|
|
422
661
|
let converted;
|
|
423
662
|
try {
|
|
424
663
|
converted = convertClaudeAgentToOmp(
|
|
425
|
-
readFileSync(
|
|
664
|
+
readFileSync(join2(sourceDir, filename), "utf8")
|
|
426
665
|
);
|
|
427
666
|
} catch {
|
|
428
667
|
skipped.push(filename);
|
|
@@ -436,43 +675,43 @@ function deployOmpAgents(scope, options) {
|
|
|
436
675
|
skipped.push(filename);
|
|
437
676
|
continue;
|
|
438
677
|
}
|
|
439
|
-
writeFileSync(
|
|
678
|
+
writeFileSync(join2(targetDir, filename), converted, "utf8");
|
|
440
679
|
deployed.push(filename);
|
|
441
680
|
}
|
|
442
681
|
return { deployed, skipped };
|
|
443
682
|
}
|
|
444
683
|
function removeOmpAgents(scope) {
|
|
445
684
|
const targetDir = agentsDirForScope(scope);
|
|
446
|
-
if (!
|
|
447
|
-
for (const entry of
|
|
685
|
+
if (!existsSync2(targetDir)) return;
|
|
686
|
+
for (const entry of readdirSync2(targetDir, { withFileTypes: true })) {
|
|
448
687
|
if (!(entry.isFile() || entry.isSymbolicLink()) || !isCfAgentFile(entry.name)) {
|
|
449
688
|
continue;
|
|
450
689
|
}
|
|
451
|
-
|
|
690
|
+
rmSync2(join2(targetDir, entry.name));
|
|
452
691
|
}
|
|
453
692
|
}
|
|
454
693
|
function writeOmpExtensionEntry(scope, repoRoot = process.cwd()) {
|
|
455
694
|
const extensionPath = getOmpExtensionPath(repoRoot);
|
|
456
|
-
if (!extensionPath || !
|
|
695
|
+
if (!extensionPath || !existsSync2(extensionPath)) {
|
|
457
696
|
throw new Error(
|
|
458
697
|
extensionPath ? `omp extension not found: ${extensionPath}. Run from the coding-friend repo or install the plugin first.` : "omp extension not found. Run from the coding-friend repo or install the plugin first."
|
|
459
698
|
);
|
|
460
699
|
}
|
|
461
|
-
const pluginRoot =
|
|
700
|
+
const pluginRoot = dirname2(dirname2(extensionPath));
|
|
462
701
|
const shim = [
|
|
463
702
|
`// CODING_FRIEND_PLUGIN_ROOT=${pluginRoot}`,
|
|
464
703
|
`export { default } from ${JSON.stringify(extensionPath)};`,
|
|
465
704
|
""
|
|
466
705
|
].join("\n");
|
|
467
|
-
writeTextFile(
|
|
706
|
+
writeTextFile(join2(extensionsDirForScope(scope), EXTENSION_SHIM), shim);
|
|
468
707
|
}
|
|
469
708
|
function removeOmpExtensionEntry(scope) {
|
|
470
|
-
const filePath =
|
|
471
|
-
if (
|
|
709
|
+
const filePath = join2(extensionsDirForScope(scope), EXTENSION_SHIM);
|
|
710
|
+
if (existsSync2(filePath)) rmSync2(filePath);
|
|
472
711
|
}
|
|
473
712
|
function setOmpAgentEnabled(scope) {
|
|
474
713
|
const filePath = configYmlForScope(scope);
|
|
475
|
-
if (!
|
|
714
|
+
if (!existsSync2(filePath)) return false;
|
|
476
715
|
const current = readFileSync(filePath, "utf8");
|
|
477
716
|
const next = removeOurDisabledAgents(current, ourAgentNames(scope));
|
|
478
717
|
if (next === current) return false;
|
|
@@ -481,14 +720,14 @@ function setOmpAgentEnabled(scope) {
|
|
|
481
720
|
}
|
|
482
721
|
function setOmpAgentDisabled(scope) {
|
|
483
722
|
const filePath = configYmlForScope(scope);
|
|
484
|
-
const current =
|
|
723
|
+
const current = existsSync2(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
485
724
|
writeTextFile(filePath, upsertDisabledAgents(current, ourAgentNames(scope)));
|
|
486
725
|
}
|
|
487
726
|
function isOmpAgentInstalled(scope) {
|
|
488
727
|
const dir = agentsDirForScope(scope);
|
|
489
|
-
if (!
|
|
728
|
+
if (!existsSync2(dir)) return false;
|
|
490
729
|
try {
|
|
491
|
-
return
|
|
730
|
+
return readdirSync2(dir, { withFileTypes: true }).some(
|
|
492
731
|
(entry) => (entry.isFile() || entry.isSymbolicLink()) && isCfAgentFile(entry.name)
|
|
493
732
|
);
|
|
494
733
|
} catch {
|
|
@@ -497,6 +736,18 @@ function isOmpAgentInstalled(scope) {
|
|
|
497
736
|
}
|
|
498
737
|
|
|
499
738
|
export {
|
|
739
|
+
resolveAgyPluginSource,
|
|
740
|
+
deployAgyPlugin,
|
|
741
|
+
removeAgyPlugin,
|
|
742
|
+
isAgyPluginInstalled,
|
|
743
|
+
readAgyPluginVersion,
|
|
744
|
+
setAgyPluginEnabled,
|
|
745
|
+
isAgyPluginEnabled,
|
|
746
|
+
removeAgyPluginConfigEntry,
|
|
747
|
+
readAgyMcpConfig,
|
|
748
|
+
writeAgyMcpEntry,
|
|
749
|
+
removeAgyMcpEntry,
|
|
750
|
+
validateAgyPlugin,
|
|
500
751
|
readOmpMcpJson,
|
|
501
752
|
writeOmpMcpEntry,
|
|
502
753
|
removeOmpMcpEntry,
|
|
@@ -3,8 +3,11 @@ import {
|
|
|
3
3
|
writeJson
|
|
4
4
|
} from "./chunk-5UVDWG5L.js";
|
|
5
5
|
import {
|
|
6
|
+
claudeLocalSettingsPath,
|
|
7
|
+
claudeProjectSettingsPath,
|
|
8
|
+
claudeSettingsPath,
|
|
6
9
|
pluginCachePath
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IYBIIRH4.js";
|
|
8
11
|
|
|
9
12
|
// src/lib/permissions.ts
|
|
10
13
|
var STATIC_RULES = [
|
|
@@ -451,6 +454,23 @@ async function runDangerousRulesAudit(settingsPaths, log, promptConfirm) {
|
|
|
451
454
|
}
|
|
452
455
|
}
|
|
453
456
|
}
|
|
457
|
+
var AUTO_APPROVE_CROSS_HOST_NOTE = "autoApprove enables Claude Code (LLM classifier), Antigravity, and Codex (deterministic rules).";
|
|
458
|
+
async function afterAutoApproveEnabled(log, promptConfirm) {
|
|
459
|
+
await runDangerousRulesAudit(
|
|
460
|
+
[
|
|
461
|
+
claudeProjectSettingsPath(),
|
|
462
|
+
claudeLocalSettingsPath(),
|
|
463
|
+
claudeSettingsPath()
|
|
464
|
+
],
|
|
465
|
+
log,
|
|
466
|
+
promptConfirm
|
|
467
|
+
);
|
|
468
|
+
log.dim(`Note: ${AUTO_APPROVE_CROSS_HOST_NOTE}`);
|
|
469
|
+
log.dim(
|
|
470
|
+
"Tip: Fine-tune with autoApproveAllowExtra / autoApproveIgnore in config.json"
|
|
471
|
+
);
|
|
472
|
+
log.dim("Docs: https://cf.dinhanhthi.com/docs/reference/auto-approve/");
|
|
473
|
+
}
|
|
454
474
|
function logPluginScriptWarning(log, chalk) {
|
|
455
475
|
log.warn(
|
|
456
476
|
`Plugin script rules use ${chalk.bold("wide patterns")} that allow executing any script in the Coding Friend plugin cache.`
|
|
@@ -462,12 +482,7 @@ function logPluginScriptWarning(log, chalk) {
|
|
|
462
482
|
|
|
463
483
|
export {
|
|
464
484
|
STATIC_RULES,
|
|
465
|
-
buildPluginScriptRules,
|
|
466
485
|
getAllRules,
|
|
467
|
-
PERMISSION_RULES,
|
|
468
|
-
DANGEROUS_RULE_PATTERNS,
|
|
469
|
-
auditDangerousRules,
|
|
470
|
-
stripDangerousRules,
|
|
471
486
|
getExistingRules,
|
|
472
487
|
getMissingRules,
|
|
473
488
|
buildLearnDirRules,
|
|
@@ -475,6 +490,7 @@ export {
|
|
|
475
490
|
groupByCategory,
|
|
476
491
|
extractTag,
|
|
477
492
|
cleanupStalePluginRules,
|
|
478
|
-
|
|
493
|
+
AUTO_APPROVE_CROSS_HOST_NOTE,
|
|
494
|
+
afterAutoApproveEnabled,
|
|
479
495
|
logPluginScriptWarning
|
|
480
496
|
};
|