ErisPulse 2.8.0.dev1__tar.gz → 2.8.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.
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/.gitignore +2 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/PKG-INFO +9 -4
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/README.pypi.md +2 -2
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/pyproject.toml +11 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/create.py +28 -2
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/init.py +4 -116
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/run.py +1 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/config_wizard.py +26 -4
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/package_manager.py +18 -97
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/scaffold_text.py +10 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/__init__.py +30 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/adapter.py +84 -8
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/config_schema.py +336 -79
- erispulse-2.8.1/src/ErisPulse/Core/Bases/errors.py +328 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/kv_builder.py +28 -22
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/module.py +13 -5
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/router.py +3 -1
- erispulse-2.8.1/src/ErisPulse/Core/Bases/sql_base.py +1612 -0
- erispulse-2.8.1/src/ErisPulse/Core/Bases/storage.py +1171 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/__init__.py +17 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/base.py +164 -108
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/command.py +191 -123
- erispulse-2.8.1/src/ErisPulse/Core/Event/interaction.py +924 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/overrides.py +114 -10
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/wrapper.py +585 -24
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/__init__.py +34 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/adapter.py +169 -10
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/client.py +35 -10
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/config.py +303 -63
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/constants.py +158 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/__init__.py +25 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/en.py +85 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/ja.py +85 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/ru.py +85 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/zh_cn.py +85 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/zh_tw.py +85 -3
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/lifecycle.py +162 -33
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/module.py +520 -19
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/router.py +31 -12
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/scope.py +149 -13
- erispulse-2.8.1/src/ErisPulse/Core/storage/__init__.py +89 -0
- erispulse-2.8.1/src/ErisPulse/Core/storage/mysql.py +279 -0
- erispulse-2.8.1/src/ErisPulse/Core/storage/postgres.py +282 -0
- erispulse-2.8.1/src/ErisPulse/Core/storage/sqlite.py +261 -0
- erispulse-2.8.1/src/ErisPulse/Core/transcript.py +375 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/__init__.py +24 -7
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/bases/finder.py +5 -2
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/adapter.py +20 -4
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/bases/loader.py +90 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/module.py +48 -13
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/plugin_folder.py +29 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/strict.py +1 -17
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/__init__.py +21 -0
- erispulse-2.8.1/src/ErisPulse/runtime/context.py +200 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/diagnostics.py +11 -2
- erispulse-2.8.1/src/ErisPulse/runtime/example_config.py +266 -0
- {erispulse-2.8.0.dev1/src/ErisPulse/CLI/utils → erispulse-2.8.1/src/ErisPulse/runtime}/file_watcher.py +1 -1
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/frame_config.py +68 -19
- erispulse-2.8.1/src/ErisPulse/runtime/owner_cleanup.py +171 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/plugin_reload.py +2 -2
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/tasks.py +19 -1
- erispulse-2.8.1/src/ErisPulse/runtime/version.py +166 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/sdk.py +95 -6
- erispulse-2.8.0.dev1/src/ErisPulse/Core/Bases/errors.py +0 -137
- erispulse-2.8.0.dev1/src/ErisPulse/Core/Bases/storage.py +0 -534
- erispulse-2.8.0.dev1/src/ErisPulse/Core/storage.py +0 -1520
- erispulse-2.8.0.dev1/src/ErisPulse/runtime/context.py +0 -104
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/LICENSE +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/base.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/cli.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/config.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/doctor.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/install.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/language.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/list.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/self_update.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/types.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/console.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/constants.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/hints.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/en.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/ja.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/ru.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/registry.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/display.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/client.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/converter.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/manager.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/websocket.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/message.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/message_builder.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/meta.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/notice.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/request.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/session_type.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/error.css +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/error.html +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/root.css +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/root.html +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/constants.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/logger.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/master.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/text_match.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/__main__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/adapter.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/bases/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/module.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/bases/__init__.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/strategy.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/py.typed +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/config_schema.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/exceptions.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/hints.py +0 -0
- {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/memory.py +0 -0
|
@@ -3,6 +3,7 @@ devs/videos
|
|
|
3
3
|
main.py
|
|
4
4
|
plugins/
|
|
5
5
|
venvs
|
|
6
|
+
config.full.example
|
|
6
7
|
config.toml
|
|
7
8
|
uv.lock
|
|
8
9
|
snapshots/
|
|
@@ -16,6 +17,7 @@ config/config.db
|
|
|
16
17
|
config/config.db-journal
|
|
17
18
|
config/config.db-wal
|
|
18
19
|
config/config.db-shm
|
|
20
|
+
.erispulse_config.lock
|
|
19
21
|
|
|
20
22
|
# site-packages
|
|
21
23
|
config/.packages
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ErisPulse
|
|
3
|
-
Version: 2.8.
|
|
3
|
+
Version: 2.8.1
|
|
4
4
|
Summary: Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署
|
|
5
5
|
Project-URL: Homepage, https://github.com/ErisPulse/ErisPulse
|
|
6
6
|
Project-URL: Documentation, https://www.erisdev.com#docs
|
|
@@ -29,11 +29,16 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
29
29
|
Classifier: Typing :: Typed
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Requires-Dist: aiohttp>=3.9.0
|
|
32
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
32
33
|
Requires-Dist: fastapi>=0.116.1
|
|
33
34
|
Requires-Dist: rich>=13.0.0
|
|
34
|
-
Requires-Dist:
|
|
35
|
+
Requires-Dist: tomlkit>=0.15.1
|
|
35
36
|
Requires-Dist: uvicorn>=0.30.0
|
|
36
37
|
Requires-Dist: websockets>=12.0
|
|
38
|
+
Provides-Extra: mysql
|
|
39
|
+
Requires-Dist: aiomysql>=0.2.0; extra == 'mysql'
|
|
40
|
+
Provides-Extra: postgres
|
|
41
|
+
Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
|
|
37
42
|
Provides-Extra: test
|
|
38
43
|
Requires-Dist: httpx>=0.24.0; extra == 'test'
|
|
39
44
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
|
|
@@ -44,8 +49,6 @@ Requires-Dist: pytest-xdist>=3.0.0; extra == 'test'
|
|
|
44
49
|
Requires-Dist: pytest>=7.0.0; extra == 'test'
|
|
45
50
|
Description-Content-Type: text/markdown
|
|
46
51
|
|
|
47
|
-

|
|
48
|
-
|
|
49
52
|
# ErisPulse
|
|
50
53
|
|
|
51
54
|
**Write once, deploy on multiple platforms.**
|
|
@@ -54,6 +57,8 @@ An event-driven, multi-platform chatbot development framework based on the OneBo
|
|
|
54
57
|
|
|
55
58
|
[](https://pypi.org/project/ErisPulse/)
|
|
56
59
|
[](https://pypi.org/project/ErisPulse/)
|
|
60
|
+
[](https://github.com/botuniverse/onebot-11)
|
|
61
|
+
[](https://12.onebot.dev/)
|
|
57
62
|
[](https://github.com/ErisPulse/ErisPulse/blob/main/LICENSE)
|
|
58
63
|
[](https://www.erisdev.com)
|
|
59
64
|
[](https://github.com/ErisPulse/ErisPulse)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-

|
|
2
|
-
|
|
3
1
|
# ErisPulse
|
|
4
2
|
|
|
5
3
|
**Write once, deploy on multiple platforms.**
|
|
@@ -8,6 +6,8 @@ An event-driven, multi-platform chatbot development framework based on the OneBo
|
|
|
8
6
|
|
|
9
7
|
[](https://pypi.org/project/ErisPulse/)
|
|
10
8
|
[](https://pypi.org/project/ErisPulse/)
|
|
9
|
+
[](https://github.com/botuniverse/onebot-11)
|
|
10
|
+
[](https://12.onebot.dev/)
|
|
11
11
|
[](https://github.com/ErisPulse/ErisPulse/blob/main/LICENSE)
|
|
12
12
|
[](https://www.erisdev.com)
|
|
13
13
|
[](https://github.com/ErisPulse/ErisPulse)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ErisPulse"
|
|
7
|
-
version = "2.8.
|
|
7
|
+
version = "2.8.1"
|
|
8
8
|
description = "Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署"
|
|
9
9
|
readme = "README.pypi.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -61,13 +61,14 @@ classifiers = [
|
|
|
61
61
|
|
|
62
62
|
dependencies = [
|
|
63
63
|
"rich>=13.0.0",
|
|
64
|
-
"
|
|
65
|
-
|
|
64
|
+
"tomlkit>=0.15.1",
|
|
66
65
|
# network 相关
|
|
67
66
|
"websockets>=12.0",
|
|
68
67
|
"aiohttp>=3.9.0",
|
|
69
68
|
"fastapi>=0.116.1",
|
|
70
69
|
"uvicorn>=0.30.0",
|
|
70
|
+
# storage 相关(默认 SQLite 后端异步驱动,开箱即用)
|
|
71
|
+
"aiosqlite>=0.20.0",
|
|
71
72
|
]
|
|
72
73
|
|
|
73
74
|
[project.urls]
|
|
@@ -79,6 +80,13 @@ Issues = "https://github.com/ErisPulse/ErisPulse/issues"
|
|
|
79
80
|
Changelog = "https://github.com/ErisPulse/ErisPulse/blob/main/CHANGELOG.md"
|
|
80
81
|
|
|
81
82
|
[project.optional-dependencies]
|
|
83
|
+
# 存储后端可选驱动:pip install ErisPulse[mysql] / ErisPulse[postgres]
|
|
84
|
+
mysql = [
|
|
85
|
+
"aiomysql>=0.2.0",
|
|
86
|
+
]
|
|
87
|
+
postgres = [
|
|
88
|
+
"asyncpg>=0.29.0",
|
|
89
|
+
]
|
|
82
90
|
test = [
|
|
83
91
|
"pytest>=7.0.0",
|
|
84
92
|
"pytest-cov>=4.0.0",
|
|
@@ -86,7 +86,11 @@ class Main(BaseModule):
|
|
|
86
86
|
# {text[module.config_hint]}
|
|
87
87
|
@dataclass
|
|
88
88
|
class ConfigClass(BaseConfig):
|
|
89
|
-
\"\"\"
|
|
89
|
+
\"\"\"
|
|
90
|
+
{text[module.config_doc]}
|
|
91
|
+
|
|
92
|
+
:ivar advanced_threshold: 高级阈值(docstring :ivar: 声明即为字段描述,无需 metadata)
|
|
93
|
+
\"\"\"
|
|
90
94
|
|
|
91
95
|
enabled: bool = field(
|
|
92
96
|
default=True,
|
|
@@ -94,6 +98,11 @@ class Main(BaseModule):
|
|
|
94
98
|
\"description\": {{\"i18n\": \"module.{name}.enabled\", \"default\": \"Enable module\"}},
|
|
95
99
|
}},
|
|
96
100
|
)
|
|
101
|
+
# example 字段:默认不写入 config.toml(仅记录在 config.full.example,用户按需启用)
|
|
102
|
+
advanced_threshold: int = field(
|
|
103
|
+
default=100,
|
|
104
|
+
metadata={{\"example\": True, \"min\": 0}},
|
|
105
|
+
)
|
|
97
106
|
|
|
98
107
|
# {text[module.i18n_hint]}
|
|
99
108
|
class I18nClass(BaseI18n):
|
|
@@ -157,8 +166,13 @@ class Main(BaseModule):
|
|
|
157
166
|
description={{\"i18n\": \"module.{name}.meta.description\", \"default\": \"{name} module\"}},
|
|
158
167
|
version=\"0.1.0\",
|
|
159
168
|
author=\"ErisDev\",
|
|
169
|
+
# 最低 SDK 版本(可选):不满足时框架在加载期明确报错并跳过本模块
|
|
170
|
+
min_sdk_version=\"2.8.0\",
|
|
160
171
|
group=\"default\",
|
|
161
172
|
tags=[\"{name}\"],
|
|
173
|
+
# 对外服务白名单(可选):声明后其他模块可经 sdk.module.call() 调用这些方法;
|
|
174
|
+
# 缺省时公开方法全开放(限制由用户通过 scope.actions 配置)
|
|
175
|
+
# services=[\"get_welcome_message\"],
|
|
162
176
|
)
|
|
163
177
|
|
|
164
178
|
@staticmethod
|
|
@@ -285,10 +299,17 @@ class {name}(BaseAdapter):
|
|
|
285
299
|
depends: ClassVar[dict] = {{}}
|
|
286
300
|
optional_modules: ClassVar[list] = []
|
|
287
301
|
|
|
302
|
+
# 声明所需最低 SDK 版本:不满足时框架在加载期明确报错并跳过本适配器(可选)
|
|
303
|
+
min_sdk_version = "2.8.0"
|
|
304
|
+
|
|
288
305
|
# {text[adapter.config_hint]}
|
|
289
306
|
@dataclass
|
|
290
307
|
class ConfigClass(BaseConfig):
|
|
291
|
-
\"\"\"
|
|
308
|
+
\"\"\"
|
|
309
|
+
{text[adapter.config_doc]}
|
|
310
|
+
|
|
311
|
+
:ivar request_timeout: 请求超时秒数(docstring :ivar: 声明即为字段描述,无需 metadata)
|
|
312
|
+
\"\"\"
|
|
292
313
|
|
|
293
314
|
endpoint: str = field(
|
|
294
315
|
default="https://api.example.com",
|
|
@@ -307,6 +328,11 @@ class {name}(BaseAdapter):
|
|
|
307
328
|
"ui": {{"widget": "password", "group": "basic", "order": 2}},
|
|
308
329
|
}},
|
|
309
330
|
)
|
|
331
|
+
# example 字段:默认不写入 config.toml(仅记录在 config.full.example,用户按需启用)
|
|
332
|
+
request_timeout: int = field(
|
|
333
|
+
default=30,
|
|
334
|
+
metadata={{"example": True, "min": 1, "max": 300}},
|
|
335
|
+
)
|
|
310
336
|
|
|
311
337
|
# {text[adapter.i18n_hint]}
|
|
312
338
|
class I18nClass(BaseI18n):
|
|
@@ -175,128 +175,16 @@ class InitCommand(Command):
|
|
|
175
175
|
"""
|
|
176
176
|
生成完整的配置示例文本
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
生成逻辑收归 ``ErisPulse.runtime.example_config``(框架运行与 CLI 共用:
|
|
179
|
+
含自维护首行标记、静态框架段与已安装组件声明式段)。此处仅保留调用入口。
|
|
180
180
|
|
|
181
181
|
:param adapter_list: [list] 适配器名称列表 (默认: None)
|
|
182
182
|
:return: [str] 完整配置示例字符串
|
|
183
183
|
"""
|
|
184
|
-
from
|
|
185
|
-
|
|
186
|
-
st = ScaffoldText()
|
|
187
|
-
lines = [
|
|
188
|
-
st.t("cfg.header.title"),
|
|
189
|
-
st.t("cfg.header.desc"),
|
|
190
|
-
st.t("cfg.header.usage"),
|
|
191
|
-
"",
|
|
192
|
-
st.t("cfg.section.server"),
|
|
193
|
-
"",
|
|
194
|
-
"[ErisPulse.server]",
|
|
195
|
-
f'host = "0.0.0.0" # {st.t("cfg.server.host")}',
|
|
196
|
-
f"port = 8000 # {st.t('cfg.server.port')}",
|
|
197
|
-
f"auto_start = true # {st.t('cfg.server.auto_start')}",
|
|
198
|
-
f'ssl_certfile = "config/ssl/cert.pem" # {st.t("cfg.server.ssl_certfile")}',
|
|
199
|
-
f'ssl_keyfile = "config/ssl/key.pem" # {st.t("cfg.server.ssl_keyfile")}',
|
|
200
|
-
st.t("cfg.server.ssl_inline_hint"),
|
|
201
|
-
'# ssl_cert = """-----BEGIN CERTIFICATE-----',
|
|
202
|
-
"# ...",
|
|
203
|
-
'# -----END CERTIFICATE-----"""',
|
|
204
|
-
'# ssl_key = """-----BEGIN PRIVATE KEY-----',
|
|
205
|
-
"# ...",
|
|
206
|
-
'# -----END PRIVATE KEY-----"""',
|
|
207
|
-
"",
|
|
208
|
-
st.t("cfg.section.logger"),
|
|
209
|
-
"",
|
|
210
|
-
"[ErisPulse.logger]",
|
|
211
|
-
f'level = "INFO" # {st.t("cfg.logger.level")}',
|
|
212
|
-
f"log_files = [] # {st.t('cfg.logger.log_files')}",
|
|
213
|
-
f'log_dir = "" # {st.t("cfg.logger.log_dir")}',
|
|
214
|
-
f'log_rotation = "size" # {st.t("cfg.logger.log_rotation")}',
|
|
215
|
-
f"log_max_size_mb = 10 # {st.t('cfg.logger.log_max_size_mb')}",
|
|
216
|
-
f"log_backup_count = 5 # {st.t('cfg.logger.log_backup_count')}",
|
|
217
|
-
f'log_rotation_when = "midnight" # {st.t("cfg.logger.log_rotation_when")}',
|
|
218
|
-
f"memory_limit = 1000 # {st.t('cfg.logger.memory_limit')}",
|
|
219
|
-
"",
|
|
220
|
-
st.t("cfg.section.storage"),
|
|
221
|
-
"",
|
|
222
|
-
"[ErisPulse.storage]",
|
|
223
|
-
f"use_global_db = false # {st.t('cfg.storage.use_global_db')}",
|
|
224
|
-
"",
|
|
225
|
-
st.t("cfg.section.event"),
|
|
226
|
-
"",
|
|
227
|
-
"[ErisPulse.event.message]",
|
|
228
|
-
f"ignore_self = true # {st.t('cfg.event.ignore_self')}",
|
|
229
|
-
"",
|
|
230
|
-
"[ErisPulse.event.command]",
|
|
231
|
-
f'prefix = "/" # {st.t("cfg.command.prefix")}',
|
|
232
|
-
f"case_sensitive = true # {st.t('cfg.command.case_sensitive')}",
|
|
233
|
-
f"allow_space_prefix = false # {st.t('cfg.command.allow_space_prefix')}",
|
|
234
|
-
f"must_at_bot = false # {st.t('cfg.command.must_at_bot')}",
|
|
235
|
-
"",
|
|
236
|
-
st.t("cfg.section.framework"),
|
|
237
|
-
"",
|
|
238
|
-
"[ErisPulse.framework]",
|
|
239
|
-
f"enable_lazy_loading = true # {st.t('cfg.framework.enable_lazy_loading')}",
|
|
240
|
-
f'plugins_dir = "plugins" # {st.t("cfg.framework.plugins_dir")}',
|
|
241
|
-
f"uninit_timeout = 30 # {st.t('cfg.framework.uninit_timeout')}",
|
|
242
|
-
f" {st.t('cfg.framework.uninit_timeout_line1')}",
|
|
243
|
-
f" {st.t('cfg.framework.uninit_timeout_line2')}",
|
|
244
|
-
f"strict_mode = false # {st.t('cfg.framework.strict_mode')}",
|
|
245
|
-
f"strict_mode_exceptions = {{ modules = [], adapters = [] }} # {st.t('cfg.framework.strict_mode_exceptions')}",
|
|
246
|
-
f"handler_max_concurrency = 64 # {st.t('cfg.framework.handler_max_concurrency')}",
|
|
247
|
-
f"proactive_gc_interval = 300 # {st.t('cfg.framework.proactive_gc_interval')}",
|
|
248
|
-
f"proactive_gc_generation = 2 # {st.t('cfg.framework.proactive_gc_generation')}",
|
|
249
|
-
f"proactive_gc_full_every = 10 # {st.t('cfg.framework.proactive_gc_full_every')}",
|
|
250
|
-
f"proactive_gc_memory_growth_mb = 100 # {st.t('cfg.framework.proactive_gc_memory_growth_mb')}",
|
|
251
|
-
f"proactive_gc_idle_only = true # {st.t('cfg.framework.proactive_gc_idle_only')}",
|
|
252
|
-
f"proactive_gc_gen0_min = 100 # {st.t('cfg.framework.proactive_gc_gen0_min')}",
|
|
253
|
-
f"offline_bot_expiry = 3600 # {st.t('cfg.framework.offline_bot_expiry')}",
|
|
254
|
-
"",
|
|
255
|
-
st.t("cfg.section.router"),
|
|
256
|
-
"",
|
|
257
|
-
"[ErisPulse.router.cors]",
|
|
258
|
-
"enabled = false",
|
|
259
|
-
'allow_origins = ["*"]',
|
|
260
|
-
'allow_methods = ["*"]',
|
|
261
|
-
'allow_headers = ["*"]',
|
|
262
|
-
"allow_credentials = false",
|
|
263
|
-
"max_age = 600",
|
|
264
|
-
"",
|
|
265
|
-
"[ErisPulse.router.security]",
|
|
266
|
-
"enabled = false",
|
|
267
|
-
"",
|
|
268
|
-
"[ErisPulse.router.security.headers]",
|
|
269
|
-
'X-Content-Type-Options = "nosniff"',
|
|
270
|
-
'X-Frame-Options = "DENY"',
|
|
271
|
-
"",
|
|
272
|
-
st.t("cfg.section.adapter_status"),
|
|
273
|
-
"",
|
|
274
|
-
"[ErisPulse.adapters.status]",
|
|
275
|
-
]
|
|
276
|
-
|
|
277
|
-
if adapter_list:
|
|
278
|
-
lines.extend(f"# {adapter} = false" for adapter in adapter_list)
|
|
279
|
-
else:
|
|
280
|
-
lines.extend(
|
|
281
|
-
[
|
|
282
|
-
"# yunhu = false",
|
|
283
|
-
"# telegram = false",
|
|
284
|
-
"# onebot11 = false",
|
|
285
|
-
]
|
|
286
|
-
)
|
|
184
|
+
from ErisPulse.runtime.example_config import render_full_example
|
|
287
185
|
|
|
288
|
-
|
|
289
|
-
[
|
|
290
|
-
"",
|
|
291
|
-
st.t("cfg.section.module_status"),
|
|
292
|
-
"",
|
|
293
|
-
"[ErisPulse.modules.status]",
|
|
294
|
-
"# MyModule = true",
|
|
295
|
-
"",
|
|
296
|
-
]
|
|
297
|
-
)
|
|
186
|
+
return render_full_example(adapter_list=adapter_list)
|
|
298
187
|
|
|
299
|
-
return "\n".join(lines)
|
|
300
188
|
|
|
301
189
|
async def _fetch_available_adapters(self):
|
|
302
190
|
"""
|
|
@@ -16,11 +16,11 @@ from pathlib import Path
|
|
|
16
16
|
|
|
17
17
|
from rich.panel import Panel
|
|
18
18
|
|
|
19
|
+
from ...runtime.file_watcher import FileSystemEventHandler, PollingObserver
|
|
19
20
|
from ..base import Command
|
|
20
21
|
from ..console import console
|
|
21
22
|
from ..constants import ENV_SUPERVISED, HARD_RESTART_EXIT_CODE
|
|
22
23
|
from ..i18n import i18n
|
|
23
|
-
from ..utils.file_watcher import FileSystemEventHandler, PollingObserver
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class ReloadHandler(FileSystemEventHandler):
|
|
@@ -524,6 +524,9 @@ def fill_config_fields(config_class, current_values: dict) -> dict:
|
|
|
524
524
|
"""
|
|
525
525
|
渲染整个配置类的表单并收集用户输入
|
|
526
526
|
|
|
527
|
+
``example`` 字段不进入向导(默认值不落盘,仅记录在 config.full.example);
|
|
528
|
+
嵌套 dataclass 字段(schema 含 ``fields`` 子树)递归渲染为子表单。
|
|
529
|
+
|
|
527
530
|
:param config_class: dataclass 配置类
|
|
528
531
|
:param current_values: 当前存储的配置字典(作为各字段初值)
|
|
529
532
|
:return: 收集后的配置字典
|
|
@@ -531,12 +534,31 @@ def fill_config_fields(config_class, current_values: dict) -> dict:
|
|
|
531
534
|
from ErisPulse.Core.Bases.config_schema import resolve_config_schema
|
|
532
535
|
|
|
533
536
|
schema = resolve_config_schema(config_class)
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
+
values = dict(current_values or {})
|
|
538
|
+
_fill_from_schema_fields(schema.get("fields", {}), values)
|
|
539
|
+
return values
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def _fill_from_schema_fields(fields_dict: dict, values: dict) -> None:
|
|
543
|
+
"""
|
|
544
|
+
{!--< internal-use >!--}
|
|
545
|
+
按 schema 字段树渲染表单并就地收集到 values(嵌套子树递归)
|
|
546
|
+
"""
|
|
547
|
+
current_store = dict(values)
|
|
548
|
+
for name, field_schema in _sort_fields(fields_dict):
|
|
549
|
+
if field_schema.get("example") and name not in current_store:
|
|
550
|
+
# example 字段仅当用户已显式设置时保留原值,不主动询问
|
|
551
|
+
continue
|
|
552
|
+
nested_fields = field_schema.get("fields")
|
|
553
|
+
if isinstance(nested_fields, dict):
|
|
554
|
+
sub_values = current_store.get(name)
|
|
555
|
+
if not isinstance(sub_values, dict):
|
|
556
|
+
sub_values = {}
|
|
557
|
+
_fill_from_schema_fields(nested_fields, sub_values)
|
|
558
|
+
values[name] = sub_values
|
|
559
|
+
continue
|
|
537
560
|
has_value = name in current_store
|
|
538
561
|
values[name] = _prompt_field(name, field_schema, values.get(name), has_value)
|
|
539
|
-
return values
|
|
540
562
|
|
|
541
563
|
|
|
542
564
|
def _validate_dataclass(config_class, data: dict) -> list[str]:
|
|
@@ -26,54 +26,8 @@ from ..console import console
|
|
|
26
26
|
from ..constants import PYPI_PACKAGE_JSON_URL_TEMPLATE
|
|
27
27
|
from ..i18n import i18n
|
|
28
28
|
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# post 版本 (1.0.postN) 与本地版本 (1.0+local)。
|
|
32
|
-
# 例如 2.5.0-dev.1 / 2.5.0a1 / 1.0rc1 / 1.0.post1 / 1.0+local / 1!1.0 均可解析。
|
|
33
|
-
# 不支持的格式(如 1.0.post1.dev1 这类 post 后跟 dev)由 _parse_version 返回 None 退化处理。
|
|
34
|
-
_VERSION_RE = re.compile(
|
|
35
|
-
r"^\s*v?(?P<epoch>\d+!)?(?P<release>\d+(?:\.\d+)*)"
|
|
36
|
-
r"(?:[-._]?(?P<pre>dev|alpha|beta|rc|a|b|c|pre)[-._]?(?P<num>\d*))?"
|
|
37
|
-
r"(?:[-._]?post[-._]?(?P<post>\d+))?"
|
|
38
|
-
r"(?:\+(?P<local>[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*))?",
|
|
39
|
-
re.IGNORECASE,
|
|
40
|
-
)
|
|
41
|
-
# 预发布类型排序权重:正式版 > rc > beta > alpha > dev
|
|
42
|
-
_PRE_RELEASE_RANK = {
|
|
43
|
-
"dev": 0,
|
|
44
|
-
"alpha": 1,
|
|
45
|
-
"a": 1,
|
|
46
|
-
"beta": 2,
|
|
47
|
-
"b": 2,
|
|
48
|
-
"rc": 3,
|
|
49
|
-
"c": 3,
|
|
50
|
-
"pre": 3,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _parse_version(version: str) -> dict | None:
|
|
55
|
-
"""
|
|
56
|
-
将版本号解析为结构化组件(PEP 440 子集,纯标准库)。
|
|
57
|
-
|
|
58
|
-
与 :meth:`PackageManager._version_key` / :meth:`PackageManager._is_pre_release`
|
|
59
|
-
共用同一解析口径,避免不同正则导致判定分歧(如 ``1.0c2`` 此前在
|
|
60
|
-
``_is_pre_release`` 与 ``_version_key`` 间判定口径不一致)。
|
|
61
|
-
|
|
62
|
-
:param version: [str] 版本号字符串
|
|
63
|
-
:return: [Optional[dict]] 含 epoch/release/pre_type/pre_num/post/local 的字典,
|
|
64
|
-
无法解析时返回 None
|
|
65
|
-
"""
|
|
66
|
-
match = _VERSION_RE.match(str(version).strip().lstrip("vV"))
|
|
67
|
-
if not match:
|
|
68
|
-
return None
|
|
69
|
-
return {
|
|
70
|
-
"epoch": int((match.group("epoch") or "0").rstrip("!") or 0),
|
|
71
|
-
"release": match.group("release"),
|
|
72
|
-
"pre_type": match.group("pre"),
|
|
73
|
-
"pre_num": match.group("num"),
|
|
74
|
-
"post": match.group("post"),
|
|
75
|
-
"local": match.group("local"),
|
|
76
|
-
}
|
|
29
|
+
# 版本号解析与比较的唯一实现在 runtime/version.py(PEP 440 子集,纯标准库);
|
|
30
|
+
# 本模块经下方方法级委托复用同一解析口径,避免双正则导致判定分歧
|
|
77
31
|
|
|
78
32
|
|
|
79
33
|
class PackageManager:
|
|
@@ -853,63 +807,28 @@ class PackageManager:
|
|
|
853
807
|
"""
|
|
854
808
|
将版本号解析为可比较的元组键
|
|
855
809
|
|
|
856
|
-
|
|
857
|
-
epoch 优先于一切 release 段;本地版本 (+local) 不影响主排序,
|
|
858
|
-
但同一版本号带 local 段者 > 不带 local 段者。
|
|
859
|
-
例如 2.4.5-dev.1 先于 2.4.5 正式版,1.0 < 1.0.post1 < 1.1。
|
|
810
|
+
委托 :func:`ErisPulse.runtime.version.version_key`(框架内唯一实现)。
|
|
860
811
|
|
|
861
812
|
:param version: [str] 版本号字符串
|
|
862
|
-
:return: [tuple]
|
|
813
|
+
:return: [tuple] 逐段可比较的比较键元组
|
|
863
814
|
"""
|
|
864
|
-
|
|
865
|
-
if parsed is None:
|
|
866
|
-
# 无法解析时退化为基础键,保证不抛异常
|
|
867
|
-
return (0, (0, 0, 0, 0), (1,), (0,), ((1, str(version).lower()),))
|
|
868
|
-
|
|
869
|
-
release = tuple(int(x) for x in parsed["release"].split("."))
|
|
870
|
-
# release 段对齐到固定长度,确保 (2.5) 与 (2.5.0) 可正确比较
|
|
871
|
-
padded = release + (0,) * max(0, 4 - len(release))
|
|
872
|
-
|
|
873
|
-
pre_type = parsed["pre_type"]
|
|
874
|
-
if pre_type is None:
|
|
875
|
-
# 正式版:预发布键高于任何预发布版本
|
|
876
|
-
pre_key = (1,)
|
|
877
|
-
else:
|
|
878
|
-
rank = _PRE_RELEASE_RANK.get(pre_type.lower(), 1)
|
|
879
|
-
pre_num = int(parsed["pre_num"] or 0)
|
|
880
|
-
pre_key = (0, rank, pre_num)
|
|
881
|
-
|
|
882
|
-
# post 段:无 post 视为 post0,保证 1.0 == 1.0.post0 < 1.0.post1
|
|
883
|
-
post_num = int(parsed["post"] or 0)
|
|
884
|
-
post_key = (post_num,)
|
|
885
|
-
|
|
886
|
-
local = parsed["local"]
|
|
887
|
-
if local:
|
|
888
|
-
# 本地段按 "数值段 < 字母段" 拆分,避免 int/str 直接比较抛异常
|
|
889
|
-
local_key = tuple(
|
|
890
|
-
(0, int(part)) if part.isdigit() else (1, part.lower())
|
|
891
|
-
for part in local.split(".")
|
|
892
|
-
)
|
|
893
|
-
else:
|
|
894
|
-
local_key = ()
|
|
815
|
+
from ...runtime.version import version_key
|
|
895
816
|
|
|
896
|
-
return (
|
|
817
|
+
return version_key(version)
|
|
897
818
|
|
|
898
819
|
def _compare_versions(self, version1: str, version2: str) -> int:
|
|
899
820
|
"""
|
|
900
821
|
比较两个版本号的大小
|
|
901
822
|
|
|
823
|
+
委托 :func:`ErisPulse.runtime.version.compare_versions`(框架内唯一实现)。
|
|
824
|
+
|
|
902
825
|
:param version1: [str] 第一个版本号
|
|
903
826
|
:param version2: [str] 第二个版本号
|
|
904
827
|
:return: [int] version1 大于/等于/小于 version2 时分别返回 1/0/-1
|
|
905
828
|
"""
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return 1
|
|
910
|
-
if k1 < k2:
|
|
911
|
-
return -1
|
|
912
|
-
return 0
|
|
829
|
+
from ...runtime.version import compare_versions
|
|
830
|
+
|
|
831
|
+
return compare_versions(version1, version2)
|
|
913
832
|
|
|
914
833
|
def _check_sdk_compatibility(self, min_sdk_version: str) -> tuple[bool, str]:
|
|
915
834
|
"""
|
|
@@ -1435,14 +1354,16 @@ class PackageManager:
|
|
|
1435
1354
|
"""
|
|
1436
1355
|
判断版本号是否为预发布版本
|
|
1437
1356
|
|
|
1438
|
-
与 :meth:`_version_key`
|
|
1439
|
-
|
|
1440
|
-
post 版本 (1.0.post1) 与本地版本 (1.0+local)
|
|
1357
|
+
与 :meth:`_version_key` 共用同一解析口径(:func:`ErisPulse.runtime.version.parse_version`)。
|
|
1358
|
+
当版本号含预发布段 (dev/alpha/beta/rc/c/pre) 时返回 True。
|
|
1359
|
+
post 版本 (1.0.post1) 与本地版本 (1.0+local) 不视为预发布版本
|
|
1441
1360
|
|
|
1442
1361
|
:param version: [str] 版本号字符串
|
|
1443
|
-
:return: [bool]
|
|
1362
|
+
:return: [bool] 是预发布版本时返回 True
|
|
1444
1363
|
"""
|
|
1445
|
-
|
|
1364
|
+
from ...runtime.version import parse_version
|
|
1365
|
+
|
|
1366
|
+
parsed = parse_version(version)
|
|
1446
1367
|
return parsed is not None and parsed["pre_type"] is not None
|
|
1447
1368
|
|
|
1448
1369
|
def update_self(self, target_version: str | None = None, force: bool = False) -> bool:
|
|
@@ -96,6 +96,8 @@ _EN_FALLBACK: dict[str, str] = {
|
|
|
96
96
|
"cfg.section.router": "# ==================== Router ====================",
|
|
97
97
|
"cfg.section.adapter_status": "# ==================== Adapter Status ====================",
|
|
98
98
|
"cfg.section.module_status": "# ==================== Module Status ====================",
|
|
99
|
+
"cfg.section.components": "# ==================== Installed Components (declarative, auto-generated) ====================",
|
|
100
|
+
"cfg.section.components_hint": "# Rendered from each installed adapter/module ConfigClass; example: fields only live here (not auto-persisted to config.toml)",
|
|
99
101
|
"cfg.server.host": "Listen address",
|
|
100
102
|
"cfg.server.port": "Listen port",
|
|
101
103
|
"cfg.server.auto_start": "Auto start HTTP server (set false for pure WS/polling adapters)",
|
|
@@ -112,6 +114,9 @@ _EN_FALLBACK: dict[str, str] = {
|
|
|
112
114
|
"cfg.logger.log_rotation_when": "date mode: rotation period S/M/H/D/midnight",
|
|
113
115
|
"cfg.logger.memory_limit": "In-memory log entries limit",
|
|
114
116
|
"cfg.storage.use_global_db": "Use global database",
|
|
117
|
+
"cfg.storage.backend": "Storage backend: \"sqlite\" / \"mysql\" / \"postgres\"",
|
|
118
|
+
"cfg.storage.mysql": "MySQL connection params (effective when backend = \"mysql\"), requires: pip install ErisPulse[mysql]",
|
|
119
|
+
"cfg.storage.postgres": "PostgreSQL connection params (effective when backend = \"postgres\"), requires: pip install ErisPulse[postgres]",
|
|
115
120
|
"cfg.event.ignore_self": "Ignore self messages",
|
|
116
121
|
"cfg.command.prefix": "Command prefix",
|
|
117
122
|
"cfg.command.case_sensitive": "Case sensitive",
|
|
@@ -196,6 +201,8 @@ _TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
|
196
201
|
"cfg.section.router": "# ==================== 路由增强 ====================",
|
|
197
202
|
"cfg.section.adapter_status": "# ==================== 适配器状态 ====================",
|
|
198
203
|
"cfg.section.module_status": "# ==================== 模块状态 ====================",
|
|
204
|
+
"cfg.section.components": "# ==================== 已安装组件(声明式自动生成) ====================",
|
|
205
|
+
"cfg.section.components_hint": "# 由各已安装适配器/模块的 ConfigClass 渲染;example: 字段仅记录于此(不会自动写入 config.toml)",
|
|
199
206
|
"cfg.server.host": "监听地址",
|
|
200
207
|
"cfg.server.port": "监听端口",
|
|
201
208
|
"cfg.server.auto_start": "是否自动启动 HTTP 服务器 (纯 WS/轮询适配器可设 false)",
|
|
@@ -211,6 +218,9 @@ _TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
|
211
218
|
"cfg.logger.log_rotation_when": "date 模式轮转周期: S/M/H/D/midnight",
|
|
212
219
|
"cfg.logger.memory_limit": "内存日志条数上限",
|
|
213
220
|
"cfg.storage.use_global_db": "是否使用全局数据库",
|
|
221
|
+
"cfg.storage.backend": "存储后端: \"sqlite\" / \"mysql\" / \"postgres\"",
|
|
222
|
+
"cfg.storage.mysql": "MySQL 连接参数(backend = \"mysql\" 时生效),需安装: pip install ErisPulse[mysql]",
|
|
223
|
+
"cfg.storage.postgres": "PostgreSQL 连接参数(backend = \"postgres\" 时生效),需安装: pip install ErisPulse[postgres]",
|
|
214
224
|
"cfg.event.ignore_self": "忽略自身消息",
|
|
215
225
|
"cfg.command.prefix": "命令前缀",
|
|
216
226
|
"cfg.command.case_sensitive": "区分大小写",
|
|
@@ -9,7 +9,8 @@ from .converter import BaseConverter
|
|
|
9
9
|
from .send_rules import SendContext
|
|
10
10
|
from .send_builder import SendBuilder, BatchContext
|
|
11
11
|
from .module import BaseModule, ModuleMeta
|
|
12
|
-
from .storage import BaseStorage, BaseQueryBuilder
|
|
12
|
+
from .storage import AsyncBridge, BaseStorage, BaseQueryBuilder
|
|
13
|
+
from .sql_base import AlterTableBuilder, SQLDialect, SQLQueryBuilder, SQLStorageBase
|
|
13
14
|
from .kv_builder import KVQueryBuilder
|
|
14
15
|
from .errors import (
|
|
15
16
|
ErisPulseError,
|
|
@@ -17,6 +18,17 @@ from .errors import (
|
|
|
17
18
|
ClientConnectionError,
|
|
18
19
|
ClientTimeoutError,
|
|
19
20
|
HTTPStatusError,
|
|
21
|
+
InteractionCancelled,
|
|
22
|
+
InteractionError,
|
|
23
|
+
ModuleCallError,
|
|
24
|
+
ModuleCallTimeoutError,
|
|
25
|
+
ModuleError,
|
|
26
|
+
ModuleNotAvailableError,
|
|
27
|
+
ServiceNotProvidedError,
|
|
28
|
+
SessionOccupiedError,
|
|
29
|
+
StorageError,
|
|
30
|
+
StorageUnreachableError,
|
|
31
|
+
StrictModeError,
|
|
20
32
|
WebSocketError,
|
|
21
33
|
WebSocketDisconnect,
|
|
22
34
|
)
|
|
@@ -66,16 +78,33 @@ __all__ = [
|
|
|
66
78
|
"I18nConfig",
|
|
67
79
|
# i18n 单键声明
|
|
68
80
|
"I18nKey",
|
|
81
|
+
"AsyncBridge",
|
|
82
|
+
"InteractionCancelled",
|
|
83
|
+
"InteractionError",
|
|
69
84
|
"KVQueryBuilder",
|
|
85
|
+
"ModuleCallError",
|
|
86
|
+
"ModuleCallTimeoutError",
|
|
87
|
+
"ModuleError",
|
|
70
88
|
"ModuleMeta",
|
|
89
|
+
"ModuleNotAvailableError",
|
|
71
90
|
"RequestDSL",
|
|
72
91
|
"SendBuilder",
|
|
73
92
|
"SendContext",
|
|
74
93
|
"SendDSL",
|
|
94
|
+
"ServiceNotProvidedError",
|
|
95
|
+
"SessionOccupiedError",
|
|
75
96
|
"SseEmitter",
|
|
97
|
+
"StorageError",
|
|
98
|
+
"StorageUnreachableError",
|
|
99
|
+
"StrictModeError",
|
|
76
100
|
"WSMessage",
|
|
77
101
|
"WebSocketConnection",
|
|
78
102
|
"WebSocketConnectionBase",
|
|
79
103
|
"WebSocketDisconnect",
|
|
80
104
|
"WebSocketError",
|
|
105
|
+
# SQL 存储基类(自定义 SQL 后端扩展用)
|
|
106
|
+
"AlterTableBuilder",
|
|
107
|
+
"SQLDialect",
|
|
108
|
+
"SQLQueryBuilder",
|
|
109
|
+
"SQLStorageBase",
|
|
81
110
|
]
|