news 2026/9/20 8:38:24

Cherry Studio 飞书 Webhook 通知 CLI:`scripts/feishu-notify.ts` 全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cherry Studio 飞书 Webhook 通知 CLI:`scripts/feishu-notify.ts` 全指南

Cherry Studio 飞书 Webhook 通知 CLI:scripts/feishu-notify.ts全指南

【免费下载链接】cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio

本篇技术指南围绕 CherryHQ/cherry-studio 仓库中的 scripts/feishu-notify.ts 展开,讲解如何通过一个基于 TypeScript 与 Commander 的子命令式 CLI 向飞书(Lark)Webhook 发送交互式卡片通知,并重点剖析其在 .github/workflows/github-issue-tracker.yml 中的自动化落地实践。读完本文,你将掌握sendissue两个命令的完整用法、环境变量鉴权机制、HMAC-SHA256 签名原理、GitHub Actions 集成方式,以及如何扩展新的通知命令。

一、工具定位与核心特性

scripts/feishu-notify.ts是 Cherry Studio 仓库中一个独立、可脱离主程序运行的 CLI 工具,用于向飞书群机器人 Webhook 发送通知。它不依赖 Electron 主进程或渲染进程的任何代码,仅依赖 Node.js 标准库与少量 npm 包,因此可以在 CI(如 GitHub Actions)或任何安装了 Node.js 的环境中直接运行。

从源码(scripts/feishu-notify.ts)可见其设计要点:

  • 子命令式 CLI 结构:基于commander实现,通过sendissue两个子命令区分通用通知与 GitHub Issue 通知,便于按业务扩展(program.command('send')program.command('issue'))。
  • HMAC-SHA256 签名校验:使用crypto.createHmac('sha256', ...)按飞书官方规则生成签名,保证 Webhook 请求来源可信。
  • 交互式卡片消息:发送msg_type: 'interactive'的飞书卡片(含头部颜色模板、lark_md 富文本、分隔线与跳转按钮)。
  • 完整 TypeScript 类型支持:所有卡片元素、载荷、命令选项均定义了明确的 interface,配合zod枚举(FeishuHeaderTemplateSchema)在运行时校验颜色等枚举参数。
  • 凭据走环境变量FEISHU_WEBHOOK_URLFEISHU_WEBHOOK_SECRET从环境读取,避免把密钥硬编码进命令或仓库。

依赖版本(见 package.json)为:commander ^14.0.2dotenv 16.6.1tsx ^4.20.3zod ^4.1.5@types/node 24.10.4,其中tsx用于直接执行 TypeScript 脚本,无需预编译。

二、环境准备与运行方式

2.1 前置条件

pnpm install

仓库使用 pnpm 管理依赖(根目录存在pnpm-lock.yamlpnpm-workspace.yaml)。由于脚本以#!/usr/bin/env npx tsx开头,并通过pnpm tsx调用,因此依赖tsx这一 TypeScript 执行器。

2.2 CLI 通用结构

pnpm tsx scripts/feishu-notify.ts [command] [options]

脚本启动时通过dotenv.config()自动加载.env文件(若存在),这意味着除了在 CI 中通过环境变量注入凭据外,本地调试时也可以把凭据写入仓库根目录的.env文件。

2.3 必需环境变量

变量说明
FEISHU_WEBHOOK_URL飞书群自定义机器人 Webhook 地址
FEISHU_WEBHOOK_SECRET飞书 Webhook 签名密钥(安全设置中开启"签名校验"后获得)

这两个变量缺一不可:getCredentials()scripts/feishu-notify.ts中)会在缺失时打印Error: FEISHU_WEBHOOK_URL environment variable is required并以退出码 1 结束进程,避免向错误目标发送请求。

三、命令详解与实战示例

3.1send—— 发送通用通知

send用于发送不带业务逻辑的通用通知,适合部署完成、构建失败、告警等场景:

pnpm tsx scripts/feishu-notify.ts send [options]
选项短参说明是否必填
--title-t卡片标题
--description-d卡片描述内容(支持 Markdown)
--color-c头部颜色模板否(默认turquoise

可选颜色bluewathetturquoisegreenyelloworangeredcarminevioletpurpleindigogreydefault。该枚举由FeishuHeaderTemplateSchema(zod enum)在运行时校验,若传入非法值,脚本会输出合法颜色列表并以退出码 1 终止(见handleSendCommand)。

示例一:部署完成通知(绿色)

# 使用 $'...' 语法保证换行正确 pnpm tsx scripts/feishu-notify.ts send \ -t "Deployment Completed" \ -d $'**Status:** Success\n\n**Environment:** Production\n\n**Version:** v1.2.3' \ -c green

示例二:错误告警(红色)

pnpm tsx scripts/feishu-notify.ts send \ -t "Error Alert" \ -d $'**Error Type:** Connection failed\n\n**Severity:** High\n\nPlease check the system status' \ -c red

换行注意事项:描述中的换行必须使用 bash 的$'...'语法(如$'**Status:** Success\n\n...')。不要直接在双引号内写字面量\n——它会被当作普通字符原样显示在飞书卡片中。createSimpleCard会把整个 description 作为lark_md文本元素写入卡片正文,因此 Markdown 语法(**加粗**、空行分段)都会在飞书端渲染。

3.2issue—— 发送 GitHub Issue 通知

issue专为 GitHub Issue 通知设计,自动组装作者、标签、摘要与跳转按钮:

pnpm tsx scripts/feishu-notify.ts issue [options]
选项短参说明是否必填
--url-uGitHub Issue 地址
--number-nIssue 编号
--title-tIssue 标题
--summary-mIssue 摘要
--author-aIssue 作者否(默认Unknown
--labels-lIssue 标签(逗号分隔)

示例

pnpm tsx scripts/feishu-notify.ts issue \ -u "https://github.com/owner/repo/issues/123" \ -n "123" \ -t "Bug: Something is broken" \ -m "This is a bug report about a feature" \ -a "username" \ -l "bug,high-priority"

handleIssueCommand中会校验urlnumbertitlesummary四项必填,缺失即报错退出;labels字符串经split(',').map(trim).filter(Boolean)清洗成数组,只有非空标签才会出现在卡片上。

四、GitHub Actions 自动化集成

该脚本的主要用途即是在 CI 工作流中实现"Issue 一创建即通知飞书"的自动化。.github/workflows/github-issue-tracker.yml 提供了完整的生产级示例:

- name: Install dependencies run: pnpm install - name: Send notification run: | pnpm tsx scripts/feishu-notify.ts issue \ -u "${{ github.event.issue.html_url }}" \ -n "${{ github.event.issue.number }}" \ -t "${{ github.event.issue.title }}" \ -a "${{ github.event.issue.user.login }}" \ -l "${{ join(github.event.issue.labels.*.name, ',') }}" \ -m "Issue summary content" env: FEISHU_WEBHOOK_URL: ${{ secrets.FEISHU_WEBHOOK_URL }} FEISHU_WEBHOOK_SECRET: ${{ secrets.FEISHU_WEBHOOK_SECRET }}

4.1 静默期延迟通知机制

该工作流还实现了"北京时间 00:00–08:30 静默期延迟通知"的工程细节,值得借鉴:

  • process-new-issuejob 监听issues: [opened]事件,先用TZ='Asia/Shanghai'计算北京当前时间;
  • 若处于静默期,则为 Issue 打上pending-feishu-notification标签,暂不发送通知;
  • process-pending-issuesjob 由schedule(每天 00:30 UTC,即北京时间 08:30)触发,通过gh api拉取带该标签的 Issue 列表,逐个调用feishu-notify.ts issue补发通知,成功后用gh api -X DELETE移除标签,并在多个 Issue 之间间隔 2–3 秒避免 API 限流。

4.2 与 Claude Code Agent 的组合

值得注意的细节是:工作流中飞书通知并非由 YAML 直接拼接参数发送,而是通过anthropics/claude-code-action@v1让 Claude Code Agent 读取 Issue 正文、用简体中文生成 2–3 句摘要后,再调用pnpm tsx scripts/feishu-notify.ts issue发送(claude_args中通过--allowed-tools白名单了该 CLI 的调用权限)。这体现了issue命令"摘要内容由上层逻辑生成"的设计意图——-m参数只负责承载已经处理好的文本,命令本身保持职责单一。

五、飞书卡片消息格式

issue命令发送的交互式卡片结构(由createIssueCard生成)如下:

  • Header 标题#<issue_number> - <issue_title>,颜色模板固定为blue
  • 作者行**Author:** <author>,使用lark_md标签渲染;
  • 标签行**Labels:** label1, label2(仅在存在标签时出现);
  • 摘要区:以hr分隔线隔开的**Summary:**\n<summary>
  • 操作按钮action元素内的primary按钮"View Issue",url指向 Issue 页面。

send命令的卡片则更简单(createSimpleCard):仅包含一个lark_md正文元素与一个指定颜色模板的 header,默认颜色为turquoise

5.1 底层消息载荷

两种卡片最终都由sendToFeishu统一打包成飞书 Webhook 期望的载荷结构(FeishuPayload):

{ timestamp: string // 当前 Unix 秒级时间戳 sign: string // HMAC-SHA256 签名 msg_type: 'interactive', card: FeishuCard // 卡片内容 }

请求通过 Node.js 原生https.requestPOST方式发送到FEISHU_WEBHOOK_URL(解析hostnamepathname + search),Content-Typeapplication/json。响应为 2xx 时打印飞书返回的 JSON 并成功 resolve,否则抛出Feishu API error: <statusCode> - <data>错误。

5.2 HMAC-SHA256 签名原理

签名实现位于generateSignature

const stringToSign = `${timestamp}\n${secret}` const hmac = crypto.createHmac('sha256', stringToSign) return hmac.digest('base64')

即:以timestamp + '\n' + secret作为 HMAC-SHA256 的密钥,对空内容求摘要后取 Base64。这正是飞书官方"签名校验"的算法约定(时间戳必须与请求体中的timestamp字段一致,飞书端用同一密钥复算比对)。在飞书群设置中开启安全设置 → 签名校验后即可获得secret

六、配置飞书 Webhook

  1. 进入目标飞书群 → 设置 → 群机器人 → 添加机器人 → 选择"自定义机器人";
  2. 记录生成的 Webhook 地址,并在"安全设置"中开启签名校验,复制签名密钥;
  3. 将两者配置为 GitHub 仓库的 Secrets(Settings → Secrets and variables → Actions):
    • FEISHU_WEBHOOK_URL:Webhook 地址
    • FEISHU_WEBHOOK_SECRET:签名密钥

本地调试时也可以直接以环境变量前缀方式运行:

FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/xxx" \ FEISHU_WEBHOOK_SECRET="your-secret" \ pnpm tsx scripts/feishu-notify.ts send -t "Test" -d "Hello Feishu"

七、错误处理行为

脚本在以下场景会以非零退出码结束(便于 CI 感知失败):

  • 缺失必需环境变量(FEISHU_WEBHOOK_URLFEISHU_WEBHOOK_SECRET),由getCredentials()检测并process.exit(1)
  • 缺失必需命令选项(issue缺少--url/--number/--title/--summarysend缺少--title/--description),由commanderrequiredOptionhandleIssueCommand的显式校验拦截;
  • send传入非法颜色,由 zod 枚举校验拦截并列出合法值;
  • 飞书 API 返回非 2xx 状态码,抛Feishu API error
  • 网络请求失败(DNS、连接被拒、超时等),req.on('error')将错误透传给命令处理函数,统一打印Error: <message>后退出。

两个子命令的action回调都包在try/catch中,因此任何异步错误都会转换为清晰的错误输出与退出码 1,不会出现静默失败。

八、扩展新的通知命令

CLI 通过program.command()注册子命令,扩展新通知类型只需四步(以源码结构为参照):

  1. 定义命令选项接口:仿照IssueOptions/SendOptions声明选项类型;
  2. 编写卡片构建函数:仿照createIssueCard/createSimpleCard,返回符合FeishuCard类型的卡片(elements数组 +header),元素类型可为div(lark_md 文本)、hr(分隔线)、action(按钮)三种,见FeishuCardElement联合类型;
  3. 添加命令处理器:仿照handleIssueCommand,先getCredentials()校验环境变量,再组装卡片并调用sendToFeishu
  4. 注册命令:在program.parse()之前调用program.command('your-command').requiredOption(...).action(...)注册。

由于sendToFeishugenerateSignaturegetCredentials均为通用函数,新命令可零成本复用签名、发送与鉴权逻辑,这也是该脚本"以子命令为扩展单元"的架构收益。

九、总结

scripts/feishu-notify.ts是一个小而完整的工程化示例:Commander 子命令结构、zod 运行时校验、HMAC-SHA256 安全签名、原生 HTTPS 请求、环境变量凭据管理,以及 GitHub Actions 中的静默期调度与 Agent 协作——这些设计使其既能作为 Cherry Studio 仓库的 CI 通知组件,也能被其他项目直接借鉴或复刻。更多细节可对照源码 scripts/feishu-notify.ts 与工作流 .github/workflows/github-issue-tracker.yml 查阅,本文档的原始出处为 docs/contrib/feishu-notify.md。

【免费下载链接】cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 8:38:14

BrewUI:给Homebrew套上一层图形界面,让macOS包管理不再劝退

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 8:37:26

在 Ray Tune 中使用 BayesOptSearch 进行贝叶斯超参数优化

在 Ray Tune 中使用 BayesOptSearch 进行贝叶斯超参数优化 【免费下载链接】ray Ray is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads. 项目地址: https://gitcode.com/gh_mirrors/ra/ray …

作者头像 李华
网站建设 2026/9/20 8:35:32

基于ResNet50的单图人脸重建:ModelScope实战与优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 8:34:08

AI辅助教材编写:低查重率与一键生成技术解析

1. 项目背景与核心价值去年我在参与高校教材修订项目时&#xff0c;发现一个普遍痛点&#xff1a;教师团队花费大量时间在内容查重和格式调整上&#xff0c;真正用于教学设计的时间不足30%。这促使我开始探索如何用AI技术优化教材编写流程。经过半年多的实测验证&#xff0c;这…

作者头像 李华
网站建设 2026/9/20 8:31:14

平板电脑检测报告PDF结构化解析实战指南

简介&#xff1a;本资源是一份完整的平板电脑专业检测报告&#xff0c;面向电子产品质量工程师、硬件测试人员及智能终端研发从业者&#xff0c;用于指导日常产线检验、来料验收或第三方合规性评估。报告系统覆盖结构检测&#xff08;外观工艺、接口牢固度、散热与人机工学&…

作者头像 李华