agent-bridge-aun 1.0.34 → 1.0.35
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 +2 -0
- package/dist/src-ts/plugins/aun/evolcore.js +93 -17
- package/dist/src-ts/plugins/aun/index.js +11 -2
- package/package.json +1 -1
- package/plugin.json +1 -1
package/README.md
CHANGED
|
@@ -15,3 +15,5 @@
|
|
|
15
15
|
ABWeb 的 AUN 设置只展示已连接 AID,并按来源分组。成功注册并记录在插件 `created_aids` 中的 AID 属于本工程;共享密钥库中其余 AID 属于 EvolCore。旧版 `created-aids.json` 记录继续兼容。来源只用于展示,连接和关联由 AUN 插件直接管理。列表先显示已关联 Agent 的身份,各组按最近成功关联的时间倒序排列,时间相同或旧记录没有时间时按 AID 名称排序。关联时间保存在插件配置的 `binding_times` 中,刷新或重启后保留;旧记录不补造时间,再次关联成功后开始记录。
|
|
16
16
|
|
|
17
17
|
AUN 独立包支持核心后台每五分钟检测更新;可信提供者在自动安装策略下会下载新副本并重载通道。
|
|
18
|
+
|
|
19
|
+
显式关联已有 EvolCore Agent 的 AID 时,先执行 `ec agent disable <aid>`,再配置 `ecagent` 路由并重载。`ec` 不存在或命令失败时,只将所选 AID 的 JSON 配置更新为 `enabled=false`、`active_baseagent=ecagent` 和对应路由;其它 AID 保持原值。仍有 EvolCore 运行实例时,必须确认重载成功才完成关联,避免原 Claude 与桌面 Agent 同时回复。纯密钥库身份不调用 `ec`,解绑不自动启用原 Agent。
|
|
@@ -4,10 +4,14 @@ exports.runEc = runEc;
|
|
|
4
4
|
exports.configureAidForPlugin = configureAidForPlugin;
|
|
5
5
|
const node_child_process_1 = require("node:child_process");
|
|
6
6
|
const node_util_1 = require("node:util");
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const node_os_1 = require("node:os");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
7
11
|
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
8
|
-
async function runEc(args) {
|
|
12
|
+
async function runEc(args, home) {
|
|
9
13
|
try {
|
|
10
|
-
const { stdout } = await execFileAsync("ec", args, { shell: process.platform === "win32", timeout:
|
|
14
|
+
const { stdout } = await execFileAsync("ec", args, { shell: process.platform === "win32", timeout: 60_000, env: { ...process.env, ...(home ? { EVOLCORE_HOME: home } : {}) }, windowsHide: true, maxBuffer: 1024 * 1024 });
|
|
11
15
|
return JSON.parse(stdout);
|
|
12
16
|
}
|
|
13
17
|
catch (error) {
|
|
@@ -21,24 +25,96 @@ async function runEc(args) {
|
|
|
21
25
|
throw error;
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
|
-
async function
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
async function ecIsRunning(home) {
|
|
29
|
+
const records = [];
|
|
30
|
+
try {
|
|
31
|
+
records.push(Number(await (0, promises_1.readFile)((0, node_path_1.join)(home, "daemon.pid"), "utf8")));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error.code !== "ENOENT")
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
const directory = (0, node_path_1.join)(home, "data", "instance");
|
|
38
|
+
let names;
|
|
39
|
+
try {
|
|
40
|
+
names = await (0, promises_1.readdir)(directory);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.code !== "ENOENT")
|
|
44
|
+
throw error;
|
|
45
|
+
names = [];
|
|
46
|
+
}
|
|
47
|
+
for (const name of names.filter(name => /^main-\d+\.json$/.test(name))) {
|
|
48
|
+
records.push(JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(directory, name), "utf8")).pid);
|
|
49
|
+
}
|
|
50
|
+
return records.some(pid => {
|
|
51
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
52
|
+
return false;
|
|
53
|
+
try {
|
|
54
|
+
process.kill(pid, 0);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error.code === "ESRCH")
|
|
59
|
+
return false;
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async function configureAidForPlugin(pluginId, aid, port, run = runEc, home = process.env.EVOLCORE_HOME ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".evolcore")) {
|
|
65
|
+
if (!/^[a-z0-9][a-z0-9_.-]+$/i.test(aid) || !aid.includes("."))
|
|
66
|
+
throw new Error("AID 格式无效");
|
|
27
67
|
if (!/^[a-z0-9_-]+$/.test(pluginId))
|
|
28
68
|
throw new Error("插件 ID 格式无效");
|
|
29
|
-
|
|
69
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
70
|
+
throw new Error("后台端口无效");
|
|
30
71
|
const path = pluginId === "dsh" ? "/dsh/v1" : `/api/agents/${pluginId}/v1`;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
["
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
72
|
+
const ecagent = { baseUrl: `http://127.0.0.1:${port}${path}`, apiKey: "mab-local", model: pluginId };
|
|
73
|
+
try {
|
|
74
|
+
// MAB 直接接收 AUN 消息,先停用该 AID 的 EvolCore Agent,避免双重回复。
|
|
75
|
+
const disabled = await run(["agent", "disable", aid, "--format", "json"], home);
|
|
76
|
+
if (!disabled?.ok)
|
|
77
|
+
throw new Error(`停用原 Agent 失败:${disabled?.code ?? ""} ${disabled?.error ?? "未知错误"}`);
|
|
78
|
+
for (const [key, value] of [
|
|
79
|
+
...Object.entries(ecagent).map(([key, value]) => [`baseagents.ecagent.${key}`, value]),
|
|
80
|
+
["active_baseagent", "ecagent"],
|
|
81
|
+
]) {
|
|
82
|
+
const result = await run(["agent", "set", aid, key, value, "--format", "json"], home);
|
|
83
|
+
if (!result?.ok)
|
|
84
|
+
throw new Error(`配置 ${key} 失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
85
|
+
}
|
|
86
|
+
const result = await run(["agent", "reload", aid, "--format", "json"], home);
|
|
38
87
|
if (!result?.ok)
|
|
39
|
-
throw new Error(
|
|
88
|
+
throw new Error(`重载失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
89
|
+
return "ec";
|
|
90
|
+
}
|
|
91
|
+
catch (commandError) {
|
|
92
|
+
const file = (0, node_path_1.join)(home, "agents", aid, "config.json");
|
|
93
|
+
const config = JSON.parse(await (0, promises_1.readFile)(file, "utf8"));
|
|
94
|
+
if (!config || typeof config !== "object" || Array.isArray(config) || config.baseagents && (typeof config.baseagents !== "object" || Array.isArray(config.baseagents)))
|
|
95
|
+
throw new Error(`AID ${aid} 原配置格式无效,未覆盖文件`);
|
|
96
|
+
config.enabled = false;
|
|
97
|
+
config.active_baseagent = "ecagent";
|
|
98
|
+
config.baseagents = { ...config.baseagents, ecagent: { ...config.baseagents?.ecagent, ...ecagent } };
|
|
99
|
+
const temporary = `${file}.mab-${(0, node_crypto_1.randomUUID)()}.tmp`;
|
|
100
|
+
try {
|
|
101
|
+
await (0, promises_1.writeFile)(temporary, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
102
|
+
await (0, promises_1.rename)(temporary, file);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await (0, promises_1.rm)(temporary, { force: true });
|
|
106
|
+
}
|
|
107
|
+
// 写盘不能关闭运行中的旧 Agent;存在活跃实例时必须确认重载成功。
|
|
108
|
+
if (await ecIsRunning(home)) {
|
|
109
|
+
try {
|
|
110
|
+
const result = await run(["agent", "reload", aid, "--format", "json"], home);
|
|
111
|
+
if (!result?.ok)
|
|
112
|
+
throw new Error(result?.error ?? "重载失败");
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new AggregateError([commandError, error], `AID ${aid} 配置已保存,但 EvolCore 仍在运行,原 Agent 未确认停用:${error instanceof Error ? error.message : error}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return "json";
|
|
40
119
|
}
|
|
41
|
-
const result = await run(["agent", "reload", aid, "--format", "json"]);
|
|
42
|
-
if (!result?.ok)
|
|
43
|
-
throw new Error(`重载 AID ${aid} 失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
44
120
|
}
|
|
@@ -9,10 +9,11 @@ const node_path_1 = require("node:path");
|
|
|
9
9
|
const node_os_1 = require("node:os");
|
|
10
10
|
const node_url_1 = require("node:url");
|
|
11
11
|
const agent_1 = require("../../agent");
|
|
12
|
+
const evolcore_1 = require("./evolcore");
|
|
12
13
|
const messages_1 = require("./messages");
|
|
13
14
|
const attachments_1 = require("./attachments");
|
|
14
15
|
const manifest = {
|
|
15
|
-
id: "aun", version: "1.0.
|
|
16
|
+
id: "aun", version: "1.0.35", type: "channel", displayName: "AUN 通道",
|
|
16
17
|
entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
|
|
17
18
|
capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health", "cli"],
|
|
18
19
|
configSchema: "config.schema.json",
|
|
@@ -124,7 +125,7 @@ class AunPlugin {
|
|
|
124
125
|
this.creating = false;
|
|
125
126
|
}
|
|
126
127
|
},
|
|
127
|
-
bind: async (pluginId, aid,
|
|
128
|
+
bind: async (pluginId, aid, port) => {
|
|
128
129
|
if (!aid || !aidPattern.test(aid))
|
|
129
130
|
throw new Error("AID 格式无效,必须指定要关联的 AID");
|
|
130
131
|
if (pluginId === "aun" || pluginId === "abweb")
|
|
@@ -140,6 +141,14 @@ class AunPlugin {
|
|
|
140
141
|
const loaded = this.store.load(aid);
|
|
141
142
|
if (!loaded.ok || !loaded.data)
|
|
142
143
|
throw new Error("AID 不在本地密钥库中,无法关联");
|
|
144
|
+
// 仅接管用户本次选中的 EvolCore Agent;纯密钥库身份不调用 ec。
|
|
145
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(this.path(), "agents", aid, "config.json"))) {
|
|
146
|
+
const method = await (0, evolcore_1.configureAidForPlugin)(pluginId, aid, port, this.options.runEc ?? evolcore_1.runEc, this.path());
|
|
147
|
+
if (method === "json")
|
|
148
|
+
this.context?.logger.warn("ec 命令不可用或失败,已通过 JSON 停用原 Agent 并配置 ecagent", { aid, pluginId });
|
|
149
|
+
else
|
|
150
|
+
this.context?.logger.info("已通过 ec 命令停用原 Agent 并切换为 ecagent", { aid, pluginId });
|
|
151
|
+
}
|
|
143
152
|
this.identities.add(aid);
|
|
144
153
|
if (!connection)
|
|
145
154
|
await this.connectAid(aid);
|
package/package.json
CHANGED