mu-agent-bridge 1.0.24 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ OpenAI 兼容 API 为 `/v1/models` 和 `/v1/chat/completions`。管理页面位
20
20
  安装后使用 `mab start` 启动。旧桥仍可使用 `17893`,不会与管理页面冲突。局域网访问时设置
21
21
  `AGENT_BRIDGE_HOST=0.0.0.0` 和 `AGENT_BRIDGE_TOKEN`,然后访问
22
22
  `http://<Windows 主机 IP>:26107/abweb/`。页面使用一次性配置码配对后管理插件;请只在可信网络使用。
23
- 如果 26107 被旧的 mab 进程占用,可执行 `mab restart`;命令会结束旧 daemon 并重新启动。`mab stop` 只停止 daemon,
23
+ 如果 26107 被旧的 mab 进程占用,可执行 `mab restart`;Windows 会扫描并结束同一 CLI 安装路径的全部旧 daemon,并重新启动。`mab stop` 只停止 daemon,
24
24
  `mab update` 会结束旧 daemon、安装最新核心包并启动新版本。不会把自己的旧进程误当成新的 daemon,也不会因此默认改用临时端口。
25
25
  已有 AID 的连接状态由 AUN 插件自己建立和查询,只有当前已连接的身份才能关联 Agent。
26
26
  AUN 插件通过 SDK 枚举 EvolCore 的本地 AID,并逐个建立连接;ABWeb 只展示已连接 AID,并按 EvolCore 与 mu-agent-bridge 分组,未连接身份不显示。状态检测不调用 `ec agent list/show`。
@@ -112,7 +112,7 @@ $env:CODEBUDDY_NPM_DIR = 'C:\path\to\node_modules\@tencent-ai\codebuddy-code'
112
112
 
113
113
  千问工作区默认使用 `%APPDATA%\QwenWorkCN\workspace`,可用 `$env:QWEN_WORKSPACE`
114
114
  覆盖;AUN 数据默认使用 `$env:EVOLCORE_HOME` 或用户目录下的 `.evolcore`。
115
- 千问 CDP 端口默认为 `9228`,也可用 `$env:QWEN_CDP_PORT` 或 `$env:AGENT_BRIDGE_QWEN_CDP_PORT` 覆盖。守护进程注入端口优先级最高,用来覆盖插件配置中的冲突端口;之后依次读取插件配置、环境变量和默认值。守护进程监听端口被占用时,会按 `AGENT_BRIDGE_FALLBACK_PORTS` 或系统临时端口回退,并在启动日志中报告实际端口。豆包和 WorkBuddy 分别使用 `DOUBAO_CDP_PORT`、`WORKBUDDY_CDP_PORT`,也支持对应的 `AGENT_BRIDGE_*_CDP_PORT`。
115
+ 千问 CDP 端口默认为 `9228`,也可用 `$env:QWEN_CDP_PORT` 或 `$env:AGENT_BRIDGE_QWEN_CDP_PORT` 覆盖。守护进程注入端口优先级最高,用来覆盖插件配置中的冲突端口;之后依次读取插件配置、环境变量和默认值。守护进程默认保持监听端口 26107;被其他程序占用时报告错误,仅显式配置 `AGENT_BRIDGE_FALLBACK_PORTS` 才允许回退。豆包和 WorkBuddy 分别使用 `DOUBAO_CDP_PORT`、`WORKBUDDY_CDP_PORT`,也支持对应的 `AGENT_BRIDGE_*_CDP_PORT`。
116
116
 
117
117
  ## 自检与运行
118
118
 
@@ -46,6 +46,7 @@ const dsh_agent_1 = require("./dsh-agent");
46
46
  const registry_1 = require("./registry");
47
47
  const bridge_1 = require("./bridge");
48
48
  const plugin_manager_1 = require("./plugin-manager");
49
+ const daemon_process_1 = require("./daemon-process");
49
50
  const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
50
51
  let activeManager;
51
52
  const logger = {
@@ -115,7 +116,7 @@ async function update() {
115
116
  return 2;
116
117
  }
117
118
  await stopDaemon();
118
- await execFileAsync("npm.cmd", ["install", "-g", "mu-agent-bridge@latest", "--no-fund", "--no-audit"], { timeout: 120_000 });
119
+ await execFileAsync("npm.cmd", ["install", "-g", "mu-agent-bridge@latest", "--no-fund", "--no-audit"], { timeout: 120_000, shell: true });
119
120
  await startDaemon();
120
121
  console.log("核心已更新,旧 daemon 已结束并启动新版本");
121
122
  return 0;
@@ -128,11 +129,17 @@ async function stopDaemon(stopTask = true) {
128
129
  pid = address.pid;
129
130
  }
130
131
  catch { /* 地址文件不存在时继续尝试计划任务 */ }
131
- if (pid && process.platform === "win32") {
132
- try {
133
- await execFileAsync("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { timeout: 15_000 });
132
+ if (process.platform === "win32") {
133
+ const script = "Get-CimInstance Win32_Process -Filter \"name = 'node.exe'\" | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress";
134
+ const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], { timeout: 15_000 });
135
+ const value = stdout.trim() ? JSON.parse(stdout) : [];
136
+ const processes = Array.isArray(value) ? value : [value];
137
+ for (const old of processes) {
138
+ if (old.ProcessId === process.pid || !(0, daemon_process_1.isDaemonCommand)(old.CommandLine ?? "", (0, node_path_1.resolve)(__dirname, "cli.js")))
139
+ continue;
140
+ await execFileAsync("taskkill.exe", ["/PID", String(old.ProcessId), "/F"], { timeout: 15_000 });
141
+ console.log(`已结束旧 daemon:${old.ProcessId}`);
134
142
  }
135
- catch { /* 进程已退出 */ }
136
143
  }
137
144
  else if (pid) {
138
145
  try {
@@ -234,8 +241,6 @@ async function serve() {
234
241
  throw new Error("局域网监听必须设置 AGENT_BRIDGE_TOKEN");
235
242
  }
236
243
  const fallbackPorts = (process.env.AGENT_BRIDGE_FALLBACK_PORTS ?? "").split(",").map((value) => Number(value.trim())).filter((value) => Number.isInteger(value) && value >= 0);
237
- if (port > 0 && !fallbackPorts.length)
238
- fallbackPorts.push(0);
239
244
  const server = new control_server_1.ControlServer({ manager, host, port, fallbackPorts, token: process.env.AGENT_BRIDGE_TOKEN, sessionFile: (0, node_path_1.resolve)(stateDirectory(), "paired-sessions.json") });
240
245
  const address = await server.start();
241
246
  const addressFile = (0, node_path_1.resolve)(stateDirectory(), "daemon-address.json");
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDaemonCommand = isDaemonCommand;
4
+ /** 只识别直接运行本安装 CLI 的后台进程,避免旧地址文件中的 PID 被其他程序复用。 */
5
+ function isDaemonCommand(commandLine, cli) {
6
+ const args = [...commandLine.matchAll(/"([^"]*)"|(\S+)/g)].map((match) => (match[1] ?? match[2]).replaceAll("\\", "/").toLowerCase());
7
+ return args[1] === cli.replaceAll("\\", "/").toLowerCase() && ["start", "--serve"].includes(args[2]);
8
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = __importDefault(require("node:test"));
8
+ const daemon_process_1 = require("../src-ts/daemon-process");
9
+ const cli = "C:\\Users\\molian\\AppData\\Roaming\\npm\\node_modules\\mu-agent-bridge\\dist\\src-ts\\cli.js";
10
+ (0, node_test_1.default)("识别同一安装的全部旧 daemon,兼容 Windows 路径与引号", () => {
11
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)(`"C:\\Program Files\\nodejs\\node.exe" ${cli.replaceAll("\\", "/")} start`, cli), true);
12
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)(`node.exe "${cli}" --serve`, cli), true);
13
+ });
14
+ (0, node_test_1.default)("清理进程时保留 CLI 操作、其他安装及普通 Node 程序", () => {
15
+ for (const args of ["restart", "stop", "update", "status"])
16
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)(`node.exe "${cli}" ${args}`, cli), false);
17
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)('node.exe C:\\other\\cli.js start', cli), false);
18
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)(`node.exe -e "${cli} start"`, cli), false);
19
+ strict_1.default.equal((0, daemon_process_1.isDaemonCommand)(`node.exe "${cli}.backup" start`, cli), false);
20
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mu-agent-bridge",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "description": "将 AUN Agent 连接到本地桌面 AI 客户端的插件平台。",
5
5
  "main": "dist/src-ts/cli.js",
6
6
  "bin": {