nonebot-plugin-lingchu-bot 0.8.0.dev1__tar.gz → 0.9.0.dev1__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 (136) hide show
  1. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/PKG-INFO +1 -1
  2. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/pyproject.toml +2 -2
  3. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/pyproject.toml.orig +2 -2
  4. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/_lingchu_bot_contracts/runtime_settings.py +1 -0
  5. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/__init__.py +16 -0
  6. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/config.py +1 -1
  7. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/handle_config_defaults/__init__.py +1 -0
  8. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/handle_default_values.py +1 -0
  9. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/menu.py +12 -0
  10. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/mute.py +42 -14
  11. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/remote.py +110 -0
  12. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/remote.py +14 -0
  13. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/triggers.py +6 -0
  14. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/locales/en_US/LC_MESSAGES/messages.mo +0 -0
  15. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/locales/en_US/LC_MESSAGES/messages.po +117 -97
  16. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/locales/zh_CN/LC_MESSAGES/messages.mo +0 -0
  17. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/locales/zh_CN/LC_MESSAGES/messages.po +111 -94
  18. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/messages.pot +111 -94
  19. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/CLA.md +0 -0
  20. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-apache +0 -0
  21. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-cc-by-sa +0 -0
  22. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-cc0 +0 -0
  23. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-code +0 -0
  24. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-docs +0 -0
  25. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/LICENSE-mit +0 -0
  26. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/README.md +0 -0
  27. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/Repository-Policy.md +0 -0
  28. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/_lingchu_bot_contracts/__init__.py +0 -0
  29. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/async_utils.py +0 -0
  30. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/bot_state.py +0 -0
  31. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/handle_config_manager.py +0 -0
  32. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/http_security.py +0 -0
  33. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/menu_config.py +0 -0
  34. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/mutable_settings.py +0 -0
  35. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/core/runtime_config.py +0 -0
  36. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/_dialect_compat.py +0 -0
  37. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/__init__.py +0 -0
  38. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/blocklist.py +0 -0
  39. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/identity.py +0 -0
  40. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/message.py +0 -0
  41. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/registry.py +0 -0
  42. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/scheduler.py +0 -0
  43. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/models/subject_policy.py +0 -0
  44. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/orm_crud/__init__.py +0 -0
  45. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/orm_crud/_base.py +0 -0
  46. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/orm_crud/_bulk.py +0 -0
  47. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/orm_crud/_single.py +0 -0
  48. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/__init__.py +0 -0
  49. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/atomic.py +0 -0
  50. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/checksum.py +0 -0
  51. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/journal.py +0 -0
  52. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/recovery.py +0 -0
  53. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/persistence/versioning.py +0 -0
  54. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/schema_guard.py +0 -0
  55. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/sqlite_pragmas.py +0 -0
  56. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/toml_store/__init__.py +0 -0
  57. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/toml_store/_helpers.py +0 -0
  58. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/toml_store/_sync.py +0 -0
  59. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/database/toml_store/exceptions.py +0 -0
  60. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/__init__.py +0 -0
  61. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/__init__.py +0 -0
  62. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/__init__.py +0 -0
  63. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/__init__.py +0 -0
  64. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/announcement.py +0 -0
  65. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/block.py +0 -0
  66. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/bot_state.py +0 -0
  67. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/common.py +0 -0
  68. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/handle_defaults.py +0 -0
  69. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/kick.py +0 -0
  70. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/lifecycle.py +0 -0
  71. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/member.py +0 -0
  72. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/menu.py +0 -0
  73. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/profile.py +0 -0
  74. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/protect.py +0 -0
  75. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/default/protect_notice.py +0 -0
  76. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/llbot/__init__.py +0 -0
  77. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/llbot/mute_list.py +0 -0
  78. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/napcat/__init__.py +0 -0
  79. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/napcat/announcement.py +0 -0
  80. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/adapters/onebot11/napcat/profile.py +0 -0
  81. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/__init__.py +0 -0
  82. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/announcement.py +0 -0
  83. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/block.py +0 -0
  84. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/bot_state.py +0 -0
  85. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/common.py +0 -0
  86. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/handle_defaults.py +0 -0
  87. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/kick.py +0 -0
  88. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/lifecycle.py +0 -0
  89. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/member.py +0 -0
  90. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/mute.py +0 -0
  91. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/profile.py +0 -0
  92. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/handle/qq/commands/protect.py +0 -0
  93. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/__init__.py +0 -0
  94. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/adapters.py +0 -0
  95. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/handlers/__init__.py +0 -0
  96. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/handlers/api_audit.py +0 -0
  97. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/handlers/bot_connection.py +0 -0
  98. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/handlers/lifecycle.py +0 -0
  99. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/handlers/message_store.py +0 -0
  100. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/hooks/interfaces.py +0 -0
  101. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/__init__.py +0 -0
  102. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/i18n/babel.cfg +0 -0
  103. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/1a2b3c4d5e6f_permissions_schema.py +0 -0
  104. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/2b3c4d5e6f7a_event_policy_partitions.py +0 -0
  105. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/30f5a01259cd_initial_schema.py +0 -0
  106. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/c3d4e5f6a7b8_scheduler_jobs.py +0 -0
  107. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/cf2c06d51a17_blocklist_unique_constraint.py +0 -0
  108. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/d7e8f9a0b1c2_identity_integrity.py +0 -0
  109. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/f6a7b8c9d0e1_message_protocol_default.py +0 -0
  110. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/migrations/g7b8c9d0e1f2_protocol_id_not_null.py +0 -0
  111. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/__init__.py +0 -0
  112. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/admin.py +0 -0
  113. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/bootstrap.py +0 -0
  114. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/config.py +0 -0
  115. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/platforms.py +0 -0
  116. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/service.py +0 -0
  117. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/subject_policy.py +0 -0
  118. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/permissions/types.py +0 -0
  119. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/platforms/__init__.py +0 -0
  120. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/platforms/qq/__init__.py +0 -0
  121. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/platforms/qq/permissions.py +0 -0
  122. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/platforms/registry.py +0 -0
  123. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/__init__.py +0 -0
  124. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/blocklist.py +0 -0
  125. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/message_store.py +0 -0
  126. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/permissions.py +0 -0
  127. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/registry.py +0 -0
  128. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/repositories/scheduler_jobs.py +0 -0
  129. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/restart_worker.py +0 -0
  130. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/message_store.py +0 -0
  131. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/protocol_restart_feedback.py +0 -0
  132. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/restart_app.py +0 -0
  133. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/scheduler.py +0 -0
  134. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/webui/__init__.py +0 -0
  135. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/services/webui/info.py +0 -0
  136. {nonebot_plugin_lingchu_bot-0.8.0.dev1 → nonebot_plugin_lingchu_bot-0.9.0.dev1}/src/plugins/nonebot_plugin_lingchu_bot/start/startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-lingchu-bot
3
- Version: 0.8.0.dev1
3
+ Version: 0.9.0.dev1
4
4
  Summary: 由NoneBot2驱动,面向多平台的管理机器人
5
5
  Keywords: nonebot2,nonebot,bot,cross-platform,group-management
6
6
  Author: xinvxueyuan
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-lingchu-bot"
3
- version = "0.8.0.dev1"
3
+ version = "0.9.0.dev1"
4
4
  description = "由NoneBot2驱动,面向多平台的管理机器人"
5
5
  keywords = [
6
6
  "nonebot2",
@@ -578,5 +578,5 @@ include-group = "lint"
578
578
  include-group = "git"
579
579
 
580
580
  [build-system]
581
- requires = ["uv_build>=0.11.8,<0.13"]
581
+ requires = ["uv_build>=0.11.8,<0.14"]
582
582
  build-backend = "uv_build"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-lingchu-bot"
3
- version = "0.8.0.dev1"
3
+ version = "0.9.0.dev1"
4
4
  # dynamic = ["version"]
5
5
  description = "由NoneBot2驱动,面向多平台的管理机器人"
6
6
  keywords = ["nonebot2", "nonebot", "bot", "cross-platform", "group-management"]
@@ -591,7 +591,7 @@ exclude_lines = [
591
591
 
592
592
  # TODO: add build system configuration
593
593
  [build-system]
594
- requires = ["uv_build>=0.11.8,<0.13"]
594
+ requires = ["uv_build>=0.11.8,<0.14"]
595
595
  build-backend = "uv_build"
596
596
 
597
597
 
@@ -76,6 +76,7 @@ class DeploymentSettings:
76
76
  "global_block_member",
77
77
  "member_mute",
78
78
  "recall_message",
79
+ "remote_recall",
79
80
  "set_member_card",
80
81
  "set_member_title",
81
82
  "set_member_admin",
@@ -20,6 +20,8 @@ __plugin_meta__ = PluginMetadata(
20
20
  "常用命令:\n"
21
21
  "- 禁言 @用户 [时长] [原因] / mute @user [duration] [reason]\n"
22
22
  "- 撤回 [@用户] [数量] / recall [@user] [count]\n"
23
+ "- 远程撤回 <群号或群名称> [@用户] [数量] / "
24
+ "remote-recall <group> [@user] [count]\n"
23
25
  "- 远程禁言 <群号或群名称> @用户 [时长] / "
24
26
  "remote-mute <group> @user [duration]\n"
25
27
  "- 闭嘴 / 说话 (silence / speak)\n"
@@ -45,6 +47,20 @@ __plugin_meta__ = PluginMetadata(
45
47
  }
46
48
  for profile in iter_platform_profiles()
47
49
  ),
50
+ # ── 信息插件(命令「功能」)读的帮助元数据 ──
51
+ "menu_type": "管理",
52
+ "order": 5,
53
+ "commands": [
54
+ {"command": "菜单", "desc": "功能菜单"},
55
+ {"command": "禁言 / 解禁", "desc": "群内禁言与解除(含全员/一键解禁)"},
56
+ {"command": "撤回", "desc": "撤回消息(支持批量)"},
57
+ {"command": "远程撤回", "desc": "跨群撤回 <群号或群名> [@用户] [数量]"},
58
+ {"command": "踢出 / 拉黑 / 拉白", "desc": "成员管理(含全局/远程变体)"},
59
+ {"command": "设置群名称 / 发送群公告", "desc": "群资料与公告"},
60
+ {"command": "远程禁言", "desc": "跨群禁言 <群号或群名> @用户"},
61
+ {"command": "闭嘴 / 说话", "desc": "机器人全局静默 / 恢复"},
62
+ {"command": "开机 / 关机", "desc": "启用 / 停用机器人"},
63
+ ],
48
64
  },
49
65
  )
50
66
 
@@ -123,7 +123,7 @@ class Config(DeploymentSettings):
123
123
 
124
124
  """
125
125
 
126
- core_version: str = "0.8.0.dev1"
126
+ core_version: str = "0.9.0.dev1"
127
127
  data_dir: Path = field(default_factory=get_plugin_data_dir)
128
128
  config_dir: Path = field(default_factory=get_plugin_config_dir)
129
129
  cache_dir: Path = field(default_factory=get_plugin_cache_dir)
@@ -45,6 +45,7 @@ HANDLE_DEFAULTS_REGISTRY: dict[str, HandleDefaultsFactory] = {
45
45
  "block_duration": None,
46
46
  "default_reason": "违反群规",
47
47
  }),
48
+ "remote_recall": lambda: _config({"default_count": 10}),
48
49
  "remote_announcement": _config,
49
50
  "mass_announcement": _config,
50
51
  "restart_protocol_endpoint": lambda: _config({"default_platform": "当前平台"}),
@@ -93,6 +93,7 @@ HANDLE_DEFAULT_DEFINITIONS: Final[tuple[HandleDefaultDefinition, ...]] = (
93
93
  HandleDefaultDefinition("block_member", "default_reason", _parse_text),
94
94
  HandleDefaultDefinition("remote_block", "block_duration", _parse_optional_duration),
95
95
  HandleDefaultDefinition("remote_block", "default_reason", _parse_text),
96
+ HandleDefaultDefinition("remote_recall", "default_count", _parse_positive_count),
96
97
  HandleDefaultDefinition("recall_message", "default_count", _parse_positive_count),
97
98
  HandleDefaultDefinition("protect_member", "whitelist_scope", _parse_scope),
98
99
  HandleDefaultDefinition("protect_member", "default_reason", _parse_text),
@@ -526,6 +526,18 @@ _BASE_MENU_FEATURES: Final[tuple[MenuFeature, ...]] = (
526
526
  PlatformCapability.ANNOUNCEMENT,
527
527
  (*_ONEBOT_ANNOUNCEMENT,),
528
528
  ),
529
+ MenuFeature(
530
+ "remote-recall",
531
+ "remote_recall",
532
+ "remote-management",
533
+ LocalizedText("远程撤回", "Remote recall"),
534
+ LocalizedText(
535
+ "<群号|群名称> [@用户] [数量]",
536
+ "<group_id|group_name> [@user] [count]",
537
+ ),
538
+ PlatformCapability.MEMBER_MODERATION,
539
+ (MenuAvailability(QQ_PLATFORM_ID, ONEBOT_V11_ADAPTER_ID),),
540
+ ),
529
541
  MenuFeature(
530
542
  "bot-silence",
531
543
  "bot_silence",
@@ -456,8 +456,12 @@ async def _is_recall_protected_target(
456
456
  bot: OneBot11Bot,
457
457
  event: OneBot11GroupMessageEvent,
458
458
  target_user_id: int,
459
+ *,
460
+ group_id: int | None = None,
459
461
  ) -> bool:
460
- if "recall_message" not in plugin_config.protected_subject_feature_keys:
462
+ effective_group_id = event.group_id if group_id is None else group_id
463
+ feature_keys = set(plugin_config.protected_subject_feature_keys)
464
+ if not ({"recall_message", "remote_recall"} & feature_keys):
461
465
  return False
462
466
  protected = await find_active_subject_policy(
463
467
  session,
@@ -465,7 +469,7 @@ async def _is_recall_protected_target(
465
469
  platform_id="qq",
466
470
  adapter_id="~onebot.v11",
467
471
  bot_id=bot_id(bot),
468
- group_id=event.group_id,
472
+ group_id=effective_group_id,
469
473
  user_id=target_user_id,
470
474
  )
471
475
  return protected is not None
@@ -478,12 +482,14 @@ async def _can_recall_sender(
478
482
  sender_id: int,
479
483
  *,
480
484
  sender_decisions: dict[int, bool] | None = None,
485
+ group_id: int | None = None,
481
486
  ) -> bool:
482
487
  """Return True when messages from sender_id may be recalled.
483
488
 
484
489
  Fail closed: when the sender's role cannot be verified (API failure),
485
490
  skip the recall instead of potentially recalling an admin/owner message.
486
491
  """
492
+ effective_group_id = event.group_id if group_id is None else group_id
487
493
  if sender_id == event.user_id:
488
494
  return False
489
495
  bot_self = bot_self_id_safe(bot)
@@ -491,7 +497,9 @@ async def _can_recall_sender(
491
497
  return False
492
498
  if sender_decisions is not None and sender_id in sender_decisions:
493
499
  return sender_decisions[sender_id]
494
- decision = await _evaluate_recall_sender(session, bot, event, sender_id)
500
+ decision = await _evaluate_recall_sender(
501
+ session, bot, event, sender_id, group_id=effective_group_id
502
+ )
495
503
  if sender_decisions is not None:
496
504
  sender_decisions[sender_id] = decision
497
505
  return decision
@@ -502,24 +510,29 @@ async def _evaluate_recall_sender(
502
510
  bot: OneBot11Bot,
503
511
  event: OneBot11GroupMessageEvent,
504
512
  sender_id: int,
513
+ *,
514
+ group_id: int | None = None,
505
515
  ) -> bool:
506
- if await _is_recall_protected_target(session, bot, event, sender_id):
516
+ effective_group_id = event.group_id if group_id is None else group_id
517
+ if await _is_recall_protected_target(
518
+ session, bot, event, sender_id, group_id=effective_group_id
519
+ ):
507
520
  return False
508
521
  try:
509
522
  member_info = await bot.get_group_member_info(
510
- group_id=event.group_id,
523
+ group_id=effective_group_id,
511
524
  user_id=sender_id,
512
525
  no_cache=True,
513
526
  )
514
527
  except OneBot11ActionFailed:
515
528
  logger.warning(
516
- f"无法确认发送者角色,跳过撤回: group_id={event.group_id}, "
529
+ f"无法确认发送者角色,跳过撤回: group_id={effective_group_id}, "
517
530
  f"sender_id={sender_id}"
518
531
  )
519
532
  return False
520
533
  except OneBot11NetworkError as e:
521
534
  logger.warning(
522
- f"查询发送者角色网络异常,跳过撤回: group_id={event.group_id}, "
535
+ f"查询发送者角色网络异常,跳过撤回: group_id={effective_group_id}, "
523
536
  f"sender_id={sender_id}, error={e!r}"
524
537
  )
525
538
  return False
@@ -585,7 +598,9 @@ async def _list_recall_candidate_records(
585
598
  *,
586
599
  target_user_id: int | None,
587
600
  recall_count: int,
601
+ group_id: int | None = None,
588
602
  ) -> list[Any]:
603
+ effective_group_id = event.group_id if group_id is None else group_id
589
604
  fetch_limit = _candidate_fetch_limit(recall_count)
590
605
  common_filters: dict[str, Any] = {
591
606
  "platform_id": "qq",
@@ -601,13 +616,13 @@ async def _list_recall_candidate_records(
601
616
  group_records = await message_repository.list_recent_messages(
602
617
  session,
603
618
  **common_filters,
604
- conversation_id=str(event.group_id),
619
+ conversation_id=str(effective_group_id),
605
620
  limit=fetch_limit,
606
621
  )
607
622
  return await _merge_recall_candidates(
608
623
  broad_records,
609
624
  group_records,
610
- group_id=event.group_id,
625
+ group_id=effective_group_id,
611
626
  )
612
627
 
613
628
 
@@ -616,10 +631,13 @@ async def _resolve_recall_args(
616
631
  count: int | None,
617
632
  bot: OneBot11Bot,
618
633
  event: OneBot11GroupMessageEvent,
634
+ *,
635
+ default_count: int | None = None,
619
636
  ) -> tuple[int | None, str | None, int]:
620
- # 读取配置中的默认撤回数量
621
- config = await get_handle_config_manager().get_config("recall_message")
622
- default_count = config.defaults.get("default_count", 10)
637
+ # 未显式指定时,读取配置中的默认撤回数量
638
+ if default_count is None:
639
+ config = await get_handle_config_manager().get_config("recall_message")
640
+ default_count = int(config.defaults.get("default_count", 10))
623
641
 
624
642
  if isinstance(target, At):
625
643
  target_user_id, target_name = await resolve_user_onebot11(target, bot, event)
@@ -652,14 +670,16 @@ async def _recall_record_message(
652
670
  trigger_message_id: str,
653
671
  target_user_id: int | None,
654
672
  sender_decisions: dict[int, bool],
673
+ group_id: int | None = None,
655
674
  ) -> str:
675
+ effective_group_id = event.group_id if group_id is None else group_id
656
676
  message_id = _message_id_int(getattr(record, "message_id", None))
657
677
  if message_id is None or str(message_id) == trigger_message_id:
658
678
  return "skipped"
659
679
  message = await _verified_recall_message(
660
680
  bot,
661
681
  message_id=message_id,
662
- group_id=event.group_id,
682
+ group_id=effective_group_id,
663
683
  target_user_id=target_user_id,
664
684
  )
665
685
  if message is None:
@@ -668,7 +688,12 @@ async def _recall_record_message(
668
688
  if sender_id is None:
669
689
  sender_id = _message_id_int(getattr(record, "user_id", None))
670
690
  if sender_id is None or not await _can_recall_sender(
671
- session, bot, event, sender_id, sender_decisions=sender_decisions
691
+ session,
692
+ bot,
693
+ event,
694
+ sender_id,
695
+ sender_decisions=sender_decisions,
696
+ group_id=effective_group_id,
672
697
  ):
673
698
  return "skipped"
674
699
  try:
@@ -690,7 +715,9 @@ async def _recall_records(
690
715
  *,
691
716
  target_user_id: int | None,
692
717
  recall_count: int,
718
+ group_id: int | None = None,
693
719
  ) -> RecallResult:
720
+ effective_group_id = event.group_id if group_id is None else group_id
694
721
  result = RecallResult()
695
722
  trigger_message_id = str(getattr(event, "message_id", ""))
696
723
  sender_decisions: dict[int, bool] = {}
@@ -705,6 +732,7 @@ async def _recall_records(
705
732
  trigger_message_id=trigger_message_id,
706
733
  target_user_id=target_user_id,
707
734
  sender_decisions=sender_decisions,
735
+ group_id=effective_group_id,
708
736
  )
709
737
  if status == "recalled":
710
738
  result.recalled += 1
@@ -30,6 +30,7 @@ from ....commands.remote import (
30
30
  remote_block_cmd,
31
31
  remote_kick_cmd,
32
32
  remote_mute_cmd,
33
+ remote_recall_cmd,
33
34
  remote_unblock_cmd,
34
35
  remote_unmute_cmd,
35
36
  remote_whole_mute_cmd,
@@ -54,6 +55,12 @@ from .common import (
54
55
  resolve_user_onebot11,
55
56
  store_block_record,
56
57
  )
58
+ from .mute import (
59
+ RECALL_COUNT_MAX,
60
+ _list_recall_candidate_records,
61
+ _recall_records,
62
+ _resolve_recall_args,
63
+ )
57
64
 
58
65
  _MASS_TARGET_SEPARATOR = re.compile(r"[,,、;;]")
59
66
  _MASS_ALL_TARGETS = frozenset({"全部群", "所有群", "all", "*"})
@@ -547,6 +554,109 @@ async def onebot11_remote_whole_unmute(
547
554
  )
548
555
 
549
556
 
557
+ @selected_adapter_handle(remote_recall_cmd, "~onebot.v11", "remote_recall")
558
+ async def onebot11_remote_recall(
559
+ group_id: int | str,
560
+ bot: OneBot11Bot,
561
+ event: OneBot11GroupMessageEvent,
562
+ session: async_scoped_session,
563
+ target: At | int | None = None,
564
+ count: int | None = None,
565
+ ) -> Any:
566
+ """远程撤回处理器:在 <群> 撤回最近消息(可选 @用户 / 数量)。"""
567
+ config = await get_handle_config_manager().get_config("remote_recall")
568
+ if not config.enabled:
569
+ return await remote_recall_cmd.finish(await _("该功能已禁用"))
570
+ default_count = int(config.defaults.get("default_count", 10))
571
+
572
+ resolved_group_id = await _resolve_group_id(bot, group_id, remote_recall_cmd)
573
+ if resolved_group_id is None:
574
+ return None
575
+ group_id_int = resolved_group_id
576
+
577
+ if not await _validate_remote_context(bot, group_id_int, remote_recall_cmd):
578
+ return None
579
+
580
+ try:
581
+ target_user_id, target_name, recall_count = await _resolve_recall_args(
582
+ target, count, bot, event, default_count=default_count
583
+ )
584
+ except ValueError as e:
585
+ # 目标不在当前群时 @ 解析会失败 —— 但「远程」场景下目标本来就可能不在本群:
586
+ # 退化为「只用 QQ 号」继续(撤回的是 ta 在目标群里的消息)。
587
+ if isinstance(target, At):
588
+ raw_target = str(target.target)
589
+ if not raw_target.isdigit():
590
+ return await remote_recall_cmd.finish(
591
+ (await _("不支持的目标: {target}")).format(target=raw_target)
592
+ )
593
+ target_user_id, target_name = int(raw_target), None
594
+ recall_count = count if count is not None else default_count
595
+ else:
596
+ logger.warning(f"解析用户失败: {e}")
597
+ return await remote_recall_cmd.finish(str(e))
598
+
599
+ if recall_count < 1:
600
+ return await remote_recall_cmd.finish(await _("撤回数量不能小于 1 条"))
601
+ if recall_count > RECALL_COUNT_MAX:
602
+ return await remote_recall_cmd.finish(
603
+ (await _("撤回数量不能超过 {max} 条")).format(max=RECALL_COUNT_MAX)
604
+ )
605
+
606
+ records = await _list_recall_candidate_records(
607
+ session,
608
+ bot,
609
+ event,
610
+ target_user_id=target_user_id,
611
+ recall_count=recall_count,
612
+ group_id=group_id_int,
613
+ )
614
+ result = await _recall_records(
615
+ session,
616
+ bot,
617
+ event,
618
+ records,
619
+ target_user_id=target_user_id,
620
+ recall_count=recall_count,
621
+ group_id=group_id_int,
622
+ )
623
+
624
+ record_audit_fire_and_forget(
625
+ bot,
626
+ event,
627
+ CommandAudit(
628
+ action="remote_recall",
629
+ target_user_id=target_user_id,
630
+ reason=(
631
+ f"group={group_id_int}, count={recall_count}, "
632
+ f"recalled={result.recalled}, skipped={result.skipped}, "
633
+ f"failed={result.failed}"
634
+ ),
635
+ group_id=group_id_int,
636
+ ),
637
+ )
638
+
639
+ target_text = ""
640
+ if target_user_id is not None:
641
+ target_text = "\n" + (await _("目标: {target}")).format(
642
+ target=format_user_display_name(target_user_id, target_name)
643
+ )
644
+ message = await _(
645
+ "已远程撤回: \n"
646
+ "目标群: {group_id}\n"
647
+ "已撤回 {recalled} 条消息,跳过 {skipped} 条,失败 {failed} 条{target_text}"
648
+ )
649
+ return await remote_recall_cmd.finish(
650
+ message.format(
651
+ group_id=group_id_int,
652
+ recalled=result.recalled,
653
+ skipped=result.skipped,
654
+ failed=result.failed,
655
+ target_text=target_text,
656
+ )
657
+ )
658
+
659
+
550
660
  @selected_adapter_handle(remote_kick_cmd, "~onebot.v11", "remote_kick")
551
661
  async def onebot11_remote_kick(
552
662
  group_id: int | str,
@@ -18,6 +18,7 @@ _REMOTE_WHOLE_MUTE = COMMAND_TRIGGERS["remote_whole_mute"]
18
18
  _REMOTE_WHOLE_UNMUTE = COMMAND_TRIGGERS["remote_whole_unmute"]
19
19
  _REMOTE_KICK = COMMAND_TRIGGERS["remote_kick"]
20
20
  _REMOTE_BLOCK = COMMAND_TRIGGERS["remote_block"]
21
+ _REMOTE_RECALL = COMMAND_TRIGGERS["remote_recall"]
21
22
  _REMOTE_UNBLOCK = COMMAND_TRIGGERS["remote_unblock"]
22
23
  _REMOTE_ANNOUNCEMENT = COMMAND_TRIGGERS["remote_announcement"]
23
24
  _MASS_ANNOUNCEMENT = COMMAND_TRIGGERS["mass_announcement"]
@@ -89,6 +90,19 @@ remote_kick_cmd: type[AlconnaMatcher] = on_alconna(
89
90
  use_cmd_start=True,
90
91
  )
91
92
 
93
+ # 远程撤回命令
94
+ remote_recall_cmd: type[AlconnaMatcher] = on_alconna(
95
+ command=Alconna(
96
+ _REMOTE_RECALL.primary,
97
+ Args["group_id", (int, str)]["target?", At | int, None]["count?", int, None],
98
+ ),
99
+ aliases=_REMOTE_RECALL.aliases,
100
+ priority=805,
101
+ block=True,
102
+ use_cmd_sep=False,
103
+ use_cmd_start=True,
104
+ )
105
+
92
106
  # 远程拉黑命令
93
107
  remote_block_cmd: type[AlconnaMatcher] = on_alconna(
94
108
  command=Alconna(
@@ -457,6 +457,12 @@ _DEFAULT_COMMAND_TRIGGERS = {
457
457
  chinese_aliases=frozenset({"跨群拉黑", "远程拉黑用户"}),
458
458
  english_aliases=frozenset({"remote-block-member", "cross-group-block"}),
459
459
  ),
460
+ "remote_recall": CommandTrigger(
461
+ chinese="远程撤回",
462
+ english="remote-recall",
463
+ chinese_aliases=frozenset({"跨群撤回", "远程撤回消息"}),
464
+ english_aliases=frozenset({"cross-group-recall", "remote-delete-message"}),
465
+ ),
460
466
  "remote_unblock": CommandTrigger(
461
467
  chinese="远程删黑",
462
468
  english="remote-unblock",