mu-agent-bridge 1.0.27 → 1.0.29
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/dist/src-ts/plugin-manager.js +12 -6
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +20 -1
- package/dist/src-ts/plugins/abweb/public/index.html +3 -0
- package/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/dist/src-ts/plugins/aun/index.js +5 -5
- package/dist/src-ts/plugins/aun/public/app.js +17 -4
- package/dist/tests-ts/abweb-login.test.js +1 -0
- package/dist/tests-ts/aun-plugin.test.js +6 -1
- package/dist/tests-ts/bundled-package.test.js +3 -1
- package/dist/tests-ts/channel-feedback.test.js +99 -0
- package/dist/tests-ts/plugin-manager.test.js +38 -0
- package/package.json +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +20 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +16 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +3 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/plugins/abweb/package.json +32 -0
- package/plugins/abweb/plugin.json +1 -1
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +5 -5
- package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +17 -4
- package/plugins/aun/package.json +35 -0
- package/plugins/aun/plugin.json +1 -1
- package/plugins/chatgpt/package.json +1 -0
- package/plugins/doubao/package.json +32 -0
- package/plugins/dsh/package.json +32 -0
- package/plugins/feishu/package.json +31 -0
- package/plugins/qwenwork/package.json +32 -0
- package/plugins/workbuddy/package.json +32 -0
|
@@ -115,8 +115,8 @@ class PluginManager {
|
|
|
115
115
|
async discover() {
|
|
116
116
|
await this.loadPluginTrust();
|
|
117
117
|
await (0, promises_1.mkdir)(this.root, { recursive: true });
|
|
118
|
-
await this.discoverNpmPackages();
|
|
119
118
|
await this.discoverManagedPackages();
|
|
119
|
+
await this.discoverNpmPackages();
|
|
120
120
|
for (const id of await (0, promises_1.readdir)(this.root, { withFileTypes: true })) {
|
|
121
121
|
if (!id.isDirectory())
|
|
122
122
|
continue;
|
|
@@ -145,7 +145,7 @@ class PluginManager {
|
|
|
145
145
|
const root = (0, node_path_1.resolve)(this.options.stateDir, "npm");
|
|
146
146
|
const path = (0, node_path_1.resolve)(record.path);
|
|
147
147
|
const managed = path.startsWith(`${root}${node_path_1.sep}`);
|
|
148
|
-
const packageName =
|
|
148
|
+
const packageName = record.packageName;
|
|
149
149
|
return { packageName: packageName && /^agent-bridge-[a-z0-9-]+$/.test(packageName) ? packageName : undefined, managed, version: record.version };
|
|
150
150
|
}
|
|
151
151
|
async checkPackageUpdates() {
|
|
@@ -165,12 +165,13 @@ class PluginManager {
|
|
|
165
165
|
const loaded = this.plugins.get(id);
|
|
166
166
|
if (!loaded)
|
|
167
167
|
throw new agent_1.AgentError(`unknown plugin: ${id}`);
|
|
168
|
-
if (
|
|
169
|
-
throw new agent_1.AgentError("
|
|
168
|
+
if (loaded.record.packageName !== packageName)
|
|
169
|
+
throw new agent_1.AgentError("插件未声明对应的 npm 包,不能通过 npm 升级");
|
|
170
170
|
const prefix = (0, node_path_1.join)(this.options.stateDir, "npm", packageName);
|
|
171
171
|
const cached = await this.cachedPackage(packageName, version);
|
|
172
172
|
const staging = cached ?? (0, node_path_1.join)(this.options.stateDir, "npm", `.staging-${packageName}-${Date.now()}`);
|
|
173
173
|
const backup = `${prefix}.backup-${Date.now()}`;
|
|
174
|
+
const hadPrefix = await this.existsDir(prefix);
|
|
174
175
|
let stopped = false;
|
|
175
176
|
this.log("info", `开始升级插件:${id}`, { packageName, version }, "插件升级");
|
|
176
177
|
await (0, promises_1.mkdir)(staging, { recursive: true });
|
|
@@ -192,7 +193,8 @@ class PluginManager {
|
|
|
192
193
|
this.validateCandidate(manifest, meta.agentBridge);
|
|
193
194
|
await this.stop(id, "reload");
|
|
194
195
|
stopped = true;
|
|
195
|
-
|
|
196
|
+
if (hadPrefix)
|
|
197
|
+
await (0, promises_1.rename)(prefix, backup);
|
|
196
198
|
await (0, promises_1.rename)(staging, prefix);
|
|
197
199
|
this.plugins.delete(id);
|
|
198
200
|
await this.discoverManagedPackages();
|
|
@@ -209,10 +211,14 @@ class PluginManager {
|
|
|
209
211
|
await (0, promises_1.rm)(prefix, { recursive: true, force: true });
|
|
210
212
|
await (0, promises_1.rename)(backup, prefix);
|
|
211
213
|
}
|
|
214
|
+
else if (stopped && !hadPrefix)
|
|
215
|
+
await (0, promises_1.rm)(prefix, { recursive: true, force: true });
|
|
212
216
|
if (stopped) {
|
|
213
217
|
this.plugins.delete(id);
|
|
218
|
+
loaded.instance = undefined;
|
|
219
|
+
loaded.record.status = "discovered";
|
|
220
|
+
this.plugins.set(id, loaded);
|
|
214
221
|
try {
|
|
215
|
-
await this.discoverManagedPackages();
|
|
216
222
|
await this.start(id);
|
|
217
223
|
}
|
|
218
224
|
catch { /* 回滚后仍无法启动时保留原错误 */ }
|
|
@@ -35,6 +35,25 @@
|
|
|
35
35
|
let loading = false;
|
|
36
36
|
const installingPackages = new Set();
|
|
37
37
|
function error(message) { errorNode.textContent = message; errorNode.hidden = !message; }
|
|
38
|
+
function showResult(title, message, failed) {
|
|
39
|
+
node("#operation-result-title").textContent = title;
|
|
40
|
+
const detail = node("#operation-result-message");
|
|
41
|
+
detail.textContent = message;
|
|
42
|
+
detail.className = failed ? "error" : "";
|
|
43
|
+
const dialog = node("#operation-result");
|
|
44
|
+
if (!dialog.open)
|
|
45
|
+
dialog.showModal();
|
|
46
|
+
}
|
|
47
|
+
node("#operation-result-close").onclick = () => node("#operation-result").close();
|
|
48
|
+
window.addEventListener("message", (event) => {
|
|
49
|
+
const frame = channelPanel.querySelector("iframe.channel-frame");
|
|
50
|
+
if (event.origin !== window.location.origin || !frame || event.source !== frame.contentWindow)
|
|
51
|
+
return;
|
|
52
|
+
const result = event.data;
|
|
53
|
+
if (!result || result.type !== "mab:operation-result" || typeof result.title !== "string" || typeof result.message !== "string" || typeof result.failed !== "boolean")
|
|
54
|
+
return;
|
|
55
|
+
showResult(result.title, result.message, result.failed);
|
|
56
|
+
});
|
|
38
57
|
async function loadCatalog() {
|
|
39
58
|
const result = await request(`/api/plugins/catalog?q=${encodeURIComponent(packageSearchNode.value.trim())}`);
|
|
40
59
|
const items = result.plugins ?? [];
|
|
@@ -113,7 +132,7 @@
|
|
|
113
132
|
item.type = "button";
|
|
114
133
|
item.textContent = label;
|
|
115
134
|
item.title = title;
|
|
116
|
-
item.onclick = () => { item.disabled = true; void run().catch((cause) =>
|
|
135
|
+
item.onclick = () => { item.disabled = true; void run().catch((cause) => { const message = cause instanceof Error ? cause.message : String(cause); error(message); showResult(`${title}失败`, message, true); }).finally(() => { item.disabled = false; void load(false); }); };
|
|
117
136
|
return item;
|
|
118
137
|
}
|
|
119
138
|
async function load(refreshCatalog = true) {
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
<div id="logs-panel" role="tabpanel" aria-labelledby="logs-tab" hidden><section><div class="section-heading"><h2>运行日志</h2><button id="logs-refresh" type="button">刷新日志</button></div><div class="table-scroll"><table><thead><tr><th>时间</th><th>级别</th><th>来源</th><th>消息</th><th>详细字段</th></tr></thead><tbody id="logs"></tbody></table></div><p id="logs-empty" class="muted" hidden>暂无运行日志</p><div class="section-heading"><button id="logs-prev" type="button">上一页</button><span id="logs-page" class="muted">第 1 页</span><button id="logs-next" type="button">下一页</button></div></section></div>
|
|
22
22
|
<p id="error" class="error" role="alert" hidden></p>
|
|
23
23
|
</main>
|
|
24
|
+
<dialog id="operation-result" aria-labelledby="operation-result-title" aria-describedby="operation-result-message">
|
|
25
|
+
<h2 id="operation-result-title">操作结果</h2><p id="operation-result-message"></p><button id="operation-result-close" type="button" autofocus>确定</button>
|
|
26
|
+
</dialog>
|
|
24
27
|
<script src="/abweb/app.js"></script>
|
|
25
28
|
</body>
|
|
26
29
|
</html>
|
|
@@ -56,3 +56,7 @@ th { color: #566761; font-weight: 600; background: #edf1ef; }
|
|
|
56
56
|
th:nth-child(1) { width: 145px; } th:nth-child(2) { width: 100px; } th:nth-child(3), th:nth-child(4) { width: 145px; } th:nth-child(5) { width: 62px; } th:nth-child(7) { width: 140px; }
|
|
57
57
|
.message-error td:last-child { color: #a83427; }
|
|
58
58
|
@media (max-width: 620px) { .shell { padding: 16px; } .section-heading { align-items: flex-start; flex-direction: column; } form, form input { width: 100%; } }
|
|
59
|
+
|
|
60
|
+
#operation-result { width: min(520px, calc(100% - 32px)); border: 1px solid #bfc9c5; border-radius: 8px; padding: 24px; }
|
|
61
|
+
#operation-result::backdrop { background: rgb(0 0 0 / 35%); }
|
|
62
|
+
#operation-result-message { white-space: pre-wrap; overflow-wrap: anywhere; margin: 16px 0; }
|
|
@@ -10,7 +10,7 @@ const node_url_1 = require("node:url");
|
|
|
10
10
|
const messages_1 = require("./messages");
|
|
11
11
|
const evolcore_1 = require("./evolcore");
|
|
12
12
|
const manifest = {
|
|
13
|
-
id: "aun", version: "1.0.
|
|
13
|
+
id: "aun", version: "1.0.17", type: "channel", displayName: "AUN 通道",
|
|
14
14
|
entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
|
|
15
15
|
capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health"],
|
|
16
16
|
configSchema: "config.schema.json",
|
|
@@ -87,9 +87,8 @@ class AunPlugin {
|
|
|
87
87
|
await this.persist();
|
|
88
88
|
this.context?.logger.info("AUN 身份已创建", { aid, owner });
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return { aid, status: "已创建", connection: this.clients.has(aid) ? "ready" : "degraded" };
|
|
90
|
+
const connectionError = !this.clients.has(aid) ? await this.connectAid(aid) : undefined;
|
|
91
|
+
return { aid, status: "已创建", connection: this.clients.has(aid) ? "ready" : "degraded", ...(connectionError ? { connectionError } : {}) };
|
|
93
92
|
}
|
|
94
93
|
finally {
|
|
95
94
|
this.creating = false;
|
|
@@ -244,7 +243,8 @@ class AunPlugin {
|
|
|
244
243
|
catch (error) {
|
|
245
244
|
this.status = "degraded";
|
|
246
245
|
this.healthMessage = safeError(error);
|
|
247
|
-
this.context?.logger.warn("AUN 通道连接失败", { error: this.healthMessage });
|
|
246
|
+
this.context?.logger.warn("AUN 通道连接失败", { aid, error: this.healthMessage });
|
|
247
|
+
return this.healthMessage;
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
async deactivate(_reason) {
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
return result;
|
|
16
16
|
}
|
|
17
17
|
function show(message, failed = false) { status.textContent = message; status.className = failed ? "error" : ""; }
|
|
18
|
+
function notify(title, message, failed = false) {
|
|
19
|
+
show(message, failed);
|
|
20
|
+
if (window.parent !== window) window.parent.postMessage({ type: "mab:operation-result", title, message, failed }, window.location.origin);
|
|
21
|
+
else window.alert(`${title}\n${message}`);
|
|
22
|
+
}
|
|
23
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
18
24
|
async function load(refreshForm = true) {
|
|
19
25
|
if (loading) return;
|
|
20
26
|
loading = true;
|
|
@@ -50,15 +56,22 @@
|
|
|
50
56
|
async function bind(aid, pluginId) {
|
|
51
57
|
try {
|
|
52
58
|
await request(`/api/plugins/${encodeURIComponent(pluginId)}/aid`, "PATCH", { aid });
|
|
53
|
-
await load();
|
|
54
|
-
} catch (error) {
|
|
59
|
+
await load(); notify("关联成功", `${aid} 已关联 ${pluginId}`);
|
|
60
|
+
} catch (error) { notify("关联失败", errorMessage(error), true); }
|
|
55
61
|
}
|
|
56
62
|
createForm.onsubmit = (event) => { event.preventDefault(); const aid = createForm.elements.aid.value.trim(); const owner = createForm.elements.ownerAid.value.trim();
|
|
57
|
-
|
|
63
|
+
show("正在创建 AID 并连接,请稍候……");
|
|
64
|
+
void request("/api/plugins/aun/aid", "POST", { aid, ownerAid: owner }).then((result) => {
|
|
65
|
+
const failed = result.connection === "degraded";
|
|
66
|
+
const message = failed ? `${aid} 已创建,但连接失败:${result.connectionError || "未提供连接失败原因,请查看运行日志"}\n身份已经保存在本地,请勿重复注册。`
|
|
67
|
+
: result.status === "等待 Owner 确认" ? `${aid} 等待 Owner 确认` : `${aid} 已创建并连接`;
|
|
68
|
+
notify(failed ? "AID 创建完成,连接失败" : "AID 创建结果", message, failed);
|
|
69
|
+
return load();
|
|
70
|
+
}).catch((error) => notify("创建 AID 失败", errorMessage(error), true));
|
|
58
71
|
};
|
|
59
72
|
configForm.onsubmit = (event) => { event.preventDefault(); const changes = { agent_plugin: configForm.elements.agent_plugin.value, allow_from: configForm.elements.allow_from.value, aun_path: configForm.elements.aun_path.value };
|
|
60
73
|
if (configForm.elements.encryption_seed.value) changes.encryption_seed = configForm.elements.encryption_seed.value;
|
|
61
|
-
void request("/api/plugins/aun/settings", "POST", changes).then(() => request("/api/plugins/aun/reload", "POST")).then(() => load()).then(() =>
|
|
74
|
+
void request("/api/plugins/aun/settings", "POST", changes).then(() => request("/api/plugins/aun/reload", "POST")).then(() => load()).then(() => notify("保存成功", "配置已保存")).catch((error) => notify("保存配置失败", errorMessage(error), true));
|
|
62
75
|
};
|
|
63
76
|
find("#refresh").onclick = () => void load();
|
|
64
77
|
void load();
|
|
@@ -34,6 +34,7 @@ class Element {
|
|
|
34
34
|
Date: class extends Date {
|
|
35
35
|
static now() { return now; }
|
|
36
36
|
},
|
|
37
|
+
window: { addEventListener() { } },
|
|
37
38
|
setInterval() { }, confirm: () => false,
|
|
38
39
|
fetch: async (path, options) => {
|
|
39
40
|
calls.push({ path, token: options.headers.authorization });
|
|
@@ -137,6 +137,7 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
137
137
|
const calls = [];
|
|
138
138
|
let registration = { ok: true, data: {} };
|
|
139
139
|
let loadOk = true;
|
|
140
|
+
let connectError = "";
|
|
140
141
|
let loadFailAid = "";
|
|
141
142
|
const clients = [];
|
|
142
143
|
const sdk = {
|
|
@@ -150,7 +151,8 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
150
151
|
AUNClient: class {
|
|
151
152
|
constructor() { const current = this; current.emit = (payload) => current.handler?.(payload); clients.push(current); }
|
|
152
153
|
on(_event, handler) { this.handler = handler; return { unsubscribe() { } }; }
|
|
153
|
-
async connect() { calls.push("client.connect");
|
|
154
|
+
async connect() { calls.push("client.connect"); if (connectError)
|
|
155
|
+
throw new Error(connectError); }
|
|
154
156
|
async close() { calls.push("client.close"); }
|
|
155
157
|
async call(method, params) { calls.push(`${method}:${params.to}:${params.encrypt}`); }
|
|
156
158
|
},
|
|
@@ -203,6 +205,9 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
203
205
|
strict_1.default.deepEqual(await plugin.identity.create("pending.agentid.pub", "owner.agentid.pub"), { aid: "pending.agentid.pub", status: "已创建", connection: "ready" });
|
|
204
206
|
strict_1.default.ok(calls.includes("register:pending.agentid.pub"));
|
|
205
207
|
strict_1.default.equal((await plugin.health()).details?.aids instanceof Array, true);
|
|
208
|
+
connectError = "no trusted roots available for auth certificate verification";
|
|
209
|
+
strict_1.default.deepEqual(await plugin.identity.create("unconnected.agentid.pub", "owner.agentid.pub"), { aid: "unconnected.agentid.pub", status: "已创建", connection: "degraded", connectionError: connectError });
|
|
210
|
+
connectError = "";
|
|
206
211
|
registration = { ok: false, error: { message: "注册失败" } };
|
|
207
212
|
await strict_1.default.rejects(plugin.identity.create("failed.agentid.pub", "owner.agentid.pub"), /注册失败/);
|
|
208
213
|
registration = { ok: true, data: {} };
|
|
@@ -30,6 +30,8 @@ const ids = ["abweb", "aun", "chatgpt", "doubao", "dsh", "feishu", "qwenwork", "
|
|
|
30
30
|
strict_1.default.deepEqual(manifest, packageManifest);
|
|
31
31
|
await (0, promises_1.access)((0, node_path_1.join)(directory, "config.schema.json"));
|
|
32
32
|
await (0, promises_1.access)((0, node_path_1.join)(directory, manifest.entry));
|
|
33
|
-
|
|
33
|
+
const meta = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(directory, "package.json"), "utf8"));
|
|
34
|
+
strict_1.default.equal(meta.name, `agent-bridge-${id}`);
|
|
35
|
+
strict_1.default.equal(meta.version, packageManifest.version);
|
|
34
36
|
}
|
|
35
37
|
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const promises_1 = require("node:fs/promises");
|
|
9
|
+
const node_vm_1 = require("node:vm");
|
|
10
|
+
class Element {
|
|
11
|
+
hidden = true;
|
|
12
|
+
value = "";
|
|
13
|
+
textContent = "";
|
|
14
|
+
className = "";
|
|
15
|
+
open = false;
|
|
16
|
+
options = [];
|
|
17
|
+
selectedIndex = 0;
|
|
18
|
+
children = [];
|
|
19
|
+
elements = {};
|
|
20
|
+
onclick;
|
|
21
|
+
onsubmit;
|
|
22
|
+
replaceChildren(...items) { this.children = items; }
|
|
23
|
+
append(...items) { this.children.push(...items); }
|
|
24
|
+
setAttribute() { }
|
|
25
|
+
querySelector() { return this.children.find(item => item.className === "channel-frame"); }
|
|
26
|
+
showModal() { this.open = true; }
|
|
27
|
+
close() { this.open = false; }
|
|
28
|
+
}
|
|
29
|
+
const flush = () => new Promise(resolve => setImmediate(resolve));
|
|
30
|
+
(0, node_test_1.default)("ABWeb只接受当前同源通道页面的结果,刷新不关闭弹窗", async () => {
|
|
31
|
+
const nodes = new Map();
|
|
32
|
+
const node = (selector) => { if (!nodes.has(selector))
|
|
33
|
+
nodes.set(selector, new Element()); return nodes.get(selector); };
|
|
34
|
+
const source = {};
|
|
35
|
+
const frame = new Element();
|
|
36
|
+
frame.className = "channel-frame";
|
|
37
|
+
frame.contentWindow = source;
|
|
38
|
+
let receive;
|
|
39
|
+
(0, node_vm_1.runInNewContext)(await (0, promises_1.readFile)("src-ts/plugins/abweb/public/app.js", "utf8"), {
|
|
40
|
+
document: { querySelector: node, createElement: () => new Element(), hidden: false },
|
|
41
|
+
window: { location: { origin: "http://localhost:26107" }, addEventListener(name, handler) { if (name === "message")
|
|
42
|
+
receive = handler; } },
|
|
43
|
+
localStorage: { getItem: () => null, removeItem() { } }, setInterval() { }, confirm: () => false,
|
|
44
|
+
fetch: async () => ({ ok: true, status: 200, json: async () => ({ plugins: [], messages: [], sessions: [] }) }),
|
|
45
|
+
});
|
|
46
|
+
await flush();
|
|
47
|
+
node("#channel-panel").children = [frame];
|
|
48
|
+
const data = { type: "mab:operation-result", title: "创建 AID 失败", message: "owner AID has no active owner profile", failed: true };
|
|
49
|
+
strict_1.default.equal(typeof receive, "function");
|
|
50
|
+
receive({ origin: "http://other.invalid", source, data });
|
|
51
|
+
receive({ origin: "http://localhost:26107", source: {}, data });
|
|
52
|
+
strict_1.default.equal(node("#operation-result").open, false);
|
|
53
|
+
receive({ origin: "http://localhost:26107", source, data });
|
|
54
|
+
strict_1.default.equal(node("#operation-result").open, true);
|
|
55
|
+
strict_1.default.equal(node("#operation-result-title").textContent, data.title);
|
|
56
|
+
strict_1.default.equal(node("#operation-result-message").textContent, data.message);
|
|
57
|
+
node("#refresh").onclick();
|
|
58
|
+
await flush();
|
|
59
|
+
strict_1.default.equal(node("#operation-result").open, true);
|
|
60
|
+
node("#operation-result-close").onclick();
|
|
61
|
+
strict_1.default.equal(node("#operation-result").open, false);
|
|
62
|
+
});
|
|
63
|
+
for (const scenario of [
|
|
64
|
+
{ ok: false, result: { error: "注册被拒绝" }, expected: "注册被拒绝", failed: true },
|
|
65
|
+
{ ok: true, result: { status: "已创建", connection: "degraded", connectionError: "no trusted roots available" }, expected: "已创建,但连接失败:no trusted roots available", failed: true },
|
|
66
|
+
{ ok: true, result: { status: "已创建", connection: "ready" }, expected: "已创建并连接", failed: false },
|
|
67
|
+
])
|
|
68
|
+
(0, node_test_1.default)(`AUN创建结果通知ABWeb:${scenario.expected}`, async () => {
|
|
69
|
+
const nodes = new Map();
|
|
70
|
+
const node = (selector) => { if (!nodes.has(selector))
|
|
71
|
+
nodes.set(selector, new Element()); return nodes.get(selector); };
|
|
72
|
+
for (const [selector, keys] of [["#create-form", ["aid", "ownerAid"]], ["#config-form", ["agent_plugin", "allow_from", "aun_path", "encryption_seed"]]]) {
|
|
73
|
+
for (const key of keys)
|
|
74
|
+
node(selector).elements[key] = new Element();
|
|
75
|
+
}
|
|
76
|
+
const messages = [];
|
|
77
|
+
let refresh;
|
|
78
|
+
(0, node_vm_1.runInNewContext)(await (0, promises_1.readFile)("src-ts/plugins/aun/public/app.js", "utf8"), {
|
|
79
|
+
document: { querySelector: node, createElement: () => new Element(), hidden: false },
|
|
80
|
+
window: { parent: { postMessage(data, origin) { messages.push({ data, origin }); } }, location: { origin: "http://localhost:26107" } },
|
|
81
|
+
Option: function () { return new Element(); }, localStorage: { getItem: () => null }, setInterval(handler) { refresh = handler; },
|
|
82
|
+
fetch: async (path, options) => options.method === "POST"
|
|
83
|
+
? { ok: scenario.ok, status: scenario.ok ? 201 : 502, json: async () => scenario.result }
|
|
84
|
+
: { ok: true, json: async () => path.endsWith("/identities") ? { groups: { muAgentBridge: [], evolcore: [] } } : { plugins: [] } },
|
|
85
|
+
});
|
|
86
|
+
await flush();
|
|
87
|
+
node("#create-form").elements.aid.value = "new.agentid.cn";
|
|
88
|
+
node("#create-form").elements.ownerAid.value = "owner.agentid.cn";
|
|
89
|
+
node("#create-form").onsubmit({ preventDefault() { } });
|
|
90
|
+
await flush();
|
|
91
|
+
strict_1.default.equal(messages.length, 1);
|
|
92
|
+
strict_1.default.equal(messages[0].data.type, "mab:operation-result");
|
|
93
|
+
strict_1.default.equal(messages[0].data.failed, scenario.failed);
|
|
94
|
+
strict_1.default.ok(messages[0].data.message.includes(scenario.expected));
|
|
95
|
+
strict_1.default.equal(messages[0].origin, "http://localhost:26107");
|
|
96
|
+
refresh();
|
|
97
|
+
await flush();
|
|
98
|
+
strict_1.default.equal(messages.length, 1, "自动刷新不反复弹窗");
|
|
99
|
+
});
|
|
@@ -44,6 +44,44 @@ const node_test_1 = __importDefault(require("node:test"));
|
|
|
44
44
|
const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
45
45
|
const version_manager_1 = require("../src-ts/version-manager");
|
|
46
46
|
const channel_sessions_1 = require("../src-ts/channel-sessions");
|
|
47
|
+
(0, node_test_1.default)("随包插件检查独立 npm 更新,升级后重启仍选新副本,失败恢复内置版本", async () => {
|
|
48
|
+
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-bundled-update-"));
|
|
49
|
+
const stateDir = (0, node_path_1.join)(root, "state");
|
|
50
|
+
const pluginsDir = (0, node_path_1.join)(root, "plugins");
|
|
51
|
+
const packageName = "agent-bridge-demo";
|
|
52
|
+
const writePlugin = async (dir, version, failed = false) => {
|
|
53
|
+
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
54
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "package.json"), JSON.stringify({ name: packageName, version, agentBridge: { plugin: "./plugin.json" } }));
|
|
55
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "demo", version, entry: "index.js", apiVersion: "1", capabilities: [] }));
|
|
56
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), `module.exports = { activate: async()=>{${failed ? 'throw new Error("升级测试失败")' : ''}}, deactivate: async()=>{}, health: async()=>({status:"ready"}) };`);
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
await writePlugin((0, node_path_1.join)(pluginsDir, "demo"), "1.0.0");
|
|
60
|
+
const versions = new version_manager_1.VersionManager({ stateDir, npm: async () => JSON.stringify({ version: "1.0.1" }) });
|
|
61
|
+
const options = { pluginsDir, stateDir, versions, publisherResolver: async () => "m2lihui" };
|
|
62
|
+
const manager = new plugin_manager_1.PluginManager(options);
|
|
63
|
+
await manager.discover();
|
|
64
|
+
await manager.start("demo");
|
|
65
|
+
strict_1.default.equal((await manager.checkPackageUpdates()).find((item) => item.packageName === packageName)?.state, "update-available");
|
|
66
|
+
strict_1.default.equal(manager.list()[0].autoUpdate, true);
|
|
67
|
+
const downloaded = (0, node_path_1.join)(root, "downloaded");
|
|
68
|
+
await writePlugin((0, node_path_1.join)(downloaded, "node_modules", packageName), "1.0.1", true);
|
|
69
|
+
manager.downloadPackage = async () => downloaded;
|
|
70
|
+
await strict_1.default.rejects(manager.upgradePackage("demo", packageName, "1.0.1"), /升级测试失败/);
|
|
71
|
+
strict_1.default.equal(manager.list()[0].version, "1.0.0");
|
|
72
|
+
strict_1.default.equal(manager.list()[0].status, "ready");
|
|
73
|
+
await writePlugin((0, node_path_1.join)(downloaded, "node_modules", packageName), "1.0.1");
|
|
74
|
+
strict_1.default.equal((await manager.upgradePackage("demo", packageName, "1.0.1")).version, "1.0.1");
|
|
75
|
+
await manager.stop("demo");
|
|
76
|
+
const restarted = new plugin_manager_1.PluginManager(options);
|
|
77
|
+
await restarted.discover();
|
|
78
|
+
strict_1.default.equal(restarted.list()[0].version, "1.0.1");
|
|
79
|
+
strict_1.default.equal(restarted.packageInfo("demo").managed, true);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
47
85
|
(0, node_test_1.default)("通道会话隔离、续接和重启恢复", async () => {
|
|
48
86
|
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-sessions-"));
|
|
49
87
|
try {
|
package/package.json
CHANGED
|
@@ -35,6 +35,25 @@
|
|
|
35
35
|
let loading = false;
|
|
36
36
|
const installingPackages = new Set();
|
|
37
37
|
function error(message) { errorNode.textContent = message; errorNode.hidden = !message; }
|
|
38
|
+
function showResult(title, message, failed) {
|
|
39
|
+
node("#operation-result-title").textContent = title;
|
|
40
|
+
const detail = node("#operation-result-message");
|
|
41
|
+
detail.textContent = message;
|
|
42
|
+
detail.className = failed ? "error" : "";
|
|
43
|
+
const dialog = node("#operation-result");
|
|
44
|
+
if (!dialog.open)
|
|
45
|
+
dialog.showModal();
|
|
46
|
+
}
|
|
47
|
+
node("#operation-result-close").onclick = () => node("#operation-result").close();
|
|
48
|
+
window.addEventListener("message", (event) => {
|
|
49
|
+
const frame = channelPanel.querySelector("iframe.channel-frame");
|
|
50
|
+
if (event.origin !== window.location.origin || !frame || event.source !== frame.contentWindow)
|
|
51
|
+
return;
|
|
52
|
+
const result = event.data;
|
|
53
|
+
if (!result || result.type !== "mab:operation-result" || typeof result.title !== "string" || typeof result.message !== "string" || typeof result.failed !== "boolean")
|
|
54
|
+
return;
|
|
55
|
+
showResult(result.title, result.message, result.failed);
|
|
56
|
+
});
|
|
38
57
|
async function loadCatalog() {
|
|
39
58
|
const result = await request(`/api/plugins/catalog?q=${encodeURIComponent(packageSearchNode.value.trim())}`);
|
|
40
59
|
const items = result.plugins ?? [];
|
|
@@ -113,7 +132,7 @@
|
|
|
113
132
|
item.type = "button";
|
|
114
133
|
item.textContent = label;
|
|
115
134
|
item.title = title;
|
|
116
|
-
item.onclick = () => { item.disabled = true; void run().catch((cause) =>
|
|
135
|
+
item.onclick = () => { item.disabled = true; void run().catch((cause) => { const message = cause instanceof Error ? cause.message : String(cause); error(message); showResult(`${title}失败`, message, true); }).finally(() => { item.disabled = false; void load(false); }); };
|
|
117
136
|
return item;
|
|
118
137
|
}
|
|
119
138
|
async function load(refreshCatalog = true) {
|
|
@@ -34,6 +34,21 @@
|
|
|
34
34
|
const installingPackages = new Set<string>();
|
|
35
35
|
|
|
36
36
|
function error(message: string): void { errorNode.textContent = message; errorNode.hidden = !message; }
|
|
37
|
+
function showResult(title: string, message: string, failed: boolean): void {
|
|
38
|
+
node<HTMLElement>("#operation-result-title").textContent = title;
|
|
39
|
+
const detail = node<HTMLElement>("#operation-result-message");
|
|
40
|
+
detail.textContent = message; detail.className = failed ? "error" : "";
|
|
41
|
+
const dialog = node<HTMLDialogElement>("#operation-result");
|
|
42
|
+
if (!dialog.open) dialog.showModal();
|
|
43
|
+
}
|
|
44
|
+
node<HTMLButtonElement>("#operation-result-close").onclick = () => node<HTMLDialogElement>("#operation-result").close();
|
|
45
|
+
window.addEventListener("message", (event: MessageEvent) => {
|
|
46
|
+
const frame = channelPanel.querySelector<HTMLIFrameElement>("iframe.channel-frame");
|
|
47
|
+
if (event.origin !== window.location.origin || !frame || event.source !== frame.contentWindow) return;
|
|
48
|
+
const result = event.data;
|
|
49
|
+
if (!result || result.type !== "mab:operation-result" || typeof result.title !== "string" || typeof result.message !== "string" || typeof result.failed !== "boolean") return;
|
|
50
|
+
showResult(result.title, result.message, result.failed);
|
|
51
|
+
});
|
|
37
52
|
async function loadCatalog(): Promise<void> {
|
|
38
53
|
const result = await request(`/api/plugins/catalog?q=${encodeURIComponent(packageSearchNode.value.trim())}`);
|
|
39
54
|
const items: Array<{ name: string; version: string; description: string; type: string }> = result.plugins ?? [];
|
|
@@ -80,7 +95,7 @@
|
|
|
80
95
|
}
|
|
81
96
|
function button(label: string, title: string, run: () => Promise<void>): HTMLButtonElement {
|
|
82
97
|
const item = document.createElement("button"); item.type = "button"; item.textContent = label; item.title = title;
|
|
83
|
-
item.onclick = () => { item.disabled = true; void run().catch((cause) =>
|
|
98
|
+
item.onclick = () => { item.disabled = true; void run().catch((cause) => { const message = cause instanceof Error ? cause.message : String(cause); error(message); showResult(`${title}失败`, message, true); }).finally(() => { item.disabled = false; void load(false); }); }; return item;
|
|
84
99
|
}
|
|
85
100
|
async function load(refreshCatalog = true): Promise<void> {
|
|
86
101
|
if (loading) return;
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
<div id="logs-panel" role="tabpanel" aria-labelledby="logs-tab" hidden><section><div class="section-heading"><h2>运行日志</h2><button id="logs-refresh" type="button">刷新日志</button></div><div class="table-scroll"><table><thead><tr><th>时间</th><th>级别</th><th>来源</th><th>消息</th><th>详细字段</th></tr></thead><tbody id="logs"></tbody></table></div><p id="logs-empty" class="muted" hidden>暂无运行日志</p><div class="section-heading"><button id="logs-prev" type="button">上一页</button><span id="logs-page" class="muted">第 1 页</span><button id="logs-next" type="button">下一页</button></div></section></div>
|
|
22
22
|
<p id="error" class="error" role="alert" hidden></p>
|
|
23
23
|
</main>
|
|
24
|
+
<dialog id="operation-result" aria-labelledby="operation-result-title" aria-describedby="operation-result-message">
|
|
25
|
+
<h2 id="operation-result-title">操作结果</h2><p id="operation-result-message"></p><button id="operation-result-close" type="button" autofocus>确定</button>
|
|
26
|
+
</dialog>
|
|
24
27
|
<script src="/abweb/app.js"></script>
|
|
25
28
|
</body>
|
|
26
29
|
</html>
|
|
@@ -56,3 +56,7 @@ th { color: #566761; font-weight: 600; background: #edf1ef; }
|
|
|
56
56
|
th:nth-child(1) { width: 145px; } th:nth-child(2) { width: 100px; } th:nth-child(3), th:nth-child(4) { width: 145px; } th:nth-child(5) { width: 62px; } th:nth-child(7) { width: 140px; }
|
|
57
57
|
.message-error td:last-child { color: #a83427; }
|
|
58
58
|
@media (max-width: 620px) { .shell { padding: 16px; } .section-heading { align-items: flex-start; flex-direction: column; } form, form input { width: 100%; } }
|
|
59
|
+
|
|
60
|
+
#operation-result { width: min(520px, calc(100% - 32px)); border: 1px solid #bfc9c5; border-radius: 8px; padding: 24px; }
|
|
61
|
+
#operation-result::backdrop { background: rgb(0 0 0 / 35%); }
|
|
62
|
+
#operation-result-message { white-space: pre-wrap; overflow-wrap: anywhere; margin: 16px 0; }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-abweb",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "agent-bridge 的网页管理插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-management"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/abweb"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/abweb/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "management"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -10,7 +10,7 @@ const node_url_1 = require("node:url");
|
|
|
10
10
|
const messages_1 = require("./messages");
|
|
11
11
|
const evolcore_1 = require("./evolcore");
|
|
12
12
|
const manifest = {
|
|
13
|
-
id: "aun", version: "1.0.
|
|
13
|
+
id: "aun", version: "1.0.17", type: "channel", displayName: "AUN 通道",
|
|
14
14
|
entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
|
|
15
15
|
capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health"],
|
|
16
16
|
configSchema: "config.schema.json",
|
|
@@ -87,9 +87,8 @@ class AunPlugin {
|
|
|
87
87
|
await this.persist();
|
|
88
88
|
this.context?.logger.info("AUN 身份已创建", { aid, owner });
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return { aid, status: "已创建", connection: this.clients.has(aid) ? "ready" : "degraded" };
|
|
90
|
+
const connectionError = !this.clients.has(aid) ? await this.connectAid(aid) : undefined;
|
|
91
|
+
return { aid, status: "已创建", connection: this.clients.has(aid) ? "ready" : "degraded", ...(connectionError ? { connectionError } : {}) };
|
|
93
92
|
}
|
|
94
93
|
finally {
|
|
95
94
|
this.creating = false;
|
|
@@ -244,7 +243,8 @@ class AunPlugin {
|
|
|
244
243
|
catch (error) {
|
|
245
244
|
this.status = "degraded";
|
|
246
245
|
this.healthMessage = safeError(error);
|
|
247
|
-
this.context?.logger.warn("AUN 通道连接失败", { error: this.healthMessage });
|
|
246
|
+
this.context?.logger.warn("AUN 通道连接失败", { aid, error: this.healthMessage });
|
|
247
|
+
return this.healthMessage;
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
async deactivate(_reason) {
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
return result;
|
|
16
16
|
}
|
|
17
17
|
function show(message, failed = false) { status.textContent = message; status.className = failed ? "error" : ""; }
|
|
18
|
+
function notify(title, message, failed = false) {
|
|
19
|
+
show(message, failed);
|
|
20
|
+
if (window.parent !== window) window.parent.postMessage({ type: "mab:operation-result", title, message, failed }, window.location.origin);
|
|
21
|
+
else window.alert(`${title}\n${message}`);
|
|
22
|
+
}
|
|
23
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
18
24
|
async function load(refreshForm = true) {
|
|
19
25
|
if (loading) return;
|
|
20
26
|
loading = true;
|
|
@@ -50,15 +56,22 @@
|
|
|
50
56
|
async function bind(aid, pluginId) {
|
|
51
57
|
try {
|
|
52
58
|
await request(`/api/plugins/${encodeURIComponent(pluginId)}/aid`, "PATCH", { aid });
|
|
53
|
-
await load();
|
|
54
|
-
} catch (error) {
|
|
59
|
+
await load(); notify("关联成功", `${aid} 已关联 ${pluginId}`);
|
|
60
|
+
} catch (error) { notify("关联失败", errorMessage(error), true); }
|
|
55
61
|
}
|
|
56
62
|
createForm.onsubmit = (event) => { event.preventDefault(); const aid = createForm.elements.aid.value.trim(); const owner = createForm.elements.ownerAid.value.trim();
|
|
57
|
-
|
|
63
|
+
show("正在创建 AID 并连接,请稍候……");
|
|
64
|
+
void request("/api/plugins/aun/aid", "POST", { aid, ownerAid: owner }).then((result) => {
|
|
65
|
+
const failed = result.connection === "degraded";
|
|
66
|
+
const message = failed ? `${aid} 已创建,但连接失败:${result.connectionError || "未提供连接失败原因,请查看运行日志"}\n身份已经保存在本地,请勿重复注册。`
|
|
67
|
+
: result.status === "等待 Owner 确认" ? `${aid} 等待 Owner 确认` : `${aid} 已创建并连接`;
|
|
68
|
+
notify(failed ? "AID 创建完成,连接失败" : "AID 创建结果", message, failed);
|
|
69
|
+
return load();
|
|
70
|
+
}).catch((error) => notify("创建 AID 失败", errorMessage(error), true));
|
|
58
71
|
};
|
|
59
72
|
configForm.onsubmit = (event) => { event.preventDefault(); const changes = { agent_plugin: configForm.elements.agent_plugin.value, allow_from: configForm.elements.allow_from.value, aun_path: configForm.elements.aun_path.value };
|
|
60
73
|
if (configForm.elements.encryption_seed.value) changes.encryption_seed = configForm.elements.encryption_seed.value;
|
|
61
|
-
void request("/api/plugins/aun/settings", "POST", changes).then(() => request("/api/plugins/aun/reload", "POST")).then(() => load()).then(() =>
|
|
74
|
+
void request("/api/plugins/aun/settings", "POST", changes).then(() => request("/api/plugins/aun/reload", "POST")).then(() => load()).then(() => notify("保存成功", "配置已保存")).catch((error) => notify("保存配置失败", errorMessage(error), true));
|
|
62
75
|
};
|
|
63
76
|
find("#refresh").onclick = () => void load();
|
|
64
77
|
void load();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-aun",
|
|
3
|
+
"version": "1.0.17",
|
|
4
|
+
"description": "mu-agent-bridge 的 AUN 通道插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-channel"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/aun"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/aun/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "channel"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.16.0"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@agentunion/fastaun": "0.5.18"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/plugins/aun/plugin.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"agent-bridge-chatgpt","version":"1.0.1","description":"agent-bridge 的 ChatGPT Codex CDP 插件。","keywords":["mu-agent-bridge-plugin","mu-agent-bridge-agent"],"main":"dist/src-ts/plugins/chatgpt/index.js","files":["dist/","plugin.json","config.schema.json","README.md"],"agentBridge":{"plugin":"./plugin.json","type":"agent"},"engines":{"node":">=22"}}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-doubao",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "agent-bridge 的豆包插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-agent"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/doubao"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/doubao/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "agent"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-dsh",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "agent-bridge 的 DeepSeek Harness 插件,支持后台定时自动升级验证。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-agent"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/dsh"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/dsh/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "agent"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-feishu",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "agent-bridge 的飞书通道插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-channel"
|
|
8
|
+
],
|
|
9
|
+
"main": "dist/src-ts/plugins/feishu/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"plugin.json",
|
|
13
|
+
"config.schema.json",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"agentBridge": {
|
|
17
|
+
"plugin": "./plugin.json",
|
|
18
|
+
"type": "channel"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"qrcode": "^1.5.4",
|
|
25
|
+
"@larksuiteoapi/node-sdk": "1.74.0"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-qwenwork",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "agent-bridge 的千问办公插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-agent"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/qwenwork"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/qwenwork/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "agent"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-bridge-workbuddy",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "agent-bridge 的 CodeBuddy CLI 插件。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu-agent-bridge-plugin",
|
|
7
|
+
"mu-agent-bridge-agent"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
|
|
12
|
+
"directory": "packages/workbuddy"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/src-ts/plugins/workbuddy/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"plugin.json",
|
|
18
|
+
"config.schema.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"agentBridge": {
|
|
22
|
+
"plugin": "./plugin.json",
|
|
23
|
+
"type": "agent"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
}
|
|
32
|
+
}
|