@masterxinxin/lark-coding-agent-bridge 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +480 -2
- package/README.zh.md +479 -0
- package/bin/lark-channel-bridge.mjs +2 -0
- package/dist/cli.js +23880 -0
- package/dist/index.d.ts +212 -0
- package/dist/index.js +817 -0
- package/package.json +101 -3
package/README.zh.md
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# @masterxinxin/lark-coding-agent-bridge
|
|
2
|
+
|
|
3
|
+
> **[zarazhangrui/lark-coding-agent-bridge](https://github.com/zarazhangrui/lark-coding-agent-bridge) 的私人 fork**(上游 npm 包名 `lark-channel-bridge`)。fork 存在的理由:在上游 Claude Code 与 Codex adapter 旁边再加一个 **opencode** adapter。下面大部分文档沿用上游内容,fork 特有改动会在行内标注。
|
|
4
|
+
|
|
5
|
+
把飞书 / Lark 消息和本地 Claude Code、Codex 或 opencode CLI 打通的轻量 bot。用一条命令启动,扫码绑定 PersonalAgent 应用,然后在飞书里和本机编程助手对话,让它读图、处理文件、改代码。
|
|
6
|
+
|
|
7
|
+
[English README](./README.md)
|
|
8
|
+
|
|
9
|
+
关于能实现的效果,详情可以阅读[飞书文档](https://larkcommunity.feishu.cn/docx/OaRIdFIRFoLM3xxTmKwcetHqn5e)
|
|
10
|
+
|
|
11
|
+
## 主要功能
|
|
12
|
+
|
|
13
|
+
- 在飞书私聊直接发消息,或在群里 `@bot`,把任务转给本机 Claude Code / Codex / opencode CLI。
|
|
14
|
+
- **流式卡片**:文本回复和工具调用实时更新在同一张卡片上。
|
|
15
|
+
- **COT 过程消息**:可选先发一条过程消息展示 agent 的阶段性文本和工具调用,再单独发送最终答案。
|
|
16
|
+
- **会话延续**:每个聊天、话题或文档评论有自己的会话,不会互相串。
|
|
17
|
+
- **排队与消息合并**:短时间连续发送的消息会合并处理;任务运行中收到的普通消息会排队到下一轮,`/new`、`/cd`、`/ws use`、`/stop` 这类命令可以中断当前任务。
|
|
18
|
+
- **多工作空间**:用 `/cd` 切换当前项目,用 `/ws` 保存和复用常用项目目录。
|
|
19
|
+
- **图片 / 文件**:直接发给 bot,bridge 下载到本地后交给本机 agent 处理。
|
|
20
|
+
- **卡片按钮**:`/help`、`/ws list`、`/status` 返回可点击的交互卡片。
|
|
21
|
+
|
|
22
|
+
## Fork 在上游基础上增加的能力
|
|
23
|
+
|
|
24
|
+
上游已经把 Claude Code / Codex 接得很完整了。本 fork 主要补 **opencode 这条线**,并围绕它加了一些跨 agent 的体验改进:
|
|
25
|
+
|
|
26
|
+
| 增量 | 价值 | 谁能用 |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| **opencode adapter** | 上游只支持 Claude / Codex;本 fork 把 opencode 接成第三种 agent,复用全部上游能力(profile / workspace / 权限模式 / 卡片)。 | opencode profile |
|
|
29
|
+
| **持久 opencode 会话** | 同一个聊天的多轮消息复用同一个 opencode session,agent 记得上下文。否则每条消息都是新 session,上下文丢失。 | opencode |
|
|
30
|
+
| **后台任务唤醒卡片** | 装了 `oh-my-openagent` 插件后,它在后台跑完任务能"主动"在飞书弹一张新卡片续聊,不需要你再问一次。 | opencode + oh-my-openagent |
|
|
31
|
+
| **Interactive permission 卡片** | opencode 弹 `permission.asked` 时,bridge 用卡片让你点"允许一次 / 始终允许 / 拒绝",5 分钟超时自动拒绝。 | opencode |
|
|
32
|
+
| **`/new chat <name>` 自建群** | 一条命令拉一个新群,bot 是群主,发起人登记成 owner,**群里无需 @ bot 即可触发回复**——类似 [`lark-opencode-bridge`](https://github.com/fullstackjam/lark-opencode-bridge) 的 `/spawn` 体验。 | 所有 agent |
|
|
33
|
+
| **工具调用展示** | 工具卡片读取 opencode 的 `state.title`:`✅ read — src/foo.ts` 而不是裸的 `✅ read`;大小写不敏感的工具名 + camelCase fallback。 | 所有 agent,opencode 收益最大 |
|
|
34
|
+
|
|
35
|
+
### 数据流
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
User([飞书 / Lark 用户])
|
|
40
|
+
Lark[飞书 WS<br/>长连接]
|
|
41
|
+
Bridge[lark-channel-bridge<br/>本机 daemon]
|
|
42
|
+
Agent[Claude / Codex / opencode<br/>本机 CLI]
|
|
43
|
+
|
|
44
|
+
User -- 消息 / 图片 --> Lark
|
|
45
|
+
Lark -- 推送事件 --> Bridge
|
|
46
|
+
Bridge -- prompt / stdin --> Agent
|
|
47
|
+
Agent -- 流式事件 --> Bridge
|
|
48
|
+
Bridge -- 流式卡片 --> Lark
|
|
49
|
+
Lark -- 渲染卡片 --> User
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
代码和模型执行**始终在你本机**;飞书侧只负责消息传递和卡片渲染。
|
|
53
|
+
|
|
54
|
+
### opencode 多轮会话 + 后台任务唤醒
|
|
55
|
+
|
|
56
|
+
```mermaid
|
|
57
|
+
sequenceDiagram
|
|
58
|
+
autonumber
|
|
59
|
+
participant U as 用户
|
|
60
|
+
participant B as Bridge
|
|
61
|
+
participant O as opencode serve
|
|
62
|
+
participant P as oh-my-openagent
|
|
63
|
+
|
|
64
|
+
U->>B: "查一下 X,慢慢做"
|
|
65
|
+
B->>O: createSession + prompt_async
|
|
66
|
+
O-->>B: SSE: text / tool / status:idle
|
|
67
|
+
B->>U: 卡片 (turn 1 完成)
|
|
68
|
+
|
|
69
|
+
Note over O,P: 后台任务跑着<br/>(LSP 索引 / 长查询)
|
|
70
|
+
|
|
71
|
+
P->>O: notifyParentSession<br/>(prompt_async 注入合成 user msg)
|
|
72
|
+
O-->>B: SSE: 新 message.updated
|
|
73
|
+
B->>U: 新卡片<br/>🔔 后台任务完成后由 agent 主动接续
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
关键点:
|
|
77
|
+
|
|
78
|
+
- Bridge 每个聊天维护一个长连 SSE consumer,opencode session 在多轮消息间复用——`/new` 或 `/cd` 才换 session。
|
|
79
|
+
- 后台 wake-up 通过 SSE 事件的 messageID 去识别(trailing re-broadcast 会被 dedupe,避免空卡片)。
|
|
80
|
+
- 卡片走 `processAgentStream + channel.stream`——和用户消息走同一条渲染管道,文字、工具、permission 卡片、停止按钮都和正常 turn 一致。
|
|
81
|
+
|
|
82
|
+
### `/new chat`:直接拉个工作群
|
|
83
|
+
|
|
84
|
+
灵感来源是 [`lark-opencode-bridge`](https://github.com/fullstackjam/lark-opencode-bridge) 的 `/spawn`。一个群 = 一个独立 session = 一份项目上下文。
|
|
85
|
+
|
|
86
|
+
```mermaid
|
|
87
|
+
flowchart TD
|
|
88
|
+
A["/new chat workbench"] --> B[bridge 调 lark<br/>im.chat.create]
|
|
89
|
+
B --> C[新群: bot 是群主<br/>邀请发起人]
|
|
90
|
+
C --> D[workbenchGroups<br/>chatId → 发起人 openId]
|
|
91
|
+
D --> E[群里发起人发任意消息<br/>**不需要 @ bot**]
|
|
92
|
+
E --> F{shouldTriggerWorkbenchMessage}
|
|
93
|
+
F -- senderId == owner --> G[触发 run]
|
|
94
|
+
F -- @ 了其他人 --> H[跳过]
|
|
95
|
+
F -- 回复非 bot 消息 --> H
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
工作机制:
|
|
99
|
+
|
|
100
|
+
1. `/new chat <name>` 在飞书里建群,bridge 作为群主,把发起人邀请进去。
|
|
101
|
+
2. cwd 继承自原聊天的工作目录(`/cd` 切过的会带过去)。
|
|
102
|
+
3. "chatId → 发起人 openId" 写进 `workbenchGroups` (持久化到 `config.json`)。
|
|
103
|
+
4. 发起人在群里发任何消息(不需要 @)都会触发 run;@ 了别人或回复非 bot 消息会跳过。
|
|
104
|
+
|
|
105
|
+
> ⚠️ **需要飞书"群消息读取"权限**:默认情况下飞书只把"群里 @ bot"的消息推给应用。要让"owner 无需 @ 即可触发"真的生效,**必须在飞书开放平台后台给应用加 `im:message.group_msg:readonly` 权限**("获取群组中所有消息")并通过审批。这是飞书侧的高级权限,没有的话 bridge 这边逻辑写得再对也收不到事件。验证方法:群里发条非 @ 消息,看 `~/.lark-channel/profiles/<profile>/logs/bridge-$(date +%Y%m%d).jsonl` 里有没有对应的 `intake.enter` 条目,没有就是 Lark 没推过来。
|
|
106
|
+
|
|
107
|
+
## 前置条件
|
|
108
|
+
|
|
109
|
+
- Node.js **>= 20.12.0**
|
|
110
|
+
- 本机至少安装并登录一个 agent:
|
|
111
|
+
- Claude Code:`claude`,安装说明:https://docs.anthropic.com/en/docs/claude-code/quickstart
|
|
112
|
+
- Codex CLI:`codex`,安装说明:https://developers.openai.com/codex/cli
|
|
113
|
+
- opencode CLI:`opencode`,安装说明:https://opencode.ai/docs/
|
|
114
|
+
- 一个飞书 / Lark PersonalAgent 应用。首次启动的扫码向导可以帮你创建并绑定。
|
|
115
|
+
|
|
116
|
+
## 安装
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm i -g @masterxinxin/lark-coding-agent-bridge
|
|
120
|
+
# 或
|
|
121
|
+
pnpm add -g @masterxinxin/lark-coding-agent-bridge
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
安装后实际可用的 CLI 命令仍然是 `lark-channel-bridge`,与上游保持兼容。
|
|
125
|
+
|
|
126
|
+
## 首次启动
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
lark-channel-bridge run
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
第一次运行会进入扫码向导:
|
|
133
|
+
|
|
134
|
+
1. 终端渲染二维码。
|
|
135
|
+
2. 用飞书 App 扫码。
|
|
136
|
+
3. 选择或创建 PersonalAgent 应用。
|
|
137
|
+
4. 如果终端提示,选择本次要初始化的 agent。
|
|
138
|
+
5. 成功后配置写入 `~/.lark-channel/config.json`。
|
|
139
|
+
|
|
140
|
+
没有指定项目目录也可以启动。bridge 会创建一个 profile 托管的默认工作目录;启动后在飞书里发送 `/cd <path>` 切到实际项目。
|
|
141
|
+
|
|
142
|
+
如果已经有 PersonalAgent app,可以在初始化时传 `--app-id` 跳过创建应用流程;命令会提示输入 App Secret。
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
lark-channel-bridge run --app-id cli_xxx
|
|
146
|
+
# 或直接初始化并启动后台服务
|
|
147
|
+
lark-channel-bridge start --app-id cli_xxx
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Lark 国际版应用可加 `--tenant lark`。
|
|
151
|
+
|
|
152
|
+
## 后台运行
|
|
153
|
+
|
|
154
|
+
`run` 适合首次配置和前台调试。确认 bot 能正常收发消息后,先用 `Ctrl-C` 停掉前台进程,再用系统服务常驻后台:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
lark-channel-bridge start
|
|
158
|
+
lark-channel-bridge status
|
|
159
|
+
lark-channel-bridge stop
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
服务层命令必须先全局安装,不能直接用 `npx`。daemon 的 launchd plist / systemd unit / Windows 任务会记录 bridge CLI 的路径;如果这个路径来自 npm 临时缓存,缓存清掉后 daemon 就起不来。`run` 用 `npx` 单次启动没问题。
|
|
163
|
+
|
|
164
|
+
服务层命令按 profile 注册,每个 profile 有独立服务:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
lark-channel-bridge start [--profile <name>]
|
|
168
|
+
lark-channel-bridge stop [--profile <name>]
|
|
169
|
+
lark-channel-bridge restart [--profile <name>]
|
|
170
|
+
lark-channel-bridge status [--profile <name>]
|
|
171
|
+
lark-channel-bridge unregister [--profile <name>]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
平台映射:
|
|
175
|
+
- **macOS**:launchd 用户代理 `ai.lark-channel-bridge.bot.<profile>`
|
|
176
|
+
- **Linux**:systemd 用户单元 `lark-channel-bridge.bot.<profile>.service`
|
|
177
|
+
- **Windows**:Task Scheduler 任务 `LarkChannelBridge.Bot.<profile>`,launcher 是 `.cmd`
|
|
178
|
+
|
|
179
|
+
daemon 日志在 `~/.lark-channel/profiles/<profile>/logs/daemon/`。
|
|
180
|
+
|
|
181
|
+
### 多 profile:分别运行 Claude、Codex 和 opencode
|
|
182
|
+
|
|
183
|
+
默认情况下,bridge 使用当前激活的 profile;可以通过 `profile use <name>` 切换。每个 profile 会维护独立的应用凭据、会话、工作目录和日志。只有在需要同时连接多个 PersonalAgent 应用,或分别运行 Claude、Codex 和 opencode 时,才需要创建多个 profile:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
lark-channel-bridge start --profile claude --agent claude
|
|
187
|
+
lark-channel-bridge start --profile codex --agent codex
|
|
188
|
+
lark-channel-bridge start --profile opencode --agent opencode
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
例如只重启 Codex bot:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
lark-channel-bridge restart --profile codex
|
|
195
|
+
lark-channel-bridge status --profile codex
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## 命令速查
|
|
199
|
+
|
|
200
|
+
### 宿主 CLI
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
lark-channel-bridge run [--profile <name>] [--agent claude|codex|opencode] [--workspace <path>] [-c <config>]
|
|
204
|
+
lark-channel-bridge migrate [--profile <name>] [--agent claude|codex|opencode]
|
|
205
|
+
lark-channel-bridge ps
|
|
206
|
+
lark-channel-bridge kill <id|#>
|
|
207
|
+
lark-channel-bridge --help
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`profile use <name>` 会切换后续默认启动使用的 profile。需要同时跑 Claude / Codex / opencode 多个 bot、连接多套 PersonalAgent 应用,或做脚本化部署时,再使用这些 profile 管理命令:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
lark-channel-bridge profile create claude --agent claude
|
|
214
|
+
lark-channel-bridge profile create codex --agent codex
|
|
215
|
+
lark-channel-bridge profile create opencode --agent opencode
|
|
216
|
+
lark-channel-bridge profile list
|
|
217
|
+
lark-channel-bridge profile use <name>
|
|
218
|
+
lark-channel-bridge profile remove <name>
|
|
219
|
+
lark-channel-bridge profile remove <name> --purge --yes
|
|
220
|
+
lark-channel-bridge profile export <name> [--output ./profile.json] [--force]
|
|
221
|
+
lark-channel-bridge profile export <name> --include-secrets --yes
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`profile remove` 默认归档本地状态,也可以删除当前激活的 profile。若还剩其他 profile,会自动切到下一个;若这是最后一个 profile,会清空 root config,之后可以用同名重新创建。只有加 `--purge --yes` 才会永久删除。`profile export` 默认脱敏 app secret;只有加 `--include-secrets --yes` 才会导出敏感配置。
|
|
225
|
+
|
|
226
|
+
如果某个 profile 被建成了错误的 agent 类型,先 `stop` 或 `unregister --profile <name>` 清理对应后台服务,再 `profile remove <name>`,然后用正确的 `--agent` 重新创建。
|
|
227
|
+
|
|
228
|
+
### 飞书内斜杠命令
|
|
229
|
+
|
|
230
|
+
| 命令 | 作用 |
|
|
231
|
+
|---|---|
|
|
232
|
+
| `/new`, `/reset` | 清空当前会话 |
|
|
233
|
+
| `/new chat [name]` | 拉个新群、bot 是群主、发起人是 owner(fork 新增;详见 "Fork 增量功能 → `/new chat`") |
|
|
234
|
+
| `/cd <path>` | 切换工作目录并重置会话 |
|
|
235
|
+
| `/ws list` | 列出命名工作空间 |
|
|
236
|
+
| `/ws save <name>` | 把当前工作目录保存为命名工作空间 |
|
|
237
|
+
| `/ws use <name>` | 切换到命名工作空间 |
|
|
238
|
+
| `/ws remove <name>` | 删除命名工作空间 |
|
|
239
|
+
| `/ws dir <路径>` | 设置 profile 的默认工作空间目录(新项目默认在此检出) |
|
|
240
|
+
| `/ws pull [项目名]` | 立即拉取全部(或指定)项目 |
|
|
241
|
+
| `/ws schedule on\|off\|<分钟>` | 开启 / 关闭定时拉取,或设置间隔(5–1440 分钟) |
|
|
242
|
+
| `/project add <地址> [分支]` | 手动添加一个项目并检出 |
|
|
243
|
+
| `/project rm <名字>` | 移除项目记录(**不**删除磁盘目录) |
|
|
244
|
+
| `/project branch <名字> <分支>` | 把项目检出切换到另一个分支 |
|
|
245
|
+
| `/resume` | 恢复同 agent、工作目录、权限模式兼容的历史会话 |
|
|
246
|
+
| `/status` | 查看 profile、agent、工作目录、会话、lark-cli 身份和运行状态 |
|
|
247
|
+
| `/config` | 调整展示偏好、访问控制和 lark-cli 身份策略(工作空间 / Git 项目在控制台配置) |
|
|
248
|
+
| `/invite user @某人` | 允许用户私聊使用 bot |
|
|
249
|
+
| `/invite admin @某人` | 添加访问控制管理员 |
|
|
250
|
+
| `/invite group` | 允许当前群使用 bot |
|
|
251
|
+
| `/invite all group` | 允许 bot 所在的所有群使用 |
|
|
252
|
+
| `/remove user @某人`, `/remove admin @某人`, `/remove group` | 移除访问控制条目 |
|
|
253
|
+
| `/stop` | 停止当前 run,也可点卡片停止按钮 |
|
|
254
|
+
| `/timeout [N\|off\|default]` | 设置或清除当前会话的 idle watchdog |
|
|
255
|
+
| `/ps` | 列出本机 bridge 进程 |
|
|
256
|
+
| `/exit <id\|#>` | 停止指定 bridge 进程 |
|
|
257
|
+
| `/reconnect` | 强制 WebSocket 重连 |
|
|
258
|
+
| `/doctor [描述]` | 执行低敏诊断 |
|
|
259
|
+
| `/help` | 帮助卡片 |
|
|
260
|
+
|
|
261
|
+
私聊不需要 @。群和话题群默认必须 `@bot`;`@all` 会被忽略。支持的云文档评论里 @bot 就会触发回复。`/new chat` 拉起来的 workbench 群是例外:发起人在那个群里发任何消息都不用 @。
|
|
262
|
+
|
|
263
|
+
## 回复展示与 COT
|
|
264
|
+
|
|
265
|
+
`/config` 可以调整运行模型和三类展示选项:
|
|
266
|
+
|
|
267
|
+
- **模型**:Claude / Codex 使用预设选择器;opencode 填写带 provider 的模型 ID(如 `openai/gpt-5`),留空则跟随 opencode 自身配置。
|
|
268
|
+
- **消息回复方式**:`消息卡片` 流式更新最终回复;`纯文本` 在 run 完成后一次性发送。
|
|
269
|
+
- **工具调用显示**:控制最终回复卡片 / markdown 中是否展示工具块。
|
|
270
|
+
- **COT 过程消息**:`关闭` 只发送最终回复;`简略` 先用 COT 消息展示 agent 的过程文本和工具摘要;`详细` 还会展示工具参数和截断后的输出。
|
|
271
|
+
|
|
272
|
+
开启 COT 后,bridge 会把过程消息和最终答案拆成两条消息。过程消息用于追踪 agent 做了什么;最终答案仍由 agent 原始文本生成,bridge 不做启发式过滤。若 agent 把最终答案也作为普通流式文本输出,COT 过程消息中可能会出现对应片段。
|
|
273
|
+
|
|
274
|
+
## lark-cli 身份策略
|
|
275
|
+
|
|
276
|
+
每个 profile 都使用当前 profile 的 lark-cli 目录:`~/.lark-channel/profiles/<profile>/lark-cli`。agent 子进程会收到指向这个目录的 `LARKSUITE_CLI_CONFIG_DIR`,所以一个 profile 里的个人授权不会共享给另一个 profile。
|
|
277
|
+
|
|
278
|
+
默认策略是 `bot-only`:lark-cli 使用应用 / bot 身份,不访问个人资源。当用户为了日历、邮箱、云盘等个人资源完成授权后,当前 profile 可以切到 `user-default`,保留应用身份,同时允许已授权的用户身份。owner/admin 可以在 `/config` 查看或切换这个策略;`/status` 会用 `lark-cli: app` 或 `lark-cli: user-ready` 展示当前摘要。
|
|
279
|
+
|
|
280
|
+
## 工作目录
|
|
281
|
+
|
|
282
|
+
每个 profile 都可以有一个默认工作目录:`workspaces.default`。新建 profile 时可以传 `--workspace <path>` 作为初始目录;没传时 bridge 会创建一个 profile 托管的默认工作目录。
|
|
283
|
+
|
|
284
|
+
下面只是 profile 里的字段片段,不要整段覆盖 `config.json`;请改对应 profile 下的 `workspaces` 字段。
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"workspaces": {
|
|
289
|
+
"default": "/Users/me/.lark-channel-workspaces/claude/default"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
bridge 会检查所选目录存在、是目录,并且不是 `/`、Home 根、系统目录或临时目录根这类范围过大的位置。工作目录只是 agent run 的当前目录,不是文件系统 sandbox;agent 实际能访问哪些文件仍取决于本机 agent 进程及其权限模式。
|
|
295
|
+
|
|
296
|
+
### 控制台:工作空间与项目
|
|
297
|
+
|
|
298
|
+
管理控制台(bridge 启动时打印的 `http://127.0.0.1:<port>/?token=…`)的「工作空间」页用于查看/修改工作空间目录、管理全局 Git 账号,以及添加和拉取项目。
|
|
299
|
+
|
|
300
|
+
- **从账号添加**:配置好 Git 账号后可列出远端仓库、逐仓库选分支批量添加;也可手动填写仓库地址。
|
|
301
|
+
- **实时进度**:添加(clone)或拉取(pull)在后台执行,界面弹出进度窗口实时滚动显示 git 输出(进度、`remote:` 消息)与阶段。关闭窗口任务仍在后台继续,刷新页面会自动回到该任务的进度视图;窗口内可点「取消任务」就地终止并回滚半成品。
|
|
302
|
+
- **移除项目**:默认仅移除记录;确认框中可勾选「移除并删除目录」把本地检出一起删除(脏工作区 / 目录不存在 / 非 git 仓库时会红字警示但仍可删)。
|
|
303
|
+
- **切换分支**:项目行的分支是下拉框,选项为该仓库分支(含远程分支;取不到时退化为手动输入)。选中后立即 `fetch` + 切换检出目录,并持久化;已索引项目随之增量同步。工作区有未提交改动时会拒绝切换并保留原分支。定时/手动拉取也按配置的分支进行(`fetch-only` 策略只取不切)。
|
|
304
|
+
- **定时拉取**:可开启 profile 级定时任务(间隔 5–1440 分钟,策略 `ff-only` / `reset-hard`)。由 supervisor 统一调度,profile 离线也会执行;本地有未提交改动时跳过并记录,绝不覆盖。上次定时拉取时间从执行记录恢复,重启 bridge 后仍按间隔到点执行,不会立刻重拉。
|
|
305
|
+
- **执行记录**:每次拉取(定时或手动)都会写入 `profiles/<profile>/pull-history.jsonl`;控制台展示最近记录,失败时给 owner 发飞书消息(可关闭)。
|
|
306
|
+
- **CodeGraph 代码索引**:检测并可一键安装 codegraph CLI(官方脚本或 npm),接入本机 agent 的 codegraph MCP;建索引需在控制台显式发起(不再随首次 clone 自动执行),已索引项目在 git 拉取确有文件更新时自动增量同步,项目行显示「已索引 / 未索引」。
|
|
307
|
+
- 同一时刻只允许一个添加/拉取任务;任务状态只保存在内存中。关闭服务、停止/重启 profile 或点「取消任务」时,正在跑的 git 拉取 / codegraph 索引会连同子进程一起终止并回滚半成品(未完成的检出目录、半截 `.codegraph/`)。正在运行的作业同时落盘在 `<rootDir>/running-jobs/`:进程被强制结束(`kill -9` / 关窗口 / `taskkill /F`)后,下次启动会据此清理残留子进程并回滚。
|
|
308
|
+
|
|
309
|
+
### 控制台:角色
|
|
310
|
+
|
|
311
|
+
profile 详情页的「角色」页用于给该 profile 写一段**角色设定**。它本质是该 profile 的系统提示词软限制:作为 `## 角色设定` 段追加在 bridge 运行约定之后,注入该 profile 的每一次运行(claude 走 `--append-system-prompt-file`、codex 前缀进 stdin、opencode v1 每轮 `system` / v2 前置进文本)。
|
|
312
|
+
|
|
313
|
+
- 它是提示词层的约束(身份、语气、边界),**不是硬权限**;真正的权限在「配置」页的访问控制里。
|
|
314
|
+
- 在线 profile 保存后**下一轮运行即生效**;离线 profile 保存后**下次启动生效**。
|
|
315
|
+
- 空内容保存即清除角色。
|
|
316
|
+
- 「角色」页还列出现该 profile 的 **MCP server 与 skill**,并允许勾选生效范围。一期(2a)**只保存选择、尚未强制生效**;真正的按 profile 限制在二期 2b 落地。目录来自本地配置文件(opencode `opencode.json(c)`、claude `~/.claude.json` 与工作区 `.mcp.json`、codex `config.toml`),探测失败会提示可重试,不影响角色本身。
|
|
317
|
+
|
|
318
|
+
## 权限模式
|
|
319
|
+
|
|
320
|
+
推荐给用户配置的是 `permissions.defaultAccess` 和 `permissions.maxAccess`。新 profile 默认两项都是 `full`,以保持 bridge 的本地工具、授权流程、文件写入等能力完整可用。如需收紧权限,可以改成 `workspace` 或 `read-only`;收紧后本地工具执行、登录 / 授权流程、文件写入等能力可能受限。
|
|
321
|
+
|
|
322
|
+
下面只是 profile 里的字段片段,不要整段覆盖 `config.json`;请改对应 profile 下的 `permissions` 字段。
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"permissions": {
|
|
327
|
+
"defaultAccess": "full",
|
|
328
|
+
"maxAccess": "full"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
模式映射:
|
|
334
|
+
|
|
335
|
+
| Bridge access | Claude permission mode | Codex mode |
|
|
336
|
+
|---|---|---|
|
|
337
|
+
| `full` | `bypassPermissions` | `danger-full-access` |
|
|
338
|
+
| `workspace` | `acceptEdits` | `workspace-write` |
|
|
339
|
+
| `read-only` | `plan` | `read-only` |
|
|
340
|
+
|
|
341
|
+
旧版 `sandbox` 字段仍可读取。bridge 保存 profile 后,会把该设置迁移为 canonical `permissions`。
|
|
342
|
+
|
|
343
|
+
## 数据目录
|
|
344
|
+
|
|
345
|
+
| 路径 | 内容 |
|
|
346
|
+
|---|---|
|
|
347
|
+
| `~/.lark-channel/config.json` | root config,包含 profiles 和 active profile |
|
|
348
|
+
| `~/.lark-channel/active-profile` | 最近选择的 profile |
|
|
349
|
+
| `~/.lark-channel/git-accounts.json` | 全局 Git 账号(令牌存主机级加密库) |
|
|
350
|
+
| `~/.lark-channel/secrets.enc` | 主机级加密密钥(Git 账号令牌) |
|
|
351
|
+
| `~/.lark-channel/.keystore.salt` | 主机级密钥盐值 |
|
|
352
|
+
| `~/.lark-channel/profiles/<profile>/sessions.json` | 会话状态 |
|
|
353
|
+
| `~/.lark-channel/profiles/<profile>/sessions.json.catalog.json` | agent-aware 会话索引 |
|
|
354
|
+
| `~/.lark-channel/profiles/<profile>/workspaces.json` | 当前和命名工作空间绑定 |
|
|
355
|
+
| `~/.lark-channel/profiles/<profile>/secrets.enc` | profile 本地加密 secret |
|
|
356
|
+
| `~/.lark-channel/profiles/<profile>/lark-cli/` | 当前 profile 的 lark-cli 目录 |
|
|
357
|
+
| `~/.lark-channel/profiles/<profile>/media/` | 附件缓存 |
|
|
358
|
+
| `~/.lark-channel/profiles/<profile>/logs/` | 结构化运行日志 |
|
|
359
|
+
| `~/.lark-channel/registry/processes.json` | 本机进程注册表 |
|
|
360
|
+
| `~/.lark-channel/registry/locks/` | profile lock 和 app lock |
|
|
361
|
+
|
|
362
|
+
设置 `LARK_CHANNEL_HOME=/path/to/state` 可以迁移整棵本地状态目录。`LARK_CHANNEL_LOG_DAYS` 可以调整日志保留天数。
|
|
363
|
+
|
|
364
|
+
## 访问控制
|
|
365
|
+
|
|
366
|
+
**聊天访问默认是私有的:开箱即用时,只有"你"能在私聊和群聊里用这个 bot。** 这里的"你" = 创建 / 拥有这个飞书应用的人(也就是扫码把 bot 建起来的那位)。bot 会自动从飞书查出谁是应用 owner,所以**一个人用聊天入口完全不用配置**——你私聊它、在任意群里 @它都正常工作,其他人的聊天消息会被静默忽略(bot 不会回"你没权限",免得暴露自己的存在)。云文档评论按文档权限生效,见下文。
|
|
367
|
+
|
|
368
|
+
想让别的同事或某些群也能用,就把他们加进下面三类名单:
|
|
369
|
+
|
|
370
|
+
| 名单 | 控制谁 | 加入 | 移除 |
|
|
371
|
+
|------|--------|------|------|
|
|
372
|
+
| **允许私聊的用户** | 谁可以私聊 bot | `/invite user @某人` | `/remove user @某人` |
|
|
373
|
+
| **响应的群** | bot 在哪些群里对**群内所有人**响应 | `/invite group`(当前群)/ `/invite all group`(bot 所在的全部群) | `/remove group`(当前群) |
|
|
374
|
+
| **管理员** | 谁能改设置、并能在任意群用 bot | `/invite admin @某人` | `/remove admin @某人` |
|
|
375
|
+
|
|
376
|
+
> `/invite`、`/remove` 这些命令只有**你(创建者)和管理员**能发。命令里 @ 的是**对方**(不是 @ bot),bot 会自动把 @ 解析成对应的人,你不用手动去找 ID。
|
|
377
|
+
|
|
378
|
+
### 两种"畅通无阻"的身份
|
|
379
|
+
|
|
380
|
+
- **你(创建者)**:不受任何名单限制——私聊、任意群、所有命令都能用,而且**永远锁不死自己**:哪怕名单配乱了,回到 bot 私聊发 `/config` 总能进来。在飞书后台把应用 owner 转给别人后,bot 也会自动跟着切换。
|
|
381
|
+
- **管理员**:能私聊、能用 `/config` 等管理命令,而且**不受"响应的群"名单限制**——无论群在不在名单里,bot 都会回他们。适合给一起维护 bot 的同事。
|
|
382
|
+
|
|
383
|
+
### 几种常见配置
|
|
384
|
+
|
|
385
|
+
- **只给自己用** → 什么都不用做,默认就是。
|
|
386
|
+
- **让某个同事能私聊 bot** → `/invite user @他`
|
|
387
|
+
- **让某个工作群里所有人都能用** → 在那个群里发 `/invite group`
|
|
388
|
+
- **第一次配,想把 bot 已经在的群一次性全开放** → 发 `/invite all group` 一键拉取 bot 所在的全部群加入名单,之后再用 `/remove group` 删掉不想要的
|
|
389
|
+
- **再拉个人一起当管理员** → `/invite admin @他`
|
|
390
|
+
|
|
391
|
+
### 还需要知道的
|
|
392
|
+
|
|
393
|
+
- 改完**下一条消息**就生效,不用重启。
|
|
394
|
+
- **群里默认要先 @bot 才会回**(私聊不用 @)。这是另一个独立开关(`/config` →"群里需要 @ bot"),和上面的名单是两回事。
|
|
395
|
+
- 陌生人发消息一律静默丢弃,不会有任何回复。唯一的例外:有人在一个还没开放的群里 @bot,bot 会回一句友好提示,告诉他可以让管理员发 `/invite group` 开放这个群。
|
|
396
|
+
- 云文档评论按文档权限生效:能在支持的文档里评论并 @bot 的人可以触发回复。
|
|
397
|
+
|
|
398
|
+
### 高级:直接改配置文件
|
|
399
|
+
|
|
400
|
+
不想在飞书里点的话,`/invite`、`/config` 背后写的是 `~/.lark-channel/config.json` 中对应 profile 的 `access` 字段。空白名单表示这个名单没人,不表示所有人都能用。下面只是 profile 里的字段片段,不要整段覆盖 `config.json`:
|
|
401
|
+
|
|
402
|
+
```json
|
|
403
|
+
{
|
|
404
|
+
"schemaVersion": 2,
|
|
405
|
+
"profiles": {
|
|
406
|
+
"claude": {
|
|
407
|
+
"agentKind": "claude",
|
|
408
|
+
"access": {
|
|
409
|
+
"allowedUsers": ["ou_xxxxxxxxxxxxx"],
|
|
410
|
+
"allowedChats": ["oc_xxxxxxxxxxxxx"],
|
|
411
|
+
"admins": ["ou_xxxxxxxxxxxxx"],
|
|
412
|
+
"requireMentionInGroup": true
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
`allowedUsers` / `admins` 填用户 `open_id`,`allowedChats` 填群 `chat_id`。手动找 ID 最简单的办法:让对方给 bot 发条消息(群里就 @ 它一下),然后看当前 profile 的日志:
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
grep '"event":"enter"' ~/.lark-channel/profiles/<profile>/logs/bridge-$(date +%Y%m%d).jsonl | tail -5
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
每行都带 `chatId`(群 / 私聊 ID)和 `senderId`(用户 `open_id`)。手改完后**重启 bridge**,或在允许的 admin 上下文里发 `/reconnect` 让它生效。日常调整还是 `/invite` / `/config` 更省事,直接改文件主要用于部署脚本预填。
|
|
426
|
+
|
|
427
|
+
## 云文档评论
|
|
428
|
+
|
|
429
|
+
云文档评论不再需要单独绑定工作目录或维护文档白名单。支持的文档评论里 @bot 后,bridge 会在同一个评论线程里回复。评论运行复用文档级 session key;没有记录过文档 cwd 时回退到用户 home 目录。
|
|
430
|
+
|
|
431
|
+
## 常见问题
|
|
432
|
+
|
|
433
|
+
**bot 没反应 / agent 不回复**:通常是本机 `claude`、`codex` 或 `opencode` CLI 没登录,或者当前会话指向了不存在的工作目录。发 `/status` 看当前状态;`/new` 重开会话往往就好。
|
|
434
|
+
|
|
435
|
+
**agent 子进程假死(卡片停在最后一帧不动)**:支持 idle 探活。agent 一段时间没输出就会被 SIGTERM kill,卡片末尾会标出自动终止原因。默认关闭。开启方式:`/config` 设全局值(分钟),或 `/timeout 10` 只对当前会话生效;`/timeout off` 关掉当前会话的探活;`/timeout default` 清掉会话覆盖,回退到全局设置。
|
|
436
|
+
|
|
437
|
+
**图片发过去 agent 说看不到**:升级到最新版,0.1.0 之前的版本有文件名去重 bug。
|
|
438
|
+
|
|
439
|
+
## 测试与 CI
|
|
440
|
+
|
|
441
|
+
本地检查:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
pnpm test
|
|
445
|
+
pnpm typecheck
|
|
446
|
+
pnpm build
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`pnpm test` 包含 unit、integration 和 process-level adapter 测试。CI 在 macOS、Ubuntu、Windows 上执行 `pnpm install --frozen-lockfile`、`pnpm test`、`pnpm typecheck` 和 `pnpm build`。
|
|
450
|
+
|
|
451
|
+
## 可选:遥测(Telemetry)
|
|
452
|
+
|
|
453
|
+
默认情况下 bridge **不上报任何数据**:没有指标、没有日志离开你的机器,也不引入任何遥测依赖。下面这个钩子在你主动开启前完全是空操作。
|
|
454
|
+
|
|
455
|
+
想接自己的监控时,用环境变量指向一个 default export(或导出 `createAdapter`)`AdapterFactory` 的模块:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
LARK_CHANNEL_TELEMETRY_MODULE=your-telemetry-package lark-channel-bridge start
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
该模块会收到每一条 `log.*` 事件,以及错误 / 指标钩子,转发到任何你想要的地方。接口从包根导出:
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
import type { AdapterFactory, TelemetryAdapter, TelemetryEvent } from '@masterxinxin/lark-coding-agent-bridge';
|
|
465
|
+
|
|
466
|
+
const createAdapter: AdapterFactory = (meta) => ({
|
|
467
|
+
emit(event) {/* 上报事件 */},
|
|
468
|
+
recordError(err, ctx) {/* 上报异常 */},
|
|
469
|
+
recordMetric(name, value, tags) {/* 上报指标 */},
|
|
470
|
+
flush(timeoutMs) {/* 冲刷缓冲事件 */},
|
|
471
|
+
});
|
|
472
|
+
export default createAdapter;
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
模块不存在、工厂函数不合法、或者 adapter 抛错,都会降级为空操作——遥测永远不会阻止 bridge 启动,也不会打断日志。
|
|
476
|
+
|
|
477
|
+
## 许可
|
|
478
|
+
|
|
479
|
+
[MIT](./LICENSE)
|