ErisPulse 2.11.0.dev0__tar.gz → 2.11.1.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 (154) hide show
  1. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/.gitignore +0 -1
  2. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/PKG-INFO +1 -1
  3. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/pyproject.toml +9 -8
  4. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/base.py +3 -3
  5. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/cli.py +22 -1
  6. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/config.py +3 -3
  7. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/create.py +367 -6
  8. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/doctor.py +342 -8
  9. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/init.py +23 -12
  10. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/install.py +19 -7
  11. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/language.py +3 -3
  12. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/list.py +3 -3
  13. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/list_remote.py +3 -3
  14. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/run.py +312 -102
  15. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/runtime.py +4 -4
  16. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/self_update.py +3 -3
  17. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/types.py +10 -6
  18. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/uninstall.py +3 -3
  19. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/upgrade.py +9 -5
  20. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/version.py +3 -2
  21. erispulse-2.11.1.dev0/src/ErisPulse/CLI/constants.py +159 -0
  22. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/en.py +50 -1
  23. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/ja.py +50 -1
  24. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/ru.py +50 -1
  25. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +50 -1
  26. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +50 -1
  27. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/registry.py +1 -1
  28. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/package_manager.py +300 -36
  29. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/runtime_state.py +46 -0
  30. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/scaffold_text.py +81 -2
  31. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/__init__.py +3 -0
  32. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/adapter.py +156 -18
  33. erispulse-2.11.1.dev0/src/ErisPulse/Core/Bases/adapter_patterns.py +324 -0
  34. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/client.py +5 -4
  35. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/manager.py +93 -1
  36. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/model.py +7 -2
  37. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/module.py +81 -4
  38. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/router.py +20 -20
  39. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/storage.py +2 -1
  40. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/websocket.py +9 -9
  41. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/base.py +1 -1
  42. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/conversation.py +6 -6
  43. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/governance.py +64 -8
  44. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/interaction.py +1 -1
  45. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/message.py +4 -4
  46. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/meta.py +4 -4
  47. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/notice.py +5 -5
  48. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/request.py +3 -3
  49. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/wrapper.py +9 -6
  50. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/__init__.py +4 -0
  51. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/adapter.py +150 -155
  52. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/client.py +7 -7
  53. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/config.py +49 -10
  54. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/connections.py +4 -2
  55. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/constants.py +122 -1
  56. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/__init__.py +44 -11
  57. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/en.py +36 -10
  58. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/ja.py +115 -89
  59. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/ru.py +115 -89
  60. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/zh_cn.py +115 -89
  61. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/zh_tw.py +115 -89
  62. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/lifecycle.py +3 -3
  63. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/logger.py +245 -64
  64. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/module.py +103 -112
  65. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/router.py +30 -26
  66. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/scope.py +7 -7
  67. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/transcript.py +123 -17
  68. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/__init__.py +4 -0
  69. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/finders/bases/finder.py +7 -4
  70. erispulse-2.11.1.dev0/src/ErisPulse/loaders/_reload_utils.py +249 -0
  71. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/adapter.py +109 -118
  72. erispulse-2.11.1.dev0/src/ErisPulse/loaders/bases/__init__.py +3 -0
  73. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/bases/loader.py +118 -121
  74. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/module.py +392 -201
  75. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/plugin_folder.py +31 -48
  76. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/__init__.py +4 -0
  77. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/example_config.py +15 -1
  78. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/file_watcher.py +97 -25
  79. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/frame_config.py +20 -1
  80. erispulse-2.11.1.dev0/src/ErisPulse/runtime/kernel.py +110 -0
  81. erispulse-2.11.1.dev0/src/ErisPulse/runtime/plugin_reload.py +358 -0
  82. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/proactive_gc.py +9 -2
  83. erispulse-2.11.1.dev0/src/ErisPulse/runtime/process_state.py +91 -0
  84. erispulse-2.11.1.dev0/src/ErisPulse/runtime/reload_ops.py +197 -0
  85. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/sdk_initializer.py +35 -7
  86. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/troubleshoot.py +71 -1
  87. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/sdk.py +186 -64
  88. erispulse-2.11.0.dev0/src/ErisPulse/CLI/constants.py +0 -76
  89. erispulse-2.11.0.dev0/src/ErisPulse/loaders/bases/__init__.py +0 -3
  90. erispulse-2.11.0.dev0/src/ErisPulse/runtime/plugin_reload.py +0 -186
  91. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/LICENSE +0 -0
  92. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/README.pypi.md +0 -0
  93. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
  94. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  95. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/console.py +0 -0
  96. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/hints.py +0 -0
  97. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
  98. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
  99. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  100. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/config_wizard.py +0 -0
  101. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/display.py +0 -0
  102. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/CLI/utils/interactive.py +0 -0
  103. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/api_dsl.py +0 -0
  104. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/config_schema.py +0 -0
  105. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/converter.py +0 -0
  106. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/errors.py +0 -0
  107. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
  108. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
  109. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
  110. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
  111. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Bases/sql_base.py +0 -0
  112. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/__init__.py +0 -0
  113. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/command.py +0 -0
  114. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/command_args.py +0 -0
  115. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/command_flow.py +0 -0
  116. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  117. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/overrides.py +0 -0
  118. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
  119. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/throttle.py +0 -0
  120. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/Event/trace.py +0 -0
  121. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/assets/__init__.py +0 -0
  122. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/assets/error.css +0 -0
  123. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/assets/error.html +0 -0
  124. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/assets/root.css +0 -0
  125. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/assets/root.html +0 -0
  126. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/di.py +0 -0
  127. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/constants.py +0 -0
  128. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
  129. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/master.py +0 -0
  130. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/ownership.py +0 -0
  131. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/shadow.py +0 -0
  132. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/storage/__init__.py +0 -0
  133. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/storage/mysql.py +0 -0
  134. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/storage/postgres.py +0 -0
  135. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/storage/sqlite.py +0 -0
  136. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/Core/text_match.py +0 -0
  137. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/__main__.py +0 -0
  138. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/finders/__init__.py +0 -0
  139. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/finders/adapter.py +0 -0
  140. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
  141. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/finders/module.py +0 -0
  142. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
  143. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/strategy.py +0 -0
  144. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/loaders/strict.py +0 -0
  145. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/py.typed +0 -0
  146. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/config_schema.py +0 -0
  147. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/context.py +0 -0
  148. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/diagnostics.py +0 -0
  149. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/exceptions.py +0 -0
  150. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/hints.py +0 -0
  151. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/memory.py +0 -0
  152. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/owner_cleanup.py +0 -0
  153. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/tasks.py +0 -0
  154. {erispulse-2.11.0.dev0 → erispulse-2.11.1.dev0}/src/ErisPulse/runtime/version.py +0 -0
@@ -234,7 +234,6 @@ pyvenv.cfg
234
234
  # docs/ar/
235
235
 
236
236
  # 翻译缓存(已提交到版本控制)
237
- # .translate_cache/
238
237
 
239
238
  # 但保留源中文文档
240
239
  !docs/zh-CN/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ErisPulse
3
- Version: 2.11.0-dev.0
3
+ Version: 2.11.1-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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.11.0-dev.0"
7
+ version = "2.11.1-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"
@@ -223,13 +223,14 @@ ignore = [
223
223
 
224
224
  [tool.ruff.lint.per-file-ignores]
225
225
  "__init__.py" = ["F401", "PLC0415", "I001"] # 导出式 __init__ 经常按需导入
226
- # 旧版生成/翻译脚本:存量风格债渐进收编(新脚本 check_i18n_locales/check_docs_links/
227
- # release_check/_common 已全净)。TODO: 逐步修复后移除本段。
228
- "scripts/tools/translate-docs.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "UP008", "A001", "SIM"]
229
- "scripts/tools/check-translation.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "SIM"]
230
- "scripts/tools/generate-api-docs.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "A001", "SIM", "W29", "E501"]
231
- "scripts/tools/generate-docs-index.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "RUF015", "SIM"]
232
- "scripts/tools/generate-type-stubs.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "ANN", "A001", "PLW0603", "SIM", "W29"]
226
+ # 旧版生成/翻译脚本:存量风格债渐进收编。TODO: 逐步修复后移除本段;
227
+ # 2026-10 scripts/tools 包化重组,路径由平铺文件名改为包内模块。
228
+ "scripts/tools/translate.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "UP008", "A001", "SIM"]
229
+ "scripts/tools/checks/translation.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "SIM"]
230
+ "scripts/tools/generators/api_docs.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "A001", "SIM", "W29", "E501"]
231
+ "scripts/tools/generators/docs_index.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "RUF015", "SIM"]
232
+ "scripts/tools/generators/type_stubs.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "ANN", "A001", "PLW0603", "SIM", "W29"]
233
+ "scripts/tools/generators/skills.py" = ["PERF401", "PTH", "UP035", "B", "RET505", "FURB", "RUF013", "SIM", "E501"]
233
234
  "tests/**/*.py" = [
234
235
  # 断言/夹具相关(测试代码天然模式)
235
236
  "S101", "PLR2004", "SLF001", "ARG", "ANN", "PTH",
@@ -5,7 +5,7 @@ CLI 命令基类
5
5
  """
6
6
 
7
7
  from abc import ABC, abstractmethod
8
- from argparse import ArgumentParser
8
+ from argparse import ArgumentParser, Namespace
9
9
 
10
10
 
11
11
  class Command(ABC):
@@ -29,7 +29,7 @@ class Command(ABC):
29
29
  category: str = "" # 主帮助分组类别标识(project/components/config/misc;空串归入 misc)
30
30
 
31
31
  @abstractmethod
32
- def add_arguments(self, parser: ArgumentParser):
32
+ def add_arguments(self, parser: ArgumentParser) -> None:
33
33
  """
34
34
  添加命令参数
35
35
 
@@ -38,7 +38,7 @@ class Command(ABC):
38
38
  ...
39
39
 
40
40
  @abstractmethod
41
- def execute(self, args):
41
+ def execute(self, args: Namespace) -> None:
42
42
  """
43
43
  执行命令
44
44
 
@@ -264,6 +264,24 @@ class CLI:
264
264
  )
265
265
  )
266
266
 
267
+ @staticmethod
268
+ def _ensure_utf8_stdio() -> None:
269
+ """
270
+ 将标准流重配置为 UTF-8(Windows GBK 代码页兜底)
271
+
272
+ 中文 Windows 控制台默认 GBK 编码,非 Rich 的裸 print 与子进程管道
273
+ 输出遇到非 GBK 字符会 ``UnicodeEncodeError``——CLI 入口统一兜底,
274
+ 一次性消灭该类偶发乱码/崩溃(历史点状爆发:翻译脚本、PowerShell BOM)。
275
+ 仅在流支持 reconfigure 时生效(Python 3.7+ 的 io.TextIOWrapper)。
276
+ """
277
+ for stream_name in ("stdout", "stderr", "stdin"):
278
+ try:
279
+ stream = getattr(sys, stream_name, None)
280
+ if stream is not None and hasattr(stream, "reconfigure"):
281
+ stream.reconfigure(encoding="utf-8")
282
+ except Exception:
283
+ pass
284
+
267
285
  def _check_command_typo(self) -> None:
268
286
  """
269
287
  在 argparse 解析之前检查命令拼写
@@ -351,7 +369,7 @@ class CLI:
351
369
  )
352
370
  i18n.increment_lang_hint()
353
371
 
354
- def run(self):
372
+ def run(self) -> None:
355
373
  """
356
374
  运行 CLI
357
375
 
@@ -361,6 +379,9 @@ class CLI:
361
379
  # 在 argparse 之前检查命令拼写(argparse 的 choices 验证会直接报错退出)
362
380
  self._check_command_typo()
363
381
 
382
+ # Windows GBK 代码页兜底:标准流统一 UTF-8(入口级一次性修复)
383
+ self._ensure_utf8_stdio()
384
+
364
385
  args, unknown = self.parser.parse_known_args()
365
386
  args._unknown_args = unknown
366
387
 
@@ -5,7 +5,7 @@ Config 命令实现
5
5
  """
6
6
 
7
7
  import json
8
- from argparse import ArgumentParser
8
+ from argparse import ArgumentParser, Namespace
9
9
 
10
10
  from rich.box import SIMPLE
11
11
  from rich.prompt import Prompt
@@ -36,7 +36,7 @@ class ConfigCommand(Command):
36
36
  aliases = ["cfg", "conf"]
37
37
  category = "config"
38
38
 
39
- def add_arguments(self, parser: ArgumentParser):
39
+ def add_arguments(self, parser: ArgumentParser) -> None:
40
40
  parser.add_argument(
41
41
  "name",
42
42
  nargs="?",
@@ -54,7 +54,7 @@ class ConfigCommand(Command):
54
54
  help=i18n.t("cli.config.json_help"),
55
55
  )
56
56
 
57
- def execute(self, args):
57
+ def execute(self, args: Namespace) -> None:
58
58
  from ErisPulse import config
59
59
 
60
60
  targets = config_wizard.load_config_targets()
@@ -7,7 +7,7 @@ Create 命令实现
7
7
  import datetime
8
8
  import shutil
9
9
  import sys
10
- from argparse import ArgumentParser
10
+ from argparse import ArgumentParser, Namespace
11
11
  from pathlib import Path
12
12
 
13
13
  from rich.prompt import IntPrompt, Prompt
@@ -555,7 +555,7 @@ class {name}(BaseAdapter):
555
555
  raw = json.loads(data)
556
556
  event = self.convert(raw)
557
557
  if event:
558
- await self.adapter.emit(event)
558
+ await self.emit_event(event)
559
559
  except Exception as e:
560
560
  self.logger.warning("{text[adapter.log.connection_lost]}")
561
561
  finally:
@@ -595,6 +595,351 @@ class {name}(BaseAdapter):
595
595
  """
596
596
 
597
597
 
598
+ _ADAPTER_CORE_POLLING = """import asyncio
599
+ from dataclasses import dataclass, field
600
+ from typing import ClassVar
601
+ from ErisPulse import PollingAdapter, BaseConfig, BaseI18n, I18nKey, client
602
+
603
+
604
+ class {name}(PollingAdapter):
605
+ \"\"\"
606
+ {text[adapter.polling.doc]}
607
+ \"\"\"
608
+
609
+ # 依赖声明(可选,ErisPulse 2.9.0+):
610
+ # depends = {{"adapters": [], "modules": []}} # 硬依赖:缺失时跳过启动
611
+ # optional_modules = [] # 软依赖:就绪/丢失时收到
612
+ # # on_dependency_ready/lost 回调
613
+ depends: ClassVar[dict] = {{}}
614
+ optional_modules: ClassVar[list] = []
615
+
616
+ # 声明所需最低 SDK 版本:不满足时框架在加载期明确报错并跳过本适配器(可选)
617
+ min_sdk_version = "{min_sdk}"
618
+
619
+ # 轮询间隔(秒):声明了下方 ConfigClass.poll_interval 字段后以配置值为准
620
+ poll_interval = 5.0
621
+
622
+ # {text[adapter.config_hint]}
623
+ @dataclass
624
+ class ConfigClass(BaseConfig):
625
+ \"\"\"
626
+ {text[adapter.config_doc]}
627
+
628
+ :ivar poll_interval: 轮询间隔秒数(热更新生效)
629
+ \"\"\"
630
+
631
+ endpoint: str = field(
632
+ default="https://api.example.com",
633
+ metadata={{
634
+ "description": {{"i18n": "adapter.{name}.endpoint", "default": "Platform API Endpoint"}},
635
+ "required": False,
636
+ "ui": {{"widget": "text", "group": "connection", "order": 1}},
637
+ }},
638
+ )
639
+ token: str = field(
640
+ default="",
641
+ metadata={{
642
+ "description": {{"i18n": "adapter.{name}.token", "default": "Platform Token"}},
643
+ "required": True,
644
+ "secret": True,
645
+ "ui": {{"widget": "password", "group": "basic", "order": 2}},
646
+ }},
647
+ )
648
+ poll_interval: float = field(
649
+ default=5.0,
650
+ metadata={{
651
+ "description": {{"i18n": "adapter.{name}.poll_interval", "default": "Polling interval (seconds)"}},
652
+ "required": False,
653
+ "min": 0.1,
654
+ "ui": {{"widget": "number", "group": "connection", "order": 3}},
655
+ }},
656
+ )
657
+
658
+ # {text[adapter.i18n_hint]}
659
+ class I18nClass(BaseI18n):
660
+ \"\"\"{name} translation keys\"\"\"
661
+
662
+ endpoint: I18nKey = I18nKey(
663
+ key="adapter.{name}.endpoint",
664
+ default="Platform API Endpoint",
665
+ zh_CN="平台 API 地址",
666
+ en="Platform API Endpoint",
667
+ ja="APIアドレス",
668
+ ru="API адрес",
669
+ zh_TW="API 位址",
670
+ )
671
+ token: I18nKey = I18nKey(
672
+ key="adapter.{name}.token",
673
+ default="Platform Token",
674
+ zh_CN="平台 Token",
675
+ en="Platform Token",
676
+ ja="トークン",
677
+ ru="Токен",
678
+ zh_TW="權杖",
679
+ )
680
+ poll_interval: I18nKey = I18nKey(
681
+ key="adapter.{name}.poll_interval",
682
+ default="Polling interval (seconds)",
683
+ zh_CN="轮询间隔(秒)",
684
+ en="Polling interval (seconds)",
685
+ ja="ポーリング間隔(秒)",
686
+ ru="Интервал опроса (сек)",
687
+ zh_TW="輪詢間隔(秒)",
688
+ )
689
+
690
+ def __init__(self, sdk=None):
691
+ super().__init__(sdk=sdk)
692
+ self.logger = self._get_logger()
693
+ self.converter = self._setup_converter()
694
+
695
+ def on_config_update(self, old_config, new_config):
696
+ \"\"\"Called when adapter config hot-reloads\"\"\"
697
+ self.logger.info("{text[adapter.log.config_updated]}")
698
+
699
+ def _setup_converter(self):
700
+ from .Converter import {converter_name}
701
+ return {converter_name}()
702
+
703
+ # start() / shutdown() 由 PollingAdapter 基类管理:
704
+ # start 拉起带指数退避的轮询循环后立即返回;shutdown 时框架按 owner 自动取消
705
+
706
+ async def fetch_events(self):
707
+ \"\"\"
708
+ {text[adapter.polling.fetch_doc]}
709
+ \"\"\"
710
+ cfg = self.cfg
711
+ # TODO: 替换为平台的增量拉取接口(如 Telegram getUpdates,配合 offset 去重)
712
+ resp = await client.get(
713
+ f"{{cfg.endpoint}}/getUpdates",
714
+ headers={{"Authorization": "Bearer " + cfg.token}},
715
+ )
716
+ data = await resp.json()
717
+ return data.get("events", [])
718
+
719
+ def convert_one(self, raw):
720
+ \"\"\"
721
+ {text[adapter.polling.convert_one_doc]}
722
+ \"\"\"
723
+ # TODO: 按平台事件结构调整(Converter 模板已给出 message 型骨架)
724
+ return self.converter.convert(raw)
725
+
726
+ class Send(PollingAdapter.Send):
727
+ \"\"\"
728
+ {text[adapter.dsl.send_doc]}
729
+ \"\"\"
730
+
731
+ def Raw_ob12(self, message, **kwargs):
732
+ async def _do_send():
733
+ segments = self._apply_modifiers(message)
734
+ return await self._adapter.call_api(
735
+ endpoint="/send_message",
736
+ message=segments,
737
+ **self.send_context,
738
+ **kwargs,
739
+ )
740
+ return asyncio.create_task(_do_send())
741
+
742
+ # {text[adapter.dsl.send_std_methods_hint]}
743
+ # {text[adapter.dsl.send_override_hint]}
744
+ # def Text(self, text: str):
745
+ # return self.Raw_ob12([{{"type": "text", "data": {{"text": text}}}}])
746
+
747
+ # {text[adapter.dsl.send_extra_methods_hint]}
748
+ # def Sticker(self, sticker_id: str):
749
+ # return self.Raw_ob12([{{"type": "sticker", "data": {{"id": sticker_id}}}}])
750
+
751
+ # Request / Api 内部类继承基类默认实现即可;如需平台特定逻辑可按需覆盖
752
+
753
+ async def call_api(self, endpoint: str, **params):
754
+ \"\"\"Call platform API\"\"\"
755
+ cfg = self.cfg
756
+ headers = {{"Authorization": "Bearer " + cfg.token}}
757
+ url = cfg.endpoint + endpoint
758
+
759
+ try:
760
+ resp = await client.post(
761
+ url,
762
+ json=params,
763
+ headers=headers,
764
+ timeout=30,
765
+ max_retries=2,
766
+ )
767
+ result = await resp.json()
768
+ return self.make_response(
769
+ data=result.get("data"),
770
+ message_id=result.get("data", {{}}).get("message_id", ""),
771
+ raw=result,
772
+ )
773
+ except Exception as e:
774
+ self.logger.error(("{text[adapter.log.api_call_failed]}").format(error=e))
775
+ return self.make_error(message=str(e))
776
+ """
777
+
778
+
779
+ _ADAPTER_CORE_WEBHOOK = """import asyncio
780
+ from dataclasses import dataclass, field
781
+ from typing import ClassVar
782
+ from ErisPulse import WebhookAdapter, BaseConfig, BaseI18n, I18nKey, client
783
+
784
+
785
+ class {name}(WebhookAdapter):
786
+ \"\"\"
787
+ {text[adapter.webhook.doc]}
788
+ \"\"\"
789
+
790
+ # 依赖声明(可选,ErisPulse 2.9.0+):
791
+ # depends = {{"adapters": [], "modules": []}} # 硬依赖:缺失时跳过启动
792
+ # optional_modules = [] # 软依赖:就绪/丢失时收到
793
+ # # on_dependency_ready/lost 回调
794
+ depends: ClassVar[dict] = {{}}
795
+ optional_modules: ClassVar[list] = []
796
+
797
+ # 声明所需最低 SDK 版本:不满足时框架在加载期明确报错并跳过本适配器(可选)
798
+ min_sdk_version = "{min_sdk}"
799
+
800
+ # {text[adapter.config_hint]}
801
+ @dataclass
802
+ class ConfigClass(BaseConfig):
803
+ \"\"\"
804
+ {text[adapter.config_doc]}
805
+ \"\"\"
806
+
807
+ endpoint: str = field(
808
+ default="https://api.example.com",
809
+ metadata={{
810
+ "description": {{"i18n": "adapter.{name}.endpoint", "default": "Platform API Endpoint"}},
811
+ "required": False,
812
+ "ui": {{"widget": "text", "group": "connection", "order": 1}},
813
+ }},
814
+ )
815
+ token: str = field(
816
+ default="",
817
+ metadata={{
818
+ "description": {{"i18n": "adapter.{name}.token", "default": "Verify Token (empty = accept all)"}},
819
+ "required": False,
820
+ "secret": True,
821
+ "ui": {{"widget": "password", "group": "basic", "order": 2}},
822
+ }},
823
+ )
824
+
825
+ # {text[adapter.i18n_hint]}
826
+ class I18nClass(BaseI18n):
827
+ \"\"\"{name} translation keys\"\"\"
828
+
829
+ endpoint: I18nKey = I18nKey(
830
+ key="adapter.{name}.endpoint",
831
+ default="Platform API Endpoint",
832
+ zh_CN="平台 API 地址",
833
+ en="Platform API Endpoint",
834
+ ja="APIアドレス",
835
+ ru="API адрес",
836
+ zh_TW="API 位址",
837
+ )
838
+ token: I18nKey = I18nKey(
839
+ key="adapter.{name}.token",
840
+ default="Verify Token (empty = accept all)",
841
+ zh_CN="校验 Token(留空放行全部请求)",
842
+ en="Verify Token (empty = accept all)",
843
+ ja="検証トークン(空なら全許可)",
844
+ ru="Токен проверки (пусто = разрешить все)",
845
+ zh_TW="校驗權杖(留空放行全部請求)",
846
+ )
847
+
848
+ def __init__(self, sdk=None):
849
+ super().__init__(sdk=sdk)
850
+ self.logger = self._get_logger()
851
+ self.converter = self._setup_converter()
852
+
853
+ def on_config_update(self, old_config, new_config):
854
+ \"\"\"Called when adapter config hot-reloads\"\"\"
855
+ self.logger.info("{text[adapter.log.config_updated]}")
856
+
857
+ def _setup_converter(self):
858
+ from .Converter import {converter_name}
859
+ return {converter_name}()
860
+
861
+ # start() / shutdown() 由 WebhookAdapter 基类管理:
862
+ # start 在框架 router 上注册 POST /{entry_key}/webhook 接收路由(owner 归属,
863
+ # 卸载自动清理);回调地址经 sdk.adapter.get_connection_info("{entry_key}") 查询
864
+
865
+ def verify_request(self, request) -> bool:
866
+ \"\"\"
867
+ {text[adapter.webhook.verify_doc]}
868
+ \"\"\"
869
+ cfg = self.cfg
870
+ if not cfg.token:
871
+ return True
872
+ # TODO: 按平台校验方式调整(签名头 / query token / 时间戳防重放等)
873
+ auth = request.headers.get("authorization", "")
874
+ return auth == f"Bearer {{cfg.token}}"
875
+
876
+ def convert(self, payload):
877
+ \"\"\"
878
+ {text[adapter.webhook.convert_doc]}
879
+ \"\"\"
880
+ # TODO: 按平台回调载荷结构调整(Converter 模板已给出 message 型骨架)
881
+ return self.converter.convert(payload)
882
+
883
+ class Send(WebhookAdapter.Send):
884
+ \"\"\"
885
+ {text[adapter.dsl.send_doc]}
886
+ \"\"\"
887
+
888
+ def Raw_ob12(self, message, **kwargs):
889
+ async def _do_send():
890
+ segments = self._apply_modifiers(message)
891
+ return await self._adapter.call_api(
892
+ endpoint="/send_message",
893
+ message=segments,
894
+ **self.send_context,
895
+ **kwargs,
896
+ )
897
+ return asyncio.create_task(_do_send())
898
+
899
+ # {text[adapter.dsl.send_std_methods_hint]}
900
+ # {text[adapter.dsl.send_override_hint]}
901
+ # def Text(self, text: str):
902
+ # return self.Raw_ob12([{{"type": "text", "data": {{"text": text}}}}])
903
+
904
+ # {text[adapter.dsl.send_extra_methods_hint]}
905
+ # def Sticker(self, sticker_id: str):
906
+ # return self.Raw_ob12([{{"type": "sticker", "data": {{"id": sticker_id}}}}])
907
+
908
+ # Request / Api 内部类继承基类默认实现即可;如需平台特定逻辑可按需覆盖
909
+
910
+ async def call_api(self, endpoint: str, **params):
911
+ \"\"\"Call platform API\"\"\"
912
+ cfg = self.cfg
913
+ headers = {{"Authorization": "Bearer " + cfg.token}}
914
+ url = cfg.endpoint + endpoint
915
+
916
+ try:
917
+ resp = await client.post(
918
+ url,
919
+ json=params,
920
+ headers=headers,
921
+ timeout=30,
922
+ max_retries=2,
923
+ )
924
+ result = await resp.json()
925
+ return self.make_response(
926
+ data=result.get("data"),
927
+ message_id=result.get("data", {{}}).get("message_id", ""),
928
+ raw=result,
929
+ )
930
+ except Exception as e:
931
+ self.logger.error(("{text[adapter.log.api_call_failed]}").format(error=e))
932
+ return self.make_error(message=str(e))
933
+ """
934
+
935
+ # 适配器 --template 选项 → 核心模板映射(ws-server 保持既有默认行为)
936
+ _ADAPTER_CORE_TEMPLATES = {
937
+ "ws-server": _ADAPTER_CORE,
938
+ "polling": _ADAPTER_CORE_POLLING,
939
+ "webhook": _ADAPTER_CORE_WEBHOOK,
940
+ }
941
+
942
+
598
943
  _ADAPTER_CONVERTER = """\"\"\"
599
944
  {text[adapter.converter_doc]}
600
945
  \"\"\"
@@ -796,7 +1141,7 @@ class CreateCommand(Command):
796
1141
  aliases = ["c", "new"]
797
1142
  category = "project"
798
1143
 
799
- def add_arguments(self, parser: ArgumentParser):
1144
+ def add_arguments(self, parser: ArgumentParser) -> None:
800
1145
  parser.add_argument(
801
1146
  "create_type",
802
1147
  nargs="?",
@@ -828,8 +1173,14 @@ class CreateCommand(Command):
828
1173
  default=False,
829
1174
  help=i18n.t("cli.create.local_help"),
830
1175
  )
1176
+ parser.add_argument(
1177
+ "--template",
1178
+ choices=list(_ADAPTER_CORE_TEMPLATES),
1179
+ default="ws-server",
1180
+ help=i18n.t("cli.create.adapter_template_help"),
1181
+ )
831
1182
 
832
- def execute(self, args):
1183
+ def execute(self, args: Namespace) -> None:
833
1184
  create_type = getattr(args, "create_type", None)
834
1185
  if not create_type:
835
1186
  create_type = self._interactive_select_type()
@@ -1243,13 +1594,15 @@ class CreateCommand(Command):
1243
1594
 
1244
1595
  converter_name = _to_converter_name(name)
1245
1596
  entry_key = _camel_to_snake(name)
1597
+ template = getattr(args, "template", None) or "ws-server"
1598
+ core_template = _ADAPTER_CORE_TEMPLATES[template]
1246
1599
 
1247
1600
  (plugin_dir / "__init__.py").write_text(
1248
1601
  _ADAPTER_INIT.format(name=name, converter_name=converter_name),
1249
1602
  encoding="utf-8",
1250
1603
  )
1251
1604
  (plugin_dir / "Core.py").write_text(
1252
- _ADAPTER_CORE.format(
1605
+ core_template.format(
1253
1606
  name=name,
1254
1607
  converter_name=converter_name,
1255
1608
  entry_key=entry_key,
@@ -1272,6 +1625,9 @@ class CreateCommand(Command):
1272
1625
  console.print(
1273
1626
  f"[success] {i18n.t('cli.create.adapter_created', name=name)}[/]"
1274
1627
  )
1628
+ console.print(
1629
+ f"[dim] {i18n.t('cli.create.template_used', template=i18n.t('cli.create.template_' + template.replace('-', '_')))}[/]"
1630
+ )
1275
1631
  console.print()
1276
1632
  console.print(Text(i18n.t("cli.create.local_structure"), style="bold"))
1277
1633
  console.print(" plugins/")
@@ -1328,6 +1684,8 @@ class CreateCommand(Command):
1328
1684
 
1329
1685
  converter_name = _to_converter_name(name)
1330
1686
  entry_key = _camel_to_snake(name)
1687
+ template = getattr(args, "template", None) or "ws-server"
1688
+ core_template = _ADAPTER_CORE_TEMPLATES[template]
1331
1689
  output = Path(args.output)
1332
1690
  project_dir = output / name
1333
1691
 
@@ -1347,7 +1705,7 @@ class CreateCommand(Command):
1347
1705
  encoding="utf-8",
1348
1706
  )
1349
1707
  (pkg_dir / "Core.py").write_text(
1350
- _ADAPTER_CORE.format(
1708
+ core_template.format(
1351
1709
  name=name,
1352
1710
  converter_name=converter_name,
1353
1711
  entry_key=entry_key,
@@ -1393,6 +1751,9 @@ class CreateCommand(Command):
1393
1751
  console.print(
1394
1752
  f"[success] {i18n.t('cli.create.adapter_created', name=name)}[/]"
1395
1753
  )
1754
+ console.print(
1755
+ f"[dim] {i18n.t('cli.create.template_used', template=i18n.t('cli.create.template_' + template.replace('-', '_')))}[/]"
1756
+ )
1396
1757
  console.print()
1397
1758
  console.print(Text(i18n.t("cli.create.project_structure"), style="bold"))
1398
1759
  console.print(f" {name}/")