ErisPulse 2.4.3.dev1__tar.gz → 2.4.5.dev0__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.3.dev1 → erispulse-2.4.5.dev0}/PKG-INFO +45 -2
  2. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/README.md +44 -1
  3. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/pyproject.toml +1 -1
  4. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/init.py +5 -13
  5. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/install.py +60 -67
  6. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/install.pyi +0 -6
  7. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/run.py +66 -17
  8. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/run.pyi +5 -5
  9. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/console.py +0 -1
  10. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/utils/package_manager.py +333 -541
  11. erispulse-2.4.5.dev0/src/ErisPulse/CLI/utils/package_manager.pyi +105 -0
  12. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/adapter.py +12 -3
  13. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/command.py +19 -5
  14. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/wrapper.py +33 -11
  15. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/wrapper.pyi +10 -1
  16. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/adapter.py +14 -7
  17. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/config.py +1 -1
  18. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/lifecycle.py +5 -3
  19. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/lifecycle.pyi +9 -0
  20. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/logger.py +18 -17
  21. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/module.py +15 -1
  22. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/router.py +5 -3
  23. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/router.pyi +2 -2
  24. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/storage.py +14 -7
  25. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/storage.pyi +4 -0
  26. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/bases/finder.py +15 -11
  27. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/bases/finder.pyi +1 -0
  28. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/adapter.py +15 -8
  29. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/bases/loader.py +3 -3
  30. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/module.py +88 -45
  31. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/strategy.py +1 -1
  32. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/exceptions.py +9 -9
  33. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/frame_config.py +29 -9
  34. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/frame_config.pyi +11 -0
  35. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/sdk.py +22 -15
  36. erispulse-2.4.3.dev1/src/ErisPulse/CLI/utils/package_manager.pyi +0 -250
  37. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/.gitignore +0 -0
  38. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/LICENSE +0 -0
  39. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
  40. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/__init__.pyi +0 -0
  41. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/base.py +0 -0
  42. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/base.pyi +0 -0
  43. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/cli.py +0 -0
  44. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/cli.pyi +0 -0
  45. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  46. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/__init__.pyi +0 -0
  47. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/init.pyi +0 -0
  48. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/list.py +0 -0
  49. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/list.pyi +0 -0
  50. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  51. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/list_remote.pyi +0 -0
  52. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/self_update.py +0 -0
  53. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/self_update.pyi +0 -0
  54. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
  55. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/uninstall.pyi +0 -0
  56. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  57. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/commands/upgrade.pyi +0 -0
  58. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/console.pyi +0 -0
  59. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/registry.py +0 -0
  60. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/registry.pyi +0 -0
  61. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  62. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/CLI/utils/__init__.pyi +0 -0
  63. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/__init__.py +0 -0
  64. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/__init__.pyi +0 -0
  65. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/adapter.pyi +0 -0
  66. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/manager.py +0 -0
  67. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/manager.pyi +0 -0
  68. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/module.py +0 -0
  69. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/module.pyi +0 -0
  70. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/storage.py +0 -0
  71. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Bases/storage.pyi +0 -0
  72. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/__init__.py +0 -0
  73. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/__init__.pyi +0 -0
  74. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/base.py +0 -0
  75. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/base.pyi +0 -0
  76. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/command.pyi +0 -0
  77. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/message.py +0 -0
  78. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/message.pyi +0 -0
  79. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  80. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/message_builder.pyi +0 -0
  81. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/meta.py +0 -0
  82. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/meta.pyi +0 -0
  83. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/notice.py +0 -0
  84. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/notice.pyi +0 -0
  85. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/request.py +0 -0
  86. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/request.pyi +0 -0
  87. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
  88. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/Event/session_type.pyi +0 -0
  89. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/__init__.py +0 -0
  90. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/__init__.pyi +0 -0
  91. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/adapter.pyi +0 -0
  92. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/config.pyi +0 -0
  93. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/logger.pyi +0 -0
  94. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/Core/module.pyi +0 -0
  95. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/__init__.py +0 -0
  96. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/__init__.pyi +0 -0
  97. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/__main__.py +0 -0
  98. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/__main__.pyi +0 -0
  99. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/__init__.py +0 -0
  100. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/__init__.pyi +0 -0
  101. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/adapter.py +0 -0
  102. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/adapter.pyi +0 -0
  103. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
  104. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/bases/__init__.pyi +0 -0
  105. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/module.py +0 -0
  106. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/finders/module.pyi +0 -0
  107. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
  108. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/__init__.pyi +0 -0
  109. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/adapter.pyi +0 -0
  110. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  111. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/bases/__init__.pyi +0 -0
  112. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/bases/loader.pyi +0 -0
  113. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/module.pyi +0 -0
  114. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/loaders/strategy.pyi +0 -0
  115. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/__init__.py +0 -0
  116. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/__init__.pyi +0 -0
  117. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/runtime/exceptions.pyi +0 -0
  118. {erispulse-2.4.3.dev1 → erispulse-2.4.5.dev0}/src/ErisPulse/sdk.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 2.4.3.dev1
3
+ Version: 2.4.5.dev0
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: ErisDev <erisdev@88.com>
6
6
  Maintainer-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>
@@ -79,7 +79,7 @@ Description-Content-Type: text/markdown
79
79
  <table>
80
80
  <tr>
81
81
  <td width="35%" valign="middle" align="center">
82
- <img src=".github/assets/erispulse_logo_1024.png" width="280" alt="ErisPulse" />
82
+ <img src=".github/assets/erispulse_logo_hp.png" width="280" alt="ErisPulse" />
83
83
  </td>
84
84
  <td width="65%" valign="middle">
85
85
 
@@ -127,6 +127,7 @@ ErisPulse 是一个基于 Python 的事件驱动型多平台机器人开发框
127
127
  | [邮件](https://github.com/ErisPulse/ErisPulse-EmailAdapter) | 邮件协议收发适配器 |
128
128
  | [云湖](https://github.com/ErisPulse/ErisPulse-YunhuAdapter) | 企业级即时通讯平台(机器人接入) |
129
129
  | [云湖用户](https://github.com/wsu2059q/ErisPulse-YunhuUserAdapter) | 基于云湖用户协议的接入适配器 |
130
+ | [花枫咖啡馆](https://github.com/ErisPulse/ErisPulse-Ideaura/) | Allons! \(・ω・) / |
130
131
 
131
132
  查看 [适配器详情介绍](docs/zh-CN/platform-guide/README.md)
132
133
 
@@ -171,6 +172,48 @@ ERISPULSE_DASHBOARD_TOKEN=your-token docker compose up -d
171
172
 
172
173
  </details>
173
174
 
175
+ <details>
176
+ <summary>使用预发布版本 (Dev)</summary>
177
+
178
+ 设置 `ERISPULSE_CHANNEL=dev` 即可使用预发布版本:
179
+
180
+ ```bash
181
+ # 方式一:使用环境变量(推荐)
182
+ ERISPULSE_CHANNEL=dev ERISPULSE_DASHBOARD_TOKEN=your-token docker compose up -d
183
+
184
+ # 方式二:构建 dev 镜像
185
+ ERISPULSE_BUILD_TARGET=dev docker compose up -d --build
186
+ ```
187
+
188
+ 如需启动时自动更新到最新版本(无论 stable 还是 dev),显式设置 `ERISPULSE_UPDATE_ON_START=true`:
189
+
190
+ ```bash
191
+ ERISPULSE_CHANNEL=dev ERISPULSE_UPDATE_ON_START=true docker compose up -d
192
+ ```
193
+
194
+ 也可以拉取预构建的 dev 镜像:
195
+
196
+ ```bash
197
+ docker pull erispulse/erispulse:dev
198
+ ```
199
+
200
+ </details>
201
+
202
+ <details>
203
+ <summary>Docker 环境变量</summary>
204
+
205
+ | 变量 | 默认值 | 说明 |
206
+ |------|--------|------|
207
+ | `ERISPULSE_CHANNEL` | `stable` | 版本通道:`stable`(稳定版)或 `dev`(预发布版) |
208
+ | `ERISPULSE_UPDATE_ON_START` | `false` | 容器启动时是否自动更新到最新版本(需显式启用) |
209
+ | `ERISPULSE_DASHBOARD_TOKEN` | 空 | Dashboard 登录令牌 |
210
+ | `ERISPULSE_PORT` | `8000` | Dashboard 端口映射 |
211
+ | `TZ` | `Asia/Shanghai` | 容器时区 |
212
+
213
+ > 启用 `ERISPULSE_UPDATE_ON_START=true` 可确保即使镜像较旧,容器也能在启动时自动获取最新版本。
214
+
215
+ </details>
216
+
174
217
  ### 使用 pip 安装
175
218
 
176
219
  ```bash
@@ -7,7 +7,7 @@
7
7
  <table>
8
8
  <tr>
9
9
  <td width="35%" valign="middle" align="center">
10
- <img src=".github/assets/erispulse_logo_1024.png" width="280" alt="ErisPulse" />
10
+ <img src=".github/assets/erispulse_logo_hp.png" width="280" alt="ErisPulse" />
11
11
  </td>
12
12
  <td width="65%" valign="middle">
13
13
 
@@ -55,6 +55,7 @@ ErisPulse 是一个基于 Python 的事件驱动型多平台机器人开发框
55
55
  | [邮件](https://github.com/ErisPulse/ErisPulse-EmailAdapter) | 邮件协议收发适配器 |
56
56
  | [云湖](https://github.com/ErisPulse/ErisPulse-YunhuAdapter) | 企业级即时通讯平台(机器人接入) |
57
57
  | [云湖用户](https://github.com/wsu2059q/ErisPulse-YunhuUserAdapter) | 基于云湖用户协议的接入适配器 |
58
+ | [花枫咖啡馆](https://github.com/ErisPulse/ErisPulse-Ideaura/) | Allons! \(・ω・) / |
58
59
 
59
60
  查看 [适配器详情介绍](docs/zh-CN/platform-guide/README.md)
60
61
 
@@ -99,6 +100,48 @@ ERISPULSE_DASHBOARD_TOKEN=your-token docker compose up -d
99
100
 
100
101
  </details>
101
102
 
103
+ <details>
104
+ <summary>使用预发布版本 (Dev)</summary>
105
+
106
+ 设置 `ERISPULSE_CHANNEL=dev` 即可使用预发布版本:
107
+
108
+ ```bash
109
+ # 方式一:使用环境变量(推荐)
110
+ ERISPULSE_CHANNEL=dev ERISPULSE_DASHBOARD_TOKEN=your-token docker compose up -d
111
+
112
+ # 方式二:构建 dev 镜像
113
+ ERISPULSE_BUILD_TARGET=dev docker compose up -d --build
114
+ ```
115
+
116
+ 如需启动时自动更新到最新版本(无论 stable 还是 dev),显式设置 `ERISPULSE_UPDATE_ON_START=true`:
117
+
118
+ ```bash
119
+ ERISPULSE_CHANNEL=dev ERISPULSE_UPDATE_ON_START=true docker compose up -d
120
+ ```
121
+
122
+ 也可以拉取预构建的 dev 镜像:
123
+
124
+ ```bash
125
+ docker pull erispulse/erispulse:dev
126
+ ```
127
+
128
+ </details>
129
+
130
+ <details>
131
+ <summary>Docker 环境变量</summary>
132
+
133
+ | 变量 | 默认值 | 说明 |
134
+ |------|--------|------|
135
+ | `ERISPULSE_CHANNEL` | `stable` | 版本通道:`stable`(稳定版)或 `dev`(预发布版) |
136
+ | `ERISPULSE_UPDATE_ON_START` | `false` | 容器启动时是否自动更新到最新版本(需显式启用) |
137
+ | `ERISPULSE_DASHBOARD_TOKEN` | 空 | Dashboard 登录令牌 |
138
+ | `ERISPULSE_PORT` | `8000` | Dashboard 端口映射 |
139
+ | `TZ` | `Asia/Shanghai` | 容器时区 |
140
+
141
+ > 启用 `ERISPULSE_UPDATE_ON_START=true` 可确保即使镜像较旧,容器也能在启动时自动获取最新版本。
142
+
143
+ </details>
144
+
102
145
  ### 使用 pip 安装
103
146
 
104
147
  ```bash
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.4.3-dev.1"
7
+ version = "2.4.5-dev.0"
8
8
  description = "ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -16,7 +16,6 @@ from ..console import console
16
16
  from ..utils import PackageManager
17
17
  from ..base import Command
18
18
 
19
-
20
19
  class InitCommand(Command):
21
20
  name = "init"
22
21
  description = "初始化 ErisPulse 项目"
@@ -62,6 +61,10 @@ class InitCommand(Command):
62
61
  :param adapter_list: 需要初始化的适配器列表
63
62
  :return: 是否初始化成功
64
63
  """
64
+ if not project_name or not all(c.isalnum() or c in ('_', '-', '.') for c in project_name):
65
+ console.print("[error]项目名称只能包含字母、数字、下划线、连字符和点号[/]")
66
+ return False
67
+
65
68
  try:
66
69
  project_path = Path(project_name)
67
70
  if project_path.exists():
@@ -119,18 +122,7 @@ class InitCommand(Command):
119
122
  f.write("import asyncio\n")
120
123
  f.write("from ErisPulse import sdk\n\n")
121
124
  f.write("async def main():\n")
122
- f.write(' """主程序入口"""\n')
123
- f.write(" # 初始化 SDK\n")
124
- f.write(" await sdk.init()\n\n")
125
- f.write(" # 启动适配器\n")
126
- f.write(" await sdk.adapter.startup()\n\n")
127
- f.write(' print("ErisPulse 已启动,按 Ctrl+C 退出")\n')
128
- f.write(" try:\n")
129
- f.write(" while True:\n")
130
- f.write(" await asyncio.sleep(1)\n")
131
- f.write(" except KeyboardInterrupt:\n")
132
- f.write(" print(\"\\n正在关闭...\")\n")
133
- f.write(" await sdk.adapter.shutdown()\n\n")
125
+ f.write(" await sdk.run(keep_running=True)\n\n")
134
126
  f.write("if __name__ == \"__main__\":\n")
135
127
  f.write(" asyncio.run(main())\n")
136
128
 
@@ -21,10 +21,10 @@ from ..base import Command
21
21
  class InstallCommand(Command):
22
22
  name = "install"
23
23
  description = "安装模块/适配器包"
24
-
24
+
25
25
  def __init__(self):
26
26
  self.package_manager = PackageManager()
27
-
27
+
28
28
  def add_arguments(self, parser: ArgumentParser):
29
29
  parser.add_argument(
30
30
  'package',
@@ -161,7 +161,7 @@ class InstallCommand(Command):
161
161
  action='store_true',
162
162
  help='允许覆盖系统管理的包'
163
163
  )
164
-
164
+
165
165
  def _build_extra_pip_args(self, args) -> list:
166
166
  extra = []
167
167
  if getattr(args, 'user', False):
@@ -210,30 +210,30 @@ class InstallCommand(Command):
210
210
  extra.extend(['--upgrade-strategy', args.upgrade_strategy])
211
211
  if getattr(args, 'break_system_packages', False):
212
212
  extra.append('--break-system-packages')
213
-
213
+
214
214
  unknown_args = getattr(args, '_unknown_args', []) or []
215
215
  extra.extend(unknown_args)
216
-
216
+
217
217
  return extra
218
-
218
+
219
219
  def execute(self, args):
220
220
  editable_paths = getattr(args, 'editable', None)
221
221
  requirement_file = getattr(args, 'requirement', None)
222
-
222
+
223
223
  if args.package or editable_paths or requirement_file:
224
224
  success = True
225
225
  pm = self.package_manager
226
226
  extra = self._build_extra_pip_args(args)
227
-
227
+
228
228
  if editable_paths:
229
229
  for path in editable_paths:
230
230
  if not pm.install_direct(['-e', path] + extra, f"可编辑安装 {path}"):
231
231
  success = False
232
-
232
+
233
233
  if requirement_file:
234
234
  if not pm.install_direct(['-r', requirement_file] + extra, f"从文件安装 {requirement_file}"):
235
235
  success = False
236
-
236
+
237
237
  if args.package:
238
238
  if not pm.install_package(
239
239
  args.package,
@@ -242,73 +242,66 @@ class InstallCommand(Command):
242
242
  extra_pip_args=extra
243
243
  ):
244
244
  success = False
245
-
245
+
246
246
  if not success:
247
247
  sys.exit(1)
248
248
  else:
249
249
  self._interactive_install(args.upgrade, args.pre)
250
-
250
+
251
251
  def _interactive_install(self, upgrade: bool = False, pre: bool = False):
252
- """
253
- 交互式安装界面
254
-
255
- :param upgrade: 是否升级模式
256
- :param pre: 是否包含预发布版本
257
- """
258
252
  console.print(Panel(
259
253
  "[bold cyan]ErisPulse 安装组件[/]\n"
260
254
  "选择您要安装的组件类型",
261
255
  title="欢迎",
262
256
  border_style="cyan"
263
257
  ))
264
-
265
- console.print("[info]正在获取远程包列表...[/]")
266
- remote_packages = asyncio.run(self.package_manager.get_remote_packages())
267
- console.print("[success]远程包列表获取完成[/]")
268
- console.print("")
269
-
258
+
259
+ with console.status("[bold green]正在获取远程包列表...", spinner="dots"):
260
+ remote_packages = asyncio.run(self.package_manager.get_remote_packages())
261
+ console.print("[success]远程包列表获取完成[/]\n")
262
+
270
263
  while True:
271
264
  console.print("[bold cyan]请选择组件类型:[/]")
272
- console.print(" 1. 适配器")
273
- console.print(" 2. 模块")
274
- console.print(" 3. 自定义安装")
275
- console.print(" q. 退出")
276
-
265
+ console.print(" [bold]1.[/] 适配器")
266
+ console.print(" [bold]2.[/] 模块")
267
+ console.print(" [bold]3.[/] 自定义安装")
268
+ console.print(" [bold]q.[/] 退出")
269
+
277
270
  choice = Prompt.ask(
278
- "\n请输入选项 ",
271
+ "\n请输入选项",
279
272
  choices=["1", "2", "3", "q"],
280
273
  default="q"
281
274
  )
282
-
275
+
283
276
  if choice == "q":
284
277
  console.print("[info]退出安装向导[/]")
285
278
  break
286
-
279
+
287
280
  elif choice == "1":
288
281
  self._install_adapters(remote_packages, upgrade, pre)
289
282
  elif choice == "2":
290
283
  self._install_modules(remote_packages, upgrade, pre)
291
284
  elif choice == "3":
292
285
  self._install_custom(upgrade, pre)
293
-
286
+
294
287
  if not Confirm.ask("\n[cyan]是否继续安装其他组件?[/cyan]", default=False):
295
288
  break
296
-
289
+
297
290
  def _install_adapters(self, remote_packages: dict, upgrade: bool, pre: bool):
298
291
  console.print("\n[bold]可用的适配器:[/bold]")
299
-
292
+
300
293
  adapters = remote_packages.get("adapters", {})
301
-
294
+
302
295
  if not adapters:
303
296
  console.print("[yellow]没有可用的适配器[/yellow]")
304
297
  return
305
-
306
- table = Table(box=SIMPLE, header_style="adapter")
307
- table.add_column("序号", style="cyan")
298
+
299
+ table = Table(box=SIMPLE, header_style="adapter", show_lines=False)
300
+ table.add_column("序号", style="cyan", width=4)
308
301
  table.add_column("适配器名", style="adapter")
309
302
  table.add_column("包名")
310
303
  table.add_column("描述")
311
-
304
+
312
305
  adapter_list = list(adapters.items())
313
306
  for i, (name, info) in enumerate(adapter_list, 1):
314
307
  table.add_row(
@@ -317,20 +310,20 @@ class InstallCommand(Command):
317
310
  info.get("package", ""),
318
311
  info.get("description", "")
319
312
  )
320
-
313
+
321
314
  console.print(table)
322
-
315
+
323
316
  selected = Prompt.ask(
324
- "\n[cyan]请输入要安装的适配器序号(多个用逗号分隔,如: 1,3)或按 q 返回:[/cyan]"
317
+ "\n[cyan]请输入要安装的适配器序号(多个用逗号分隔,如: 1,3)或按 q 返回[/cyan]"
325
318
  )
326
-
319
+
327
320
  if selected.lower() == 'q':
328
321
  return
329
-
322
+
330
323
  try:
331
324
  indices = [int(idx.strip()) for idx in selected.split(",")]
332
325
  selected_packages = []
333
-
326
+
334
327
  for idx in indices:
335
328
  if 1 <= idx <= len(adapter_list):
336
329
  adapter_name = adapter_list[idx - 1][0]
@@ -338,32 +331,32 @@ class InstallCommand(Command):
338
331
  console.print(f"[green]已选择: {adapter_name}[/]")
339
332
  else:
340
333
  console.print(f"[red]无效的序号: {idx}[/]")
341
-
334
+
342
335
  if selected_packages:
343
336
  if Confirm.ask(
344
337
  f"\n[cyan]确认安装以下 {len(selected_packages)} 个适配器吗?[/cyan]",
345
338
  default=True
346
339
  ):
347
340
  self.package_manager.install_package(selected_packages, upgrade=upgrade, pre=pre)
348
-
341
+
349
342
  except ValueError:
350
343
  console.print("[red]输入格式错误,请输入数字序号[/]")
351
-
344
+
352
345
  def _install_modules(self, remote_packages: dict, upgrade: bool, pre: bool):
353
346
  console.print("\n[bold]可用的模块:[/bold]")
354
-
347
+
355
348
  modules = remote_packages.get("modules", {})
356
-
349
+
357
350
  if not modules:
358
351
  console.print("[yellow]没有可用的模块[/yellow]")
359
352
  return
360
-
361
- table = Table(box=SIMPLE, header_style="module")
362
- table.add_column("序号", style="cyan")
353
+
354
+ table = Table(box=SIMPLE, header_style="module", show_lines=False)
355
+ table.add_column("序号", style="cyan", width=4)
363
356
  table.add_column("模块名", style="module")
364
357
  table.add_column("包名")
365
358
  table.add_column("描述")
366
-
359
+
367
360
  module_list = list(modules.items())
368
361
  for i, (name, info) in enumerate(module_list, 1):
369
362
  table.add_row(
@@ -372,20 +365,20 @@ class InstallCommand(Command):
372
365
  info.get("package", ""),
373
366
  info.get("description", "")
374
367
  )
375
-
368
+
376
369
  console.print(table)
377
-
370
+
378
371
  selected = Prompt.ask(
379
- "\n[cyan]请输入要安装的模块序号(多个用逗号分隔,如: 1,3)或按 q 返回:[/cyan]"
372
+ "\n[cyan]请输入要安装的模块序号(多个用逗号分隔,如: 1,3)或按 q 返回[/cyan]"
380
373
  )
381
-
374
+
382
375
  if selected.lower() == 'q':
383
376
  return
384
-
377
+
385
378
  try:
386
379
  indices = [int(idx.strip()) for idx in selected.split(",")]
387
380
  selected_packages = []
388
-
381
+
389
382
  for idx in indices:
390
383
  if 1 <= idx <= len(module_list):
391
384
  module_name = module_list[idx - 1][0]
@@ -393,25 +386,25 @@ class InstallCommand(Command):
393
386
  console.print(f"[green]已选择: {module_name}[/]")
394
387
  else:
395
388
  console.print(f"[red]无效的序号: {idx}[/]")
396
-
389
+
397
390
  if selected_packages:
398
391
  if Confirm.ask(
399
392
  f"\n[cyan]确认安装以下 {len(selected_packages)} 个模块吗?[/cyan]",
400
393
  default=True
401
394
  ):
402
395
  self.package_manager.install_package(selected_packages, upgrade=upgrade, pre=pre)
403
-
396
+
404
397
  except ValueError:
405
398
  console.print("[red]输入格式错误,请输入数字序号[/]")
406
-
399
+
407
400
  def _install_custom(self, upgrade: bool, pre: bool):
408
401
  package_name = Prompt.ask(
409
- "\n[cyan]请输入要安装的包名(或按 q 返回):[/cyan]"
402
+ "\n[cyan]请输入要安装的包名(或按 q 返回)[/cyan]"
410
403
  )
411
-
404
+
412
405
  if package_name.lower() == 'q':
413
406
  return
414
-
407
+
415
408
  if package_name:
416
409
  if Confirm.ask(
417
410
  f"\n[cyan]确认安装包 {package_name} 吗?[/cyan]",
@@ -31,12 +31,6 @@ class InstallCommand(Command):
31
31
  def execute(self: object, args: ...) -> ...:
32
32
  ...
33
33
  def _interactive_install(self: object, upgrade: bool = ..., pre: bool = ...) -> ...:
34
- """
35
- 交互式安装界面
36
-
37
- :param upgrade: 是否升级模式
38
- :param pre: 是否包含预发布版本
39
- """
40
34
  ...
41
35
  def _install_adapters(self: object, remote_packages: dict, upgrade: bool, pre: bool) -> ...:
42
36
  ...
@@ -5,16 +5,26 @@ Run 命令实现
5
5
  """
6
6
 
7
7
  import os
8
+ import sys
8
9
  import time
9
10
  import asyncio
11
+ import subprocess
12
+ import runpy
10
13
  from argparse import ArgumentParser
11
- from watchdog.observers import Observer
12
14
  from rich.panel import Panel
13
- from watchdog.events import FileSystemEventHandler
14
15
 
15
16
  from ..console import console
16
17
  from ..base import Command
17
18
 
19
+ try:
20
+ from watchdog.observers import Observer
21
+ from watchdog.events import FileSystemEventHandler
22
+ _WATCHDOG_AVAILABLE = True
23
+ except ImportError:
24
+ _WATCHDOG_AVAILABLE = False
25
+ Observer = None
26
+ FileSystemEventHandler = object
27
+
18
28
 
19
29
  class ReloadHandler(FileSystemEventHandler):
20
30
  """
@@ -82,6 +92,10 @@ class RunCommand(Command):
82
92
  script = args.script
83
93
  reload_mode = args.reload
84
94
 
95
+ if reload_mode and not _WATCHDOG_AVAILABLE:
96
+ console.print("[error]热重载需要 watchdog 库,请运行: pip install watchdog[/]")
97
+ reload_mode = False
98
+
85
99
  if script:
86
100
  if not os.path.exists(script):
87
101
  console.print(f"[error]脚本 [path]{script}[/] 不存在[/]")
@@ -114,27 +128,62 @@ class RunCommand(Command):
114
128
  self._observer.join()
115
129
 
116
130
  def _run_script(self, script_path: str, reload_mode: bool):
117
- """
118
- 运行指定脚本文件
119
- """
120
- async def _run():
121
- from ... import sdk
131
+ script_path_abs = os.path.abspath(script_path)
122
132
 
123
- if reload_mode:
124
- loop = asyncio.get_running_loop()
125
- watch_dir = os.path.dirname(os.path.abspath(script_path))
126
- self._setup_watchdog(watch_dir, loop)
133
+ if reload_mode:
134
+ self._run_script_with_reload(script_path_abs)
135
+ else:
136
+ try:
137
+ runpy.run_path(script_path_abs, run_name="__main__")
138
+ except SystemExit:
139
+ pass
140
+ except KeyboardInterrupt:
141
+ pass
142
+
143
+ def _run_script_with_reload(self, script_path_abs: str):
144
+ watch_dir = os.path.dirname(script_path_abs)
145
+
146
+ process = subprocess.Popen([sys.executable, script_path_abs])
147
+
148
+ reload_state = {
149
+ "process": process,
150
+ "last_reload": 0.0,
151
+ }
152
+
153
+ class _ScriptReloadHandler(FileSystemEventHandler):
154
+ def on_modified(self, event):
155
+ now = time.time()
156
+ if now - reload_state["last_reload"] < 1.0:
157
+ return
158
+ if event.src_path.endswith(".py"):
159
+ reload_state["last_reload"] = now
160
+ console.print(f"检测到文件变更 ({os.path.basename(event.src_path)}),正在重启...")
161
+ reload_state["process"].terminate()
162
+ reload_state["process"].wait()
163
+ reload_state["process"] = subprocess.Popen([sys.executable, script_path_abs])
164
+
165
+ observer = Observer()
166
+ observer.schedule(_ScriptReloadHandler(), watch_dir, recursive=True)
167
+ observer.start()
127
168
 
128
- await sdk.run(keep_running=True)
169
+ console.print(Panel(
170
+ f"[bold]开发重载模式[/]\n监控目录: [path]{watch_dir}[/]",
171
+ title="热重载已启动",
172
+ border_style="info"
173
+ ))
129
174
 
130
175
  try:
131
- asyncio.run(_run())
176
+ while True:
177
+ proc = reload_state["process"]
178
+ proc.wait()
179
+ time.sleep(0.3)
180
+ if reload_state["process"] is proc:
181
+ break
132
182
  except KeyboardInterrupt:
133
- pass
183
+ reload_state["process"].terminate()
134
184
  finally:
135
- if reload_mode and hasattr(self, '_observer'):
136
- self._observer.stop()
137
- self._observer.join()
185
+ observer.stop()
186
+ observer.join()
138
187
 
139
188
  def _setup_watchdog(self, watch_dir: str, loop: asyncio.AbstractEventLoop):
140
189
  if not os.path.exists(watch_dir):
@@ -11,12 +11,13 @@ Run 命令实现
11
11
  """
12
12
 
13
13
  import os
14
+ import sys
14
15
  import time
15
16
  import asyncio
17
+ import subprocess
18
+ import runpy
16
19
  from argparse import ArgumentParser
17
- from watchdog.observers import Observer
18
20
  from rich.panel import Panel
19
- from watchdog.events import FileSystemEventHandler
20
21
  from ..console import console
21
22
  from ..base import Command
22
23
 
@@ -55,9 +56,8 @@ class RunCommand(Command):
55
56
  """
56
57
  ...
57
58
  def _run_script(self: object, script_path: str, reload_mode: bool) -> ...:
58
- """
59
- 运行指定脚本文件
60
- """
59
+ ...
60
+ def _run_script_with_reload(self: object, script_path_abs: str) -> ...:
61
61
  ...
62
62
  def _setup_watchdog(self: object, watch_dir: str, loop: asyncio.AbstractEventLoop) -> ...:
63
63
  ...
@@ -39,7 +39,6 @@ theme = Theme({
39
39
  console = Console(
40
40
  theme=theme,
41
41
  color_system="auto",
42
- force_terminal=True,
43
42
  highlighter=CommandHighlighter()
44
43
  )
45
44