把飞书变成AI遥控器:WorkBuddy与Codex教程

先看懂三条链路,再开始配置

你可能常常看到有人直接在飞书里下指令,让电脑上的 WorkBuddy 或 Codex 自动处理任务,却不知道这套流程究竟是怎么搭起来的。这篇教程会从创建飞书应用开始,带你逐步完成权限配置、消息连接和应用发布,实际跑通飞书与 WorkBuddy 的双向对话和定时推送,同时讲清 Codex 通过独立应用和本地桥接接入飞书的完整路径。

本文会完整实操 WorkBuddy 双向对话和定时推送;Codex 部分只讲清独立接入路径并完成本机安全验证,飞书端桥接开发不在本篇实操范围。

1. 先看懂三条链路,准备账号与安全边界

开始配置之前,先把三条消息路径分开。它们都以飞书为入口或出口,但接收消息、执行任务和回传结果的方式并不一样。分清每条路径使用的应用和机器人,后面配置权限、事件和凭证时才不会混淆。

人在外面发出任务,办公室电脑继续执行并返回结果

即时对话:用飞书向 WorkBuddy 发任务

即时对话是本文的主路径:

手机飞书 → 企业自建应用机器人 → WebSocket 长连接 → WorkBuddy → 电脑执行 → 飞书回复

你在手机飞书中把任务发给企业自建应用机器人。WebSocket 长连接让电脑上的 WorkBuddy 持续接收飞书消息;WorkBuddy 收到任务后在电脑上执行,再通过机器人把结果回复到飞书。这条路径负责一问一答的双向消息,也是后面从创建应用到完成首次对话的配置主线。

定时推送:把自动化结果主动送到飞书

定时推送使用一条独立的补充路径:

WorkBuddy 自动化 → 本地发送脚本 → 飞书群自定义机器人 → 手机收到结果

WorkBuddy 自动化按设定运行后,由电脑上的本地发送脚本调用飞书群自定义机器人的 Webhook,将结果发到测试群。Webhook 是群机器人接收推送的专用地址。这条路径只负责把自动化结果送到飞书,不是即时对话机器人接通后自动附带的能力。

Codex:通过独立桥接接收和回复消息

Codex 使用第三条进阶路径:

飞书负责发起,本地桥接负责判断,Codex 只执行被允许的任务

独立飞书应用 → 本地受控桥接 → codex exec → 飞书回复

独立飞书应用接收消息后,本地受控桥接先检查发送者、任务范围和运行权限,再把允许执行的任务交给 codex exec,最后将结果回复到飞书。WorkBuddy 在设置中提供“飞书集成”配置,Codex 不能直接沿用这套接入方式,因此需要单独的飞书应用和本地桥接程序。

这三条路径不能合并成同一个入口。即时对话依赖企业自建应用机器人接收消息,定时推送依赖群自定义机器人向群里发送结果,两者的消息方向和用途不同。WorkBuddy 与 Codex 也不能共享同一个飞书应用:同一应用连接多个长连接客户端时,飞书会随机分发事件,并不会把每条消息同时发送给所有客户端。混用后,一条原本发给 WorkBuddy 的任务可能被 Codex 桥接收到,反之亦然。

开始前准备好这些条件

你需要一个能够进入飞书开放平台的飞书账号,以及一台已经安装并能运行 WorkBuddy 的电脑。账号应当具备创建企业自建应用、配置权限和发布应用的权限;如果所在企业要求管理员审批,发布时还需要等待管理员通过。

任务执行期间,电脑必须保持开机、联网,并避免进入深度睡眠。WorkBuddy 退出只会中断 WorkBuddy 即时对话和自动化任务。电脑睡眠或网络中断会影响所有依赖本机运行的链路。Codex 桥接尚待搭建,未来运行时也需要电脑保持唤醒和联网。

先划清远程执行的安全边界

应用密钥(App Secret)、Webhook 地址等敏感信息只保存在自己的设备上,例如写入不对外分享的私有配置文件;不要把它们放进公开文档、聊天记录或截图。后续首次连通时,先发送只要求返回固定文字的低风险任务,不要一开始就让 AI 读取、修改或删除文件。

只允许远程任务访问明确指定的目录,并只授予完成任务所需的操作权限。只有的确 需要写入文件时才开放写入权限,不把整个电脑或含有私人资料的目录交给远程任务;Codex 桥接也应检查发送者,并为任务设置受控工作目录、最小权限和超时限制。

完成检查

继续下一步之前,请确认:你能区分 WorkBuddy 即时对话、定时推送和 Codex 桥接三条路径;WorkBuddy 与 Codex 将分别使用独立的飞书应用;飞书账号具备相应的创建与发布权限;电脑可以在测试期间保持开机联网;所有凭证都不会泄露,远程操作也只会在明确允许的目录内进行。

2. 在飞书开放平台创建 WorkBuddy 应用

这一部分先创建一个企业自建应用,并为它添加机器人能力。完成后,你会得到一个可以继续配置的飞书应用;权限、事件订阅和 WorkBuddy 接入将在后面的步骤中处理。事件订阅是飞书把收到的新消息通知给应用的机制。

1. 从开发者后台打开创建入口

从飞书开发者后台进入企业自建应用创建入口

打开飞书开放平台并进入开发者后台。在首页找到“创建企业自建应用”,单击进入创建表单。

如果首页显示了多个已有应用,先确认自己仍在开发者后台的应用列表页,再找创建入口,不要进入其他应用的详情页修改设置。

2. 填写应用信息并创建

填写应用名称、描述与图标后创建应用

在创建表单中填写应用名称和描述,再按页面提供的方式选择或上传图标。名称应能让你在飞书中辨认出它的用途,例如“远程任务助手”;描述可以写成“接收飞书任务并交给 WorkBuddy 处理”。应用名称、描述和图标都可能在应用页面中显示。填写名称和描述时,不要使用真实姓名、手机号、公司内部项目名等个人或业务敏感信息;选择或上传图标时,也不要使用含有个人头像、内部标识等可识别敏感内容的图片。

确认信息无误后,单击表单中的创建按钮。系统跳转到新应用的详情页,并显示刚才填写的应用信息,就说明企业自建应用已经创建成功。

3. 添加机器人能力

机器人能力启用后才能继续配置消息权限与事件

在应用详情页打开“应用能力”,再进入“添加应用能力”。找到“机器人”卡片,单击“+添加”,按页面提示完成机器人能力的添加。

完成后,“应用能力”页面中应当能看到机器人,并可以继续进入它的配置页面。这里先确认机器人能力已经添加,不要提前配置权限、事件或其他扩展能力。

完成检查

你目前应当位于新应用的详情页,页面显示正确的应用名称、描述和图标;“应用能力”中可以看到已经添加或启用的机器人。满足这两个条件后,再继续配置消息权限。

3. 只开需要的权限,找到并保护应用凭证

机器人已经添加,但还不能直接收发消息。接下来先开通机器人单聊所需的两项核心权限;群聊、文档、日历等功能对应的权限暂不增加,的确 需要时再逐项开通。

1. 开通单聊所需的两项核心权限

在权限管理中按权限名称和代码逐项开通

在应用详情页左侧打开“开发配置”,进入“权限管理”。在权限列表中依次搜索下面两项权限,并开通对应的应用身份权限:

  • im:message.p2p_msg:readonly:读取用户发给机器人的单聊消息。
  • im:message:send_as_bot:以应用机器人身份发送消息。

选择权限时,同时核对页面显示的权限名称和代码,避免只凭相近名称判断。开通后,返回“权限管理”页面;两项权限都出目前“已开通”列表中,即可确认当前应用已经开通单聊收发消息所需的权限。这里看到的是当前应用的权限配置,之后仍需发布应用版本,权限才会正式生效。

2. 需要在群聊中 @ 机器人时再加权限

如果你只准备与机器人单聊,不需要开通群聊权限。只有的确 要在群聊中通过 @ 机器人发送任务时,再搜索并开通:

  • im:message.group_at_msg:readonly:读取群聊中 @ 机器人的消息。

开通后,这项权限同样应出目前“权限管理”的已开通列表中。如果你暂时不用群聊,可以跳过这一步,不要为了“后来可能用到”提前扩大授权范围。

3. 不要把完整权限清单当成简单对话的必选项

WorkBuddy 官方指南中的完整权限清单覆盖了更广的能力,例如读写飞书文档和多维表格,以及查看或操作日历和任务。部分扩展能力还会涉及创建、修改或删除内容。如果只做机器人单聊,不需要把这些权限全部开通。

本教程先从两项核心消息权限开始。只有的确 要让 WorkBuddy 操作文档、多维表格、日历或任务时,才按照实际功能逐类核对用途和风险,缺哪一项再增加哪一项。

4. 找到 App ID 和 App Secret

App ID 与 App Secret 位于凭证与基础信息页面,具体值必须遮挡

在应用详情页左侧打开“基础信息”,进入“凭证与基础信息”。在页面中找到 App ID 和 App Secret:App ID 用于标识这个应用,App Secret 是验证应用身份的应用密钥。

这里只需确认两个字段的位置,等后面配置 WorkBuddy 时再复制需要的内容。不要在教程、截图或聊天中展示任何具体值,也不要把 App Secret 复制到公开文档或提交到代码仓库。

App Secret 只应填入 WorkBuddy 的飞书配置,并保存在自己的设备上。如果它意外出目前公开截图、文档、聊天记录或代码仓库中,应立即回到凭证页面重置密钥;重置后,旧密钥将不能继续使用,相关本地配置也需要改用新密钥。

完成检查

“权限管理”中已经能看到
im:message.p2p_msg:readonly 和 im:message:send_as_bot;只有需要群聊 @ 时,才额外出现
im:message.group_at_msg:readonly。“凭证与基础信息”页面中可以找到 App ID 和 App Secret,但具体值没有出目前截图、文档、聊天记录或代码仓库中。满足这些条件后,再继续把应用接入 WorkBuddy。

4. 在 WorkBuddy 中注册飞书通道

飞书应用和核心消息权限准备好后,接下来把这个应用注册到 WorkBuddy。本文使用 WorkBuddy 5.3.8 的 WebSocket 长连接,不需要准备公网服务器或回调地址。

1. 打开“飞书集成”配置

从 WorkBuddy 设置进入助理设置与飞书集成

打开 WorkBuddy,进入左侧的“助理”。单击助理标题旁的齿轮,打开“助理设置”,再找到“飞书集成”,进入配置页面。

如果没有看到“飞书集成”,先确认当前打开的是助理设置,而不是某个任务或自动化的设置页面。不同版本的入口位置可能变化,本文实测路径以 WorkBuddy 5.3.8 为准。

2. 选择 WebSocket 长连接

WebSocket 长连接只需填写 App ID 与 App Secret 后注册

在飞书通道的连接方式中,选择“WebSocket 长连接”。它的作用是让本机上的 WorkBuddy 与飞书保持连接,持续接收飞书发来的消息。

页面还会提供 URL 回调方式。它适合已经有公网回调地址、能够接收飞书请求的场景;本文面向没有公网服务器的本机接入,不使用这条路径。

3. 输入应用凭证并注册

注册完成后,飞书通道应显示已连接

WorkBuddy 本地助理顶部显示飞书已连接

从飞书应用的“凭证与基础信息”页面复制 App ID 和 App Secret,分别填入 WorkBuddy 配置页面中对应的输入框。确认没有多复制空格或遗漏字符后,单击“注册”。

输入凭证时不要截图或录屏,也不要把内容临时粘贴到聊天窗口、公开文档或代码仓库。App Secret 是应用密钥,只应在飞书凭证页面与 WorkBuddy 配置之间传递,不要向任何人展示具体值。

提交后,WorkBuddy 会尝试建立连接。界面显示“已连接”,就说明飞书通道已经注册成功;如果仍显示未连接,先重新核对 App ID、App Secret、电脑网络和 WorkBuddy 的运行状态。此处的“已连接”只表明 WorkBuddy 已经建立飞书通道,不代表机器人已经完成全部消息接收配置。

完成检查

“助理设置 → 飞书集成”中已经选择 WebSocket 长连接,App ID 和 App Secret 已填入对应字段,页面状态显示“已连接”,并且凭证没有出目前截图、录屏、聊天、公开文档或代码仓库中。满足这些条件后,WorkBuddy 端的飞书通道就已注册完成。

5. 订阅接收消息事件并发布应用

WorkBuddy 显示“已连接”后,还需要告知飞书:机器人收到新消息时,应当把这条消息交给已连接的 WorkBuddy。完成事件订阅并发布应用后,前面配置的机器人能力、权限和消息事件才会在飞书中正式生效。

1. 把事件订阅方式设为长连接

事件订阅使用长连接,不需要公网回调地址

回到飞书开放平台,进入刚才创建的应用详情页。在左侧“开发配置”中打开“事件与回调”,进入事件配置区域。

找到“订阅方式”,选择“长连接”,再按页面提示保存。这里的长连接与 WorkBuddy 中选择的 WebSocket 长连接对应:飞书通过这条持续连接把事件发送给本机上的 WorkBuddy,不需要填写公网回调地址。

完成检查

重新查看事件配置,订阅方式仍显示为“长连接”,说明选择已经保存。如果页面提示尚未建立连接,先确认 WorkBuddy 保持运行,并且“飞书集成”仍显示“已连接”。

2. 添加接收消息事件

事件列表中应出现接收消息事件

在同一页面的事件配置中,单击“添加事件”。搜索并添加下面这项事件:

  • im.message.receive_v1:接收消息。它表明机器人收到消息时,飞书会发出一条事件通知,并通过长连接交给已经连接的 WorkBuddy。

添加后,返回事件列表检查事件代码,不要只凭中文名称判断。普通文字对话只需要先订阅接收消息事件;卡片回调用于处理消息卡片中的交互,只有的确 要使用 WorkBuddy 的卡片功能时才按需配置,不是普通文字对话的必选项。

完成检查

事件列表中已经出现 im.message.receive_v1,并且订阅方式仍为长连接,就说明接收消息事件已经加入当前应用配置。

3. 创建版本并设置可用范围

创建新版本并核对当前发布状态

版本状态显示已发布后,机器人配置才正式生效

打开左侧“应用发布”,进入“版本管理与发布”。单击“创建版本”,在版本配置页设置应用的可用范围,确保当前用于测试的飞书账号包含在范围内。可用范围没有包含当前账号时,即使应用已经发布,也可能无法在飞书中找到机器人。

确认版本信息和可用范围后,提交发布。应用能力、权限或事件发生变化时,都需要通过新版本发布后才能正式生效。

提交后,在版本列表中查看状态。如果企业允许自建应用免审,版本可能直接进入已发布状态;如果企业规则要求管理员审核,页面会显示相应的审核或发布状态,需要等待管理员通过。不要把“已提交”当成“已发布”,也不要假定审批会立即完成。

完成检查

“版本管理与发布”中可以看到刚创建的版本和当前状态;可用范围包含测试账号;版本最终显示为“已发布”。如果页面仍显示审核中或等待审批,先等待管理员完成审核,状态变为“已发布”后再继续。

6. 在飞书里完成第一轮真实对话

应用已经发布,并且当前账号处于可用范围内,目前可以验证整条即时对话链路。第一次测试只要求返回一段固定文字,不让 AI 读取或改动文件,这样既容易判断是否成功,也能把风险降到最低。

1. 在飞书中打开机器人单聊

在飞书里打开 WorkBuddy 助理并发送低风险测试指令

打开飞书客户端,搜索刚才创建的机器人或应用名称。在搜索结果中找到对应应用,打开机器人单聊。

进入会话后,先确认页面中有消息输入框并且可以发送消息。如果搜不到机器人,先跳到第 9 部分第 1 项排查;如果会话中没有输入框,先看第 9 部分第 2 项。恢复正常并看到输入框后,再回到这里继续。

2. 发送一条低风险测试任务

在机器人单聊中发送:

请只回复 WORKBUDDY_FEISHU_OK,不要读取、创建、修改或删除任何文件

这条任务只要求返回固定文字,不需要访问本机文件。发送后先保留飞书会话,同时转到电脑端查看 WorkBuddy。

3. 确认 WorkBuddy 收到并执行任务

WorkBuddy 收到任务并将结果返回同一轮飞书会话

在电脑端查看 WorkBuddy 中是否出现刚才从飞书发来的任务。看到对应任务后,等待它执行完成;任务内容应与飞书中发送的测试语句一致。

再回到飞书会话,确认机器人回复:

WORKBUDDY_FEISHU_OK

只有 WorkBuddy 收到了任务,并且指定回复重新出目前飞书中,才说明“手机发出任务—电脑接收并执行—飞书收到结果”的双向消息链路已经跑通。

可选:在群聊中 @ 机器人

如果之前已经开通
im:message.group_at_msg:readonly,并发布了包含该权限的新版本,可以把机器人加入群聊,再通过 @ 机器人发送任务。没有群聊需求时继续使用单聊即可,不必为了测试额外扩大权限范围。

完成这次验证后,人在外面也可以用手机飞书交代整理资料、检查内容等受控任务,由保持在线的电脑运行 WorkBuddy,再把结果回复到飞书。实际使用时仍要限定允许访问的目录和操作权限,不要把低风险测试直接扩大成不受限制的远程操作。

完成检查

机器人单聊中可以正常发送消息;电脑端 WorkBuddy 收到了内容一致的测试任务;飞书中收到了指定回复 WORKBUDDY_FEISHU_OK。这三个结果同时出现,才代表第一轮真实双向对话已经完成。

7. 让定时任务主动把结果送到飞书

前面配置的 WorkBuddy 飞书集成负责双向对话,但接通它并不等于自动获得定时结果推送。WorkBuddy 官方自动化功能的结果推送列表里目前没有飞书选项,因此这里使用一条独立的补充通道:WorkBuddy 自动化完成任务后调用本地脚本,再由飞书群自定义机器人把结果送到手机。不要把这条通道误认为 WorkBuddy 原生支持飞书自动化通知。

下面这套方案已经实际跑通过,但换到你的电脑后,仍要先测试脚本,再新建一个一次性自动化完成现场验证。

1. 创建只供测试的飞书群和自定义机器人

在测试群设置中进入群机器人

Webhook 位于自定义机器人详情页,地址必须完整遮挡

在飞书中创建一个只供自己测试的群聊。先不要邀请同事,也不要使用已有工作群,以免配置过程中的测试消息发给其他人。

打开测试群的设置,进入“群机器人”,选择添加机器人,再添加“自定义机器人”。完成创建后,飞书会提供一个 Webhook。Webhook 是群机器人接收推送的专用地址;脚本把文字发送到这个地址后,机器人就会把内容发到当前群聊。

复制 Webhook 后,不要把它粘贴到截图、录屏、聊天、公开文档或代码仓库中。后面只把它保存到本机的私有配置文件;Webhook 一旦泄露,其他人可能利用它向群里发送消息。

2. 查出账号短名称并确认 Node.js 可用

打开 macOS 的“终端”,先运行:

whoami

终端返回的文字就是当前 macOS 账号短名称,不是你的姓名,也不是 Apple 账户名。记下这个结果;后面示例路径中的 yourname 都要替换成它。

接着运行:

node --version

node 是运行本地发送脚本的程序。这份脚本需要 Node.js 20 或更高版本。运行 node –version 后,版本号开头的主版本数字应当不小于 20,例如 v20、v22 或 v24。如果出现 command not found,或者主版本低于 20,请从 [Node.js 官方下载页](
https://nodejs.org/en/download) 安装 macOS 的长期支持版(LTS);安装完成后关闭并重新打开终端,再运行一次 node –version,确认主版本已经达到 20 或更高。

3. 用终端创建专用目录和空文件

“绝对路径”是从 /Users/你的账号短名称/ 开始写出的完整位置。下面假设专用项目放在
/Users/yourname/WorkBuddy-Feishu-Push。先把命令中的 yourname 全部替换成 whoami 返回的结果,再逐行运行:

mkdir -p "/Users/yourname/WorkBuddy-Feishu-Push/.work/private"
mkdir -p "/Users/yourname/WorkBuddy-Feishu-Push/.work/result"
mkdir -p "/Users/yourname/WorkBuddy-Feishu-Push/scripts"
touch "/Users/yourname/WorkBuddy-Feishu-Push/.work/private/feishu-webhook.env"
touch "/Users/yourname/WorkBuddy-Feishu-Push/.work/result/test-message.txt"
touch "/Users/yourname/WorkBuddy-Feishu-Push/scripts/feishu_push.mjs"
chmod 700 "/Users/yourname/WorkBuddy-Feishu-Push/.work/private"
chmod 600 "/Users/yourname/WorkBuddy-Feishu-Push/.work/private/feishu-webhook.env"

其中,chmod 700 把私有目录限制为只有当前 macOS 账号可以进入和读写,chmod 600 把 Webhook 配置文件限制为只有当前账号可以读写。

这些命令会直接创建以点号开头的隐藏目录和文件,不需要在访达中手动寻找。最终结构应当是:

/Users/yourname/WorkBuddy-Feishu-Push/
├── .work/
│   ├── private/
│   │   └── feishu-webhook.env
│   └── result/
│       └── test-message.txt
└── scripts/
    └── feishu_push.mjs

Git 是保存项目版本记录的工具。如果你从未主动配置或使用 Git,直接跳过本段。只有已经用 Git 管理这个目录时,才需要在项目根目录的 .gitignore 文件中单独加入一行 .work/private/,防止私有配置被提交。可以先运行下面两条命令创建并打开该文件,再用文本编辑器加入这一行:

touch "/Users/yourname/WorkBuddy-Feishu-Push/.gitignore"
open -e "/Users/yourname/WorkBuddy-Feishu-Push/.gitignore"

4. 用文本编辑器保存私有 Webhook

不要用带有真实 Webhook 的 echo 命令写文件,否则地址可能留在终端历史中。运行下面的命令,用 macOS 文本编辑器打开已经创建好的私有配置文件:

open -e "/Users/yourname/WorkBuddy-Feishu-Push/.work/private/feishu-webhook.env"

在文件中只填写下面一行:

FEISHU_WEBHOOK_URL=<你的 Webhook>

把 <你的 Webhook> 整体替换为刚才复制的真实地址,等号两边不要添加空格,然后保存并关闭文件。编辑时不要截图或录屏,也不要把真实地址复制到终端命令、WorkBuddy 任务说明或其他公开位置。文件已经预先以 .env 结尾,保存后确认名称没有变成 feishu-webhook.env.txt。

脚本会固定读取这份私有文件。后来运行时,不需要每次在终端重新填写 Webhook。

5. 保存本地发送脚本

运行下面的命令,用文本编辑器打开脚本文件:

open -e "/Users/yourname/WorkBuddy-Feishu-Push/scripts/feishu_push.mjs"

把下面的代码完整粘贴进去,保存并关闭文件。它负责读取私有配置和指定的结果文件,按飞书群机器人要求发送文字,并在成功后输出“飞书推送成功”。代码中不包含真实 Webhook。

#!/usr/bin/env node

import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import path from "node:path";

const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const projectDir = path.dirname(scriptDir);
const envPath = path.join(projectDir, ".work", "private", "feishu-webhook.env");

function parseArgs(argv) {
  const result = { text: "", file: "" };
  for (let index = 0; index < argv.length; index += 1) {
    if (argv[index] === "--text") result.text = argv[index + 1] ?? "";
    if (argv[index] === "--file") result.file = argv[index + 1] ?? "";
  }
  return result;
}

function parseEnv(source) {
  const values = {};
  for (const line of source.split(/
?
/)) {
    const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
    if (match) values[match[1]] = match[2];
  }
  return values;
}

const args = parseArgs(process.argv.slice(2));
const env = parseEnv(await readFile(envPath, "utf8"));
const webhook = env.FEISHU_WEBHOOK_URL;

if (!webhook) throw new Error("未找到 FEISHU_WEBHOOK_URL");

let text = args.text;
if (args.file) text = await readFile(path.resolve(args.file), "utf8");
if (!text.trim()) throw new Error("请使用 --text 或 --file 提供推送内容");
if (!text.includes("[WorkBuddy]")) text = `[WorkBuddy] ${text}`;

async function sendOnce() {
  const response = await fetch(webhook, {
    method: "POST",
    headers: { "content-type": "application/json; charset=utf-8" },
    body: JSON.stringify({ msg_type: "text", content: { text } }),
    signal: AbortSignal.timeout(15_000),
  });

  const payload = await response.json();
  if (!response.ok || payload.code !== 0) {
    throw new Error(`飞书返回错误:${payload.msg ?? response.status}`);
  }
}

let sent = false;
let lastError;

for (let attempt = 1; attempt <= 3; attempt += 1) {
  try {
    await sendOnce();
    console.log(`飞书推送成功(第 ${attempt} 次尝试)`);
    sent = true;
    break;
  } catch (error) {
    lastError = error;
    let reason = `其他错误:${error.message}`;
    if (error?.name === "TimeoutError") reason = "请求超时(15 秒)";
    else if (error instanceof TypeError) reason = `网络错误:${error.message}`;
    else if (error?.message?.startsWith("飞书返回错误")) reason = error.message;
    console.error(`第 ${attempt} 次发送失败:${reason}`);
  }
}

if (!sent) {
  throw new Error(`飞书推送失败:总共尝试 3 次。最后错误:${lastError?.message ?? "未知错误"}`);
}

脚本的每次网络请求最多等待 15 秒,总共最多尝试 3 次。每次失败都会在输出中记录“请求超时”“网络错误”或“飞书返回错误”;三次都失败后,脚本会停止并保留最后的错误。脚本通过自己的位置找到同一项目中的
.work/private/feishu-webhook.env,所以不要改变 scripts、.work/private 和配置文件之间的层级。保存后确认脚本文件名仍是 feishu_push.mjs,末尾没有多出 .txt。

6. 使用绝对路径单独测试脚本

先单独测试本地脚本是否能把消息送到飞书

先运行下面的命令,在测试结果文件中写入一条不含敏感信息的固定文字:

printf '%s
' 'WORKBUDDY_AUTOMATION_WEBHOOK_OK' > "/Users/yourname/WorkBuddy-Feishu-Push/.work/result/test-message.txt"

再使用脚本和结果文件的绝对路径运行:

node "/Users/yourname/WorkBuddy-Feishu-Push/scripts/feishu_push.mjs" --file "/Users/yourname/WorkBuddy-Feishu-Push/.work/result/test-message.txt"

两条命令中的 yourname 都要替换为 whoami 返回的结果。终端输出“飞书推送成功”后,再打开测试群;群里应当出现以 [WorkBuddy] 开头的测试消息。只有终端成功输出和飞书实际消息同时出现,才说明私有配置、脚本和 Webhook 已经连通。

7. 创建一次性 WorkBuddy 自动化

WorkBuddy 自动化页面提供定时任务与运行记录入口

逐项填写名称、工作空间、提示词、周期与执行时间

保持 WorkBuddy 运行,在左侧进入“自动化”,单击右上角的新建入口。任务名称可以填写“飞书定时推送测试”。在当前界面名为“工作空间”或“工作目录”的字段中,选择前面建立的
/Users/yourname/WorkBuddy-Feishu-Push 专用项目目录。执行方式选择一次性,并把执行时间设在几分钟后,方便现场观察。

把下面的模板填入任务说明。粘贴前,将其中三处 yourname 换成 whoami 返回的账号短名称;这里的替换只用于保证脚本路径和结果文件路径正确。工作空间或工作目录需要在 WorkBuddy 界面中单独选择。

请严格执行以下任务:

1. 生成一条少于 200 字、不含任何敏感信息的测试提醒。
2. 只把这条提醒保存到:
   /Users/yourname/WorkBuddy-Feishu-Push/.work/result/automation-result.txt
3. 保存成功后运行:
   node "/Users/yourname/WorkBuddy-Feishu-Push/scripts/feishu_push.mjs" --file "/Users/yourname/WorkBuddy-Feishu-Push/.work/result/automation-result.txt"
4. 看到“飞书推送成功”后结束任务。

权限边界:
- 任务只允许生成并写入结果文件:
  /Users/yourname/WorkBuddy-Feishu-Push/.work/result/automation-result.txt
- 任务只允许运行上面指定的 `node` 发送命令,不运行其他脚本或命令。
- 发送脚本会在内部读取 `.work/private/feishu-webhook.env`;任务本身不得打开、输出、复制或改写这个文件及其中的 Webhook。
- 除生成并写入结果文件、运行指定发送脚本外,不读取、创建、修改或删除其他文件。
- 发送脚本内部总共最多尝试 3 次;如果最终失败,立即停止,不要再次运行脚本,并在运行记录中保留超时、网络或飞书返回的错误。

不要把真实 Webhook 加进任务名称、任务说明或提示词。保存自动化后,不要退出 WorkBuddy,也不要让电脑断网。

关闭显示器和电脑进入睡眠不是一回事:显示器熄灭时,电脑仍可能保持运行;电脑睡眠后,本地自动化就无法继续执行。在测试完成前,保持笔记本打开并接通电源。你可以在“系统设置”的“电池”或“节能”页面中,临时启用显示器关闭时仍防止电脑自动睡眠的选项;不同 macOS 版本的文字可能略有差异。也可以另开一个终端窗口运行:

caffeinate

让这个终端窗口保持打开,Mac 就会临时保持唤醒。验证结束后在该窗口按 Control-C 停止,不要合上笔记本电脑。

8. 核对三项成功信号

自动化、关键词校验和本地发送脚本均已连通

飞书群收到实际每日提醒,定时推送闭环完成

到达设定时间后,在 WorkBuddy 的“运行记录”中找到这次一次性任务,确认任务显示完成,并查看脚本执行输出。随后打开飞书测试群,核对实际消息。

WorkBuddy 的完成记录证明一次性任务已经执行;脚本输出“飞书推送成功”说明发送成功;飞书群出现以 [WorkBuddy] 开头的消息,说明结果已经通过补充通道送达。三项同时满足,才算这条补充推送通道已经配置成功并通过验证。

完成检查

独立测试时,终端输出“飞书推送成功”,测试群收到固定消息;一次性自动化运行后,WorkBuddy 中出现完成记录和“飞书推送成功”的脚本输出;飞书测试群收到以 [WorkBuddy] 开头的自动化结果。另外,运行下面的命令核对本机访问权限:

ls -ld "/Users/yourname/WorkBuddy-Feishu-Push/.work/private" "/Users/yourname/WorkBuddy-Feishu-Push/.work/private/feishu-webhook.env"

私有目录权限应以 drwx—— 开头,Webhook 配置文件权限应以 -rw——- 开头,表明只有当前 macOS 账号可以访问。上述结果全部出现后,定时任务的补充推送通道才算真正跑通。

8. Codex 为什么需要另一条接入路径

前面使用的是 WorkBuddy 设置中的图形化飞书集成:填入应用凭证、选择长连接,就能让 WorkBuddy 接收飞书消息。长连接是一种让电脑持续等待并接收飞书消息的连接方式。Codex 的接法不同,它需要一个独立飞书应用,再由电脑上的本地受控桥接连接飞书与 codex exec。

这里的“桥接”可以理解为一个守门并转交任务的本地程序。它先接收飞书消息,确认消息来自允许的发送者、任务只涉及指定工作目录,再把符合条件的任务交给 Codex;Codex 执行结束后,桥接程序读取结果并回复到飞书。

完整路径是:

独立飞书应用 → 本地受控桥接 → codex exec → 飞书回复

WorkBuddy 与 Codex 不要共用飞书应用

WorkBuddy 和 Codex 都需要接收飞书发来的消息,但不能把两者连接到同一个飞书应用。同一应用同时连着两个接收程序时,飞书会把一条事件,也就是一条新消息通知,随机交给其中一个程序。它不会广播这条事件,也就是不会让两个程序同时收到。

如果共用应用,原本要交给 WorkBuddy 的任务可能被 Codex 桥接收到,反过来也一样。分别创建应用,才能让两条消息路径各自接收自己的任务,也便于分别设置允许发送消息的飞书账号名单、应用权限和可用范围。

本地桥接先把权限收紧

桥接程序不能收到什么就执行什么。至少要在调用 codex exec 前完成这些限制:

  • 只接受白名单中的飞书发送者,不处理陌生账号发来的任务。
  • 只允许 Codex 在指定的工作目录内执行任务,不把整个电脑交给远程消息控制。
  • 为 Codex 设置沙箱。沙箱是一组执行限制,用来约束任务可以访问和改动的内容;只做验证时使用 read-only,限制 Codex 任务写入文件。
  • 设置任务超时和回复长度上限。任务超过时间就停止并返回清楚的失败缘由;结果过长时先截断或整理,再回复飞书。

这些限制应由桥接程序统一执行,不能只依赖飞书消息中的文字提醒。

先在本机验证 codex exec

在连接飞书之前,先确认本机能够以只读方式调用 Codex。下面是本机实际验证使用的命令,其中“允许的工作目录”需要替换为你明确授权的绝对路径:

/Applications/ChatGPT.app/Contents/Resources/codex exec 
  --skip-git-repo-check 
  --sandbox read-only 
  --cd "允许的工作目录" 
  --output-last-message "/tmp/codex-last-message.txt" 
  "只回复 CODEX_BRIDGE_OK,不要读取、创建、修改或删除任何文件。"

–sandbox read-only 限制 Codex 任务本身,禁止它在允许的工作目录中写入文件;测试提示词又进一步要求任务不要读取或改动任何文件。–output-last-message 则由 Codex 命令行程序(CLI)在任务结束后,把最终回复写入命令中明确指定的临时结果文件。这个结果导出动作不会让 Codex 任务获得写入工作目录的权限。

首次实测没有加入 –skip-git-repo-check,由于所选目录不是 Git 仓库,命令因此停止。确认目录安全后加入这个参数,表明跳过 Git 仓库检查;它不会撤销只读沙箱。再次执行后,最终得到:

CODEX_BRIDGE_OK

这次运行中,实时连接失败后先进行了重试,随后改用普通网络请求继续,具体表现为 WebSocket 失败后回退到 HTTPS 并完成请求。桥接程序需要给这种重试留出时间,总超时不能设得过短;如果最终失败,应把“超时”“网络连接失败”或 Codex 返回的错误清楚回复给用户,不能让飞书会话一直没有结果。

这一步验证了什么

看到 CODEX_BRIDGE_OK,只能证明这次本机验证中,codex exec 可以在指定目录和只读限制下运行。它不代表飞书应用、本地桥接和 Codex 已经完成端到端连接。即使已经建好了专门给 Codex 使用的独立飞书应用,只要还没有完成端到端验证,就不能说它“已经接通”。

本文在这里讲清独立接入路径和本机安全验证,不展开第二套飞书后台配置。真正上线时,桥接程序还要接收飞书消息并核对发送者,避免同一条飞书消息多次触发同一项任务,为任务设置超时并限制回复长度,最后把结果回复到飞书。

完成检查

你已经能说清“独立飞书应用接收消息—本地受控桥接检查任务—codex exec 执行—结果回复飞书”的路径,并理解它不能与 WorkBuddy 共用同一个飞书应用;本机只读命令执行后得到 CODEX_BRIDGE_OK。完成检查只确认路径理解和本机命令可用,不表明飞书端已经接通。

9. 按现象排查,确认已经完成的部分与仍待搭建的部分

如果某一步没有出现对应的成功信号,不要从头反复重配。先按你看到的现象找到下面对应的一项,再按其中的步骤检查。排查时不要展示应用密钥(App Secret),也不要展示群自定义机器人接收推送所用的专用地址(Webhook);不要截图、粘贴或公开这两类敏感信息。

1. 飞书里搜不到机器人

  • 可能缘由: 应用还没有发布、仍在等待管理员审批、当前账号不在可用范围内,或者机器人能力没有添加成功。
  • 处理方法: 回到飞书开放平台,先看“版本管理与发布”中的状态,再核对可用范围是否包含当前账号,最后到“应用能力”中确认机器人已经添加。
  • 成功信号: 应用状态显示“已发布”,当前账号位于可用范围内,并且可以在飞书客户端搜索到机器人。

2. 机器人会话中没有输入框

  • 可能缘由: 应用尚未处于可用状态、当前账号不在可用范围内,或者打开了名称相近的其他机器人。
  • 处理方法: 核对应用发布状态和可用范围,再对照开放平台中的应用名称与图标,重新打开正确的机器人会话。
  • 成功信号: 正确的机器人单聊页面出现消息输入框,并且可以发送文字。

3. WorkBuddy 显示“未连接”

  • 可能缘由: App ID 或 App Secret 填写错误,飞书的连接方式未设为 WebSocket 长连接,电脑网络中断,或者 WorkBuddy 已退出。WebSocket 长连接是让飞书把新消息实时送到 WorkBuddy 的连接方式。
  • 处理方法: 打开“助理设置 → 飞书集成”,确认连接方式为 WebSocket 长连接;从飞书“凭证与基础信息”页面重新核对凭证,并确认电脑联网、WorkBuddy 保持运行。核对时不要截图或展示 App Secret。
  • 成功信号: WorkBuddy 的“飞书集成”状态重新显示“已连接”。

4. 飞书能发消息,但 WorkBuddy 没收到

  • 可能缘由: “接收消息”事件 im.message.receive_v1 没有加入事件列表,订阅方式没有保存为长连接,或者消息已经到达飞书,但对应的事件通知没有送到 WorkBuddy 当前保持的长连接。
  • 处理方法: 回到应用的“事件与回调”,确认订阅方式仍为长连接,事件列表中存在 im.message.receive_v1。随后到“运营监控 → 日志检索”查看刚才的测试消息:

– 如果日志中没有这条消息对应的事件,回到“事件与回调”重新检查事件订阅和长连接方式,再确认包含这些配置的应用版本已经发布、当前账号位于可用范围内。完成后发送一条新的测试消息。 – 如果日志中已有事件,但 WorkBuddy 没有出现任务,打开“助理设置 → 飞书集成”检查长连接状态,重新核对 App ID 和 App Secret,并重新注册连接。状态恢复为“已连接”后,再发送一条新的测试消息。

  • 成功信号: 飞书日志中可以找到新测试消息的事件记录,并且 WorkBuddy 收到了内容一致的任务。

5. WorkBuddy 已收到并执行,但飞书没有回复

  • 可能缘由: WorkBuddy 中的任务尚未真正完成,机器人缺少 im:message:send_as_bot 发送权限,包含该权限的应用版本尚未发布,或者回复消息时发生错误。
  • 处理方法: 先在 WorkBuddy 的任务详情中确认任务已经执行完成,并生成了预期回复。再到飞书开放平台的“权限管理”确认 im:message:send_as_bot 出目前“已开通”列表中;到“版本管理与发布”确认包含该权限的最新版本已经发布;最后到“运营监控 → 日志检索”查看机器人发送或回复消息时是否留下错误记录。如果刚补开权限,创建并发布新版本后,再发送一条新的低风险测试消息。
  • 成功信号: WorkBuddy 中的新测试任务显示完成,飞书机器人单聊收到指定回复 WORKBUDDY_FEISHU_OK。

6. 一次性自动化没有执行

  • 可能缘由: 电脑睡眠或断网、WorkBuddy 已退出、执行时间设置错误、“工作空间”选错,或者任务说明中的绝对路径不正确。
  • 处理方法: 确认电脑保持唤醒并联网,WorkBuddy 持续运行;重新核对一次性执行时间。WorkBuddy 5.3.8 中应检查“工作空间”字段,部分版本可能显示为“工作目录”,两者指的是同一处设置;这里应选择第 7 部分建立的、存放发送脚本的 /Users/yourname/WorkBuddy-Feishu-Push 专用目录。最后核对任务说明中脚本和结果文件的绝对路径。
  • 成功信号: 到达设定时间后,“运行记录”中出现对应任务,并显示已经开始或执行完成。

7. WorkBuddy 显示成功,但飞书群没有消息

  • 可能缘由: Node.js 版本低于 20,或者终端出现 fetch is not defined;本地发送脚本没有真正发送成功;.work/private/feishu-webhook.env 中缺少 FEISHU_WEBHOOK_URL 或地址已经失效;群自定义机器人被停用;或者发送时网络中断。
  • 处理方法: 先运行 node –version。如果主版本低于 20,或者脚本报错 fetch is not defined,按第 7 部分的说明升级到 Node.js 20 或更高版本。然后回到第 7 部分“使用绝对路径单独测试脚本”,重新运行 scripts/feishu_push.mjs。命令中的 –file 后面填写测试结果文件的绝对路径,例如:

“bash node “/Users/yourname/WorkBuddy-Feishu-Push/scripts/feishu_push.mjs” –file “/Users/yourname/WorkBuddy-Feishu-Push/.work/result/test-message.txt” “

把 yourname 替换为 whoami 返回的账号短名称。随后依次检查私有配置文件名是否正确、文件中是否使用变量名 FEISHU_WEBHOOK_URL、群自定义机器人是否仍启用,以及电脑网络是否正常。真实 Webhook 只能在本机私有文件中核对,绝不能粘贴到聊天、截图、公开文档或代码仓库。

  • 成功信号: 独立脚本测试输出“飞书推送成功”,测试群收到以 [WorkBuddy] 开头的消息;再次运行自动化后,群里也收到对应结果。

8. 本机 codex exec 验证失败

  • 可能缘由: 命令中的工作目录不存在或当前账号无权访问,非 Git 目录缺少 –skip-git-repo-check,只读模式与测试任务的写入要求冲突,或者网络连接仍在重试。
  • 处理方法: 回到第 8 部分“先在本机验证 codex exec”,重新运行只回复 CODEX_BRIDGE_OK 的完整只读验证命令,并按看到的情况逐项处理:

– –cd 应指向一个的确 存在、由你本人选择并有权访问的测试目录。 – Git 仓库是使用 Git 保存版本记录的项目目录。如果命令提示当前目录不是 Git 仓库,确认目录安全后加入 –skip-git-repo-check。 – –sandbox read-only 是只读限制。如果测试任务要求创建或修改文件,应撤销写入要求,而不是把只读验证改成不受限制的执行。 – 实时连接失败后,程序可能重试并改用普通网络请求继续,因此要给本机命令留出重试时间。最终仍失败时,以终端显示的具体错误为准。

  • 成功信号: 本机命令在设定时间内返回 CODEX_BRIDGE_OK。这个结果只证明本机 Codex 调用链可用,不代表飞书端桥接已经完成。

9. 未来接通后,飞书桥接出现超时

  • 适用时机: 这一项不是当前已经接通环境的故障排查。只有独立飞书应用和本地受控桥接完成端到端搭建后,才检查桥接是否能按时回复。
  • 需要预先实现: 桥接程序应为实时连接重试和改用普通网络请求留出时间,同时设置明确的总超时。任务成功时把结果回复飞书;超过总时限或调用失败时,把“超时”“网络连接失败”或 Codex 返回的错误清楚回复飞书。
  • 届时成功信号: 飞书提交的每项任务都能在时限内收到执行结果或明确错误,不会一直停留在等待状态。这个信号仍待未来桥接完成后验证。

10. App Secret 或 Webhook 已经泄露

  • 可能缘由: 敏感值出目前截图、录屏、聊天、公开文档、代码仓库或终端历史中。
  • 处理方法: 立即停止使用泄露的值。App Secret 泄露时,到飞书应用的凭证页面重置应用密钥,再更新 WorkBuddy 中的本机配置;Webhook 泄露时,到对应群自定义机器人的设置中重置地址,再更新 .work/private/feishu-webhook.env。不要继续用旧值测试。
  • 成功信号: 本机配置已经改用新值,WorkBuddy 恢复“已连接”或独立脚本重新发送成功,旧值不再出目前任何正在使用的配置中。

确认已经完成的部分与仍待搭建的部分

WorkBuddy 双向对话和定时推送补充通道已经具备可观察的闭环信号;Codex 目前只完成本机调用验证,飞书端桥接仍待搭建。

  • WorkBuddy 双向对话: 飞书机器人单聊可以发送测试任务,电脑端 WorkBuddy 收到同一任务,飞书收到指定回复 WORKBUDDY_FEISHU_OK。
  • 定时推送补充通道: 独立脚本测试成功;一次性自动化的运行记录显示完成并输出“飞书推送成功”;飞书测试群收到以 [WorkBuddy] 开头的结果。这条通道由 WorkBuddy 自动化、本地脚本和群自定义机器人组成,不是即时对话集成自带的能力。
  • Codex 本机验证: 已验证的系统信号只有本机只读 codex exec 返回 CODEX_BRIDGE_OK,它证明本机 Codex 调用链可用。“独立飞书应用—本地受控桥接—Codex—飞书回复”是计划中的接入路径,本节没有完成飞书端到端验证。

完成上述已验证部分的检查后,可以继续把已经验证的一次性提醒改为周期提醒,或在指定工作目录内安排资料整理和内容检查,并继续使用最小读写权限。未来搭建独立桥接时,必须同时配置允许向桥接提交任务的飞书账号白名单和执行日志,用来追踪每次任务的来源与结果。

以上。既然看到这里了,如果觉得不错,随手点个赞、关注、转发三连吧,这对我有特别大的协助!

谢谢你看我的文章。我们下次再见。

版权声明:本文为 @David Roto 原创内容,未经授权,不得转载、摘编或以其他方式使用。

© 版权声明

相关文章

1 条评论

none
暂无评论...