Skip to content

feat: add static help image command (/鹿帮助) v2.1.2 - #25

Closed
shitianyaa wants to merge 1 commit into
AstrBot-Elementary-School:masterfrom
shitianyaa:feat/static-help-image-v2.1.2
Closed

feat: add static help image command (/鹿帮助) v2.1.2#25
shitianyaa wants to merge 1 commit into
AstrBot-Elementary-School:masterfrom
shitianyaa:feat/static-help-image-v2.1.2

Conversation

@shitianyaa

@shitianyaa shitianyaa commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Add /鹿帮助 with static assets/help.png, plain-text help triggers, and event-level dedup/stop for help/deer/calendar double-fire. Also allow no-space 🦌@用户 plain triggers and ignore local data/.

Motivation / 动机

  • 用户需要快速查看命令说明,但不希望依赖 t2i / 网络渲染。
  • 私聊或 @bot 时,slash 命令与 plain regex 可能同时激活,导致帮助图/打卡/鹿历重复发送。
  • 部分客户端把 @ 拼进 message_str 时,无空格 🦌@用户 无法触发 plain 打卡。
  • 本地运行时目录 data/(含配置/缓存)不应被误提交。

Modifications / 改动点

  • 新增固定帮助图命令:/鹿帮助(别名 🦌帮助 / 鹿菜单 / deer_help / deerhelp

  • 新增纯文本帮助触发:鹿帮助🦌帮助鹿菜单deer help 等(大小写不敏感,允许中文空格)

  • 运行时直接发送打包资源 assets/help.png;缺失时回退文本提示

  • 新增开发机截图脚本 scripts/gen_help_image.py非运行时依赖

  • 帮助 / 打卡 / 鹿历共用 event.extra 幂等键,并在处理后 stop_event,避免 slash + plain 双发

  • plain 打卡正则支持无空格 🦌@用户 / 帮🦌@用户

  • .gitignore 增加 data/

  • 版本号 v2.1.2;同步 CHANGELOG.md / README.md / CLAUDE.md

  • 测试:tests/test_help_handler.py、扩展 tests/test_plain_message_patterns.py

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

python tests/run_tests.py --quick --no-install
# All tests passed! Total: 85 tests passed

python -m ruff check main.py src/shared/constants.py \
  src/application/commands/help_cmd.py \
  src/application/commands/deer_cmd.py \
  src/application/commands/calendar_cmd.py \
  tests/test_plain_message_patterns.py \
  tests/test_help_handler.py \
  scripts/gen_help_image.py
# All checks passed!

帮助图已本地生成:assets/help.png(约 472KB)。建议真机再验证:私聊发 鹿帮助 是否只回一张图。


Verification Steps / 验证步骤

# 在插件仓库根目录
python tests/run_tests.py --quick --no-install
python -m ruff check main.py src/shared/constants.py src/application/commands/help_cmd.py src/application/commands/deer_cmd.py src/application/commands/calendar_cmd.py tests/test_plain_message_patterns.py tests/test_help_handler.py scripts/gen_help_image.py

(可选)语法检查:

python -m py_compile main.py src/application/commands/help_cmd.py src/shared/constants.py

(可选)重生成帮助图(需本机 Playwright Chromium):

python scripts/gen_help_image.py

真机抽查:

  1. 私聊发送 鹿帮助 / /鹿帮助 → 应只收到 一张 帮助图
  2. 群聊发送 🦌@用户(客户端 @)→ 应走帮打卡
  3. 私聊发送 鹿 / 鹿历 → 不应双发

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed them with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 无新运行时依赖;Playwright 仅用于开发机生成 help.png

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

  • 📘 I have read and followed repository contribution guidelines.
    / 我已阅读并遵守仓库贡献规范。

Summary by Sourcery

添加一个静态帮助图片命令,并统一纯文本触发词、文档及事件处理逻辑,以避免重复响应并支持更自然的帮助/打卡使用方式。

New Features:

  • 引入专用的帮助命令,提供打包的静态帮助图片,而不是使用 t2i 渲染。
  • 为中英文输入添加与帮助命令别名一致的纯文本帮助触发词。

Bug Fixes:

  • 当同一事件中同时触发斜杠命令和纯文本触发词时,避免对帮助、打卡和日历命令进行重复处理。
  • 确保纯文本打卡匹配规则不再匹配与帮助相关的短语,并支持像 🦌@用户 这样的无空格 @ 提及格式。

Enhancements:

  • 在新的 HelpCommandHandler 中集中处理帮助逻辑,以事件为粒度实现幂等行为并发送静态图片。
  • 收紧并记录鹿、日历和帮助命令的纯文本触发模式,并提供辅助脚本用于通过 Playwright 重新生成帮助图片。

Documentation:

  • README.mdCLAUDE.md 中记录新的静态帮助图片命令、无空格 @ 提及支持以及帮助维护流程,并更新 v2.1.2 的更新日志。

Tests:

  • 添加关于帮助图片处理和事件去重的测试,并扩展纯文本触发模式测试以覆盖新的帮助和打卡用例。

Chores:

  • 将插件版本提升到 v2.1.2,更新测试运行配置以包含新的帮助处理器测试,并在版本控制中忽略本地 data/ 目录。
Original summary in English

Summary by Sourcery

Add a static help image command and align plain-text triggers, documentation, and event handling to avoid duplicate responses and support more natural help/check-in usage.

New Features:

  • Introduce a dedicated help command that serves a bundled static help image instead of using t2i rendering.
  • Add plain-text help triggers that mirror the help command aliases for both Chinese and English inputs.

Bug Fixes:

  • Prevent duplicate handling of help, check-in, and calendar commands when both slash and plain-text triggers fire on the same event.
  • Ensure plain-text check-in patterns no longer match help-related phrases and support no-space mention formats like 🦌@用户.

Enhancements:

  • Centralize help handling in a new HelpCommandHandler that sends the static image with idempotent event-level behavior.
  • Tighten and document plain-text trigger patterns for deer, calendar, and help commands, and expose a helper script to regenerate the help image from Playwright.

Documentation:

  • Document the new static help image command, no-space mention support, and help maintenance workflow in README.md and CLAUDE.md, and update the changelog for v2.1.2.

Tests:

  • Add tests for help image handling and event deduplication, and extend plain-text trigger pattern tests to cover new help and check-in cases.

Chores:

  • Bump plugin version to v2.1.2 and update test runner configuration to include the new help handler tests, while ignoring local data/ in version control.

Summary by CodeRabbit

  • 新功能

    • 新增 /鹿帮助鹿帮助 及相关别名,发送固定帮助图片。
    • 帮助图片缺失时自动回退为文本提示。
    • 支持更多纯文本帮助与打卡命令格式。
  • 问题修复

    • 修复私聊、唤醒及重复触发导致的重复响应。
    • 优化帮助命令大小写、空格和别名识别。
    • 避免帮助、打卡和日历请求被错误路由。
  • 文档

    • 更新版本至 2.1.2,并同步完善命令说明。

Add /鹿帮助 with static assets/help.png, plain-text help triggers, and
event-level dedup/stop for help/deer/calendar double-fire. Also allow
no-space 🦌@用户 plain triggers and ignore local data/.
@shitianyaa
shitianyaa requested a review from FlanChanXwO as a code owner July 21, 2026 01:02
@sourcery-ai

sourcery-ai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

实现一个静态帮助图片命令(/鹿帮助),同时支持斜杠命令和纯文本触发;为帮助 / 鹿 / 日历在斜杠与纯文本处理器之间增加事件级去重;扩展纯文本“鹿”匹配模式以支持无空格提及;更新文档描述新行为,并将插件版本提升到 v2.1.2。

帮助命令处理与斜杠/纯文本去重的序列图

sequenceDiagram
    actor User
    participant AstrBot
    participant Main as MainHandler
    participant Help as HelpCommandHandler
    participant Event as AstrMessageEvent

    User->>AstrBot: /鹿帮助
    AstrBot->>Main: help_cmd(event)
    Main->>Help: handle_help(event)
    Help->>Event: get_extra(EVENT_DEDUP_HELP)
    alt [event not yet handled]
        Help->>Event: set_extra(EVENT_DEDUP_HELP, True)
        Help->>Help: help_image.is_file()
        alt [image exists]
            Help->>Event: image_result(help.png)
            Help->>Event: stop_event()
        else [image missing]
            Help->>Event: plain_result("帮助图资源缺失,请重新安装或更新插件。")
            Help->>Event: stop_event()
        end
    else [event already handled]
        Help-->>Main: return
    end

    User->>AstrBot: 鹿帮助
    AstrBot->>Main: plain_help_cmd(event)
    Main->>Main: _is_explicit_slash_command(event)
    alt [_is_explicit_slash_command returns False]
        Main->>Help: handle_help(event)
    else [_is_explicit_slash_command returns True]
        Main-->>AstrBot: return (do not run plain handler)
    end
Loading

File-Level Changes

Change Details Files
引入 HelpCommandHandler,通过斜杠和纯文本帮助命令提供静态 help.png,并在事件级别上进行去重。
  • 添加 HelpCommandHandler 类,解析 assets/help.png,在图片存在时发出 image_result,图片缺失时回退到纯文本错误提示,并使用 EVENT_DEDUP_HELP 加上 stop_event 实现幂等性。
  • 在 main.py 中接入帮助处理器,新增 /鹿帮助 斜杠命令(别名 🦌帮助、鹿菜单、deer_help、deerhelp),以及使用 PLAIN_HELP_TRIGGER_PATTERN 的纯文本正则处理器,避免对斜杠命令进行重复处理。
  • 从 src 和 application 的 init 模块导出 HelpCommandHandler,以便供 main 和测试使用,并新增 tests/test_help_handler.py,以验证图片发送、回退以及去重行为。
src/application/commands/help_cmd.py
main.py
src/__init__.py
src/application/__init__.py
src/application/commands/__init__.py
tests/test_help_handler.py
优化纯文本触发模式并引入帮助触发/去重常量,更好地区分鹿、日历和帮助流程,并防止重复触发。
  • 更新 PLAIN_DEER_TRIGGER_PATTERN,使其允许无空格的 🦌@用户 / 帮🦌@用户 / 鹿@用户 等,同时显式排除像 鹿帮助 和 鹿菜单 这样的帮助/菜单短语不被匹配。
  • 添加 PLAIN_HELP_TRIGGER_PATTERN,作为针对 鹿帮助 / 🦌帮助 / 鹿菜单 / deer[_ ]?help 的大小写不敏感、带锚点的模式,并引入 EVENT_DEDUP_HELP/DEER/CALENDAR 常量,以实现跨处理器的幂等性。
  • 扩展 test_plain_message_patterns.py 中的测试,覆盖新的“鹿”接受/拒绝案例以及中英文帮助命令的接受/拒绝行为。
src/shared/constants.py
tests/test_plain_message_patterns.py
为鹿和日历命令处理器添加去重和 stop_event 行为,以避免在斜杠/纯文本处理器之间产生重复响应,尤其是在私聊和 @bot 场景下。
  • 在 DeerCommandHandler.run_deer_checkin 中,使用 EVENT_DEDUP_DEER 进行保护,并在首次处理时进行设置;在自助和帮他人两种流程(包括错误分支)中产生任何响应后都调用 event.stop_event()。
  • 在日历处理器 _run_calendar_query 中,使用 EVENT_DEDUP_CALENDAR 进行保护并在首次处理时设置,在自助和目标用户日历查询的响应之后都调用 event.stop_event()。
  • 增强 main._is_explicit_slash_command,检查 message_str 和 Plain 组件中的前导 '/',以区分显式斜杠命令和纯文本,从而避免同时运行两个处理器。
src/application/commands/deer_cmd.py
src/application/commands/calendar_cmd.py
main.py
src/shared/constants.py
添加仅供开发使用的 Playwright 脚本,以重新生成帮助图片,并澄清资源使用和文档。
  • 引入 scripts/gen_help_image.py,使用 Playwright 和打包的 resources/images,将 HTML 帮助卡片渲染为 assets/help.png,基于与 main.py 命令对齐的 SECTIONS 定义。
  • 更新 README,加入新的帮助命令说明、鹿帮助 和无空格 🦌@用户 / 帮🦌@用户 的示例,并增加维护说明,描述在命令别名变更时如何重新生成 help.png。
  • 调整 CLAUDE.md 的项目概览和目录注释,将 assets/help.png 视为运行时静态资源并提及该仅供开发使用的脚本,同时添加 tests/run_tests.py,将 test_help_handler.py 纳入快速测试套件。
scripts/gen_help_image.py
README.md
CLAUDE.md
tests/run_tests.py
提升插件版本和元数据,同时在 git 中忽略本地运行时数据。
  • 将 metadata.yaml 版本从 v2.1.1 更新为 v2.1.2,并在 CHANGELOG.md 中记录本次发布,详细说明帮助命令、去重修复以及触发行为变更。
  • 在 README 和 CLAUDE.md 中提及静态帮助图片能力和去重行为,并相应调整命令表和使用示例。
  • 将 data/ 添加到 .gitignore 中,以避免提交本地运行时配置/缓存目录。
metadata.yaml
CHANGELOG.md
README.md
CLAUDE.md
.gitignore

Tips and commands

Interacting with Sourcery

  • 触发新评审: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的评审评论。
  • 从评审评论生成 GitHub issue: 回复 Sourcery 的评审评论,要求其从该评论创建一个 issue。你也可以在评审评论中回复 @sourcery-ai issue 来从该评论创建一个 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写上 @sourcery-ai,即可随时生成一个标题。你也可以在拉取请求中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成拉取请求摘要: 在拉取请求正文任意位置写上 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成评审者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时(重新)生成评审者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。适用于你已经处理完所有评论且不再希望看到它们的情况。
  • 关闭所有 Sourcery 评审: 在拉取请求中评论 @sourcery-ai dismiss,即可关闭所有现有的 Sourcery 评审。特别适用于你希望以一次全新的评审重新开始——别忘了再评论 @sourcery-ai review 来触发新的评审!

Customizing Your Experience

访问你的 dashboard 以:

  • 启用或禁用评审功能,例如 Sourcery 生成的拉取请求摘要、评审者指南等。
  • 更改评审语言。
  • 添加、移除或编辑自定义评审说明。
  • 调整其他评审设置。

Getting Help

Original review guide in English

Reviewer's Guide

Implements a static help image command (/鹿帮助) with both slash and plain-text triggers, adds event-level deduplication between slash/plain handlers for help/deer/calendar, extends plain deer patterns to support no-space mentions, documents the new behavior, and bumps the plugin to v2.1.2.

Sequence diagram for help command handling and slash/plain deduplication

sequenceDiagram
    actor User
    participant AstrBot
    participant Main as MainHandler
    participant Help as HelpCommandHandler
    participant Event as AstrMessageEvent

    User->>AstrBot: /鹿帮助
    AstrBot->>Main: help_cmd(event)
    Main->>Help: handle_help(event)
    Help->>Event: get_extra(EVENT_DEDUP_HELP)
    alt [event not yet handled]
        Help->>Event: set_extra(EVENT_DEDUP_HELP, True)
        Help->>Help: help_image.is_file()
        alt [image exists]
            Help->>Event: image_result(help.png)
            Help->>Event: stop_event()
        else [image missing]
            Help->>Event: plain_result("帮助图资源缺失,请重新安装或更新插件。")
            Help->>Event: stop_event()
        end
    else [event already handled]
        Help-->>Main: return
    end

    User->>AstrBot: 鹿帮助
    AstrBot->>Main: plain_help_cmd(event)
    Main->>Main: _is_explicit_slash_command(event)
    alt [_is_explicit_slash_command returns False]
        Main->>Help: handle_help(event)
    else [_is_explicit_slash_command returns True]
        Main-->>AstrBot: return (do not run plain handler)
    end
Loading

File-Level Changes

Change Details Files
Introduce HelpCommandHandler to serve a static help.png via slash and plain-text help commands with event-level deduplication.
  • Add HelpCommandHandler class that resolves assets/help.png, emits an image_result when present, falls back to a plain text error when missing, and uses EVENT_DEDUP_HELP plus stop_event for idempotence.
  • Wire help handler into main.py with a new /鹿帮助 slash command (aliases 🦌帮助, 鹿菜单, deer_help, deerhelp) and a plain-text regex handler using PLAIN_HELP_TRIGGER_PATTERN that avoids double-handling slash commands.
  • Export HelpCommandHandler from src and application init modules so it can be used by main and tests, and add tests/test_help_handler.py to validate image delivery, fallback, and dedup behavior.
src/application/commands/help_cmd.py
main.py
src/__init__.py
src/application/__init__.py
src/application/commands/__init__.py
tests/test_help_handler.py
Refine plain-text trigger patterns and introduce help trigger/duplication constants to better separate deer, calendar, and help flows and prevent double firing.
  • Update PLAIN_DEER_TRIGGER_PATTERN to allow no-space 🦌@用户 / 帮🦌@用户 / 鹿@用户 etc., while explicitly excluding help/menu phrases like 鹿帮助 and 鹿菜单 from matching.
  • Add PLAIN_HELP_TRIGGER_PATTERN as a case-insensitive, anchored pattern for 鹿帮助/🦌帮助/鹿菜单/deer[_ ]?help and introduce EVENT_DEDUP_HELP/DEER/CALENDAR constants for cross-handler idempotence.
  • Extend tests in test_plain_message_patterns.py to cover new deer acceptance/rejection cases and help acceptance/rejection for both Chinese and English variants.
src/shared/constants.py
tests/test_plain_message_patterns.py
Add deduplication and stop_event behavior to deer and calendar command handlers to avoid duplicate responses across slash/plain handlers, especially in private chats and @bot scenarios.
  • In DeerCommandHandler.run_deer_checkin, guard with EVENT_DEDUP_DEER and set it on first handling, then call event.stop_event() after producing any response in both self and help-others flows, including error branches.
  • In calendar handler _run_calendar_query, guard with EVENT_DEDUP_CALENDAR and set it on first handling, calling event.stop_event() after responding for both self and target calendar queries.
  • Enhance main._is_explicit_slash_command to inspect both message_str and Plain components for leading '/' to distinguish explicit slash commands from pure text and avoid running both handlers.
src/application/commands/deer_cmd.py
src/application/commands/calendar_cmd.py
main.py
src/shared/constants.py
Add a dev-only Playwright script to regenerate the help image and clarify asset usage and documentation.
  • Introduce scripts/gen_help_image.py which uses Playwright and bundled resources/images to render an HTML help card to assets/help.png based on a SECTIONS definition aligned with main.py commands.
  • Update README with the new help command description, examples for 鹿帮助 and no-space 🦌@用户/帮🦌@用户, and a maintenance note describing how to regenerate help.png when command aliases change.
  • Adjust CLAUDE.md project overview and directory comments to treat assets/help.png as a runtime static asset and mention the dev-only script, and add tests/run_tests.py to include test_help_handler.py in the quick test suite.
scripts/gen_help_image.py
README.md
CLAUDE.md
tests/run_tests.py
Bump plugin version and metadata while ignoring local runtime data in git.
  • Update metadata.yaml version from v2.1.1 to v2.1.2 and document the new release in CHANGELOG.md with details on the help command, dedup fixes, and trigger behavior changes.
  • Mention the static help image capability and dedup behavior in README and CLAUDE.md, and adjust command tables and usage examples accordingly.
  • Add data/ to .gitignore so local runtime configuration/cache directories are not committed.
metadata.yaml
CHANGELOG.md
README.md
CLAUDE.md
.gitignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1630dfa6-d67c-4801-be26-f11d40597bdf

📥 Commits

Reviewing files that changed from the base of the PR and between 0510872 and 661a648.

⛔ Files ignored due to path filters (1)
  • assets/help.png is excluded by !**/*.png
📒 Files selected for processing (17)
  • .gitignore
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • main.py
  • metadata.yaml
  • scripts/gen_help_image.py
  • src/__init__.py
  • src/application/__init__.py
  • src/application/commands/__init__.py
  • src/application/commands/calendar_cmd.py
  • src/application/commands/deer_cmd.py
  • src/application/commands/help_cmd.py
  • src/shared/constants.py
  • tests/run_tests.py
  • tests/test_help_handler.py
  • tests/test_plain_message_patterns.py

📝 Walkthrough

Walkthrough

新增固定帮助图命令(/鹿帮助 及纯文本触发),实现 HelpCommandHandler 直接发送 assets/help.png(无 t2i 依赖),并在 main.py 中接入相应命令与正则处理器。新增事件去重常量并在打卡/日历命令流程中添加去重检查与 stop_event 调用。新增帮助图生成脚本、测试及文档/版本更新。

Changes

帮助图命令与去重停止事件

Layer / File(s) Summary
触发正则与去重常量
src/shared/constants.py
更新 PLAIN_DEER_TRIGGER_PATTERN,新增 PLAIN_HELP_TRIGGER_PATTERNEVENT_DEDUP_HELP/EVENT_DEDUP_DEER/EVENT_DEDUP_CALENDAR 常量。
HelpCommandHandler 实现与导出
src/application/commands/help_cmd.py, src/application/commands/__init__.py, src/application/__init__.py, src/__init__.py
新增帮助命令处理器,检测图片是否存在并返回图片或文本回退,通过去重标记避免重复处理,并在各级 __init__ 中导出。
main.py 命令注册与显式斜杠检测
main.py
接入 HelpCommandHandler,新增 help_cmd/plain_help_cmd 命令处理器,增强 _is_explicit_slash_command 检测逻辑以避免重复触发。
打卡与日历命令去重及 stop_event
src/application/commands/deer_cmd.py, src/application/commands/calendar_cmd.py
为打卡与日历查询流程加入去重检查,并在多个处理分支结束处调用 event.stop_event()
帮助图生成脚本
scripts/gen_help_image.py
新增基于 Playwright 的 HTML 渲染脚本,生成 assets/help.png
测试覆盖:帮助处理器与纯文本触发
tests/test_help_handler.py, tests/test_plain_message_patterns.py, tests/run_tests.py
新增帮助处理器单测(图片发送/缺失回退/幂等性)及纯文本触发正则测试,并注册新测试文件。
文档与版本更新
CHANGELOG.md, CLAUDE.md, README.md, metadata.yaml, .gitignore
更新变更日志、项目说明、README 命令表与维护说明、版本号,以及 gitignore 忽略规则。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: flanchanxwo

Poem

兔子蹦跳来敲门,🐇
帮助图片藏好啦,help.png 稳稳当当,
去重标记像胡萝卜,吃一次就够,
stop_event 一声令,事件链路不再走,
鹿帮助一喊,图卡送到手~ 🦌📋


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@shitianyaa

shitianyaa commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator Author

误提到上游,已经关闭惹

@shitianyaa shitianyaa closed this Jul 21, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体层面的反馈:

  • 事件去重模式(EVENT_DEDUP_* + get_extra/set_extra + stop_event)现在在 help_cmddeer_cmdcalendar_cmd 中都有重复;建议提取一个小的辅助函数(例如 mark_handled(event, key))来集中这部分逻辑,以避免未来新 handler 中出现一些不易察觉的不一致。
  • tests/test_help_handler.py::_load_help_command_handler 中的自定义导入路径脚手架逻辑比较复杂、也比较脆弱;可以考虑通过直接从真实的 src 包中(或者通过一个最小的测试专用 shim 模块)导入 HelpCommandHandlerEVENT_DEDUP_HELP,而不是去模拟一套单独的包层级结构,从而简化实现。
给 AI Agent 的提示
请根据本次代码评审中的意见进行修改:

## 整体性评论
- 事件去重模式(`EVENT_DEDUP_*` + `get_extra/set_extra` + `stop_event`)现在在 `help_cmd``deer_cmd``calendar_cmd` 中都有重复;建议提取一个小的辅助函数(例如 `mark_handled(event, key)`)来集中这部分逻辑,以避免未来新 handler 中出现一些不易察觉的不一致。
- `tests/test_help_handler.py::_load_help_command_handler` 中的自定义导入路径脚手架逻辑比较复杂、也比较脆弱;可以考虑通过直接从真实的 `src` 包中(或者通过一个最小的测试专用 shim 模块)导入 `HelpCommandHandler``EVENT_DEDUP_HELP`,而不是去模拟一套单独的包层级结构,从而简化实现。

## 单条评论

### 评论 1
<location path="scripts/gen_help_image.py" line_range="197" />
<code_context>
+            await browser.close()
+    finally:
+        html_path.unlink(missing_ok=True)
+    print(f"saved {OUT_PNG} ({OUT_PNG.stat().st_size} bytes)")
+
+
</code_context>
<issue_to_address>
**issue:** 为最后一次 OUT_PNG.stat() 调用增加保护,以避免在截图生成失败时导致崩溃。

如果 Playwright 在渲染或写入截图时失败,OUT_PNG 可能不会被创建,而此时调用 OUT_PNG.stat() 会抛出 FileNotFoundError。这样会把工具层面的问题(例如缺少 Chromium、字体下载出错等)变成脚本里一个不友好的崩溃。请在调用 stat() 之前先检查 OUT_PNG.exists(),并在文件缺失时输出更清晰的提示信息,使脚本在失败时表现得更“温和”一些。
</issue_to_address>

### 评论 2
<location path="src/shared/constants.py" line_range="14-21" />
<code_context>
 # =============================================================================

 PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
-    r"^(?!/)(?:[🦌鹿撸]|撸🦌|帮\s*(?:[🦌鹿撸]|撸🦌))(?:\s+.*)?$"
+    r"^(?!/)"
+    r"(?:"
+    r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.*|@.*)?|"
</code_context>
<issue_to_address>
**suggestion:** 重新审视 PLAIN_DEER_TRIGGER_PATTERN,以更好处理像不带目标对象的裸 "帮🦌" 这类边界情况。

由于增加了可选的 (?:\s+.*|@.*)? 分组,现在该模式会匹配裸 "帮🦌" / "帮鹿"。在 run_deer_checkin 中,当 at_ids 为空时,帮 分支会退回到自助打卡,因此这些输入会被当作普通打卡,而不是“帮别人打卡”命令。如果这不是你想要的行为,可以考虑收紧 帮… 的正则,让它必须包含 @ 提及或额外文本(例如 @.* 或 \s+@...)。

```suggestion
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
    r"^(?!/)"
    r"(?:"
    r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.+|@.+)|"
    r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
    r")$"
)
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;要求帮命令后有 @ 或额外文本;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""
```
</issue_to_address>

Sourcery 对开源项目免费使用——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • The event deduplication pattern (EVENT_DEDUP_* + get_extra/set_extra + stop_event) is now duplicated across help_cmd, deer_cmd, and calendar_cmd; consider extracting a small helper (e.g., mark_handled(event, key)) to centralize this behavior and avoid subtle inconsistencies in future handlers.
  • The custom import path scaffolding in tests/test_help_handler.py::_load_help_command_handler is quite involved and brittle; you might simplify this by importing HelpCommandHandler and EVENT_DEDUP_HELP from the real src package (or via a minimal test-only shim module) instead of emulating a separate package hierarchy.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The event deduplication pattern (`EVENT_DEDUP_*` + `get_extra/set_extra` + `stop_event`) is now duplicated across `help_cmd`, `deer_cmd`, and `calendar_cmd`; consider extracting a small helper (e.g., `mark_handled(event, key)`) to centralize this behavior and avoid subtle inconsistencies in future handlers.
- The custom import path scaffolding in `tests/test_help_handler.py::_load_help_command_handler` is quite involved and brittle; you might simplify this by importing `HelpCommandHandler` and `EVENT_DEDUP_HELP` from the real `src` package (or via a minimal test-only shim module) instead of emulating a separate package hierarchy.

## Individual Comments

### Comment 1
<location path="scripts/gen_help_image.py" line_range="197" />
<code_context>
+            await browser.close()
+    finally:
+        html_path.unlink(missing_ok=True)
+    print(f"saved {OUT_PNG} ({OUT_PNG.stat().st_size} bytes)")
+
+
</code_context>
<issue_to_address>
**issue:** Guard the final OUT_PNG.stat() call to avoid crashing when screenshot generation fails.

If Playwright fails to render or write the screenshot, OUT_PNG may not be created and OUT_PNG.stat() will raise FileNotFoundError. This turns tooling issues (e.g. missing Chromium, font download problems) into an unhelpful crash in this script. Please check OUT_PNG.exists() before calling stat(), and emit a clearer message when the file is missing so the script fails more gracefully.
</issue_to_address>

### Comment 2
<location path="src/shared/constants.py" line_range="14-21" />
<code_context>
 # =============================================================================

 PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
-    r"^(?!/)(?:[🦌鹿撸]|撸🦌|帮\s*(?:[🦌鹿撸]|撸🦌))(?:\s+.*)?$"
+    r"^(?!/)"
+    r"(?:"
+    r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.*|@.*)?|"
</code_context>
<issue_to_address>
**suggestion:** Revisit the PLAIN_DEER_TRIGGER_PATTERN for edge cases like bare "帮🦌" without a target.

With the optional (?:\s+.*|@.*)? group, the pattern now matches bare "帮🦌" / "帮鹿". In run_deer_checkin, the 帮 branch falls back to self-checkin when at_ids is empty, so these inputs are treated as normal check-ins rather than "help others" commands. If that’s not desired, consider tightening the 帮… regex to require an @ mention or additional text (e.g., @.* or \s+@...).

```suggestion
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
    r"^(?!/)"
    r"(?:"
    r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.+|@.+)|"
    r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
    r")$"
)
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;要求帮命令后有 @ 或额外文本;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread scripts/gen_help_image.py
await browser.close()
finally:
html_path.unlink(missing_ok=True)
print(f"saved {OUT_PNG} ({OUT_PNG.stat().st_size} bytes)")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: 为最后一次 OUT_PNG.stat() 调用增加保护,以避免在截图生成失败时导致崩溃。

如果 Playwright 在渲染或写入截图时失败,OUT_PNG 可能不会被创建,而此时调用 OUT_PNG.stat() 会抛出 FileNotFoundError。这样会把工具层面的问题(例如缺少 Chromium、字体下载出错等)变成脚本里一个不友好的崩溃。请在调用 stat() 之前先检查 OUT_PNG.exists(),并在文件缺失时输出更清晰的提示信息,使脚本在失败时表现得更“温和”一些。

Original comment in English

issue: Guard the final OUT_PNG.stat() call to avoid crashing when screenshot generation fails.

If Playwright fails to render or write the screenshot, OUT_PNG may not be created and OUT_PNG.stat() will raise FileNotFoundError. This turns tooling issues (e.g. missing Chromium, font download problems) into an unhelpful crash in this script. Please check OUT_PNG.exists() before calling stat(), and emit a clearer message when the file is missing so the script fails more gracefully.

Comment thread src/shared/constants.py
Comment on lines 14 to +21
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
r"^(?!/)(?:[🦌鹿撸]|撸🦌|帮\s*(?:[🦌鹿撸]|撸🦌))(?:\s+.*)?$"
r"^(?!/)"
r"(?:"
r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.*|@.*)?|"
r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
r")$"
)
"""纯文本打卡触发:仅完整短命令或“帮鹿/帮🦌 ...”格式,避免普通文本误触发."""
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: 重新审视 PLAIN_DEER_TRIGGER_PATTERN,以更好处理像不带目标对象的裸 "帮🦌" 这类边界情况。

由于增加了可选的 (?:\s+.|@.)? 分组,现在该模式会匹配裸 "帮🦌" / "帮鹿"。在 run_deer_checkin 中,当 at_ids 为空时,帮 分支会退回到自助打卡,因此这些输入会被当作普通打卡,而不是“帮别人打卡”命令。如果这不是你想要的行为,可以考虑收紧 帮… 的正则,让它必须包含 @ 提及或额外文本(例如 @.* 或 \s+@...)。

Suggested change
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
r"^(?!/)(?:[🦌鹿撸]|撸🦌|帮\s*(?:[🦌鹿撸]|撸🦌))(?:\s+.*)?$"
r"^(?!/)"
r"(?:"
r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.*|@.*)?|"
r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
r")$"
)
"""纯文本打卡触发:仅完整短命令或“帮鹿/帮🦌 ...”格式,避免普通文本误触发."""
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
r"^(?!/)"
r"(?:"
r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.+|@.+)|"
r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
r")$"
)
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;要求帮命令后有 @ 或额外文本;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""
Original comment in English

suggestion: Revisit the PLAIN_DEER_TRIGGER_PATTERN for edge cases like bare "帮🦌" without a target.

With the optional (?:\s+.|@.)? group, the pattern now matches bare "帮🦌" / "帮鹿". In run_deer_checkin, the 帮 branch falls back to self-checkin when at_ids is empty, so these inputs are treated as normal check-ins rather than "help others" commands. If that’s not desired, consider tightening the 帮… regex to require an @ mention or additional text (e.g., @.* or \s+@...).

Suggested change
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
r"^(?!/)(?:[🦌鹿撸]|撸🦌|帮\s*(?:[🦌鹿撸]|撸🦌))(?:\s+.*)?$"
r"^(?!/)"
r"(?:"
r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.*|@.*)?|"
r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
r")$"
)
"""纯文本打卡触发:仅完整短命令或“帮鹿/帮🦌 ...”格式,避免普通文本误触发."""
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""
PLAIN_DEER_TRIGGER_PATTERN: Final[str] = (
r"^(?!/)"
r"(?:"
r"帮\s*(?:[🦌鹿撸]|撸🦌)(?:\s+.+|@.+)|"
r"(?:撸🦌|[🦌鹿撸])(?!\s*(?:帮助|菜单))(?:\s+.*|@.*)?"
r")$"
)
"""纯文本打卡触发:短命令或“帮鹿/帮🦌 ...”;要求帮命令后有 @ 或额外文本;允许 🦌@用户 无空格;排除“鹿帮助/鹿菜单”."""

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant