Skip to content

feat(lark-doc): 飞书文档评论作为话题输入/输出入口 (/subscribe-lark-doc)#205

Open
deepcoldy wants to merge 5 commits into
masterfrom
feat/subscribe-lark-doc
Open

feat(lark-doc): 飞书文档评论作为话题输入/输出入口 (/subscribe-lark-doc)#205
deepcoldy wants to merge 5 commits into
masterfrom
feat/subscribe-lark-doc

Conversation

@deepcoldy

Copy link
Copy Markdown
Owner

背景

申晗点题:botmux 目前唯一的话题发起入口在飞书聊天里。本 PR 把飞书文档做成会话的输入/输出通道——在飞书正常起会话后用 /subscribe-lark-doc <文档链接> 订阅文档,文档评论喂进会话当输入,bot 的回复嵌套回到那条评论 thread;状态卡/按钮/终端卡仍发在会话起点(飞书)。

交互(申晗拍板)

  • 命令名 /subscribe-lark-doc(已核对不撞 CC/Codex 原生命令、不在现有 daemon 命令集)
  • 触发范围两种:mention-only(评论 @bot 才触发,默认)/ all(所有新评论),dashboard 可配
  • 1 文档只绑 1 活跃会话;1 会话可订阅多文档
  • 回复嵌套进评论 thread(真嵌套,非新建全文评论)

关键实现

  • im/lark/doc-comment.ts:URL/wiki→token、订阅/退订、读评论、嵌套回复(裸打 drive-v1 file.comment.reply.create——node-sdk 1.64.0 未暴露 create,但裸 endpoint 存在,由 lark-cli 二进制实锤)、自触发防死循环(bot reply_id 集合 + 隐形哨兵)、长回复分块
  • services/doc-subs-store.ts:订阅注册表(fileToken 主键天然 1文档:1会话,per-app,原子写)
  • 入站:event-dispatcher 注册 drive.file/notice.comment_add_v1(两候选名防错)→ 订阅匹配 + 自触发过滤 + 触发范围 → daemon.handleDocComment
  • 出站分流:本轮来自文档评论时,botmux send(主回复路,经磁盘 currentDocCommentTarget)与 final_output(兜底)都回评论;状态卡走会话锚点天然留飞书
  • 生命周期:/close 退订清理;daemon 重启恢复订阅(孤儿退订)
  • OAuth 加 docs:document.comment 等 scope;BotConfig + dashboard Bot Defaults 加 docSubscribeDefaultMode

⚠️ 需真机验证(飞书侧不确定点)

  1. 评论事件确切名(drive.file.comment_add_v1 vs drive.notice.comment_add_v1,已两个都注册)+ payload 字段路径
  2. 评论事件是否必须 user_access_token 订阅(已强制 /subscribe-lark-doc 前要 /login
  3. 嵌套回复 / 订阅 API 实际行为

测试

  • tsc 0、pnpm build 绿
  • 新增单测 19 例(doc-subs-store + doc-comment 纯逻辑)
  • 全量 unit 4343/4343(更新了 DAEMON_COMMANDS 计数断言)

未发版、未部署。

/subscribe-lark-doc 把一个飞书文档订阅到当前会话:文档评论喂进会话当输入,
bot 的回复嵌套回到那条评论 thread;状态卡/按钮/终端卡仍发在会话起点(飞书)。

- 新增 im/lark/doc-comment.ts:URL/wiki→token 解析、订阅/退订、读评论、
  嵌套回复(裸打 drive-v1 file.comment.reply.create,node-sdk 未暴露)、
  自触发防死循环(bot 创建 reply_id 集合 + 隐形哨兵双保险)、长回复分块
- 新增 services/doc-subs-store.ts:订阅注册表(fileToken 主键 = 1文档:1会话,
  per-app 文件,原子写)
- 命令 /subscribe-lark-doc <链接|list|off>(command-handler)+ 中英文案
- 入站:event-dispatcher 注册 drive.file/notice.comment_add_v1(两候选名),
  订阅匹配 + 自触发过滤 + 触发范围(mention-only/all)后转 daemon.handleDocComment
- 出站分流:本轮来自文档评论时,botmux send(主路,经磁盘 currentDocCommentTarget)
  与 final_output(兜底)都改为回评论;状态卡天然留飞书
- 生命周期:/close 退订清理;daemon 重启恢复订阅(孤儿退订)
- OAuth 加 docs:document.comment 等 scope;BotConfig + dashboard 加
  docSubscribeDefaultMode(新订阅默认触发范围,可在 Bot Defaults 配)
- 测试:doc-subs-store + doc-comment 纯逻辑 19 例;更新 DAEMON_COMMANDS 计数
申晗实测 /subscribe-lark-doc 的授权链接报 20043「docs:document.comment error」:
scope 名写错了(裸 docs:document.comment 不存在,drive:drive:readonly 也不在
清单),且把文档 scope 加进全局 DEFAULT_SCOPES 会让所有 bot 的通用 /login(图片
下载)一起请求这些 scope → 没启用的 app 全部 20043。

- DEFAULT_SCOPES 改回原 3 个(im:message:readonly/im:resource/offline_access)
- 新增 DOC_COMMENT_OAUTH_SCOPES(全部对 lark-scopes.json 校验过):
  docs:document.subscription / docs:event:subscribe / docs:document.comment:read /
  docs:document.comment:create / wiki:wiki:readonly
- generateAuthUrl 加 extraScopes 参数(去重合并)
- /subscribe-lark-doc 未授权 / 403 时生成「带文档 scope」的专用授权链接(不再
  让用户跑通用 /login),文案点明还需后台启用权限 + 订阅评论事件
@deepcoldy deepcoldy force-pushed the feat/subscribe-lark-doc branch from 0c05eb5 to 95de5de Compare June 13, 2026 18:51
申晗实测:①授权回调 URL 难抓(需开 Network 面板)②订阅成功但评论后 daemon
收不到事件。

- event-dispatcher 包一层 eventDispatcher.invoke,记录长连接收到的每个事件
  类型(含未注册的);comment 类连 file_token/comment_id/notice_type/keys 一起打,
  其余事件仅 DEBUG 下打。用来一锤定音「飞书没发」还是「我们解析丢了」
- processCommentEvent 的「缺字段 / 不在订阅表」丢弃分支提到 info 级,便于排查
- 授权提示 step2/step3 改写:点明回调页打不开是正常(127.0.0.1 在远端连不上),
  优先复制地址栏 URL,看不到再用 F12→Network→All→Copy URL 兜底

注:lark-cli 二进制实锤评论事件名 = drive.notice.comment_add_v1(已注册),
故事件名无误;下一步靠诊断日志确认后台是否漏订阅该事件。
真机诊断实锤 drive.notice.comment_add_v1 的 event 体 = {comment_id, is_mentioned,
notice_meta, reply_id},file_token 不在顶层而在 notice_meta(可能是对象或 JSON 串)。
之前按顶层 file_token 解析 → 全被 drop。

- parseCommentEvent 展开 notice_meta(对象/字符串都吃)挖 file_token/file_type/
  notice_type,多路径兜底;新增 isMentioned(事件自带 @ 判定)
- file_type 拿不到无妨:用订阅表里的(getDocSubscription 只按 fileToken 命中)
- mention-only 触发改用事件 is_mentioned(飞书已判),回退正文 @person 比对
- 诊断日志 dump 完整 notice_meta + parsed 结果,万一字段名再不符可一眼定位
申晗建议把 drive.notice.comment_add_v1 纳入 bot 启动权限检查。飞书无「列出已订阅
事件」的 API(事件订阅查不了),故务实方案:对**已订阅过文档**的 bot 才检查(opt-in,
不打扰其他 bot),① 校验文档 app 权限是否开通(可查 → 缺则 DM 深链)② 一并提醒
去后台订阅 drive.notice.comment_add_v1 事件(不可查只能提醒)。让「订阅成功却收不到
评论」的配置漏项在重启自检时暴露。

- verify-permissions: 新增 DOC_FEATURE_SCOPES(名字单一源=user-token.DOC_COMMENT_OAUTH_SCOPES
  + 中文说明,全 critical:false)+ DOC_COMMENT_EVENT 常量
- event-dispatcher.checkRequiredScopes: grantedScopes 算出后加文档就绪分支
  (仅 docSubs>0 时生效;缺权限 DM 管理员含事件订阅提醒;齐全则 info 提醒事件)
- 测试: DOC_FEATURE_SCOPES 全在 lark-scopes.json + 与 DOC_COMMENT_OAUTH_SCOPES 同名
  防漂移 + 恒非 critical
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