ErisPulse 2.5.2.dev0__py3-none-any.whl → 2.5.2.dev2__py3-none-any.whl

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 (45) hide show
  1. ErisPulse/CLI/commands/run.py +24 -20
  2. ErisPulse/CLI/commands/run.pyi +8 -2
  3. ErisPulse/CLI/i18n/locales/en.py +11 -10
  4. ErisPulse/CLI/i18n/locales/ja.py +11 -10
  5. ErisPulse/CLI/i18n/locales/ru.py +11 -10
  6. ErisPulse/CLI/i18n/locales/zh_cn.py +11 -10
  7. ErisPulse/CLI/i18n/locales/zh_tw.py +11 -10
  8. ErisPulse/CLI/utils/package_manager.py +8 -47
  9. ErisPulse/CLI/utils/package_manager.pyi +0 -3
  10. ErisPulse/Core/Event/__init__.py +33 -26
  11. ErisPulse/Core/Event/__init__.pyi +4 -4
  12. ErisPulse/Core/Event/base.py +36 -19
  13. ErisPulse/Core/Event/base.pyi +7 -7
  14. ErisPulse/Core/Event/command.py +45 -14
  15. ErisPulse/Core/Event/command.pyi +1 -1
  16. ErisPulse/Core/Event/session_type.py +2 -2
  17. ErisPulse/Core/Event/wrapper.py +73 -38
  18. ErisPulse/Core/Event/wrapper.pyi +3 -3
  19. ErisPulse/Core/adapter.py +14 -10
  20. ErisPulse/Core/client.py +19 -9
  21. ErisPulse/Core/client.pyi +7 -1
  22. ErisPulse/Core/config.py +37 -15
  23. ErisPulse/Core/config.pyi +1 -0
  24. ErisPulse/Core/constants.py +12 -8
  25. ErisPulse/Core/i18n/locales/en.py +4 -3
  26. ErisPulse/Core/i18n/locales/ja.py +4 -3
  27. ErisPulse/Core/i18n/locales/ru.py +4 -3
  28. ErisPulse/Core/i18n/locales/zh_cn.py +4 -3
  29. ErisPulse/Core/i18n/locales/zh_tw.py +4 -3
  30. ErisPulse/Core/logger.py +155 -32
  31. ErisPulse/Core/logger.pyi +34 -4
  32. ErisPulse/Core/module.py +2 -0
  33. ErisPulse/Core/router.py +22 -17
  34. ErisPulse/Core/storage.py +30 -3
  35. ErisPulse/finders/bases/finder.py +5 -4
  36. ErisPulse/loaders/module.py +6 -6
  37. ErisPulse/loaders/strict.py +1 -1
  38. ErisPulse/loaders/strict.pyi +1 -1
  39. ErisPulse/sdk.py +16 -31
  40. ErisPulse/sdk.pyi +6 -3
  41. {erispulse-2.5.2.dev0.dist-info → erispulse-2.5.2.dev2.dist-info}/METADATA +1 -1
  42. {erispulse-2.5.2.dev0.dist-info → erispulse-2.5.2.dev2.dist-info}/RECORD +45 -45
  43. {erispulse-2.5.2.dev0.dist-info → erispulse-2.5.2.dev2.dist-info}/WHEEL +0 -0
  44. {erispulse-2.5.2.dev0.dist-info → erispulse-2.5.2.dev2.dist-info}/entry_points.txt +0 -0
  45. {erispulse-2.5.2.dev0.dist-info → erispulse-2.5.2.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -128,13 +128,20 @@ class RunCommand(Command):
128
128
  self._run_internal(reload_mode)
129
129
 
130
130
  _RESTART_EXIT_CODE = 42
131
+ _MAX_CRASH_BACKOFF = 60.0
131
132
 
132
133
  def _run_internal(self, reload_mode: bool):
133
134
  """
134
135
  直接运行 SDK(不指定脚本时)
135
136
 
136
- 以子进程方式运行 SDK,支持硬重启:当 SDK 进程以特定退出码退出时,
137
- 自动重新启动新进程,确保资源完全释放。
137
+ 以子进程方式运行 SDK,支持硬重启。
138
+
139
+ {!--< tips >!--}
140
+ 重要设计原则:
141
+ 1. 只有硬重启(退出码 42)或 KeyboardInterrupt 才能停止主进程
142
+ 2. 模块/适配器的任何错误都**不会**导致主进程退出
143
+ 3. 子进程异常退出时自动重试,使用递增退避策略避免刷屏
144
+ {!--< /tips >!--}
138
145
  """
139
146
 
140
147
  if reload_mode:
@@ -168,33 +175,30 @@ class RunCommand(Command):
168
175
  "asyncio.run(sdk.run(keep_running=True))",
169
176
  ]
170
177
 
171
- import signal
172
-
178
+ crash_count = 0
173
179
  try:
174
180
  while True:
175
181
  process = subprocess.Popen(cmd)
176
-
177
- # 转发 SIGTERM/SIGINT 到子进程,使 SDK 能优雅关闭
178
- def _forward_signal(signum, frame):
179
- try:
180
- process.send_signal(signum)
181
- except Exception:
182
- pass
183
-
184
- old_term = signal.signal(signal.SIGTERM, _forward_signal)
185
- old_int = signal.signal(signal.SIGINT, _forward_signal)
186
-
187
182
  process.wait()
188
183
 
189
- # 恢复默认信号处理
190
- signal.signal(signal.SIGTERM, old_term)
191
- signal.signal(signal.SIGINT, old_int)
192
-
193
184
  if process.returncode == self._RESTART_EXIT_CODE:
194
185
  console.print(f"[info]{i18n.t('cli.run.restart_request')}[/]")
186
+ crash_count = 0
195
187
  time.sleep(0.5)
196
188
  continue
197
- break
189
+
190
+ # 非硬重启退出码:模块/适配器内部错误导致子进程异常终止
191
+ # 不退出主进程,等待后自动重试
192
+ crash_count += 1
193
+ backoff = min(self._MAX_CRASH_BACKOFF, 3.0 * crash_count)
194
+ console.print(
195
+ f"[warning]{i18n.t('cli.run.process_crashed', code=process.returncode)}[/]"
196
+ )
197
+ console.print(
198
+ f"[info]{i18n.t('cli.run.subprocess_crashed_retry', seconds=backoff)}[/]"
199
+ )
200
+ time.sleep(backoff)
201
+ # 继续循环,重新启动子进程
198
202
  except KeyboardInterrupt:
199
203
  pass
200
204
 
@@ -72,8 +72,14 @@ class RunCommand(Command):
72
72
  """
73
73
  直接运行 SDK(不指定脚本时)
74
74
 
75
- 以子进程方式运行 SDK,支持硬重启:当 SDK 进程以特定退出码退出时,
76
- 自动重新启动新进程,确保资源完全释放。
75
+ 以子进程方式运行 SDK,支持硬重启。
76
+
77
+ {!--< tips >!--}
78
+ 重要设计原则:
79
+ 1. 只有硬重启(退出码 42)或 KeyboardInterrupt 才能停止主进程
80
+ 2. 模块/适配器的任何错误都**不会**导致主进程退出
81
+ 3. 子进程异常退出时自动重试,使用递增退避策略避免刷屏
82
+ {!--< /tips >!--}
77
83
  """
78
84
  ...
79
85
  def _run_script(self: object, script_path: str, reload_mode: bool) -> ...:
@@ -249,6 +249,7 @@ TRANSLATIONS = {
249
249
  "cli.run.file_changed_restart": "File change detected ([cmd]{file}[/]), restarting...",
250
250
  "cli.run.process_exited": "Process exited normally, waiting for file changes to restart",
251
251
  "cli.run.process_crashed": "Process crashed (exit code {code}), fix and save to restart",
252
+ "cli.run.subprocess_crashed_retry": "Subprocess crashed, will auto-retry in {seconds}s...",
252
253
  # ==================== uninstall command ====================
253
254
  "cli.uninstall.description": "Uninstall module/adapter packages",
254
255
  "cli.uninstall.package_help": "Package name(s) to uninstall (multiple allowed)",
@@ -315,18 +316,18 @@ TRANSLATIONS = {
315
316
  "cli.package.compat_warning_upgrade": "SDK Version Compatibility Warning\nPackage {package} requires minimum SDK version {version}\n{message}\n\nContinuing the upgrade may cause issues.",
316
317
  "cli.package.compat_warning_title": "Compatibility Warning",
317
318
  "cli.package.installing": "Installing {package}",
318
- "cli.package.install_success": " Package {package} installed successfully",
319
- "cli.package.install_failed": " Package {package} installation failed",
320
- "cli.package.operation_success": " {description} succeeded",
321
- "cli.package.operation_failed": " {description} failed",
319
+ "cli.package.install_success": "[OK] Package {package} installed successfully",
320
+ "cli.package.install_failed": "[FAIL] Package {package} installation failed",
321
+ "cli.package.operation_success": "[OK] {description} succeeded",
322
+ "cli.package.operation_failed": "[FAIL] {description} failed",
322
323
  "cli.package.alias_mapping": " Alias mapping: {alias} → {package}",
323
324
  "cli.package.installed_package_found": " Found installed package: {package}",
324
325
  "cli.package.uninstall_alias_not_found": " No alias found, attempting direct uninstall: {package}",
325
326
  "cli.package.confirm_uninstall": "Confirm uninstall the following packages?\n{packages}",
326
327
  "cli.package.operation_cancelled": " Operation cancelled",
327
328
  "cli.package.uninstalling": "Uninstalling {package}",
328
- "cli.package.uninstall_success": " Package {package} uninstalled successfully",
329
- "cli.package.uninstall_failed": " Package {package} uninstall failed",
329
+ "cli.package.uninstall_success": "[OK] Package {package} uninstalled successfully",
330
+ "cli.package.uninstall_failed": "[FAIL] Package {package} uninstall failed",
330
331
  "cli.package.all_up_to_date": "All ErisPulse packages are up to date",
331
332
  "cli.package.updates_found": "Found {count} package(s) to upgrade:",
332
333
  "cli.package.upgrade_list_title": "Upgrade List",
@@ -343,8 +344,8 @@ TRANSLATIONS = {
343
344
  "cli.package.confirm_upgrade": "Continue with upgrade?",
344
345
  "cli.package.upgrade_cancelled": "Upgrade cancelled",
345
346
  "cli.package.upgrading": "Upgrading {package}",
346
- "cli.package.upgrade_success": " Package {package} upgraded successfully",
347
- "cli.package.upgrade_failed": " Package {package} upgrade failed",
347
+ "cli.package.upgrade_success": "[OK] Package {package} upgraded successfully",
348
+ "cli.package.upgrade_failed": "[FAIL] Package {package} upgrade failed",
348
349
  "cli.package.pypi_versions_failed": "Failed to fetch PyPI version info",
349
350
  "cli.package.already_target_version": "Already at target version {version}",
350
351
  "cli.package.invalid_version": "Invalid version number: {version}",
@@ -353,7 +354,7 @@ TRANSLATIONS = {
353
354
  "cli.package.update_desc_with_version": "Updating ErisPulse SDK to {version}",
354
355
  "cli.package.update_desc_latest": "Updating ErisPulse SDK to the latest version",
355
356
  "cli.package.latest_version": "latest version",
356
- "cli.package.sdk_update_success": " ErisPulse SDK updated successfully: {old} → {new}",
357
+ "cli.package.sdk_update_success": "[OK] ErisPulse SDK updated successfully: {old} → {new}",
357
358
  "cli.package.restart_cli": "Please restart the CLI to use the new version",
358
- "cli.package.sdk_update_failed": " ErisPulse SDK update failed",
359
+ "cli.package.sdk_update_failed": "[FAIL] ErisPulse SDK update failed",
359
360
  }
@@ -249,6 +249,7 @@ TRANSLATIONS = {
249
249
  "cli.run.file_changed_restart": "ファイル変更を検出 ([cmd]{file}[/])、再起動中...",
250
250
  "cli.run.process_exited": "プロセスが正常に終了しました。ファイルの変更を待機して再起動",
251
251
  "cli.run.process_crashed": "プロセスが異常終了しました(終了コード {code})。修正して保存すると自動再起動",
252
+ "cli.run.subprocess_crashed_retry": "サブプロセスが異常終了しました。{seconds} 秒後に自動再試行します...",
252
253
  # ==================== uninstall コマンド ====================
253
254
  "cli.uninstall.description": "モジュール/アダプターパッケージをアンインストール",
254
255
  "cli.uninstall.package_help": "アンインストールするパッケージ名(複数指定可)",
@@ -315,18 +316,18 @@ TRANSLATIONS = {
315
316
  "cli.package.compat_warning_upgrade": "SDK バージョン互換性警告\nパッケージ {package} は最小 SDK バージョン {version} が必要です\n{message}\n\nアップグレードを続行すると問題が発生する可能性があります。",
316
317
  "cli.package.compat_warning_title": "互換性警告",
317
318
  "cli.package.installing": "インストール中 {package}",
318
- "cli.package.install_success": " パッケージ {package} のインストールに成功しました",
319
- "cli.package.install_failed": " パッケージ {package} のインストールに失敗しました",
320
- "cli.package.operation_success": " {description} 成功",
321
- "cli.package.operation_failed": " {description} 失敗",
319
+ "cli.package.install_success": "[OK] パッケージ {package} のインストールに成功しました",
320
+ "cli.package.install_failed": "[FAIL] パッケージ {package} のインストールに失敗しました",
321
+ "cli.package.operation_success": "[OK] {description} 成功",
322
+ "cli.package.operation_failed": "[FAIL] {description} 失敗",
322
323
  "cli.package.alias_mapping": " エイリアスマッピング: {alias} → {package}",
323
324
  "cli.package.installed_package_found": " インストール済みパッケージが見つかりました: {package}",
324
325
  "cli.package.uninstall_alias_not_found": " エイリアスが見つかりません。直接アンインストールを試みます: {package}",
325
326
  "cli.package.confirm_uninstall": "以下のパッケージをアンインストールしますか?\n{packages}",
326
327
  "cli.package.operation_cancelled": " 操作がキャンセルされました",
327
328
  "cli.package.uninstalling": "アンインストール中 {package}",
328
- "cli.package.uninstall_success": " パッケージ {package} のアンインストールに成功しました",
329
- "cli.package.uninstall_failed": " パッケージ {package} のアンインストールに失敗しました",
329
+ "cli.package.uninstall_success": "[OK] パッケージ {package} のアンインストールに成功しました",
330
+ "cli.package.uninstall_failed": "[FAIL] パッケージ {package} のアンインストールに失敗しました",
330
331
  "cli.package.all_up_to_date": "すべての ErisPulse パッケージは最新です",
331
332
  "cli.package.updates_found": "{count} 個のアップグレード可能なパッケージが見つかりました:",
332
333
  "cli.package.upgrade_list_title": "アップグレードリスト",
@@ -343,8 +344,8 @@ TRANSLATIONS = {
343
344
  "cli.package.confirm_upgrade": "アップグレードを続行しますか?",
344
345
  "cli.package.upgrade_cancelled": "アップグレードがキャンセルされました",
345
346
  "cli.package.upgrading": "アップグレード中 {package}",
346
- "cli.package.upgrade_success": " パッケージ {package} のアップグレードに成功しました",
347
- "cli.package.upgrade_failed": " パッケージ {package} のアップグレードに失敗しました",
347
+ "cli.package.upgrade_success": "[OK] パッケージ {package} のアップグレードに成功しました",
348
+ "cli.package.upgrade_failed": "[FAIL] パッケージ {package} のアップグレードに失敗しました",
348
349
  "cli.package.pypi_versions_failed": "PyPI バージョン情報の取得に失敗しました",
349
350
  "cli.package.already_target_version": "すでにターゲットバージョン {version} です",
350
351
  "cli.package.invalid_version": "無効なバージョン番号: {version}",
@@ -353,7 +354,7 @@ TRANSLATIONS = {
353
354
  "cli.package.update_desc_with_version": "ErisPulse SDK を {version} に更新中",
354
355
  "cli.package.update_desc_latest": "ErisPulse SDK を最新バージョンに更新中",
355
356
  "cli.package.latest_version": "最新バージョン",
356
- "cli.package.sdk_update_success": " ErisPulse SDK の更新に成功しました: {old} → {new}",
357
+ "cli.package.sdk_update_success": "[OK] ErisPulse SDK の更新に成功しました: {old} → {new}",
357
358
  "cli.package.restart_cli": "新しいバージョンを使用するには CLI を再起動してください",
358
- "cli.package.sdk_update_failed": " ErisPulse SDK の更新に失敗しました",
359
+ "cli.package.sdk_update_failed": "[FAIL] ErisPulse SDK の更新に失敗しました",
359
360
  }
@@ -249,6 +249,7 @@ TRANSLATIONS = {
249
249
  "cli.run.file_changed_restart": "Обнаружено изменение файла ([cmd]{file}[/]), перезапуск...",
250
250
  "cli.run.process_exited": "Процесс завершен нормально, ожидание изменений файлов для перезапуска",
251
251
  "cli.run.process_crashed": "Процесс аварийно завершен (код {code}), исправьте и сохраните для перезапуска",
252
+ "cli.run.subprocess_crashed_retry": "Подпроцесс аварийно завершен, автоматическая перезагрузка через {seconds}с...",
252
253
  # ==================== команда uninstall ====================
253
254
  "cli.uninstall.description": "Удалить пакеты модулей/адаптеров",
254
255
  "cli.uninstall.package_help": "Имя(ена) пакета(ов) для удаления (можно указать несколько)",
@@ -315,18 +316,18 @@ TRANSLATIONS = {
315
316
  "cli.package.compat_warning_upgrade": "Предупреждение о совместимости версии SDK\nПакет {package} требует минимальную версию SDK {version}\n{message}\n\nПродолжение обновления может вызвать проблемы.",
316
317
  "cli.package.compat_warning_title": "Предупреждение о совместимости",
317
318
  "cli.package.installing": "Установка {package}",
318
- "cli.package.install_success": " Пакет {package} успешно установлен",
319
- "cli.package.install_failed": " Ошибка установки пакета {package}",
320
- "cli.package.operation_success": " {description} выполнено",
321
- "cli.package.operation_failed": " {description} не удалось",
319
+ "cli.package.install_success": "[OK] Пакет {package} успешно установлен",
320
+ "cli.package.install_failed": "[FAIL] Ошибка установки пакета {package}",
321
+ "cli.package.operation_success": "[OK] {description} выполнено",
322
+ "cli.package.operation_failed": "[FAIL] {description} не удалось",
322
323
  "cli.package.alias_mapping": " Сопоставление псевдонима: {alias} → {package}",
323
324
  "cli.package.installed_package_found": " Найден установленный пакет: {package}",
324
325
  "cli.package.uninstall_alias_not_found": " Псевдоним не найден, попытка прямого удаления: {package}",
325
326
  "cli.package.confirm_uninstall": "Подтвердить удаление следующих пакетов?\n{packages}",
326
327
  "cli.package.operation_cancelled": " Операция отменена",
327
328
  "cli.package.uninstalling": "Удаление {package}",
328
- "cli.package.uninstall_success": " Пакет {package} успешно удалён",
329
- "cli.package.uninstall_failed": " Ошибка удаления пакета {package}",
329
+ "cli.package.uninstall_success": "[OK] Пакет {package} успешно удалён",
330
+ "cli.package.uninstall_failed": "[FAIL] Ошибка удаления пакета {package}",
330
331
  "cli.package.all_up_to_date": "Все пакеты ErisPulse обновлены до последней версии",
331
332
  "cli.package.updates_found": "Найдено пакетов для обновления: {count}",
332
333
  "cli.package.upgrade_list_title": "Список обновлений",
@@ -343,8 +344,8 @@ TRANSLATIONS = {
343
344
  "cli.package.confirm_upgrade": "Продолжить обновление?",
344
345
  "cli.package.upgrade_cancelled": "Обновление отменено",
345
346
  "cli.package.upgrading": "Обновление {package}",
346
- "cli.package.upgrade_success": " Пакет {package} успешно обновлён",
347
- "cli.package.upgrade_failed": " Ошибка обновления пакета {package}",
347
+ "cli.package.upgrade_success": "[OK] Пакет {package} успешно обновлён",
348
+ "cli.package.upgrade_failed": "[FAIL] Ошибка обновления пакета {package}",
348
349
  "cli.package.pypi_versions_failed": "Не удалось получить информацию о версиях PyPI",
349
350
  "cli.package.already_target_version": "Уже установлена целевая версия {version}",
350
351
  "cli.package.invalid_version": "Недопустимый номер версии: {version}",
@@ -353,7 +354,7 @@ TRANSLATIONS = {
353
354
  "cli.package.update_desc_with_version": "Обновление ErisPulse SDK до {version}",
354
355
  "cli.package.update_desc_latest": "Обновление ErisPulse SDK до последней версии",
355
356
  "cli.package.latest_version": "последняя версия",
356
- "cli.package.sdk_update_success": " ErisPulse SDK успешно обновлён: {old} → {new}",
357
+ "cli.package.sdk_update_success": "[OK] ErisPulse SDK успешно обновлён: {old} → {new}",
357
358
  "cli.package.restart_cli": "Пожалуйста, перезапустите CLI, чтобы использовать новую версию",
358
- "cli.package.sdk_update_failed": " Ошибка обновления ErisPulse SDK",
359
+ "cli.package.sdk_update_failed": "[FAIL] Ошибка обновления ErisPulse SDK",
359
360
  }
@@ -249,6 +249,7 @@ TRANSLATIONS = {
249
249
  "cli.run.file_changed_restart": "检测到文件变更 ([cmd]{file}[/]),正在重启...",
250
250
  "cli.run.process_exited": "进程已正常退出,等待文件变更后重启",
251
251
  "cli.run.process_crashed": "进程异常退出(退出码 {code}),修复后保存文件将自动重启",
252
+ "cli.run.subprocess_crashed_retry": "子进程异常终止,将在 {seconds} 秒后自动重试...",
252
253
  # ==================== uninstall 命令 ====================
253
254
  "cli.uninstall.description": "卸载模块/适配器包",
254
255
  "cli.uninstall.package_help": "要卸载的包名(可指定多个)",
@@ -315,18 +316,18 @@ TRANSLATIONS = {
315
316
  "cli.package.compat_warning_upgrade": "SDK版本兼容性警告\n包 {package} 需要最低SDK版本 {version}\n{message}\n\n继续升级可能会导致问题。",
316
317
  "cli.package.compat_warning_title": "兼容性警告",
317
318
  "cli.package.installing": "安装 {package}",
318
- "cli.package.install_success": " 包 {package} 安装成功",
319
- "cli.package.install_failed": " 包 {package} 安装失败",
320
- "cli.package.operation_success": " {description} 成功",
321
- "cli.package.operation_failed": " {description} 失败",
319
+ "cli.package.install_success": "[OK] 包 {package} 安装成功",
320
+ "cli.package.install_failed": "[FAIL] 包 {package} 安装失败",
321
+ "cli.package.operation_success": "[OK] {description} 成功",
322
+ "cli.package.operation_failed": "[FAIL] {description} 失败",
322
323
  "cli.package.alias_mapping": " 别名映射: {alias} → {package}",
323
324
  "cli.package.installed_package_found": " 找到已安装包: {package}",
324
325
  "cli.package.uninstall_alias_not_found": " 未找到别名,将尝试直接卸载: {package}",
325
326
  "cli.package.confirm_uninstall": "确认卸载以下包吗?\n{packages}",
326
327
  "cli.package.operation_cancelled": " 操作已取消",
327
328
  "cli.package.uninstalling": "卸载 {package}",
328
- "cli.package.uninstall_success": " 包 {package} 卸载成功",
329
- "cli.package.uninstall_failed": " 包 {package} 卸载失败",
329
+ "cli.package.uninstall_success": "[OK] 包 {package} 卸载成功",
330
+ "cli.package.uninstall_failed": "[FAIL] 包 {package} 卸载失败",
330
331
  "cli.package.all_up_to_date": "所有ErisPulse包已是最新版本",
331
332
  "cli.package.updates_found": "找到 {count} 个可升级的包:",
332
333
  "cli.package.upgrade_list_title": "升级列表",
@@ -343,8 +344,8 @@ TRANSLATIONS = {
343
344
  "cli.package.confirm_upgrade": "是否继续升级?",
344
345
  "cli.package.upgrade_cancelled": "已取消升级",
345
346
  "cli.package.upgrading": "升级 {package}",
346
- "cli.package.upgrade_success": " 包 {package} 升级成功",
347
- "cli.package.upgrade_failed": " 包 {package} 升级失败",
347
+ "cli.package.upgrade_success": "[OK] 包 {package} 升级成功",
348
+ "cli.package.upgrade_failed": "[FAIL] 包 {package} 升级失败",
348
349
  "cli.package.pypi_versions_failed": "获取PyPI版本信息失败",
349
350
  "cli.package.already_target_version": "当前已是目标版本 {version}",
350
351
  "cli.package.invalid_version": "无效的版本号: {version}",
@@ -353,7 +354,7 @@ TRANSLATIONS = {
353
354
  "cli.package.update_desc_with_version": "更新 ErisPulse SDK 到 {version}",
354
355
  "cli.package.update_desc_latest": "更新 ErisPulse SDK 到最新版本",
355
356
  "cli.package.latest_version": "最新版本",
356
- "cli.package.sdk_update_success": " ErisPulse SDK 更新成功: {old} → {new}",
357
+ "cli.package.sdk_update_success": "[OK] ErisPulse SDK 更新成功: {old} → {new}",
357
358
  "cli.package.restart_cli": "请重新启动CLI以使用新版本",
358
- "cli.package.sdk_update_failed": " ErisPulse SDK 更新失败",
359
+ "cli.package.sdk_update_failed": "[FAIL] ErisPulse SDK 更新失败",
359
360
  }
@@ -249,6 +249,7 @@ TRANSLATIONS = {
249
249
  "cli.run.file_changed_restart": "檢測到檔案變更 ([cmd]{file}[/]),正在重啟...",
250
250
  "cli.run.process_exited": "程式已正常退出,等待檔案變更後重啟",
251
251
  "cli.run.process_crashed": "程式異常退出(退出碼 {code}),修復後儲存檔案將自動重啟",
252
+ "cli.run.subprocess_crashed_retry": "子程序異常終止,將在 {seconds} 秒後自動重試...",
252
253
  # ==================== uninstall 命令 ====================
253
254
  "cli.uninstall.description": "解除安裝模組/適配器包",
254
255
  "cli.uninstall.package_help": "要解除安裝的包名(可指定多個)",
@@ -315,18 +316,18 @@ TRANSLATIONS = {
315
316
  "cli.package.compat_warning_upgrade": "SDK版本相容性警告\n包 {package} 需要最低SDK版本 {version}\n{message}\n\n繼續升級可能會導致問題。",
316
317
  "cli.package.compat_warning_title": "相容性警告",
317
318
  "cli.package.installing": "安裝 {package}",
318
- "cli.package.install_success": " 包 {package} 安裝成功",
319
- "cli.package.install_failed": " 包 {package} 安裝失敗",
320
- "cli.package.operation_success": " {description} 成功",
321
- "cli.package.operation_failed": " {description} 失敗",
319
+ "cli.package.install_success": "[OK] 包 {package} 安裝成功",
320
+ "cli.package.install_failed": "[FAIL] 包 {package} 安裝失敗",
321
+ "cli.package.operation_success": "[OK] {description} 成功",
322
+ "cli.package.operation_failed": "[FAIL] {description} 失敗",
322
323
  "cli.package.alias_mapping": " 別名對映: {alias} → {package}",
323
324
  "cli.package.installed_package_found": " 找到已安裝包: {package}",
324
325
  "cli.package.uninstall_alias_not_found": " 未找到別名,將嘗試直接解除安裝: {package}",
325
326
  "cli.package.confirm_uninstall": "確認解除安裝以下包嗎?\n{packages}",
326
327
  "cli.package.operation_cancelled": " 操作已取消",
327
328
  "cli.package.uninstalling": "解除安裝 {package}",
328
- "cli.package.uninstall_success": " 包 {package} 解除安裝成功",
329
- "cli.package.uninstall_failed": " 包 {package} 解除安裝失敗",
329
+ "cli.package.uninstall_success": "[OK] 包 {package} 解除安裝成功",
330
+ "cli.package.uninstall_failed": "[FAIL] 包 {package} 解除安裝失敗",
330
331
  "cli.package.all_up_to_date": "所有ErisPulse包已是最新版本",
331
332
  "cli.package.updates_found": "找到 {count} 個可升級的包:",
332
333
  "cli.package.upgrade_list_title": "升級列表",
@@ -343,8 +344,8 @@ TRANSLATIONS = {
343
344
  "cli.package.confirm_upgrade": "是否繼續升級?",
344
345
  "cli.package.upgrade_cancelled": "已取消升級",
345
346
  "cli.package.upgrading": "升級 {package}",
346
- "cli.package.upgrade_success": " 包 {package} 升級成功",
347
- "cli.package.upgrade_failed": " 包 {package} 升級失敗",
347
+ "cli.package.upgrade_success": "[OK] 包 {package} 升級成功",
348
+ "cli.package.upgrade_failed": "[FAIL] 包 {package} 升級失敗",
348
349
  "cli.package.pypi_versions_failed": "取得PyPI版本資訊失敗",
349
350
  "cli.package.already_target_version": "當前已是目標版本 {version}",
350
351
  "cli.package.invalid_version": "無效的版本號: {version}",
@@ -353,7 +354,7 @@ TRANSLATIONS = {
353
354
  "cli.package.update_desc_with_version": "更新 ErisPulse SDK 到 {version}",
354
355
  "cli.package.update_desc_latest": "更新 ErisPulse SDK 到最新版本",
355
356
  "cli.package.latest_version": "最新版本",
356
- "cli.package.sdk_update_success": " ErisPulse SDK 更新成功: {old} → {new}",
357
+ "cli.package.sdk_update_success": "[OK] ErisPulse SDK 更新成功: {old} → {new}",
357
358
  "cli.package.restart_cli": "請重新啟動CLI以使用新版本",
358
- "cli.package.sdk_update_failed": " ErisPulse SDK 更新失敗",
359
+ "cli.package.sdk_update_failed": "[FAIL] ErisPulse SDK 更新失敗",
359
360
  }
@@ -381,6 +381,8 @@ class PackageManager:
381
381
  :param name: [str] 原始名称
382
382
  :return: [str] 标准化后的名称
383
383
  """
384
+ if not name:
385
+ return ""
384
386
  return name.lower().strip()
385
387
 
386
388
  async def _find_package_by_alias(self, alias: str) -> Optional[str]:
@@ -494,7 +496,7 @@ class PackageManager:
494
496
  :param force_refresh: [bool] 是否强制刷新缓存 (默认: False)
495
497
  :return: [Optional[str]] 最新版本号,失败时返回 None
496
498
  """
497
- cache_key = package_name.lower()
499
+ cache_key = (package_name or "").lower()
498
500
  if not force_refresh and cache_key in self._pypi_cache:
499
501
  if time.time() - self._pypi_cache_time[cache_key] < self.CACHE_EXPIRY:
500
502
  return self._pypi_cache[cache_key]
@@ -621,7 +623,7 @@ class PackageManager:
621
623
  proxy_hint = f" [dim](proxy: {safe_proxy})[/]"
622
624
 
623
625
  console.print(
624
- f"\n[bold blue] {description}[/] [dim]({backend})[/]{proxy_hint}"
626
+ f"\n[bold blue][*] {description}[/] [dim]({backend})[/]{proxy_hint}"
625
627
  )
626
628
  console.print("[dim]─────────────────────────────────────────────────[/]")
627
629
 
@@ -673,59 +675,18 @@ class PackageManager:
673
675
  并将目标 Python 解析为当前虚拟环境的解释器,
674
676
  避免安装到全局环境。
675
677
 
676
- 操作成功后自动保存包快照到持久化目录,
677
- 供 Docker 容器重建后恢复使用。
678
-
679
678
  :param args: [List[str]] pip 子命令与参数,如 ["install", "--upgrade", pkg]
680
679
  :param description: [str] 展示给用户的操作描述
681
680
  :return: [bool] 执行成功返回 True
682
681
  """
683
682
  uv_cmd = self._get_uv_command()
684
- success = False
685
683
  if uv_cmd:
686
684
  if self._execute_backend(uv_cmd + ["pip"], args, description, "uv"):
687
- success = True
688
- else:
689
- console.print(f"[warning]{i18n.t('cli.package.uv_fallback_to_pip')}[/]")
690
-
691
- if not success:
692
- pip_cmd = [self._get_target_python(), "-m", "pip"]
693
- success = self._execute_backend(pip_cmd, args, description, "pip")
694
-
695
- # 操作成功后保存包快照(非关键,失败不影响主流程)
696
- if success:
697
- self._save_package_snapshot()
698
-
699
- return success
700
-
701
- def _save_package_snapshot(self) -> None:
702
- """
703
- {!--< internal-use >!--}
704
- 将当前已安装的包列表保存到持久化目录。
705
-
706
- 快照文件用于 Docker 容器重建后的包恢复:
707
- entrypoint 创建新 venv 时会读取 .pip-snapshot.txt
708
- 并尝试重新安装这些包。
685
+ return True
686
+ console.print(f"[warning]{i18n.t('cli.package.uv_fallback_to_pip')}[/]")
709
687
 
710
- 仅在 config/ 目录存在时保存(即项目环境或 Docker 环境)。
711
- """
712
- try:
713
- config_dir = os.path.join(os.getcwd(), "config")
714
- if not os.path.isdir(config_dir):
715
- return
716
-
717
- result = subprocess.run(
718
- [sys.executable, "-m", "pip", "freeze"],
719
- capture_output=True,
720
- text=True,
721
- timeout=30,
722
- )
723
- if result.returncode == 0:
724
- snapshot_path = os.path.join(config_dir, ".pip-snapshot.txt")
725
- with open(snapshot_path, "w", encoding="utf-8") as f:
726
- f.write(result.stdout)
727
- except Exception:
728
- pass
688
+ pip_cmd = [self._get_target_python(), "-m", "pip"]
689
+ return self._execute_backend(pip_cmd, args, description, "pip")
729
690
 
730
691
  def _version_key(self, version: str) -> tuple:
731
692
  """
@@ -243,9 +243,6 @@ class PackageManager:
243
243
  并将目标 Python 解析为当前虚拟环境的解释器,
244
244
  避免安装到全局环境。
245
245
 
246
- 操作成功后自动保存包快照到持久化目录,
247
- 供 Docker 容器重建后恢复使用。
248
-
249
246
  :param args: [List[str]] pip 子命令与参数,如 ["install", "--upgrade", pkg]
250
247
  :param description: [str] 展示给用户的操作描述
251
248
  :return: [bool] 执行成功返回 True
@@ -12,48 +12,55 @@ ErisPulse 事件处理模块
12
12
 
13
13
  from .command import command
14
14
  from .message import message
15
+ from .message_builder import MessageBuilder
16
+ from .meta import meta
15
17
  from .notice import notice
16
18
  from .request import request
17
- from .meta import meta
18
- from .wrapper import (
19
- Event,
20
- Conversation,
21
- CONFIRM_YES_WORDS,
22
- CONFIRM_NO_WORDS,
23
- register_event_mixin,
24
- register_event_method,
25
- unregister_event_method,
26
- unregister_platform_event_methods,
27
- get_platform_event_methods,
28
- _builtin_wait_reply,
29
- _builtin_confirm,
30
- _builtin_choose,
31
- _builtin_collect,
32
- )
33
- from .message_builder import MessageBuilder
34
19
  from .session_type import (
35
20
  # 标准类型常量
36
21
  RECEIVE_TYPES,
37
22
  SEND_TYPES,
38
23
  # 自定义类型注册
39
- register_custom_type,
40
- unregister_custom_type,
24
+ clear_custom_types,
25
+ convert_to_receive_type,
26
+ convert_to_send_type,
41
27
  # 类型获取方法
42
28
  get_id_field,
43
29
  get_receive_type,
44
- convert_to_send_type,
45
- convert_to_receive_type,
30
+ get_send_type_and_target_id,
31
+ get_send_types,
32
+ get_standard_types,
33
+ get_target_id,
46
34
  # 自动推断方法
47
35
  infer_receive_type,
48
- get_target_id,
49
- get_send_type_and_target_id,
50
36
  # 工具方法
51
37
  is_standard_type,
52
38
  is_valid_send_type,
53
- get_standard_types,
54
- get_send_types,
55
- clear_custom_types,
39
+ # 自定义类型注册
40
+ register_custom_type,
41
+ unregister_custom_type,
56
42
  )
43
+ from .wrapper import (
44
+ CONFIRM_NO_WORDS,
45
+ CONFIRM_YES_WORDS,
46
+ Conversation,
47
+ Event,
48
+ _builtin_choose,
49
+ _builtin_collect,
50
+ _builtin_confirm,
51
+ _builtin_wait_reply,
52
+ get_platform_event_methods,
53
+ register_event_method,
54
+ register_event_mixin,
55
+ unregister_event_method,
56
+ unregister_platform_event_methods,
57
+ )
58
+
59
+ # 将 command 的命令分发器绑定到 message 的共享 BaseEventHandler,
60
+ # 使命令处理和消息处理共享同一个优先级队列。
61
+ # 命令分发器 _handle_message 以 DEFAULT_COMMAND_DISPATCHER_PRIORITY (100) 注册,
62
+ # 确保命令 /xxx 始终优先于 on_message / on_group_message 等处理器触发。
63
+ command.bind_message_handler(message.handler)
57
64
 
58
65
 
59
66
  def _clear_all_handlers():
@@ -18,9 +18,9 @@ ErisPulse 事件处理模块
18
18
 
19
19
  from .command import command
20
20
  from .message import message
21
+ from .message_builder import MessageBuilder
22
+ from .meta import meta
21
23
  from .notice import notice
22
24
  from .request import request
23
- from .meta import meta
24
- from .wrapper import Event, Conversation, CONFIRM_YES_WORDS, CONFIRM_NO_WORDS, register_event_mixin, register_event_method, unregister_event_method, unregister_platform_event_methods, get_platform_event_methods, _builtin_wait_reply, _builtin_confirm, _builtin_choose, _builtin_collect
25
- from .message_builder import MessageBuilder
26
- from .session_type import RECEIVE_TYPES, SEND_TYPES, register_custom_type, unregister_custom_type, get_id_field, get_receive_type, convert_to_send_type, convert_to_receive_type, infer_receive_type, get_target_id, get_send_type_and_target_id, is_standard_type, is_valid_send_type, get_standard_types, get_send_types, clear_custom_types
25
+ from .session_type import RECEIVE_TYPES, SEND_TYPES, clear_custom_types, convert_to_receive_type, convert_to_send_type, get_id_field, get_receive_type, get_send_type_and_target_id, get_send_types, get_standard_types, get_target_id, infer_receive_type, is_standard_type, is_valid_send_type, register_custom_type, unregister_custom_type
26
+ from .wrapper import CONFIRM_NO_WORDS, CONFIRM_YES_WORDS, Conversation, Event, _builtin_choose, _builtin_collect, _builtin_confirm, _builtin_wait_reply, get_platform_event_methods, register_event_method, register_event_mixin, unregister_event_method, unregister_platform_event_methods