mu-agent-bridge 1.0.73 → 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 (152) hide show
  1. package/README.md +12 -8
  2. package/dist/src-ts/cli.js +67 -37
  3. package/dist/src-ts/control-server.js +7 -28
  4. package/dist/src-ts/core-updater.js +141 -33
  5. package/dist/src-ts/daemon-process.js +2 -1
  6. package/dist/src-ts/dsh-agent.js +7 -2
  7. package/dist/src-ts/http-agent.js +36 -0
  8. package/dist/src-ts/plugin-manager.js +185 -58
  9. package/dist/src-ts/plugins/abweb/index.js +1 -1
  10. package/dist/src-ts/plugins/abweb/public/app.js +8 -6
  11. package/dist/src-ts/plugins/abweb/public/index.html +3 -3
  12. package/dist/src-ts/plugins/aun/attachments.js +3 -21
  13. package/dist/src-ts/plugins/aun/index.js +89 -11
  14. package/dist/src-ts/plugins/aun/messages.js +1 -1
  15. package/dist/src-ts/plugins/aun/public/app.js +2 -1
  16. package/dist/src-ts/plugins/aun/public/index.html +1 -1
  17. package/dist/src-ts/plugins/cdp-draft.js +5 -2
  18. package/dist/src-ts/plugins/chatgpt/index.js +3 -2
  19. package/dist/src-ts/plugins/claude-cli/index.js +1 -1
  20. package/dist/src-ts/plugins/desktop-launch.js +44 -3
  21. package/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
  22. package/dist/src-ts/plugins/doubao/index.js +119 -7
  23. package/dist/src-ts/plugins/doubao/native-task.js +134 -0
  24. package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  25. package/dist/src-ts/plugins/dsh/index.js +102 -23
  26. package/dist/src-ts/plugins/dsh/session-history.js +31 -3
  27. package/dist/src-ts/plugins/feishu/index.js +1 -1
  28. package/dist/src-ts/plugins/personal-assistant/index.js +29 -8
  29. package/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
  30. package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  31. package/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
  32. package/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
  33. package/dist/src-ts/plugins/qwenwork/index.js +52 -18
  34. package/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
  35. package/dist/src-ts/plugins/workbuddy/index.js +24 -12
  36. package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  37. package/dist/src-ts/plugins/zcode/index.js +97 -0
  38. package/dist/src-ts/session-management.js +27 -8
  39. package/dist/src-ts/version-manager.js +6 -3
  40. package/dist/tests-ts/abweb-model-config.test.js +44 -41
  41. package/dist/tests-ts/aun-attachments.test.js +19 -17
  42. package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
  43. package/dist/tests-ts/aun-messages.test.js +14 -0
  44. package/dist/tests-ts/aun-plugin.test.js +207 -19
  45. package/dist/tests-ts/bundled-package.test.js +1 -1
  46. package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
  47. package/dist/tests-ts/chatgpt-plugin.test.js +19 -0
  48. package/dist/tests-ts/control-server.test.js +20 -0
  49. package/dist/tests-ts/core-updater.test.js +215 -46
  50. package/dist/tests-ts/daemon-process.test.js +126 -1
  51. package/dist/tests-ts/desktop-launch.test.js +73 -0
  52. package/dist/tests-ts/doubao-native-task.test.js +237 -0
  53. package/dist/tests-ts/doubao-plugin.test.js +688 -19
  54. package/dist/tests-ts/dsh-agent.test.js +91 -19
  55. package/dist/tests-ts/dsh-cdp.test.js +148 -0
  56. package/dist/tests-ts/dsh-history.test.js +37 -0
  57. package/dist/tests-ts/feishu-plugin.test.js +1 -1
  58. package/dist/tests-ts/http-agent.test.js +18 -0
  59. package/dist/tests-ts/local-cli.test.js +29 -2
  60. package/dist/tests-ts/model-provider-cancellation.test.js +2 -0
  61. package/dist/tests-ts/native-session-management.test.js +8 -7
  62. package/dist/tests-ts/personal-assistant-coordination.test.js +16 -0
  63. package/dist/tests-ts/personal-assistant-extensions.test.js +7 -1
  64. package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
  65. package/dist/tests-ts/personal-assistant.test.js +277 -3
  66. package/dist/tests-ts/platform-integration.test.js +60 -1
  67. package/dist/tests-ts/plugin-manager.test.js +78 -6
  68. package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
  69. package/dist/tests-ts/publish-packages.test.js +1 -1
  70. package/dist/tests-ts/qwenwork-plugin.test.js +30 -0
  71. package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
  72. package/dist/tests-ts/qwenwork-sse.test.js +33 -0
  73. package/dist/tests-ts/session-access-defaults.test.js +112 -0
  74. package/dist/tests-ts/session-management.test.js +8 -8
  75. package/dist/tests-ts/version-manager.test.js +40 -0
  76. package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
  77. package/dist/tests-ts/workbuddy-plugin.test.js +356 -13
  78. package/dist/tests-ts/zcode-cdp.test.js +894 -0
  79. package/dist/tests-ts/zcode-plugin.test.js +396 -0
  80. package/package.json +1 -1
  81. package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
  82. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +8 -6
  83. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +7 -5
  84. package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +3 -3
  85. package/plugins/abweb/package.json +1 -1
  86. package/plugins/abweb/plugin.json +1 -1
  87. package/plugins/aun/config.schema.json +1 -1
  88. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
  89. package/plugins/aun/dist/src-ts/plugins/aun/index.js +89 -11
  90. package/plugins/aun/dist/src-ts/plugins/aun/messages.js +1 -1
  91. package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
  92. package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
  93. package/plugins/aun/package.json +1 -1
  94. package/plugins/aun/plugin.json +1 -1
  95. package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
  96. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +3 -2
  97. package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
  98. package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +1 -1
  99. package/plugins/claude-cli/package.json +1 -1
  100. package/plugins/claude-cli/plugin.json +1 -1
  101. package/plugins/doubao/config.schema.json +2 -1
  102. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
  103. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
  104. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +119 -7
  105. package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
  106. package/plugins/doubao/package.json +1 -1
  107. package/plugins/doubao/plugin.json +1 -1
  108. package/plugins/dsh/config.schema.json +5 -2
  109. package/plugins/dsh/dist/src-ts/dsh-agent.js +7 -2
  110. package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
  111. package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  112. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +102 -23
  113. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
  114. package/plugins/dsh/package.json +1 -1
  115. package/plugins/dsh/plugin.json +1 -1
  116. package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
  117. package/plugins/feishu/package.json +1 -1
  118. package/plugins/feishu/plugin.json +1 -1
  119. package/plugins/personal-assistant/config.schema.json +3 -2
  120. package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
  121. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +29 -8
  122. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
  123. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  124. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
  125. package/plugins/personal-assistant/package.json +2 -2
  126. package/plugins/personal-assistant/plugin.json +1 -1
  127. package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
  128. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
  129. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
  130. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +52 -18
  131. package/plugins/qwenwork/package.json +1 -1
  132. package/plugins/qwenwork/plugin.json +1 -1
  133. package/plugins/workbuddy/config.schema.json +1 -1
  134. package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
  135. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
  136. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +24 -12
  137. package/plugins/workbuddy/package.json +1 -1
  138. package/plugins/workbuddy/plugin.json +1 -1
  139. package/plugins/zcode/config.schema.json +13 -0
  140. package/plugins/zcode/dist/src-ts/agent.js +69 -0
  141. package/plugins/zcode/dist/src-ts/attachments.js +62 -0
  142. package/plugins/zcode/dist/src-ts/plugin.js +13 -0
  143. package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
  144. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
  145. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  146. package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
  147. package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
  148. package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  149. package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  150. package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
  151. package/plugins/zcode/package.json +16 -0
  152. package/plugins/zcode/plugin.json +11 -0
@@ -25,6 +25,7 @@ const desktop_launch_1 = require("./plugins/desktop-launch");
25
25
  const workbuddy_1 = require("./plugins/workbuddy");
26
26
  const logger = { info() { }, warn() { }, error() { } };
27
27
  const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
28
+ const PLUGIN_UPGRADE_WAIT_MS = 2 * 60 * 60 * 1000;
28
29
  class PluginManager {
29
30
  options;
30
31
  controlUrl;
@@ -220,8 +221,22 @@ class PluginManager {
220
221
  if (manifest.id !== id || (0, plugin_catalog_1.resolvePluginId)(packageName, meta.agentBridge.id) !== id || manifest.version !== meta.version)
221
222
  throw new agent_1.AgentError("npm 包插件 ID 或版本不匹配");
222
223
  this.validateCandidate(manifest, meta.agentBridge);
223
- await this.stop(id, "reload");
224
- stopped = true;
224
+ const deadline = new AbortController();
225
+ const cancellation = loaded.cancellation;
226
+ const error = new agent_1.AgentOperationError("PLUGIN_UPGRADE_WAIT_TIMEOUT", "等待旧插件任务结束", new Error("升级已等待两小时,强制结束桥接任务并继续升级"));
227
+ this.log("info", `插件升级等待旧任务结束:${id}`, { waitMs: PLUGIN_UPGRADE_WAIT_MS, deadline: new Date(Date.now() + PLUGIN_UPGRADE_WAIT_MS).toISOString() }, "插件升级");
228
+ const timer = setTimeout(() => {
229
+ this.log("warn", `插件升级等待超时,强制结束桥接任务:${id}`, { code: error.code, waitMs: PLUGIN_UPGRADE_WAIT_MS }, "插件升级");
230
+ cancellation?.abort(error);
231
+ deadline.abort(error);
232
+ }, PLUGIN_UPGRADE_WAIT_MS);
233
+ try {
234
+ await this.stop(id, "reload", deadline.signal);
235
+ }
236
+ finally {
237
+ clearTimeout(timer);
238
+ stopped = !loaded.instance;
239
+ }
225
240
  if (hadPrefix)
226
241
  await (0, promises_1.rename)(prefix, backup);
227
242
  await (0, promises_1.rename)(staging, prefix);
@@ -280,12 +295,12 @@ class PluginManager {
280
295
  if (!(request.signal instanceof AbortSignal))
281
296
  throw new agent_1.AgentError("模型来源请求缺少取消信号");
282
297
  // 模型来源只接收最小调用契约,避免把未来扩展字段误传给桌面或 CLI 插件。
283
- const result = await loaded.instance.modelProvider.complete({
298
+ const result = await this.runPluginTask(loaded, request.signal, signal => loaded.instance.modelProvider.complete({
284
299
  prompt: request.prompt,
285
300
  sessionId: request.sessionId,
286
301
  timeoutMs: request.timeoutMs,
287
- signal: request.signal,
288
- });
302
+ signal,
303
+ }));
289
304
  if (!result || typeof result.text !== "string" || !result.text.trim() || Buffer.byteLength(result.text) > 1024 * 1024)
290
305
  throw new agent_1.AgentError(`模型来源插件“${loaded.record.displayName}”返回空内容或超大响应`);
291
306
  return { text: result.text };
@@ -366,7 +381,7 @@ class PluginManager {
366
381
  }
367
382
  if (loaded.instance) {
368
383
  try {
369
- await loaded.instance.deactivate("reload");
384
+ await loaded.instance.deactivate("reload", this.upgrades.has(id) ? { preserveDesktop: true } : undefined);
370
385
  }
371
386
  catch (error) {
372
387
  this.log("warn", `插件恢复前清理失败:${id}`, { error: error instanceof Error ? error.message : String(error) }, "插件生命周期");
@@ -396,14 +411,12 @@ class PluginManager {
396
411
  let instance;
397
412
  try {
398
413
  instance = await this.load(loaded.record);
414
+ const cancellation = loaded.cancellation = new AbortController();
415
+ loaded.tasks = new Set();
416
+ const http = loaded.http = this.createHttpRegistry(id);
399
417
  const dataDir = (0, node_path_1.join)(this.options.stateDir, id);
400
418
  await (0, promises_1.mkdir)(dataDir, { recursive: true });
401
- const configPath = (0, node_path_1.join)(dataDir, "config.json");
402
- let config = {};
403
- try {
404
- config = JSON.parse(await (0, promises_1.readFile)(configPath, "utf8"));
405
- }
406
- catch { /* defaults */ }
419
+ const config = await this.config(id);
407
420
  const pluginLogger = {
408
421
  info: (message, fields) => { this.log("info", message, fields, id); this.options.logger?.info(message, fields); if (fields?.direction && typeof fields.text === "string")
409
422
  this.recordMessage(id, fields.direction, fields.text, typeof fields.peer === "string" ? fields.peer : undefined, typeof fields.agentAid === "string" ? fields.agentAid : undefined); },
@@ -414,23 +427,33 @@ class PluginManager {
414
427
  dataDir,
415
428
  config,
416
429
  logger: pluginLogger,
417
- http: this.createHttpRegistry(id),
430
+ http,
418
431
  modelInputGuard: true,
419
432
  callPlugin: async (targetId, request) => {
420
433
  if (targetId === id)
421
434
  throw new agent_1.AgentError(`插件不能调用自身: ${id}`);
422
435
  if (request.management)
423
436
  throw new agent_1.AgentError("插件间调用不能传递管理能力");
424
- return this.handle(targetId, request);
437
+ cancellation.signal.throwIfAborted();
438
+ if (loaded.cancellation !== cancellation || !loaded.instance)
439
+ throw new agent_1.AgentError("插件实例已停止,旧调用已失效");
440
+ return this.handle(targetId, { ...request, signal: request.signal ? AbortSignal.any([request.signal, cancellation.signal]) : cancellation.signal });
425
441
  },
426
442
  callModelProvider: async (targetId, request) => {
427
443
  if (targetId === id)
428
444
  throw new agent_1.AgentError(`插件不能调用自身: ${id}`);
429
- return this.completeModelProvider(targetId, request);
445
+ cancellation.signal.throwIfAborted();
446
+ if (loaded.cancellation !== cancellation || !loaded.instance)
447
+ throw new agent_1.AgentError("插件实例已停止,旧调用已失效");
448
+ return this.completeModelProvider(targetId, { ...request, signal: AbortSignal.any([request.signal, cancellation.signal]) });
430
449
  },
431
450
  pluginStatus: (targetId) => this.plugins.get(targetId)?.record.status,
432
451
  ingress: {
433
- publish: async (message) => {
452
+ publish: message => this.runPluginTask(loaded, undefined, async (signal) => {
453
+ if (loaded.cancellation !== cancellation || loaded.instance !== instance)
454
+ throw new agent_1.AgentError("通道插件实例已停止,旧调用已失效");
455
+ if (loaded.record.status !== "ready")
456
+ throw new agent_1.AgentError("通道插件正在停止或尚未就绪,不再接收新任务");
434
457
  if (message.channel !== id)
435
458
  throw new agent_1.AgentError("消息来源与通道插件身份不一致");
436
459
  const trustedChannel = loaded.record.type === "channel" && (id === "aun" || id === "feishu");
@@ -444,7 +467,8 @@ class PluginManager {
444
467
  throw new agent_1.AgentError("当前通道不支持会话管理");
445
468
  const current = await this.sessions.current(message, target);
446
469
  const result = await this.sessionManagement.command(message.text, { source: current.source, sessionId: current.logicalSessionId });
447
- await message.reply(result);
470
+ signal.throwIfAborted();
471
+ await (0, agent_1.abortable)(message.reply(result, signal), signal);
448
472
  return;
449
473
  }
450
474
  if (trustedChannel)
@@ -457,15 +481,17 @@ class PluginManager {
457
481
  try {
458
482
  const agentInstance = this.plugins.get(target)?.instance;
459
483
  const control = agentInstance?.sessionOperations?.includes("new")
460
- ? (request) => this.controlSession(target, request)
484
+ ? (request) => this.controlSession(target, request, signal)
461
485
  : undefined;
462
486
  const task = !message.text.trim() && message.attachments?.length ? "请处理收到的附件" : message.text;
463
487
  const forwarded = new Set();
464
488
  const sent = [];
465
489
  const onMessage = async (text) => {
490
+ signal.throwIfAborted();
466
491
  if (!text.trim() || forwarded.has(text))
467
492
  return;
468
- await message.reply(text);
493
+ await (0, agent_1.abortable)(message.reply(text, signal), signal);
494
+ signal.throwIfAborted();
469
495
  forwarded.add(text);
470
496
  sent.push({ text });
471
497
  this.recordMessage(target, "reply", text, message.peerId);
@@ -473,9 +499,10 @@ class PluginManager {
473
499
  const response = await this.sessions.run(message, target, async (sessionId, newSession, logicalSessionId) => {
474
500
  const targetRecord = this.plugins.get(target)?.record;
475
501
  const config = targetRecord?.type === "agent" && targetRecord.capabilities.includes("management") ? await this.config(target) : undefined;
476
- const ability = trustedChannel && id === "aun" && loaded.instance === instance && loaded.record.status === "ready" && Array.isArray(config?.allowedPeers) && (config.allowedPeers.includes("*") || config.allowedPeers.includes(message.peerId))
477
- ? this.createRequestManagement(target, message.peerId, source, logicalSessionId) : undefined;
478
- const request = { task, sessionId, onMessage, ...(newSession ? { newSession: true } : {}), ...(message.attachments ? { attachments: message.attachments } : {}), ...(ability ? { management: ability } : {}) };
502
+ const ability = trustedChannel && id === "aun" && loaded.instance === instance && loaded.record.status === "ready" && Array.isArray(config?.allowedPeers) && (config.allowedPeers.length === 0 || config.allowedPeers.includes("*") || config.allowedPeers.includes(message.peerId))
503
+ ? this.createRequestManagement(target, message.peerId, source, logicalSessionId, { signal, onMessage, ...(message.replyAttachments ? { attachmentOutput: true } : {}) }) : undefined;
504
+ signal.throwIfAborted();
505
+ const request = { task, sessionId, signal, onMessage, ...(newSession ? { newSession: true } : {}), ...(message.attachments ? { attachments: message.attachments } : {}), ...(message.replyAttachments ? { attachmentOutput: true } : {}), ...(ability ? { management: ability } : {}) };
479
506
  const issued = ability ? this.issuedManagement.get(ability) : undefined;
480
507
  if (issued)
481
508
  issued.active = true;
@@ -487,14 +514,16 @@ class PluginManager {
487
514
  issued.active = false;
488
515
  }
489
516
  }, control);
517
+ signal.throwIfAborted();
490
518
  const attachments = response.attachments?.length ? response.attachments : (0, attachments_1.asAttachments)(response.images);
491
519
  (0, attachments_1.validateAttachments)(attachments);
492
520
  if (attachments.length) {
493
521
  if (!message.replyAttachments) {
494
- await message.reply("当前通道不支持附件回传");
522
+ await (0, agent_1.abortable)(message.reply("当前通道不支持附件回传", signal), signal);
495
523
  throw new agent_1.AgentError("当前通道不支持附件回传");
496
524
  }
497
- await message.replyAttachments(attachments, response.text);
525
+ await (0, agent_1.abortable)(message.replyAttachments(attachments, response.text, signal), signal);
526
+ signal.throwIfAborted();
498
527
  sent.push({ text: response.text, attachments });
499
528
  this.recordMessage(target, "reply", response.text, message.peerId);
500
529
  }
@@ -526,7 +555,7 @@ class PluginManager {
526
555
  else
527
556
  this.activeIngress.delete(source);
528
557
  }
529
- },
558
+ }),
530
559
  },
531
560
  runtime: { controlUrl: this.controlUrl, ports: {
532
561
  qwenwork: Number(process.env.AGENT_BRIDGE_QWEN_CDP_PORT ?? process.env.QWEN_CDP_PORT ?? "9228"),
@@ -542,13 +571,15 @@ class PluginManager {
542
571
  catch (error) {
543
572
  if (instance) {
544
573
  try {
545
- await instance.deactivate("reload");
574
+ await instance.deactivate("reload", this.upgrades.has(id) ? { preserveDesktop: true } : undefined);
546
575
  }
547
576
  catch (cleanupError) {
548
577
  this.log("warn", `插件启动失败后的清理失败:${id}`, { error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError) }, "插件生命周期");
549
578
  }
550
579
  this.unregisterHttpRoutes(id);
551
580
  }
581
+ loaded.http?.unregister();
582
+ loaded.cancellation?.abort(new agent_1.AgentError("插件启动失败,调用已取消"));
552
583
  loaded.instance = undefined;
553
584
  loaded.record.status = "failed";
554
585
  loaded.record.error = error instanceof Error ? error.message : String(error);
@@ -556,17 +587,44 @@ class PluginManager {
556
587
  throw error;
557
588
  }
558
589
  }
559
- async stop(id, reason = "stop") {
590
+ async stop(id, reason = "stop", deadline) {
560
591
  const loaded = this.plugins.get(id);
561
592
  if (!loaded)
562
593
  throw new agent_1.AgentError(`unknown plugin: ${id}`);
563
594
  if (loaded.instance) {
564
595
  loaded.record.status = "stopping";
596
+ const instance = loaded.instance;
597
+ const stopping = Promise.resolve().then(async () => {
598
+ if (deadline)
599
+ await Promise.allSettled([...(loaded.tasks ?? [])]);
600
+ await instance.deactivate(reason, deadline ? { preserveDesktop: true } : undefined);
601
+ });
565
602
  try {
566
- await loaded.instance.deactivate(reason);
603
+ try {
604
+ await (0, agent_1.abortable)(stopping, deadline);
605
+ }
606
+ catch (error) {
607
+ if (!deadline?.aborted)
608
+ throw error;
609
+ let cleanupTimer;
610
+ try {
611
+ const cleaned = await Promise.race([
612
+ stopping.then(() => true, () => false),
613
+ new Promise(resolve => { cleanupTimer = setTimeout(() => resolve(false), 5_000); }),
614
+ ]);
615
+ if (!cleaned)
616
+ this.log("warn", `旧插件未完成清理,已隔离并继续升级:${id}`, { code: "PLUGIN_UPGRADE_CLEANUP_TIMEOUT" }, "插件升级");
617
+ }
618
+ finally {
619
+ clearTimeout(cleanupTimer);
620
+ }
621
+ }
567
622
  }
568
623
  finally {
624
+ loaded.http?.unregister();
569
625
  this.unregisterHttpRoutes(id);
626
+ if (deadline)
627
+ loaded.cancellation?.abort(new agent_1.AgentError("插件已停止,旧实例调用已取消"));
570
628
  loaded.instance = undefined;
571
629
  }
572
630
  }
@@ -647,13 +705,31 @@ class PluginManager {
647
705
  }
648
706
  }
649
707
  async setAid(id, aid) { await this.saveConfig(id, { ...await this.config(id), aid }); }
650
- async config(id) { if (!this.plugins.has(id))
651
- throw new agent_1.AgentError(`unknown plugin: ${id}`); try {
652
- return JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(this.options.stateDir, id, "config.json"), "utf8"));
708
+ async config(id) {
709
+ const loaded = this.plugins.get(id);
710
+ if (!loaded)
711
+ throw new agent_1.AgentError(`unknown plugin: ${id}`);
712
+ let defaults = {};
713
+ if (loaded.record.manifest.configSchema) {
714
+ try {
715
+ const schema = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.resolve)(loaded.record.path, loaded.record.manifest.configSchema), "utf8"));
716
+ if (schema.default && typeof schema.default === "object" && !Array.isArray(schema.default))
717
+ defaults = schema.default;
718
+ }
719
+ catch { /* 默认声明不可读时保留已有配置 */ }
720
+ }
721
+ try {
722
+ const saved = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(this.options.stateDir, id, "config.json"), "utf8"));
723
+ if (!saved || typeof saved !== "object" || Array.isArray(saved))
724
+ throw new agent_1.AgentError("插件配置必须是对象");
725
+ return { ...defaults, ...saved };
726
+ }
727
+ catch (error) {
728
+ if (error.code === "ENOENT")
729
+ return defaults;
730
+ throw new agent_1.AgentError(`插件 ${id} 的配置无法读取或格式无效`);
731
+ }
653
732
  }
654
- catch {
655
- return {};
656
- } }
657
733
  async reloadStrategy(record) { if (!record.manifest.configSchema)
658
734
  return "reload"; try {
659
735
  const schema = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.resolve)(record.path, record.manifest.configSchema), "utf8"));
@@ -684,26 +760,28 @@ class PluginManager {
684
760
  ...await (0, agent_availability_1.agentAvailability)(plugin.id, await this.config(plugin.id), plugin.status),
685
761
  })));
686
762
  }
687
- createRequestManagement(pluginId, peerId, source, logicalSessionId) {
763
+ createRequestManagement(pluginId, peerId, source, logicalSessionId, output) {
688
764
  const issued = { pluginId, instance: this.plugins.get(pluginId)?.instance, active: false };
765
+ const cancellation = this.plugins.get(pluginId)?.cancellation;
689
766
  const checkActive = () => {
690
767
  const current = this.plugins.get(pluginId);
691
768
  if (!issued.active || !current?.instance || current.instance !== issued.instance)
692
769
  throw new agent_1.AgentError("管理能力请求已结束或已撤销");
770
+ cancellation?.signal.throwIfAborted();
693
771
  };
694
772
  const allowed = async (agentId) => {
695
773
  checkActive();
696
774
  const loaded = this.plugins.get(pluginId);
697
- if (!loaded?.instance || loaded.record.status !== "ready" || !loaded.record.capabilities.includes("management"))
775
+ if (!loaded?.instance || (loaded.record.status !== "ready" && !(loaded.record.status === "stopping" && this.upgrades.has(pluginId))) || !loaded.record.capabilities.includes("management"))
698
776
  throw new agent_1.AgentError("当前插件未声明管理能力或未就绪");
699
777
  const config = await this.config(pluginId);
700
778
  checkActive();
701
- const peers = Array.isArray(config.allowedPeers) ? config.allowedPeers : [];
702
- if (!peers.includes("*") && !peers.includes(peerId))
779
+ const peers = config.allowedPeers;
780
+ if (!Array.isArray(peers) || (peers.length > 0 && !peers.includes("*") && !peers.includes(peerId)))
703
781
  throw new agent_1.AgentError("当前 AUN 身份无权使用管理能力");
704
782
  if (agentId !== undefined) {
705
- const agents = Array.isArray(config.allowedAgents) ? config.allowedAgents : [];
706
- if (!agents.includes(agentId))
783
+ const agents = config.allowedAgents;
784
+ if (!Array.isArray(agents) || (agents.length > 0 && !agents.includes("*") && !agents.includes(agentId)))
707
785
  throw new agent_1.AgentError("目标 Agent 不在允许列表中");
708
786
  }
709
787
  return { loaded, config };
@@ -739,7 +817,7 @@ class PluginManager {
739
817
  const aids = identitiesAvailable
740
818
  ? Object.entries(bindings).filter(([aid, bound]) => /^[a-z0-9][a-z0-9_-]{2,63}\.[a-z0-9-]+(?:\.[a-z0-9-]+)+$/.test(aid) && agentIds.has(bound) && bound === record.id).map(([aid]) => aid).sort()
741
819
  : [];
742
- const callable = Boolean(latest?.instance) && latestRecord.type === "agent" && latestRecord.id !== pluginId && latestRecord.status === "ready" && availability.available && !latestRecord.capabilities.includes("management") && (Array.isArray(config.allowedAgents) && config.allowedAgents.includes(record.id));
820
+ const callable = Boolean(latest?.instance) && latestRecord.type === "agent" && latestRecord.id !== pluginId && latestRecord.status === "ready" && availability.available && !latestRecord.capabilities.includes("management") && (Array.isArray(config.allowedAgents) && (config.allowedAgents.length === 0 || config.allowedAgents.includes("*") || config.allowedAgents.includes(record.id)));
743
821
  result.push({ id: latestRecord.id, displayName: latestRecord.displayName, status: latestRecord.status, ...availability, reason: !identitiesAvailable && !availability.reason ? "AUN 身份数据不可用" : availability.reason, capabilities: [...latestRecord.capabilities], aids, callable });
744
822
  }
745
823
  await allowed();
@@ -759,14 +837,35 @@ class PluginManager {
759
837
  const sessionId = id === "workbuddy" && target.instance?.sessionOperations?.includes("new")
760
838
  ? `management-${(0, node_crypto_1.createHash)("sha256").update(`${logicalSessionId}\0${id}`).digest("hex")}`
761
839
  : undefined;
762
- const response = await this.handle(id, { task, ...(sessionId ? { sessionId } : {}) });
840
+ const signal = output?.signal ? AbortSignal.any([output.signal, cancellation.signal]) : cancellation.signal;
841
+ const response = await this.handle(id, { task, ...output, signal, ...(sessionId ? { sessionId } : {}) });
763
842
  if (loaded.instance !== this.plugins.get(pluginId)?.instance)
764
843
  throw new agent_1.AgentError("管理插件已重载");
765
844
  await allowed(id);
766
845
  return response;
767
846
  },
768
- listAunIdentities: async () => { await allowed(); const aun = this.plugins.get("aun")?.instance; if (!aun?.aunManagement)
769
- throw new agent_1.AgentError("AUN 身份管理不可用"); const result = await aun.aunManagement.list(); await allowed(); return result; },
847
+ listAunIdentities: async () => {
848
+ await allowed();
849
+ const aun = this.plugins.get("aun")?.instance;
850
+ let result;
851
+ if (aun?.aunManagement)
852
+ result = await aun.aunManagement.list();
853
+ else if (aun?.identity) {
854
+ // 旧 AUN 只有身份列表和健康绑定;兼容只读查询,不开放创建或绑定操作。
855
+ const groups = await aun.identity.list();
856
+ const health = await aun.health();
857
+ const aidPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{2,255}$/;
858
+ const aids = [...new Set([...groups.evolcore, ...groups.muAgentBridge, ...(groups.localMuAgentBridge ?? [])])].filter(aid => aidPattern.test(aid)).sort();
859
+ const raw = health.details?.bindings;
860
+ const bindings = raw && typeof raw === "object" && !Array.isArray(raw)
861
+ ? Object.fromEntries(Object.entries(raw).filter(([aid, id]) => aidPattern.test(aid) && typeof id === "string" && /^[a-z0-9][a-z0-9-]{0,63}$/.test(id))) : {};
862
+ result = { aids, bindings };
863
+ }
864
+ else
865
+ throw new agent_1.AgentError("AUN 身份管理不可用");
866
+ await allowed();
867
+ return result;
868
+ },
770
869
  createAunIdentity: async (input) => { await allowed(); const aun = this.plugins.get("aun")?.instance; if (!aun?.aunManagement)
771
870
  throw new agent_1.AgentError("AUN 身份管理不可用"); const result = await aun.aunManagement.create(input); await allowed(); return result; },
772
871
  bindAunIdentity: async (input) => { await allowed(input.agentId); const target = this.plugins.get(input.agentId); if (!target?.instance || target.record.type !== "agent" || target.record.status !== "ready")
@@ -784,6 +883,20 @@ class PluginManager {
784
883
  async health(id) { const loaded = this.plugins.get(id); if (!loaded)
785
884
  throw new agent_1.AgentError(`unknown plugin: ${id}`); if (!loaded.instance)
786
885
  return { status: loaded.record.status }; return loaded.instance.health(); }
886
+ async runPluginTask(loaded, upstream, work) {
887
+ const local = loaded.cancellation.signal;
888
+ const signal = upstream ? AbortSignal.any([upstream, local]) : local;
889
+ signal.throwIfAborted();
890
+ const task = (0, agent_1.abortable)(work(signal), signal);
891
+ const tasks = loaded.tasks;
892
+ tasks.add(task);
893
+ try {
894
+ return await task;
895
+ }
896
+ finally {
897
+ tasks.delete(task);
898
+ }
899
+ }
787
900
  async handle(id, request) {
788
901
  const loaded = this.plugins.get(id);
789
902
  if (!loaded?.instance || loaded.record.status !== "ready") {
@@ -803,17 +916,22 @@ class PluginManager {
803
916
  (0, attachments_1.validateAttachments)(request.attachments);
804
917
  if (request.attachments?.length && !loaded.instance.attachmentInput)
805
918
  throw new agent_1.AgentError(`插件 ${id} 不支持接收附件`);
806
- return loaded.instance.handle(request);
919
+ const instance = loaded.instance;
920
+ return this.runPluginTask(loaded, request.signal, signal => instance.handle({
921
+ ...request, signal,
922
+ ...(request.onMessage ? { onMessage: async (text) => { signal.throwIfAborted(); await request.onMessage(text); } } : {}),
923
+ }));
807
924
  }
808
- async controlSession(id, request) {
925
+ async controlSession(id, request, signal) {
809
926
  const loaded = this.plugins.get(id);
810
927
  if (!loaded?.instance || loaded.record.status !== "ready")
811
928
  throw new agent_1.AgentError(`插件 ${id} 未就绪,无法控制会话`);
812
929
  if (!loaded.instance.sessionOperations?.includes(request.operation))
813
930
  throw new agent_1.AgentError(`插件 ${id} 不支持新建会话`);
814
- const response = loaded.instance.controlSession
815
- ? await loaded.instance.controlSession(request)
816
- : { text: `${loaded.record.displayName} 已创建新会话`, sessionId: request.sessionId };
931
+ const instance = loaded.instance;
932
+ const response = await this.runPluginTask(loaded, signal, async () => instance.controlSession
933
+ ? instance.controlSession(request)
934
+ : { text: `${loaded.record.displayName} 已创建新会话`, sessionId: request.sessionId });
817
935
  if (typeof response.sessionId !== "string" || !response.sessionId.trim())
818
936
  throw new agent_1.AgentError("插件未返回有效的新会话标识,原会话绑定保持不变");
819
937
  return response;
@@ -831,18 +949,25 @@ class PluginManager {
831
949
  return true;
832
950
  }
833
951
  createHttpRegistry(pluginId) {
952
+ const disposers = new Set();
953
+ let closed = false;
954
+ const check = () => { if (closed)
955
+ throw new agent_1.AgentError("插件 HTTP 注册表已停止"); };
956
+ const remember = (dispose) => { disposers.add(dispose); return () => { dispose(); disposers.delete(dispose); }; };
834
957
  return {
835
958
  register: (routeOrMethod, pathOrHandler, maybeHandler) => {
959
+ check();
836
960
  if (typeof routeOrMethod === "object")
837
- return this.registerHttpRoute(pluginId, routeOrMethod.method, routeOrMethod.path, routeOrMethod.handler);
961
+ return remember(this.registerHttpRoute(pluginId, routeOrMethod.method, routeOrMethod.path, routeOrMethod.handler));
838
962
  if (typeof pathOrHandler === "string" && maybeHandler)
839
- return this.registerHttpRoute(pluginId, routeOrMethod, pathOrHandler, maybeHandler);
963
+ return remember(this.registerHttpRoute(pluginId, routeOrMethod, pathOrHandler, maybeHandler));
840
964
  if (typeof pathOrHandler === "function")
841
- return this.registerLegacyRoute(pluginId, routeOrMethod, pathOrHandler);
965
+ return remember(this.registerLegacyRoute(pluginId, routeOrMethod, pathOrHandler));
842
966
  throw new agent_1.AgentError("invalid plugin HTTP route");
843
967
  },
844
- registerRoute: (path, handler) => this.registerLegacyRoute(pluginId, path, handler),
845
- unregister: () => this.unregisterHttpRoutes(pluginId),
968
+ registerRoute: (path, handler) => { check(); return remember(this.registerLegacyRoute(pluginId, path, handler)); },
969
+ unregister: () => { closed = true; for (const dispose of disposers)
970
+ dispose(); disposers.clear(); },
846
971
  };
847
972
  }
848
973
  registerHttpRoute(pluginId, method, path, handler) {
@@ -854,8 +979,9 @@ class PluginManager {
854
979
  const existing = this.httpRoutes.get(key);
855
980
  if (existing)
856
981
  throw new agent_1.AgentError(`HTTP route already registered: ${normalizedMethod} ${normalizedPath}`);
857
- this.httpRoutes.set(key, { pluginId, method: normalizedMethod, path: normalizedPath, handler });
858
- return () => { if (this.httpRoutes.get(key)?.pluginId === pluginId)
982
+ const route = { pluginId, method: normalizedMethod, path: normalizedPath, handler };
983
+ this.httpRoutes.set(key, route);
984
+ return () => { if (this.httpRoutes.get(key) === route)
859
985
  this.httpRoutes.delete(key); };
860
986
  }
861
987
  registerLegacyRoute(pluginId, path, handler) {
@@ -876,8 +1002,9 @@ class PluginManager {
876
1002
  response.setHeader(name, value);
877
1003
  response.end(result?.body ?? "");
878
1004
  };
879
- this.httpRoutes.set(key, { pluginId, method: "*", path: normalizedPath, handler: nativeHandler });
880
- return () => { if (this.httpRoutes.get(key)?.pluginId === pluginId)
1005
+ const route = { pluginId, method: "*", path: normalizedPath, handler: nativeHandler };
1006
+ this.httpRoutes.set(key, route);
1007
+ return () => { if (this.httpRoutes.get(key) === route)
881
1008
  this.httpRoutes.delete(key); };
882
1009
  }
883
1010
  unregisterHttpRoutes(pluginId) { for (const [key, route] of this.httpRoutes)
@@ -5,7 +5,7 @@ const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const MANIFEST = {
7
7
  id: "abweb",
8
- version: "1.0.13",
8
+ version: "1.0.15",
9
9
  displayName: "Agent Bridge Web",
10
10
  entry: "dist/index.js",
11
11
  apiVersion: "1",
@@ -219,7 +219,8 @@
219
219
  versionsNode.replaceChildren(...entries.map((entry) => {
220
220
  const row = document.createElement("div");
221
221
  row.className = "version-row";
222
- row.textContent = `${entry.packageName} · 当前 ${entry.currentVersion} · ${entry.latestVersion ? `最新 ${entry.latestVersion}` : "最新版本未知"} · ${entry.state}${entry.error ? ` · ${entry.error}` : ""}`;
222
+ const state = entry.state === "unpublished" ? "未发布" : entry.state;
223
+ row.textContent = `${entry.packageName} · 当前 ${entry.currentVersion} · ${entry.latestVersion ? `最新 ${entry.latestVersion}` : "最新版本未知"} · ${state}${entry.error ? ` · ${entry.error}` : ""}`;
223
224
  return row;
224
225
  }));
225
226
  if (!entries.length)
@@ -427,8 +428,8 @@
427
428
  node("#assistant-api-key").value = "";
428
429
  node("#assistant-api-key").placeholder = config.apiKey ? "已配置,留空保留" : "可选,本地免认证服务可留空";
429
430
  node("#assistant-timeout").value = String(config.timeoutMs ?? 120000);
430
- node("#assistant-allowed-peers").value = (config.allowedPeers ?? []).join("\n");
431
- node("#assistant-allowed-agents").value = (config.allowedAgents ?? []).join("\n");
431
+ node("#assistant-allowed-peers").value = config.allowedPeers?.includes("*") ? "" : (config.allowedPeers ?? []).join("\n");
432
+ node("#assistant-allowed-agents").value = config.allowedAgents?.includes("*") ? "" : (config.allowedAgents ?? []).join("\n");
432
433
  node("#assistant-config-error").hidden = true;
433
434
  node("#assistant-config-dialog").showModal();
434
435
  }
@@ -457,7 +458,8 @@
457
458
  if (timeoutMs !== Number(assistantOriginal.timeoutMs ?? 120000))
458
459
  body.timeoutMs = timeoutMs;
459
460
  for (const [field, selector] of [["allowedPeers", "#assistant-allowed-peers"], ["allowedAgents", "#assistant-allowed-agents"]]) {
460
- const values = [...new Set(node(selector).value.split(/[\s,,]+/).filter(Boolean))];
461
+ const entries = [...new Set(node(selector).value.split(/[\s,,]+/).filter(Boolean))];
462
+ const values = entries.includes("*") ? [] : entries;
461
463
  if (JSON.stringify(values) !== JSON.stringify(assistantOriginal[field]))
462
464
  body[field] = values;
463
465
  }
@@ -519,8 +521,8 @@
519
521
  node("#check-versions").onclick = () => void request("/api/versions/check", "POST", {}).then(() => load()).catch((cause) => error(String(cause)));
520
522
  node("#save-update-policy").onclick = () => void request("/api/update-policy", "PATCH", { mode: policyNode.value }).then(() => load()).catch((cause) => error(String(cause)));
521
523
  node("#save-plugin-trust").onclick = () => { const button = node("#save-plugin-trust"); button.disabled = true; trustStatusNode.textContent = "正在保存…"; void request("/api/plugin-trust", "PATCH", pluginTrustConfig).then(() => { pluginTrustDirty = false; trustStatusNode.textContent = "信任设置已保存"; return load(false); }).catch((cause) => { trustStatusNode.textContent = String(cause); }).finally(() => { button.disabled = false; }); };
522
- node("#update-core").onclick = () => { if (confirm("确认升级后台并自动重启?"))
523
- void request("/api/update", "POST", {}).then(() => { error("后台正在升级,页面将在几秒后恢复"); }).catch((cause) => error(String(cause))); };
524
+ node("#update-core").onclick = () => { if (confirm("确认检查后台更新?有更高版本时将升级并自动重启"))
525
+ void request("/api/update", "POST", {}).then(() => { error("后台正在检查更新,有更高版本时升级并重启;结果请查看运行日志"); }).catch((cause) => error(String(cause))); };
524
526
  node("#pair-button").onclick = () => {
525
527
  const code = pairCodeNode.value.trim();
526
528
  if (!/^\d{6}$/.test(code))
@@ -39,9 +39,9 @@
39
39
  <label for="assistant-endpoint">OpenAI 兼容地址</label><input id="assistant-endpoint" type="url" placeholder="http://127.0.0.1:11434/v1/chat/completions">
40
40
  <label for="assistant-api-key">API 密钥(留空保留已有密钥)</label><input id="assistant-api-key" type="password" autocomplete="new-password">
41
41
  <label for="assistant-timeout">模型超时(毫秒)</label><input id="assistant-timeout" type="number" min="1000" max="120000" required>
42
- <label for="assistant-allowed-peers">允许使用助理的 Peer AID(每行一个)</label><textarea id="assistant-allowed-peers" rows="3" placeholder="example.agentid.cn"></textarea>
43
- <label for="assistant-allowed-agents">允许调用的 Agent 插件 ID(每行一个)</label><textarea id="assistant-allowed-agents" rows="3" placeholder="workbuddy&#10;dsh"></textarea>
44
- <p class="muted">插件来源沿用客户端登录及当前模型;留空白名单表示不授权。AID 关联请在 Channel 设置中完成。</p>
42
+ <label for="assistant-allowed-peers">允许使用助理的 Peer AID(每行一个,留空接受所有)</label><textarea id="assistant-allowed-peers" rows="3" placeholder="留空接受所有 Peer"></textarea>
43
+ <label for="assistant-allowed-agents">允许调用的 Agent 插件 ID(每行一个,留空允许所有)</label><textarea id="assistant-allowed-agents" rows="3" placeholder="留空允许所有已就绪 Agent"></textarea>
44
+ <p class="muted">默认留空,接受所有 Peer 并允许调用所有已就绪的普通 Agent;填写具体名单后才限制。插件来源沿用客户端登录及当前模型,AID 关联请在 Channel 设置中完成。</p>
45
45
  <p id="assistant-config-error" class="error" role="alert" hidden></p>
46
46
  <div><button id="assistant-config-save" type="submit">保存配置</button><button id="assistant-config-cancel" type="button">取消</button></div>
47
47
  </form>
@@ -250,30 +250,12 @@ async function uploadAunAttachments(client, ownerAid, peerAid, items) {
250
250
  const objectKey = `shared/${(0, node_crypto_1.randomUUID)()}/${filename.replace(/[^A-Za-z0-9._-]/g, "_")}`;
251
251
  const sha256 = digest(item.data);
252
252
  const contentType = item.contentType.toLowerCase();
253
- // 视频播放器不携带 AID 凭据,沿用 EvolCore 的标准可读对象上传方式。
254
- const video = contentType.startsWith("video/");
253
+ // 会话媒体控件不携带 AID 凭据,沿用 ec msg 的标准可读对象上传方式。
255
254
  const ref = { ownerAid, bucket: "default", objectKey, filename, contentType, sizeBytes: item.data.byteLength, sha256 };
256
- const uploaded = await client.storage.writeBytes(`/${objectKey}`, item.data, { contentType, public: video, overwrite: video })
255
+ const uploaded = await client.storage.writeBytes(`/${objectKey}`, item.data, { contentType, public: true, overwrite: true })
257
256
  .catch(error => { throw new agent_1.AgentOperationError("AUN_FS_UPLOAD_FAILED", `上传 AUN FS 文件“${filename}”`, error); });
258
257
  checkedMetadata({ ...uploaded, size: uploaded.size ?? uploaded.size_bytes ?? item.data.byteLength }, ref);
259
- if (video) {
260
- result.push({ owner_aid: ownerAid, object_key: objectKey, filename, content_type: contentType, size_bytes: item.data.byteLength, sha256 });
261
- continue;
262
- }
263
- const share = await client.storage.lowlevel.createShareLink({ owner: ownerAid, bucket: "default", objectKey, allowedAids: [peerAid], expireInSeconds: 86400 })
264
- .catch(error => { throw new agent_1.AgentOperationError("AUN_FS_SHARE_FAILED", `创建 AUN FS 文件“${filename}”的接收方授权`, error); });
265
- if (share.owner_aid && share.owner_aid !== ownerAid || share.bucket && share.bucket !== "default" || share.object_key && share.object_key !== objectKey)
266
- throw new Error("AUN 附件分享对象不一致");
267
- if (share.allowed_aids !== undefined && (!Array.isArray(share.allowed_aids) || share.allowed_aids.length !== 1 || share.allowed_aids[0] !== peerAid))
268
- throw new Error("AUN 附件分享授权不一致");
269
- const shareId = typeof share.share_id === "string" && /^[A-Za-z0-9]{10}$/.test(share.share_id) ? share.share_id : undefined;
270
- if (share.share_id !== undefined && !shareId)
271
- throw new Error("AUN 附件分享标识无效");
272
- const url = typeof share.path_url === "string" && share.path_url ? share.path_url : shareId ? `https://${ownerAid}/${objectKey}?t=${shareId}` : "";
273
- const token = url ? pathToken(url, ownerAid, objectKey) : undefined;
274
- if (!token || shareId && shareId !== token)
275
- throw new Error("AUN 附件分享链接无效");
276
- result.push({ owner_aid: ownerAid, bucket: "default", object_key: objectKey, url, filename, content_type: item.contentType, size_bytes: item.data.byteLength, sha256 });
258
+ result.push({ owner_aid: ownerAid, object_key: objectKey, filename, content_type: contentType, size_bytes: item.data.byteLength, sha256 });
277
259
  }
278
260
  return result;
279
261
  }