ErisPulse-HelpModule 2.0.0__tar.gz → 2.1.1__tar.gz

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.
@@ -0,0 +1,171 @@
1
+ from typing import Dict, List, Optional
2
+
3
+ from ErisPulse import sdk
4
+ from ErisPulse.Core import config
5
+ from ErisPulse.Core.Bases import BaseModule
6
+ from ErisPulse.Core.Event import command
7
+
8
+ from .templates import HelpTemplates
9
+
10
+
11
+ class HelpModule(BaseModule):
12
+ def __init__(self):
13
+ self.sdk = sdk
14
+ self.logger = sdk.logger.get_child("HelpModule")
15
+ self.command_list = []
16
+ self.command_map = {}
17
+
18
+ @staticmethod
19
+ def should_eager_load():
20
+ return True
21
+
22
+ async def on_load(self, event):
23
+ self._register_commands()
24
+ self.logger.info("HelpModule 已加载")
25
+ return True
26
+
27
+ async def on_unload(self, event):
28
+ self._unregister_commands()
29
+ self.logger.info("HelpModule 已卸载")
30
+ return True
31
+
32
+ def _get_config(self):
33
+ module_config = config.getConfig("HelpModule")
34
+ if not module_config:
35
+ default_config = {"show_hidden_commands": False, "group_commands": True}
36
+ config.setConfig("HelpModule", default_config)
37
+ self.logger.warning("未找到HelpModule配置,已创建默认配置")
38
+ return default_config
39
+ return module_config
40
+
41
+ def _get_command_prefix(self) -> str:
42
+ event_config = config.getConfig("ErisPulse.event", {})
43
+ command_config = event_config.get("command", {})
44
+ return command_config.get("prefix", "/")
45
+
46
+ def _register_commands(self):
47
+ self.help_command_func = self._create_help_command()
48
+ command(
49
+ "help",
50
+ aliases=["h", "帮助"],
51
+ help="显示帮助信息",
52
+ usage="help [序号] - 显示命令列表或查看指定序号的命令详情",
53
+ )(self.help_command_func)
54
+
55
+ def _unregister_commands(self):
56
+ if hasattr(self, "help_command_func"):
57
+ command.unregister(self.help_command_func)
58
+
59
+ def _create_help_command(self):
60
+ async def help_command(event):
61
+ await self._handle_help_command(event)
62
+
63
+ return help_command
64
+
65
+ def _build_command_list(self) -> List[Dict]:
66
+ self.command_list = []
67
+ module_config = self._get_config()
68
+ show_hidden = module_config.get("show_hidden_commands", False)
69
+
70
+ if show_hidden:
71
+ all_commands = command.get_commands()
72
+ for cmd_name in all_commands:
73
+ cmd_info = command.get_command(cmd_name)
74
+ if cmd_info and cmd_name == cmd_info.get("main_name"):
75
+ self.command_list.append({"name": cmd_name, "info": cmd_info})
76
+ else:
77
+ visible_commands = command.get_visible_commands()
78
+ for cmd_name in visible_commands:
79
+ cmd_info = command.get_command(cmd_name)
80
+ if cmd_info and cmd_name == cmd_info.get("main_name"):
81
+ self.command_list.append({"name": cmd_name, "info": cmd_info})
82
+
83
+ return self.command_list
84
+
85
+ def _group_commands_by_category(self, commands: List[Dict]) -> Dict[str, List]:
86
+ grouped = {}
87
+ for cmd in commands:
88
+ group = cmd["info"].get("group") or "default"
89
+ if group not in grouped:
90
+ grouped[group] = []
91
+ grouped[group].append(cmd)
92
+ return grouped
93
+
94
+ async def _handle_help_command(self, event) -> None:
95
+ try:
96
+ platform = event.get_platform()
97
+ args = event.get_command_args()
98
+
99
+ commands = self._build_command_list()
100
+ module_config = self._get_config()
101
+
102
+ if args:
103
+ # 显示命令详情
104
+ try:
105
+ index = int(args[0])
106
+ if index in self.command_map:
107
+ # 使用模板构建命令详情
108
+ templates = HelpTemplates.build_command_detail(
109
+ self.command_map[index], self._get_command_prefix()
110
+ )
111
+ else:
112
+ # 使用错误模板
113
+ templates = HelpTemplates.build_error(
114
+ "序号超出范围", f"请输入 1-{len(commands)} 之间的序号"
115
+ )
116
+ except ValueError:
117
+ templates = HelpTemplates.build_error(
118
+ "参数错误", "请输入有效的序号"
119
+ )
120
+ else:
121
+ # 显示命令列表
122
+ templates = HelpTemplates.build_help_list(
123
+ commands,
124
+ self.command_map,
125
+ self._get_command_prefix(),
126
+ module_config.get("group_commands", True),
127
+ )
128
+
129
+ # 根据平台能力选择最佳格式,通过 event.reply 发送
130
+ # event.reply 内部自动解析会话类型(含 channel/guild/thread 等)
131
+ format_name, content = self._select_best_format(platform, templates)
132
+ await event.reply(content, method=format_name)
133
+ except Exception as e:
134
+ self.logger.error(f"处理帮助命令时出错: {e}", exc_info=True)
135
+
136
+ def _select_best_format(self, platform: str, templates: Dict[str, str]) -> tuple:
137
+ """
138
+ 根据平台支持的发送方法选择最佳格式
139
+ 优先使用 list_sends,不支持时使用 hasattr 兜底
140
+
141
+ 返回: (format_name, content)
142
+ """
143
+ # 首先尝试使用 list_sends(推荐方式)
144
+ try:
145
+ supported_methods = sdk.adapter.list_sends(platform)
146
+
147
+ # 优先级: Html > Markdown > Text
148
+ if "Html" in supported_methods:
149
+ return ("Html", templates["html"])
150
+ elif "Markdown" in supported_methods:
151
+ return ("Markdown", templates["markdown"])
152
+ else:
153
+ return ("Text", templates["text"])
154
+ except Exception as e:
155
+ self.logger.warning(f"list_sends 检测失败: {e},尝试使用 hasattr 兜底")
156
+
157
+ # 使用 hasattr 作为兜底方案
158
+ adapter = getattr(sdk.adapter, platform)
159
+ send_obj = adapter.Send if hasattr(adapter, "Send") else None
160
+
161
+ if send_obj is None:
162
+ self.logger.warning(f"平台 {platform} 不支持 Send 接口,使用纯文本格式")
163
+ return ("Text", templates["text"])
164
+
165
+ # 检查支持的方法
166
+ if hasattr(send_obj, "Html"):
167
+ return ("Html", templates["html"])
168
+ elif hasattr(send_obj, "Markdown"):
169
+ return ("Markdown", templates["markdown"])
170
+ else:
171
+ return ("Text", templates["text"])
@@ -0,0 +1,460 @@
1
+ """
2
+ 帮助模块模板系统
3
+ 提供多平台支持的消息模板
4
+ """
5
+ from typing import Dict, List, Optional
6
+ from ErisPulse.Core.Event import command
7
+
8
+
9
+ class HelpTemplates:
10
+ """帮助模块模板类"""
11
+
12
+ # 配色方案
13
+ PRIMARY_COLOR = "#1565c0" # 蓝色 - 主标题
14
+ SUCCESS_COLOR = "#2e7d32" # 绿色 - 成功信息
15
+ WARNING_COLOR = "#e65100" # 橙色 - 警告信息
16
+ ERROR_COLOR = "#b71c1c" # 红色 - 错误信息
17
+
18
+ # 半透明背景色
19
+ PRIMARY_BG = "rgba(21, 101, 192, 0.05)"
20
+ SUCCESS_BG = "rgba(76, 175, 80, 0.1)"
21
+ WARNING_BG = "rgba(255, 167, 38, 0.15)"
22
+ ERROR_BG = "rgba(183, 28, 28, 0.1)"
23
+
24
+ @classmethod
25
+ def _get_group_name(cls, group: str) -> str:
26
+ if group == "default":
27
+ return "通用命令"
28
+ return f"{group}命令" if group else "其他"
29
+
30
+ # ==================== 帮助列表模板 ====================
31
+
32
+ @classmethod
33
+ def build_help_list(cls, commands: List[Dict], command_map: Dict[int, Dict],
34
+ prefix: str, group_commands: bool = True) -> Dict[str, str]:
35
+ # 构建 HTML
36
+ html = cls._build_help_list_html(commands, command_map, prefix, group_commands)
37
+
38
+ # 构建 Markdown
39
+ markdown = cls._build_help_list_markdown(commands, command_map, prefix, group_commands)
40
+
41
+ # 构建 Text
42
+ text = cls._build_help_list_text(commands, command_map, prefix, group_commands)
43
+
44
+ return {"html": html, "markdown": markdown, "text": text}
45
+
46
+ @classmethod
47
+ def _build_help_list_html(cls, commands: List[Dict], command_map: Dict[int, Dict],
48
+ prefix: str, group_commands: bool) -> str:
49
+ # 重置命令映射
50
+ grouped = {}
51
+ if group_commands:
52
+ for cmd in commands:
53
+ group = cmd["info"].get("group") or "default"
54
+ if group not in grouped:
55
+ grouped[group] = []
56
+ grouped[group].append(cmd)
57
+ else:
58
+ grouped["default"] = commands
59
+
60
+ # 构建命令列表 HTML(带展开/折叠功能)
61
+ commands_html = ""
62
+ global_idx = 1
63
+
64
+ for group, cmds in grouped.items():
65
+ group_name = cls._get_group_name(group)
66
+
67
+ commands_html += f"""
68
+ <div style="font-size:13px; margin-bottom: 8px; font-weight: bold; color: {cls.PRIMARY_COLOR};">{group_name}</div>
69
+ """
70
+
71
+ for cmd in cmds:
72
+ name = cmd["name"]
73
+ info = cmd["info"]
74
+ help_text = info.get("help", "暂无描述")
75
+ command_map[global_idx] = cmd
76
+
77
+ # 构建命令详情内容
78
+ detail_content = cls._build_command_detail_inline(name, info, prefix)
79
+
80
+ commands_html += f"""<details style="margin-bottom: 8px;">
81
+ <summary style="cursor: pointer; font-size: 13px; padding: 4px; background: rgba(0, 0, 0, 0.02); border-radius: 4px; display: flex; align-items: center;">
82
+ <span style="font-weight: bold; margin-right: 8px;">{global_idx}.</span>
83
+ <code style="background: rgba(0, 0, 0, 0.05); padding: 2px 6px; border-radius: 3px; margin-right: 8px;">{prefix}{name}</code>
84
+ <span style="color: #666;">- {help_text}</span>
85
+ </summary>
86
+ <div style="padding: 8px; margin-top: 6px; border-left: 3px solid {cls.PRIMARY_BG}; background: rgba(0, 0, 0, 0.01); border-radius: 4px;">
87
+ {detail_content}
88
+ </div>
89
+ </details>"""
90
+ global_idx +=1
91
+
92
+ commands_html += "\n"
93
+
94
+ # 构建完整 HTML
95
+ html = f"""<div style="padding: 12px; border-radius: 8px;">
96
+ <div style="color: {cls.PRIMARY_COLOR}; font-size: 16px; font-weight: bold; margin-bottom: 12px;">
97
+ 命令帮助
98
+ </div>
99
+
100
+ <div style="padding: 8px; background: {cls.PRIMARY_BG}; border-radius: 6px; margin-bottom: 12px;">
101
+ <div style="font-size: 13px;">
102
+ 使用 '{prefix}help <序号>' 查看命令详情
103
+ </div>
104
+ </div>
105
+
106
+ {commands_html}
107
+
108
+ <div style="font-size: 12px; color: #666; margin-top: 8px;">
109
+ 共 {len(commands)} 个可用命令
110
+ </div>
111
+ </div>"""
112
+
113
+ return html
114
+
115
+ @classmethod
116
+ def _build_help_list_markdown(cls, commands: List[Dict], command_map: Dict[int, Dict],
117
+ prefix: str, group_commands: bool) -> str:
118
+ lines = [
119
+ "**命令帮助**",
120
+ "",
121
+ f"使用 `{prefix}help <序号>` 查看命令详情",
122
+ ""
123
+ ]
124
+
125
+ global_idx = 1
126
+
127
+ if group_commands:
128
+ grouped = {}
129
+ for cmd in commands:
130
+ group = cmd["info"].get("group") or "default"
131
+ if group not in grouped:
132
+ grouped[group] = []
133
+ grouped[group].append(cmd)
134
+
135
+ for group, cmds in grouped.items():
136
+ group_name = cls._get_group_name(group)
137
+ lines.append(f"**{group_name}**")
138
+ lines.append("")
139
+
140
+ for cmd in cmds:
141
+ name = cmd["name"]
142
+ help_text = cmd["info"].get("help", "暂无描述")
143
+ command_map[global_idx] = cmd
144
+ lines.append(f"{global_idx}. `{prefix}{name}` - {help_text}")
145
+ global_idx += 1
146
+
147
+ lines.append("")
148
+ else:
149
+ lines.append("**所有命令**")
150
+ lines.append("")
151
+ for cmd in commands:
152
+ name = cmd["name"]
153
+ help_text = cmd["info"].get("help", "暂无描述")
154
+ command_map[global_idx] = cmd
155
+ lines.append(f"{global_idx}. `{prefix}{name}` - {help_text}")
156
+ global_idx += 1
157
+ lines.append("")
158
+
159
+ lines.append("---")
160
+ lines.append(f"共 {len(commands)} 个可用命令")
161
+
162
+ return "\n".join(lines)
163
+
164
+ @classmethod
165
+ def _build_help_list_text(cls, commands: List[Dict], command_map: Dict[int, Dict],
166
+ prefix: str, group_commands: bool) -> str:
167
+ lines = [
168
+ "命令帮助",
169
+ "----------",
170
+ f"使用 '{prefix}help <序号>' 查看命令详情",
171
+ ""
172
+ ]
173
+
174
+ global_idx = 1
175
+
176
+ if group_commands:
177
+ grouped = {}
178
+ for cmd in commands:
179
+ group = cmd["info"].get("group") or "default"
180
+ if group not in grouped:
181
+ grouped[group] = []
182
+ grouped[group].append(cmd)
183
+
184
+ for group, cmds in grouped.items():
185
+ group_name = cls._get_group_name(group)
186
+ lines.append(f"[{group_name}]")
187
+ lines.append("")
188
+
189
+ for cmd in cmds:
190
+ name = cmd["name"]
191
+ help_text = cmd["info"].get("help", "暂无描述")
192
+ command_map[global_idx] = cmd
193
+ lines.append(f"{global_idx}. {prefix}{name} - {help_text}")
194
+ global_idx += 1
195
+
196
+ lines.append("")
197
+ else:
198
+ lines.append("[所有命令]")
199
+ lines.append("")
200
+ for cmd in commands:
201
+ name = cmd["name"]
202
+ help_text = cmd["info"].get("help", "暂无描述")
203
+ command_map[global_idx] = cmd
204
+ lines.append(f"{global_idx}. {prefix}{name} - {help_text}")
205
+ global_idx += 1
206
+ lines.append("")
207
+
208
+ lines.append("----------")
209
+ lines.append(f"共 {len(commands)} 个可用命令")
210
+
211
+ return "\n".join(lines)
212
+
213
+ @classmethod
214
+ def _build_command_detail_inline(cls, name: str, info: Dict, prefix: str) -> str:
215
+ """
216
+ 构建内联命令详情(用于展开区域)
217
+ """
218
+ parts = []
219
+
220
+ # 描述
221
+ parts.append(f"""<div style="margin-bottom: 8px;">
222
+ <strong style="font-size: 12px; color: {cls.PRIMARY_COLOR};">描述:</strong>
223
+ <span style="font-size: 12px; margin-left: 8px;">{info.get('help', '暂无描述')}</span>
224
+ </div>""")
225
+
226
+ # 别名 - 从全局 command.aliases 获取
227
+ main_name = info.get('main_name', name)
228
+ aliases = []
229
+ for alias, mapped_name in command.aliases.items():
230
+ if mapped_name == main_name and alias != main_name:
231
+ aliases.append(alias)
232
+
233
+ if aliases:
234
+ aliases_text = ", ".join(f"<code style='font-size: 11px;'>{prefix}{a}</code>" for a in aliases)
235
+ parts.append(f"""<div style="margin-bottom: 8px;">
236
+ <strong style="font-size: 12px; color: {cls.PRIMARY_COLOR};">别名:</strong>
237
+ <span style="font-size: 12px; margin-left: 8px;">{aliases_text}</span>
238
+ </div>""")
239
+
240
+ # 用法
241
+ if info.get("usage"):
242
+ parts.append(f"""<div style="margin-bottom: 8px;">
243
+ <strong style="font-size: 12px; color: {cls.PRIMARY_COLOR};">用法:</strong>
244
+ <span style="font-size: 12px; margin-left: 8px; font-family: monospace; background: rgba(0, 0, 0, 0.03); padding: 2px 6px; border-radius: 3px;">{info['usage'].replace('/', prefix)}</span>
245
+ </div>""")
246
+
247
+ # 权限
248
+ if info.get("permission"):
249
+ parts.append(f"""<div style="margin-bottom: 8px;">
250
+ <strong style="font-size: 12px; color: {cls.PRIMARY_COLOR};">权限:</strong>
251
+ <span style="font-size: 12px; margin-left: 8px; color: {cls.WARNING_COLOR};">需要特殊权限</span>
252
+ </div>""")
253
+
254
+ # 分组
255
+ if info.get("group"):
256
+ group_name = cls._get_group_name(info["group"])
257
+ parts.append(f"""<div style="margin-bottom: 8px;">
258
+ <strong style="font-size: 12px; color: {cls.PRIMARY_COLOR};">分组:</strong>
259
+ <span style="font-size: 12px; margin-left: 8px;">{group_name}</span>
260
+ </div>""")
261
+
262
+ return "\n".join(parts)
263
+
264
+ # ==================== 命令详情模板 ====================
265
+
266
+ @classmethod
267
+ def build_command_detail(cls, cmd: Dict, prefix: str) -> Dict[str, str]:
268
+ # 构建 HTML
269
+ html = cls._build_command_detail_html(cmd, prefix)
270
+
271
+ # 构建 Markdown
272
+ markdown = cls._build_command_detail_markdown(cmd, prefix)
273
+
274
+ # 构建 Text
275
+ text = cls._build_command_detail_text(cmd, prefix)
276
+
277
+ return {"html": html, "markdown": markdown, "text": text}
278
+
279
+ @classmethod
280
+ def _build_command_detail_html(cls, cmd: Dict, prefix: str) -> str:
281
+ name = cmd["name"]
282
+ info = cmd["info"]
283
+
284
+ html_parts = [
285
+ f"""<div style="padding: 12px; border-radius: 8px;">
286
+ <div style="color: {cls.PRIMARY_COLOR}; font-size: 16px; font-weight: bold; margin-bottom: 12px;">
287
+ 命令详情: {prefix}{name}
288
+ </div>"""
289
+ ]
290
+
291
+ # 描述
292
+ html_parts.append(f"""
293
+ <div style="margin-bottom: 12px; border: 1px solid #e0e0e0; padding: 12px; border-radius: 6px;">
294
+ <div style="margin-bottom: 8px;">
295
+ <strong style="font-size: 14px;">描述:</strong>
296
+ </div>
297
+ <div style="font-size: 13px;">
298
+ {info.get('help', '暂无描述')}
299
+ </div>
300
+ </div>""")
301
+
302
+ # 别名 - 从全局 command.aliases 获取
303
+ main_name = info.get('main_name', name)
304
+ aliases = []
305
+ for alias, mapped_name in command.aliases.items():
306
+ if mapped_name == main_name and alias != main_name:
307
+ aliases.append(alias)
308
+
309
+ if aliases:
310
+ aliases_text = ", ".join(f"{prefix}{a}" for a in aliases)
311
+ html_parts.append(f"""
312
+ <div style="margin-bottom: 8px;">
313
+ <div style="font-size: 13px; margin-bottom: 4px;">
314
+ <strong>别名:</strong>
315
+ </div>
316
+ <div style="font-size: 13px;">
317
+ {aliases_text}
318
+ </div>
319
+ </div>""")
320
+
321
+ # 用法
322
+ if info.get("usage"):
323
+ html_parts.append(f"""
324
+ <div style="margin-bottom: 8px;">
325
+ <div style="font-size: 13px; margin-bottom: 4px;">
326
+ <strong>用法:</strong>
327
+ </div>
328
+ <div style="font-size: 13px; font-family: monospace; background: rgba(0, 0, 0, 0.03); padding: 6px; border-radius: 4px;">
329
+ {info['usage'].replace('/', prefix)}
330
+ </div>
331
+ </div>""")
332
+
333
+ # 权限
334
+ if info.get("permission"):
335
+ html_parts.append(f"""
336
+ <div style="margin-bottom: 8px;">
337
+ <div style="font-size: 13px; margin-bottom: 4px;">
338
+ <strong>权限:</strong>
339
+ </div>
340
+ <div style="font-size: 13px; color: {cls.WARNING_COLOR};">
341
+ 需要特殊权限
342
+ </div>
343
+ </div>""")
344
+
345
+ # 分组
346
+ if info.get("group"):
347
+ group_name = cls._get_group_name(info["group"])
348
+ html_parts.append(f"""
349
+ <div style="margin-bottom: 8px;">
350
+ <div style="font-size: 13px; margin-bottom: 4px;">
351
+ <strong>分组:</strong>
352
+ </div>
353
+ <div style="font-size: 13px;">
354
+ {group_name}
355
+ </div>
356
+ </div>""")
357
+
358
+ html_parts.append("</div>")
359
+
360
+ return "\n".join(html_parts)
361
+
362
+ @classmethod
363
+ def _build_command_detail_markdown(cls, cmd: Dict, prefix: str) -> str:
364
+ name = cmd["name"]
365
+ info = cmd["info"]
366
+
367
+ lines = [
368
+ f"**命令详情:** `{prefix}{name}`",
369
+ "",
370
+ f"**描述:** {info.get('help', '暂无描述')}",
371
+ ""
372
+ ]
373
+
374
+ # 别名 - 从全局 command.aliases 获取
375
+ main_name = info.get('main_name', name)
376
+ aliases = []
377
+ for alias, mapped_name in command.aliases.items():
378
+ if mapped_name == main_name and alias != main_name:
379
+ aliases.append(alias)
380
+
381
+ if aliases:
382
+ aliases_text = ", ".join(f"`{prefix}{a}`" for a in aliases)
383
+ lines.append(f"**别名:** {aliases_text}")
384
+ lines.append("")
385
+
386
+ # 用法
387
+ if info.get("usage"):
388
+ lines.append(f"**用法:** `{info['usage'].replace('/', prefix)}`")
389
+ lines.append("")
390
+
391
+ # 权限
392
+ if info.get("permission"):
393
+ lines.append("**权限:** 需要特殊权限")
394
+ lines.append("")
395
+
396
+ # 分组
397
+ if info.get("group"):
398
+ group_name = cls._get_group_name(info["group"])
399
+ lines.append(f"**分组:** {group_name}")
400
+ lines.append("")
401
+
402
+ return "\n".join(lines)
403
+
404
+ @classmethod
405
+ def _build_command_detail_text(cls, cmd: Dict, prefix: str) -> str:
406
+ name = cmd["name"]
407
+ info = cmd["info"]
408
+
409
+ lines = [
410
+ f"命令详情: {prefix}{name}",
411
+ "----------",
412
+ f"描述: {info.get('help', '暂无描述')}",
413
+ ""
414
+ ]
415
+
416
+ # 别名 - 从全局 command.aliases 获取
417
+ main_name = info.get('main_name', name)
418
+ aliases = []
419
+ for alias, mapped_name in command.aliases.items():
420
+ if mapped_name == main_name and alias != main_name:
421
+ aliases.append(alias)
422
+
423
+ if aliases:
424
+ aliases_text = ", ".join(f"{prefix}{a}" for a in aliases)
425
+ lines.append(f"别名: {aliases_text}")
426
+ lines.append("")
427
+
428
+ # 用法
429
+ if info.get("usage"):
430
+ lines.append(f"用法: {info['usage'].replace('/', prefix)}")
431
+ lines.append("")
432
+
433
+ # 权限
434
+ if info.get("permission"):
435
+ lines.append("权限: 需要特殊权限")
436
+ lines.append("")
437
+
438
+ # 分组
439
+ if info.get("group"):
440
+ group_name = cls._get_group_name(info["group"])
441
+ lines.append(f"分组: {group_name}")
442
+ lines.append("")
443
+
444
+ return "\n".join(lines)
445
+
446
+ # ==================== 错误消息模板 ====================
447
+
448
+ @classmethod
449
+ def build_error(cls, title: str, message: str) -> Dict[str, str]:
450
+ html = f"""
451
+ <div style="padding: 12px; border-radius: 8px;">
452
+ <div style="color: {cls.ERROR_COLOR}; font-size: 14px; font-weight: bold; margin-bottom: 8px;">{title}</div>
453
+ <div style="font-size: 13px;">{message}</div>
454
+ </div>"""
455
+
456
+ markdown = f"**{title}**\n\n{message}"
457
+
458
+ text = f"{title}\n\n{message}"
459
+
460
+ return {"html": html, "markdown": markdown, "text": text}
@@ -1,15 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse-HelpModule
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: ErisPulse 帮助命令模块,提供自动化的命令帮助系统,支持查看所有可用命令及其用法说明
5
5
  Author-email: wsu2059q <wsu2059@qq.com>
6
- License: Copyright 2025 wsu2059q
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
-
12
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6
+ License-Expression: MIT
13
7
  Project-URL: homepage, https://github.com/wsu2059q/ErisPulse-HelpModule
14
8
  Requires-Python: >=3.10
15
9
  Description-Content-Type: text/markdown
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  ErisPulse_HelpModule/Core.py
5
5
  ErisPulse_HelpModule/__init__.py
6
+ ErisPulse_HelpModule/templates.py
6
7
  ErisPulse_HelpModule.egg-info/PKG-INFO
7
8
  ErisPulse_HelpModule.egg-info/SOURCES.txt
8
9
  ErisPulse_HelpModule.egg-info/dependency_links.txt
@@ -1,15 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse-HelpModule
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: ErisPulse 帮助命令模块,提供自动化的命令帮助系统,支持查看所有可用命令及其用法说明
5
5
  Author-email: wsu2059q <wsu2059@qq.com>
6
- License: Copyright 2025 wsu2059q
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
-
12
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6
+ License-Expression: MIT
13
7
  Project-URL: homepage, https://github.com/wsu2059q/ErisPulse-HelpModule
14
8
  Requires-Python: >=3.10
15
9
  Description-Content-Type: text/markdown
@@ -1,10 +1,11 @@
1
1
  [project]
2
2
  name = "ErisPulse-HelpModule"
3
- version = "2.0.0"
3
+ version = "2.1.1"
4
4
  description = "ErisPulse 帮助命令模块,提供自动化的命令帮助系统,支持查看所有可用命令及其用法说明"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
- license = { file = "LICENSE" }
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
8
9
  authors = [ { name = "wsu2059q", email = "wsu2059@qq.com" } ]
9
10
 
10
11
  dependencies = [
@@ -15,3 +16,6 @@ dependencies = [
15
16
 
16
17
  [project.entry-points."erispulse.module"]
17
18
  "HelpModule" = "ErisPulse_HelpModule:HelpModule"
19
+
20
+ [tool.setuptools.packages.find]
21
+ include = ["ErisPulse_HelpModule*"]
@@ -1,213 +0,0 @@
1
- from ErisPulse import sdk
2
- from ErisPulse.Core.Event import command
3
- from ErisPulse.Core import config
4
- from ErisPulse.Core.Bases import BaseModule
5
- from typing import Dict, List
6
-
7
- class HelpModule(BaseModule):
8
- def __init__(self):
9
- self.sdk = sdk
10
- self.logger = sdk.logger.get_child("HelpModule")
11
- self.command_list = []
12
-
13
- @staticmethod
14
- def should_eager_load():
15
- return True
16
-
17
- async def on_load(self, event):
18
- self._register_commands()
19
- self.logger.info("HelpModule 已加载")
20
- return True
21
-
22
- async def on_unload(self, event):
23
- self._unregister_commands()
24
- self.logger.info("HelpModule 已卸载")
25
- return True
26
-
27
- def _get_config(self):
28
- module_config = config.getConfig("HelpModule")
29
- if not module_config:
30
- default_config = {
31
- "show_hidden_commands": False,
32
- "group_commands": True
33
- }
34
- config.setConfig("HelpModule", default_config)
35
- self.logger.warning("未找到HelpModule配置,已创建默认配置")
36
- return default_config
37
- return module_config
38
-
39
- def _get_command_prefix(self) -> str:
40
- event_config = config.getConfig("ErisPulse.event", {})
41
- command_config = event_config.get("command", {})
42
- return command_config.get("prefix", "/")
43
-
44
- def _register_commands(self):
45
- self.help_command_func = self._create_help_command()
46
- command(
47
- "help",
48
- aliases=["h", "帮助"],
49
- help="显示帮助信息",
50
- usage="help [序号] - 显示命令列表或查看指定序号的命令详情"
51
- )(self.help_command_func)
52
-
53
- def _unregister_commands(self):
54
- if hasattr(self, 'help_command_func'):
55
- command.unregister(self.help_command_func)
56
-
57
- def _create_help_command(self):
58
- async def help_command(event):
59
- await self._handle_help_command(event)
60
- return help_command
61
-
62
- def _build_command_list(self) -> List[Dict]:
63
- self.command_list = []
64
- module_config = self._get_config()
65
- show_hidden = module_config.get("show_hidden_commands", False)
66
-
67
- if show_hidden:
68
- all_commands = command.get_commands()
69
- for cmd_name in all_commands:
70
- cmd_info = command.get_command(cmd_name)
71
- if cmd_info and cmd_name == cmd_info.get("main_name"):
72
- self.command_list.append({
73
- "name": cmd_name,
74
- "info": cmd_info
75
- })
76
- else:
77
- visible_commands = command.get_visible_commands()
78
- for cmd_name in visible_commands:
79
- cmd_info = command.get_command(cmd_name)
80
- if cmd_info and cmd_name == cmd_info.get("main_name"):
81
- self.command_list.append({
82
- "name": cmd_name,
83
- "info": cmd_info
84
- })
85
-
86
- return self.command_list
87
-
88
- def _group_commands_by_category(self, commands: List[Dict]) -> Dict[str, List]:
89
- grouped = {}
90
- for cmd in commands:
91
- group = cmd["info"].get("group") or "default"
92
- if group not in grouped:
93
- grouped[group] = []
94
- grouped[group].append(cmd)
95
- return grouped
96
-
97
- async def _handle_help_command(self, event: Dict) -> None:
98
- try:
99
- platform = event["platform"]
100
- if event.get("detail_type") == "group":
101
- target_type = "group"
102
- target_id = event["group_id"]
103
- else:
104
- target_type = "user"
105
- target_id = event["user_id"]
106
-
107
- args = event.get("command", {}).get("args", [])
108
- adapter = getattr(sdk.adapter, platform)
109
-
110
- commands = self._build_command_list()
111
-
112
- if args:
113
- try:
114
- index = int(args[0]) - 1
115
- if 0 <= index < len(commands):
116
- help_text = self._format_command_detail(commands[index])
117
- else:
118
- help_text = f"错误: 序号超出范围,请输入 1-{len(commands)} 之间的序号"
119
- except ValueError:
120
- help_text = "错误: 请输入有效的序号"
121
- else:
122
- help_text = self._format_command_list(commands)
123
-
124
- await adapter.Send.To(target_type, target_id).Text(help_text)
125
- except Exception as e:
126
- self.logger.error(f"处理帮助命令时出错: {e}")
127
-
128
- def _format_command_list(self, commands: List[Dict]) -> str:
129
- prefix = self._get_command_prefix()
130
- module_config = self._get_config()
131
-
132
- lines = [
133
- "命令帮助",
134
- "-" * 10,
135
- f"使用 '{prefix}help <序号>' 查看命令详情",
136
- ""
137
- ]
138
-
139
- if module_config.get("group_commands", True):
140
- grouped = self._group_commands_by_category(commands)
141
-
142
- # 默认组
143
- if "default" in grouped:
144
- lines.append("[通用命令]")
145
- for idx, cmd in enumerate(grouped["default"], 1):
146
- name = cmd["name"]
147
- help_text = cmd["info"].get("help", "暂无描述")
148
- lines.append(f"{idx}. {prefix}{name} - {help_text}")
149
- lines.append("")
150
-
151
- # 其他组
152
- for group, cmds in grouped.items():
153
- if group == "default":
154
- continue
155
- group_name = str(group) if group else "其他"
156
- lines.append(f"[{group_name}命令]")
157
- for idx, cmd in enumerate(cmds, 1):
158
- name = cmd["name"]
159
- help_text = cmd["info"].get("help", "暂无描述")
160
- lines.append(f"{idx}. {prefix}{name} - {help_text}")
161
- lines.append("")
162
- else:
163
- lines.append("[所有命令]")
164
- for idx, cmd in enumerate(commands, 1):
165
- name = cmd["name"]
166
- help_text = cmd["info"].get("help", "暂无描述")
167
- lines.append(f"{idx}. {prefix}{name} - {help_text}")
168
- lines.append("")
169
-
170
- lines.append("-" * 10)
171
- lines.append(f"共 {len(commands)} 个可用命令")
172
-
173
- return "\n".join(lines)
174
-
175
- def _format_command_detail(self, cmd: Dict) -> str:
176
- prefix = self._get_command_prefix()
177
- name = cmd["name"]
178
- info = cmd["info"]
179
-
180
- lines = [
181
- f"命令详情: {prefix}{name}",
182
- "-" * 10,
183
- f"描述: {info.get('help', '暂无描述')}"
184
- ]
185
-
186
- # 别名
187
- aliases = []
188
- for alias, main_name in command.aliases.items():
189
- if main_name == info['main_name'] and alias != info['main_name']:
190
- aliases.append(alias)
191
-
192
- if aliases:
193
- lines.append(f"别名: {', '.join(f'{prefix}{a}' for a in aliases)}")
194
-
195
- # 用法
196
- if info.get("usage"):
197
- lines.append(f"用法: {info['usage'].replace('/', prefix)}")
198
-
199
- # 权限
200
- if info.get("permission"):
201
- lines.append("权限: 需要特殊权限")
202
-
203
- # 隐藏状态
204
- if info.get("hidden"):
205
- lines.append("状态: 隐藏命令")
206
-
207
- # 分组
208
- if info.get("group"):
209
- lines.append(f"分组: {info['group']}")
210
-
211
- lines.append("-" * 10)
212
-
213
- return "\n".join(lines)