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.
Files changed (40) hide show
  1. package/README.md +5 -0
  2. package/dist/{chunk-ODW27NAC.js → chunk-B44ROTV6.js} +10 -10
  3. package/dist/{chunk-ZGIUKUL2.js → chunk-CZW36H3D.js} +39 -7
  4. package/dist/{chunk-FQUIO5BW.js → chunk-E4NBTQXR.js} +13 -7
  5. package/dist/{chunk-IV5OPG34.js → chunk-IYBIIRH4.js} +29 -1
  6. package/dist/{chunk-GTOEIGDM.js → chunk-KCBMCHSA.js} +295 -44
  7. package/dist/{chunk-463QKRBN.js → chunk-KG6HYBGD.js} +23 -7
  8. package/dist/{chunk-WJHQUCOF.js → chunk-KTUPGMIV.js} +111 -15
  9. package/dist/{chunk-7JQZRMOG.js → chunk-NIMO4VJW.js} +37 -6
  10. package/dist/{chunk-OFEC6OVI.js → chunk-OBCNHQFA.js} +42 -2
  11. package/dist/{chunk-4CPUWHIN.js → chunk-Q2QDSYQT.js} +1 -1
  12. package/dist/{chunk-JSH6BMVZ.js → chunk-RG3EMZH6.js} +11 -1
  13. package/dist/{chunk-2EY7VVFT.js → chunk-SUYE5S2W.js} +1 -1
  14. package/dist/{chunk-YPW67OGP.js → chunk-TFF47F7P.js} +1 -1
  15. package/dist/{chunk-ZZNTNIM4.js → chunk-TN3Y75WG.js} +2 -2
  16. package/dist/{chunk-VMODQCSL.js → chunk-Z5XTSF7L.js} +5 -5
  17. package/dist/{clean-LPWEBJJ5.js → clean-PKSSS662.js} +3 -3
  18. package/dist/{config-VNSC2NAY.js → config-2CH4GI2L.js} +47 -26
  19. package/dist/{dev-NRTDUQAR.js → dev-HWKNWOZY.js} +7 -7
  20. package/dist/{disable-NROSQUHR.js → disable-DCGVIHKG.js} +22 -8
  21. package/dist/{enable-26FFJGX5.js → enable-YYWJDOYB.js} +21 -8
  22. package/dist/{guide-HCLEOAGR.js → guide-45EIK76P.js} +1 -1
  23. package/dist/{host-2JOPHLN3.js → host-GZJSMJSF.js} +7 -7
  24. package/dist/index.js +67 -46
  25. package/dist/{init-MHHII5EP.js → init-TUBWQCBQ.js} +236 -53
  26. package/dist/{install-OEFJLAWA.js → install-45O5ICBA.js} +68 -11
  27. package/dist/{learn-SSNBBDY3.js → learn-AJT7Z6F7.js} +5 -5
  28. package/dist/{mcp-J5VO3OH7.js → mcp-JGBZMNWL.js} +26 -13
  29. package/dist/{mcp-serve-55DSE2J4.js → mcp-serve-SHS5MQRW.js} +5 -5
  30. package/dist/{mcp-serve-learn-EDBWNL4I.js → mcp-serve-learn-HXZZ3DUI.js} +6 -6
  31. package/dist/{memory-CDZKWOFL.js → memory-4NVLWOFS.js} +10 -10
  32. package/dist/{permission-DPKPA2HU.js → permission-L5QMNMID.js} +25 -25
  33. package/dist/{session-YWJDLNBP.js → session-GBHL5TH3.js} +3 -3
  34. package/dist/{status-4WMIQL7L.js → status-KQQJNSEZ.js} +33 -15
  35. package/dist/{statusline-R5BNYK3H.js → statusline-B7PXP3AQ.js} +3 -3
  36. package/dist/{uninstall-EV7362NK.js → uninstall-6QKNGLKK.js} +38 -13
  37. package/dist/{update-YQBBAIIF.js → update-YJ363TBU.js} +11 -11
  38. package/dist/{update-check-EJSGVGO6.js → update-check-5JZUJGUM.js} +1 -1
  39. package/package.json +1 -1
  40. package/dist/permissions-HZYUVKCY.js +0 -38
@@ -1,14 +1,27 @@
1
1
  import {
2
2
  getOmpExtensionPath
3
- } from "./chunk-ZZNTNIM4.js";
3
+ } from "./chunk-TN3Y75WG.js";
4
4
  import {
5
5
  compareVersions
6
- } from "./chunk-OFEC6OVI.js";
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-IV5OPG34.js";
33
+ } from "./chunk-IYBIIRH4.js";
21
34
 
22
- // src/lib/omp-config.ts
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
- writeFileSync
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 isPlainObject(value) {
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 (!existsSync(dir)) return [];
347
+ if (!existsSync2(dir)) return [];
109
348
  try {
110
- return readdirSync(dir, { withFileTypes: true }).filter(
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 = resolve(repoRoot, ...parts);
132
- const parent = resolve(repoRoot, "..", ...parts);
133
- if (existsSync(direct)) return direct;
134
- if (existsSync(parent)) return parent;
135
- if (existsSync(resolve(repoRoot, "..", "plugin", "agents"))) return parent;
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 (!existsSync(cacheRoot)) return null;
140
- if (existsSync(join(cacheRoot, "agents"))) return cacheRoot;
378
+ if (!existsSync2(cacheRoot)) return null;
379
+ if (existsSync2(join2(cacheRoot, "agents"))) return cacheRoot;
141
380
  let dirs = [];
142
381
  try {
143
- dirs = readdirSync(cacheRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
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 join(cacheRoot, versions[0]);
387
+ if (versions[0]) return join2(cacheRoot, versions[0]);
149
388
  const rest = [...dirs].sort(compareVersions).reverse();
150
- return rest[0] ? join(cacheRoot, rest[0]) : null;
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
- mkdirSync(dirname(filePath), { recursive: true });
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 || !isPlainObject(data.mcpServers)) return null;
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 = isPlainObject(existing) ? { ...existing } : {};
361
- const mcpServers = isPlainObject(
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 || !isPlainObject(existing.mcpServers)) return;
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 (existsSync(repoAgents)) return repoAgents;
642
+ if (existsSync2(repoAgents)) return repoAgents;
404
643
  const cached = latestCachedPluginDir();
405
644
  if (!cached) return null;
406
- const cachedAgents = join(cached, "agents");
407
- if (existsSync(cachedAgents)) return cachedAgents;
408
- const nested = join(cached, "plugin", "agents");
409
- return existsSync(nested) ? nested : null;
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) mkdirSync(targetDir, { recursive: true });
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(join(sourceDir, filename), "utf8")
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(join(targetDir, filename), converted, "utf8");
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 (!existsSync(targetDir)) return;
447
- for (const entry of readdirSync(targetDir, { withFileTypes: true })) {
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
- rmSync(join(targetDir, entry.name));
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 || !existsSync(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 = dirname(dirname(extensionPath));
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(join(extensionsDirForScope(scope), EXTENSION_SHIM), shim);
706
+ writeTextFile(join2(extensionsDirForScope(scope), EXTENSION_SHIM), shim);
468
707
  }
469
708
  function removeOmpExtensionEntry(scope) {
470
- const filePath = join(extensionsDirForScope(scope), EXTENSION_SHIM);
471
- if (existsSync(filePath)) rmSync(filePath);
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 (!existsSync(filePath)) return false;
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 = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
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 (!existsSync(dir)) return false;
728
+ if (!existsSync2(dir)) return false;
490
729
  try {
491
- return readdirSync(dir, { withFileTypes: true }).some(
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-IV5OPG34.js";
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
- runDangerousRulesAudit,
493
+ AUTO_APPROVE_CROSS_HOST_NOTE,
494
+ afterAutoApproveEnabled,
479
495
  logPluginScriptWarning
480
496
  };