mu-agent-bridge 1.0.5 → 1.0.13

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 (42) hide show
  1. package/README.md +16 -11
  2. package/dist/src-ts/channel-sessions.js +68 -0
  3. package/dist/src-ts/cli.js +60 -25
  4. package/dist/src-ts/control-server.js +75 -94
  5. package/dist/src-ts/local-aids.js +26 -0
  6. package/dist/src-ts/log-store.js +64 -0
  7. package/dist/src-ts/plugin-manager.js +240 -39
  8. package/dist/src-ts/plugin-manifest.js +5 -1
  9. package/dist/src-ts/plugins/abweb/index.js +1 -1
  10. package/dist/src-ts/plugins/abweb/public/app.js +164 -100
  11. package/dist/src-ts/plugins/abweb/public/index.html +7 -6
  12. package/dist/src-ts/plugins/abweb/public/style.css +12 -13
  13. package/dist/src-ts/plugins/aun/evolcore.js +54 -0
  14. package/dist/src-ts/plugins/aun/index.js +253 -51
  15. package/dist/src-ts/plugins/aun/public/app.js +66 -0
  16. package/dist/src-ts/plugins/aun/public/index.html +14 -0
  17. package/dist/src-ts/plugins/aun/public/style.css +21 -0
  18. package/dist/src-ts/plugins/doubao/cdp-client.js +5 -4
  19. package/dist/src-ts/plugins/doubao/index.js +3 -2
  20. package/dist/src-ts/plugins/feishu/client.js +133 -0
  21. package/dist/src-ts/plugins/feishu/index.js +257 -0
  22. package/dist/src-ts/plugins/feishu/public/app.js +147 -0
  23. package/dist/src-ts/plugins/feishu/public/index.html +17 -0
  24. package/dist/src-ts/plugins/feishu/public/style.css +30 -0
  25. package/dist/src-ts/plugins/workbuddy/cdp-client.js +118 -0
  26. package/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  27. package/dist/src-ts/plugins/workbuddy/index.js +139 -0
  28. package/dist/src-ts/version-manager.js +9 -1
  29. package/dist/tests-ts/abweb-plugin.test.js +13 -2
  30. package/dist/tests-ts/aun-plugin.test.js +108 -4
  31. package/dist/tests-ts/control-server.test.js +88 -6
  32. package/dist/tests-ts/doubao-plugin.test.js +18 -0
  33. package/dist/tests-ts/feishu-client.test.js +72 -0
  34. package/dist/tests-ts/feishu-page.test.js +53 -0
  35. package/dist/tests-ts/feishu-plugin.test.js +148 -0
  36. package/dist/tests-ts/log-store.test.js +27 -0
  37. package/dist/tests-ts/platform-integration.test.js +40 -1
  38. package/dist/tests-ts/plugin-catalog.test.js +8 -0
  39. package/dist/tests-ts/plugin-manager.test.js +219 -13
  40. package/dist/tests-ts/workbuddy-plugin.test.js +85 -0
  41. package/package.json +30 -6
  42. package/plugins/abweb/plugin.json +1 -1
@@ -9,6 +9,225 @@ const node_os_1 = require("node:os");
9
9
  const node_path_1 = require("node:path");
10
10
  const node_test_1 = __importDefault(require("node:test"));
11
11
  const plugin_manager_1 = require("../src-ts/plugin-manager");
12
+ const version_manager_1 = require("../src-ts/version-manager");
13
+ const channel_sessions_1 = require("../src-ts/channel-sessions");
14
+ (0, node_test_1.default)("通道会话隔离、续接和重启恢复", async () => {
15
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-sessions-"));
16
+ try {
17
+ const store = new channel_sessions_1.ChannelSessions(root);
18
+ const seen = [];
19
+ const message = { channel: "feishu", recipientId: "cli_1", chatId: "group", peerId: "peer", text: "消息" };
20
+ const call = async (sessionId) => { seen.push(sessionId); return { text: "回复", sessionId: "agent-session" }; };
21
+ await store.run(message, "dsh", call);
22
+ await store.run(message, "dsh", call);
23
+ strict_1.default.equal(seen[1], "agent-session");
24
+ strict_1.default.notEqual(seen[0], "agent-session");
25
+ const resumed = new channel_sessions_1.ChannelSessions(root);
26
+ await resumed.run(message, "dsh", call);
27
+ strict_1.default.equal(seen[2], "agent-session");
28
+ await resumed.run({ ...message, recipientId: "cli_2" }, "dsh", call);
29
+ strict_1.default.notEqual(seen[3], seen[0]);
30
+ await resumed.run({ ...message, channel: "aun" }, "dsh", call);
31
+ strict_1.default.notEqual(seen[4], seen[0]);
32
+ await resumed.run(message, "doubao", call);
33
+ strict_1.default.notEqual(seen[5], "agent-session");
34
+ }
35
+ finally {
36
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
37
+ }
38
+ });
39
+ (0, node_test_1.default)("同一来源排队续接,失败不污染会话且不同来源可并发", async () => {
40
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-session-queue-"));
41
+ try {
42
+ const store = new channel_sessions_1.ChannelSessions(root);
43
+ const message = { channel: "aun", recipientId: "local", peerId: "peer" };
44
+ let release;
45
+ const gate = new Promise((resolve) => { release = resolve; });
46
+ const events = [];
47
+ const first = store.run(message, "dsh", async () => { events.push("first"); await gate; return { text: "一", sessionId: "saved" }; });
48
+ const second = store.run(message, "dsh", async (id) => { events.push(id); return { text: "二" }; });
49
+ await store.run({ ...message, peerId: "other" }, "dsh", async () => ({ text: "其它" }));
50
+ strict_1.default.deepEqual(events, ["first"]);
51
+ release();
52
+ await Promise.all([first, second]);
53
+ strict_1.default.deepEqual(events, ["first", "saved"]);
54
+ await strict_1.default.rejects(store.run(message, "dsh", async () => { throw new Error("失败"); }), /失败/);
55
+ await store.run(message, "dsh", async (id) => { strict_1.default.equal(id, "saved"); return { text: "恢复" }; });
56
+ }
57
+ finally {
58
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
59
+ }
60
+ });
61
+ (0, node_test_1.default)("插件版本约束支持常用比较符", () => {
62
+ strict_1.default.equal((0, version_manager_1.satisfiesVersion)("1.2.0", ">=1.0.0 <2.0.0"), true);
63
+ strict_1.default.equal((0, version_manager_1.satisfiesVersion)("2.0.0", ">=1.0.0 <2.0.0"), false);
64
+ strict_1.default.equal((0, version_manager_1.satisfiesVersion)("1.0.0", "=1.0.0"), true);
65
+ });
66
+ (0, node_test_1.default)("从没有 package.json 的计划任务目录启动插件", async () => {
67
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-task-cwd-"));
68
+ const previous = process.cwd();
69
+ try {
70
+ const dir = (0, node_path_1.join)(root, "plugins", "sample");
71
+ await (0, promises_1.mkdir)(dir, { recursive: true });
72
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "sample", version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [] }));
73
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
74
+ process.chdir(root);
75
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
76
+ await manager.discover();
77
+ await manager.start("sample");
78
+ strict_1.default.equal(manager.list()[0].status, "ready");
79
+ await manager.stop("sample");
80
+ }
81
+ finally {
82
+ process.chdir(previous);
83
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
84
+ }
85
+ });
86
+ (0, node_test_1.default)("插件启动前拒绝缺失依赖", async () => {
87
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-dependency-"));
88
+ try {
89
+ const dir = (0, node_path_1.join)(root, "needs", "1.0.0");
90
+ await (0, promises_1.mkdir)(dir, { recursive: true });
91
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "needs", version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [], dependencies: { aun: ">=1.0.0" } }));
92
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
93
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
94
+ await manager.discover();
95
+ await strict_1.default.rejects(() => manager.start("needs"), /缺少插件依赖/);
96
+ strict_1.default.equal(manager.list()[0].status, "failed");
97
+ }
98
+ finally {
99
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
100
+ }
101
+ });
102
+ (0, node_test_1.default)("插件配置按 schema 重载并拒绝无效值", async () => {
103
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-config-"));
104
+ try {
105
+ const dir = (0, node_path_1.join)(root, "configurable", "1.0.0");
106
+ await (0, promises_1.mkdir)(dir, { recursive: true });
107
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "configurable", version: "1.0.0", entry: "index.js", configSchema: "config.schema.json", apiVersion: "1", capabilities: [] }));
108
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "config.schema.json"), JSON.stringify({ type: "object", properties: { value: { type: "string" } }, required: ["value"], additionalProperties: false, "x-agent-bridge": { reload: "reload" } }));
109
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{globalThis.activations=(globalThis.activations||0)+1},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
110
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
111
+ await manager.discover();
112
+ await manager.start("configurable");
113
+ strict_1.default.deepEqual(await manager.saveConfig("configurable", { value: "ok" }), { action: "reload", restartRequired: false });
114
+ await strict_1.default.rejects(() => manager.saveConfig("configurable", { value: 1 }), /配置无效/);
115
+ strict_1.default.deepEqual(await manager.config("configurable"), { value: "ok" });
116
+ }
117
+ finally {
118
+ delete globalThis.activations;
119
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
120
+ }
121
+ });
122
+ (0, node_test_1.default)("依赖插件不能直接卸载并显示诊断", async () => {
123
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-dependency-protection-"));
124
+ try {
125
+ for (const [id, dependencies] of [["base", undefined], ["consumer", { base: ">=1.0.0" }]]) {
126
+ const dir = (0, node_path_1.join)(root, id, "1.0.0");
127
+ await (0, promises_1.mkdir)(dir, { recursive: true });
128
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [], ...(dependencies ? { dependencies } : {}) }));
129
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
130
+ }
131
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
132
+ await manager.discover();
133
+ strict_1.default.deepEqual(manager.list().find((item) => item.id === "consumer")?.dependencyStatus, []);
134
+ await strict_1.default.rejects(() => manager.uninstall("base"), /仍被依赖/);
135
+ }
136
+ finally {
137
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
138
+ }
139
+ });
140
+ (0, node_test_1.default)("依赖循环会出现在诊断中", async () => {
141
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-cycle-"));
142
+ try {
143
+ for (const [id, dependency] of [["first", "second"], ["second", "first"]]) {
144
+ const dir = (0, node_path_1.join)(root, id, "1.0.0");
145
+ await (0, promises_1.mkdir)(dir, { recursive: true });
146
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [], dependencies: { [dependency]: ">=1.0.0" } }));
147
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
148
+ }
149
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
150
+ await manager.discover();
151
+ strict_1.default.ok(manager.list().every((item) => item.dependencyStatus?.includes("存在循环依赖")));
152
+ }
153
+ finally {
154
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
155
+ }
156
+ });
157
+ (0, node_test_1.default)("现有六个插件配置兼容且局部更新保留旧字段", async () => {
158
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-existing-schema-"));
159
+ try {
160
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
161
+ await manager.discover();
162
+ for (const id of ["abweb", "aun", "doubao", "dsh", "qwenwork", "workbuddy"]) {
163
+ await manager.install((0, node_path_1.join)(process.cwd(), "plugins", id));
164
+ const config = id === "abweb" ? { publicPath: "/abweb" } : { aid: "existing.agentid.cn" };
165
+ await manager.saveConfig(id, config);
166
+ await manager.saveConfig(id, {});
167
+ strict_1.default.deepEqual(await manager.config(id), config, id);
168
+ }
169
+ }
170
+ finally {
171
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
172
+ }
173
+ });
174
+ (0, node_test_1.default)("依赖会先启动且循环依赖无法启动", async () => {
175
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-dependency-start-"));
176
+ try {
177
+ for (const [id, dependencies] of [["consumer", { provider: ">=1.0.0" }], ["provider", {}], ["cyclea", { cycleb: ">=1.0.0" }], ["cycleb", { cyclea: ">=1.0.0" }]]) {
178
+ const dir = (0, node_path_1.join)(root, id);
179
+ await (0, promises_1.mkdir)(dir, { recursive: true });
180
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [], dependencies }));
181
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
182
+ }
183
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
184
+ await manager.discover();
185
+ await manager.start("consumer");
186
+ strict_1.default.equal(manager.get("provider")?.record.status, "ready");
187
+ await strict_1.default.rejects(() => manager.start("cyclea"), /循环依赖/);
188
+ }
189
+ finally {
190
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
191
+ }
192
+ });
193
+ (0, node_test_1.default)("不兼容的缓存升级不会停用原插件", async () => {
194
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-upgrade-compat-"));
195
+ const name = "agent-bridge-sample";
196
+ try {
197
+ for (const [folder, version, requires] of [["npm", "1.0.0", undefined], ["downloads", "2.0.0", { "mu-agent-bridge": ">=999.0.0" }]]) {
198
+ const dir = folder === "npm" ? (0, node_path_1.join)(root, "state", "npm", name, "node_modules", name) : (0, node_path_1.join)(root, "state", "downloads", name, version, "node_modules", name);
199
+ await (0, promises_1.mkdir)(dir, { recursive: true });
200
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "package.json"), JSON.stringify({ name, version, agentBridge: { plugin: "./plugin.json", ...(requires ? { requires } : {}) } }));
201
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "sample", version, entry: "index.js", apiVersion: "1", capabilities: [] }));
202
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'ok'})};");
203
+ }
204
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
205
+ await manager.discover();
206
+ await manager.start("sample");
207
+ await strict_1.default.rejects(() => manager.upgradePackage("sample", name, "2.0.0"), /核心版本/);
208
+ strict_1.default.equal(manager.get("sample")?.record.version, "1.0.0");
209
+ strict_1.default.equal(manager.get("sample")?.record.status, "ready");
210
+ }
211
+ finally {
212
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
213
+ }
214
+ });
215
+ (0, node_test_1.default)("已安装插件核心版本不兼容时仍显示在列表中", async () => {
216
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-incompatible-installed-"));
217
+ try {
218
+ const name = "agent-bridge-newer";
219
+ const dir = (0, node_path_1.join)(root, "state", "npm", name, "node_modules", name);
220
+ await (0, promises_1.mkdir)(dir, { recursive: true });
221
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "package.json"), JSON.stringify({ name, version: "1.0.0", agentBridge: { plugin: "./plugin.json", requires: { "mu-agent-bridge": ">=999.0.0" } } }));
222
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id: "newer", version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [] }));
223
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
224
+ strict_1.default.equal((await manager.discover()).find((record) => record.id === "newer")?.status, "failed");
225
+ strict_1.default.match(manager.list().find((record) => record.id === "newer")?.error ?? "", /核心版本/);
226
+ }
227
+ finally {
228
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
229
+ }
230
+ });
12
231
  (0, node_test_1.default)("plugin manager discovers and controls a plugin lifecycle", async () => {
13
232
  const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-plugin-"));
14
233
  try {
@@ -170,16 +389,3 @@ const plugin_manager_1 = require("../src-ts/plugin-manager");
170
389
  await (0, promises_1.rm)(root, { recursive: true, force: true });
171
390
  }
172
391
  });
173
- (0, node_test_1.default)("页面创建的 AID 来源跨重启保存且不会重复", async () => {
174
- const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-created-aids-"));
175
- try {
176
- const options = { pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") };
177
- const manager = new plugin_manager_1.PluginManager(options);
178
- await manager.recordCreatedAid("new.agentid.cn");
179
- await manager.recordCreatedAid("new.agentid.cn");
180
- strict_1.default.deepEqual(await new plugin_manager_1.PluginManager(options).createdAids(), ["new.agentid.cn"]);
181
- }
182
- finally {
183
- await (0, promises_1.rm)(root, { recursive: true, force: true });
184
- }
185
- });
@@ -0,0 +1,85 @@
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 promises_1 = require("node:fs/promises");
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = require("node:path");
10
+ const node_test_1 = __importDefault(require("node:test"));
11
+ const workbuddy_1 = require("../src-ts/plugins/workbuddy");
12
+ const cdp_client_1 = require("../src-ts/plugins/workbuddy/cdp-client");
13
+ (0, node_test_1.default)("workbuddy CDP 拒绝连接其他应用的调试页面", async () => {
14
+ const client = new cdp_client_1.WorkbuddyCdpClient({ fetchImpl: async () => new Response(JSON.stringify([{ type: "page", title: "Other App", webSocketDebuggerUrl: "ws://127.0.0.1:9229/devtools/page/1" }])) });
15
+ await strict_1.default.rejects(() => client.connect(), /未找到 WorkBuddy 页面 target/);
16
+ });
17
+ (0, node_test_1.default)("workbuddy 插件通过已连接 CDP 返回桌面端回复", async () => {
18
+ const calls = [];
19
+ const plugin = new workbuddy_1.WorkbuddyPlugin({ client: { connect: async () => undefined, close() { }, connected: () => true, direct: async (text) => { calls.push(text); return "WB_DESKTOP_REPLY"; } } });
20
+ await plugin.activate({ config: { transport: "cdp" }, logger: { info() { }, warn() { }, error() { } } });
21
+ strict_1.default.deepEqual(await plugin.handle({ task: "请回复固定文本", sessionId: "aun:peer.agentid.cn" }), { text: "WB_DESKTOP_REPLY", sessionId: "aun:peer.agentid.cn" });
22
+ strict_1.default.deepEqual(calls, ["请回复固定文本"]);
23
+ strict_1.default.equal((await plugin.health()).status, "ready");
24
+ await plugin.deactivate("stop");
25
+ });
26
+ (0, node_test_1.default)("workbuddy 清单使用 CDP 插件能力", () => {
27
+ strict_1.default.equal(workbuddy_1.workbuddyManifest.id, "workbuddy");
28
+ strict_1.default.deepEqual(workbuddy_1.workbuddyManifest.capabilities, ["chat", "health"]);
29
+ });
30
+ (0, node_test_1.default)("workbuddy 保留 CLI 会话调用", async () => {
31
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "wb-cli-"));
32
+ const cliPath = (0, node_path_1.join)(root, "codebuddy.cjs");
33
+ const plugin = new workbuddy_1.WorkbuddyPlugin();
34
+ try {
35
+ await (0, promises_1.writeFile)(cliPath, "const a=process.argv;console.log(a[a.indexOf('--session-id')+1])");
36
+ await plugin.activate({ config: { transport: "cli", cliPath }, logger: { info() { }, warn() { }, error() { } } });
37
+ strict_1.default.equal((await plugin.handle({ task: "你好", sessionId: "aun:peer.agentid.cn" })).text, "aun-peer-agentid-cn");
38
+ await plugin.deactivate("stop");
39
+ }
40
+ finally {
41
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
42
+ }
43
+ });
44
+ (0, node_test_1.default)("workbuddy auto 不会在 CLI 未登录时切换到 CDP", async () => {
45
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "wb-cli-auth-"));
46
+ const cliPath = (0, node_path_1.join)(root, "codebuddy.cjs");
47
+ let cdpCalls = 0;
48
+ const plugin = new workbuddy_1.WorkbuddyPlugin({ client: { connect: async () => undefined, close() { }, connected: () => true, direct: async () => { cdpCalls++; return "桌面端回复"; } } });
49
+ try {
50
+ await (0, promises_1.writeFile)(cliPath, "console.error('Authentication required. Please use /login command to sign in to your account')");
51
+ await plugin.activate({ config: { transport: "auto", cliPath }, logger: { info() { }, warn() { }, error() { } } });
52
+ await strict_1.default.rejects(() => plugin.handle({ task: "你好" }), /CodeBuddy CLI 尚未登录/);
53
+ strict_1.default.equal(cdpCalls, 0);
54
+ await plugin.deactivate("stop");
55
+ }
56
+ finally {
57
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
58
+ }
59
+ });
60
+ (0, node_test_1.default)("workbuddy 从用户提示识别专家名称", () => {
61
+ strict_1.default.equal((0, workbuddy_1.extractExpertQuery)("只要AI短剧剧本专家,帮我写开场"), "AI短剧剧本专家");
62
+ strict_1.default.equal((0, workbuddy_1.extractExpertQuery)("请调用视频生成专家制作分镜"), "视频生成专家");
63
+ strict_1.default.equal((0, workbuddy_1.extractExpertQuery)("请解释什么是专家技能"), undefined);
64
+ });
65
+ (0, node_test_1.default)("workbuddy 专家请求使用 CDP,普通请求保留 CLI", async () => {
66
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "wb-expert-"));
67
+ const cliPath = (0, node_path_1.join)(root, "codebuddy.cjs");
68
+ const calls = [];
69
+ const plugin = new workbuddy_1.WorkbuddyPlugin({ client: {
70
+ connect: async () => undefined, close() { }, connected: () => true,
71
+ direct: async (task, _timeout, expert) => { calls.push({ task, expert }); return "专家回复"; },
72
+ } });
73
+ try {
74
+ await (0, promises_1.writeFile)(cliPath, "console.log('CLI_REPLY')");
75
+ await plugin.activate({ config: { transport: "auto", cliPath }, logger: { info() { }, warn() { }, error() { } } });
76
+ const task = "只要AI短剧剧本专家,帮我写开场";
77
+ strict_1.default.equal((await plugin.handle({ task })).text, "专家回复");
78
+ strict_1.default.deepEqual(calls, [{ task, expert: "AI短剧剧本专家" }]);
79
+ strict_1.default.equal((await plugin.handle({ task: "你好" })).text, "CLI_REPLY");
80
+ await plugin.deactivate("stop");
81
+ }
82
+ finally {
83
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
84
+ }
85
+ });
package/package.json CHANGED
@@ -1,13 +1,29 @@
1
1
  {
2
2
  "name": "mu-agent-bridge",
3
- "version": "1.0.5",
3
+ "version": "1.0.13",
4
4
  "description": "将 AUN Agent 连接到本地桌面 AI 客户端的插件平台。",
5
5
  "main": "dist/src-ts/cli.js",
6
- "bin": { "mab": "dist/src-ts/cli.js", "agent-bridge": "dist/src-ts/cli.js" },
7
- "files": ["dist/", "plugins/qwenwork/", "plugins/abweb/", "README.md"],
8
- "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" },
9
- "repository": { "type": "git", "url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git" },
10
- "engines": { "node": ">=22" },
6
+ "bin": {
7
+ "mab": "dist/src-ts/cli.js",
8
+ "agent-bridge": "dist/src-ts/cli.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "plugins/qwenwork/",
13
+ "plugins/abweb/",
14
+ "README.md"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git"
23
+ },
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
11
27
  "directories": {
12
28
  "doc": "docs",
13
29
  "test": "tests"
@@ -29,6 +45,14 @@
29
45
  "type": "commonjs",
30
46
  "devDependencies": {
31
47
  "@types/node": "^26.6.4",
48
+ "@types/qrcode": "^1.5.6",
49
+ "@types/semver": "^7.8.0",
32
50
  "typescript": "^5.9.3"
51
+ },
52
+ "dependencies": {
53
+ "@larksuiteoapi/node-sdk": "1.74.0",
54
+ "ajv": "^8.20.0",
55
+ "qrcode": "^1.5.4",
56
+ "semver": "^7.8.5"
33
57
  }
34
58
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "abweb",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "type": "management",
5
5
  "displayName": "Agent Bridge Web",
6
6
  "entry": "dist/index.js",