ErisPulse 2.7.0.dev0__tar.gz → 2.7.0.dev5__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.7.0.dev0 → erispulse-2.7.0.dev5}/PKG-INFO +1 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/pyproject.toml +1 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/cli.py +17 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/create.py +193 -181
- erispulse-2.7.0.dev5/src/ErisPulse/CLI/commands/doctor.py +127 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/init.py +1 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/list.py +29 -9
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/run.py +2 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/types.py +3 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/console.py +2 -2
- erispulse-2.7.0.dev5/src/ErisPulse/CLI/constants.py +46 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/__init__.py +82 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/en.py +33 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/ja.py +33 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/ru.py +33 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +33 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +33 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/utils/display.py +4 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/utils/package_manager.py +229 -38
- erispulse-2.7.0.dev5/src/ErisPulse/CLI/utils/scaffold_text.py +338 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/__init__.py +4 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/adapter.py +363 -15
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/config_schema.py +93 -18
- erispulse-2.7.0.dev5/src/ErisPulse/Core/Bases/converter.py +80 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/send_rules.py +3 -3
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/command.py +60 -25
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/session_type.py +28 -6
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/wrapper.py +111 -4
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/__init__.py +2 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/adapter.py +33 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/client.py +4 -3
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/config.py +164 -26
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/constants.py +66 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/en.py +43 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/ja.py +43 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/ru.py +43 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/zh_cn.py +43 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/zh_tw.py +43 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/lifecycle.py +61 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/logger.py +31 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/master.py +1 -1
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/router.py +183 -20
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/storage.py +30 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/finders/adapter.py +3 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/finders/module.py +3 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/adapter.py +9 -2
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/module.py +22 -7
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/__init__.py +15 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/config_schema.py +2 -0
- erispulse-2.7.0.dev5/src/ErisPulse/runtime/diagnostics.py +317 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/frame_config.py +51 -1
- erispulse-2.7.0.dev5/src/ErisPulse/runtime/memory.py +121 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/sdk.py +221 -31
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/.gitignore +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/LICENSE +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/README.pypi.md +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/base.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/install.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/language.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/self_update.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/hints.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/registry.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/utils/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/CLI/utils/file_watcher.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/client.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/errors.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/manager.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/module.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/router.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/storage.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Bases/websocket.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/base.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/message.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/message_builder.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/meta.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/notice.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/Event/request.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/assets/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/assets/error.css +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/assets/error.html +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/assets/root.css +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/assets/root.html +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/constants.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/Core/module.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/__main__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/finders/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/finders/bases/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/finders/bases/finder.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/bases/__init__.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/bases/loader.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/strategy.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/loaders/strict.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/py.typed +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/context.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/exceptions.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/hints.py +0 -0
- {erispulse-2.7.0.dev0 → erispulse-2.7.0.dev5}/src/ErisPulse/runtime/tasks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ErisPulse
|
|
3
|
-
Version: 2.7.0.
|
|
3
|
+
Version: 2.7.0.dev5
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ErisPulse"
|
|
7
|
-
version = "2.7.0-
|
|
7
|
+
version = "2.7.0-dev.5"
|
|
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"
|
|
@@ -60,6 +60,19 @@ class CLI:
|
|
|
60
60
|
default=0,
|
|
61
61
|
help=i18n.t("cli.parser.verbose_help"),
|
|
62
62
|
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--no-color",
|
|
65
|
+
action="store_true",
|
|
66
|
+
default=False,
|
|
67
|
+
help=i18n.t("cli.parser.no_color_help"),
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--yes",
|
|
71
|
+
"-y",
|
|
72
|
+
action="store_true",
|
|
73
|
+
default=False,
|
|
74
|
+
help=i18n.t("cli.parser.yes_help"),
|
|
75
|
+
)
|
|
63
76
|
|
|
64
77
|
# 子命令
|
|
65
78
|
subparsers = parser.add_subparsers(
|
|
@@ -286,6 +299,10 @@ class CLI:
|
|
|
286
299
|
args, unknown = self.parser.parse_known_args()
|
|
287
300
|
args._unknown_args = unknown
|
|
288
301
|
|
|
302
|
+
# --no-color:禁用 Rich 控制台着色(CI / 日志采集场景)
|
|
303
|
+
if getattr(args, "no_color", False):
|
|
304
|
+
console.no_color = True
|
|
305
|
+
|
|
289
306
|
print_banner()
|
|
290
307
|
|
|
291
308
|
# 前几次启动时提醒用户确认语言(检测错误时用户仍可看懂多语言提示)
|
|
@@ -16,6 +16,7 @@ from ..base import Command
|
|
|
16
16
|
from ..console import console
|
|
17
17
|
from ..i18n import i18n
|
|
18
18
|
from ..utils.display import prompt_validated, section_header
|
|
19
|
+
from ..utils.scaffold_text import ScaffoldText
|
|
19
20
|
|
|
20
21
|
_LICENSE_TEMPLATE = """MIT License
|
|
21
22
|
|
|
@@ -65,42 +66,57 @@ _MODULE_INIT = """from .Core import Main
|
|
|
65
66
|
_MODULE_CORE = """from dataclasses import dataclass, field
|
|
66
67
|
from ErisPulse.Core.Bases import BaseConfig, BaseI18n, BaseModule, I18nKey
|
|
67
68
|
from ErisPulse.Core.Event import command, message, notice
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@dataclass
|
|
71
|
-
class {name}Config(BaseConfig):
|
|
72
|
-
\"\"\"{name} 模块配置\"\"\"
|
|
73
|
-
enabled: bool = field(
|
|
74
|
-
default=True,
|
|
75
|
-
metadata={{
|
|
76
|
-
\"description\": \"是否启用模块\",
|
|
77
|
-
}},
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class {name}I18n(BaseI18n):
|
|
82
|
-
\"\"\"{name} 模块翻译键声明
|
|
83
|
-
|
|
84
|
-
声明的翻译键会被框架自动注册到 i18n 系统。
|
|
85
|
-
键路径自动生成为: <模块名>.<属性名>
|
|
86
|
-
\"\"\"
|
|
87
|
-
# 示例:取消注释并修改以启用
|
|
88
|
-
# welcome: I18nKey = I18nKey(
|
|
89
|
-
# default="Welcome to {name}!",
|
|
90
|
-
# zh_CN="欢迎使用 {name}!",
|
|
91
|
-
# en="Welcome to {name}!",
|
|
92
|
-
# )
|
|
69
|
+
from ErisPulse.Core.i18n import i18n
|
|
93
70
|
|
|
94
71
|
|
|
95
72
|
class Main(BaseModule):
|
|
96
73
|
\"\"\"
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
继承自BaseModule基类,实现了标准化的模块生命周期管理和事件处理
|
|
74
|
+
{text[module.doc]}
|
|
100
75
|
\"\"\"
|
|
101
76
|
|
|
102
|
-
|
|
103
|
-
|
|
77
|
+
# {text[module.config_hint]}
|
|
78
|
+
@dataclass
|
|
79
|
+
class ConfigClass(BaseConfig):
|
|
80
|
+
\"\"\"{text[module.config_doc]}\"\"\"
|
|
81
|
+
|
|
82
|
+
enabled: bool = field(
|
|
83
|
+
default=True,
|
|
84
|
+
metadata={{
|
|
85
|
+
\"description\": {{\"i18n\": \"module.{name}.enabled\", \"default\": \"Enable module\"}},
|
|
86
|
+
}},
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# {text[module.i18n_hint]}
|
|
90
|
+
class I18nClass(BaseI18n):
|
|
91
|
+
\"\"\"{name} translation keys\"\"\"
|
|
92
|
+
|
|
93
|
+
enabled: I18nKey = I18nKey(
|
|
94
|
+
key=\"module.{name}.enabled\",
|
|
95
|
+
default=\"Enable module\",
|
|
96
|
+
zh_CN=\"是否启用模块\",
|
|
97
|
+
en=\"Enable module\",
|
|
98
|
+
ja=\"モジュールを有効にする\",
|
|
99
|
+
ru=\"Включить модуль\",
|
|
100
|
+
zh_TW=\"啟用模組\",
|
|
101
|
+
)
|
|
102
|
+
hello_help: I18nKey = I18nKey(
|
|
103
|
+
key=\"module.{name}.command.hello.help\",
|
|
104
|
+
default=\"Send a greeting message\",
|
|
105
|
+
zh_CN=\"发送问候消息\",
|
|
106
|
+
en=\"Send a greeting message\",
|
|
107
|
+
ja=\"挨拶メッセージを送信\",
|
|
108
|
+
ru=\"Отправить приветствие\",
|
|
109
|
+
zh_TW=\"發送問候訊息\",
|
|
110
|
+
)
|
|
111
|
+
hello_reply: I18nKey = I18nKey(
|
|
112
|
+
key=\"module.{name}.command.hello.reply\",
|
|
113
|
+
default=\"Hello from {name}!\",
|
|
114
|
+
zh_CN=\"来自 {name} 的问候!\",
|
|
115
|
+
en=\"Hello from {name}!\",
|
|
116
|
+
ja=\"{name} からの挨拶です!\",
|
|
117
|
+
ru=\"Привет от {name}!\",
|
|
118
|
+
zh_TW=\"來自 {name} 的問候!\",
|
|
119
|
+
)
|
|
104
120
|
|
|
105
121
|
def __init__(self, sdk=None):
|
|
106
122
|
from ErisPulse import sdk as _sdk
|
|
@@ -110,7 +126,7 @@ class Main(BaseModule):
|
|
|
110
126
|
self.adapter = self.sdk.adapter
|
|
111
127
|
self.client = self.sdk.client
|
|
112
128
|
|
|
113
|
-
self.logger.info(\"{name}
|
|
129
|
+
self.logger.info((\"{text[module.log.init_done]}\").format(name=\"{name}\"))
|
|
114
130
|
|
|
115
131
|
@staticmethod
|
|
116
132
|
def get_load_strategy():
|
|
@@ -122,35 +138,39 @@ class Main(BaseModule):
|
|
|
122
138
|
|
|
123
139
|
async def on_load(self, event: dict) -> bool:
|
|
124
140
|
\"\"\"
|
|
125
|
-
|
|
141
|
+
{text[module.on_load_doc]}
|
|
126
142
|
|
|
127
|
-
:param event:
|
|
128
|
-
:return:
|
|
143
|
+
:param event: event data
|
|
144
|
+
:return: processing result
|
|
129
145
|
\"\"\"
|
|
130
146
|
await self._register_commands()
|
|
131
147
|
await self._register_message_handlers()
|
|
132
|
-
self.logger.info(
|
|
148
|
+
self.logger.info((\"{text[module.log.loaded]}\").format(event=event))
|
|
133
149
|
return True
|
|
134
150
|
|
|
135
151
|
async def on_unload(self, event: dict) -> bool:
|
|
136
152
|
\"\"\"
|
|
137
|
-
|
|
153
|
+
{text[module.on_unload_doc]}
|
|
138
154
|
|
|
139
|
-
:param event:
|
|
140
|
-
:return:
|
|
155
|
+
:param event: event data
|
|
156
|
+
:return: processing result
|
|
141
157
|
\"\"\"
|
|
142
|
-
self.logger.info(
|
|
158
|
+
self.logger.info((\"{text[module.log.unloaded]}\").format(event=event))
|
|
143
159
|
return True
|
|
144
160
|
|
|
161
|
+
def on_config_update(self, old_config, new_config):
|
|
162
|
+
\"\"\"{text[module.config_updated_doc]}\"\"\"
|
|
163
|
+
self.logger.info(\"{text[module.log.config_updated]}\")
|
|
164
|
+
|
|
145
165
|
async def _register_commands(self):
|
|
146
|
-
@command(\"hello\", help
|
|
166
|
+
@command(\"hello\", help=i18n.t(\"module.{name}.command.hello.help\"))
|
|
147
167
|
async def hello_command(event):
|
|
148
|
-
await event.reply(\"
|
|
168
|
+
await event.reply(i18n.t(\"module.{name}.command.hello.reply\"))
|
|
149
169
|
|
|
150
170
|
async def _register_message_handlers(self):
|
|
151
171
|
@message.on_private_message()
|
|
152
172
|
async def private_message_handler(event):
|
|
153
|
-
self.logger.info(
|
|
173
|
+
self.logger.info((\"{text[module.log.private_message]}\").format(content=event.get_text()))
|
|
154
174
|
|
|
155
175
|
@message.on_group_message()
|
|
156
176
|
async def group_message_handler(event):
|
|
@@ -158,7 +178,7 @@ class Main(BaseModule):
|
|
|
158
178
|
|
|
159
179
|
@notice.on_friend_add()
|
|
160
180
|
async def friend_add_handler(event):
|
|
161
|
-
self.logger.info(
|
|
181
|
+
self.logger.info((\"{text[module.log.friend_add]}\").format(nickname=event.get_user_nickname()))
|
|
162
182
|
"""
|
|
163
183
|
|
|
164
184
|
_ADAPTER_PYPROJECT = """[project]
|
|
@@ -193,89 +213,79 @@ _ADAPTER_CORE = """import asyncio
|
|
|
193
213
|
import json
|
|
194
214
|
from dataclasses import dataclass, field
|
|
195
215
|
from ErisPulse.Core import BaseAdapter
|
|
196
|
-
from ErisPulse.Core.Bases import BaseConfig,
|
|
216
|
+
from ErisPulse.Core.Bases import BaseConfig, BaseI18n, I18nKey
|
|
197
217
|
from ErisPulse.Core import router
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
@dataclass
|
|
201
|
-
class {name}Config(BaseConfig):
|
|
202
|
-
\"\"\"{name} 适配器配置\"\"\"
|
|
203
|
-
endpoint: str = field(
|
|
204
|
-
default="https://api.example.com",
|
|
205
|
-
metadata={{
|
|
206
|
-
"description": {{"i18n": "adapter.{name}.endpoint", "default": "平台 API 地址"}},
|
|
207
|
-
"required": False,
|
|
208
|
-
"ui": {{"widget": "text", "group": "connection", "order": 1}},
|
|
209
|
-
}},
|
|
210
|
-
)
|
|
211
|
-
token: str = field(
|
|
212
|
-
default="",
|
|
213
|
-
metadata={{
|
|
214
|
-
"description": {{"i18n": "adapter.{name}.token", "default": "平台 Token"}},
|
|
215
|
-
"required": True,
|
|
216
|
-
"secret": True,
|
|
217
|
-
"ui": {{"widget": "password", "group": "basic", "order": 2}},
|
|
218
|
-
}},
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
class {name}I18n(BaseI18n):
|
|
223
|
-
\"\"\"{name} 适配器翻译键声明
|
|
224
|
-
|
|
225
|
-
声明的翻译键会被框架自动注册到 i18n 系统。
|
|
226
|
-
这里集中管理适配器用到的所有翻译键(含配置描述引用的键)。
|
|
227
|
-
\"\"\"
|
|
228
|
-
# 注册配置描述中引用的 i18n 键的多语言译文
|
|
229
|
-
endpoint: I18nKey = I18nKey(
|
|
230
|
-
default="Platform API Endpoint",
|
|
231
|
-
zh_CN="平台 API 地址",
|
|
232
|
-
en="Platform API Endpoint",
|
|
233
|
-
ja="APIアドレス",
|
|
234
|
-
ru="API адрес",
|
|
235
|
-
zh_TW="API 位址",
|
|
236
|
-
)
|
|
237
|
-
token: I18nKey = I18nKey(
|
|
238
|
-
default="Platform Token",
|
|
239
|
-
zh_CN="平台 Token",
|
|
240
|
-
en="Platform Token",
|
|
241
|
-
ja="トークン",
|
|
242
|
-
ru="Токен",
|
|
243
|
-
zh_TW="權杖",
|
|
244
|
-
)
|
|
218
|
+
from ErisPulse.Core.i18n import i18n
|
|
245
219
|
|
|
246
220
|
|
|
247
221
|
class {name}(BaseAdapter):
|
|
248
222
|
\"\"\"
|
|
249
|
-
{
|
|
250
|
-
|
|
251
|
-
继承自 BaseAdapter 基类,使用声明式配置管理(ConfigClass),
|
|
252
|
-
实现了 SendDSL 风格的链式调用接口和 Bot 状态追踪。
|
|
223
|
+
{text[adapter.doc]}
|
|
253
224
|
\"\"\"
|
|
254
225
|
|
|
255
|
-
|
|
256
|
-
|
|
226
|
+
# {text[adapter.config_hint]}
|
|
227
|
+
@dataclass
|
|
228
|
+
class ConfigClass(BaseConfig):
|
|
229
|
+
\"\"\"{text[adapter.config_doc]}\"\"\"
|
|
230
|
+
|
|
231
|
+
endpoint: str = field(
|
|
232
|
+
default="https://api.example.com",
|
|
233
|
+
metadata={{
|
|
234
|
+
"description": {{"i18n": "adapter.{name}.endpoint", "default": "Platform API Endpoint"}},
|
|
235
|
+
"required": False,
|
|
236
|
+
"ui": {{"widget": "text", "group": "connection", "order": 1}},
|
|
237
|
+
}},
|
|
238
|
+
)
|
|
239
|
+
token: str = field(
|
|
240
|
+
default="",
|
|
241
|
+
metadata={{
|
|
242
|
+
"description": {{"i18n": "adapter.{name}.token", "default": "Platform Token"}},
|
|
243
|
+
"required": True,
|
|
244
|
+
"secret": True,
|
|
245
|
+
"ui": {{"widget": "password", "group": "basic", "order": 2}},
|
|
246
|
+
}},
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# {text[adapter.i18n_hint]}
|
|
250
|
+
class I18nClass(BaseI18n):
|
|
251
|
+
\"\"\"{name} translation keys\"\"\"
|
|
252
|
+
|
|
253
|
+
endpoint: I18nKey = I18nKey(
|
|
254
|
+
key="adapter.{name}.endpoint",
|
|
255
|
+
default="Platform API Endpoint",
|
|
256
|
+
zh_CN="平台 API 地址",
|
|
257
|
+
en="Platform API Endpoint",
|
|
258
|
+
ja="APIアドレス",
|
|
259
|
+
ru="API адрес",
|
|
260
|
+
zh_TW="API 位址",
|
|
261
|
+
)
|
|
262
|
+
token: I18nKey = I18nKey(
|
|
263
|
+
key="adapter.{name}.token",
|
|
264
|
+
default="Platform Token",
|
|
265
|
+
zh_CN="平台 Token",
|
|
266
|
+
en="Platform Token",
|
|
267
|
+
ja="トークン",
|
|
268
|
+
ru="Токен",
|
|
269
|
+
zh_TW="權杖",
|
|
270
|
+
)
|
|
257
271
|
|
|
258
272
|
def __init__(self, sdk=None):
|
|
259
|
-
super().__init__()
|
|
273
|
+
super().__init__(sdk=sdk)
|
|
274
|
+
self.logger = self._get_logger()
|
|
260
275
|
self.converter = self._setup_converter()
|
|
261
276
|
self.convert = self.converter.convert
|
|
262
277
|
|
|
278
|
+
def on_config_update(self, old_config, new_config):
|
|
279
|
+
\"\"\"Called when adapter config hot-reloads\"\"\"
|
|
280
|
+
self.logger.info("{text[adapter.log.config_updated]}")
|
|
281
|
+
|
|
263
282
|
def _setup_converter(self):
|
|
264
283
|
from .Converter import {converter_name}
|
|
265
284
|
return {converter_name}()
|
|
266
285
|
|
|
267
286
|
class Send(BaseAdapter.Send):
|
|
268
287
|
\"\"\"
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
At / AtAll / Reply / Using / To 由框架基类内置处理。
|
|
272
|
-
标准发送方法(Text/Image/Voice/Video/File)已从 SendDSL 基类继承,
|
|
273
|
-
默认委托给 Raw_ob12,无需重复实现。
|
|
274
|
-
使用 self._apply_modifiers(message) 合并修饰器到消息段。
|
|
275
|
-
使用 self.send_context 获取发送上下文 (target_type, target_id, account_id)。
|
|
276
|
-
|
|
277
|
-
支持链式调用:
|
|
278
|
-
Send.To("group", "123").At("456").Reply("789").Text("hi")
|
|
288
|
+
{text[adapter.dsl.send_doc]}
|
|
279
289
|
\"\"\"
|
|
280
290
|
|
|
281
291
|
def Raw_ob12(self, message, **kwargs):
|
|
@@ -289,22 +299,18 @@ class {name}(BaseAdapter):
|
|
|
289
299
|
)
|
|
290
300
|
return asyncio.create_task(_do_send())
|
|
291
301
|
|
|
292
|
-
#
|
|
293
|
-
#
|
|
302
|
+
# {text[adapter.dsl.send_std_methods_hint]}
|
|
303
|
+
# {text[adapter.dsl.send_override_hint]}
|
|
294
304
|
# def Text(self, text: str):
|
|
295
305
|
# return self.Raw_ob12([{{"type": "text", "data": {{"text": text}}}}])
|
|
296
306
|
|
|
297
|
-
#
|
|
307
|
+
# {text[adapter.dsl.send_extra_methods_hint]}
|
|
298
308
|
# def Sticker(self, sticker_id: str):
|
|
299
309
|
# return self.Raw_ob12([{{"type": "sticker", "data": {{"id": sticker_id}}}}])
|
|
300
310
|
|
|
301
311
|
class Request(BaseAdapter.Request):
|
|
302
312
|
\"\"\"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
适配器应重写 accept / reject 实现平台特定的请求处理逻辑。
|
|
306
|
-
如果平台不支持请求操作,可不实现此内部类。
|
|
307
|
-
基类默认返回 retcode=10002(不支持的操作)。
|
|
313
|
+
{text[adapter.dsl.request_doc]}
|
|
308
314
|
\"\"\"
|
|
309
315
|
|
|
310
316
|
async def _do_accept(self, **kwargs):
|
|
@@ -339,23 +345,34 @@ class {name}(BaseAdapter):
|
|
|
339
345
|
"message": result.get("message", ""),
|
|
340
346
|
}}
|
|
341
347
|
|
|
348
|
+
class Api(BaseAdapter.Api):
|
|
349
|
+
\"\"\"
|
|
350
|
+
{text[adapter.dsl.api_doc]}
|
|
351
|
+
\"\"\"
|
|
352
|
+
|
|
353
|
+
# {text[adapter.dsl.api_std_methods_hint]}
|
|
354
|
+
# {text[adapter.dsl.api_override_hint]}
|
|
355
|
+
# async def get_user_info(self, user_id: str) -> dict:
|
|
356
|
+
# raw = await self._adapter._request("GET", f"/users/{{user_id}}")
|
|
357
|
+
# return self._adapter.make_response(data={{...}}, raw=raw)
|
|
358
|
+
|
|
342
359
|
async def start(self):
|
|
343
|
-
\"\"\"
|
|
360
|
+
\"\"\"Start the adapter\"\"\"
|
|
344
361
|
cfg = self.cfg
|
|
345
|
-
self.logger.info(
|
|
362
|
+
self.logger.info("{text[adapter.log.starting]}")
|
|
346
363
|
|
|
347
364
|
router.register_websocket(
|
|
348
365
|
module_name="{entry_key}",
|
|
349
366
|
path="/ws",
|
|
350
367
|
handler=self._ws_handler,
|
|
351
368
|
)
|
|
352
|
-
self.logger.info("
|
|
369
|
+
self.logger.info("{text[adapter.log.ws_registered]}")
|
|
353
370
|
|
|
354
371
|
async def _ws_handler(self, websocket):
|
|
355
372
|
bot_id = self._get_bot_id()
|
|
356
373
|
|
|
357
374
|
await self.emit_meta("connect", bot_id, user_name="{name}")
|
|
358
|
-
self.logger.info(
|
|
375
|
+
self.logger.info("{text[adapter.log.bot_connected]}")
|
|
359
376
|
|
|
360
377
|
try:
|
|
361
378
|
while True:
|
|
@@ -365,18 +382,18 @@ class {name}(BaseAdapter):
|
|
|
365
382
|
if event:
|
|
366
383
|
await self.adapter.emit(event)
|
|
367
384
|
except Exception as e:
|
|
368
|
-
self.logger.warning(
|
|
385
|
+
self.logger.warning("{text[adapter.log.connection_lost]}")
|
|
369
386
|
finally:
|
|
370
387
|
await self.emit_meta("disconnect", bot_id)
|
|
371
|
-
self.logger.info(
|
|
388
|
+
self.logger.info("{text[adapter.log.bot_disconnected]}")
|
|
372
389
|
|
|
373
390
|
async def shutdown(self):
|
|
374
|
-
\"\"\"
|
|
391
|
+
\"\"\"Shut down the adapter\"\"\"
|
|
375
392
|
router.unregister_websocket("{entry_key}", "/ws")
|
|
376
|
-
self.logger.info("
|
|
393
|
+
self.logger.info("{text[adapter.log.shutdown]}")
|
|
377
394
|
|
|
378
395
|
async def call_api(self, endpoint: str, **params):
|
|
379
|
-
\"\"\"
|
|
396
|
+
\"\"\"Call platform API\"\"\"
|
|
380
397
|
from ErisPulse.Core import client
|
|
381
398
|
|
|
382
399
|
cfg = self.cfg
|
|
@@ -398,77 +415,51 @@ class {name}(BaseAdapter):
|
|
|
398
415
|
raw=result,
|
|
399
416
|
)
|
|
400
417
|
except Exception as e:
|
|
401
|
-
self.logger.error(
|
|
418
|
+
self.logger.error(("{text[adapter.log.api_call_failed]}").format(error=e))
|
|
402
419
|
return self.make_error(message=str(e))
|
|
403
420
|
"""
|
|
404
421
|
|
|
405
422
|
_ADAPTER_CONVERTER = """\"\"\"
|
|
406
|
-
{
|
|
407
|
-
|
|
408
|
-
将平台原生事件转换为 OneBot12 标准格式(正向转换)。
|
|
409
|
-
反向转换(发送方向)由适配器的 Send.Raw_ob12() 处理。
|
|
423
|
+
{text[adapter.converter_doc]}
|
|
410
424
|
\"\"\"
|
|
411
425
|
|
|
412
|
-
import
|
|
413
|
-
import uuid
|
|
426
|
+
from ErisPulse.Core.Bases import BaseConverter
|
|
414
427
|
|
|
415
428
|
|
|
416
|
-
class {converter_name}:
|
|
429
|
+
class {converter_name}(BaseConverter):
|
|
417
430
|
\"\"\"
|
|
418
|
-
{
|
|
431
|
+
{converter_name} converter class
|
|
419
432
|
|
|
420
|
-
|
|
421
|
-
|
|
433
|
+
Converts platform-specific event formats to the ErisPulse standard OneBot12 format.
|
|
434
|
+
Inherits BaseConverter to reuse common field construction (build_base_event)
|
|
435
|
+
and message-segment helpers (text/at/image).
|
|
422
436
|
\"\"\"
|
|
423
437
|
|
|
424
|
-
def
|
|
438
|
+
def __init__(self):
|
|
439
|
+
super().__init__(platform="{entry_key}")
|
|
440
|
+
|
|
441
|
+
def convert(self, raw_event: dict) -> dict | None:
|
|
425
442
|
\"\"\"
|
|
426
|
-
|
|
443
|
+
Convert a platform-native event to the OneBot12 standard format
|
|
427
444
|
|
|
428
|
-
:param raw_event:
|
|
429
|
-
:return: OneBot12
|
|
445
|
+
:param raw_event: raw platform event data
|
|
446
|
+
:return: OneBot12 event dict, or None if unrecognized
|
|
430
447
|
\"\"\"
|
|
431
448
|
if not isinstance(raw_event, dict):
|
|
432
449
|
return None
|
|
433
450
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
event = {{
|
|
438
|
-
"id": str(event_id),
|
|
439
|
-
"time": int(timestamp),
|
|
440
|
-
"type": self._convert_type(raw_event),
|
|
441
|
-
"detail_type": self._convert_detail_type(raw_event),
|
|
442
|
-
"platform": "{entry_key}",
|
|
443
|
-
"self": {{
|
|
444
|
-
"platform": "{entry_key}",
|
|
445
|
-
"user_id": str(raw_event.get("self_id", "")),
|
|
446
|
-
}},
|
|
447
|
-
"{entry_key}_raw": raw_event,
|
|
448
|
-
"{entry_key}_raw_type": raw_event.get("type", ""),
|
|
449
|
-
}}
|
|
450
|
-
|
|
451
|
-
if event["type"] == "message":
|
|
452
|
-
event["user_id"] = str(raw_event.get("sender_id", ""))
|
|
453
|
-
event["message"] = self._convert_message_segments(raw_event.get("content", ""))
|
|
454
|
-
event["alt_message"] = raw_event.get("content", "")
|
|
451
|
+
event_type = raw_event.get("type", "")
|
|
452
|
+
base = self.build_base_event(raw_event, event_type)
|
|
455
453
|
|
|
456
|
-
|
|
454
|
+
if event_type == "message":
|
|
455
|
+
base["type"] = "message"
|
|
456
|
+
base["detail_type"] = "private" if raw_event.get("is_private") else "group"
|
|
457
|
+
base["user_id"] = str(raw_event.get("sender_id", ""))
|
|
458
|
+
base["message"] = [self.text(raw_event.get("content", ""))]
|
|
459
|
+
base["alt_message"] = raw_event.get("content", "")
|
|
460
|
+
return base
|
|
457
461
|
|
|
458
|
-
|
|
459
|
-
event_type = raw_event.get("type", "")
|
|
460
|
-
type_map = {{
|
|
461
|
-
"chat": "message",
|
|
462
|
-
}}
|
|
463
|
-
return type_map.get(event_type, "unknown")
|
|
464
|
-
|
|
465
|
-
def _convert_detail_type(self, raw_event: dict) -> str:
|
|
466
|
-
return "private" if raw_event.get("is_private") else "group"
|
|
467
|
-
|
|
468
|
-
def _convert_message_segments(self, content) -> list:
|
|
469
|
-
if isinstance(content, str) and content:
|
|
470
|
-
return [{{"type": "text", "data": {{"text": content}}}}]
|
|
471
|
-
return []
|
|
462
|
+
return None
|
|
472
463
|
"""
|
|
473
464
|
|
|
474
465
|
_README_MODULE = """# {name}
|
|
@@ -478,7 +469,7 @@ _README_MODULE = """# {name}
|
|
|
478
469
|
## 安装
|
|
479
470
|
|
|
480
471
|
```bash
|
|
481
|
-
epsdk install {name}
|
|
472
|
+
epsdk install ErisPulse-{name}
|
|
482
473
|
```
|
|
483
474
|
|
|
484
475
|
## 使用
|
|
@@ -502,7 +493,7 @@ _README_ADAPTER = """# {name}
|
|
|
502
493
|
## 安装
|
|
503
494
|
|
|
504
495
|
```bash
|
|
505
|
-
epsdk install {name}
|
|
496
|
+
epsdk install ErisPulse-{name}
|
|
506
497
|
```
|
|
507
498
|
|
|
508
499
|
## 使用
|
|
@@ -570,6 +561,20 @@ def _validate_name(name: str) -> bool:
|
|
|
570
561
|
return all(c.isalnum() or c == "_" for c in name)
|
|
571
562
|
|
|
572
563
|
|
|
564
|
+
def _scaffold_text(name: str) -> dict:
|
|
565
|
+
"""
|
|
566
|
+
构建当前语言的脚手架文案映射,并预填充 {name} 占位符
|
|
567
|
+
|
|
568
|
+
:param name: [str] 模块/适配器名称
|
|
569
|
+
:return: [dict] ScaffoldText.all() 的文案字典(含占位符替换)
|
|
570
|
+
"""
|
|
571
|
+
st = ScaffoldText()
|
|
572
|
+
return {
|
|
573
|
+
key: (value.replace("{name}", name) if value else value)
|
|
574
|
+
for key, value in st.all().items()
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
573
578
|
class CreateCommand(Command):
|
|
574
579
|
"""
|
|
575
580
|
create 命令
|
|
@@ -709,7 +714,8 @@ class CreateCommand(Command):
|
|
|
709
714
|
|
|
710
715
|
(pkg_dir / "__init__.py").write_text(_MODULE_INIT, encoding="utf-8")
|
|
711
716
|
(pkg_dir / "Core.py").write_text(
|
|
712
|
-
_MODULE_CORE.format(name=name
|
|
717
|
+
_MODULE_CORE.format(name=name, text=_scaffold_text(name)),
|
|
718
|
+
encoding="utf-8",
|
|
713
719
|
)
|
|
714
720
|
(project_dir / "pyproject.toml").write_text(
|
|
715
721
|
_MODULE_PYPROJECT.format(
|
|
@@ -807,13 +813,19 @@ class CreateCommand(Command):
|
|
|
807
813
|
)
|
|
808
814
|
(pkg_dir / "Core.py").write_text(
|
|
809
815
|
_ADAPTER_CORE.format(
|
|
810
|
-
name=name,
|
|
816
|
+
name=name,
|
|
817
|
+
converter_name=converter_name,
|
|
818
|
+
entry_key=entry_key,
|
|
819
|
+
text=_scaffold_text(name),
|
|
811
820
|
),
|
|
812
821
|
encoding="utf-8",
|
|
813
822
|
)
|
|
814
823
|
(pkg_dir / "Converter.py").write_text(
|
|
815
824
|
_ADAPTER_CONVERTER.format(
|
|
816
|
-
name=name,
|
|
825
|
+
name=name,
|
|
826
|
+
converter_name=converter_name,
|
|
827
|
+
entry_key=entry_key,
|
|
828
|
+
text=_scaffold_text(name),
|
|
817
829
|
),
|
|
818
830
|
encoding="utf-8",
|
|
819
831
|
)
|