协作办公
用 lark-cli 实时订阅/消费飞书(Lark)事件流时…
适用于用 lark-cli 以子进程方式实时消费 Lark/Feishu 事件(IM、审批、任务、VC、Minutes、白板等),并按 schema 安全编写 jq 过滤/投影。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 lark-cli 实时订阅/消费飞书特定
解决思路
- 先阅读 `../lark-shared/SKILL.md`,掌握认证、`--as user/bot` 切换、`Permission denied` 处理和安全规则。
- 列出所有可订阅 EventKey:`lark-cli event list [--json]`。
- 查看某个 EventKey 的参数和输出 schema:`lark-cli event schema <EventKey> [--json]`。
- 阻塞式消费事件,事件以 NDJSON 写 stdout:`lark-cli event consume <EventKey> [flags]`。
- 查看本地 bus daemon 状态:`lark-cli event status [--json] [--fail-on-orphan]`。
- 停止 bus daemon:`lark-cli event stop [--all] [--force]`。
- 用 `--param key=value` 或 `-p` 传业务参数;可重复,多值用逗号分隔;未知 key 会失败并在提示中列出合法名称。
- 用 `--jq <expr>` 对每个事件过滤/转换;输出为空则跳过该事件。
- 用 `--max-events N` 达到 N 个事件后退出;默认 0 表示不限。
- 用 `--timeout D` 到达时长后退出(如 `30s`、`2m`);默认 0 表示无超时;`--max-events` 与 `--timeout` 谁先触发谁生效。
- 用 `--output-dir <dir>` 把每个事件写成文件;只允许相对路径,防止路径穿越。
- 不要用 `--quiet`(AI 不应使用):它会抑制 ready/exit 标记和逐事件 stderr 诊断(包括丢弃警告),可能隐藏事件丢失,移除就绪与完整性信号。
- 用 `--as user|bot|auto` 指定会话身份(见 lark-shared)。
- 默认消费某个 key 的所有事件,不加过滤和投影:`lark-cli event consume im.message.receive_v1 --as bot`。
- 列出某个 domain 的所有 EventKey:`lark-cli event list --domain vc --json`。
- 抓一个样本事件查看 payload 形状:`lark-cli event consume im.message.receive_v1 --max-events 1 --timeout 30s --as bot`。
- 运行 10 分钟后自动退出:`lark-cli event consume im.message.receive_v1 --timeout 10m --as bot`。
- 并发消费多个 EventKey:对每个 key 启动一个进程并重定向到不同 ndjson,例如 `lark-cli event consume im.message.receive_v1 --as bot > receive.ndjson &` 和 `lark-cli event consume im.message.reaction.created_v1 --as bot > reaction.ndjson & wait`,每个进程一种形状,无需 dispatcher。
- 调用流程第 1 步:`lark-cli event list --json` 选合法 key;`--domain <d>` 可缩小到一个 domain;合法 domains 是 `application`、`approval`、`board`、`card`、`im`、`minutes`、`task`、`vc`;未知 domain 会失败并在 hint 中列出合法集合。
- 调用流程第 2 步:`lark-cli event schema <key> --json`,读取 `resolved_output_schema` + `jq_root_path` 判断字段路径。
- 调用流程第 3 步:`lark-cli event consume <key> [--jq '<expr>']` 消费。
- Ready marker:`event consume` 的 stderr 会输出固定行 `[event] ready event_key=<key>`;父进程应阻塞在 stderr 直到该行出现,再开始读 stdout;不要退化成 `sleep`。
- stdin EOF = graceful exit:`event consume` 把 stdin 关闭当作关闭信号(为 AI 子进程调用者设计)。Bounded runs 例外:设置了 `--max-events` 或 `--timeout`(>0)时,stdin EOF 被忽略,只能通过自身边界、timeout 或 SIGTERM 退出。对于无界运行,`< /dev/null`、`nohup`、systemd 默认 `StandardInput=null` 会导致立即优雅退出(stderr `reason: signal`)。
- 保持无界运行存活:给 stdin 喂一个永不 EOF 的源:`< <(tail -f /dev/null)`;或改为有界:`--max-events N` / `--timeout D`。
- 退出时最后一行 stderr:`[event] exited — received N event(s) in Xs (reason: ...)`。
- 退出码 0 且 `reason: limit`:达到 `--max-events` 后退出。
- 退出码 0 且 `reason: timeout`:达到 `--timeout` 后退出。
- 退出码 0 且 `reason: signal`:Ctrl+C / SIGTERM / stdin EOF 触发;stdin EOF 只适用于无界运行。
- 退出码 1:stderr 输出 JSON error envelope;Lark API 业务失败发生在 pre-consume 设置期间(例如 subscription create/delete)。
- 退出码 2:stderr 输出 JSON error envelope(没有 `exited` 行);校验失败(未知 EventKey、错误 `--param` / `--jq`、已有另一个 bus 连接)。
- 退出码 3:stderr 输出 JSON error envelope;认证失败(缺少 token、缺少 scopes)。
- 退出码 4 / 5:stderr 输出 JSON error envelope;网络 / 内部失败(bus 启动、握手、文件 I/O)。
- 启动和运行时失败会在 stderr 输出结构化 JSON envelope:`{ok:false,error:{type,subtype,param,message,hint,...}}`(也可能携带顶层 `identity` / `_notice` siblings)。解析 `error.type` / `error.subtype` 来分支(例如 `missing_scope` 带 `missing_scopes` 列表),用 `error.param` 找有问题的 flag,用 `error.hint` 做恢复动作;不要用正则匹配 message 文本。
- Orchestrators 应把 `reason: limit/timeout/signal`(均 exit 0)视为“业务完成”,非零视为“失败”。
- Never `kill -9`:避免对 consume 进程使用 `kill -9`,尤其 EventKeys 的 PreConsume 注册了服务端订阅并在退出时取消订阅的(minutes、vc、board keys):`kill -9` 会跳过 OAPI unsubscribe,泄漏服务端订阅(症状:重启时 “subscription already exists”、重复事件投递)。task、approval keys 的订阅是 durable relation 且无 cleanup,不会这样泄漏,但 SIGTERM 或关闭 stdin 仍是所有 key 的正确关闭方式。
- One consume, one EventKey:命令只接受一个位置参数;不支持 `k1,k2` 和通配符。监听 N 个 key 需要 N 个子进程,这是有意设计。
- 多进程好处:每个进程 stdout 一种形状,AI 无需 dispatcher 逻辑;故障隔离(一个 key 失败不影响其他);每个 key 可独立设置 `--as` / `--jq` / `--max-events` / `--timeout`;所有 N 个 consumer 共享一个 bus daemon(UDS 本地 IPC),开销小。
- 写 `--jq` 时以 `event schema <key> --json` 为唯一事实来源。
- 看 `jq_root_path` 确定字段起点:值为 `"."` 时字段在顶层,写 `.chat_id`;值为 `".event"` 时字段在 V2 envelope 内,写 `.event.chat_id`。
- 看 `resolved_output_schema.properties.<name>` 获取字段列表和类型;每个字段带 `type` / `description`,部分带 `format`。示例:`chat_id` 是 string、format 为 chat_id、description 说明以 oc_ 开头;`sender_id` 是 open_id、以 ou_ 开头;`create_time` 是 timestamp_ms、毫秒时间戳字符串。
- 看 `format` tag 理解字段语义;Lark 定义语义标签(不是 JSON Schema 标准 `format`)。常见值:`open_id` / `chat_id` / `message_id` / `timestamp_ms` / `email`。用途:区分“同为 string 类型但含义不同”的字段,以便通过 API 反查或转换格式。
- 读字段 `description` 判断解码状态:`event consume` 会运行 Process hooks,可能预解码部分 payload 字段(扁平化 V2 envelope、把 `.content` 渲染为纯文本等),行为不同于原始 OAPI。写 jq 前始终读字段 description,尤其是通用字段名 `content` / `data` / `body` / `payload`。
- 为什么重要:盲目对已解码文本字段应用 `fromjson` 会让 jq 对每个事件报错并静默丢弃——consumer 看起来活着但不输出,只有一行 `WARN` 埋在 stderr。(通用行为:任何 jq 运行时错误会跳过事件并输出一行 WARN;循环不会中止。)
- 不要走捷径:用 jq 投影 `event schema --json` 时,不要从 `properties` 中删掉 `.description`——它告诉你字段是否已解码。输出完整属性对象,不要只输出 keys。
- Aside:`--param` 的合法参数也在 schema 中——`params` 节列出 `name` / `type` / `required` / `enum` / `default` / `description`;`params` 节缺失 = 该 key 不接受任何 `--param`。
- 按主题查阅 Application 参考:`references/lark-event-application.md`,覆盖 Application EventKeys 目录,包括 `application.bot.menu_v6` 自定义 bot 菜单推送事件 + 扁平化 `event_key` / operator 字段 + jq recipe。
- 按主题查阅 Approval 参考:`references/lark-event-approval.md`,覆盖 2 个 Approval EventKeys(`approval.instance.status_changed_v4`、`approval.task.status_changed_v4`)+ 可选/多 `subscription_type` 预注册 + user-auth 订阅生命周期 + flat output 字段参考。
- 按主题查阅 IM 参考:`references/lark-event-im.md`,覆盖 12 个 IM EventKeys + shape notes(flat vs V2 envelope)+ `im.message.receive_v1` 字段坑(`sender_id` 只有 open_id;`.content` 除 `interactive` cards 外是纯文本)+ 常用 jq recipes(按 chat_type / message_type / sender 过滤);`card.action.trigger` 另见 `../lark-im/references/lark-im-card-action-reply.md`。
- 按主题查阅 Task 参考:`references/lark-event-task.md`,覆盖 1 个 Task EventKey(`task.task.update_user_access_v2`)+ Native V2 envelope shape + task commit types + user/bot subscription notes。
- 按主题查阅 VC 参考:`references/lark-event-vc.md`,覆盖 7 个 VC EventKeys(meeting lifecycle `participant_meeting_started/joined/ended_v1`、`vc.note.generated_v1`、recording `recording_started/transcript_generated/ended_v1`)+ field reference + source type semantics;实时列表始终用 `lark-cli event list --domain vc --json`。
- 按主题查阅 Minutes 参考:`references/lark-event-minutes.md`,覆盖 1 个 Minutes EventKey(`minutes.minute.generated_v1`)+ field reference + source type semantics(meeting only)。
- 按主题查阅 Whiteboard 参考:`references/lark-event-whiteboard.md`,覆盖 1 个 Board EventKey(`board.whiteboard.updated_v1`)+ per-whiteboard 订阅模型(requires `-p whiteboard_id=<token>`)+ payload field reference(whiteboard_id / operator_ids triple-id)。
适用边界 · 注意事项
- 没有安装 `lark-cli` 或无法完成 Lark/Feishu 认证、授权(token/scope)时,不适用。
- 只需要查询历史数据、发消息或其他非实时事件场景时,不适用。
- 无法让父进程监控 stderr 的 ready/exit 标记,或必须使用 `--quiet` 隐藏就绪与完整性信号时,不适用。