zarazhangrui/lark-coding-agent-bridge
GitHub: zarazhangrui/lark-coding-agent-bridge
将飞书/Lark 即时通讯与本地 Claude Code 或 Codex CLI 连接的轻量级桥接机器人,支持流式卡片回复、多工作区和会话管理。
Stars: 1206 | Forks: 185
# lark-channel-bridge
一个轻量级的 bot,用于将飞书 / Lark 即时通讯与您的本地 Claude Code 或 Codex CLI 连接起来。运行一条命令,扫描二维码即可绑定 PersonalAgent 应用,并直接从聊天中与您的本地编码代理进行对话。
[中文 README](./README.zh.md)
有关产品演示,请参阅[飞书文档](https://larkcommunity.feishu.cn/docx/OaRIdFIRFoLM3xxTmKwcetHqn5e)。
## 功能介绍
- 将飞书 / Lark 消息转发至本地 Claude Code 或 Codex CLI。可以直接发送私信,或在群聊中 `@bot`。
- **流式卡片**:文本回复和工具调用会在同一个 Lark 卡片上实时更新。
- **会话连续性**:每个聊天、话题或文档评论串都会保留各自的会话。
- **排队与批处理**:快速连续发送的消息会被一起处理;在运行期间发送的消息会排入下一轮队列,而 `/new`、`/cd`、`/ws use` 和 `/stop` 等命令可以中断当前任务。
- **多工作区**:使用 `/cd` 切换当前项目,使用 `/ws` 保存并复用常用的项目目录。
- **图片与文件**:直接发送给 bot,bridge 会将其下载到本地供代理使用。
- **交互式卡片**:`/help`、`/ws list` 和 `/status` 会返回带有可点击按钮的卡片。
## 前置条件
- Node.js **>= 20.12.0**
- 至少安装并登录了一个本地代理:
- Claude Code:`claude`,请参阅 https://docs.anthropic.com/en/docs/claude-code/quickstart
- Codex CLI:`codex`,请参阅 https://developers.openai.com/codex/cli
- 一个飞书 / Lark **PersonalAgent** 应用。首次运行的二维码向导可以为您创建并绑定一个应用。
## 安装
```
npm i -g lark-channel-bridge
# 或者
pnpm add -g lark-channel-bridge
```
## 首次运行
```
lark-channel-bridge run
```
首次运行会打开一个二维码向导:
1. 您的终端会显示一个二维码。
2. 使用飞书 / Lark 应用扫描它。
3. 选择或创建一个 PersonalAgent 应用。
4. 如果出现提示,请选择要初始化的代理。
5. 配置将写入 `~/.lark-channel/config.json`。
您无需预先选择项目目录。bridge 会创建一个由配置管理的默认工作目录;启动后,在飞书 / Lark 中发送 `/cd ` 即可切换到实际项目。
如果您已经有了 PersonalAgent 应用,请在初始化期间传入 `--app-id` 以跳过应用创建。该命令会提示您输入 App Secret。
```
lark-channel-bridge run --app-id cli_xxx
# 或者直接初始化并启动 background service
lark-channel-bridge start --app-id cli_xxx
```
对于 Lark 全球应用,请添加 `--tenant lark`。
## 后台服务
使用 `run` 进行首次运行设置和前台调试。在 bot 可以发送和接收消息后,使用 `Ctrl-C` 停止前台进程,然后使用操作系统管理的服务进行后台运行:
```
lark-channel-bridge start
lark-channel-bridge status
lark-channel-bridge stop
```
在使用服务命令之前,请先全局安装。daemon 的 launchd plist / systemd unit / Windows 任务会记录 bridge CLI 的路径;如果该路径来自通过 `npx` 访问的 npm 临时缓存,那么在清理缓存时 daemon 可能会损坏。作为一次性前台进程,通过 `npx` 运行 `run` 是没问题的。
服务命令会为每个配置安装相应的服务:
```
lark-channel-bridge start [--profile ]
lark-channel-bridge stop [--profile ]
lark-channel-bridge restart [--profile ]
lark-channel-bridge status [--profile ]
lark-channel-bridge unregister [--profile ]
```
平台映射:
- **macOS**:launchd 用户代理 `ai.lark-channel-bridge.bot.`
- **Linux**:systemd 用户单元 `lark-channel-bridge.bot..service`
- **Windows**:任务计划程序任务 `LarkChannelBridge.Bot.`,通过 `.cmd` 包装器启动
Daemon 日志位于 `~/.lark-channel/profiles//logs/daemon/`。
### 多配置文件:Claude 和 Codex
默认情况下,bridge 会使用当前选定的配置文件启动。使用 `profile use ` 可进行更改。每个配置都保留其各自的应用凭证、会话、工作目录和日志。仅当您需要连接多个 PersonalAgent 应用,或将 Claude 和 Codex 作为独立的 bot 运行时,才创建多个配置文件:
```
lark-channel-bridge start --profile claude --agent claude
lark-channel-bridge start --profile codex --agent codex
```
例如,要仅重启 Codex bot:
```
lark-channel-bridge restart --profile codex
lark-channel-bridge status --profile codex
```
## 命令
### 宿主机 CLI
```
lark-channel-bridge run [--profile ] [--agent claude|codex] [--workspace ] [-c ]
lark-channel-bridge migrate [--profile ] [--agent claude|codex]
lark-channel-bridge ps
lark-channel-bridge kill
lark-channel-bridge --help
```
`profile use ` 会更改后续默认启动时使用的配置文件。在运行独立的 Claude / Codex bot、连接多个 PersonalAgent 应用或进行脚本化部署时,请使用这些配置文件管理命令:
```
lark-channel-bridge profile create claude --agent claude
lark-channel-bridge profile create codex --agent codex
lark-channel-bridge profile list
lark-channel-bridge profile use
lark-channel-bridge profile remove
lark-channel-bridge profile remove --purge --yes
lark-channel-bridge profile export [--output ./profile.json] [--force]
lark-channel-bridge profile export --include-secrets --yes
```
`profile remove` 默认会对本地状态进行归档,包括活跃的配置文件。如果还保留了其他配置文件,bridge 会切换到下一个;如果这是最后一个配置文件,根配置将被清除,以便可以再次创建同名文件。`--purge --yes` 会永久删除本地状态。`profile export` 默认会对 app secret 进行脱敏处理;`--include-secrets --yes` 则会包含敏感配置。
如果某个配置文件在创建时代理类型选择错误,请先停止或注销任何匹配的后台服务,然后运行 `profile remove ` 并使用预期的 `--agent` 重新创建。
### 飞书 / Lark 中的斜杠命令
| 命令 | 作用 |
|---|---|
| `/new`, `/reset` | 清除当前会话 |
| `/cd ` | 切换工作目录并重置会话 |
| `/ws list` | 列出已命名的工作区 |
| `/ws save ` | 将当前工作目录保存为已命名的工作区 |
| `/ws use ` | 切换到已命名的工作区 |
| `/ws remove ` | 删除已命名的工作区 |
| `/resume` | 为相同的代理、工作目录和权限模式恢复兼容的历史记录 |
| `/status` | 显示配置、代理、工作目录、会话、lark-cli 身份和运行状态 |
| `/config` | 调整展示偏好、访问设置和 lark-cli 身份策略 |
| `/invite user @name` | 允许某用户在私信中使用 bot |
| `/invite admin @name` | 添加访问控制管理员 |
| `/invite group` | 允许当前群组使用 bot |
| `/invite all group` | 允许 bot 已加入的所有群组使用 bot |
| `/remove user @name`, `/remove admin @name`, `/remove group` | 移除访问条目 |
| `/stop` | 停止当前运行,包括卡片停止按钮 |
| `/timeout [N\|off\|default]` | 设置或清除当前会话的空闲看门狗 |
| `/ps` | 列出本地 bridge 进程 |
| `/exit ` | 停止某个 bridge 进程 |
| `/reconnect` | 强制重新连接 WebSocket |
| `/doctor [description]` | 运行低敏感度诊断 |
| `/help` | 帮助卡片 |
私信不需要 @ 提及。群组和话题群组默认需要 `@bot`;`@all` 会被忽略。受支持文档类型中的云文档评论会在提及 bot 时触发运行。
## lark-cli 身份策略
每个配置使用位于 `~/.lark-channel/profiles//lark-cli` 的本地 lark-cli 目录。代理进程会为该目录接收 `LARKSUITE_CLI_CONFIG_DIR` 环境变量,因此一个配置中的个人授权不会与另一个配置共享。
默认策略是 `bot-only`:lark-cli 使用 app/bot 身份,并且不访问个人资源。当用户授权访问日历、邮件或云盘等个人资源时,当前配置可以切换为 `user-default`,这会保留 app 身份可用性,同时允许已授权的用户身份。所有者/管理员用户可以在 `/config` 中检查或更改此策略;`/status` 会将当前摘要显示为 `lark-cli: app` 或 `lark-cli: user-ready`。
## 工作目录
每个配置可以通过 `workspaces.default` 定义一个默认工作目录。在创建新配置时可以使用 `--workspace ` 指定;如果省略,bridge 会创建一个由配置管理的默认工作目录。
这是一个配置字段的代码片段。请勿用它替换整个 `config.json`;请编辑匹配配置的 `workspaces` 字段。
```
{
"workspaces": {
"default": "/Users/me/.lark-channel-workspaces/claude/default"
}
}
```
bridge 会检查所选目录是否存在、是否为目录,以及是否处于 `/`、家目录根、系统目录或临时根等过于宽泛的位置。工作目录仅仅是代理运行的当前目录。它不是文件系统沙盒;实际的文件访问权限仍然取决于本地代理进程及其权限模式。
## 权限模式
推荐给用户使用的配置项是 `permissions.defaultAccess` 和 `permissions.maxAccess`。新配置的这两个值默认都为 `full`,以便 bridge 能保持本地工具、授权流程、文件写入和其他代理功能完全可用。要收紧配置,请将其中一个或两个值设置为 `workspace` 或 `read-only`;更严格的模式可能会限制本地工具执行、登录/授权流程、文件写入及类似功能。
这是一个配置字段的代码片段。请勿用它替换整个 `config.json`;请编辑匹配配置的 `permissions` 字段。
```
{
"permissions": {
"defaultAccess": "full",
"maxAccess": "full"
}
}
```
模式映射:
| Bridge 访问权限 | Claude 权限模式 | Codex 模式 |
|---|---|---|
| `full` | `bypassPermissions` | `danger-full-access` |
| `workspace` | `acceptEdits` | `workspace-write` |
| `read-only` | `plan` | `read-only` |
旧版的 `sandbox` 字段对于旧配置仍然可读。在 bridge 保存配置文件后,它将该设置迁移至标准的 `permissions`。
## 数据目录
| 路径 | 内容 |
|---|---|
| `~/.lark-channel/config.json` | 包含配置和活跃配置的根配置文件 |
| `~/.lark-channel/active-profile` | 最后选择的配置 |
| `~/.lark-channel/profiles//sessions.json` | 会话状态 |
| `~/.lark-channel/profiles//sessions.json.catalog.json` | 感知代理的会话目录 |
| `~/.lark-channel/profiles//workspaces.json` | 当前和已命名的工作区绑定 |
| `~/.lark-channel/profiles//secrets.enc` | 本地配置的加密密钥 |
| `~/.lark-channel/profiles//lark-cli/` | 本地配置的 lark-cli 目录 |
| `~/.lark-channel/profiles//media/` | 附件缓存 |
| `~/.lark-channel/profiles//logs/` | 结构化运行日志 |
| `~/.lark-channel/registry/processes.json` | 本地进程注册表 |
| `~/.lark-channel/registry/locks/` | 配置和应用锁 |
设置 `LARK_CHANNEL_HOME=/path/to/state` 可移动所有本地 bridge 状态。`LARK_CHANNEL_LOG_DAYS` 可覆盖日志保留期。
## 访问控制
**聊天访问默认是私有的:开箱即用时,在私信和群组中只有*您*能使用该 bot。** “您” = 创建/拥有飞书应用的人(扫描二维码进行设置的人)。bot 会自动从飞书获取应用所有者的身份,因此**单人聊天无需任何配置** —— 您可以在任何群组中向它发送私信并 `@` 提及它,而其他所有人的聊天消息都会被静默忽略(不会回复“权限拒绝”,因为那只会证明 bot 的存在)。云文档评论是基于文档范围的;请参阅下文。
要让其他人或群组加入,请将他们添加到以下三个列表之一:
| 列表 | 控制内容 | 添加 | 移除 |
|------|----------|-----|--------|
| **允许的用户** | 谁可以向 bot 发送私信 | `/invite user @them` | `/remove user @them` |
| **允许的群组** | bot 会在哪些群组中回复(针对里面的**所有人**) | `/invite group`(当前群组) / `/invite all group`(bot 加入的所有群组) | `/remove group`(当前群组) |
| **管理员** | 谁可以更改设置,并在任何群组中使用 bot | `/invite admin @them` | `/remove admin @them` |
### 两种可绕过一切限制的身份
- **您(创建者)**:完全不受任何列表限制 —— 可发私信,进任何群组,执行所有命令。您**永远不会被自己锁在门外**:即使列表被弄乱了,向 bot 发送私信并带上 `/config` 即可重新进入。在飞书控制台转移应用所有权后,bot 会自动跟随新所有者。
- **管理员**:可以发送私信,运行如 `/config` 的管理命令,并且**绕过允许的群组列表** —— 无论是否被列入名单,bot 都会在任何群组中回复他们。适合共同维护 bot 的队友。
### 常见设置
- **只有我** → 什么都不用做;这是默认设置。
- **让队友向 bot 发私信** → `/invite user @them`
- **向群组所有人开放工作群** → 在该群组内发送 `/invite group`
- **首次设置,将 bot 已加入的所有群组都纳入白名单** → `/invite all group` 会一次性将它们全部拉入列表;之后可使用 `/remove group` 进行删减
- **添加共同管理员** → `/invite admin @them`
### 值得了解
- 更改将在**下一条消息**上生效 —— 无需重启。
- **在群组中,您必须先 `@` 提及 bot**(私信不需要)。这是一个单独的开关(`/config` → “在群组中要求 @”),独立于上述列表。
- 陌生人只会得到纯粹的沉默 —— 完全没有任何回复。唯一的例外是:如果有人在一个尚未开放的群组中 `@` 提及 bot,bot 会发布一条友好的简短提示,告诉他们管理员可以运行 `/invite group` 来启用它。
- 云文档评论的范围限定于文档:任何可以在受支持的文档中进行评论并提及 bot 的人,都可以触发回复。
### 进阶:直接编辑配置文件
如果您不想在飞书内部进行操作,`/invite` 和 `/config` 会写入 `~/.lark-channel/config.json` 中匹配配置的 `access` 字段。空列表表示该列表中没有任何人,而不是开放访问。这是一个配置字段的代码片段;请勿用它替换整个 `config.json`:
```
{
"schemaVersion": 2,
"profiles": {
"claude": {
"agentKind": "claude",
"access": {
"allowedUsers": ["ou_xxxxxxxxxxxxx"],
"allowedChats": ["oc_xxxxxxxxxxxxx"],
"admins": ["ou_xxxxxxxxxxxxx"],
"requireMentionInGroup": true
}
}
}
}
```
`allowedUsers` / `admins` 接受用户 `open_id`;`allowedChats` 接受群组 `chat_id`。手动查找 ID 最简单的方法是:让该用户向 bot 发送消息(或在群组中 `@` 它),然后检查活跃配置的日志:
```
grep '"event":"enter"' ~/.lark-channel/profiles//logs/bridge-$(date +%Y%m%d).jsonl | tail -5
```
每一行都包含 `chatId`(群组/私信 ID)和 `senderId`(用户 `open_id`)。手动编辑后,请**重启 bridge** 或在已授权的管理员上下文中发送 `/reconnect` 以使其生效。对于日常调整,使用 `/invite` / `/config` 会更简单;直接编辑主要用于预置访问权限的部署脚本。
## 云文档评论
云文档评论不需要单独的工作区绑定或文档白名单。在受支持的文档评论中提及 bot,bridge 就会在同一个话题中回复。评论运行会复用文档的会话密钥,并在之前没有记录文档当前工作目录时回退到用户主目录。
## 常见问题解答
**bot 毫无反应,或者本地 CLI 没有回复。** 通常是因为本地 `claude` 或 `codex` CLI 未登录,或者当前会话指向的工作目录已不存在。发送 `/status` 进行检查;`/new` 通常可以通过启动新会话来解决问题。
**代理子进程似乎卡住了(卡片停留在最后一帧)。** bridge 支持空闲看门狗:如果代理在 N 分钟内未输出任何内容,进程将被终止,并且卡片会注明自动终止的原因。默认禁用。使用 `/config` 进行全局启用,或使用 `/timeout 10` 为当前会话启用;`/timeout off` 会为此会话禁用;`/timeout default` 会清除会话覆盖设置。
**代理说它看不到我发送的图片。** 升级到最新版本。0.1.0 之前的版本存在文件名去重 bug。
## 测试与 CI
本地检查:
```
pnpm test
pnpm typecheck
pnpm build
```
`pnpm test` 包括单元测试、集成测试和进程级适配器测试。CI 在 macOS、Ubuntu 和 Windows 上运行,执行 `pnpm install --frozen-lockfile`、`pnpm test`、`pnpm typecheck` 和 `pnpm build`。
## 可选遥测
默认情况下,bridge 不会报告**任何内容**:不会有任何指标或日志离开您的计算机,并且它不引入任何遥测依赖项。除非您主动选择启用,否则以下钩子是不起作用的。
要接入您自己的监控系统,请将一个环境变量指向一个默认导出(或导出 `createAdapter`) `AdapterFactory` 的模块:
```
LARK_CHANNEL_TELEMETRY_MODULE=your-telemetry-package lark-channel-bridge start
```
该模块会接收每一个 `log.*` 事件以及错误/指标钩子,并将它们转发到您想要的任何地方。该接口从包的根目录导出:
```
import type { AdapterFactory, TelemetryAdapter, TelemetryEvent } from 'lark-channel-bridge';
const createAdapter: AdapterFactory = (meta) => ({
emit(event) {/* ship event */},
recordError(err, ctx) {/* ship exception */},
recordMetric(name, value, tags) {/* ship metric */},
flush(timeoutMs) {/* drain buffered events */},
});
export default createAdapter;
```
缺失的模块、错误的工厂或抛出异常的适配器都会降级为空操作 —— 遥测永远不会阻止 bridge 启动或破坏日志记录。
## 许可证
[MIT](./LICENSE)
标签:Claude Code, Codex CLI, MITM代理, 威胁情报, 开发者工具, 消息桥接, 自动化攻击, 飞书