ErisPulse 2.10.1__tar.gz → 2.11.0.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.
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/PKG-INFO +3 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/pyproject.toml +4 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/base.py +3 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/cli.py +62 -3
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/config.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/create.py +306 -6
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/doctor.py +127 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/init.py +86 -13
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/install.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/language.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/list.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/list_remote.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/run.py +185 -31
- erispulse-2.11.0.dev0/src/ErisPulse/CLI/commands/runtime.py +153 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/self_update.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/types.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/uninstall.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/upgrade.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/version.py +1 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/en.py +50 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/ja.py +50 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/ru.py +50 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +50 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +50 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/config_wizard.py +7 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/package_manager.py +7 -6
- erispulse-2.11.0.dev0/src/ErisPulse/CLI/utils/runtime_state.py +208 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/scaffold_text.py +18 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/adapter.py +1 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/config_schema.py +68 -7
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/module.py +3 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/__init__.py +2 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/base.py +8 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/command.py +17 -1
- erispulse-2.11.0.dev0/src/ErisPulse/Core/Event/command_flow.py +348 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/wrapper.py +5 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/adapter.py +49 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/assets/error.css +20 -10
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/assets/root.css +23 -13
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/config.py +299 -101
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/constants.py +48 -4
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/en.py +29 -11
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/ja.py +29 -11
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/ru.py +29 -11
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_cn.py +29 -11
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_tw.py +29 -11
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/lifecycle.py +2 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/module.py +541 -36
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/router.py +0 -16
- erispulse-2.11.0.dev0/src/ErisPulse/loaders/adapter.py +907 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/module.py +378 -37
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/plugin_folder.py +203 -7
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/example_config.py +5 -1
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/sdk_initializer.py +4 -2
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/sdk.py +102 -213
- erispulse-2.10.1/src/ErisPulse/loaders/adapter.py +0 -356
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/.gitignore +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/LICENSE +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/README.pypi.md +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/console.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/constants.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/hints.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/registry.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/display.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/CLI/utils/interactive.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/api_dsl.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/client.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/converter.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/errors.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/manager.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/model.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/router.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/sql_base.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/storage.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Bases/websocket.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/command_args.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/conversation.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/governance.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/interaction.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/message.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/meta.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/notice.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/overrides.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/request.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/throttle.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/Event/trace.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/assets/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/assets/error.html +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/assets/root.html +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/client.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/connections.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/di.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/constants.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/logger.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/master.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/ownership.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/scope.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/shadow.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/storage/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/storage/mysql.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/storage/postgres.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/storage/sqlite.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/text_match.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/Core/transcript.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/__main__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/finders/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/finders/adapter.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/finders/bases/finder.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/finders/module.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/bases/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/bases/loader.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/strategy.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/loaders/strict.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/py.typed +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/__init__.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/config_schema.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/context.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/diagnostics.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/exceptions.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/file_watcher.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/frame_config.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/hints.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/memory.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/owner_cleanup.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/plugin_reload.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/proactive_gc.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/tasks.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/troubleshoot.py +0 -0
- {erispulse-2.10.1 → erispulse-2.11.0.dev0}/src/ErisPulse/runtime/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ErisPulse
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0-dev.0
|
|
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
|
|
@@ -33,7 +33,7 @@ Requires-Dist: aiohttp>=3.9.0
|
|
|
33
33
|
Requires-Dist: aiosqlite>=0.20.0
|
|
34
34
|
Requires-Dist: fastapi>=0.116.1
|
|
35
35
|
Requires-Dist: rich>=13.0.0
|
|
36
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: tomlclass<0.4,>=0.3.2
|
|
37
37
|
Requires-Dist: uvicorn<1.0,>=0.35.0
|
|
38
38
|
Requires-Dist: websockets>=12.0
|
|
39
39
|
Provides-Extra: mysql
|
|
@@ -49,6 +49,7 @@ Requires-Dist: pytest-mock>=3.10.0; extra == 'test'
|
|
|
49
49
|
Requires-Dist: pytest-timeout>=2.1.0; extra == 'test'
|
|
50
50
|
Requires-Dist: pytest-xdist>=3.0.0; extra == 'test'
|
|
51
51
|
Requires-Dist: pytest>=7.0.0; extra == 'test'
|
|
52
|
+
Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'test'
|
|
52
53
|
Description-Content-Type: text/markdown
|
|
53
54
|
|
|
54
55
|
# ErisPulse
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ErisPulse"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.11.0-dev.0"
|
|
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"
|
|
@@ -62,7 +62,8 @@ classifiers = [
|
|
|
62
62
|
|
|
63
63
|
dependencies = [
|
|
64
64
|
"rich>=13.0.0",
|
|
65
|
-
"
|
|
65
|
+
"tomlclass>=0.3.2,<0.4",
|
|
66
|
+
|
|
66
67
|
# network 相关
|
|
67
68
|
"websockets>=12.0",
|
|
68
69
|
"aiohttp>=3.9.0",
|
|
@@ -102,6 +103,7 @@ test = [
|
|
|
102
103
|
"pytest-timeout>=2.1.0",
|
|
103
104
|
"pytest-mock>=3.10.0",
|
|
104
105
|
"httpx>=0.24.0",
|
|
106
|
+
"tomli>=2.0.0; python_version < '3.11'",
|
|
105
107
|
]
|
|
106
108
|
|
|
107
109
|
[dependency-groups]
|
|
@@ -18,13 +18,15 @@ class Command(ABC):
|
|
|
18
18
|
1. 每个命令类必须实现 add_arguments 和 execute 方法
|
|
19
19
|
2. name 和 description 为类属性,必须在子类中定义
|
|
20
20
|
3. aliases 为可选类属性,用于定义命令的简化形式
|
|
21
|
-
4.
|
|
21
|
+
4. category 为可选类属性,决定主帮助分组表中的归类
|
|
22
|
+
5. execute 方法接收解析后的 args 对象
|
|
22
23
|
{!--< /tips >!--}
|
|
23
24
|
"""
|
|
24
25
|
|
|
25
26
|
name: str = "" # 命令名称
|
|
26
27
|
description: str = "" # 命令描述
|
|
27
28
|
aliases: list = [] # 命令别名(简化形式,如 "install" -> ["i", "add"])
|
|
29
|
+
category: str = "" # 主帮助分组类别标识(project/components/config/misc;空串归入 misc)
|
|
28
30
|
|
|
29
31
|
@abstractmethod
|
|
30
32
|
def add_arguments(self, parser: ArgumentParser):
|
|
@@ -168,6 +168,65 @@ class CLI:
|
|
|
168
168
|
)
|
|
169
169
|
)
|
|
170
170
|
|
|
171
|
+
# 主帮助分组表展示顺序(未列出的类别按注册顺序附在末尾)
|
|
172
|
+
_HELP_CATEGORY_ORDER = ("project", "components", "config", "misc")
|
|
173
|
+
|
|
174
|
+
def _print_grouped_help(self) -> None:
|
|
175
|
+
"""
|
|
176
|
+
按类别分组打印主帮助(Rich 表格渲染)
|
|
177
|
+
|
|
178
|
+
取代 argparse 默认的子命令平铺列表:命令按 category 归类展示
|
|
179
|
+
(名称 + 别名 + 描述),全局选项从 ``parser._actions`` 实时遍历
|
|
180
|
+
生成避免与实际参数漂移。子命令级 ``--help`` 保持 argparse 原样。
|
|
181
|
+
"""
|
|
182
|
+
from rich.table import Table
|
|
183
|
+
|
|
184
|
+
if self.parser.description:
|
|
185
|
+
console.print(f"[bold]{self.parser.description}[/]\n")
|
|
186
|
+
console.print(f"[dim]{self.parser.format_usage().strip()}[/]\n")
|
|
187
|
+
|
|
188
|
+
groups: dict[str, list[Command]] = {}
|
|
189
|
+
for command in self.registry.get_all():
|
|
190
|
+
groups.setdefault(command.category or "misc", []).append(command)
|
|
191
|
+
|
|
192
|
+
ordered = list(self._HELP_CATEGORY_ORDER) + [
|
|
193
|
+
cat for cat in groups if cat not in self._HELP_CATEGORY_ORDER
|
|
194
|
+
]
|
|
195
|
+
table = Table(show_header=False, box=None, pad_edge=False, expand=True)
|
|
196
|
+
table.add_column(min_width=18)
|
|
197
|
+
table.add_column(ratio=1)
|
|
198
|
+
for cat in ordered:
|
|
199
|
+
commands = groups.get(cat)
|
|
200
|
+
if not commands:
|
|
201
|
+
continue
|
|
202
|
+
table.add_row(
|
|
203
|
+
f"[title]{i18n.t(f'cli.help.category.{cat}')}[/]", ""
|
|
204
|
+
)
|
|
205
|
+
for command in sorted(commands, key=lambda c: c.name):
|
|
206
|
+
aliases = getattr(command, "aliases", None) or []
|
|
207
|
+
name_text = command.name + (
|
|
208
|
+
f" [dim]({', '.join(aliases)})[/]" if aliases else ""
|
|
209
|
+
)
|
|
210
|
+
table.add_row(f" [cmd]{name_text}[/]", command.description)
|
|
211
|
+
console.print(table)
|
|
212
|
+
|
|
213
|
+
option_lines: list[tuple[str, str]] = []
|
|
214
|
+
for action in self.parser._actions:
|
|
215
|
+
if not action.option_strings:
|
|
216
|
+
continue
|
|
217
|
+
option_lines.append(
|
|
218
|
+
(", ".join(action.option_strings), action.help or "")
|
|
219
|
+
)
|
|
220
|
+
if option_lines:
|
|
221
|
+
width = max(len(opts) for opts, _ in option_lines)
|
|
222
|
+
console.print(f"\n[title]{i18n.t('cli.parser.optionals_title')}[/]")
|
|
223
|
+
for opts, help_text in option_lines:
|
|
224
|
+
console.print(f" [cmd]{opts.ljust(width)}[/] {help_text}")
|
|
225
|
+
|
|
226
|
+
console.print(
|
|
227
|
+
f"\n[dim]{i18n.t('cli.run.quickstart.run_help_hint')}[/]"
|
|
228
|
+
)
|
|
229
|
+
|
|
171
230
|
def _print_quickstart(self) -> None:
|
|
172
231
|
"""
|
|
173
232
|
打印 Quick Start 面板
|
|
@@ -248,7 +307,7 @@ class CLI:
|
|
|
248
307
|
console.print(
|
|
249
308
|
f"[error]{i18n.t('cli.run.unknown_command', command=cmd)}[/]"
|
|
250
309
|
)
|
|
251
|
-
self.
|
|
310
|
+
self._print_grouped_help()
|
|
252
311
|
sys.exit(1)
|
|
253
312
|
|
|
254
313
|
def _maybe_show_language_hint(self) -> None:
|
|
@@ -336,7 +395,7 @@ class CLI:
|
|
|
336
395
|
f"[warning]{i18n.t('cli.run.unknown_args', args=' '.join(unknown))}[/]"
|
|
337
396
|
)
|
|
338
397
|
self._print_quickstart()
|
|
339
|
-
self.
|
|
398
|
+
self._print_grouped_help()
|
|
340
399
|
return
|
|
341
400
|
|
|
342
401
|
# 将别名解析为规范命令名
|
|
@@ -373,7 +432,7 @@ class CLI:
|
|
|
373
432
|
console.print(
|
|
374
433
|
f"[error]{i18n.t('cli.run.unknown_command', command=args.command)}[/]"
|
|
375
434
|
)
|
|
376
|
-
self.
|
|
435
|
+
self._print_grouped_help()
|
|
377
436
|
sys.exit(1)
|
|
378
437
|
|
|
379
438
|
except KeyboardInterrupt:
|
|
@@ -5,6 +5,7 @@ Create 命令实现
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import datetime
|
|
8
|
+
import shutil
|
|
8
9
|
import sys
|
|
9
10
|
from argparse import ArgumentParser
|
|
10
11
|
from pathlib import Path
|
|
@@ -76,6 +77,33 @@ packages = ["{name}"]
|
|
|
76
77
|
_MODULE_INIT = """from .Core import Main
|
|
77
78
|
"""
|
|
78
79
|
|
|
80
|
+
# pack 转换用:entry-point 组与类名按插件类型动态生成
|
|
81
|
+
_PACK_PYPROJECT = """[project]
|
|
82
|
+
name = "{pypi_name}"
|
|
83
|
+
version = "1.0.0"
|
|
84
|
+
description = "{description}"
|
|
85
|
+
readme = "README.md"
|
|
86
|
+
requires-python = ">=3.10"
|
|
87
|
+
license = {{ file = "LICENSE" }}
|
|
88
|
+
authors = [ {{ name = "{author}", email = "{email}" }} ]
|
|
89
|
+
|
|
90
|
+
dependencies = [
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[project.urls]
|
|
94
|
+
"homepage" = "{homepage}"
|
|
95
|
+
|
|
96
|
+
[project.entry-points]
|
|
97
|
+
"{group}" = {{ "{entry_key}" = "{name}:{class_name}" }}
|
|
98
|
+
|
|
99
|
+
[build-system]
|
|
100
|
+
requires = ["hatchling"]
|
|
101
|
+
build-backend = "hatchling.build"
|
|
102
|
+
|
|
103
|
+
[tool.hatch.build.targets.wheel]
|
|
104
|
+
packages = ["{name}"]
|
|
105
|
+
"""
|
|
106
|
+
|
|
79
107
|
_MODULE_CORE = """from dataclasses import dataclass, field
|
|
80
108
|
|
|
81
109
|
from ErisPulse import (
|
|
@@ -207,8 +235,13 @@ class Main(BaseModule):
|
|
|
207
235
|
group=\"default\",
|
|
208
236
|
tags=[\"{name}\"],
|
|
209
237
|
# 对外服务白名单(可选):声明后其他模块可经 sdk.module.call() 调用这些方法;
|
|
210
|
-
# 缺省时公开方法全开放(限制由用户通过 scope.actions
|
|
211
|
-
# services
|
|
238
|
+
# 缺省时公开方法全开放(限制由用户通过 scope.actions 配置)。
|
|
239
|
+
# dict 形态可声明 description 与 parameters 参数提示(供 sdk.module.services()
|
|
240
|
+
# 服务目录 / AI 智能体消费);未声明的参数自动取方法 docstring 的 :param: 行
|
|
241
|
+
# services=[
|
|
242
|
+
# "get_welcome_message",
|
|
243
|
+
# {{"name": "render", "description": "渲染", "parameters": {{"html": "HTML 文本"}}}},
|
|
244
|
+
# ],
|
|
212
245
|
)
|
|
213
246
|
|
|
214
247
|
@staticmethod
|
|
@@ -561,6 +594,7 @@ class {name}(BaseAdapter):
|
|
|
561
594
|
return self.make_error(message=str(e))
|
|
562
595
|
"""
|
|
563
596
|
|
|
597
|
+
|
|
564
598
|
_ADAPTER_CONVERTER = """\"\"\"
|
|
565
599
|
{text[adapter.converter_doc]}
|
|
566
600
|
\"\"\"
|
|
@@ -760,12 +794,13 @@ class CreateCommand(Command):
|
|
|
760
794
|
name = "create"
|
|
761
795
|
description = i18n.t("cli.create.description")
|
|
762
796
|
aliases = ["c", "new"]
|
|
797
|
+
category = "project"
|
|
763
798
|
|
|
764
799
|
def add_arguments(self, parser: ArgumentParser):
|
|
765
800
|
parser.add_argument(
|
|
766
801
|
"create_type",
|
|
767
802
|
nargs="?",
|
|
768
|
-
choices=["module", "adapter"],
|
|
803
|
+
choices=["module", "adapter", "pack"],
|
|
769
804
|
help=i18n.t("cli.create.type_help"),
|
|
770
805
|
)
|
|
771
806
|
parser.add_argument("--name", "-n", help=i18n.t("cli.create.name_help"))
|
|
@@ -791,7 +826,7 @@ class CreateCommand(Command):
|
|
|
791
826
|
"--local",
|
|
792
827
|
action="store_true",
|
|
793
828
|
default=False,
|
|
794
|
-
help=i18n.t("cli.create.
|
|
829
|
+
help=i18n.t("cli.create.local_help"),
|
|
795
830
|
)
|
|
796
831
|
|
|
797
832
|
def execute(self, args):
|
|
@@ -799,6 +834,11 @@ class CreateCommand(Command):
|
|
|
799
834
|
if not create_type:
|
|
800
835
|
create_type = self._interactive_select_type()
|
|
801
836
|
|
|
837
|
+
# pack:本地插件 → 可发布项目(无需组件名,直接进入转换流程)
|
|
838
|
+
if create_type == "pack":
|
|
839
|
+
self._create_pack(args)
|
|
840
|
+
return
|
|
841
|
+
|
|
802
842
|
default_name = "MyModule" if create_type == "module" else "MyAdapter"
|
|
803
843
|
name = args.name
|
|
804
844
|
# 名称校验:非法时保留输入并重新提示,而非直接退出
|
|
@@ -828,12 +868,15 @@ class CreateCommand(Command):
|
|
|
828
868
|
console.print(
|
|
829
869
|
f" [bold]2.[/] Adapter [dim]{i18n.t('cli.create.select_type_adapter')}[/]"
|
|
830
870
|
)
|
|
871
|
+
console.print(
|
|
872
|
+
f" [bold]3.[/] Pack [dim]{i18n.t('cli.create.select_type_pack')}[/]"
|
|
873
|
+
)
|
|
831
874
|
console.print()
|
|
832
875
|
choice = IntPrompt.ask(
|
|
833
|
-
i18n.t("cli.create.select_prompt"), default=1, choices=["1", "2"]
|
|
876
|
+
i18n.t("cli.create.select_prompt"), default=1, choices=["1", "2", "3"]
|
|
834
877
|
)
|
|
835
878
|
console.print()
|
|
836
|
-
return "module"
|
|
879
|
+
return ("module", "adapter", "pack")[choice - 1]
|
|
837
880
|
|
|
838
881
|
def _ask_missing(
|
|
839
882
|
self, args, field_name: str, prompt_text: str, default: str = ""
|
|
@@ -852,6 +895,184 @@ class CreateCommand(Command):
|
|
|
852
895
|
val = Prompt.ask(f" {prompt_text}", default=default)
|
|
853
896
|
return val
|
|
854
897
|
|
|
898
|
+
def _create_pack(self, args):
|
|
899
|
+
"""
|
|
900
|
+
将本地插件(plugins/ 目录)转换为可发布的标准项目结构
|
|
901
|
+
|
|
902
|
+
交互式选择插件目录中的插件,识别类型(模块/适配器)后输入包元信息,
|
|
903
|
+
输出含 pyproject.toml(entry-point 按插件类型生成)与插件源码的完整
|
|
904
|
+
项目目录,可直接 ``pip install -e .`` 或打包发布。
|
|
905
|
+
|
|
906
|
+
:param args: [Any] 解析后的命令参数对象
|
|
907
|
+
:return: [None] 无返回值
|
|
908
|
+
"""
|
|
909
|
+
from ErisPulse.loaders.plugin_folder import PluginFolderLoader
|
|
910
|
+
|
|
911
|
+
# 1. 收集插件目录中的候选插件
|
|
912
|
+
loader = PluginFolderLoader()
|
|
913
|
+
candidates: list[tuple[str, Path]] = []
|
|
914
|
+
for base in loader.get_plugins_dirs():
|
|
915
|
+
if not base.is_dir():
|
|
916
|
+
continue
|
|
917
|
+
for entry in sorted(base.iterdir()):
|
|
918
|
+
plugin_name = PluginFolderLoader._plugin_name_of(entry)
|
|
919
|
+
if plugin_name is not None:
|
|
920
|
+
candidates.append((plugin_name, entry))
|
|
921
|
+
|
|
922
|
+
if not candidates:
|
|
923
|
+
console.print(f"[error] {i18n.t('cli.create.pack_no_plugins')}")
|
|
924
|
+
sys.exit(1)
|
|
925
|
+
|
|
926
|
+
# 2. 选择插件:--name 直选,否则交互编号选择
|
|
927
|
+
plugin_name = getattr(args, "name", None)
|
|
928
|
+
selected = next((c for c in candidates if c[0] == plugin_name), None)
|
|
929
|
+
if selected is None:
|
|
930
|
+
if plugin_name:
|
|
931
|
+
console.print(
|
|
932
|
+
f"[error] {i18n.t('cli.create.pack_not_found', name=plugin_name)}"
|
|
933
|
+
)
|
|
934
|
+
sys.exit(1)
|
|
935
|
+
console.print(Text(i18n.t("cli.create.pack_select_title"), style="bold"))
|
|
936
|
+
for i, (name, path) in enumerate(candidates, start=1):
|
|
937
|
+
console.print(f" [bold]{i}.[/] {name} [dim]{path}[/]")
|
|
938
|
+
console.print()
|
|
939
|
+
choice = IntPrompt.ask(
|
|
940
|
+
i18n.t("cli.create.pack_select_prompt"),
|
|
941
|
+
default=1,
|
|
942
|
+
choices=[str(i) for i in range(1, len(candidates) + 1)],
|
|
943
|
+
)
|
|
944
|
+
selected = candidates[choice - 1]
|
|
945
|
+
console.print()
|
|
946
|
+
|
|
947
|
+
plugin_name, plugin_path = selected
|
|
948
|
+
|
|
949
|
+
# 3. 导入插件并识别类型
|
|
950
|
+
try:
|
|
951
|
+
module_obj = loader._import_plugin(plugin_name, plugin_path)
|
|
952
|
+
except Exception as e:
|
|
953
|
+
console.print(f"[error] {i18n.t('cli.create.failed', error=e)}")
|
|
954
|
+
sys.exit(1)
|
|
955
|
+
module_class = PluginFolderLoader._find_module_class(module_obj)
|
|
956
|
+
adapter_class = PluginFolderLoader._find_adapter_class(module_obj)
|
|
957
|
+
if module_class is not None:
|
|
958
|
+
class_name = module_class.__name__
|
|
959
|
+
group = "erispulse.module"
|
|
960
|
+
kind_label = "module"
|
|
961
|
+
elif adapter_class is not None:
|
|
962
|
+
class_name = adapter_class.__name__
|
|
963
|
+
group = "erispulse.adapter"
|
|
964
|
+
kind_label = "adapter"
|
|
965
|
+
else:
|
|
966
|
+
console.print(
|
|
967
|
+
f"[error] {i18n.t('cli.create.pack_unknown_kind', name=plugin_name)}"
|
|
968
|
+
)
|
|
969
|
+
sys.exit(1)
|
|
970
|
+
console.print(
|
|
971
|
+
f"[success] {i18n.t('cli.create.pack_detected', name=plugin_name, kind=kind_label, cls=class_name)}"
|
|
972
|
+
)
|
|
973
|
+
|
|
974
|
+
# 4. 元信息(项目名默认插件名,经组件名校验)
|
|
975
|
+
project_name = prompt_validated(
|
|
976
|
+
i18n.t("cli.create.pack_project_prompt"),
|
|
977
|
+
default=plugin_name,
|
|
978
|
+
validate=_validate_name,
|
|
979
|
+
error_msg=i18n.t("cli.create.name_error"),
|
|
980
|
+
)
|
|
981
|
+
description = self._ask_missing(
|
|
982
|
+
args,
|
|
983
|
+
"description",
|
|
984
|
+
i18n.t("cli.create.pack_desc_prompt"),
|
|
985
|
+
i18n.t("cli.create.pack_desc_placeholder", name=project_name),
|
|
986
|
+
)
|
|
987
|
+
author = self._ask_missing(args, "author", i18n.t("cli.create.author_prompt"), "yourname")
|
|
988
|
+
email = self._ask_missing(args, "email", i18n.t("cli.create.email_prompt"), "your@mail.com")
|
|
989
|
+
homepage = self._ask_missing(
|
|
990
|
+
args,
|
|
991
|
+
"homepage",
|
|
992
|
+
i18n.t("cli.create.homepage_prompt"),
|
|
993
|
+
f"https://github.com/{author}/{project_name}",
|
|
994
|
+
)
|
|
995
|
+
entry_key = _camel_to_snake(project_name)
|
|
996
|
+
|
|
997
|
+
output = Path(args.output)
|
|
998
|
+
project_dir = output / project_name
|
|
999
|
+
if project_dir.exists() and not args.force:
|
|
1000
|
+
console.print(
|
|
1001
|
+
f"[error] {i18n.t('cli.create.dir_exists', dir=str(project_dir))}"
|
|
1002
|
+
)
|
|
1003
|
+
sys.exit(1)
|
|
1004
|
+
|
|
1005
|
+
# 5. 生成项目:源码拷贝 + pyproject(entry-point 按类型)+ LICENSE/README
|
|
1006
|
+
try:
|
|
1007
|
+
pkg_dir = project_dir / project_name
|
|
1008
|
+
pkg_dir.mkdir(parents=True, exist_ok=True)
|
|
1009
|
+
|
|
1010
|
+
if plugin_path.is_file():
|
|
1011
|
+
# 单文件插件 → 包内模块 + __init__ 导出
|
|
1012
|
+
(pkg_dir / "__init__.py").write_text(
|
|
1013
|
+
f"from .{plugin_path.stem} import {class_name}\n",
|
|
1014
|
+
encoding="utf-8",
|
|
1015
|
+
)
|
|
1016
|
+
shutil.copy2(plugin_path, pkg_dir / plugin_path.name)
|
|
1017
|
+
else:
|
|
1018
|
+
shutil.copytree(
|
|
1019
|
+
plugin_path,
|
|
1020
|
+
pkg_dir,
|
|
1021
|
+
dirs_exist_ok=True,
|
|
1022
|
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
|
1023
|
+
)
|
|
1024
|
+
|
|
1025
|
+
(project_dir / "pyproject.toml").write_text(
|
|
1026
|
+
_PACK_PYPROJECT.format(
|
|
1027
|
+
name=project_name,
|
|
1028
|
+
pypi_name=f"ErisPulse-{project_name}",
|
|
1029
|
+
description=description,
|
|
1030
|
+
author=author,
|
|
1031
|
+
email=email,
|
|
1032
|
+
homepage=homepage,
|
|
1033
|
+
group=group,
|
|
1034
|
+
entry_key=entry_key,
|
|
1035
|
+
class_name=class_name,
|
|
1036
|
+
),
|
|
1037
|
+
encoding="utf-8",
|
|
1038
|
+
)
|
|
1039
|
+
(project_dir / "LICENSE").write_text(
|
|
1040
|
+
_LICENSE_TEMPLATE.format(
|
|
1041
|
+
year=str(datetime.datetime.now().year), author=author
|
|
1042
|
+
),
|
|
1043
|
+
encoding="utf-8",
|
|
1044
|
+
)
|
|
1045
|
+
readme_tpl = _README_MODULE if module_class is not None else _README_ADAPTER
|
|
1046
|
+
readme_kwargs = {"name": project_name, "description": description}
|
|
1047
|
+
if module_class is None:
|
|
1048
|
+
readme_kwargs["name_snake"] = entry_key
|
|
1049
|
+
(project_dir / "README.md").write_text(
|
|
1050
|
+
readme_tpl.format(**readme_kwargs),
|
|
1051
|
+
encoding="utf-8",
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1054
|
+
console.print()
|
|
1055
|
+
console.print(
|
|
1056
|
+
f"[success] {i18n.t('cli.create.pack_created', name=plugin_name, dir=str(project_dir))}[/]"
|
|
1057
|
+
)
|
|
1058
|
+
console.print()
|
|
1059
|
+
console.print(Text(i18n.t("cli.create.project_structure"), style="bold"))
|
|
1060
|
+
console.print(f" {project_name}/")
|
|
1061
|
+
console.print(" ├── pyproject.toml")
|
|
1062
|
+
console.print(" ├── LICENSE")
|
|
1063
|
+
console.print(" ├── README.md")
|
|
1064
|
+
console.print(f" └── {project_name}/ [dim]({plugin_path})[/]")
|
|
1065
|
+
console.print()
|
|
1066
|
+
console.print(Text(i18n.t("cli.create.next_steps"), style="bold"))
|
|
1067
|
+
console.print(f" · {i18n.t('cli.create.cd_to', dir=project_name)}")
|
|
1068
|
+
console.print(f" · {i18n.t('cli.create.install_dev')}")
|
|
1069
|
+
console.print(f" · {i18n.t('cli.create.run_test')}")
|
|
1070
|
+
console.print(f" · {i18n.t('cli.create.pack_remove_hint', name=plugin_name)}")
|
|
1071
|
+
|
|
1072
|
+
except Exception as e:
|
|
1073
|
+
console.print(f"[error] {i18n.t('cli.create.failed', error=e)}")
|
|
1074
|
+
sys.exit(1)
|
|
1075
|
+
|
|
855
1076
|
def _create_module(self, args, name: str):
|
|
856
1077
|
"""
|
|
857
1078
|
创建 Module 项目脚手架
|
|
@@ -999,6 +1220,80 @@ class CreateCommand(Command):
|
|
|
999
1220
|
console.print(f"[error] {i18n.t('cli.create.failed', error=e)}")
|
|
1000
1221
|
sys.exit(1)
|
|
1001
1222
|
|
|
1223
|
+
def _create_adapter_local(self, args, name: str):
|
|
1224
|
+
"""
|
|
1225
|
+
创建本地适配器插件(--local):生成 plugins/ 目录结构,免打包安装
|
|
1226
|
+
|
|
1227
|
+
:param args: [Any] 解析后的命令参数对象
|
|
1228
|
+
:param name: [str] 适配器名称
|
|
1229
|
+
:return: [None] 无返回值
|
|
1230
|
+
"""
|
|
1231
|
+
output = Path(args.output)
|
|
1232
|
+
plugins_dir = output / "plugins"
|
|
1233
|
+
plugin_dir = plugins_dir / name
|
|
1234
|
+
|
|
1235
|
+
if plugin_dir.exists() and not args.force:
|
|
1236
|
+
console.print(
|
|
1237
|
+
f"[error] {i18n.t('cli.create.dir_exists', dir=str(plugin_dir))}"
|
|
1238
|
+
)
|
|
1239
|
+
sys.exit(1)
|
|
1240
|
+
|
|
1241
|
+
try:
|
|
1242
|
+
plugin_dir.mkdir(parents=True, exist_ok=True)
|
|
1243
|
+
|
|
1244
|
+
converter_name = _to_converter_name(name)
|
|
1245
|
+
entry_key = _camel_to_snake(name)
|
|
1246
|
+
|
|
1247
|
+
(plugin_dir / "__init__.py").write_text(
|
|
1248
|
+
_ADAPTER_INIT.format(name=name, converter_name=converter_name),
|
|
1249
|
+
encoding="utf-8",
|
|
1250
|
+
)
|
|
1251
|
+
(plugin_dir / "Core.py").write_text(
|
|
1252
|
+
_ADAPTER_CORE.format(
|
|
1253
|
+
name=name,
|
|
1254
|
+
converter_name=converter_name,
|
|
1255
|
+
entry_key=entry_key,
|
|
1256
|
+
text=_scaffold_text(name),
|
|
1257
|
+
min_sdk=_TEMPLATE_MIN_SDK_VERSION,
|
|
1258
|
+
),
|
|
1259
|
+
encoding="utf-8",
|
|
1260
|
+
)
|
|
1261
|
+
(plugin_dir / "Converter.py").write_text(
|
|
1262
|
+
_ADAPTER_CONVERTER.format(
|
|
1263
|
+
name=name,
|
|
1264
|
+
converter_name=converter_name,
|
|
1265
|
+
entry_key=entry_key,
|
|
1266
|
+
text=_scaffold_text(name),
|
|
1267
|
+
),
|
|
1268
|
+
encoding="utf-8",
|
|
1269
|
+
)
|
|
1270
|
+
|
|
1271
|
+
console.print()
|
|
1272
|
+
console.print(
|
|
1273
|
+
f"[success] {i18n.t('cli.create.adapter_created', name=name)}[/]"
|
|
1274
|
+
)
|
|
1275
|
+
console.print()
|
|
1276
|
+
console.print(Text(i18n.t("cli.create.local_structure"), style="bold"))
|
|
1277
|
+
console.print(" plugins/")
|
|
1278
|
+
console.print(f" └── {name}/")
|
|
1279
|
+
console.print(" ├── __init__.py")
|
|
1280
|
+
console.print(" ├── Core.py")
|
|
1281
|
+
console.print(" └── Converter.py")
|
|
1282
|
+
console.print()
|
|
1283
|
+
console.print(Text(i18n.t("cli.create.next_steps"), style="bold"))
|
|
1284
|
+
console.print(f" · {i18n.t('cli.create.cd_to', dir=str(plugin_dir))}")
|
|
1285
|
+
console.print(
|
|
1286
|
+
f" · {i18n.t('cli.create.edit_adapter', file=str(plugin_dir) + '/Core.py')}"
|
|
1287
|
+
)
|
|
1288
|
+
console.print(
|
|
1289
|
+
f" · {i18n.t('cli.create.edit_converter', file=str(plugin_dir) + '/Converter.py')}"
|
|
1290
|
+
)
|
|
1291
|
+
console.print(f" · {i18n.t('cli.create.local_tip')}")
|
|
1292
|
+
|
|
1293
|
+
except Exception as e:
|
|
1294
|
+
console.print(f"[error] {i18n.t('cli.create.failed', error=e)}")
|
|
1295
|
+
sys.exit(1)
|
|
1296
|
+
|
|
1002
1297
|
def _create_adapter(self, args, name: str):
|
|
1003
1298
|
"""
|
|
1004
1299
|
创建 Adapter 项目脚手架
|
|
@@ -1007,6 +1302,11 @@ class CreateCommand(Command):
|
|
|
1007
1302
|
:param name: [str] 适配器名称
|
|
1008
1303
|
:return: [None] 无返回值
|
|
1009
1304
|
"""
|
|
1305
|
+
# --local:创建本地适配器插件(plugins/ 目录结构,免打包安装)
|
|
1306
|
+
if getattr(args, "local", False):
|
|
1307
|
+
self._create_adapter_local(args, name)
|
|
1308
|
+
return
|
|
1309
|
+
|
|
1010
1310
|
description = self._ask_missing(
|
|
1011
1311
|
args,
|
|
1012
1312
|
"description",
|