botmux 3.1.1 → 3.2.0

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 (190) hide show
  1. package/dist/adapters/backend/sandbox.d.ts +23 -0
  2. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  3. package/dist/adapters/backend/sandbox.js +68 -1
  4. package/dist/adapters/backend/sandbox.js.map +1 -1
  5. package/dist/adapters/cli/read-isolation.d.ts +1 -1
  6. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  7. package/dist/adapters/cli/read-isolation.js +15 -7
  8. package/dist/adapters/cli/read-isolation.js.map +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +117 -25
  11. package/dist/cli.js.map +1 -1
  12. package/dist/core/command-handler.d.ts.map +1 -1
  13. package/dist/core/command-handler.js +11 -4
  14. package/dist/core/command-handler.js.map +1 -1
  15. package/dist/core/dashboard-ipc-server.d.ts +1 -0
  16. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  17. package/dist/core/dashboard-ipc-server.js +132 -0
  18. package/dist/core/dashboard-ipc-server.js.map +1 -1
  19. package/dist/core/maintenance.d.ts +23 -1
  20. package/dist/core/maintenance.d.ts.map +1 -1
  21. package/dist/core/maintenance.js +63 -25
  22. package/dist/core/maintenance.js.map +1 -1
  23. package/dist/core/plugins/cli-generation.d.ts.map +1 -1
  24. package/dist/core/plugins/cli-generation.js +7 -0
  25. package/dist/core/plugins/cli-generation.js.map +1 -1
  26. package/dist/core/plugins/convention-scanner.d.ts +3 -3
  27. package/dist/core/plugins/convention-scanner.d.ts.map +1 -1
  28. package/dist/core/plugins/convention-scanner.js.map +1 -1
  29. package/dist/core/plugins/install.d.ts.map +1 -1
  30. package/dist/core/plugins/install.js +84 -26
  31. package/dist/core/plugins/install.js.map +1 -1
  32. package/dist/core/plugins/mcp/environment.d.ts +12 -0
  33. package/dist/core/plugins/mcp/environment.d.ts.map +1 -0
  34. package/dist/core/plugins/mcp/environment.js +17 -0
  35. package/dist/core/plugins/mcp/environment.js.map +1 -0
  36. package/dist/core/plugins/mcp/gateway-installer.d.ts.map +1 -1
  37. package/dist/core/plugins/mcp/gateway-installer.js +9 -3
  38. package/dist/core/plugins/mcp/gateway-installer.js.map +1 -1
  39. package/dist/core/plugins/mcp/gateway.d.ts +13 -1
  40. package/dist/core/plugins/mcp/gateway.d.ts.map +1 -1
  41. package/dist/core/plugins/mcp/gateway.js +143 -23
  42. package/dist/core/plugins/mcp/gateway.js.map +1 -1
  43. package/dist/core/plugins/mcp/host.d.ts +18 -0
  44. package/dist/core/plugins/mcp/host.d.ts.map +1 -0
  45. package/dist/core/plugins/mcp/host.js +126 -0
  46. package/dist/core/plugins/mcp/host.js.map +1 -0
  47. package/dist/core/plugins/mcp/private-store.d.ts +15 -0
  48. package/dist/core/plugins/mcp/private-store.d.ts.map +1 -0
  49. package/dist/core/plugins/mcp/private-store.js +162 -0
  50. package/dist/core/plugins/mcp/private-store.js.map +1 -0
  51. package/dist/core/plugins/mcp/session-runtime.d.ts +25 -0
  52. package/dist/core/plugins/mcp/session-runtime.d.ts.map +1 -0
  53. package/dist/core/plugins/mcp/session-runtime.js +76 -0
  54. package/dist/core/plugins/mcp/session-runtime.js.map +1 -0
  55. package/dist/core/plugins/mcp/socket-auth.d.ts +9 -0
  56. package/dist/core/plugins/mcp/socket-auth.d.ts.map +1 -0
  57. package/dist/core/plugins/mcp/socket-auth.js +94 -0
  58. package/dist/core/plugins/mcp/socket-auth.js.map +1 -0
  59. package/dist/core/plugins/paths.d.ts +3 -0
  60. package/dist/core/plugins/paths.d.ts.map +1 -1
  61. package/dist/core/plugins/paths.js +9 -0
  62. package/dist/core/plugins/paths.js.map +1 -1
  63. package/dist/core/plugins/pm2.d.ts.map +1 -1
  64. package/dist/core/plugins/pm2.js +3 -1
  65. package/dist/core/plugins/pm2.js.map +1 -1
  66. package/dist/core/plugins/runtime.d.ts +2 -0
  67. package/dist/core/plugins/runtime.d.ts.map +1 -1
  68. package/dist/core/plugins/runtime.js.map +1 -1
  69. package/dist/core/plugins/service-manager.d.ts +22 -0
  70. package/dist/core/plugins/service-manager.d.ts.map +1 -1
  71. package/dist/core/plugins/service-manager.js +189 -52
  72. package/dist/core/plugins/service-manager.js.map +1 -1
  73. package/dist/core/plugins/types.d.ts +15 -1
  74. package/dist/core/plugins/types.d.ts.map +1 -1
  75. package/dist/core/restart-report.d.ts +1 -1
  76. package/dist/core/restart-report.d.ts.map +1 -1
  77. package/dist/core/restart-report.js +5 -3
  78. package/dist/core/restart-report.js.map +1 -1
  79. package/dist/core/scheduler.d.ts +47 -0
  80. package/dist/core/scheduler.d.ts.map +1 -1
  81. package/dist/core/scheduler.js +117 -0
  82. package/dist/core/scheduler.js.map +1 -1
  83. package/dist/core/session-manager.d.ts +7 -0
  84. package/dist/core/session-manager.d.ts.map +1 -1
  85. package/dist/core/session-manager.js +130 -33
  86. package/dist/core/session-manager.js.map +1 -1
  87. package/dist/core/silent-schedule-turns.d.ts +5 -0
  88. package/dist/core/silent-schedule-turns.d.ts.map +1 -0
  89. package/dist/core/silent-schedule-turns.js +47 -0
  90. package/dist/core/silent-schedule-turns.js.map +1 -0
  91. package/dist/core/types.d.ts +6 -0
  92. package/dist/core/types.d.ts.map +1 -1
  93. package/dist/core/types.js.map +1 -1
  94. package/dist/core/update-check.d.ts +16 -0
  95. package/dist/core/update-check.d.ts.map +1 -1
  96. package/dist/core/update-check.js +52 -0
  97. package/dist/core/update-check.js.map +1 -1
  98. package/dist/core/worker-pool.d.ts.map +1 -1
  99. package/dist/core/worker-pool.js +30 -23
  100. package/dist/core/worker-pool.js.map +1 -1
  101. package/dist/dashboard/schedule-card-model.d.ts +3 -0
  102. package/dist/dashboard/schedule-card-model.d.ts.map +1 -1
  103. package/dist/dashboard/schedule-card-model.js +5 -0
  104. package/dist/dashboard/schedule-card-model.js.map +1 -1
  105. package/dist/dashboard/web/app.d.ts.map +1 -1
  106. package/dist/dashboard/web/app.js +295 -6
  107. package/dist/dashboard/web/app.js.map +1 -1
  108. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  109. package/dist/dashboard/web/i18n.js +92 -0
  110. package/dist/dashboard/web/i18n.js.map +1 -1
  111. package/dist/dashboard/web/plugin-page.d.ts.map +1 -1
  112. package/dist/dashboard/web/plugin-page.js +1 -3
  113. package/dist/dashboard/web/plugin-page.js.map +1 -1
  114. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  115. package/dist/dashboard/web/schedules-page.js +111 -4
  116. package/dist/dashboard/web/schedules-page.js.map +1 -1
  117. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  118. package/dist/dashboard/web/settings-page.js +5 -1
  119. package/dist/dashboard/web/settings-page.js.map +1 -1
  120. package/dist/dashboard/web/update-action.d.ts +16 -0
  121. package/dist/dashboard/web/update-action.d.ts.map +1 -0
  122. package/dist/dashboard/web/update-action.js +64 -0
  123. package/dist/dashboard/web/update-action.js.map +1 -0
  124. package/dist/dashboard-web/app.js +1 -1
  125. package/dist/dashboard-web/chunks/{bot-defaults-page-KLDCZNLP.js → bot-defaults-page-4PM4T6QQ.js} +1 -1
  126. package/dist/dashboard-web/chunks/{chunk-FMJNOATE.js → chunk-3PMN55Z6.js} +1 -1
  127. package/dist/dashboard-web/chunks/{chunk-MLNI5BKE.js → chunk-AIDN2WZB.js} +1 -1
  128. package/dist/dashboard-web/chunks/{chunk-EZAW2EPM.js → chunk-IKCZ677K.js} +1 -1
  129. package/dist/dashboard-web/chunks/{chunk-KEAOTUL3.js → chunk-RXVA6XW3.js} +7 -7
  130. package/dist/dashboard-web/chunks/{connectors-page-O32LFAL5.js → connectors-page-2MKF4YTN.js} +1 -1
  131. package/dist/dashboard-web/chunks/{groups-page-PSAFIZ6M.js → groups-page-TAU2UIVS.js} +1 -1
  132. package/dist/dashboard-web/chunks/{insights-page-V23LLATX.js → insights-page-PJ2XVM6T.js} +1 -1
  133. package/dist/dashboard-web/chunks/{monitor-room-7X5AKYOF.js → monitor-room-D6445HJO.js} +1 -1
  134. package/dist/dashboard-web/chunks/{monitoring-page-CBA3CQYL.js → monitoring-page-GUHMCKSO.js} +1 -1
  135. package/dist/dashboard-web/chunks/{office-page-RL6QSEM7.js → office-page-6K6U2MS5.js} +1 -1
  136. package/dist/dashboard-web/chunks/{overview-page-XQIPO6KH.js → overview-page-USDYU7U5.js} +1 -1
  137. package/dist/dashboard-web/chunks/plugin-page-JXC5F5YV.js +1 -0
  138. package/dist/dashboard-web/chunks/{roles-page-ACIWV7QS.js → roles-page-O4OUA7ZH.js} +1 -1
  139. package/dist/dashboard-web/chunks/schedules-page-LNIBXJSZ.js +1 -0
  140. package/dist/dashboard-web/chunks/{sessions-page-2WDWHSP4.js → sessions-page-B6U6TCFF.js} +1 -1
  141. package/dist/dashboard-web/chunks/{settings-page-6VX4OUGG.js → settings-page-PXLRFF7I.js} +2 -2
  142. package/dist/dashboard-web/chunks/{skills-page-WXE3UYLT.js → skills-page-M5KYNXBA.js} +1 -1
  143. package/dist/dashboard-web/chunks/{team-federation-page-PYTF4FLM.js → team-federation-page-GT7UFQMN.js} +1 -1
  144. package/dist/dashboard-web/chunks/{v3-page-G6CD6O3I.js → v3-page-UYZIRJ2C.js} +1 -1
  145. package/dist/dashboard-web/chunks/{whiteboards-page-6SG33GP4.js → whiteboards-page-WAR77DQE.js} +1 -1
  146. package/dist/dashboard-web/style.css +697 -0
  147. package/dist/dashboard.js +404 -29
  148. package/dist/dashboard.js.map +1 -1
  149. package/dist/i18n/en.d.ts.map +1 -1
  150. package/dist/i18n/en.js +4 -0
  151. package/dist/i18n/en.js.map +1 -1
  152. package/dist/i18n/zh.d.ts.map +1 -1
  153. package/dist/i18n/zh.js +4 -0
  154. package/dist/i18n/zh.js.map +1 -1
  155. package/dist/im/lark/schedules-card.d.ts.map +1 -1
  156. package/dist/im/lark/schedules-card.js +2 -0
  157. package/dist/im/lark/schedules-card.js.map +1 -1
  158. package/dist/services/plugin-registry-store.d.ts.map +1 -1
  159. package/dist/services/plugin-registry-store.js +100 -18
  160. package/dist/services/plugin-registry-store.js.map +1 -1
  161. package/dist/services/restart-intent-store.d.ts +17 -2
  162. package/dist/services/restart-intent-store.d.ts.map +1 -1
  163. package/dist/services/restart-intent-store.js +110 -0
  164. package/dist/services/restart-intent-store.js.map +1 -1
  165. package/dist/services/schedule-store.d.ts +3 -1
  166. package/dist/services/schedule-store.d.ts.map +1 -1
  167. package/dist/services/schedule-store.js +5 -0
  168. package/dist/services/schedule-store.js.map +1 -1
  169. package/dist/skills/definitions.d.ts.map +1 -1
  170. package/dist/skills/definitions.js +3 -2
  171. package/dist/skills/definitions.js.map +1 -1
  172. package/dist/types.d.ts +16 -0
  173. package/dist/types.d.ts.map +1 -1
  174. package/dist/utils/child-env.d.ts +1 -1
  175. package/dist/utils/child-env.d.ts.map +1 -1
  176. package/dist/utils/child-env.js +5 -0
  177. package/dist/utils/child-env.js.map +1 -1
  178. package/dist/utils/global-install.d.ts +2 -0
  179. package/dist/utils/global-install.d.ts.map +1 -1
  180. package/dist/utils/global-install.js +14 -0
  181. package/dist/utils/global-install.js.map +1 -1
  182. package/dist/worker.js +125 -17
  183. package/dist/worker.js.map +1 -1
  184. package/dist/workflows/hostExecutors/botmux-schedule.d.ts +3 -0
  185. package/dist/workflows/hostExecutors/botmux-schedule.d.ts.map +1 -1
  186. package/dist/workflows/hostExecutors/botmux-schedule.js +9 -0
  187. package/dist/workflows/hostExecutors/botmux-schedule.js.map +1 -1
  188. package/package.json +1 -1
  189. package/dist/dashboard-web/chunks/plugin-page-7FW2LPJH.js +0 -1
  190. package/dist/dashboard-web/chunks/schedules-page-KJDUKOJV.js +0 -1
package/dist/cli.js CHANGED
@@ -53,7 +53,8 @@ import { isColdResumeDormant, sessionListDisposition } from './cli/session-list-
53
53
  import { dispatchPrimaryMessage, findStdinAliasAttachment, normalizeInteractiveCardInput, sendFileAttachments, sendVideoAttachments, shouldSendAsPureVideo, validateVideoAttachments } from './cli/send-dispatch.js';
54
54
  import { buildPm2SpawnCommand } from './cli/pm2-command.js';
55
55
  import { callDashboard } from './cli/dashboard-endpoint.js';
56
- import { installLatestBotmuxSync } from './core/maintenance.js';
56
+ import { globalInstallUpdateLockTargetIn, installLatestBotmuxSync } from './core/maintenance.js';
57
+ import { withFileLockSync } from './utils/file-lock.js';
57
58
  import { formatGlobalInstallCommand, resolveGlobalInstallPlan, UnsupportedGlobalInstallError, } from './utils/global-install.js';
58
59
  import { loadDashboardSecret } from './dashboard/auth.js';
59
60
  import { postWorkflowDaemonMutation, } from './workflows/v3/daemon-ipc-client.js';
@@ -68,7 +69,7 @@ import { chatAppLink, larkHosts, normalizeBrand, sdkDomain } from './im/lark/lar
68
69
  import { mergeDashboardConfig, mergeGlobalConfig, readGlobalConfig, setGlobalLocale, globalConfigPath } from './global-config.js';
69
70
  import { createWhiteboard, ensureDefaultWhiteboard, getWhiteboard, listWhiteboards, readWhiteboard, whiteboardEnabled, whiteboardPath, } from './services/whiteboard-store.js';
70
71
  import { buildBridgeSendMarkerContent } from './services/bridge-fallback-gate.js';
71
- import { writeManualIntentIfAbsentTo } from './services/restart-intent-store.js';
72
+ import { bindRestartLeaseTo, writeManualIntentIfAbsentTo } from './services/restart-intent-store.js';
72
73
  import { stripLegacyPendingCardFields } from './services/session-store.js';
73
74
  import { evaluateVcMeetingManagedSend, isTrustedVcMeetingHostRelayParent, resolveVcMeetingImTurnOrigin, } from './services/vc-meeting-send-policy.js';
74
75
  import { finishVcMeetingImReply, prepareVcMeetingDeliveryReply, prepareVcMeetingImReply, } from './services/vc-meeting-im-reply.js';
@@ -2303,6 +2304,20 @@ async function cmdStop() {
2303
2304
  console.log('daemon 未在运行。');
2304
2305
  }
2305
2306
  async function cmdRestart() {
2307
+ const restartLeaseId = process.env.BOTMUX_RESTART_LEASE_ID;
2308
+ const restartLeaseDir = process.env.BOTMUX_RESTART_LEASE_DIR;
2309
+ delete process.env.BOTMUX_RESTART_LEASE_ID;
2310
+ delete process.env.BOTMUX_RESTART_LEASE_DIR;
2311
+ if (restartLeaseId) {
2312
+ if (!restartLeaseDir)
2313
+ throw new Error('restart driver lease directory is missing');
2314
+ let bound = false;
2315
+ withFileLockSync(globalInstallUpdateLockTargetIn(restartLeaseDir), () => {
2316
+ bound = bindRestartLeaseTo(restartLeaseDir, restartLeaseId, process.pid, Date.now());
2317
+ });
2318
+ if (!bound)
2319
+ throw new Error('failed to bind restart driver lease');
2320
+ }
2306
2321
  if (!hasConfig()) {
2307
2322
  console.error('❌ 未找到配置文件');
2308
2323
  console.error(' 请先运行: botmux setup');
@@ -4210,6 +4225,7 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
4210
4225
  schedule list 列出所有任务
4211
4226
  schedule add <schedule> <prompt> 添加任务(ex: "30m" / "every 2h" / "每日9:00" / "0 9 * * *")
4212
4227
  --new-topic 每次触发在同群开一个新话题、起独立会话(不续旧话题)
4228
+ --silent 静默执行:不发「执行中」提示,模型判断是否 botmux send 报警(与 --new-topic 互斥)
4213
4229
  schedule remove <id> 删除任务
4214
4230
  schedule pause|resume <id> 暂停/恢复
4215
4231
  schedule run <id> 标记立即执行
@@ -4337,6 +4353,7 @@ function detectCurrentSession() {
4337
4353
  workingDir: s.workingDir,
4338
4354
  larkAppId: s.larkAppId,
4339
4355
  chatType: s.chatType,
4356
+ scope: s.scope,
4340
4357
  };
4341
4358
  }
4342
4359
  /** Pick a value from --flag <value> or --flag=value style args. */
@@ -4678,7 +4695,7 @@ async function cmdSchedule(sub, rest) {
4678
4695
  const prompt = t.prompt ?? '';
4679
4696
  const chatId = t.chatId ?? '—';
4680
4697
  const rootId = t.rootMessageId ?? '—';
4681
- console.log(`${status} [${t.id}] ${display} | ${t.name}`);
4698
+ console.log(`${status} [${t.id}] ${display} | ${t.name}${t.silent ? ' 🔇静默' : ''}`);
4682
4699
  console.log(` prompt: ${prompt.length > 60 ? prompt.slice(0, 60) + '…' : prompt}`);
4683
4700
  console.log(` chat: ${chatId.slice(0, 12)}… thread: ${rootId.slice(0, 16)}…`);
4684
4701
  console.log(` next: ${next} last: ${last}${t.lastStatus === 'error' ? ' ❌' : ''}`);
@@ -4687,9 +4704,9 @@ async function cmdSchedule(sub, rest) {
4687
4704
  return;
4688
4705
  }
4689
4706
  if (sub === 'add') {
4690
- const [rawSchedule, ...promptParts] = positionals(rest, ['--new-topic']);
4707
+ const [rawSchedule, ...promptParts] = positionals(rest, ['--new-topic', '--silent']);
4691
4708
  if (!rawSchedule) {
4692
- console.error('用法: botmux schedule add <schedule> <prompt> [--name NAME] [--chat-id CHAT] [--root-msg-id ROOT] [--lark-app-id APP] [--workdir DIR] [--new-topic]');
4709
+ console.error('用法: botmux schedule add <schedule> <prompt> [--name NAME] [--chat-id CHAT] [--root-msg-id ROOT] [--lark-app-id APP] [--workdir DIR] [--new-topic] [--silent]');
4693
4710
  process.exit(1);
4694
4711
  }
4695
4712
  // prompt may come from positional or --prompt flag
@@ -4708,6 +4725,13 @@ async function cmdSchedule(sub, rest) {
4708
4725
  const deliver = rest.includes('--new-topic')
4709
4726
  ? 'new-topic'
4710
4727
  : (argValue(rest, '--deliver') ?? 'origin');
4728
+ // --silent: fires post no "执行中" banner; the spawned turn stays quiet and
4729
+ // the model only `botmux send`s when the alert condition in the prompt is met.
4730
+ const silent = rest.includes('--silent');
4731
+ if (silent && deliver === 'new-topic') {
4732
+ console.error('--silent 与 --new-topic 不能同时使用:新话题必须由首条消息开启。要「有异常才开新话题」,请在 prompt 里指示模型报警时用 botmux send 顶层发送。');
4733
+ process.exit(1);
4734
+ }
4711
4735
  if (!chatId) {
4712
4736
  console.error('无法推断 chat-id。请加上 --chat-id <CHAT_ID>,或从 Lark 话题内的 CLI 会话中运行本命令。');
4713
4737
  process.exit(1);
@@ -4733,7 +4757,9 @@ async function cmdSchedule(sub, rest) {
4733
4757
  creatorRootMessageId: cur?.rootMessageId,
4734
4758
  creatorLarkAppId: cur?.larkAppId,
4735
4759
  chatType: cur?.chatType === 'p2p' ? 'p2p' : 'topic_group',
4760
+ scope: cur?.scope,
4736
4761
  deliver,
4762
+ silent,
4737
4763
  });
4738
4764
  const next = task.nextRunAt ? new Date(task.nextRunAt).toLocaleString('zh-CN', { timeZone: scheduleTimeZone() }) : '—';
4739
4765
  console.log(`✅ 已创建定时任务 [${task.id}] ${task.name}`);
@@ -4741,6 +4767,8 @@ async function cmdSchedule(sub, rest) {
4741
4767
  console.log(` 下次执行: ${next}`);
4742
4768
  console.log(` 工作目录: ${workingDir}`);
4743
4769
  console.log(` 话题: ${deliver === 'new-topic' ? '(每次新开话题,独立会话)' : rootMessageId ?? '(将新开)'}`);
4770
+ if (silent)
4771
+ console.log(' 静默: 触发时不发「执行中」提示,由模型判断是否需要 botmux send 报警');
4744
4772
  return;
4745
4773
  }
4746
4774
  const id = positionals(rest)[0];
@@ -8268,6 +8296,32 @@ function printPluginUsage() {
8268
8296
  botmux plugin service restart [plugin-id|--all]
8269
8297
  `);
8270
8298
  }
8299
+ function printPluginServiceRunningError(err) {
8300
+ if (!err || typeof err !== 'object' || err.code !== 'plugin_service_running')
8301
+ return false;
8302
+ const pluginId = String(err.pluginId ?? 'unknown');
8303
+ const operation = String(err.operation ?? 'update');
8304
+ const status = String(err.serviceStatus ?? 'unknown');
8305
+ const pid = typeof err.pid === 'number' ? `, PID ${err.pid}` : '';
8306
+ const operationLabel = operation === 'uninstall' ? '卸载' : operation === 'install' ? '安装' : '更新';
8307
+ console.error(`❌ 无法${operationLabel}插件 ${pluginId}:插件服务仍在运行(${status}${pid})。`);
8308
+ console.error(` 请先运行: botmux plugin service stop ${pluginId}`);
8309
+ console.error(' Botmux 不会在安装、更新或卸载时隐式停止插件服务。');
8310
+ return true;
8311
+ }
8312
+ function printPluginServiceDeleteError(err) {
8313
+ if (!err || typeof err !== 'object' || err.code !== 'plugin_service_delete_failed')
8314
+ return false;
8315
+ const failures = Array.isArray(err.failures) ? err.failures : [];
8316
+ const details = failures
8317
+ .map((failure) => `${String(failure.pluginId ?? 'unknown')}: ${String(failure.warning ?? 'PM2 删除失败')}`)
8318
+ .join('; ');
8319
+ console.error('❌ 插件服务的 PM2 记录删除失败,插件未卸载。');
8320
+ if (details)
8321
+ console.error(` ${details}`);
8322
+ console.error(' 请确认 PM2 可用后重新执行卸载;Botmux 未清理插件文件、配置或绑定。');
8323
+ return true;
8324
+ }
8271
8325
  async function cmdPlugin(args) {
8272
8326
  const sub = (args[0] ?? 'list').toLowerCase();
8273
8327
  if (sub === 'help' || sub === '--help' || sub === '-h') {
@@ -8283,7 +8337,17 @@ async function cmdPlugin(args) {
8283
8337
  const { installPlugin } = await import('./core/plugins/install.js');
8284
8338
  const { resolveOfficialPluginPackageSpec } = await import('./core/plugins/init.js');
8285
8339
  const resolvedSpec = resolveOfficialPluginPackageSpec(spec);
8286
- const result = installPlugin(resolvedSpec, { link: args.includes('--link') });
8340
+ let result;
8341
+ try {
8342
+ result = installPlugin(resolvedSpec, { link: args.includes('--link') });
8343
+ }
8344
+ catch (err) {
8345
+ if (printPluginServiceRunningError(err)) {
8346
+ process.exitCode = 1;
8347
+ return;
8348
+ }
8349
+ throw err;
8350
+ }
8287
8351
  const enabledPlugins = normalizePluginIdList(readGlobalConfig().plugins) ?? [];
8288
8352
  if (enabledPlugins.includes(result.record.id)) {
8289
8353
  const { materializePlugin } = await import('./core/plugins/materializer.js');
@@ -8381,27 +8445,54 @@ async function cmdPlugin(args) {
8381
8445
  if (sub === 'uninstall' || sub === 'remove' || sub === 'rm') {
8382
8446
  const pluginId = requirePluginId(args[1]);
8383
8447
  assertPluginInstalled(pluginId);
8384
- const enabledEverywhere = new Set(normalizePluginIdList(readGlobalConfig().plugins) ?? []);
8385
- for (const bot of loadBotsJson()) {
8386
- for (const id of normalizePluginIdList(bot.plugins) ?? [])
8387
- enabledEverywhere.add(id);
8388
- }
8389
- const dependents = enabledPluginDependents(pluginId, [...enabledEverywhere], registry);
8390
- if (dependents.length > 0) {
8391
- console.error(`❌ 不能卸载 ${pluginId},以下已启用插件依赖它: ${dependents.join(', ')}`);
8392
- console.error(' 请先在对应作用域显式禁用这些插件。');
8393
- process.exit(1);
8394
- }
8448
+ const { assertPluginServiceStopped, deletePluginServicesOrThrowUnlocked, withPluginServiceLock, } = await import('./core/plugins/service-manager.js');
8395
8449
  const { dematerializePlugin } = await import('./core/plugins/materializer.js');
8396
- const { deletePluginServices } = await import('./core/plugins/service-manager.js');
8397
- dematerializePlugin(pluginId);
8398
- await deletePluginServices([pluginId]);
8399
- await removePluginSkillRegistryEntries(pluginId);
8400
- const { removeInstalledPlugin } = await import('./services/plugin-registry-store.js');
8450
+ const { readPluginRegistry, removeInstalledPlugin } = await import('./services/plugin-registry-store.js');
8401
8451
  const { pluginHome } = await import('./core/plugins/paths.js');
8402
- removeInstalledPlugin(pluginId);
8403
- removePluginBindingsEverywhere(pluginId);
8404
- rmSync(pluginHome(pluginId), { recursive: true, force: true });
8452
+ try {
8453
+ await withPluginServiceLock(async () => {
8454
+ const lockedRegistry = readPluginRegistry();
8455
+ const installed = lockedRegistry.plugins[pluginId];
8456
+ if (!installed)
8457
+ throw new Error(`plugin_not_installed:${pluginId}`);
8458
+ const enabledEverywhere = new Set(normalizePluginIdList(readGlobalConfig().plugins) ?? []);
8459
+ for (const bot of loadBotsJson()) {
8460
+ for (const id of normalizePluginIdList(bot.plugins) ?? [])
8461
+ enabledEverywhere.add(id);
8462
+ }
8463
+ const dependents = enabledPluginDependents(pluginId, [...enabledEverywhere], lockedRegistry);
8464
+ if (dependents.length > 0) {
8465
+ throw new Error(`plugin_has_enabled_dependents:${pluginId}:${dependents.join(',')}`);
8466
+ }
8467
+ if (installed.manifest.service) {
8468
+ assertPluginServiceStopped(pluginId, 'uninstall');
8469
+ }
8470
+ await deletePluginServicesOrThrowUnlocked([pluginId]);
8471
+ dematerializePlugin(pluginId);
8472
+ await removePluginSkillRegistryEntries(pluginId);
8473
+ removeInstalledPlugin(pluginId);
8474
+ removePluginBindingsEverywhere(pluginId);
8475
+ rmSync(pluginHome(pluginId), { recursive: true, force: true });
8476
+ });
8477
+ }
8478
+ catch (err) {
8479
+ if (err instanceof Error && err.message.startsWith(`plugin_has_enabled_dependents:${pluginId}:`)) {
8480
+ const dependents = err.message.slice(`plugin_has_enabled_dependents:${pluginId}:`.length).split(',').filter(Boolean);
8481
+ console.error(`❌ 不能卸载 ${pluginId},以下已启用插件依赖它: ${dependents.join(', ')}`);
8482
+ console.error(' 请先在对应作用域显式禁用这些插件。');
8483
+ process.exitCode = 1;
8484
+ return;
8485
+ }
8486
+ if (printPluginServiceRunningError(err)) {
8487
+ process.exitCode = 1;
8488
+ return;
8489
+ }
8490
+ if (printPluginServiceDeleteError(err)) {
8491
+ process.exitCode = 1;
8492
+ return;
8493
+ }
8494
+ throw err;
8495
+ }
8405
8496
  console.log(`✅ 已卸载插件: ${pluginId}`);
8406
8497
  return;
8407
8498
  }
@@ -8579,6 +8670,7 @@ switch (command) {
8579
8670
  process.exitCode = 2;
8580
8671
  break;
8581
8672
  }
8673
+ process.env.SESSION_DATA_DIR ??= resolveDataDir();
8582
8674
  const { runMcpGateway } = await import('./core/plugins/mcp/gateway.js');
8583
8675
  await runMcpGateway();
8584
8676
  break;