mu-agent-bridge 1.0.71 → 1.0.78

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 (195) hide show
  1. package/README.md +17 -10
  2. package/dist/src-ts/agent.js +35 -0
  3. package/dist/src-ts/channel-sessions.js +3 -2
  4. package/dist/src-ts/cli.js +67 -37
  5. package/dist/src-ts/control-server.js +12 -30
  6. package/dist/src-ts/core-updater.js +141 -33
  7. package/dist/src-ts/daemon-process.js +2 -1
  8. package/dist/src-ts/dsh-agent.js +31 -13
  9. package/dist/src-ts/http-agent.js +36 -0
  10. package/dist/src-ts/plugin-catalog.js +11 -2
  11. package/dist/src-ts/plugin-manager.js +351 -50
  12. package/dist/src-ts/plugins/abweb/index.js +1 -1
  13. package/dist/src-ts/plugins/abweb/public/app.js +73 -5
  14. package/dist/src-ts/plugins/abweb/public/index.html +15 -0
  15. package/dist/src-ts/plugins/abweb/public/style.css +4 -0
  16. package/dist/src-ts/plugins/aun/attachments.js +3 -21
  17. package/dist/src-ts/plugins/aun/index.js +155 -21
  18. package/dist/src-ts/plugins/aun/messages.js +4 -1
  19. package/dist/src-ts/plugins/aun/public/app.js +2 -1
  20. package/dist/src-ts/plugins/aun/public/index.html +1 -1
  21. package/dist/src-ts/plugins/cdp-draft.js +5 -2
  22. package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  23. package/dist/src-ts/plugins/chatgpt/index.js +80 -19
  24. package/dist/src-ts/plugins/claude-cli/index.js +19 -2
  25. package/dist/src-ts/plugins/codex-cli/index.js +19 -2
  26. package/dist/src-ts/plugins/desktop-launch.js +44 -3
  27. package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  28. package/dist/src-ts/plugins/doubao/index.js +152 -8
  29. package/dist/src-ts/plugins/doubao/native-task.js +134 -0
  30. package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  31. package/dist/src-ts/plugins/dsh/index.js +172 -21
  32. package/dist/src-ts/plugins/dsh/session-history.js +31 -3
  33. package/dist/src-ts/plugins/feishu/index.js +1 -1
  34. package/dist/src-ts/plugins/local-cli/agent.js +74 -9
  35. package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  36. package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  37. package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  38. package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  39. package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  40. package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  41. package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  42. package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  43. package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  44. package/dist/src-ts/plugins/qwenwork/index.js +139 -24
  45. package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  46. package/dist/src-ts/plugins/workbuddy/index.js +124 -41
  47. package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  48. package/dist/src-ts/plugins/zcode/index.js +97 -0
  49. package/dist/src-ts/session-management.js +132 -14
  50. package/dist/src-ts/version-manager.js +6 -3
  51. package/dist/tests-ts/abweb-cli.test.js +10 -2
  52. package/dist/tests-ts/abweb-model-config.test.js +73 -0
  53. package/dist/tests-ts/agent.test.js +27 -0
  54. package/dist/tests-ts/aun-attachments.test.js +19 -17
  55. package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
  56. package/dist/tests-ts/aun-messages.test.js +20 -0
  57. package/dist/tests-ts/aun-plugin.test.js +292 -19
  58. package/dist/tests-ts/bundled-package.test.js +12 -2
  59. package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
  60. package/dist/tests-ts/channel-sessions.test.js +27 -0
  61. package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
  62. package/dist/tests-ts/control-server.test.js +56 -0
  63. package/dist/tests-ts/core-updater.test.js +215 -46
  64. package/dist/tests-ts/daemon-process.test.js +126 -1
  65. package/dist/tests-ts/desktop-launch.test.js +73 -0
  66. package/dist/tests-ts/doubao-native-task.test.js +237 -0
  67. package/dist/tests-ts/doubao-plugin.test.js +773 -12
  68. package/dist/tests-ts/dsh-agent.test.js +157 -8
  69. package/dist/tests-ts/dsh-cdp.test.js +148 -0
  70. package/dist/tests-ts/dsh-history.test.js +37 -0
  71. package/dist/tests-ts/feishu-plugin.test.js +1 -1
  72. package/dist/tests-ts/http-agent.test.js +18 -0
  73. package/dist/tests-ts/installer-assets.test.js +1 -1
  74. package/dist/tests-ts/local-cli.test.js +146 -1
  75. package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
  76. package/dist/tests-ts/native-session-management.test.js +8 -7
  77. package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
  78. package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
  79. package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
  80. package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
  81. package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
  82. package/dist/tests-ts/personal-assistant.test.js +663 -0
  83. package/dist/tests-ts/platform-integration.test.js +183 -1
  84. package/dist/tests-ts/plugin-catalog.test.js +12 -2
  85. package/dist/tests-ts/plugin-manager.test.js +356 -4
  86. package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
  87. package/dist/tests-ts/publish-packages.test.js +42 -0
  88. package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
  89. package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
  90. package/dist/tests-ts/qwenwork-sse.test.js +33 -0
  91. package/dist/tests-ts/session-access-defaults.test.js +112 -0
  92. package/dist/tests-ts/session-management.test.js +159 -4
  93. package/dist/tests-ts/version-manager.test.js +40 -0
  94. package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
  95. package/dist/tests-ts/workbuddy-plugin.test.js +499 -4
  96. package/dist/tests-ts/zcode-cdp.test.js +894 -0
  97. package/dist/tests-ts/zcode-plugin.test.js +396 -0
  98. package/package.json +1 -1
  99. package/plugins/abweb/dist/src-ts/agent.js +35 -0
  100. package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
  101. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
  102. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
  103. package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
  104. package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
  105. package/plugins/abweb/package.json +1 -1
  106. package/plugins/abweb/plugin.json +1 -1
  107. package/plugins/aun/config.schema.json +1 -1
  108. package/plugins/aun/dist/src-ts/agent.js +35 -0
  109. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
  110. package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
  111. package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -1
  112. package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
  113. package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
  114. package/plugins/aun/package.json +1 -1
  115. package/plugins/aun/plugin.json +1 -1
  116. package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
  117. package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
  118. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  119. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
  120. package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
  121. package/plugins/chatgpt/package.json +1 -1
  122. package/plugins/chatgpt/plugin.json +1 -1
  123. package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
  124. package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
  125. package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  126. package/plugins/claude-cli/package.json +1 -1
  127. package/plugins/claude-cli/plugin.json +3 -2
  128. package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
  129. package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
  130. package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  131. package/plugins/codex-cli/package.json +1 -1
  132. package/plugins/codex-cli/plugin.json +3 -2
  133. package/plugins/doubao/config.schema.json +2 -1
  134. package/plugins/doubao/dist/src-ts/agent.js +35 -0
  135. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
  136. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  137. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
  138. package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
  139. package/plugins/doubao/package.json +1 -1
  140. package/plugins/doubao/plugin.json +3 -2
  141. package/plugins/dsh/config.schema.json +5 -2
  142. package/plugins/dsh/dist/src-ts/agent.js +35 -0
  143. package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
  144. package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
  145. package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  146. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +172 -21
  147. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
  148. package/plugins/dsh/package.json +1 -1
  149. package/plugins/dsh/plugin.json +3 -2
  150. package/plugins/feishu/dist/src-ts/agent.js +35 -0
  151. package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
  152. package/plugins/feishu/package.json +1 -1
  153. package/plugins/feishu/plugin.json +1 -1
  154. package/plugins/personal-assistant/config.schema.json +23 -0
  155. package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
  156. package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
  157. package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
  158. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  159. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  160. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  161. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  162. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  163. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  164. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  165. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  166. package/plugins/personal-assistant/package.json +39 -0
  167. package/plugins/personal-assistant/plugin.json +15 -0
  168. package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
  169. package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
  170. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
  171. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  172. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
  173. package/plugins/qwenwork/package.json +1 -1
  174. package/plugins/qwenwork/plugin.json +3 -2
  175. package/plugins/workbuddy/config.schema.json +1 -1
  176. package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
  177. package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
  178. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  179. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
  180. package/plugins/workbuddy/package.json +1 -1
  181. package/plugins/workbuddy/plugin.json +3 -2
  182. package/plugins/zcode/config.schema.json +13 -0
  183. package/plugins/zcode/dist/src-ts/agent.js +69 -0
  184. package/plugins/zcode/dist/src-ts/attachments.js +62 -0
  185. package/plugins/zcode/dist/src-ts/plugin.js +13 -0
  186. package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
  187. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
  188. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  189. package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
  190. package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
  191. package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  192. package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  193. package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
  194. package/plugins/zcode/package.json +16 -0
  195. package/plugins/zcode/plugin.json +11 -0
@@ -45,6 +45,149 @@ const node_http_1 = require("node:http");
45
45
  const plugin_manager_1 = require("../src-ts/plugin-manager");
46
46
  const version_manager_1 = require("../src-ts/version-manager");
47
47
  const channel_sessions_1 = require("../src-ts/channel-sessions");
48
+ async function withMappedNpmPackage(run) {
49
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-package-id-"));
50
+ const source = (0, node_path_1.join)(root, "source");
51
+ const bin = (0, node_path_1.join)(root, "bin");
52
+ const previousPath = process.env.PATH;
53
+ await (0, promises_1.mkdir)(source);
54
+ await (0, promises_1.mkdir)(bin);
55
+ await (0, promises_1.writeFile)((0, node_path_1.join)(source, "package.json"), JSON.stringify({ name: "agent-bridge-pa", version: "1.0.1", agentBridge: { id: "personal-assistant", plugin: "./plugin.json", type: "agent" } }));
56
+ await (0, promises_1.writeFile)((0, node_path_1.join)(source, "plugin.json"), JSON.stringify({ id: "personal-assistant", version: "1.0.1", entry: "index.js", apiVersion: "1", capabilities: ["chat"] }));
57
+ await (0, promises_1.writeFile)((0, node_path_1.join)(source, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'完成'})};");
58
+ await (0, promises_1.writeFile)((0, node_path_1.join)(bin, "npm"), `#!${process.execPath}\nconst fs=require('node:fs');const path=require('node:path');const args=process.argv.slice(2);if(args[0]==='install'){const prefix=args[args.indexOf('--prefix')+1];fs.mkdirSync(path.join(prefix,'node_modules'),{recursive:true});fs.cpSync(${JSON.stringify(source)},path.join(prefix,'node_modules','agent-bridge-pa'),{recursive:true});}`);
59
+ await (0, promises_1.chmod)((0, node_path_1.join)(bin, "npm"), 0o755);
60
+ process.env.PATH = `${bin}:${previousPath ?? ""}`;
61
+ try {
62
+ await run(root, source);
63
+ }
64
+ finally {
65
+ if (previousPath === undefined)
66
+ delete process.env.PATH;
67
+ else
68
+ process.env.PATH = previousPath;
69
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
70
+ }
71
+ }
72
+ (0, node_test_1.default)("npm 显式 ID 支持下载、安装和默认升级且配置归属不变", { skip: process.platform === "win32" }, async () => {
73
+ await withMappedNpmPackage(async (root) => {
74
+ const stateDir = (0, node_path_1.join)(root, "state");
75
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir, publisherResolver: async () => "m2lihui", versions: new version_manager_1.VersionManager({ stateDir, npm: async () => '"1.0.2"' }) });
76
+ await (0, promises_1.mkdir)((0, node_path_1.join)(stateDir, "personal-assistant"), { recursive: true });
77
+ await (0, promises_1.writeFile)((0, node_path_1.join)(stateDir, "personal-assistant", "config.json"), JSON.stringify({ aid: "existing.agentid.cn" }));
78
+ try {
79
+ const downloaded = await manager.downloadPackage("agent-bridge-pa", "1.0.1");
80
+ strict_1.default.equal(await manager.cachedPackage("agent-bridge-pa", "1.0.1"), downloaded);
81
+ strict_1.default.equal((await manager.installPackage("agent-bridge-pa@1.0.1")).id, "personal-assistant");
82
+ strict_1.default.deepEqual(await manager.config("personal-assistant"), { aid: "existing.agentid.cn" });
83
+ const restarted = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir, publisherResolver: async () => "m2lihui" });
84
+ strict_1.default.deepEqual((await restarted.discover()).map(({ id, packageName }) => [id, packageName]), [["personal-assistant", "agent-bridge-pa"]]);
85
+ const candidate = (0, node_path_1.join)(root, "upgrade", "node_modules", "agent-bridge-pa");
86
+ await (0, promises_1.mkdir)(candidate, { recursive: true });
87
+ await (0, promises_1.writeFile)((0, node_path_1.join)(candidate, "package.json"), JSON.stringify({ name: "agent-bridge-pa", version: "1.0.2", agentBridge: { id: "personal-assistant", plugin: "./plugin.json" } }));
88
+ await (0, promises_1.writeFile)((0, node_path_1.join)(candidate, "plugin.json"), JSON.stringify({ id: "personal-assistant", version: "1.0.2", entry: "index.js", apiVersion: "1", capabilities: ["chat"] }));
89
+ await (0, promises_1.writeFile)((0, node_path_1.join)(candidate, "index.js"), "module.exports={activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'})};");
90
+ manager.downloadPackage = async (name) => { strict_1.default.equal(name, "agent-bridge-pa"); return (0, node_path_1.join)(root, "upgrade"); };
91
+ strict_1.default.equal((await manager.upgradePackage("personal-assistant", undefined, "1.0.2")).version, "1.0.2");
92
+ strict_1.default.deepEqual(await manager.config("personal-assistant"), { aid: "existing.agentid.cn" });
93
+ }
94
+ finally {
95
+ if (manager.get("personal-assistant")?.instance)
96
+ await manager.stop("personal-assistant");
97
+ await manager.logs.flush();
98
+ }
99
+ });
100
+ });
101
+ (0, node_test_1.default)("npm 安装按解析后的 ID 拒绝不同来源覆盖并清理失败下载", { skip: process.platform === "win32" }, async () => {
102
+ await withMappedNpmPackage(async (root) => {
103
+ const directory = (0, node_path_1.join)(root, "plugins", "personal-assistant");
104
+ await (0, promises_1.mkdir)(directory, { recursive: true });
105
+ await (0, promises_1.writeFile)((0, node_path_1.join)(directory, "package.json"), JSON.stringify({ name: "agent-bridge-personal-assistant", version: "1.0.0", agentBridge: { plugin: "./plugin.json" } }));
106
+ await (0, promises_1.writeFile)((0, node_path_1.join)(directory, "plugin.json"), JSON.stringify({ id: "personal-assistant", version: "1.0.0", entry: "index.js", apiVersion: "1", capabilities: [] }));
107
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state"), publisherResolver: async () => "m2lihui" });
108
+ try {
109
+ await manager.discover();
110
+ await strict_1.default.rejects(manager.installPackage("agent-bridge-pa"), /插件已经存在|来源冲突/);
111
+ strict_1.default.equal(manager.list()[0].packageName, "agent-bridge-personal-assistant");
112
+ strict_1.default.equal(manager.list()[0].path, directory);
113
+ await strict_1.default.rejects((0, promises_1.readFile)((0, node_path_1.join)(root, "state", "npm", "agent-bridge-pa", "node_modules", "agent-bridge-pa", "package.json")), /ENOENT/);
114
+ }
115
+ finally {
116
+ await manager.logs.flush();
117
+ }
118
+ });
119
+ });
120
+ (0, node_test_1.default)("npm 显式 ID、清单和请求版本必须匹配", { skip: process.platform === "win32" }, async () => {
121
+ await withMappedNpmPackage(async (root, source) => {
122
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state"), publisherResolver: async () => "m2lihui" });
123
+ try {
124
+ for (const id of ["other", "", null, 12]) {
125
+ await (0, promises_1.writeFile)((0, node_path_1.join)(source, "package.json"), JSON.stringify({ name: "agent-bridge-pa", version: "1.0.1", agentBridge: { id, plugin: "./plugin.json" } }));
126
+ await strict_1.default.rejects(manager.downloadPackage("agent-bridge-pa", "1.0.1"), /ID|清单/);
127
+ await strict_1.default.rejects(manager.installPackage("agent-bridge-pa@1.0.1"), /ID|清单/);
128
+ }
129
+ await (0, promises_1.writeFile)((0, node_path_1.join)(source, "package.json"), JSON.stringify({ name: "agent-bridge-pa", version: "1.0.1", agentBridge: { id: "personal-assistant", plugin: "./plugin.json" } }));
130
+ await strict_1.default.rejects(manager.installPackage("agent-bridge-pa@1.0.2"), /版本/);
131
+ }
132
+ finally {
133
+ await manager.logs.flush();
134
+ }
135
+ });
136
+ });
137
+ (0, node_test_1.default)("目录发现校验显式 ID 并保留不同来源的现有插件", async () => {
138
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-package-source-"));
139
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state"), publisherResolver: async () => "m2lihui" });
140
+ try {
141
+ for (const [folder, name, version, id] of [["aa", "agent-bridge-personal-assistant", "1.0.0", undefined], ["bb", "agent-bridge-pa", "2.0.0", "personal-assistant"]]) {
142
+ const directory = (0, node_path_1.join)(root, folder);
143
+ await (0, promises_1.mkdir)(directory);
144
+ await (0, promises_1.writeFile)((0, node_path_1.join)(directory, "package.json"), JSON.stringify({ name, version, agentBridge: { id, plugin: "./plugin.json" } }));
145
+ await (0, promises_1.writeFile)((0, node_path_1.join)(directory, "plugin.json"), JSON.stringify({ id: "personal-assistant", version, entry: "index.js", apiVersion: "1", capabilities: [] }));
146
+ }
147
+ await manager.discover();
148
+ strict_1.default.equal(manager.list()[0].packageName, "agent-bridge-personal-assistant");
149
+ await manager.logs.flush();
150
+ strict_1.default.ok((await manager.logs.page()).logs.some(entry => entry.level === "warn" && entry.message.includes("来源冲突")));
151
+ await (0, promises_1.writeFile)((0, node_path_1.join)(root, "bb", "package.json"), JSON.stringify({ name: "agent-bridge-pa", version: "2.0.0", agentBridge: { id: "other", plugin: "./plugin.json" } }));
152
+ await strict_1.default.rejects(manager.discover(), /ID|清单/);
153
+ }
154
+ finally {
155
+ await manager.logs.flush();
156
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
157
+ }
158
+ });
159
+ (0, node_test_1.default)("模型来源只列出显式声明者并且只能调用已就绪的独立入口", async () => {
160
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-model-provider-"));
161
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
162
+ try {
163
+ for (const [id, capabilities, provider] of [
164
+ ["model-agent", ["chat", "model-provider"], "({complete:async request=>({text:JSON.stringify({keys:Object.keys(request),prompt:request.prompt})})})"],
165
+ ["ordinary-agent", ["chat"], "undefined"],
166
+ ]) {
167
+ const dir = (0, node_path_1.join)(root, "plugins", id);
168
+ await (0, promises_1.mkdir)(dir, { recursive: true });
169
+ 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 }));
170
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), `module.exports={manifest:require('./plugin.json'),activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:'task'}),modelProvider:${provider}};`);
171
+ }
172
+ await manager.discover();
173
+ strict_1.default.deepEqual(manager.listModelProviders().map(item => item.id), ["model-agent"]);
174
+ strict_1.default.equal(manager.listModelProviders()[0].available, false);
175
+ await strict_1.default.rejects(() => manager.completeModelProvider("model-agent", { prompt: "hello", sessionId: "private-session", timeoutMs: 1000, signal: new AbortController().signal }), /未就绪/);
176
+ await manager.start("model-agent");
177
+ await manager.start("ordinary-agent");
178
+ strict_1.default.equal(manager.listModelProviders()[0].available, true);
179
+ const input = { prompt: "hello", sessionId: "private-session", timeoutMs: 1000, signal: new AbortController().signal, management: {}, onMessage: () => { }, attachments: [] };
180
+ const result = await manager.completeModelProvider("model-agent", input);
181
+ strict_1.default.deepEqual(JSON.parse(result.text), { keys: ["prompt", "sessionId", "timeoutMs", "signal"], prompt: "hello" });
182
+ await strict_1.default.rejects(manager.completeModelProvider("ordinary-agent", input), /未声明模型来源/);
183
+ }
184
+ finally {
185
+ for (const id of ["model-agent", "ordinary-agent"])
186
+ if (manager.get(id)?.instance)
187
+ await manager.stop(id);
188
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
189
+ }
190
+ });
48
191
  (0, node_test_1.default)("启动按钮恢复已退出的桌面 Agent,健康实例和依赖保持运行", async () => {
49
192
  const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-desktop-start-"));
50
193
  const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
@@ -472,6 +615,41 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
472
615
  await (0, promises_1.rm)(root, { recursive: true, force: true });
473
616
  }
474
617
  });
618
+ (0, node_test_1.default)("插件整体默认配置用于启动并保留用户显式限制", async () => {
619
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-config-defaults-"));
620
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.join)(root, "plugins"), stateDir: (0, node_path_1.join)(root, "state") });
621
+ try {
622
+ for (const id of ["with-defaults", "without-defaults"]) {
623
+ const dir = (0, node_path_1.join)(root, "plugins", id);
624
+ await (0, promises_1.mkdir)(dir, { recursive: true });
625
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", entry: "index.js", configSchema: "config.schema.json", apiVersion: "1", capabilities: ["chat"] }));
626
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "config.schema.json"), JSON.stringify({ type: "object", properties: { allowedPeers: { type: "array", items: { type: "string" }, default: ["*"] }, allowedAgents: { type: "array", items: { type: "string" } }, aid: { type: "string" } }, ...(id === "with-defaults" ? { default: { allowedPeers: ["*"], allowedAgents: ["workbuddy"] } } : {}) }));
627
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports=class{async activate(c){this.config=c.config}async deactivate(){}async health(){return {status:'ready'}}async handle(){return {text:JSON.stringify(this.config)}}};");
628
+ }
629
+ await manager.discover();
630
+ const defaults = { allowedPeers: ["*"], allowedAgents: ["workbuddy"] };
631
+ strict_1.default.deepEqual(await manager.config("with-defaults"), defaults);
632
+ await manager.start("with-defaults");
633
+ strict_1.default.deepEqual(JSON.parse((await manager.handle("with-defaults", { task: "查看配置" })).text), defaults);
634
+ await manager.saveConfig("with-defaults", { aid: "assistant.agentid.cn" });
635
+ strict_1.default.deepEqual(await manager.config("with-defaults"), { ...defaults, aid: "assistant.agentid.cn" });
636
+ await manager.saveConfig("with-defaults", { allowedPeers: [], allowedAgents: [] });
637
+ strict_1.default.deepEqual(await manager.config("with-defaults"), { allowedPeers: [], allowedAgents: [], aid: "assistant.agentid.cn" });
638
+ await manager.reload("with-defaults");
639
+ strict_1.default.deepEqual(JSON.parse((await manager.handle("with-defaults", { task: "查看限制" })).text).allowedPeers, []);
640
+ strict_1.default.deepEqual(await manager.config("without-defaults"), {});
641
+ for (const value of ["{损坏", "null", "[]", '"无效配置"']) {
642
+ await (0, promises_1.writeFile)((0, node_path_1.join)(root, "state", "with-defaults", "config.json"), value);
643
+ await strict_1.default.rejects(manager.config("with-defaults"), /配置.*无法读取|配置.*无效/);
644
+ }
645
+ }
646
+ finally {
647
+ if (manager.get("with-defaults")?.instance)
648
+ await manager.stop("with-defaults");
649
+ await manager.logs.flush();
650
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
651
+ }
652
+ });
475
653
  (0, node_test_1.default)("插件配置按 schema 重载并拒绝无效值", async () => {
476
654
  const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-config-"));
477
655
  try {
@@ -642,6 +820,7 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
642
820
  const callPlugin = globalThis.callPlugin;
643
821
  strict_1.default.ok(callPlugin);
644
822
  strict_1.default.deepEqual(await callPlugin("target", { task: "你好" }), { text: "target:你好" });
823
+ await strict_1.default.rejects(() => callPlugin("target", { task: "推理", modelResponseSchema: { type: "object" } }), /无工具模型/);
645
824
  await strict_1.default.rejects(() => callPlugin("source", { task: "loop" }), /自身|self/);
646
825
  await manager.stop("target");
647
826
  await strict_1.default.rejects(() => callPlugin("target", { task: "offline" }), /未就绪|not ready/);
@@ -651,6 +830,142 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
651
830
  await (0, promises_1.rm)(root, { recursive: true, force: true });
652
831
  }
653
832
  });
833
+ (0, node_test_1.default)("管理能力只由 AUN ingress 签发并逐次校验白名单,重载后旧能力失效", async () => {
834
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-request-management-"));
835
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
836
+ try {
837
+ const writePlugin = async (id, type, capabilities, code) => {
838
+ const dir = (0, node_path_1.join)(root, id);
839
+ await (0, promises_1.mkdir)(dir, { recursive: true });
840
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", type, entry: "index.js", apiVersion: "1", capabilities }));
841
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), code);
842
+ };
843
+ await writePlugin("personal-assistant", "agent", ["chat", "management"], "module.exports={manifest:require('./plugin.json'),activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async(r)=>{globalThis.managementRequest=r;if(r.management){globalThis.managementAbilities=await r.management.listAgents();await r.management.summarizeToday();if(globalThis.managementPause){globalThis.managementReady();await new Promise(resolve=>globalThis.managementContinue=resolve)}if(!globalThis.managementPause)globalThis.managementCall=await r.management.callAgent('target','任务');try{await r.management.callAgent(globalThis.managementPause?'target':'unlisted','任务')}catch(e){globalThis.managementDenied=e.message}}return {text:r.management?'trusted':'untrusted'}}};");
844
+ await writePlugin("target", "agent", ["chat"], "module.exports={manifest:require('./plugin.json'),sessionOperations:['new'],activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async(r)=>{(globalThis.managementTargetRequests??=[]).push(r);return {text:'target:'+r.task}}};");
845
+ await writePlugin("aun", "channel", ["channel"], "module.exports={manifest:require('./plugin.json'),activate:async(c)=>{globalThis.managementIngress=c.ingress},deactivate:async()=>{},health:async()=>({status:'ready',details:{bindings:{'target.agentid.cn':'target','bad aid':'target','orphan.agentid.cn':'missing','other.agentid.cn':42}}}),aunManagement:{list:async()=>({ok:true}),create:async(input)=>input,bind:async(input)=>input},handle:async()=>({text:''})};");
846
+ await writePlugin("forged-channel", "channel", ["channel"], "module.exports={manifest:require('./plugin.json'),activate:async(c)=>{globalThis.forgedIngress=c.ingress},deactivate:async()=>{},health:async()=>({status:'ready'}),handle:async()=>({text:''})};");
847
+ await manager.discover();
848
+ await manager.start("personal-assistant");
849
+ await manager.start("target");
850
+ await manager.start("aun");
851
+ await manager.start("forged-channel");
852
+ const managementContexts = [];
853
+ manager.sessionManagement.summarizeToday = async (context) => { managementContexts.push(context); return { summary: "" }; };
854
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["admin.agentid.cn", "second.agentid.cn"], allowedAgents: ["target"] });
855
+ const ingress = globalThis.managementIngress;
856
+ let result = "";
857
+ await ingress.publish({ channel: "aun", peerId: "admin.agentid.cn", text: "你好", agentPlugin: "personal-assistant", reply: async (text) => { result = text; } });
858
+ strict_1.default.equal(result, "trusted");
859
+ const request = globalThis.managementRequest;
860
+ const abilities = globalThis.managementAbilities;
861
+ strict_1.default.deepEqual(abilities.find((item) => item.id === "target"), {
862
+ id: "target", displayName: "target", status: "ready", available: true, reason: "", capabilities: ["chat"], aids: ["target.agentid.cn"], callable: true,
863
+ });
864
+ await globalThis.forgedIngress.publish({ channel: "forged-channel", peerId: "admin.agentid.cn", text: "伪造", agentPlugin: "personal-assistant", reply: async () => undefined });
865
+ strict_1.default.equal(globalThis.managementRequest.management, undefined);
866
+ strict_1.default.equal(managementContexts.length, 1);
867
+ await ingress.publish({ channel: "aun", peerId: "second.agentid.cn", threadId: "topic-2", text: "另一来源", agentPlugin: "personal-assistant", reply: async () => undefined });
868
+ strict_1.default.equal(managementContexts.length, 2);
869
+ strict_1.default.notEqual(managementContexts[0].source, managementContexts[1].source);
870
+ strict_1.default.notEqual(managementContexts[0].sessionId, managementContexts[1].sessionId);
871
+ const targetRequests = globalThis.managementTargetRequests;
872
+ strict_1.default.equal(targetRequests[0].sessionId, undefined, "仅声明新建会话能力的插件不应自动收到隔离会话 ID");
873
+ strict_1.default.equal(targetRequests[1].sessionId, undefined);
874
+ strict_1.default.equal(targetRequests[0].management, undefined);
875
+ await ingress.publish({ channel: "aun", peerId: "admin.agentid.cn", text: "继续任务", agentPlugin: "personal-assistant", reply: async () => undefined });
876
+ strict_1.default.equal(targetRequests[2].sessionId, undefined);
877
+ strict_1.default.deepEqual(globalThis.managementCall, { text: "target:任务" });
878
+ strict_1.default.match(globalThis.managementDenied, /允许列表/);
879
+ await strict_1.default.rejects(request.management.listAgents(), /请求已结束/);
880
+ await strict_1.default.rejects(request.management.callAgent("target", "任务"), /请求已结束/);
881
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["*"], allowedAgents: ["target"] });
882
+ let wildcardResult = "";
883
+ await ingress.publish({ channel: "aun", peerId: "any-peer.agentid.cn", text: "通配来源", agentPlugin: "personal-assistant", reply: async (text) => { wildcardResult = text; } });
884
+ strict_1.default.equal(wildcardResult, "trusted");
885
+ strict_1.default.match(globalThis.managementDenied, /允许列表/);
886
+ await globalThis.forgedIngress.publish({ channel: "forged-channel", peerId: "any-peer.agentid.cn", text: "通配不授权伪造通道", agentPlugin: "personal-assistant", reply: async () => undefined });
887
+ strict_1.default.equal(globalThis.managementRequest.management, undefined);
888
+ let ready;
889
+ globalThis.managementPause = true;
890
+ globalThis.managementReady = () => ready();
891
+ const managementReady = new Promise(resolve => { ready = resolve; });
892
+ const pendingRequest = ingress.publish({ channel: "aun", peerId: "admin.agentid.cn", text: "撤权竞态", agentPlugin: "personal-assistant", reply: async () => undefined });
893
+ await managementReady;
894
+ // 直接更新配置以验证逐次授权检查,不依赖配置保存触发的插件重载。
895
+ await (0, promises_1.writeFile)((0, node_path_1.join)(root, "state", "personal-assistant", "config.json"), JSON.stringify({ allowedPeers: ["other.agentid.cn"], allowedAgents: ["target"] }));
896
+ globalThis.managementContinue();
897
+ globalThis.managementContinue();
898
+ await pendingRequest;
899
+ strict_1.default.match(globalThis.managementDenied, /无权/);
900
+ delete globalThis.managementPause;
901
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["other.agentid.cn"], allowedAgents: ["target"] });
902
+ let unauthorizedReply = "";
903
+ await ingress.publish({ channel: "aun", peerId: "admin.agentid.cn", text: "再次请求", agentPlugin: "personal-assistant", reply: async (text) => { unauthorizedReply = text; } });
904
+ strict_1.default.equal(unauthorizedReply, "untrusted");
905
+ await strict_1.default.rejects(manager.handle("personal-assistant", { task: "伪造", management: {} }), /无效或已撤销/);
906
+ await strict_1.default.rejects(manager.handle("target", { task: "转交", management: request.management }), /无效或已撤销/);
907
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["admin.agentid.cn", "second.agentid.cn"], allowedAgents: ["target"] });
908
+ let reloadReady;
909
+ globalThis.managementPause = true;
910
+ globalThis.managementReady = () => reloadReady();
911
+ const reloadBarrier = new Promise(resolve => { reloadReady = resolve; });
912
+ const inFlight = ingress.publish({ channel: "aun", peerId: "admin.agentid.cn", text: "重载竞态", agentPlugin: "personal-assistant", reply: async () => undefined });
913
+ await reloadBarrier;
914
+ await manager.reload("personal-assistant");
915
+ globalThis.managementContinue();
916
+ await inFlight;
917
+ strict_1.default.match(globalThis.managementDenied, /请求已结束或已撤销/);
918
+ delete globalThis.managementPause;
919
+ await strict_1.default.rejects(manager.handle("personal-assistant", { task: "旧对象", management: request.management }), /无效或已撤销/);
920
+ }
921
+ finally {
922
+ for (const id of ["aun", "target", "personal-assistant", "forged-channel"])
923
+ if (manager.get(id)?.instance)
924
+ await manager.stop(id);
925
+ for (const key of ["managementIngress", "forgedIngress", "managementRequest", "managementAbilities", "managementCall", "managementDenied", "managementPause", "managementReady", "managementContinue", "managementTargetRequests"])
926
+ delete globalThis[key];
927
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
928
+ }
929
+ });
930
+ (0, node_test_1.default)("个人助理调用 WorkBuddy 时按管理来源隔离并复用目标会话", async () => {
931
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-management-workbuddy-"));
932
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
933
+ try {
934
+ for (const [id, type, capabilities, code] of [
935
+ ["personal-assistant", "agent", ["chat", "management"], "handle:async(r)=>r.management.callAgent('workbuddy',r.task)"],
936
+ ["workbuddy", "agent", ["chat"], "sessionOperations:['new'],handle:async(r)=>{(globalThis.workbuddyManagementRequests??=[]).push(r);return {text:r.task}}"],
937
+ ["aun", "channel", ["channel"], "activate:async(c)=>{globalThis.workbuddyManagementIngress=c.ingress},handle:async()=>({text:''})"],
938
+ ]) {
939
+ const dir = (0, node_path_1.join)(root, id);
940
+ await (0, promises_1.mkdir)(dir, { recursive: true });
941
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, type, capabilities, version: "1.0.0", entry: "index.js", apiVersion: "1" }));
942
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), `module.exports={manifest:require('./plugin.json'),activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),${code}};`);
943
+ }
944
+ await manager.discover();
945
+ await manager.saveConfig("workbuddy", { executablePath: process.execPath });
946
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["admin.agentid.cn", "second.agentid.cn"], allowedAgents: ["workbuddy"] });
947
+ for (const id of ["workbuddy", "personal-assistant", "aun"])
948
+ await manager.start(id);
949
+ const ingress = globalThis.workbuddyManagementIngress;
950
+ for (const peerId of ["admin.agentid.cn", "second.agentid.cn", "admin.agentid.cn"]) {
951
+ await ingress.publish({ channel: "aun", peerId, text: "任务", agentPlugin: "personal-assistant", reply: async () => undefined });
952
+ }
953
+ const requests = globalThis.workbuddyManagementRequests;
954
+ strict_1.default.equal(requests.length, 3);
955
+ strict_1.default.match(requests[0].sessionId, /^management-[a-f0-9]{64}$/);
956
+ strict_1.default.notEqual(requests[0].sessionId, requests[1].sessionId);
957
+ strict_1.default.equal(requests[0].sessionId, requests[2].sessionId);
958
+ strict_1.default.ok(requests.every((request) => request.management === undefined));
959
+ }
960
+ finally {
961
+ for (const id of ["aun", "workbuddy", "personal-assistant"])
962
+ if (manager.get(id)?.instance)
963
+ await manager.stop(id);
964
+ delete globalThis.workbuddyManagementIngress;
965
+ delete globalThis.workbuddyManagementRequests;
966
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
967
+ }
968
+ });
654
969
  (0, node_test_1.default)("通道消息调用指定 Agent 并通过原消息回复", async () => {
655
970
  const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-channel-ingress-"));
656
971
  try {
@@ -729,9 +1044,11 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
729
1044
  await globalThis.attachmentIngress.publish(message);
730
1045
  strict_1.default.equal(globalThis.attachmentRequest.task, "原文");
731
1046
  strict_1.default.deepEqual(globalThis.attachmentRequest.attachments, [item]);
1047
+ strict_1.default.equal(globalThis.attachmentRequest.attachmentOutput, true);
732
1048
  strict_1.default.deepEqual(received, { items: [{ ...png, kind: "image" }], text: "生成结果" });
733
1049
  let failureText = "";
734
1050
  await strict_1.default.rejects(() => globalThis.attachmentIngress.publish({ ...message, replyAttachments: undefined, reply: async (text) => { failureText = text; } }), /不支持附件回传/);
1051
+ strict_1.default.equal(globalThis.attachmentRequest.attachmentOutput, undefined);
735
1052
  strict_1.default.match(failureText, /不支持附件回传/);
736
1053
  }
737
1054
  finally {
@@ -968,7 +1285,7 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
968
1285
  await (0, promises_1.rm)(root, { recursive: true, force: true });
969
1286
  }
970
1287
  });
971
- (0, node_test_1.default)("归档只信任真实通道,管理命令不会执行 Agent 或归档产物", async () => {
1288
+ (0, node_test_1.default)("限制模式下归档只信任真实通道,管理命令不会执行 Agent 或归档产物", async () => {
972
1289
  const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "manager-session-history-"));
973
1290
  const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
974
1291
  let summaryRequest = "";
@@ -999,7 +1316,7 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
999
1316
  await strict_1.default.rejects(globalThis.historyIngress_fake.publish(message("伪造")), /通道|来源/);
1000
1317
  await ingress.publish(message("默认不归档"));
1001
1318
  strict_1.default.equal((await manager.sessionManagement.archive.listSessions()).sessions.length, 0);
1002
- await manager.sessionManagement.saveConfig({ enabled: true, grants: [] });
1319
+ await manager.sessionManagement.saveConfig({ enabled: true, allowFrom: ["history-admin.agentid.cn"], grants: [] });
1003
1320
  await ingress.publish(message("正文", "peer", "same-message"));
1004
1321
  await ingress.publish(message("正文", "peer", "same-message"));
1005
1322
  const archived = (await manager.sessionManagement.archive.listSessions()).sessions;
@@ -1014,7 +1331,7 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
1014
1331
  await ingress.publish(message("最近 4 小时有哪些话题", "admin"));
1015
1332
  strict_1.default.match(replies.at(-1), /无权/);
1016
1333
  strict_1.default.equal(globalThis.historyCalls, before);
1017
- await manager.sessionManagement.saveConfig({ enabled: true, grants: [{ managerSource: admin.source, managerSessionId: admin.logicalSessionId, sources: [archived[0].source] }], summarizer: { endpoint: `http://127.0.0.1:${summaryServer.address().port}/v1/chat/completions`, model: "read-only" } });
1334
+ await manager.sessionManagement.saveConfig({ enabled: true, allowFrom: ["history-admin.agentid.cn"], grants: [{ managerSource: admin.source, managerSessionId: admin.logicalSessionId, sources: [archived[0].source] }], summarizer: { endpoint: `http://127.0.0.1:${summaryServer.address().port}/v1/chat/completions`, model: "read-only" } });
1018
1335
  await ingress.publish(message("/sessions list", "admin"));
1019
1336
  const ref = replies.at(-1).split("\n")[0].split(" ")[0];
1020
1337
  await ingress.publish(message(`/sessions summary --from ${ref} 比较内容`, "admin"));
@@ -1028,7 +1345,7 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
1028
1345
  await ingress.publish(message("/sessions list", "admin"));
1029
1346
  strict_1.default.ok(!replies.at(-1).includes("agent2"));
1030
1347
  const sources = (await manager.sessionManagement.archive.listSessions()).sessions.map(item => item.source);
1031
- await manager.sessionManagement.saveConfig({ enabled: true, grants: [{ managerSource: admin.source, managerSessionId: admin.logicalSessionId, sources }], summarizer: { endpoint: `http://127.0.0.1:${summaryServer.address().port}/v1/chat/completions`, model: "read-only" } });
1348
+ await manager.sessionManagement.saveConfig({ enabled: true, allowFrom: ["history-admin.agentid.cn"], grants: [{ managerSource: admin.source, managerSessionId: admin.logicalSessionId, sources }], summarizer: { endpoint: `http://127.0.0.1:${summaryServer.address().port}/v1/chat/completions`, model: "read-only" } });
1032
1349
  await ingress.publish(message("/sessions list", "admin"));
1033
1350
  const refs = replies.at(-1).split("\n").filter(line => /^[a-f0-9]{12}\./.test(line)).map(line => line.split(" ")[0]);
1034
1351
  strict_1.default.equal(refs.length, 2);
@@ -1243,3 +1560,38 @@ const channel_sessions_1 = require("../src-ts/channel-sessions");
1243
1560
  }
1244
1561
  }
1245
1562
  });
1563
+ (0, node_test_1.default)("个人助理兼容旧 AUN 的只读身份查询,保留绑定并转交附件回传能力", async () => {
1564
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-pa-legacy-aun-"));
1565
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir: root, stateDir: (0, node_path_1.join)(root, "state") });
1566
+ try {
1567
+ for (const [id, type, capabilities, code] of [
1568
+ ["aun", "channel", ["channel"], "activate:async(c)=>{globalThis.legacyPaIngress=c.ingress},identity:{list:async()=>({evolcore:['worker.agentid.cn'],muAgentBridge:['pa.agentid.cn'],localMuAgentBridge:['local.agentid.cn']})},health:async()=>({status:'ready',details:{bindings:{'worker.agentid.cn':'workbuddy'}}})"],
1569
+ ["personal-assistant", "agent", ["chat", "management"], "handle:async(r)=>{globalThis.legacyPaIdentities=await r.management.listAunIdentities();return r.management.callAgent('workbuddy',r.task)}"],
1570
+ ["workbuddy", "agent", ["chat"], "sessionOperations:['new'],handle:async(r)=>{globalThis.legacyPaTarget=r;await r.onMessage('执行中');return {text:'完成'}}"],
1571
+ ]) {
1572
+ const dir = (0, node_path_1.join)(root, id);
1573
+ await (0, promises_1.mkdir)(dir, { recursive: true });
1574
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, type, capabilities, version: "1.0.0", entry: "index.js", apiVersion: "1" }));
1575
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), `module.exports={manifest:require('./plugin.json'),activate:async()=>{},deactivate:async()=>{},health:async()=>({status:'ready'}),${code}};`);
1576
+ }
1577
+ await manager.discover();
1578
+ await manager.saveConfig("workbuddy", { executablePath: process.execPath });
1579
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["*"], allowedAgents: ["workbuddy"] });
1580
+ for (const id of ["workbuddy", "personal-assistant", "aun"])
1581
+ await manager.start(id);
1582
+ const replies = [];
1583
+ await globalThis.legacyPaIngress.publish({ channel: "aun", peerId: "owner.agentid.cn", agentPlugin: "personal-assistant", text: "生成图片", reply: async (s) => { replies.push(s); }, replyAttachments: async () => { } });
1584
+ strict_1.default.deepEqual(globalThis.legacyPaIdentities, { aids: ["local.agentid.cn", "pa.agentid.cn", "worker.agentid.cn"], bindings: { "worker.agentid.cn": "workbuddy" } });
1585
+ strict_1.default.equal(globalThis.legacyPaTarget.attachmentOutput, true);
1586
+ strict_1.default.equal(globalThis.legacyPaTarget.management, undefined);
1587
+ strict_1.default.deepEqual(replies, ["执行中", "完成"]);
1588
+ }
1589
+ finally {
1590
+ for (const id of ["aun", "personal-assistant", "workbuddy"])
1591
+ if (manager.get(id)?.instance)
1592
+ await manager.stop(id);
1593
+ for (const key of ["legacyPaIngress", "legacyPaIdentities", "legacyPaTarget"])
1594
+ delete globalThis[key];
1595
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
1596
+ }
1597
+ });