Bundle
dsh-plugin-feishu-bridge
Feishu (Lark) long-connection bridge for DeepSeek Harness: phone Feishu DMs drive local dsh agents and replies land back in the chat
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-feishu-bridge(自用)
手机飞书私聊 → 本机 DeepSeek Harness agent 干活 → 结果文本回飞书。
插件挂在 dsh web 进程里,通过 `@larksuiteoapi/node-sdk` 的 WebSocket 长连接收发消息:不需要公网 IP、不需要回调地址。
- 普通文本消息 = 给电脑上的 agent 派任务;回合结束后把最后的助手文本回给你(超长截断)
- **agent 提问直达飞书**:agent 发起 `ask_user_question` 时,问题(含编号选项)自动推送给你,你回复编号/选项原文/自由文本即可继续回合;`/new`、`/stop` 等命令仍然优先
- `/new` 新会话;`/stop` 停止当前任务;`/status` 查看工作目录/会话/预设;`/help` 帮助
- 每个飞书私聊映射一个 agent 会话(`feishu-` 前缀),可在 web 界面历史里查看
- 白名单外的发送者被忽略,但日志会打印其 open_id(用于首次配置)
- 消息去重持久化:去重 id 存进状态文件,重启后飞书重投的旧事件不会重复执行任务
- 工作区目录不存在时挂载即自动创建
## 安装
### 0. 挂载插件(npm 包,推荐)
```bash
dsh plugin --profile web add dsh-plugin-feishu-bridge
```
包内声明 `dsh.bundle`,安装后自动加入 profile 补丁层,插件以 `enabled: false` 挂载(安全默认)。随后在你的 `~/.dsh/profiles/web/cordis.patch.yml` 里用 id 覆盖启用:
```yaml
- id: feishu-bridge
config:
enabled: true
allowedOpenIds: ['ou_你的open_id']
```
> 本仓库本身也是这个 npm 包的开发目录(`npm publish` 前先 `npx tsdown` 构建 `dist/`)。本地路径挂载(把本目录绝对路径写进 patch 的 `name:`)依然可用,但不要与 npm 包同时挂载——`id: feishu-bridge` 重复会冲突。
### 1. 飞书后台建应用
1. 打开[开发者后台](https://open.feishu.cn/app) → 创建「企业自建应用」。
2. 应用能力 → 添加「机器人」。
3. 事件与回调 → 订阅方式选「**使用长连接接收事件**」→ 添加事件 `im.message.receive_v1`。
4. 权限管理 → 开通接收与发送消息相关权限(`im:message`、`im:message:send_as_bot`,以后台提示为准)。
5. 版本管理与发布 → 创建版本并发布(不发布收不到事件)。
6. 记下 **App ID** 和 **App Secret**。
### 2. 凭证入店(二选一,别写进 cordis.yml)
- `~/.dsh/.credentials.yaml` 的 `refs:` 下加两行:
```yaml
refs:
FEISHU_APP_ID: cli_xxxx
FEISHU_APP_SECRET: xxxx
```
- 或写进 deepseek-harness 检出根目录的 `.env`(和 `DEEPSEEK_API_KEY` 同一处):`FEISHU_APP_ID=…`、`FEISHU_APP_SECRET=…`。
### 3. 启用(自动挂载后)
第 0 步已把插件挂成 `enabled: false`;重启 web 后它只是待命,不连飞书、不需要凭证。
### 4. 首次启用(拿你自己的 open_id)
1. 确认第 2 步凭证已就位。
2. 补丁行保持 `enabled: true`、`allowedOpenIds: ['ou_placeholder']`(占位符开启「回显模式」),重启 web。
3. 用手机飞书给机器人发任意消息;它会**直接回复**你的 open_id。
4. 把那个 open_id 替换占位符写进 `allowedOpenIds`,重启。发「你好」验证:agent 开工,回来 `✅ 任务完成` 或报错文本。
> 插件代码改动后需要重启 web 才会重新加载模块;只改 `cordis.patch.yml` 的配置则热重载即可。
## 配置项
| 字段 | 默认 | 说明 |
| --- | --- | --- |
| `enabled` | `false` | 总开关;`false` 时挂载但完全不动 |
| `appIdEnv` / `appSecretEnv` | `FEISHU_APP_ID` / `FEISHU_APP_SECRET` | 凭证引用名(credentials 店或 env 里的键名) |
| `domain` | `feishu` | `feishu`(feishu.cn)或 `lark`(larksuite.com) |
| `allowedOpenIds` | `[]` | 白名单;`enabled: true` 时空列表会在加载时报错(设计如此) |
| `workspacePath` | `~/.dsh/feishu-workspace` | 飞书会话的工作目录(必须绝对路径) |
| `agentPreset` | `standard` | 每个飞书会话挂的 agent 预设 |
| `permissionPreset` | `workspace-write` | 每个飞书会话的权限预设 |
| `maxReplyChars` | `3000` | 回复按码点截断的上限(100–50000) |
| `dataFile` | `~/.dsh/feishu-bridge/state.json` | chat→session 映射文件(必须绝对路径) |
## 安全
- 白名单外的发送者被忽略(打日志,不回复)。
- `permissionPreset` 默认 `workspace-write`:手机消息能触发写本机文件的操作;想保守就用只读预设,不要图省事开 `danger-full-access`。
- 回复只含回合最终文本,不会把工具输出原样倒进聊天。
## 故障排查
- **web 启动失败,日志有 `credential ref … resolved empty`**:`enabled: true` 但凭证缺失,这是设计的 fail-loud;补凭证或先改回 `enabled: false`。
- **日志有 `ignoring sender ou_xxx`**:把它加进 `allowedOpenIds`。
- **日志有 `long connection error`**:核对 App ID/Secret 和 `domain`(国内用 `feishu`,海外用 `lark`)。
- **飞书侧发了没反应**:确认应用已发布、机器人能力已添加、事件已订阅且选了长连接、权限已开通。
- **发消息没回音但控制台也无报错**:多半是 agent 在提问等你回答(旧版本问题不会推送到飞书);发 `/new` 重开会话即可解锁。
- **`task delivery failed: ENOENT … feishu-workspace`(旧版本)**:现在挂载时会自动建目录;老进程手工 `mkdir -p ~/.dsh/feishu-workspace` 即可。
- **插件代码改了没生效**:ESM 模块缓存在进程里,必须重启 web;只改 `cordis.patch.yml` 配置则热重载即可。
## 已验证
- 2026-08-29 真实端到端联调通过:飞书发任务 → 白名单 → 会话创建 → agent 执行(含工具调用)→ `ask_user_question` 推回飞书 → 回答后回合继续 → 最终文本回飞书。
- 本机加载测试:模块加载、inject 服务全部解析、`enabled: false` boot、假凭证 fail-loud。
- 去重持久化:状态文件 round-trip 后旧 id 仍被识别。
## 设计与已知取舍
- **长连接是模块级单例**(按 `domain:appId` 共享):飞书每 App 只允许一条长连接,且每条连接都会收到事件副本;配置热重载产生的新插件世代复用同一条连接,避免重复回复。
- **生命周期 disposer 有意惰性**:web profile 启动期,祖先 fiber 的 disposal 级联会在挂载后一秒内抽干本插件刚注册的 effects,而插件 fiber 本身从不失活,disposer 无法区分搅动与真实卸载;执行它们曾中止 agent lifetime 使所有后续任务 AbortError,重新注册则引发无限 drain 循环。权衡结果:disposer 不动作,socket 与文件句柄由进程退出回收;`enabled: false` 时走显式拆除。
- **去重窗口 1000 条**:超出窗口的极老消息重投理论上可能重复执行(自用可接受)。
## 已知局限
- 仅支持私聊文本消息;群聊、图片、文件不处理。
- 一个聊天同时只有一个活动会话;插件重启后映射仍在,但旧会话不在线,下一条消息自动新建会话。
- 回复不承载中间工具输出;完整过程看电脑上的会话记录。
- 本目录在 harness 仓库之外(自用,未纳入 git 管理)。
Install
dsh plugin --profile web add dsh-plugin-feishu-bridge@0.1.1
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-plugin-feishu-bridge from the hub