@@ -933,50 +891,6 @@
};
return mapping[normalizedLevel] || '暂无样本';
},
- dispatchModeTagType(mode) {
- const normalizedMode = String(mode || '').toLowerCase();
- if (normalizedMode === 'sync') return 'success';
- if (normalizedMode === 'background') return 'warning';
- if (normalizedMode === 'mixed') return '';
- return 'info';
- },
- dispatchModeLabel(mode) {
- const normalizedMode = String(mode || '').toLowerCase();
- const mapping = {
- sync: '前台同步',
- background: '后台任务',
- mixed: '混合模式',
- non_message: '非消息插件',
- unknown: '未知'
- };
- return mapping[normalizedMode] || '未知';
- },
- buildDispatchSummaryBrief(plugin) {
- const dispatchSummary = (plugin && plugin.dispatch_summary) || {};
- const mode = String(dispatchSummary.mode || plugin.dispatch_mode || '').toLowerCase();
- const syncCount = Number(dispatchSummary.sync_command_count || 0);
- const backgroundCount = Number(dispatchSummary.background_command_count || 0);
- if (mode === 'mixed') {
- return `前台 ${syncCount} / 后台 ${backgroundCount}`;
- }
- if (mode === 'background') {
- return backgroundCount > 0 ? `后台命令 ${backgroundCount} 个` : '默认后台执行';
- }
- if (mode === 'sync') {
- return syncCount > 0 ? `前台命令 ${syncCount} 个` : '默认前台执行';
- }
- if (mode === 'non_message') {
- return '不参与消息链路';
- }
- return '暂未识别';
- },
- buildDispatchSummaryText(plugin) {
- const dispatchSummary = (plugin && plugin.dispatch_summary) || {};
- if (dispatchSummary.description) {
- return dispatchSummary.description;
- }
- return this.dispatchModeLabel(dispatchSummary.mode || plugin.dispatch_mode);
- },
governanceIssueSummary(plugin) {
const errorCount = Number((plugin && plugin.governance_error_count) || 0);
const warningCount = Number((plugin && plugin.governance_warning_count) || 0);
diff --git a/base/plugin_common/plugin_manager.py b/base/plugin_common/plugin_manager.py
index d28411a..37e1f65 100644
--- a/base/plugin_common/plugin_manager.py
+++ b/base/plugin_common/plugin_manager.py
@@ -445,162 +445,6 @@ class PluginManager:
return [commands.strip()]
return []
- @staticmethod
- def _dispatch_mode_label(mode: str) -> str:
- """把消息分发模式转换成后台可读中文。"""
- normalized_mode = str(mode or "").strip().lower()
- mapping = {
- "sync": "前台同步",
- "background": "后台任务",
- "mixed": "混合模式",
- "non_message": "非消息插件",
- "unknown": "未知",
- }
- return mapping.get(normalized_mode, "未知")
-
- def _build_dispatch_preview_message(self, plugin: PluginInterface, command: str = "") -> Dict[str, Any]:
- """构造用于后台预览分发模式的假消息。
-
- 说明:
- 1. 后台只需要知道“这个插件命中后大概率走前台还是后台”,不需要真实微信上下文;
- 2. 因此这里构造一份最小可用消息,尽量覆盖多数插件 `get_message_dispatch_mode()` 的读取字段;
- 3. 如果某些插件依赖更复杂上下文,后续会在调用层捕获异常并回退为 `unknown`,不会影响治理页整体可用性。
- """
- command_text = str(command or "").strip()
- command_prefix = str(getattr(plugin, "command_prefix", "") or "").strip()
- content = command_text
- if command_text and command_prefix and not command_text.startswith(command_prefix):
- content = f"{command_prefix}{command_text}"
-
- return {
- "type": "dashboard_preview",
- "content": content,
- "sender": "dashboard_preview",
- "roomid": "dashboard_preview_room",
- "is_at": False,
- "timestamp": 0,
- "trace_id": "dashboard-preview",
- "all_contacts": {},
- "full_wx_msg": None,
- "gbm": None,
- "bot": None,
- "revoke": None,
- }
-
- def _preview_plugin_dispatch_mode(self, plugin: PluginInterface, preview_message: Dict[str, Any]) -> str:
- """安全预览插件在给定消息下的分发模式。"""
- try:
- raw_mode = plugin.get_message_dispatch_mode(preview_message)
- return MessagePluginInterface.normalize_message_dispatch_mode(raw_mode)
- except Exception as e:
- module_name = self._get_module_name_from_plugin(plugin) or getattr(plugin, "name", "unknown")
- self.LOG.debug(f"插件分发模式预览失败: module={module_name}, error={e}")
- return "unknown"
-
- def _build_plugin_dispatch_summary(
- self,
- plugin: PluginInterface,
- commands: Optional[List[str]] = None,
- ) -> Dict[str, Any]:
- """构建插件“前台 / 后台”执行方式摘要。
-
- 设计目标:
- 1. 后台插件治理页需要一眼看出消息插件是“前台同步”“后台任务”还是“按命令混合切换”;
- 2. 同一个插件里可能既有轻命令又有长命令,因此不能只看静态配置,还要做命令级预览;
- 3. 统一在快照层产出摘要后,列表、详情、移动端卡片都能直接复用,不必各写一套判断逻辑。
- """
- if not isinstance(plugin, MessagePluginInterface):
- return {
- "mode": "non_message",
- "label": self._dispatch_mode_label("non_message"),
- "description": "该插件不参与消息主链路分发,不区分前台同步或后台任务。",
- "is_message_plugin": False,
- "supports_dynamic_dispatch": False,
- "sync_command_count": 0,
- "background_command_count": 0,
- "unknown_command_count": 0,
- "preview_failed_count": 0,
- "sampled_command_count": 0,
- "command_modes": [],
- }
-
- commands = list(commands or self._collect_plugin_commands(plugin))
- preview_items: List[Tuple[str, Dict[str, Any]]] = []
- if commands:
- for command in commands:
- preview_items.append((command, self._build_dispatch_preview_message(plugin, command)))
- else:
- # 没有显式命令声明的消息插件,至少用一条空消息预览默认分发模式:
- # 1. 例如链接解析类插件可能靠正则命中,而不是 commands 数组;
- # 2. 这类插件通常不会做命令级动态切换,空消息预览已经足够判断默认模式;
- # 3. 后台仍会标记 sampled_command_count=0,避免用户误以为这里真的存在命令清单。
- preview_items.append(("", self._build_dispatch_preview_message(plugin, "")))
-
- mode_counters = {"sync": 0, "background": 0, "unknown": 0}
- command_modes = []
- for command, preview_message in preview_items:
- preview_mode = self._preview_plugin_dispatch_mode(plugin, preview_message)
- if preview_mode not in mode_counters:
- preview_mode = "unknown"
- mode_counters[preview_mode] += 1
-
- if command:
- command_modes.append(
- {
- "command": command,
- "mode": preview_mode,
- "label": self._dispatch_mode_label(preview_mode),
- }
- )
-
- known_modes = []
- if mode_counters["sync"] > 0:
- known_modes.append("sync")
- if mode_counters["background"] > 0:
- known_modes.append("background")
-
- if len(known_modes) > 1:
- summary_mode = "mixed"
- description = (
- f"插件会按命令动态切换执行链路:前台同步 {mode_counters['sync']} 个,"
- f"后台任务 {mode_counters['background']} 个。"
- )
- elif len(known_modes) == 1:
- summary_mode = known_modes[0]
- if known_modes[0] == "background":
- if commands:
- description = f"当前采样的 {len(commands)} 个命令均会转入后台任务池执行。"
- else:
- description = "该消息插件默认转入后台任务池执行。"
- else:
- if commands:
- description = f"当前采样的 {len(commands)} 个命令均在前台消息链路同步执行。"
- else:
- description = "该消息插件默认在前台消息链路同步执行。"
- else:
- summary_mode = "unknown"
- description = "插件已加载,但当前无法稳定预览其前台 / 后台执行方式。"
-
- if mode_counters["unknown"] > 0:
- description = (
- f"{description} 另有 {mode_counters['unknown']} 条预览样本无法识别,"
- "可能依赖更完整的运行时上下文。"
- )
-
- return {
- "mode": summary_mode,
- "label": self._dispatch_mode_label(summary_mode),
- "description": description,
- "is_message_plugin": True,
- "supports_dynamic_dispatch": summary_mode == "mixed",
- "sync_command_count": mode_counters["sync"],
- "background_command_count": mode_counters["background"],
- "unknown_command_count": mode_counters["unknown"],
- "preview_failed_count": mode_counters["unknown"],
- "sampled_command_count": len(commands),
- "command_modes": command_modes,
- }
-
def _build_governance_diagnostics(
self,
*,
@@ -862,7 +706,6 @@ class PluginManager:
config_path = plugin.get_config_path()
config_overview = self._read_plugin_config_overview(config_path)
commands = self._collect_plugin_commands(plugin)
- dispatch_summary = self._build_plugin_dispatch_summary(plugin, commands)
feature_key = str(getattr(plugin, "feature_key", "") or "").strip()
feature_description = str(getattr(plugin, "feature_description", "") or "").strip()
governance_diagnostics = self._build_governance_diagnostics(
@@ -886,8 +729,6 @@ class PluginManager:
"commands": commands,
"command_count": len(commands),
"command_prefix": getattr(plugin, "command_prefix", ""),
- "dispatch_mode": dispatch_summary["mode"],
- "dispatch_summary": dispatch_summary,
"dependencies": list(getattr(plugin, "dependencies", []) or []),
"feature_key": feature_key,
"feature_description": feature_description,
@@ -929,19 +770,6 @@ class PluginManager:
status = "ERROR"
elif runtime_state == "disabled_by_config":
status = "STOPPED"
- dispatch_summary = {
- "mode": "unknown",
- "label": self._dispatch_mode_label("unknown"),
- "description": "插件未成功加载,暂时无法判断其前台 / 后台执行方式。",
- "is_message_plugin": False,
- "supports_dynamic_dispatch": False,
- "sync_command_count": 0,
- "background_command_count": 0,
- "unknown_command_count": 0,
- "preview_failed_count": 0,
- "sampled_command_count": 0,
- "command_modes": [],
- }
return {
"name": module_name,
@@ -955,8 +783,6 @@ class PluginManager:
"commands": [],
"command_count": 0,
"command_prefix": "",
- "dispatch_mode": dispatch_summary["mode"],
- "dispatch_summary": dispatch_summary,
"dependencies": [],
"feature_key": "",
"feature_description": "",
@@ -1103,10 +929,10 @@ class PluginManager:
if not target_name:
return None
- # 详情页也统一走“完整治理快照列表”:
- # 1. 列表页已经会补齐依赖关系、执行摘要、分发模式等增强字段;
- # 2. 如果详情页单独重建快照,容易出现“列表里有,详情里没有”的字段不一致;
- # 3. 这里直接复用同一套结果,保证前后端看到的是同一份治理视图。
+ display_name, plugin = self.find_plugin_by_name(target_name)
+ if plugin:
+ return self._build_plugin_snapshot(plugin)
+
for snapshot in self.get_plugin_snapshots():
if snapshot.get("module_name") == target_name or snapshot.get("name") == target_name:
return snapshot