pi-lark-notify

pi 主对话 ⇄ 飞书双向桥:主对话完成时发送飞书通知;在飞书里回复通知,内容自动注入对应 pi 会话继续执行。

Packages

Package details

extension

Install pi-lark-notify from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-lark-notify
Package
pi-lark-notify
Version
0.3.1
Published
Aug 17, 2026
Downloads
291/mo · 10/wk
Author
naoki326
License
MIT
Types
extension
Size
44.3 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./extensions"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-lark-notify

🚀 把 pi 装进口袋——人在外面,手机飞书就能远程指挥 pi 连续干活。

npm license platform


✨ 它解决什么问题?

你是否有过这样的时刻——人在地铁上 / 工位上 / 回家路上,代码却还在跑?

  • pi 在后台执行长任务,你想知道进展,却只能干等?
  • 任务跑完了,你还得打开电脑才能看到结果?
  • 想让 pi"顺手再改一下",却没法在手机上开口?

pi-lark-notify 让飞书变成 pi 的遥控器:

你发布任务 ─→ pi 开始干活
pi 完成 ───→ 飞书收到通知(完整回复原文)
你长按回复 ─→ "顺便把测试也跑了"
pi 继续干 ──→ 完成后又收到通知 → 循环往复……

双向零公网成本一条命令装完就能用:

  • WebSocket 长连接,不需要服务器、不需要公网 IP
  • 手机飞书即遥控器,任务完成、进度、追问随手掌控

🎯 功能亮点

  • 📬 下行通知——主对话每次彻底完成(agent_settled, 自动重试/压缩不算)时,把项目名、完成时间、最后一条回复 完整原文推送到飞书私聊或群聊
  • 📤 上行回注——监听飞书 im.message.receive_v1 事件 (WebSocket 长连接,无需公网 webhook),把你的回复通过 pi.sendUserMessage 注入对应会话继续执行,会话忙时自动排队
  • 🎯 精确路由——回复某条通知 → 注入发出该通知的会话 (按 message_id 匹配,多窗口不串话);直接发消息 (非回复)→ 忽略,不注入任何会话
  • 🛡️ 安全边界——只接受指定用户(userId)的单聊消息, 他人给机器人发消息不会触发任何动作
  • 👻 静默子 agent——pi-subagents 的子 agent 在同进程内以独立 AgentSession 运行,同样会加载本扩展;factory 执行时检测调用栈中的 pi-subagents 帧并整体静默(不订阅、不通知、不登记), 只有主对话完成才发通知。如需子 agent 通知可配 subagentNotify: true
  • 🔄 崩溃自愈——消费者进程崩溃自动重启(退避 3s→60s); pi 进程崩溃后,新进程自动清理孤儿消费者
  • 💾 单例消费者——全局只起一个 lark-cli event consume 子进程,多 session 共享事件流,不堆积进程

🚀 快速开始(3 步)

① 安装

pi install npm:pi-lark-notify

完全自包含,零手动依赖:首次启动会话时,扩展自动完成两件事—— ① 检测不到 lark-cli 时自动 npm install~/.lark-cli (需联网,约十几秒); ② 将 lark-notify 节的 appId/appSecret 写入 ~/.lark-cli/config.json 凭证文件(0600 权限)。 不依赖 @amaster.ai/pi-lark 及其附带技能。

② 创建飞书自建应用(可多台机器复用同一个)

飞书开放平台 创建企业自建应用, 或复用已有的:

  1. 开启机器人能力(应用能力 → 机器人)
  2. 开通权限(权限管理):
    • im:message(获取与发送单聊、群组消息)
    • im:message:send_as_bot(以应用的身份发消息)
    • contact:user.id:readonly(可选,用于通过手机号/邮箱查 open_id)
  3. 创建版本并发布(版本管理与发布)——权限必须发布后才生效

事件接收由 lark-cli event consume 与开放平台建立 WebSocket 长连接, 不需要在控制台配置事件订阅,也不需要公网回调地址。

③ 配置 ~/.pi/agent/settings.json

{
  "lark-notify": {
    "enabled": true,
    "appId": "cli_xxx",
    "appSecret": "${LARK_APP_SECRET}",
    "domain": "feishu",
    "userId": "ou_xxx"
  }
}
  • appSecret 支持 ${ENV_VAR} 环境变量语法,避免明文
  • 从旧版迁移:若 settings 中凭证仍在 pi-lark 节 (@amaster.ai/pi-lark 的格式),扩展会兼容读取,无需改动配置
  • 复用同一个应用时 appId/appSecret/open_id 全部不变 (open_id 是"应用 × 用户"维度,与机器无关),配置可直接照抄
  • 不知道自己的 open_id?配好凭证后执行:
lark-cli api POST \
  "/open-apis/contact/v3/users/batch_get_id?user_id_type=open_id" \
  --data '{"mobiles":["你的手机号"]}' --as bot

✅ 验证

  1. pi 里执行 /reload(或重启会话)
  2. 随便聊一句 → 对话完成后飞书应收到通知
  3. 长按通知 → 回复 → 该会话应自动收到 【飞书】... 并继续执行,同时飞书收到"✅ 已转达"回执

⚙️ 配置项(lark-notify 一节)

默认 说明
enabled true 总开关(下行 + 上行)
appId 飞书自建应用 App ID
appSecret 飞书自建应用 App Secret,支持 ${ENV_VAR} 语法
domain feishu 应用域名:feishulark(国际版)
userId 私聊接收人 open_id(与 chatId 二选一,优先)
chatId 群聊 chat_id(需先把机器人拉进群)
replyEnabled true 上行回注开关(关闭则只发通知)
receipt true 转达后回执一条"已转达 ✅"
subagentNotify false 子 agent 完成也发通知(保险丝,栈检测误判时可显式恢复)

全局配置在 ~/.pi/agent/settings.json,项目级可用 <项目>/.pi/settings.json 覆盖(例如不同项目发给不同群)。


🧠 工作原理

session_start ─→ getLarkClient()(进程级单例)
  │ subscribe(handleEvent)
  ▼
唯一 `lark-cli event consume` 子进程
  (NDJSON 事件流,崩溃自动重启,退避 3s→60s 持续重试)
  │ 事件广播给所有订阅者
agent_settled ─→ client.sendMessage()
  ─→ 记录 通知message_id → 本会话
事件到达 ─→ 过滤(本人/单聊/去重/防过期)
  ─→ 路由(仅 reply_to 精确匹配,非回复忽略)
  ─→ 跨会话认领(ClaimDedup 状态文件目录锁)
  ─→ pi.sendUserMessage(followUp)
session_shutdown ─→ unsubscribe()
  (只移除 handler,不关 consumer;consumer 随 pi 进程退出)

状态拆分(各自独立文件 + 目录锁,15s 死锁自动破除):

状态文件 职责
lark-notify-sessions.json SessionRegistry:崩溃残留清理
lark-notify-router.json NotificationRouter:通知 → 会话映射
lark-notify-claims.json ClaimDedup:事件认领去重,先到先得

会话身份:每个扩展实例随机 sid,注入前以 sid 认领事件, 杜绝多窗口重复注入。


⚠️ 注意事项

多机器同时使用

  • 长连接模式是集群分发:同一应用的多台机器只有其中一台会收到事件, 因此请确保只有一台机器的 pi 扩展在监听事件 (其余机器只用于发送通知、不回复)
  • 回复通知的路由是精确的(按 message_id 匹配),多机并存也安全
  • 直接发消息(不回复通知)会被忽略,不注入任何会话。 多机场景请养成回复具体通知的习惯

装了 hermes 的机器(可选)

lark-cli 检测到 HERMES_HOME 等环境变量会误判运行环境并报 config bind 错误。本扩展内部的调用已自动清洗环境变量,不受影响; 但手动或让 agent 使用 lark 技能时,需要 lark-cli 包装脚本。 该脚本在 npm 包中不包含,从 git 仓库获取:

# 从 git 仓库检出后,拷到 PATH 靠前的目录(如 ~/bin)
cp bin/lark-cli bin/lark-cli.cmd ~/bin/   # Windows git-bash + cmd
# macOS/Linux 只需 cp bin/lark-cli ~/bin/

🖥️ 平台支持

  • 理论支持 Windows / macOS / Linux 三平台 (lark-cli 依赖 @larksuite/cli 声明 os: ['darwin', 'linux', 'win32'])
  • 进程枚举跨平台:Windows 走 PowerShell Get-CimInstance, macOS/Linux 走 ps axww
  • 验证状态:Windows 已充分验证;macOS/Linux 的主流程 (发消息、事件监听)应可用,但孤儿 consumer 自愈逻辑未经实测, 若 ps 不可用或输出格式异常会静默跳过(不影响主功能,仅失去自愈)
  • 已知限制:上行仅处理单聊(p2p)消息;长连接为集群分发 (详见「多机器同时使用」),lark-cli event consume 子进程退出后 自动重启(退避 3s→60s,持续重试)
  • 若你在 macOS/Linux 上遇到问题,欢迎反馈

📁 文件结构

pi-lark-notify/
├── package.json            # pi 包清单(extensions 声明)
├── extensions/
│   └── lark-notify.ts      # 扩展本体(单文件,零依赖)
├── bin/                    # 仅 git 仓库包含,npm 包不含
│   ├── lark-cli
│   └── lark-cli.cmd
├── LICENSE
└── README.md

🗑️ 卸载

pi remove pi-lark-notify

删除 settings.json 中的 lark-notify 一节即可彻底清理 (~/.lark-cli 目录可手动删除)。


📄 License

MIT © Naoki326