ErisPulse 2.9.0.dev2__tar.gz → 2.10.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.
Files changed (146) hide show
  1. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/PKG-INFO +3 -1
  2. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/README.pypi.md +2 -0
  3. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/pyproject.toml +1 -1
  4. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/create.py +84 -16
  5. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/init.py +17 -15
  6. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/types.py +27 -31
  7. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/constants.py +8 -0
  8. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/en.py +14 -0
  9. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/ja.py +14 -0
  10. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/ru.py +14 -0
  11. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +14 -0
  12. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +14 -0
  13. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/package_manager.py +7 -3
  14. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/scaffold_text.py +62 -0
  15. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/__init__.py +16 -1
  16. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/adapter.py +13 -12
  17. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/client.py +25 -3
  18. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/errors.py +87 -0
  19. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/router.py +100 -12
  20. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/sql_base.py +11 -6
  21. erispulse-2.10.0.dev0/src/ErisPulse/Core/Bases/websocket.py +477 -0
  22. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/base.py +22 -19
  23. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/command.py +6 -4
  24. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/conversation.py +62 -13
  25. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/governance.py +10 -4
  26. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/overrides.py +64 -40
  27. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/__init__.py +27 -0
  28. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/adapter.py +44 -11
  29. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/client.py +35 -4
  30. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/config.py +149 -16
  31. erispulse-2.10.0.dev0/src/ErisPulse/Core/connections.py +555 -0
  32. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/constants.py +138 -1
  33. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/__init__.py +94 -19
  34. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/en.py +31 -0
  35. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/ja.py +31 -0
  36. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/ru.py +31 -0
  37. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_cn.py +31 -0
  38. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_tw.py +31 -0
  39. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/lifecycle.py +10 -0
  40. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/logger.py +79 -8
  41. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/module.py +14 -0
  42. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/ownership.py +98 -30
  43. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/router.py +238 -53
  44. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/scope.py +3 -3
  45. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/shadow.py +15 -14
  46. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/text_match.py +3 -1
  47. erispulse-2.10.0.dev0/src/ErisPulse/Core/transcript.py +817 -0
  48. erispulse-2.10.0.dev0/src/ErisPulse/__init__.py +426 -0
  49. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/plugin_folder.py +5 -1
  50. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/__init__.py +16 -1
  51. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/sdk_initializer.py +9 -0
  52. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/tasks.py +232 -3
  53. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/troubleshoot.py +38 -30
  54. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/sdk.py +3 -1
  55. erispulse-2.9.0.dev2/src/ErisPulse/Core/Bases/websocket.py +0 -271
  56. erispulse-2.9.0.dev2/src/ErisPulse/Core/transcript.py +0 -426
  57. erispulse-2.9.0.dev2/src/ErisPulse/__init__.py +0 -108
  58. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/.gitignore +0 -0
  59. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/LICENSE +0 -0
  60. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
  61. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/base.py +0 -0
  62. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/cli.py +0 -0
  63. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  64. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/config.py +0 -0
  65. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/doctor.py +0 -0
  66. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/install.py +0 -0
  67. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/language.py +0 -0
  68. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/list.py +0 -0
  69. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  70. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/run.py +0 -0
  71. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/self_update.py +0 -0
  72. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
  73. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  74. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/commands/version.py +0 -0
  75. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/console.py +0 -0
  76. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/hints.py +0 -0
  77. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
  78. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
  79. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/registry.py +0 -0
  80. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  81. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/config_wizard.py +0 -0
  82. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/display.py +0 -0
  83. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/CLI/utils/interactive.py +0 -0
  84. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/api_dsl.py +0 -0
  85. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/config_schema.py +0 -0
  86. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/converter.py +0 -0
  87. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
  88. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
  89. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/manager.py +0 -0
  90. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/model.py +0 -0
  91. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/module.py +0 -0
  92. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
  93. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
  94. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Bases/storage.py +0 -0
  95. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/__init__.py +0 -0
  96. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/command_args.py +0 -0
  97. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/interaction.py +0 -0
  98. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/message.py +0 -0
  99. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  100. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/meta.py +0 -0
  101. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/notice.py +0 -0
  102. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/request.py +0 -0
  103. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
  104. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/throttle.py +0 -0
  105. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/trace.py +0 -0
  106. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/Event/wrapper.py +0 -0
  107. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/assets/__init__.py +0 -0
  108. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/assets/error.css +0 -0
  109. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/assets/error.html +0 -0
  110. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/assets/root.css +0 -0
  111. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/assets/root.html +0 -0
  112. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/di.py +0 -0
  113. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/constants.py +0 -0
  114. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
  115. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/master.py +0 -0
  116. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/storage/__init__.py +0 -0
  117. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/storage/mysql.py +0 -0
  118. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/storage/postgres.py +0 -0
  119. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/Core/storage/sqlite.py +0 -0
  120. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/__main__.py +0 -0
  121. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/finders/__init__.py +0 -0
  122. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/finders/adapter.py +0 -0
  123. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
  124. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/finders/bases/finder.py +0 -0
  125. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/finders/module.py +0 -0
  126. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
  127. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/adapter.py +0 -0
  128. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  129. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/bases/loader.py +0 -0
  130. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/module.py +0 -0
  131. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/strategy.py +0 -0
  132. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/loaders/strict.py +0 -0
  133. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/py.typed +0 -0
  134. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/config_schema.py +0 -0
  135. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/context.py +0 -0
  136. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/diagnostics.py +0 -0
  137. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/example_config.py +0 -0
  138. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/exceptions.py +0 -0
  139. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/file_watcher.py +0 -0
  140. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/frame_config.py +0 -0
  141. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/hints.py +0 -0
  142. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/memory.py +0 -0
  143. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/owner_cleanup.py +0 -0
  144. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/plugin_reload.py +0 -0
  145. {erispulse-2.9.0.dev2 → erispulse-2.10.0.dev0}/src/ErisPulse/runtime/proactive_gc.py +0 -0
  146. {erispulse-2.9.0.dev2 → erispulse-2.10.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.9.0-dev.2
3
+ Version: 2.10.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
@@ -95,6 +95,8 @@ It ships with a flexible plugin system, hot reload, a visual Dashboard, an AI Bu
95
95
  pip install ErisPulse
96
96
  ```
97
97
 
98
+ For a global `epsdk` CLI without any virtual environment, use `uv tool install ErisPulse` instead.
99
+
98
100
  ### Option 2 — Docker (recommended for production)
99
101
 
100
102
  ```bash
@@ -42,6 +42,8 @@ It ships with a flexible plugin system, hot reload, a visual Dashboard, an AI Bu
42
42
  pip install ErisPulse
43
43
  ```
44
44
 
45
+ For a global `epsdk` CLI without any virtual environment, use `uv tool install ErisPulse` instead.
46
+
45
47
  ### Option 2 — Docker (recommended for production)
46
48
 
47
49
  ```bash
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.9.0-dev.2"
7
+ version = "2.10.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"
@@ -41,6 +41,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41
41
  SOFTWARE.
42
42
  """
43
43
 
44
+ # 生成模块/适配器模板的最低 SDK 地板(写入模板 min_sdk_version 字段)。
45
+ # 模板示例使用 args=/options=(2.9 特性);pip 默认不解析预发布版本,
46
+ # 该地板不得高于已发布的正式版本,否则生成的组件会因依赖装不上或
47
+ # 加载器按 PEP 440 拒载(与 CLI/constants.py 的 INIT_ERISPULSE_DEPENDENCY 同步升版)。
48
+ _TEMPLATE_MIN_SDK_VERSION = "2.9.0"
49
+
44
50
  _MODULE_PYPROJECT = """[project]
45
51
  name = "ErisPulse-{name}"
46
52
  version = "1.0.0"
@@ -72,10 +78,19 @@ _MODULE_INIT = """from .Core import Main
72
78
 
73
79
  _MODULE_CORE = """from dataclasses import dataclass, field
74
80
 
75
- from ErisPulse import SDK
76
- from ErisPulse.Core.Bases import BaseConfig, BaseI18n, BaseModule, I18nKey, ModuleMeta
77
- from ErisPulse.Core.Event import Event, command, message, notice
78
- from ErisPulse.Core.i18n import i18n
81
+ from ErisPulse import (
82
+ SDK,
83
+ BaseConfig,
84
+ BaseI18n,
85
+ BaseModule,
86
+ Event,
87
+ I18nKey,
88
+ ModuleMeta,
89
+ command,
90
+ i18n,
91
+ message,
92
+ notice,
93
+ )
79
94
 
80
95
 
81
96
  class Main(BaseModule):
@@ -144,6 +159,42 @@ class Main(BaseModule):
144
159
  ru=\"Привет от {name}!\",
145
160
  zh_TW=\"來自 {name} 的問候!\",
146
161
  )
162
+ roll_help: I18nKey = I18nKey(
163
+ key=\"module.{name}.command.roll.help\",
164
+ default=\"Roll dice: count [sides]\",
165
+ zh_CN=\"掷骰子:次数 [面数]\",
166
+ en=\"Roll dice: count [sides]\",
167
+ ja=\"サイコロを振る: 回数 [面数]\",
168
+ ru=\"Бросить кости: количество [граней]\",
169
+ zh_TW=\"擲骰子:次數 [面數]\",
170
+ )
171
+ roll_reply: I18nKey = I18nKey(
172
+ key=\"module.{name}.command.roll.reply\",
173
+ default=\"Rolled {{count}}d{{sides}}, total: {{total}}{{detail}}\",
174
+ zh_CN=\"掷了 {{count}} 次 {{sides}} 面骰,总点数:{{total}}{{detail}}\",
175
+ en=\"Rolled {{count}}d{{sides}}, total: {{total}}{{detail}}\",
176
+ ja=\"{{sides}}面ダイスを {{count}} 回振った合計: {{total}}{{detail}}\",
177
+ ru=\"Бросков {{count}}d{{sides}}, сумма: {{total}}{{detail}}\",
178
+ zh_TW=\"擲了 {{count}} 次 {{sides}} 面骰,總點數:{{total}}{{detail}}\",
179
+ )
180
+ roll_detail: I18nKey = I18nKey(
181
+ key=\"module.{name}.command.roll.detail\",
182
+ default=\" (verbose: {{count}} rolls of {{sides}}-sided dice)\",
183
+ zh_CN=\"(详细模式:{{count}} 次 {{sides}} 面骰)\",
184
+ en=\" (verbose: {{count}} rolls of {{sides}}-sided dice)\",
185
+ ja=\"(詳細モード: {{sides}}面ダイスを {{count}} 回)\",
186
+ ru=\" (подробно: {{count}} бросков {{sides}}-гранного кубика)\",
187
+ zh_TW=\"(詳細模式:{{count}} 次 {{sides}} 面骰)\",
188
+ )
189
+ signin_reply: I18nKey = I18nKey(
190
+ key=\"module.{name}.command.signin.reply\",
191
+ default=\"Signed in!\",
192
+ zh_CN=\"签到成功\",
193
+ en=\"Signed in!\",
194
+ ja=\"チェックイン完了!\",
195
+ ru=\"Готово, вы отмечены!\",
196
+ zh_TW=\"簽到成功\",
197
+ )
147
198
 
148
199
  def __init__(self, sdk: SDK = None):
149
200
  # sdk 由框架在实例化时自动注入(无需手动导入兜底)
@@ -167,7 +218,7 @@ class Main(BaseModule):
167
218
  version=\"0.1.0\",
168
219
  author=\"ErisDev\",
169
220
  # 最低 SDK 版本(可选):不满足时框架在加载期明确报错并跳过本模块
170
- min_sdk_version=\"2.8.0\",
221
+ min_sdk_version=\"{min_sdk}\",
171
222
  group=\"default\",
172
223
  tags=[\"{name}\"],
173
224
  # 对外服务白名单(可选):声明后其他模块可经 sdk.module.call() 调用这些方法;
@@ -225,6 +276,20 @@ class Main(BaseModule):
225
276
  async def hello_command(event: Event):
226
277
  await event.reply(i18n.t(\"module.{name}.command.hello.reply\"))
227
278
 
279
+ # {text[module.roll_hint]}
280
+ @command(
281
+ \"roll\",
282
+ args=\"<count:int> [sides:int=6]\",
283
+ options={{\"verbose\": \"-v/--verbose\"}},
284
+ help=i18n.t(\"module.{name}.command.roll.help\"),
285
+ )
286
+ async def roll_command(event: Event, count: int, sides: int = 6, verbose: bool = False):
287
+ import random
288
+
289
+ total = sum(random.randint(1, sides) for _ in range(count))
290
+ detail = i18n.t(\"module.{name}.command.roll.detail\", count=count, sides=sides) if verbose else \"\"
291
+ await event.reply(i18n.t(\"module.{name}.command.roll.reply\", count=count, sides=sides, total=total, detail=detail))
292
+
228
293
  async def _register_message_handlers(self):
229
294
  @message.on_private_message()
230
295
  async def private_message_handler(event: Event):
@@ -235,9 +300,9 @@ class Main(BaseModule):
235
300
  pass
236
301
 
237
302
  # 消息装饰器支持 pattern(glob 通配符)/ regex(正则),不匹配则不触发
238
- @message.on_message(pattern=\"签到*\")
303
+ @message.on_message(pattern=\"{text[module.signin_pattern]}\")
239
304
  async def signin_handler(event: Event):
240
- await event.reply(\"签到成功\")
305
+ await event.reply(i18n.t(\"module.{name}.command.signin.reply\"))
241
306
 
242
307
  @notice.on_friend_add()
243
308
  async def friend_add_handler(event: Event):
@@ -283,10 +348,7 @@ _ADAPTER_CORE = """import asyncio
283
348
  import json
284
349
  from dataclasses import dataclass, field
285
350
  from typing import ClassVar
286
- from ErisPulse.Core import BaseAdapter
287
- from ErisPulse.Core.Bases import BaseConfig, BaseI18n, I18nKey
288
- from ErisPulse.Core import router
289
- from ErisPulse.Core.i18n import i18n
351
+ from ErisPulse import BaseAdapter, BaseConfig, BaseI18n, I18nKey, router, i18n
290
352
 
291
353
 
292
354
  class {name}(BaseAdapter):
@@ -294,7 +356,7 @@ class {name}(BaseAdapter):
294
356
  {text[adapter.doc]}
295
357
  \"\"\"
296
358
 
297
- # 依赖声明(可选,ErisPulse 2.8.0+):
359
+ # 依赖声明(可选,ErisPulse 2.9.0+):
298
360
  # depends = {{"adapters": [], "modules": []}} # 硬依赖:缺失时跳过启动
299
361
  # optional_modules = [] # 软依赖:就绪/丢失时收到
300
362
  # # on_dependency_ready/lost 回调
@@ -302,7 +364,7 @@ class {name}(BaseAdapter):
302
364
  optional_modules: ClassVar[list] = []
303
365
 
304
366
  # 声明所需最低 SDK 版本:不满足时框架在加载期明确报错并跳过本适配器(可选)
305
- min_sdk_version = "2.8.0"
367
+ min_sdk_version = "{min_sdk}"
306
368
 
307
369
  # {text[adapter.config_hint]}
308
370
  @dataclass
@@ -461,6 +523,11 @@ class {name}(BaseAdapter):
461
523
  async def _ws_handler(self, websocket):
462
524
  bot_id = self._get_bot_id()
463
525
 
526
+ # 连接已由框架自动登记进连接池(ErisPulse.connections):
527
+ # meta 供跨模块查看,join_group 后可被 connections.broadcast 定向推送
528
+ websocket.meta["bot_id"] = bot_id
529
+ websocket.join_group(f"bot:{{bot_id}}")
530
+
464
531
  await self.emit_meta("connect", bot_id, user_name="{name}")
465
532
  self.logger.info("{text[adapter.log.bot_connected]}")
466
533
 
@@ -484,7 +551,7 @@ class {name}(BaseAdapter):
484
551
 
485
552
  async def call_api(self, endpoint: str, **params):
486
553
  \"\"\"Call platform API\"\"\"
487
- from ErisPulse.Core import client
554
+ from ErisPulse import client
488
555
 
489
556
  cfg = self.cfg
490
557
  headers = {{"Authorization": "Bearer " + cfg.token}}
@@ -848,7 +915,7 @@ class CreateCommand(Command):
848
915
 
849
916
  (pkg_dir / "__init__.py").write_text(_MODULE_INIT, encoding="utf-8")
850
917
  (pkg_dir / "Core.py").write_text(
851
- _MODULE_CORE.format(name=name, text=_scaffold_text(name)),
918
+ _MODULE_CORE.format(name=name, text=_scaffold_text(name), min_sdk=_TEMPLATE_MIN_SDK_VERSION),
852
919
  encoding="utf-8",
853
920
  )
854
921
  (project_dir / "pyproject.toml").write_text(
@@ -921,7 +988,7 @@ class CreateCommand(Command):
921
988
 
922
989
  (plugin_dir / "__init__.py").write_text(_MODULE_INIT, encoding="utf-8")
923
990
  (plugin_dir / "Core.py").write_text(
924
- _MODULE_CORE.format(name=name, text=_scaffold_text(name)),
991
+ _MODULE_CORE.format(name=name, text=_scaffold_text(name), min_sdk=_TEMPLATE_MIN_SDK_VERSION),
925
992
  encoding="utf-8",
926
993
  )
927
994
 
@@ -1000,6 +1067,7 @@ class CreateCommand(Command):
1000
1067
  converter_name=converter_name,
1001
1068
  entry_key=entry_key,
1002
1069
  text=_scaffold_text(name),
1070
+ min_sdk=_TEMPLATE_MIN_SDK_VERSION,
1003
1071
  ),
1004
1072
  encoding="utf-8",
1005
1073
  )
@@ -15,6 +15,7 @@ from rich.text import Text
15
15
 
16
16
  from ..base import Command
17
17
  from ..console import console
18
+ from ..constants import INIT_ERISPULSE_DEPENDENCY
18
19
  from ..i18n import i18n
19
20
  from ..utils import PackageManager
20
21
  from ..utils.display import _input, prompt_validated, section_header
@@ -26,6 +27,7 @@ from ..utils.package_manager import (
26
27
  uv_add,
27
28
  warn_if_uv_isolated,
28
29
  )
30
+ from ..utils.scaffold_text import ScaffoldText
29
31
 
30
32
 
31
33
  def _validate_project_name(name: str) -> bool:
@@ -192,6 +194,9 @@ class InitCommand(Command):
192
194
  console.print(f"[success] {i18n.t('cli.init.created_dir', name=project_name)}[/]")
193
195
 
194
196
  try:
197
+ # 生成物文案(config 注释 / main docstring / .gitignore 分节 /
198
+ # README)跟随 CLI 语言;缺失键回退英文
199
+ st = ScaffoldText()
195
200
  for dir_name in ["config", "logs"]:
196
201
  (project_path / dir_name).mkdir(exist_ok=True)
197
202
  # SSL 证书默认目录:跟随项目运行目录走,配置里用相对路径引用
@@ -201,15 +206,14 @@ class InitCommand(Command):
201
206
  ssl_file = ssl_dir / ssl_name
202
207
  if not ssl_file.exists():
203
208
  ssl_file.write_text(
204
- "# 将你的证书/密钥 PEM 内容粘贴到本文件,或在配置中改用 ssl_cert/ssl_key 内联填写\n",
209
+ st.t("init.ssl_placeholder") + "\n",
205
210
  encoding="utf-8",
206
211
  )
207
212
 
208
213
  config_file = project_path / "config" / "config.toml"
209
214
  if not config_file.exists():
210
215
  with config_file.open("w", encoding="utf-8") as f:
211
- f.write("# ErisPulse 配置文件\n")
212
- f.write("# 完整配置示例请参考 config.full.example\n\n")
216
+ f.write(st.t("init.config_toml_header") + "\n\n")
213
217
  f.write("[ErisPulse.server]\n")
214
218
  f.write('host = "0.0.0.0"\n')
215
219
  f.write("port = 8000\n\n")
@@ -224,9 +228,7 @@ class InitCommand(Command):
224
228
  main_file = project_path / "main.py"
225
229
  if not main_file.exists():
226
230
  with main_file.open("w", encoding="utf-8") as f:
227
- f.write(f'"""\n{display_name} 主程序\n\n')
228
- f.write("这是 ErisPulse 自动生成的主程序文件\n")
229
- f.write('"""\n\n')
231
+ f.write(st.t("init.main_docstring", display_name=display_name) + "\n")
230
232
  f.write("import asyncio\n")
231
233
  f.write("from ErisPulse import sdk\n\n")
232
234
  f.write("async def main():\n")
@@ -245,7 +247,7 @@ class InitCommand(Command):
245
247
  f.write('description = "ErisPulse project"\n')
246
248
  f.write('requires-python = ">=3.10"\n')
247
249
  f.write("dependencies = [\n")
248
- f.write(' "erispulse>=2.8.3",\n')
250
+ f.write(f' "{INIT_ERISPULSE_DEPENDENCY}",\n')
249
251
  for adapter in adapter_list or []:
250
252
  f.write(f' "{adapter}",\n')
251
253
  f.write("]\n")
@@ -265,13 +267,13 @@ class InitCommand(Command):
265
267
  "*.egg-info/\n"
266
268
  ".eggs/\n"
267
269
  "\n"
268
- "# 虚拟环境与本地环境\n"
270
+ f"{st.t('init.gitignore_section_venv')}\n"
269
271
  ".venv/\n"
270
272
  "venv/\n"
271
273
  "env/\n"
272
274
  ".env\n"
273
275
  "\n"
274
- "# 工具缓存\n"
276
+ f"{st.t('init.gitignore_section_cache')}\n"
275
277
  ".pytest_cache/\n"
276
278
  ".mypy_cache/\n"
277
279
  ".ruff_cache/\n"
@@ -279,11 +281,11 @@ class InitCommand(Command):
279
281
  "coverage.xml\n"
280
282
  "htmlcov/\n"
281
283
  "\n"
282
- "# ErisPulse 运行时数据(配置与日志含敏感信息,不入库)\n"
284
+ f"{st.t('init.gitignore_section_runtime')}\n"
283
285
  "config/\n"
284
286
  "logs/\n"
285
287
  "\n"
286
- "# 编辑器与系统文件\n"
288
+ f"{st.t('init.gitignore_section_editor')}\n"
287
289
  ".idea/\n"
288
290
  ".vscode/\n"
289
291
  "*.swp\n"
@@ -295,14 +297,14 @@ class InitCommand(Command):
295
297
  readme_file = project_path / "README.md"
296
298
  if not readme_file.exists():
297
299
  with readme_file.open("w", encoding="utf-8") as f:
298
- f.write(f"# {display_name}\n\nErisPulse 项目。\n\n```bash\nepsdk run\n```\n")
300
+ f.write(st.t("init.readme_body", display_name=display_name))
299
301
  console.print(f"[success] {i18n.t('cli.init.readme_created')}[/]")
300
302
 
301
303
  # ---- 虚拟环境与依赖安装 ----
302
304
  if create_venv:
303
305
  console.print(f"[info] {i18n.t('cli.init.venv_creating')}[/]")
304
306
  venv_python = None
305
- if uv_add(project_path, ["erispulse>=2.8.3"]):
307
+ if uv_add(project_path, [INIT_ERISPULSE_DEPENDENCY]):
306
308
  # uv add 自动创建 .venv、安装依赖并写入 pyproject 依赖清单
307
309
  venv_python = resolve_target_python(project_path)[0]
308
310
  console.print(f"[success] {i18n.t('cli.init.venv_created')}[/]")
@@ -312,8 +314,8 @@ class InitCommand(Command):
312
314
  if venv_python:
313
315
  console.print(f"[success] {i18n.t('cli.init.venv_created')}[/]")
314
316
  pm = PackageManager(python_executable=venv_python)
315
- if pm.install_package(["erispulse>=2.8.3"]):
316
- append_pyproject_dependencies(project_path, ["erispulse>=2.8.3"])
317
+ if pm.install_package([INIT_ERISPULSE_DEPENDENCY]):
318
+ append_pyproject_dependencies(project_path, [INIT_ERISPULSE_DEPENDENCY])
317
319
  console.print(f"[success] {i18n.t('cli.init.deps_installed')}[/]")
318
320
  else:
319
321
  console.print(
@@ -26,32 +26,31 @@ from ..i18n import i18n
26
26
  # 生成文件名(带前导下划线,避免与用户业务模块冲突)
27
27
  STUB_FILENAME = "_ep_types.py"
28
28
 
29
- # 存根文件头部说明
30
- _STUB_HEADER = '''"""
31
- ErisPulse 类型存根(自动生成,请勿手动编辑)
32
-
33
- 由 `epsdk types` 命令根据已安装的模块/适配器生成。
34
- 仅导出类型供用户代码作为变量标注使用,**不提供任何运行时实例**。
35
- 所有导入都在 ``TYPE_CHECKING`` 下,运行时零开销、零行为改变。
36
-
37
- 使用方式:
38
- from _ep_types import MyModule, Yunhu
39
- from ErisPulse import sdk
40
-
41
- # 用导入的类型标注变量,即可获得 IDE 补全
42
- my_mod: MyModule = sdk.module.get("MyModule")
43
- my_mod.hello() # ← IDE 能补全 hello
44
-
45
- my_adapter: Yunhu = sdk.adapter.get("yunhu")
46
- await my_adapter.Send.To("group", "123").Board(...) # ← 补全平台特有方法
47
-
48
- 说明:
49
- - 类型名采用 entry-point 名的 PascalCase 形式(如 ``yunhu`` → ``Yunhu``),
50
- 与传入 ``sdk.adapter.get()`` / ``sdk.module.get()`` 的名称对应
51
- - 存根仅用于静态类型检查,不含运行时实现
52
- - 安装/卸载模块/适配器后请重新生成:``epsdk types``
53
- """
54
- '''
29
+ def _stub_header() -> str:
30
+ """{!--< internal-use >!--} 渲染存根文件头部说明(当前语言)"""
31
+ return (
32
+ '"""\n'
33
+ f"{i18n.t('cli.types.stub_title')}\n"
34
+ "\n"
35
+ f"{i18n.t('cli.types.stub_intro')}\n"
36
+ "\n"
37
+ f"{i18n.t('cli.types.stub_usage_title')}:\n"
38
+ " from _ep_types import MyModule, Yunhu\n"
39
+ " from ErisPulse import sdk\n"
40
+ "\n"
41
+ f" {i18n.t('cli.types.stub_usage_comment')}\n"
42
+ ' my_mod: MyModule = sdk.module.get("MyModule")\n'
43
+ f" my_mod.hello() {i18n.t('cli.types.stub_usage_module_hint')}\n"
44
+ "\n"
45
+ ' my_adapter: Yunhu = sdk.adapter.get("yunhu")\n'
46
+ f" await my_adapter.Send.To(\"group\", \"123\").Board(...) {i18n.t('cli.types.stub_usage_adapter_hint')}\n"
47
+ "\n"
48
+ f"{i18n.t('cli.types.stub_notes_title')}:\n"
49
+ f" - {i18n.t('cli.types.stub_note_naming')}\n"
50
+ f" - {i18n.t('cli.types.stub_note_static_only')}\n"
51
+ f" - {i18n.t('cli.types.stub_note_regen')}\n"
52
+ '"""\n'
53
+ )
55
54
 
56
55
  # 排除内省的方法名(来自基类、Python 内置、下划线开头)
57
56
  _EXCLUDE_METHOD_NAMES = frozenset({
@@ -491,14 +490,11 @@ class TypesCommand(Command):
491
490
  :param modules_info: 模块信息
492
491
  :return: 存根文件内容
493
492
  """
494
- lines = [_STUB_HEADER.rstrip(), ""]
493
+ lines = [_stub_header().rstrip(), ""]
495
494
  lines.append("from typing import TYPE_CHECKING")
496
495
  lines.append("")
497
496
  lines.append("if TYPE_CHECKING:")
498
- lines.append(" # 以下类型导入仅在 IDE / 类型检查器中生效,不会被运行时执行。")
499
- lines.append(" # 在用户代码中通过 ``from _ep_types import XxxModule`` 获取类型,")
500
- lines.append(" # 配合 ``my_mod: XxxModule = sdk.module.get('XxxModule')`` 获得补全。")
501
- lines.append("")
497
+ lines.append(f" # {i18n.t('cli.types.stub_typing_comment')}")
502
498
 
503
499
  export_names: list[str] = []
504
500
  seen_imports: set[str] = set() # 去重完全相同的导入语句
@@ -55,8 +55,16 @@ RUN_RESTART_PAUSE_SECS: float = 0.5
55
55
  # 修改影响: 数值越小越早提示,越大越保守(0/负数禁用提示)。
56
56
  RUN_PERSISTENT_CRASH_HINT_THRESHOLD: int = 3
57
57
 
58
+ # init 生成项目对框架本体的依赖下限(pip 依赖声明,非 SDK 加载期检查)。
59
+ # 使用位置: CLI/commands/init.py -> pyproject.toml 生成 / uv_add / pm.install_package /
60
+ # append_pyproject_dependencies 四处。
61
+ # 修改影响: 真实 pip 依赖——pip 默认不解析预发布版本,该下限不得高于已发布的
62
+ # 正式版本(与 create.py 的 _TEMPLATE_MIN_SDK_VERSION 同步升版)。
63
+ INIT_ERISPULSE_DEPENDENCY: str = "erispulse>=2.9.0"
64
+
58
65
  __all__ = [
59
66
  "ADAPTER_ENTRY_POINT_GROUP",
67
+ "INIT_ERISPULSE_DEPENDENCY",
60
68
  "RUN_CRASH_BACKOFF_MAX_SECS",
61
69
  "RUN_CRASH_BACKOFF_PER_CRASH_SECS",
62
70
  "RUN_RESTART_PAUSE_SECS",
@@ -426,6 +426,9 @@ TRANSLATIONS = {
426
426
  "cli.display.enter_number": "Please enter a number",
427
427
  # ==================== package_manager utils ====================
428
428
  "cli.package.ssl_error": "SSL verification failed: {error}",
429
+ "cli.package.uv_venv_failed": "uv venv failed: {error}",
430
+ "cli.package.python_venv_failed": "python -m venv failed: {error}",
431
+ "cli.package.pyproject_writeback_failed": "Failed to write dependencies back to pyproject.toml: {error}",
429
432
  "cli.package.ssl_error_proxy_hint": " Proxy detected, please ensure the proxy is configured correctly or try setting the HTTPS_PROXY environment variable",
430
433
  "cli.package.fetch_remote_failed": "Failed to fetch remote package list, please check your network connection or proxy settings",
431
434
  "cli.package.proxy_detected": " Proxy detected: {proxy}",
@@ -549,4 +552,15 @@ TRANSLATIONS = {
549
552
  "cli.types.usage_hint": "Import types in your code and use them as variable annotations for IDE completion:",
550
553
  "cli.types.usage_example": "from _ep_types import MyModule # then: my_mod: MyModule = sdk.module.get('MyModule')",
551
554
  "cli.types.introspect_failed": "Failed to introspect target environment: {error}",
555
+ "cli.types.stub_title": "ErisPulse type stub (auto-generated, do not edit manually)",
556
+ "cli.types.stub_intro": "Generated by the `epsdk types` command from installed modules/adapters.\nExports types only, for variable annotations in user code — **provides no runtime instances**.\nAll imports are under ``TYPE_CHECKING``: zero runtime cost, zero behavior change.",
557
+ "cli.types.stub_usage_title": "Usage",
558
+ "cli.types.stub_usage_comment": "# annotate variables with the imported types to get IDE completion",
559
+ "cli.types.stub_usage_module_hint": "# ← IDE completes hello",
560
+ "cli.types.stub_usage_adapter_hint": "# ← completes platform-specific methods",
561
+ "cli.types.stub_notes_title": "Notes",
562
+ "cli.types.stub_note_naming": "Type names are the PascalCase form of entry-point names (e.g. ``yunhu`` → ``Yunhu``), matching the names passed to ``sdk.adapter.get()`` / ``sdk.module.get()``",
563
+ "cli.types.stub_note_static_only": "The stub is for static type checking only and contains no runtime implementation",
564
+ "cli.types.stub_note_regen": "Regenerate after installing/uninstalling modules or adapters: ``epsdk types``",
565
+ "cli.types.stub_typing_comment": "The type imports below only take effect in IDEs / type checkers and are never executed at runtime; in user code, get types via ``from _ep_types import XxxModule`` and use them as variable annotations for completion",
552
566
  }
@@ -426,6 +426,9 @@ TRANSLATIONS = {
426
426
  "cli.display.enter_number": "数字を入力してください",
427
427
  # ==================== package_manager ユーティリティ ====================
428
428
  "cli.package.ssl_error": "SSL 検証失敗: {error}",
429
+ "cli.package.uv_venv_failed": "uv venv に失敗しました: {error}",
430
+ "cli.package.python_venv_failed": "python -m venv に失敗しました: {error}",
431
+ "cli.package.pyproject_writeback_failed": "pyproject.toml への依存関係の書き戻しに失敗しました: {error}",
429
432
  "cli.package.ssl_error_proxy_hint": " プロキシが検出されました。プロキシ設定が正しいことを確認するか、HTTPS_PROXY 環境変数を設定してください",
430
433
  "cli.package.fetch_remote_failed": "リモートパッケージリストを取得できませんでした。ネットワーク接続またはプロキシ設定を確認してください",
431
434
  "cli.package.proxy_detected": " プロキシを検出: {proxy}",
@@ -549,4 +552,15 @@ TRANSLATIONS = {
549
552
  "cli.types.usage_hint": "コードに型をインポートして変数アノテーションとして使用すると、IDE 補完が利用できます:",
550
553
  "cli.types.usage_example": "from _ep_types import MyModule # 次に: my_mod: MyModule = sdk.module.get('MyModule')",
551
554
  "cli.types.introspect_failed": "対象環境のイントロスペクションに失敗: {error}",
555
+ "cli.types.stub_title": "ErisPulse 型スタブ(自動生成、手動編集禁止)",
556
+ "cli.types.stub_intro": "インストール済みのモジュール/アダプタから `epsdk types` コマンドにより生成されました。\nユーザーコードの変数アノテーション用に型のみをエクスポートし、**実行時インスタンスは提供しません**。\nすべてのインポートは ``TYPE_CHECKING`` 配下にあり、実行時のオーバーヘッドと動作変更はゼロです。",
557
+ "cli.types.stub_usage_title": "使用方法",
558
+ "cli.types.stub_usage_comment": "# インポートした型で変数をアノテートすると IDE 補全が効きます",
559
+ "cli.types.stub_usage_module_hint": "# ← IDE が hello を補完します",
560
+ "cli.types.stub_usage_adapter_hint": "# ← プラットフォーム固有メソッドを補完します",
561
+ "cli.types.stub_notes_title": "説明",
562
+ "cli.types.stub_note_naming": "型名は entry-point 名の PascalCase 形式(例: ``yunhu`` → ``Yunhu``)で、``sdk.adapter.get()`` / ``sdk.module.get()`` に渡す名前に対応します",
563
+ "cli.types.stub_note_static_only": "スタブは静的型検査専用で、実行時実装を含みません",
564
+ "cli.types.stub_note_regen": "モジュール/アダプタのインストール/アンインストール後は再生成してください: ``epsdk types``",
565
+ "cli.types.stub_typing_comment": "以下の型インポートは IDE / 型チェッカーでのみ有効で、実行時には実行されません。ユーザーコードでは ``from _ep_types import XxxModule`` で型を取得し変数アノテーションに使うと補完が効きます",
552
566
  }
@@ -426,6 +426,9 @@ TRANSLATIONS = {
426
426
  "cli.display.enter_number": "Пожалуйста, введите номер",
427
427
  # ==================== утилиты package_manager ====================
428
428
  "cli.package.ssl_error": "Ошибка проверки SSL: {error}",
429
+ "cli.package.uv_venv_failed": "Сбой uv venv: {error}",
430
+ "cli.package.python_venv_failed": "Сбой python -m venv: {error}",
431
+ "cli.package.pyproject_writeback_failed": "Не удалось записать зависимости обратно в pyproject.toml: {error}",
429
432
  "cli.package.ssl_error_proxy_hint": " Обнаружен прокси. Убедитесь, что прокси настроен правильно, или попробуйте задать переменную окружения HTTPS_PROXY",
430
433
  "cli.package.fetch_remote_failed": "Не удалось получить список удалённых пакетов. Проверьте сетевое подключение или настройки прокси",
431
434
  "cli.package.proxy_detected": " Обнаружен прокси: {proxy}",
@@ -549,4 +552,15 @@ TRANSLATIONS = {
549
552
  "cli.types.usage_hint": "Импортируйте типы в коде и используйте как аннотации переменных для автодополнения IDE:",
550
553
  "cli.types.usage_example": "from _ep_types import MyModule # затем: my_mod: MyModule = sdk.module.get('MyModule')",
551
554
  "cli.types.introspect_failed": "Ошибка интроспекции целевой среды: {error}",
555
+ "cli.types.stub_title": "Заглушка типов ErisPulse (сгенерирована автоматически, вручную не редактировать)",
556
+ "cli.types.stub_intro": "Сгенерирована командой `epsdk types` по установленным модулям/адаптерам.\nЭкспортирует только типы для аннотаций переменных в коде пользователя — **экземпляры времени выполнения не предоставляет**.\nВсе импорты находятся под ``TYPE_CHECKING``: нулевые накладные расходы и нулевое изменение поведения во время выполнения.",
557
+ "cli.types.stub_usage_title": "Использование",
558
+ "cli.types.stub_usage_comment": "# аннотируйте переменные импортированными типами, чтобы получить автодополнение в IDE",
559
+ "cli.types.stub_usage_module_hint": "# ← IDE дополнит hello",
560
+ "cli.types.stub_usage_adapter_hint": "# ← дополнит методы, специфичные для платформы",
561
+ "cli.types.stub_notes_title": "Примечания",
562
+ "cli.types.stub_note_naming": "Имена типов — форма PascalCase имён entry-point (например, ``yunhu`` → ``Yunhu``) и соответствуют именам, передаваемым в ``sdk.adapter.get()`` / ``sdk.module.get()``",
563
+ "cli.types.stub_note_static_only": "Заглушка предназначена только для статической проверки типов и не содержит реализации времени выполнения",
564
+ "cli.types.stub_note_regen": "После установки/удаления модулей или адаптеров перегенерируйте: ``epsdk types``",
565
+ "cli.types.stub_typing_comment": "Импорты типов ниже действуют только в IDE / проверщиках типов и никогда не выполняются во время выполнения; в коде пользователя получайте типы через ``from _ep_types import XxxModule`` и используйте их в аннотациях переменных для автодополнения",
552
566
  }
@@ -426,6 +426,9 @@ TRANSLATIONS = {
426
426
  "cli.display.enter_number": "请输入数字序号",
427
427
  # ==================== package_manager 工具 ====================
428
428
  "cli.package.ssl_error": "SSL 验证失败: {error}",
429
+ "cli.package.uv_venv_failed": "uv venv 失败:{error}",
430
+ "cli.package.python_venv_failed": "python -m venv 失败:{error}",
431
+ "cli.package.pyproject_writeback_failed": "pyproject.toml 依赖回写失败:{error}",
429
432
  "cli.package.ssl_error_proxy_hint": " 检测到代理,请确保代理配置正确或尝试设置 HTTPS_PROXY 环境变量",
430
433
  "cli.package.fetch_remote_failed": "无法获取远程包列表,请检查网络连接或代理设置",
431
434
  "cli.package.proxy_detected": " 检测到代理: {proxy}",
@@ -549,4 +552,15 @@ TRANSLATIONS = {
549
552
  "cli.types.usage_hint": "在代码中导入类型并作为变量标注,即可获得 IDE 补全:",
550
553
  "cli.types.usage_example": "from _ep_types import MyModule # 然后写 my_mod: MyModule = sdk.module.get('MyModule')",
551
554
  "cli.types.introspect_failed": "内省目标环境失败: {error}",
555
+ "cli.types.stub_title": "ErisPulse 类型存根(自动生成,请勿手动编辑)",
556
+ "cli.types.stub_intro": "由 `epsdk types` 命令根据已安装的模块/适配器生成。\n仅导出类型供用户代码作为变量标注使用,**不提供任何运行时实例**。\n所有导入都在 ``TYPE_CHECKING`` 下,运行时零开销、零行为改变。",
557
+ "cli.types.stub_usage_title": "使用方式",
558
+ "cli.types.stub_usage_comment": "# 用导入的类型标注变量,即可获得 IDE 补全",
559
+ "cli.types.stub_usage_module_hint": "# ← IDE 能补全 hello",
560
+ "cli.types.stub_usage_adapter_hint": "# ← 补全平台特有方法",
561
+ "cli.types.stub_notes_title": "说明",
562
+ "cli.types.stub_note_naming": "类型名采用 entry-point 名的 PascalCase 形式(如 ``yunhu`` → ``Yunhu``),与传入 ``sdk.adapter.get()`` / ``sdk.module.get()`` 的名称对应",
563
+ "cli.types.stub_note_static_only": "存根仅用于静态类型检查,不含运行时实现",
564
+ "cli.types.stub_note_regen": "安装/卸载模块/适配器后请重新生成:``epsdk types``",
565
+ "cli.types.stub_typing_comment": "以下类型导入仅在 IDE / 类型检查器中生效,不会被运行时执行;用户代码中经 ``from _ep_types import XxxModule`` 获取类型并用于变量标注即可获得补全",
552
566
  }
@@ -426,6 +426,9 @@ TRANSLATIONS = {
426
426
  "cli.display.enter_number": "請輸入數字序號",
427
427
  # ==================== package_manager 工具 ====================
428
428
  "cli.package.ssl_error": "SSL 驗證失敗: {error}",
429
+ "cli.package.uv_venv_failed": "uv venv 失敗:{error}",
430
+ "cli.package.python_venv_failed": "python -m venv 失敗:{error}",
431
+ "cli.package.pyproject_writeback_failed": "pyproject.toml 依賴回寫失敗:{error}",
429
432
  "cli.package.ssl_error_proxy_hint": " 偵測到代理,請確保代理設定正確或嘗試設定 HTTPS_PROXY 環境變數",
430
433
  "cli.package.fetch_remote_failed": "無法取得遠端包列表,請檢查網路連線或代理設定",
431
434
  "cli.package.proxy_detected": " 偵測到代理: {proxy}",
@@ -549,4 +552,15 @@ TRANSLATIONS = {
549
552
  "cli.types.usage_hint": "在程式碼中匯入型別並作為變數標注,即可獲得 IDE 補全:",
550
553
  "cli.types.usage_example": "from _ep_types import MyModule # 然後寫 my_mod: MyModule = sdk.module.get('MyModule')",
551
554
  "cli.types.introspect_failed": "內省目標環境失敗: {error}",
555
+ "cli.types.stub_title": "ErisPulse 類型存根(自動產生,請勿手動編輯)",
556
+ "cli.types.stub_intro": "由 `epsdk types` 命令根據已安裝的模組/適配器產生。\n僅匯出類型供使用者程式碼作為變數標註使用,**不提供任何執行時實例**。\n所有匯入都在 ``TYPE_CHECKING`` 下,執行時零開銷、零行為改變。",
557
+ "cli.types.stub_usage_title": "使用方式",
558
+ "cli.types.stub_usage_comment": "# 用匯入的類型標註變數,即可獲得 IDE 補全",
559
+ "cli.types.stub_usage_module_hint": "# ← IDE 能補全 hello",
560
+ "cli.types.stub_usage_adapter_hint": "# ← 補全平台特有方法",
561
+ "cli.types.stub_notes_title": "說明",
562
+ "cli.types.stub_note_naming": "類型名採用 entry-point 名的 PascalCase 形式(如 ``yunhu`` → ``Yunhu``),與傳入 ``sdk.adapter.get()`` / ``sdk.module.get()`` 的名稱對應",
563
+ "cli.types.stub_note_static_only": "存根僅用於靜態類型檢查,不含執行時實作",
564
+ "cli.types.stub_note_regen": "安裝/卸載模組/適配器後請重新產生:``epsdk types``",
565
+ "cli.types.stub_typing_comment": "以下類型匯入僅在 IDE / 類型檢查器中生效,不會被執行時執行;使用者程式碼中經 ``from _ep_types import XxxModule`` 取得類型並用於變數標註即可獲得補全",
552
566
  }
@@ -1657,7 +1657,9 @@ def create_project_venv(project_dir: Path) -> "str | None":
1657
1657
  check=False,
1658
1658
  )
1659
1659
  if result.returncode != 0:
1660
- console.print(f"[warning] uv venv 失败:{result.stderr.strip()[:200]}[/]")
1660
+ console.print(
1661
+ f"[warning] {i18n.t('cli.package.uv_venv_failed', error=result.stderr.strip()[:200])}[/]"
1662
+ )
1661
1663
  else:
1662
1664
  result = subprocess.run(
1663
1665
  [sys.executable, "-m", "venv", str(venv_dir)],
@@ -1667,7 +1669,9 @@ def create_project_venv(project_dir: Path) -> "str | None":
1667
1669
  check=False,
1668
1670
  )
1669
1671
  if result.returncode != 0:
1670
- console.print(f"[warning] python -m venv 失败:{result.stderr.strip()[:200]}[/]")
1672
+ console.print(
1673
+ f"[warning] {i18n.t('cli.package.python_venv_failed', error=result.stderr.strip()[:200])}[/]"
1674
+ )
1671
1675
 
1672
1676
  if sys.platform == "win32":
1673
1677
  py = venv_dir / "Scripts" / "python.exe"
@@ -1737,7 +1741,7 @@ def append_pyproject_dependencies(project_dir: Path, packages: "list[str]") -> b
1737
1741
  pyproject.write_text(tomlkit.dumps(doc_kit), encoding="utf-8")
1738
1742
  return True
1739
1743
  except Exception as e:
1740
- console.print(f"[warning] pyproject.toml 依赖回写失败:{e}[/]")
1744
+ console.print(f"[warning] {i18n.t('cli.package.pyproject_writeback_failed', error=e)}[/]")
1741
1745
  return False
1742
1746
 
1743
1747