@fullstackjam/lark-coding-agent-bridge
v0.3.2
Published
Fork of zarazhangrui/lark-coding-agent-bridge with opencode adapter added
Maintainers
Readme
@fullstackjam/lark-coding-agent-bridge
zarazhangrui/lark-coding-agent-bridge 的私人 fork(上游 npm 包名
lark-channel-bridge)。fork 存在的理由:在上游 Claude Code 与 Codex adapter 旁边再加一个 opencode adapter。下面大部分文档沿用上游内容,fork 特有改动会在行内标注。
把飞书 / Lark 消息和本地 Claude Code、Codex 或 opencode CLI 打通的轻量 bot。用一条命令启动,扫码绑定 PersonalAgent 应用,然后在飞书里和本机编程助手对话,让它读图、处理文件、改代码。
关于能实现的效果,详情可以阅读飞书文档
主要功能
- 在飞书私聊直接发消息,或在群里
@bot,把任务转给本机 Claude Code / Codex / opencode CLI。 - 流式卡片:文本回复和工具调用实时更新在同一张卡片上。
- 会话延续:每个聊天、话题或文档评论有自己的会话,不会互相串。
- 排队与消息合并:短时间连续发送的消息会合并处理;任务运行中收到的普通消息会排队到下一轮,
/new、/cd、/ws use、/stop这类命令可以中断当前任务。 - 多工作空间:用
/cd切换当前项目,用/ws保存和复用常用项目目录。 - 图片 / 文件:直接发给 bot,bridge 下载到本地后交给本机 agent 处理。
- 卡片按钮:
/help、/ws list、/status返回可点击的交互卡片。
前置条件
- Node.js >= 20.12.0
- 本机至少安装并登录一个 agent:
- Claude Code:
claude,安装说明:https://docs.anthropic.com/en/docs/claude-code/quickstart - Codex CLI:
codex,安装说明:https://developers.openai.com/codex/cli - opencode CLI:
opencode,安装说明:https://opencode.ai/docs/
- Claude Code:
- 一个飞书 / Lark PersonalAgent 应用。首次启动的扫码向导可以帮你创建并绑定。
安装
npm i -g @fullstackjam/lark-coding-agent-bridge
# 或
pnpm add -g @fullstackjam/lark-coding-agent-bridge安装后实际可用的 CLI 命令仍然是 lark-channel-bridge,与上游保持兼容。
首次启动
lark-channel-bridge run第一次运行会进入扫码向导:
- 终端渲染二维码。
- 用飞书 App 扫码。
- 选择或创建 PersonalAgent 应用。
- 如果终端提示,选择本次要初始化的 agent。
- 成功后配置写入
~/.lark-channel/config.json。
没有指定项目目录也可以启动。bridge 会创建一个 profile 托管的默认工作目录;启动后在飞书里发送 /cd <path> 切到实际项目。
如果已经有 PersonalAgent app,可以在初始化时传 --app-id 跳过创建应用流程;命令会提示输入 App Secret。
lark-channel-bridge run --app-id cli_xxx
# 或直接初始化并启动后台服务
lark-channel-bridge start --app-id cli_xxxLark 国际版应用可加 --tenant lark。
后台运行
run 适合首次配置和前台调试。确认 bot 能正常收发消息后,先用 Ctrl-C 停掉前台进程,再用系统服务常驻后台:
lark-channel-bridge start
lark-channel-bridge status
lark-channel-bridge stop服务层命令必须先全局安装,不能直接用 npx。daemon 的 launchd plist / systemd unit / Windows 任务会记录 bridge CLI 的路径;如果这个路径来自 npm 临时缓存,缓存清掉后 daemon 就起不来。run 用 npx 单次启动没问题。
服务层命令按 profile 注册,每个 profile 有独立服务:
lark-channel-bridge start [--profile <name>]
lark-channel-bridge stop [--profile <name>]
lark-channel-bridge restart [--profile <name>]
lark-channel-bridge status [--profile <name>]
lark-channel-bridge unregister [--profile <name>]平台映射:
- macOS:launchd 用户代理
ai.lark-channel-bridge.bot.<profile> - Linux:systemd 用户单元
lark-channel-bridge.bot.<profile>.service - Windows:Task Scheduler 任务
LarkChannelBridge.Bot.<profile>,launcher 是.cmd
daemon 日志在 ~/.lark-channel/profiles/<profile>/logs/daemon/。
多 profile:分别运行 Claude、Codex 和 opencode
默认情况下,bridge 使用当前激活的 profile;可以通过 profile use <name> 切换。每个 profile 会维护独立的应用凭据、会话、工作目录和日志。只有在需要同时连接多个 PersonalAgent 应用,或分别运行 Claude、Codex 和 opencode 时,才需要创建多个 profile:
lark-channel-bridge start --profile claude --agent claude
lark-channel-bridge start --profile codex --agent codex
lark-channel-bridge start --profile opencode --agent opencode例如只重启 Codex bot:
lark-channel-bridge restart --profile codex
lark-channel-bridge status --profile codex命令速查
宿主 CLI
lark-channel-bridge run [--profile <name>] [--agent claude|codex|opencode] [--workspace <path>] [-c <config>]
lark-channel-bridge migrate [--profile <name>] [--agent claude|codex|opencode]
lark-channel-bridge ps
lark-channel-bridge kill <id|#>
lark-channel-bridge --helpprofile use <name> 会切换后续默认启动使用的 profile。需要同时跑 Claude / Codex / opencode 多个 bot、连接多套 PersonalAgent 应用,或做脚本化部署时,再使用这些 profile 管理命令:
lark-channel-bridge profile create claude --agent claude
lark-channel-bridge profile create codex --agent codex
lark-channel-bridge profile create opencode --agent opencode
lark-channel-bridge profile list
lark-channel-bridge profile use <name>
lark-channel-bridge profile remove <name>
lark-channel-bridge profile remove <name> --purge --yes
lark-channel-bridge profile export <name> [--output ./profile.json] [--force]
lark-channel-bridge profile export <name> --include-secrets --yesprofile remove 默认归档本地状态,也可以删除当前激活的 profile。若还剩其他 profile,会自动切到下一个;若这是最后一个 profile,会清空 root config,之后可以用同名重新创建。只有加 --purge --yes 才会永久删除。profile export 默认脱敏 app secret;只有加 --include-secrets --yes 才会导出敏感配置。
如果某个 profile 被建成了错误的 agent 类型,先 stop 或 unregister --profile <name> 清理对应后台服务,再 profile remove <name>,然后用正确的 --agent 重新创建。
飞书内斜杠命令
| 命令 | 作用 |
|---|---|
| /new, /reset | 清空当前会话 |
| /cd <path> | 切换工作目录并重置会话 |
| /ws list | 列出命名工作空间 |
| /ws save <name> | 把当前工作目录保存为命名工作空间 |
| /ws use <name> | 切换到命名工作空间 |
| /ws remove <name> | 删除命名工作空间 |
| /resume | 恢复同 agent、工作目录、权限模式兼容的历史会话 |
| /status | 查看 profile、agent、工作目录、会话、lark-cli 身份和运行状态 |
| /config | 调整展示偏好、访问控制和 lark-cli 身份策略 |
| /invite user @某人 | 允许用户私聊使用 bot |
| /invite admin @某人 | 添加访问控制管理员 |
| /invite group | 允许当前群使用 bot |
| /invite all group | 允许 bot 所在的所有群使用 |
| /remove user @某人, /remove admin @某人, /remove group | 移除访问控制条目 |
| /stop | 停止当前 run,也可点卡片停止按钮 |
| /timeout [N\|off\|default] | 设置或清除当前会话的 idle watchdog |
| /ps | 列出本机 bridge 进程 |
| /exit <id\|#> | 停止指定 bridge 进程 |
| /reconnect | 强制 WebSocket 重连 |
| /doctor [描述] | 执行低敏诊断 |
| /help | 帮助卡片 |
私聊不需要 @。群和话题群默认必须 @bot;@all 会被忽略。支持的云文档评论里 @bot 就会触发回复。
lark-cli 身份策略
每个 profile 都使用当前 profile 的 lark-cli 目录:~/.lark-channel/profiles/<profile>/lark-cli。agent 子进程会收到指向这个目录的 LARKSUITE_CLI_CONFIG_DIR,所以一个 profile 里的个人授权不会共享给另一个 profile。
默认策略是 bot-only:lark-cli 使用应用 / bot 身份,不访问个人资源。当用户为了日历、邮箱、云盘等个人资源完成授权后,当前 profile 可以切到 user-default,保留应用身份,同时允许已授权的用户身份。owner/admin 可以在 /config 查看或切换这个策略;/status 会用 lark-cli: app 或 lark-cli: user-ready 展示当前摘要。
工作目录
每个 profile 都可以有一个默认工作目录:workspaces.default。新建 profile 时可以传 --workspace <path> 作为初始目录;没传时 bridge 会创建一个 profile 托管的默认工作目录。
下面只是 profile 里的字段片段,不要整段覆盖 config.json;请改对应 profile 下的 workspaces 字段。
{
"workspaces": {
"default": "/Users/me/.lark-channel-workspaces/claude/default"
}
}bridge 会检查所选目录存在、是目录,并且不是 /、Home 根、系统目录或临时目录根这类范围过大的位置。工作目录只是 agent run 的当前目录,不是文件系统 sandbox;agent 实际能访问哪些文件仍取决于本机 agent 进程及其权限模式。
权限模式
推荐给用户配置的是 permissions.defaultAccess 和 permissions.maxAccess。新 profile 默认两项都是 full,以保持 bridge 的本地工具、授权流程、文件写入等能力完整可用。如需收紧权限,可以改成 workspace 或 read-only;收紧后本地工具执行、登录 / 授权流程、文件写入等能力可能受限。
下面只是 profile 里的字段片段,不要整段覆盖 config.json;请改对应 profile 下的 permissions 字段。
{
"permissions": {
"defaultAccess": "full",
"maxAccess": "full"
}
}模式映射:
| Bridge access | Claude permission mode | Codex mode |
|---|---|---|
| full | bypassPermissions | danger-full-access |
| workspace | acceptEdits | workspace-write |
| read-only | plan | read-only |
旧版 sandbox 字段仍可读取。bridge 保存 profile 后,会把该设置迁移为 canonical permissions。
数据目录
| 路径 | 内容 |
|---|---|
| ~/.lark-channel/config.json | root config,包含 profiles 和 active profile |
| ~/.lark-channel/active-profile | 最近选择的 profile |
| ~/.lark-channel/profiles/<profile>/sessions.json | 会话状态 |
| ~/.lark-channel/profiles/<profile>/sessions.json.catalog.json | agent-aware 会话索引 |
| ~/.lark-channel/profiles/<profile>/workspaces.json | 当前和命名工作空间绑定 |
| ~/.lark-channel/profiles/<profile>/secrets.enc | profile 本地加密 secret |
| ~/.lark-channel/profiles/<profile>/lark-cli/ | 当前 profile 的 lark-cli 目录 |
| ~/.lark-channel/profiles/<profile>/media/ | 附件缓存 |
| ~/.lark-channel/profiles/<profile>/logs/ | 结构化运行日志 |
| ~/.lark-channel/registry/processes.json | 本机进程注册表 |
| ~/.lark-channel/registry/locks/ | profile lock 和 app lock |
设置 LARK_CHANNEL_HOME=/path/to/state 可以迁移整棵本地状态目录。LARK_CHANNEL_LOG_DAYS 可以调整日志保留天数。
访问控制
聊天访问默认是私有的:开箱即用时,只有"你"能在私聊和群聊里用这个 bot。 这里的"你" = 创建 / 拥有这个飞书应用的人(也就是扫码把 bot 建起来的那位)。bot 会自动从飞书查出谁是应用 owner,所以一个人用聊天入口完全不用配置——你私聊它、在任意群里 @它都正常工作,其他人的聊天消息会被静默忽略(bot 不会回"你没权限",免得暴露自己的存在)。云文档评论按文档权限生效,见下文。
想让别的同事或某些群也能用,就把他们加进下面三类名单:
| 名单 | 控制谁 | 加入 | 移除 |
|------|--------|------|------|
| 允许私聊的用户 | 谁可以私聊 bot | /invite user @某人 | /remove user @某人 |
| 响应的群 | bot 在哪些群里对群内所有人响应 | /invite group(当前群)/ /invite all group(bot 所在的全部群) | /remove group(当前群) |
| 管理员 | 谁能改设置、并能在任意群用 bot | /invite admin @某人 | /remove admin @某人 |
/invite、/remove这些命令只有你(创建者)和管理员能发。命令里 @ 的是对方(不是 @ bot),bot 会自动把 @ 解析成对应的人,你不用手动去找 ID。
两种"畅通无阻"的身份
- 你(创建者):不受任何名单限制——私聊、任意群、所有命令都能用,而且永远锁不死自己:哪怕名单配乱了,回到 bot 私聊发
/config总能进来。在飞书后台把应用 owner 转给别人后,bot 也会自动跟着切换。 - 管理员:能私聊、能用
/config等管理命令,而且不受"响应的群"名单限制——无论群在不在名单里,bot 都会回他们。适合给一起维护 bot 的同事。
几种常见配置
- 只给自己用 → 什么都不用做,默认就是。
- 让某个同事能私聊 bot →
/invite user @他 - 让某个工作群里所有人都能用 → 在那个群里发
/invite group - 第一次配,想把 bot 已经在的群一次性全开放 → 发
/invite all group一键拉取 bot 所在的全部群加入名单,之后再用/remove group删掉不想要的 - 再拉个人一起当管理员 →
/invite admin @他
还需要知道的
- 改完下一条消息就生效,不用重启。
- 群里默认要先 @bot 才会回(私聊不用 @)。这是另一个独立开关(
/config→"群里需要 @ bot"),和上面的名单是两回事。 - 陌生人发消息一律静默丢弃,不会有任何回复。唯一的例外:有人在一个还没开放的群里 @bot,bot 会回一句友好提示,告诉他可以让管理员发
/invite group开放这个群。 - 云文档评论按文档权限生效:能在支持的文档里评论并 @bot 的人可以触发回复。
高级:直接改配置文件
不想在飞书里点的话,/invite、/config 背后写的是 ~/.lark-channel/config.json 中对应 profile 的 access 字段。空白名单表示这个名单没人,不表示所有人都能用。下面只是 profile 里的字段片段,不要整段覆盖 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 发条消息(群里就 @ 它一下),然后看当前 profile 的日志:
grep '"event":"enter"' ~/.lark-channel/profiles/<profile>/logs/bridge-$(date +%Y%m%d).jsonl | tail -5每行都带 chatId(群 / 私聊 ID)和 senderId(用户 open_id)。手改完后重启 bridge,或在允许的 admin 上下文里发 /reconnect 让它生效。日常调整还是 /invite / /config 更省事,直接改文件主要用于部署脚本预填。
云文档评论
云文档评论不再需要单独绑定工作目录或维护文档白名单。支持的文档评论里 @bot 后,bridge 会在同一个评论线程里回复。评论运行复用文档级 session key;没有记录过文档 cwd 时回退到用户 home 目录。
常见问题
bot 没反应 / agent 不回复:通常是本机 claude、codex 或 opencode CLI 没登录,或者当前会话指向了不存在的工作目录。发 /status 看当前状态;/new 重开会话往往就好。
agent 子进程假死(卡片停在最后一帧不动):支持 idle 探活。agent 一段时间没输出就会被 SIGTERM kill,卡片末尾会标出自动终止原因。默认关闭。开启方式:/config 设全局值(分钟),或 /timeout 10 只对当前会话生效;/timeout off 关掉当前会话的探活;/timeout default 清掉会话覆盖,回退到全局设置。
图片发过去 agent 说看不到:升级到最新版,0.1.0 之前的版本有文件名去重 bug。
测试与 CI
本地检查:
pnpm test
pnpm typecheck
pnpm buildpnpm test 包含 unit、integration 和 process-level adapter 测试。CI 在 macOS、Ubuntu、Windows 上执行 pnpm install --frozen-lockfile、pnpm test、pnpm typecheck 和 pnpm build。
可选:遥测(Telemetry)
默认情况下 bridge 不上报任何数据:没有指标、没有日志离开你的机器,也不引入任何遥测依赖。下面这个钩子在你主动开启前完全是空操作。
想接自己的监控时,用环境变量指向一个 default export(或导出 createAdapter)AdapterFactory 的模块:
LARK_CHANNEL_TELEMETRY_MODULE=your-telemetry-package lark-channel-bridge start该模块会收到每一条 log.* 事件,以及错误 / 指标钩子,转发到任何你想要的地方。接口从包根导出:
import type { AdapterFactory, TelemetryAdapter, TelemetryEvent } from '@fullstackjam/lark-coding-agent-bridge';
const createAdapter: AdapterFactory = (meta) => ({
emit(event) {/* 上报事件 */},
recordError(err, ctx) {/* 上报异常 */},
recordMetric(name, value, tags) {/* 上报指标 */},
flush(timeoutMs) {/* 冲刷缓冲事件 */},
});
export default createAdapter;模块不存在、工厂函数不合法、或者 adapter 抛错,都会降级为空操作——遥测永远不会阻止 bridge 启动,也不会打断日志。
