ErisPulse 2.4.5.dev0__tar.gz → 2.4.5.dev2__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.
Files changed (118) hide show
  1. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/PKG-INFO +9 -1
  2. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/README.md +8 -0
  3. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/pyproject.toml +1 -1
  4. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/cli.py +4 -1
  5. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/cli.pyi +1 -1
  6. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/install.py +2 -10
  7. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/install.pyi +0 -1
  8. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/run.py +4 -0
  9. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/self_update.py +1 -6
  10. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/self_update.pyi +0 -1
  11. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/uninstall.py +1 -9
  12. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/uninstall.pyi +0 -1
  13. erispulse-2.4.5.dev2/src/ErisPulse/CLI/console.py +84 -0
  14. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/console.pyi +3 -0
  15. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/registry.py +1 -1
  16. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/adapter.py +18 -37
  17. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/logger.py +24 -8
  18. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/storage.py +1 -1
  19. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/module.py +6 -5
  20. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/sdk.py +49 -18
  21. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/sdk.pyi +1 -0
  22. erispulse-2.4.5.dev0/src/ErisPulse/CLI/console.py +0 -47
  23. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/.gitignore +0 -0
  24. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/LICENSE +0 -0
  25. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/__init__.py +0 -0
  26. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/__init__.pyi +0 -0
  27. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/base.py +0 -0
  28. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/base.pyi +0 -0
  29. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  30. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/__init__.pyi +0 -0
  31. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/init.py +0 -0
  32. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/init.pyi +0 -0
  33. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/list.py +0 -0
  34. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/list.pyi +0 -0
  35. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  36. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/list_remote.pyi +0 -0
  37. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/run.pyi +0 -0
  38. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  39. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/commands/upgrade.pyi +0 -0
  40. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/registry.pyi +0 -0
  41. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  42. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/utils/__init__.pyi +0 -0
  43. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/utils/package_manager.py +0 -0
  44. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/CLI/utils/package_manager.pyi +0 -0
  45. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/__init__.py +0 -0
  46. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/__init__.pyi +0 -0
  47. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/adapter.py +0 -0
  48. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/adapter.pyi +0 -0
  49. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/manager.py +0 -0
  50. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/manager.pyi +0 -0
  51. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/module.py +0 -0
  52. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/module.pyi +0 -0
  53. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/storage.py +0 -0
  54. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Bases/storage.pyi +0 -0
  55. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/__init__.py +0 -0
  56. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/__init__.pyi +0 -0
  57. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/base.py +0 -0
  58. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/base.pyi +0 -0
  59. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/command.py +0 -0
  60. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/command.pyi +0 -0
  61. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/message.py +0 -0
  62. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/message.pyi +0 -0
  63. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  64. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/message_builder.pyi +0 -0
  65. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/meta.py +0 -0
  66. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/meta.pyi +0 -0
  67. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/notice.py +0 -0
  68. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/notice.pyi +0 -0
  69. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/request.py +0 -0
  70. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/request.pyi +0 -0
  71. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/session_type.py +0 -0
  72. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/session_type.pyi +0 -0
  73. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/wrapper.py +0 -0
  74. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/Event/wrapper.pyi +0 -0
  75. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/__init__.py +0 -0
  76. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/__init__.pyi +0 -0
  77. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/adapter.pyi +0 -0
  78. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/config.py +0 -0
  79. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/config.pyi +0 -0
  80. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/lifecycle.py +0 -0
  81. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/lifecycle.pyi +0 -0
  82. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/logger.pyi +0 -0
  83. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/module.py +0 -0
  84. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/module.pyi +0 -0
  85. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/router.py +0 -0
  86. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/router.pyi +0 -0
  87. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/Core/storage.pyi +0 -0
  88. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/__init__.py +0 -0
  89. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/__init__.pyi +0 -0
  90. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/__main__.py +0 -0
  91. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/__main__.pyi +0 -0
  92. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/__init__.py +0 -0
  93. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/__init__.pyi +0 -0
  94. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/adapter.py +0 -0
  95. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/adapter.pyi +0 -0
  96. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/bases/__init__.py +0 -0
  97. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/bases/__init__.pyi +0 -0
  98. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/bases/finder.py +0 -0
  99. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/bases/finder.pyi +0 -0
  100. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/module.py +0 -0
  101. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/finders/module.pyi +0 -0
  102. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/__init__.py +0 -0
  103. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/__init__.pyi +0 -0
  104. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/adapter.py +0 -0
  105. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/adapter.pyi +0 -0
  106. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  107. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/bases/__init__.pyi +0 -0
  108. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/bases/loader.py +0 -0
  109. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/bases/loader.pyi +0 -0
  110. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/module.pyi +0 -0
  111. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/strategy.py +0 -0
  112. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/loaders/strategy.pyi +0 -0
  113. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/__init__.py +0 -0
  114. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/__init__.pyi +0 -0
  115. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/exceptions.py +0 -0
  116. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/exceptions.pyi +0 -0
  117. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/frame_config.py +0 -0
  118. {erispulse-2.4.5.dev0 → erispulse-2.4.5.dev2}/src/ErisPulse/runtime/frame_config.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 2.4.5.dev0
3
+ Version: 2.4.5.dev2
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: ErisDev <erisdev@88.com>
6
6
  Maintainer-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>
@@ -214,6 +214,14 @@ docker pull erispulse/erispulse:dev
214
214
 
215
215
  </details>
216
216
 
217
+ ### 1Panel 应用商店
218
+
219
+ 通过 [1Panel](https://1panel.cn) 应用商店一键安装 ErisPulse,详见 [ErisPulse-1Panel](https://github.com/ErisPulse/ErisPulse-1Panel)。
220
+
221
+ ```bash
222
+ bash <(curl -sL https://get-1panel.erisdev.com/install.sh)
223
+ ```
224
+
217
225
  ### 使用 pip 安装
218
226
 
219
227
  ```bash
@@ -142,6 +142,14 @@ docker pull erispulse/erispulse:dev
142
142
 
143
143
  </details>
144
144
 
145
+ ### 1Panel 应用商店
146
+
147
+ 通过 [1Panel](https://1panel.cn) 应用商店一键安装 ErisPulse,详见 [ErisPulse-1Panel](https://github.com/ErisPulse/ErisPulse-1Panel)。
148
+
149
+ ```bash
150
+ bash <(curl -sL https://get-1panel.erisdev.com/install.sh)
151
+ ```
152
+
145
153
  ### 使用 pip 安装
146
154
 
147
155
  ```bash
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.4.5-dev.0"
7
+ version = "2.4.5-dev.2"
8
8
  description = "ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -12,7 +12,7 @@ from argparse import ArgumentParser, RawDescriptionHelpFormatter
12
12
 
13
13
  from rich.panel import Panel
14
14
 
15
- from .console import console
15
+ from .console import console, print_banner
16
16
  from .registry import CommandRegistry
17
17
  from .base import Command
18
18
 
@@ -143,6 +143,8 @@ class CLI:
143
143
  args, unknown = self.parser.parse_known_args()
144
144
  args._unknown_args = unknown
145
145
 
146
+ print_banner()
147
+
146
148
  # 处理版本选项
147
149
  if args.version:
148
150
  self._print_version()
@@ -162,6 +164,7 @@ class CLI:
162
164
  # 执行命令
163
165
  command = self.registry.get(args.command)
164
166
  if command:
167
+ console.print(f"[title]{command.description}[/]")
165
168
  command.execute(args)
166
169
  else:
167
170
  console.print(f"[error]未知命令: {args.command}[/]")
@@ -16,7 +16,7 @@ import traceback
16
16
  import pkgutil
17
17
  from argparse import ArgumentParser, RawDescriptionHelpFormatter
18
18
  from rich.panel import Panel
19
- from .console import console
19
+ from .console import console, print_banner
20
20
  from .registry import CommandRegistry
21
21
  from .base import Command
22
22
 
@@ -8,7 +8,6 @@ import sys
8
8
  import asyncio
9
9
  from argparse import ArgumentParser
10
10
 
11
- from rich.panel import Panel
12
11
  from rich.prompt import Confirm, Prompt
13
12
  from rich.table import Table
14
13
  from rich.box import SIMPLE
@@ -249,13 +248,6 @@ class InstallCommand(Command):
249
248
  self._interactive_install(args.upgrade, args.pre)
250
249
 
251
250
  def _interactive_install(self, upgrade: bool = False, pre: bool = False):
252
- console.print(Panel(
253
- "[bold cyan]ErisPulse 安装组件[/]\n"
254
- "选择您要安装的组件类型",
255
- title="欢迎",
256
- border_style="cyan"
257
- ))
258
-
259
251
  with console.status("[bold green]正在获取远程包列表...", spinner="dots"):
260
252
  remote_packages = asyncio.run(self.package_manager.get_remote_packages())
261
253
  console.print("[success]✔ 远程包列表获取完成[/]\n")
@@ -297,7 +289,7 @@ class InstallCommand(Command):
297
289
  return
298
290
 
299
291
  table = Table(box=SIMPLE, header_style="adapter", show_lines=False)
300
- table.add_column("序号", style="cyan", width=4)
292
+ table.add_column("序号", style="#A0B0C0", width=4)
301
293
  table.add_column("适配器名", style="adapter")
302
294
  table.add_column("包名")
303
295
  table.add_column("描述")
@@ -352,7 +344,7 @@ class InstallCommand(Command):
352
344
  return
353
345
 
354
346
  table = Table(box=SIMPLE, header_style="module", show_lines=False)
355
- table.add_column("序号", style="cyan", width=4)
347
+ table.add_column("序号", style="#A0B0C0", width=4)
356
348
  table.add_column("模块名", style="module")
357
349
  table.add_column("包名")
358
350
  table.add_column("描述")
@@ -13,7 +13,6 @@ Install 命令实现
13
13
  import sys
14
14
  import asyncio
15
15
  from argparse import ArgumentParser
16
- from rich.panel import Panel
17
16
  from rich.prompt import Confirm, Prompt
18
17
  from rich.table import Table
19
18
  from rich.box import SIMPLE
@@ -101,6 +101,10 @@ class RunCommand(Command):
101
101
  console.print(f"[error]脚本 [path]{script}[/] 不存在[/]")
102
102
  console.print("[info]使用 [cyan]epsdk init[/cyan] 创建新项目[/]")
103
103
  return
104
+ if os.path.isdir(script):
105
+ console.print(f"[error][path]{script}[/] 是一个目录,无法直接运行[/]")
106
+ console.print("[info]请指定具体的脚本文件,例如: [cyan]epsdk run {0}/main.py[/]".format(script))
107
+ return
104
108
  self._run_script(script, reload_mode)
105
109
  else:
106
110
  self._run_internal(reload_mode)
@@ -8,7 +8,6 @@ import sys
8
8
  import asyncio
9
9
  from argparse import ArgumentParser
10
10
  from rich.prompt import Confirm, Prompt
11
- from rich.panel import Panel
12
11
 
13
12
  from ..utils import PackageManager
14
13
  from ..console import console
@@ -41,11 +40,7 @@ class SelfUpdateCommand(Command):
41
40
 
42
41
  def execute(self, args):
43
42
  current_version = self.package_manager.get_installed_version()
44
- console.print(Panel(
45
- f"[title]ErisPulse SDK 自更新[/]\n"
46
- f"当前版本: [bold]{current_version}[/]",
47
- title_align="left"
48
- ))
43
+ console.print(f"当前版本: [bold]{current_version}[/]")
49
44
 
50
45
  # 获取可用版本
51
46
  with console.status("[bold green]正在获取版本信息...", spinner="dots"):
@@ -14,7 +14,6 @@ import sys
14
14
  import asyncio
15
15
  from argparse import ArgumentParser
16
16
  from rich.prompt import Confirm, Prompt
17
- from rich.panel import Panel
18
17
  from ..utils import PackageManager
19
18
  from ..console import console
20
19
  from ..base import Command
@@ -7,7 +7,6 @@ Uninstall 命令实现
7
7
  import sys
8
8
  from argparse import ArgumentParser
9
9
 
10
- from rich.panel import Panel
11
10
  from rich.prompt import Prompt
12
11
  from rich.table import Table
13
12
  from rich.box import SIMPLE
@@ -43,13 +42,6 @@ class UninstallCommand(Command):
43
42
  self._interactive_uninstall()
44
43
 
45
44
  def _interactive_uninstall(self):
46
- console.print(Panel(
47
- "[bold cyan]ErisPulse 卸载向导[/]\n"
48
- "选择要卸载的包",
49
- title="卸载向导",
50
- border_style="cyan"
51
- ))
52
-
53
45
  # 获取已安装的包
54
46
  installed = self.package_manager.get_installed_packages()
55
47
 
@@ -80,7 +72,7 @@ class UninstallCommand(Command):
80
72
 
81
73
  # 显示包列表
82
74
  table = Table(box=SIMPLE)
83
- table.add_column("序号", style="cyan")
75
+ table.add_column("序号", style="#A0B0C0")
84
76
  table.add_column("类型", style="bold")
85
77
  table.add_column("名称")
86
78
  table.add_column("包名")
@@ -12,7 +12,6 @@ Uninstall 命令实现
12
12
 
13
13
  import sys
14
14
  from argparse import ArgumentParser
15
- from rich.panel import Panel
16
15
  from rich.prompt import Prompt
17
16
  from rich.table import Table
18
17
  from rich.box import SIMPLE
@@ -0,0 +1,84 @@
1
+ import sys
2
+ from rich.console import Console
3
+ from rich.theme import Theme
4
+ from rich.highlighter import RegexHighlighter
5
+
6
+ BANNER = (
7
+ "\n\n"
8
+ "███████╗██████╗ ██╗███████╗██████╗ ██╗ ██╗██╗ ███████╗███████╗\n"
9
+ "██╔════╝██╔══██╗██║██╔════╝██╔══██╗██║ ██║██║ ██╔════╝██╔════╝\n"
10
+ "█████╗ ██████╔╝██║███████╗██████╔╝██║ ██║██║ ███████╗█████╗ \n"
11
+ "██╔══╝ ██╔══██╗██║╚════██║██╔═══╝ ██║ ██║██║ ╚════██║██╔══╝ \n"
12
+ "███████╗██║ ██║██║███████║██║ ╚██████╔╝███████╗███████║███████╗\n"
13
+ "╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝\n"
14
+ "\n"
15
+ )
16
+
17
+ _BANNER_MINI = (
18
+ "\n\n"
19
+ "███████╗██████╗ ███████╗██████╗ ██╗ ██╗\n"
20
+ "██╔════╝██╔══██╗██╔════╝██╔══██╗██║ ██╔╝\n"
21
+ "█████╗ ██████╔╝███████╗██║ ██║█████╔╝ \n"
22
+ "██╔══╝ ██╔═══╝ ╚════██║██║ ██║██╔═██╗ \n"
23
+ "███████╗██║ ███████║██████╔╝██║ ██╗\n"
24
+ "╚══════╝╚═╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝\n"
25
+ "\n"
26
+ )
27
+
28
+
29
+ _banner_printed = False
30
+
31
+ def print_banner():
32
+ global _banner_printed
33
+ if _banner_printed:
34
+ return
35
+ _banner_printed = True
36
+ width = console.width
37
+ if width >= 75:
38
+ console.print(BANNER, style="bold white", highlight=False)
39
+ else:
40
+ console.print(_BANNER_MINI, style="bold white", highlight=False)
41
+
42
+ class CommandHighlighter(RegexHighlighter):
43
+ """
44
+ 高亮CLI命令和参数
45
+
46
+ {!--< tips >!--}
47
+ 使用正则表达式匹配命令行参数和选项
48
+ {!--< /tips >!--}
49
+ """
50
+ highlights = [
51
+ r"(?P<switch>\-\-?\w+)",
52
+ r"(?P<option>\[\w+\])",
53
+ r"(?P<command>\b\w+\b)",
54
+ ]
55
+
56
+ # 主题配置
57
+ theme = Theme({
58
+ "info": "#A0B0C0",
59
+ "success": "#A5D6A7",
60
+ "warning": "#FFCC80",
61
+ "error": "#FFCDD2",
62
+ "title": "#7DBFE0",
63
+ "default": "default",
64
+ "progress": "#A5D6A7",
65
+ "progress.remaining": "#283545",
66
+ "cmd": "#90CAF9",
67
+ "param": "#80CBC4",
68
+ "switch": "#FFCC80",
69
+ "module": "#80CBC4",
70
+ "adapter": "#7DBFE0",
71
+ "cli": "#A0B0C0",
72
+ })
73
+
74
+ # 全局控制台实例
75
+ console = Console(
76
+ theme=theme,
77
+ color_system="auto",
78
+ highlighter=CommandHighlighter()
79
+ )
80
+
81
+ __all__ = [
82
+ "console",
83
+ "print_banner",
84
+ ]
@@ -9,6 +9,9 @@ from rich.console import Console
9
9
  from rich.theme import Theme
10
10
  from rich.highlighter import RegexHighlighter
11
11
 
12
+ def print_banner() -> ...:
13
+ ...
14
+
12
15
  class CommandHighlighter(RegexHighlighter):
13
16
  """
14
17
  高亮CLI命令和参数
@@ -40,7 +40,7 @@ class CommandRegistry:
40
40
  :raises ValueError: 命令名称已存在时抛出
41
41
  """
42
42
  if command.name in self._commands:
43
- raise ValueError(f"命令 '{command.name}' 已存在")
43
+ return
44
44
  self._commands[command.name] = command
45
45
 
46
46
  def get(self, name: str) -> Optional[Command]:
@@ -162,29 +162,10 @@ class AdapterManager(ManagerBase):
162
162
 
163
163
  logger.info(f"启动适配器 {platforms}")
164
164
 
165
- # 提交适配器启动开始事件
166
165
  await lifecycle.submit_event(
167
166
  "adapter.start", msg="开始启动适配器", data={"platforms": platforms}
168
167
  )
169
168
 
170
- from .router import router
171
- from ..runtime import get_server_config
172
-
173
- server_config = get_server_config()
174
-
175
- host = server_config["host"]
176
- port = server_config["port"]
177
- ssl_cert = server_config.get("ssl_certfile", None)
178
- ssl_key = server_config.get("ssl_keyfile", None)
179
-
180
- # 启动服务器
181
- try:
182
- await router.start(
183
- host=host, port=port, ssl_certfile=ssl_cert, ssl_keyfile=ssl_key
184
- )
185
- except Exception as e:
186
- logger.warning(f"路由服务器启动失败: {e}")
187
- # 已经被调度过的 adapter 实例集合(防止重复调度)
188
169
  scheduled_adapters = set()
189
170
 
190
171
  for platform in platforms:
@@ -398,26 +379,20 @@ class AdapterManager(ManagerBase):
398
379
  f"已清理平台 {platform} 的路由: HTTP={result['http_count']}, WebSocket={result['websocket_count']}"
399
380
  )
400
381
 
401
- # 停止路由器(仅当所有适配器都关闭时)
402
- if not self._started_instances:
403
- await router.stop()
404
-
405
382
  # 将相关 Bot 标记为离线
406
383
  for platform, bot_id in bots_to_offline:
407
384
  if platform in self._bots and bot_id in self._bots[platform]:
408
385
  self._bots[platform][bot_id]["status"] = "offline"
409
- # 提交 Bot 离线事件
410
386
  await lifecycle.submit_event(
411
387
  "adapter.bot.offline",
412
388
  msg=f"Bot {platform}/{bot_id} 离线",
413
389
  data={"platform": platform, "bot_id": bot_id, "status": "offline"},
414
390
  )
415
391
 
416
- # 如果所有适配器都关闭了,清理事件处理器
417
- if not self._started_instances:
418
- self._onebot_handlers.clear()
419
- self._raw_handlers.clear()
420
- self._onebot_middlewares.clear()
392
+ # 清理事件处理器
393
+ self._onebot_handlers.clear()
394
+ self._raw_handlers.clear()
395
+ self._onebot_middlewares.clear()
421
396
 
422
397
  # 提交适配器关闭完成事件
423
398
  await lifecycle.submit_event(
@@ -867,14 +842,20 @@ class AdapterManager(ManagerBase):
867
842
  if not self._is_being_shutdown:
868
843
  try:
869
844
  loop = asyncio.get_running_loop()
870
- task = loop.create_task(
871
- lifecycle.submit_event(
872
- "adapter.bot.offline",
873
- msg=f"Bot {platform}/{bot_id} 离线",
874
- data={"platform": platform, "bot_id": bot_id, "status": "offline"},
875
- )
876
- )
877
- self._adapter_tasks.setdefault(f"_bot_offline_{platform}_{bot_id}", task)
845
+ task_key = f"_bot_offline_{platform}_{bot_id}"
846
+
847
+ async def _offline_event():
848
+ try:
849
+ await lifecycle.submit_event(
850
+ "adapter.bot.offline",
851
+ msg=f"Bot {platform}/{bot_id} 离线",
852
+ data={"platform": platform, "bot_id": bot_id, "status": "offline"},
853
+ )
854
+ finally:
855
+ self._adapter_tasks.pop(task_key, None)
856
+
857
+ task = loop.create_task(_offline_event())
858
+ self._adapter_tasks[task_key] = task
878
859
  except RuntimeError:
879
860
  pass
880
861
 
@@ -222,14 +222,23 @@ class Logger:
222
222
  def _get_caller(self):
223
223
  try:
224
224
  frame = inspect.currentframe()
225
- # 安全地获取调用栈帧
226
- if frame is None or frame.f_back is None or frame.f_back.f_back is None:
225
+ if frame is None:
227
226
  return "Unknown"
228
227
 
229
- frame = frame.f_back.f_back
230
- module = inspect.getmodule(frame)
228
+ logger_module = inspect.getmodule(frame)
229
+
230
+ while frame is not None:
231
+ frame = frame.f_back
232
+ if frame is None:
233
+ return "Unknown"
234
+ module = inspect.getmodule(frame)
235
+ if module is not None and module is not logger_module:
236
+ break
237
+
238
+ if frame is None:
239
+ return "Unknown"
231
240
 
232
- # 处理模块为None的情况
241
+ module = inspect.getmodule(frame)
233
242
  if module is None:
234
243
  return "Unknown"
235
244
 
@@ -395,9 +404,16 @@ class LoggerChild:
395
404
  :param level_const: 日志级别常量
396
405
  :param msg: 日志消息
397
406
  """
398
- if self._parent._get_effective_level(self._name.split(".")[0]) <= level_const:
399
- self._parent._save_in_memory(self._name, msg)
400
- getattr(self._parent._logger, level_name)(f"[{self._name}] {msg}", *args, **kwargs)
407
+ parts = self._name.split(".")
408
+ deduped = [parts[0]]
409
+ for p in parts[1:]:
410
+ if p != deduped[-1]:
411
+ deduped.append(p)
412
+ display_name = ".".join(deduped)
413
+
414
+ if self._parent._get_effective_level(display_name.split(".")[0]) <= level_const:
415
+ self._parent._save_in_memory(display_name, msg)
416
+ getattr(self._parent._logger, level_name)(f"[{display_name}] {msg}", *args, **kwargs)
401
417
 
402
418
  def debug(self, msg, *args, **kwargs):
403
419
  """记录 DEBUG 级别日志"""
@@ -432,7 +432,7 @@ class StorageManager(BaseStorage):
432
432
  """
433
433
  from .logger import logger
434
434
 
435
- logger.info(f"初始化数据库: {self.db_path}")
435
+ logger.debug(f"初始化数据库: {self.db_path}")
436
436
 
437
437
  try:
438
438
  os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
@@ -338,15 +338,16 @@ class ModuleLoader(BaseLoader):
338
338
  for module_name in modules:
339
339
  module_obj = module_objs[module_name]
340
340
  meta_name = module_obj.moduleInfo["meta"]["name"]
341
+ module_class = module_obj.moduleInfo.get("module_class")
341
342
 
342
- async def register_module(name: str, obj: Any) -> bool:
343
+ async def register_module(name: str, obj: Any, cls: Any) -> bool:
343
344
  """注册单个模块"""
344
345
  try:
345
- # 使用 ModuleFinder 获取 entry-point
346
+ if cls is not None:
347
+ manager_instance.register(name, cls, obj.moduleInfo)
348
+ return True
346
349
  if entry_point := self._finder.find_by_name(name):
347
350
  module_class = entry_point.load()
348
-
349
- # 调用管理器的 register 方法
350
351
  manager_instance.register(name, module_class, obj.moduleInfo)
351
352
  return True
352
353
  return False
@@ -354,7 +355,7 @@ class ModuleLoader(BaseLoader):
354
355
  logger.error(f"注册模块 {name} 失败: {e}")
355
356
  return False
356
357
 
357
- register_tasks.append(register_module(meta_name, module_obj))
358
+ register_tasks.append(register_module(meta_name, module_obj, module_class))
358
359
 
359
360
  # 等待所有注册任务完成
360
361
  register_results = await asyncio.gather(*register_tasks, return_exceptions=True)
@@ -14,6 +14,7 @@ example:
14
14
  from __future__ import annotations
15
15
 
16
16
  import asyncio
17
+ import importlib
17
18
  import sys
18
19
  from pathlib import Path
19
20
  from typing import TYPE_CHECKING
@@ -201,6 +202,7 @@ class SDK:
201
202
  3. 注册适配器
202
203
  4. 注册模块
203
204
  5. 初始化模块
205
+ 6. 启动路由服务器
204
206
 
205
207
  :return: bool 初始化是否成功
206
208
 
@@ -261,6 +263,20 @@ class SDK:
261
263
  else:
262
264
  success = True
263
265
 
266
+ # 5. 启动路由服务器
267
+ logger.print_section_header("路由服务器启动")
268
+ from ErisPulse.runtime import get_server_config
269
+ _server_config = get_server_config()
270
+ try:
271
+ await router.start(
272
+ host=_server_config["host"],
273
+ port=_server_config["port"],
274
+ ssl_certfile=_server_config.get("ssl_certfile"),
275
+ ssl_keyfile=_server_config.get("ssl_keyfile"),
276
+ )
277
+ except Exception as e:
278
+ logger.warning(f"路由服务器启动失败: {e}")
279
+
264
280
  # 获取加载耗时
265
281
  load_duration = lifecycle.stop_timer("core.init")
266
282
 
@@ -353,11 +369,15 @@ class SDK:
353
369
  执行反初始化
354
370
 
355
371
  执行步骤:
356
- 1. 关闭所有适配器
372
+ 1. 关闭所有适配器实例
357
373
  2. 卸载所有模块
358
- 3. 清理事件处理器
359
- 4. 清理管理器
360
- 5. 清理 SDK 模块属性
374
+ 3. 停止路由服务器
375
+ 4. 清理所有事件处理器
376
+ 5. 清理适配器管理器和模块管理器
377
+ 6. 清理 LazyModule 引用
378
+ 7. 清理单例残留状态
379
+ 8. 清理 SDK 模块属性
380
+ 9. 重置初始化状态
361
381
 
362
382
  :return: bool 反初始化是否成功
363
383
  """
@@ -366,6 +386,7 @@ class SDK:
366
386
  try:
367
387
  adapter_manager = self._sdk.adapter
368
388
  module_manager = self._sdk.module
389
+ router_manager = self._sdk.router
369
390
 
370
391
  # 1. 关闭所有适配器
371
392
  registered_adapters = adapter_manager.list_registered()
@@ -377,21 +398,23 @@ class SDK:
377
398
  if loaded_modules:
378
399
  await module_manager.unload()
379
400
 
380
- # 3. 收集 SDK 对象上的模块属性(在 clear 之前)
401
+ # 3. 停止路由服务器
402
+ if router_manager._server_task and not router_manager._server_task.done():
403
+ await router_manager.stop()
404
+
405
+ # 4. 收集 SDK 对象上的模块属性(在 clear 之前)
381
406
  instance_dict = object.__getattribute__(self._sdk, '__dict__')
382
407
  module_properties_to_clear = set()
383
408
 
384
- # 收集已加载模块的属性名
385
409
  for module_name in loaded_modules:
386
410
  if module_name in instance_dict:
387
411
  module_properties_to_clear.add(module_name)
388
412
 
389
- # 处理已初始化的 LazyModule(已访问过,有实例)
413
+ # 处理 LazyModule(包括已初始化和未初始化的)
390
414
  for attr_name, attr_value in list(instance_dict.items()):
391
415
  if attr_name.startswith('_'):
392
416
  continue
393
417
  if isinstance(attr_value, LazyModule):
394
- # 只处理已初始化的 LazyModule
395
418
  lm_initialized = object.__getattribute__(attr_value, '_initialized')
396
419
  if lm_initialized:
397
420
  lm_name = object.__getattribute__(attr_value, '_module_name')
@@ -405,21 +428,27 @@ class SDK:
405
428
  instance.on_unload({"module_name": lm_name})
406
429
  except Exception as e:
407
430
  logger.warning(f"清理懒加载模块 {lm_name} 的 on_unload 失败: {e}")
408
- module_properties_to_clear.add(attr_name)
431
+ # 清除 LazyModule 内部引用,打破循环引用链
432
+ object.__setattr__(attr_value, '_sdk_ref', None)
433
+ object.__setattr__(attr_value, '_instance', None)
434
+ object.__setattr__(attr_value, '_manager_instance', None)
435
+ object.__setattr__(attr_value, '_module_class', None)
436
+ module_properties_to_clear.add(attr_name)
409
437
 
410
- # 4. 清理所有事件处理器
438
+ # 5. 清理所有事件处理器
411
439
  Event._clear_all_handlers()
412
440
 
413
- # 5. 清理管理器
441
+ # 6. 清理管理器
414
442
  adapter_manager.clear()
415
443
  module_manager.clear()
416
444
 
417
- # 6. 停止路由服务器
418
- router_manager = self._sdk.router
419
- if router_manager._server_task and not router_manager._server_task.done():
420
- await router_manager.stop()
445
+ # 7. 清理单例残留状态
446
+ lifecycle._timers.clear()
447
+ logger._logs.clear()
448
+ logger._module_levels.clear()
449
+ config.force_save()
421
450
 
422
- # 7. 清理 SDK 对象上的模块属性(使用之前收集的列表)
451
+ # 8. 清理 SDK 对象上的模块属性
423
452
  module_properties_cleared = 0
424
453
  for module_name in module_properties_to_clear:
425
454
  try:
@@ -429,7 +458,7 @@ class SDK:
429
458
  except Exception as e:
430
459
  logger.warning(f"清理模块属性 {module_name} 失败: {e}")
431
460
 
432
- # 8. 重置初始化状态
461
+ # 9. 重置初始化状态
433
462
  self._sdk._initialized = False
434
463
  self._sdk._initializer = None
435
464
 
@@ -748,7 +777,7 @@ class SDK:
748
777
  def _invalidate_module_cache(self, top_level_modules: set[str]) -> None:
749
778
  """
750
779
  {!--< internal-use >!--}
751
- 清理 sys.modules 中属于已加载包的缓存,并刷新 importlib.metadata 缓存
780
+ 清理 sys.modules 中属于已加载包的缓存,并刷新 importlib 缓存
752
781
 
753
782
  :param top_level_modules: 需要清理的顶层 Python 模块名集合
754
783
  """
@@ -763,6 +792,8 @@ class SDK:
763
792
  for key in modules_to_remove:
764
793
  del sys.modules[key]
765
794
 
795
+ importlib.invalidate_caches()
796
+
766
797
  if modules_to_remove:
767
798
  logger.debug(f"[Reload] 已清理 {len(modules_to_remove)} 个 sys.modules 缓存: {modules_to_remove}")
768
799
 
@@ -19,6 +19,7 @@ example:
19
19
 
20
20
  from __future__ import annotations
21
21
  import asyncio
22
+ import importlib
22
23
  import sys
23
24
  from pathlib import Path
24
25
  from typing import TYPE_CHECKING
@@ -1,47 +0,0 @@
1
- import sys
2
- from rich.console import Console
3
- from rich.theme import Theme
4
- from rich.highlighter import RegexHighlighter
5
-
6
- class CommandHighlighter(RegexHighlighter):
7
- """
8
- 高亮CLI命令和参数
9
-
10
- {!--< tips >!--}
11
- 使用正则表达式匹配命令行参数和选项
12
- {!--< /tips >!--}
13
- """
14
- highlights = [
15
- r"(?P<switch>\-\-?\w+)",
16
- r"(?P<option>\[\w+\])",
17
- r"(?P<command>\b\w+\b)",
18
- ]
19
-
20
- # 主题配置
21
- theme = Theme({
22
- "info": "dim cyan",
23
- "success": "bold green",
24
- "warning": "bold yellow",
25
- "error": "bold red",
26
- "title": "bold magenta",
27
- "default": "default",
28
- "progress": "green",
29
- "progress.remaining": "white",
30
- "cmd": "bold blue",
31
- "param": "italic cyan",
32
- "switch": "bold yellow",
33
- "module": "bold green",
34
- "adapter": "bold yellow",
35
- "cli": "bold magenta",
36
- })
37
-
38
- # 全局控制台实例
39
- console = Console(
40
- theme=theme,
41
- color_system="auto",
42
- highlighter=CommandHighlighter()
43
- )
44
-
45
- __all__ = [
46
- "console",
47
- ]
File without changes