dsh-lark-bot 0.5.1 → 0.7.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">dsh-lark-bot</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>把 DeepSeek Harness 接入飞书 · Bridge DeepSeek Harness into Feishu / Lark</strong>
4
+ <strong>把 DeepSeek Harness 接入飞书 | Bridge DeepSeek Harness into Feishu / Lark</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
@@ -26,99 +26,142 @@
26
26
 
27
27
  ---
28
28
 
29
- ## 快速开始 · Quick Start(普通用户先看这里)
29
+ ## 快速开始 | Quick Start(普通用户先看这里 | for end users)
30
30
 
31
- ### 1. 安装
31
+ ### 1. 安装(唯一路径)| Install (the only path)
32
32
 
33
- 两个包名内容完全一致,任选一个即可:
33
+ 本项目以 **dsh 标准 profile bundle** 交付:一行命令把它装进一个 dsh profile,dsh 启动时以
34
+ 标准插件方式加载桥接引擎(`dsh.bundle.patch` 已声明,`dsh plugin add` 可直接安装)。
34
35
 
35
- ```bash
36
- # 推荐
37
- npm install -g dsh-lark-bot
36
+ This project ships as a **standard dsh profile bundle**: one command installs it into a dsh
37
+ profile, and dsh loads the bridge engine as a standard plugin on boot (the package declares
38
+ `dsh.bundle.patch`, so `dsh plugin add` works directly).
38
39
 
39
- # 或飞书命名版本
40
- npm install -g dsh-feishu-bot
40
+ ```bash
41
+ # 唯一安装命令(无需先全局安装任何东西)| the only install command (no prior global install)
42
+ npx dsh-lark-bot@latest setup --profile dsh-lark
41
43
  ```
42
44
 
43
- 安装完成后,对应命令分别为 `dsh-lark-bot` `dsh-feishu-bot`。
44
-
45
- ### 2. 启动后台服务并绑定飞书
45
+ `setup` 会自动完成:发现本机 dsh → 预批准 pnpm 构建策略 → 执行标准的
46
+ `dsh plugin --profile dsh-lark add dsh-lark-bot`。
46
47
 
47
- ```bash
48
- dsh-lark-bot start
49
- ```
48
+ `setup` automatically: locates your dsh install → pre-approves pnpm's build policy → runs the
49
+ standard `dsh plugin --profile dsh-lark add dsh-lark-bot`.
50
50
 
51
- 或:
51
+ ### 2. 启动并扫码绑定 | Start and bind with one scan
52
52
 
53
53
  ```bash
54
- dsh-feishu-bot start
54
+ dsh --profile dsh-lark
55
55
  ```
56
56
 
57
- `start` 会自动在本机安装一个**后台服务**:加入系统开机自启列表,并在进程退出、崩溃或出错时自动重启。首次启动会:
57
+ 首次启动会在终端打印二维码:用飞书 / Lark App 扫码创建或选择 PersonalAgent 应用,绑定后
58
+ dsh-lark-bot 的桥接引擎即在 dsh 进程内运行(飞书通道、会话/工作区、卡片、通知回调),
59
+ 私聊直接发消息,群聊 / 话题里 `@bot`。常驻与守护由 dsh 自己负责。
58
60
 
59
- 1. 在终端显示二维码。
60
- 2. 用飞书 / Lark App 扫码。
61
- 3. 选择或创建 PersonalAgent 应用。
62
- 4. 绑定成功后,bot 会向你的私聊发送欢迎卡片。
63
- 5. 私聊直接发消息;群聊或话题里 `@bot`。
61
+ On first boot the terminal prints a QR code: scan it with the Feishu / Lark app to create or
62
+ choose a PersonalAgent app. After binding, the bridge engine runs **inside the dsh process**
63
+ (Feishu channel, sessions/workspaces, cards, notify callback); message it directly in private
64
+ chat, or use `@bot` in groups/topics. dsh owns the daemon lifecycle.
64
65
 
65
- 绑定完成后 bot 转入后台运行,终端可以随时关闭。
66
+ 已有 PersonalAgent 应用时可在 profile 环境变量中直接提供凭据跳过扫码(见「配置」):
66
67
 
67
- 如果你已经有 PersonalAgent 应用,也可以跳过扫码:
68
+ With an existing PersonalAgent app, provide credentials via profile env to skip the QR step
69
+ (see Configuration):
68
70
 
69
71
  ```bash
70
- dsh-lark-bot start \
71
- --app-id cli_xxx \
72
- --app-secret <secret> \
73
- --tenant feishu
72
+ DSH_LARK_APP_ID=cli_xxx DSH_LARK_APP_SECRET=<secret> DSH_LARK_TENANT=feishu \
73
+ dsh --profile dsh-lark
74
74
  ```
75
75
 
76
- ### 3. 服务管理命令
76
+ > 卸载:`dsh plugin --profile dsh-lark remove dsh-lark-bot`。
77
+ > Uninstall: `dsh plugin --profile dsh-lark remove dsh-lark-bot`.
77
78
 
78
- | 命令 | 作用 |
79
- | :--- | :--- |
80
- | `dsh-lark-bot start` | 安装后台服务、加入开机自启并启动(首次运行会先扫码绑定) |
81
- | `dsh-lark-bot status` | 查看服务状态(退出码 0=运行中,1=未运行) |
82
- | `dsh-lark-bot restart` | 重启后台服务(保留开机自启) |
83
- | `dsh-lark-bot stop` | 停止后台服务并移出开机自启 |
84
-
85
- 后台服务的运行日志写入 `~/.dsh-lark/profiles/<profile>/logs/bot.log`。
86
-
87
- ### 4. 基本使用
79
+ ### 4. 基本使用 | Basic usage
88
80
 
89
81
  在飞书里向 bot 发送普通消息即可开始工作,常用命令:
90
82
 
91
- | 命令 | 作用 |
83
+ Just send a normal message to the bot in Feishu to get started. Common commands:
84
+
85
+ | 命令 Command | 作用 Description |
92
86
  | --- | --- |
93
- | `/new` `/reset` | 开始新会话 |
94
- | `/cd <path>` | 切换工作目录并重置会话 |
95
- | `/ws list` | 查看命名工作空间 |
96
- | `/ws save <name>` | 保存当前工作空间 |
97
- | `/ws use <name>` | 切换到命名工作空间 |
98
- | `/ws remove <name>` | 删除命名工作空间 |
99
- | `/status` | 查看当前状态 |
100
- | `/resume` | 查看当前会话最近上下文 |
101
- | `/stop` | 终止当前任务 |
102
- | `/timeout [N\|off\|default]` | 查看或设置当前会话运行超时 |
103
- | `/density [compact\|standard\|detailed]` | 查看或设置卡片密度 |
104
- | `/model` | 查看当前模型、dsh 默认模型与可用模型列表 |
105
- | `/model use <id>` | 热切换当前会话模型(下一轮生效,无需重启) |
106
- | `/model default <id>` | 写入 dsh 默认模型 `agent-default-model`(管理员) |
107
- | `/model add\|remove <provider> <modelId>` | 添加 / 删除 provider 的模型(管理员) |
108
- | `/providers` | 查看 dsh 已配置 providers、模型与凭据状态 |
109
- | `/provider add\|update\|remove <id>` | 管理 provider(管理员;deepseek-official 与自定义 pi-ai) |
110
- | `/key set\|remove\|list <引用名>` | 管理 dsh 凭据(set / remove 需管理员) |
111
- | `/ask <问题>` | 发送问答卡,回答写入会话上下文 |
112
- | `/invite user\|admin\|group <id>`、`/invite list`、`/invite remove user\|group <id>` | 管理访问白名单 |
113
- | `/help` | 查看帮助 |
87
+ | `/new` `/reset` | 开始新会话<br>Start a new session |
88
+ | `/cd <path>` | 切换工作目录并重置会话<br>Change working directory and reset the session |
89
+ | `/ws list` | 查看命名工作空间<br>List named workspaces |
90
+ | `/ws save <name>` | 保存当前工作空间<br>Save the current workspace |
91
+ | `/ws use <name>` | 切换到命名工作空间<br>Switch to a named workspace |
92
+ | `/ws remove <name>` | 删除命名工作空间<br>Remove a named workspace |
93
+ | `/status` | 查看当前状态<br>Show current status |
94
+ | `/resume` | 查看当前会话最近上下文<br>Show the session's recent context |
95
+ | `/stop` | 终止当前任务<br>Stop the current task |
96
+ | `/timeout [N\|off\|default]` | 查看或设置当前会话运行超时<br>View or set the current session run timeout |
97
+ | `/concurrency [N\|default]` | 查看或设置当前 scope 并行任务数(默认 2)<br>View or set the concurrent-run limit for this scope (default 2) |
98
+ | `/role list`、`/role show <id>` | 查看角色列表 / 详情<br>List roles / show a role |
99
+ | `/role set <id>`、`/role clear` | 为当前 scope 绑定 / 解除角色<br>Bind / unbind a role for this scope |
100
+ | `/role save <id> <name> [--persona 文案] [--model <id>] [--tools <csv>] [--rules 文案]` | 创建 / 更新角色(管理员)<br>Create / update a role (admin) |
101
+ | `/role remove <id>` | 删除角色(管理员)<br>Remove a role (admin) |
102
+ | `/notify <scope\|chatId> <text>` | 跨会话发送通知(管理员)<br>Push a cross-session notification (admin) |
103
+ | `/notify list` | 查看 bridge 已注册的 scope<br>List scopes known to the bridge |
104
+ | `/retention [N\|default]` | 查看或设置保留消息条数(超出自动归档)<br>View or set the live message retention window (overflow is archived) |
105
+ | `/archive [note]`、`/archive list [N]`、`/archive clean` | 手动归档 / 查看 / 清理会话记录<br>Archive / list / clean session transcripts |
106
+ | `/density [compact\|standard\|detailed]` | 查看或设置卡片密度<br>View or set card density |
107
+ | `/model` | 查看当前模型、dsh 默认模型与可用模型列表<br>View current model, dsh default model and available models |
108
+ | `/model use <id>` | 热切换当前会话模型(下一轮生效,无需重启)<br>Hot-switch the current session model (effective next message, no restart) |
109
+ | `/model default <id>` | 写入 dsh 默认模型 `agent-default-model`(管理员)<br>Write the dsh default model `agent-default-model` (admin) |
110
+ | `/model add\|remove <provider> <modelId>` | 添加 / 删除 provider 的模型(管理员)<br>Add / remove a provider model (admin) |
111
+ | `/providers` | 查看 dsh 已配置 providers、模型与凭据状态<br>View configured dsh providers, models and credential status |
112
+ | `/provider add\|update\|remove <id>` | 管理 provider(管理员;deepseek-official 与自定义 pi-ai)<br>Manage providers (admin; deepseek-official and custom pi-ai) |
113
+ | `/key set\|remove\|list <引用名>` | 管理 dsh 凭据(set / remove 需管理员)<br>Manage dsh credentials (set / remove require admin) |
114
+ | `/ask <问题>` | 发送问答卡,回答写入会话上下文<br>Send a Q&A card; the answer is written back to session context |
115
+ | `/invite user\|admin\|group <id>`、`/invite list`、`/invite remove user\|group <id>` | 管理访问白名单<br>Manage the access allowlist |
116
+ | `/help` | 查看帮助<br>Show help |
114
117
 
115
118
  飞书消息中的图片会下载到本地 media 目录并传给 dsh;文本类文件会读取内容并注入任务上下文。
116
119
 
117
- ### 模型 / Provider / 凭据管理
120
+ Images in Feishu messages are downloaded to the local media directory and passed to dsh; text files are read and their content is injected into the task context.
121
+
122
+ 同一 scope(私聊 / 群聊 / 话题)默认允许 **2 个任务并行**(`DSH_LARK_SCOPE_CONCURRENCY` 或
123
+ `/concurrency` 调整):连续发来的多条消息会以独立 run 并行推进,每个 run 使用独立的 dsh
124
+ session 与独立 runId,`/status` 展示全部运行中的 run,`/stop` 一次性终止全部任务。
125
+
126
+ Each scope (DM / group / topic) runs up to **2 tasks in parallel** by default (adjust with
127
+ `DSH_LARK_SCOPE_CONCURRENCY` or `/concurrency`): successive messages become independent runs,
128
+ each with its own dsh session and run id. `/status` lists every active run and `/stop` interrupts
129
+ them all.
130
+
131
+ **多角色 Agent**:管理员用 `/role save <id> <name> --persona <文案> [--model <id>] [--tools
132
+ <csv>] [--rules <文案>]` 定义 PM / 开发 / 文档等角色(persona、模型偏好、工具指引、角色规则),
133
+ `/role set <id>` 把角色绑定到当前 scope:下一轮起该 scope 的每个 run 都携带角色 persona 与
134
+ 规则,并优先使用角色模型(角色模型 < 每会话 `/model use`)。角色定义持久化在
135
+ `~/.dsh-lark/profiles/<profile>/roles.json`。
136
+
137
+ **Multi-role agents**: admins define roles (PM / dev / docs / …) with `/role save <id> <name>
138
+ --persona <text> [--model <id>] [--tools <csv>] [--rules <text>]` — persona, model preference,
139
+ tool guidance and role rules — then bind one to the current scope with `/role set <id>`. Every
140
+ run in that scope carries the role instructions, and the role model wins below the per-session
141
+ `/model use` override. Role definitions persist in
142
+ `~/.dsh-lark/profiles/<profile>/roles.json`.
143
+
144
+ **出站 @ 提及与跨会话通知**:bridge 出站契约支持 `mentions`(@ 提及)与跨 chat/thread 发送;
145
+ `/notify <scope|chatId> <text>` 可向其他会话推送汇报(管理员)。agent 侧还内置 `lark_notify`
146
+ dsh 工具(SDK / ACP 两种 runtime 均可装配):agent 完成任务后可主动向其他群 / 话题发消息并
147
+ @ 指定成员,桥接进程通过 127.0.0.1 本地回调端口 + 随机 token 校验,不暴露公网。
148
+
149
+ **Outbound mentions & cross-session notify**: the outbound contract supports `mentions` and
150
+ cross-chat/thread sends; `/notify <scope|chatId> <text>` pushes a report to another session
151
+ (admin). The agent also gets a built-in `lark_notify` dsh tool (wired into both SDK and ACP
152
+ runtime profiles): after a task finishes it can push messages to other groups/topics and @mention
153
+ members. The bridge listens on 127.0.0.1 with a random per-boot token — nothing is exposed to the
154
+ public network.
155
+
156
+ ### 模型 / Provider / 凭据管理 | Models / Providers / Credentials
118
157
 
119
158
  模型与 provider 的配置以 dsh 官方方式持久化(与 dsh Web **Settings → Models** 页面完全相同的
120
159
  存储协议),改动在下一个请求生效,无需重启 bot:
121
160
 
161
+ Model and provider configuration is persisted the official dsh way (the exact storage protocol
162
+ used by the dsh Web **Settings → Models** page); changes take effect on the next request without
163
+ restarting the bot:
164
+
122
165
  - `/model use <id>`:按会话热切换模型,下一轮消息即用新模型。
123
166
  - `/model default <id>`:写入 dsh 的 `agent-default-model`,作为新会话的默认模型。
124
167
  - `/providers`:展示 dsh 已配置的 provider、模型与凭据状态(DeepSeek 官方 + 自定义 pi-ai)。
@@ -128,10 +171,23 @@ dsh-lark-bot start \
128
171
  - `/key set|remove|list`:读写 `~/.dsh/.credentials.yaml`(0600)。settings 只保存 `apiKeyEnv`
129
172
  引用,字面密钥不进入 settings 或聊天记录。
130
173
 
174
+ - `/model use <id>`: hot-switch the model for this session; the next message uses it.
175
+ - `/model default <id>`: write the dsh `agent-default-model` as the default for new sessions.
176
+ - `/providers`: show configured providers, models and credential status (official DeepSeek + custom pi-ai).
177
+ - `/provider add|update|remove`: manage custom providers (`llm-pi-ai`) or `deepseek-official`;
178
+ a custom provider needs `--api` (`openai-completions` / `openai-responses` / `anthropic-messages`),
179
+ `--base-url` and at least one `--model`, matching the official schema.
180
+ - `/key set|remove|list`: read / write `~/.dsh/.credentials.yaml` (0600). Settings keep only
181
+ `apiKeyEnv` references; literal keys never enter settings or chat history.
182
+
131
183
  安全提醒:在飞书会话里输入密钥会对该会话的可见成员暴露密钥,建议仅在私聊中使用,或优先用
132
184
  `--api-key-env` 引用已配置的环境变量 / dsh Web 页面录入。bot 不会在任何回复中回显密钥值。
133
185
 
134
- ### 5. 卸载
186
+ Security note: typing a key in a Feishu conversation exposes it to everyone who can see that
187
+ chat; prefer private chats, `--api-key-env` references to existing environment variables, or the
188
+ dsh Web UI. The bot never echoes key values in any reply.
189
+
190
+ ### 5. 卸载 | Uninstall
135
191
 
136
192
  ```bash
137
193
  dsh-lark-bot stop
@@ -141,29 +197,35 @@ rm -rf ~/.dsh-lark
141
197
 
142
198
  更详细的安装、状态目录、日志和排障说明见 [`docs/QUICK_START.md`](docs/QUICK_START.md)。
143
199
 
200
+ See [`docs/QUICK_START.md`](docs/QUICK_START.md) for installation details, state directories,
201
+ logs and troubleshooting.
202
+
144
203
  ---
145
204
 
146
- ## 关键词 · Keywords
205
+ ## 关键词 | Keywords
147
206
 
148
207
  `dsh` · `deepseek` · `deepseek harness` · `feishu` · `lark` · `bridge` · `bot`
149
208
 
150
- ## 这是什么 · What it is
209
+ ## 这是什么 | What it is
151
210
 
152
211
  **dsh-lark-bot** 是一个轻量桥接工具,把本机的 DeepSeek Harness(`dsh`)接入飞书 / Lark,复刻当年 OpenCode Telegram Bot / MiMoCode Telegram Bot 的体验——在 IM 里与 coding agent 对话、收流式卡片、审阅 diff,并在此基础上叠加**完整的项目工作区管理**。
153
212
 
154
213
  **dsh-lark-bot** is a lightweight bridge that connects your local DeepSeek Harness (`dsh`) into Feishu / Lark, recreating the beloved OpenCode / MiMoCode Telegram-bot experience — chat with your coding agent, receive streaming cards, review diffs — and adds **full project workspace management** on top.
155
214
 
156
- ## 目标 · Goals
215
+ ## 目标 | Goals
157
216
 
158
- - **一条命令启动**:clone 后一键安装运行,已发布到 npm,`npm i -g dsh-lark-bot && dsh-lark-bot start` 即可拉起后台服务。
217
+ - **一条命令安装部署**:`npx dsh-lark-bot@latest setup --profile dsh-lark` 装进 dsh profile,
218
+ 随后 `dsh --profile dsh-lark` 启动并扫码,桥接引擎作为标准插件在 dsh 进程内运行。
159
219
  - **飞书原生体验**:流式卡片、交互按钮、图片 / 文件,全程双语(文档评论为规划中能力)。
160
220
  - **完整工作区管理**:多项目隔离、git worktree、项目级规则注入、上下文持久化。
161
221
 
162
- - **One-command start**: clone and run in one step, published to npm — `npm i -g dsh-lark-bot && dsh-lark-bot start`.
222
+ - **One-command install & deploy**: `npx dsh-lark-bot@latest setup --profile dsh-lark`, then
223
+ `dsh --profile dsh-lark` and scan once — the bridge engine runs as a standard plugin inside
224
+ the dsh process.
163
225
  - **Native Feishu experience**: streaming cards, interactive buttons, images / files, doc comments.
164
226
  - **Full workspace management**: multi-project isolation, git worktrees, per-project rules, persistent context.
165
227
 
166
- ## 兼容性 · Compatibility
228
+ ## 兼容性 | Compatibility
167
229
 
168
230
  - **DeepSeek Harness(`dsh`)**:已验证 **dsh 0.1.0-rc.6**(2026-08-14:SDK JSON-RPC / ACP runtime 握手 +
169
231
  真实任务流式验证),通过官方 `@deepseek-ai/dsh-sdk-client` / `@deepseek-ai/dsh-acp` 接入;
@@ -175,67 +237,145 @@ rm -rf ~/.dsh-lark
175
237
  token 级流式事件);`DSH_LARK_ADAPTER=acp` 切到官方 **ACP server**(审批卡);`headless` 保留旧版
176
238
  子进程 fallback。首次启动自动在 `~/.dsh/profiles/dsh-lark`(或 `dsh-lark-acp`)创建 runtime profile。
177
239
 
178
- ## 配置 · Configuration
240
+ - **DeepSeek Harness (`dsh`)**: verified against **dsh 0.1.0-rc.6** (2026-08-14: SDK JSON-RPC / ACP
241
+ runtime handshake + real streaming task verification), connected through the official
242
+ `@deepseek-ai/dsh-sdk-client` / `@deepseek-ai/dsh-acp`; see
243
+ [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for pinned versions, the upgrade policy and
244
+ automated probing, and [`docs/adapter-notes.md`](docs/adapter-notes.md) for adapter details.
245
+ - **Runtime**: Node.js ≥ 22.19 (see `engines` in `package.json`).
246
+ - **Platform**: Linux / macOS / Windows (Feishu outbound WebSocket long connection; no public
247
+ server, domain or tunneling required).
248
+ - The default adapter is the official **`@deepseek-ai/dsh-sdk-client`** (SDK JSON-RPC runtime with
249
+ native session continuation and token-level streaming events); `DSH_LARK_ADAPTER=acp` switches
250
+ to the official **ACP server** (approval cards); `headless` keeps the legacy subprocess
251
+ fallback. On first start the bot creates the runtime profile at
252
+ `~/.dsh/profiles/dsh-lark` (or `dsh-lark-acp`).
253
+
254
+ ## 配置 | Configuration
179
255
 
180
256
  - 本地配置:`~/.dsh-lark/config.json`
181
257
  - 状态根目录可用 `DSH_LARK_HOME` 覆盖
182
258
  - 环境变量统一使用 `DSH_LARK_*` 前缀
183
259
  - 模板见 [`.env.example`](.env.example)
184
260
 
261
+ - Local config: `~/.dsh-lark/config.json`
262
+ - The state root can be overridden with `DSH_LARK_HOME`
263
+ - Environment variables use the `DSH_LARK_*` prefix
264
+ - Template: [`.env.example`](.env.example)
265
+
185
266
  会话运行在 Git 仓库中时,会自动在 `~/.dsh-lark/profiles/<profile>/worktrees/<scope>/` 创建隔离 worktree,并复制项目级 `AGENTS.md`。
186
267
 
187
- 每个飞书 scope 会保存最近 40 条对话消息;SDK 模式下 dsh 原生 session 续跑,headless 模式
188
- 则把历史注入下一次 prompt 实现近似记忆。
268
+ When the session runs inside a Git repository, an isolated worktree is created at
269
+ `~/.dsh-lark/profiles/<profile>/worktrees/<scope>/` and a project-level `AGENTS.md` is copied in.
270
+
271
+ 每个飞书 scope 默认保存最近 40 条对话消息(可用 `/retention` 或 `DSH_LARK_RETENTION_MSGS`
272
+ 调整);超出保留窗口的消息自动归档到 `~/.dsh-lark/profiles/<profile>/archives/`(Markdown +
273
+ JSONL,目录本身是 Git 仓库,每次归档独立 commit),支持 `/archive` 手动归档与保留策略清理。
274
+ SDK 模式下 dsh 原生 session 续跑,headless 模式则把历史注入下一次 prompt 实现近似记忆。
275
+
276
+ Each Feishu scope keeps the last 40 conversation messages by default (adjustable with
277
+ `/retention` or `DSH_LARK_RETENTION_MSGS`); messages beyond the retention window are archived to
278
+ `~/.dsh-lark/profiles/<profile>/archives/` (Markdown + JSONL inside a Git repository, one commit
279
+ per archive), and `/archive` exports the full session on demand. The SDK mode continues the native
280
+ dsh session, while headless mode approximates memory by injecting history into the next prompt.
189
281
 
190
282
  当前核心环境变量:
191
283
 
192
- | 变量 | 默认值 | 说明 |
284
+ Core environment variables:
285
+
286
+ | 变量 Variable | 默认值 Default | 说明 Description |
193
287
  | :--- | :--- | :--- |
194
- | `DSH_LARK_HOME` | `~/.dsh-lark` | 本地状态根目录 |
195
- | `DSH_LARK_TENANT` | `feishu` | `feishu` 或 `lark` |
196
- | `DSH_LARK_WORKSPACE` | 未设置 | 新会话默认工作目录 |
197
- | `DSH_LARK_DSH_COMMAND` | `自动发现` | dsh 启动命令;通常无需设置 |
198
- | `DSH_LARK_DSH_ARGS` | `自动发现` | dsh 启动参数,逗号分隔;通常无需设置 |
199
- | `DSH_LARK_ADAPTER` | `sdk` | `sdk`(默认)/ `acp`(审批)/ `headless`(legacy |
200
- | `DSH_LARK_PROVIDER` | `deepseek-official` | 模型 provider |
201
- | `DSH_LARK_MODEL` | `deepseek-v4-flash` | 默认模型 |
202
- | `DSH_LARK_MAX_TOKENS` | 未设置 | SDK agent 每请求输出 token 上限 |
203
- | `DSH_LARK_ACCESS_DEFAULT_DENY` | `false` | 无白名单时拒绝私聊 |
204
- | `DSH_LARK_EVENT_FRESHNESS_MS` | `600000` | 过期消息拒绝窗口(0 关闭) |
205
- | `DSH_LARK_RUN_TIMEOUT_MS` | `300000` | 单次运行墙钟超时 |
206
- | `DSH_LARK_STOP_GRACE_MS` | `5000` | SIGTERM 后等待优雅退出再 SIGKILL 的宽限期 |
288
+ | `DSH_LARK_HOME` | `~/.dsh-lark` | 本地状态根目录<br>Local state root directory |
289
+ | `DSH_LARK_TENANT` | `feishu` | `feishu` 或 `lark`<br>`feishu` or `lark` |
290
+ | `DSH_LARK_WORKSPACE` | 未设置 | 新会话默认工作目录<br>Default working directory for new sessions |
291
+ | `DSH_LARK_DSH_COMMAND` | `自动发现` | dsh 启动命令;通常无需设置<br>dsh launch command; usually not needed |
292
+ | `DSH_LARK_DSH_ARGS` | `自动发现` | dsh 启动参数,逗号分隔;通常无需设置<br>dsh launch args, comma-separated; usually not needed |
293
+ | `DSH_LARK_ADAPTER` | `sdk` | `sdk`(默认)/ `acp`(审批)/ `headless`(legacy)<br>`sdk` (default) / `acp` (approval) / `headless` (legacy) |
294
+ | `DSH_LARK_PROVIDER` | `deepseek-official` | 模型 provider<br>Model provider |
295
+ | `DSH_LARK_MODEL` | `deepseek-v4-flash` | 默认模型<br>Default model |
296
+ | `DSH_LARK_MAX_TOKENS` | 未设置 | SDK agent 每请求输出 token 上限<br>Per-request output token cap for SDK agents |
297
+ | `DSH_LARK_ACCESS_DEFAULT_DENY` | `false` | 无白名单时拒绝私聊<br>Reject private chats when no allowlist is configured |
298
+ | `DSH_LARK_EVENT_FRESHNESS_MS` | `600000` | 过期消息拒绝窗口(0 关闭)<br>Stale-message rejection window (0 disables) |
299
+ | `DSH_LARK_RUN_TIMEOUT_MS` | `300000` | 单次运行墙钟超时<br>Wall-clock timeout for a single run |
300
+ | `DSH_LARK_STOP_GRACE_MS` | `5000` | SIGTERM 后等待优雅退出再 SIGKILL 的宽限期<br>Grace period after SIGTERM before SIGKILL |
301
+ | `DSH_LARK_SCOPE_CONCURRENCY` | `2` | 每个 scope 的并行任务数(1=严格串行)<br>Concurrent runs per scope (1 = strictly serial) |
302
+ | `DSH_LARK_RETENTION_MSGS` | `40` | 每个 scope 保留的消息条数(0=全部保留)<br>Messages kept per scope (0 keeps everything) |
303
+ | `DSH_LARK_ARCHIVE_MAX` | `50` | 每个 scope 最多保留的归档数(0=不清理)<br>Max archives kept per scope (0 disables pruning) |
304
+ | `DSH_LARK_ARCHIVE_MAX_AGE_DAYS` | `90` | 归档最大保留天数(0=不清理)<br>Max archive age in days (0 disables pruning) |
207
305
 
208
306
  启动时会自动查找本机常见的 `@deepseek-ai/dsh` 安装位置。只有自动发现失败或需要指定特殊 profile 时,才需要设置这两个变量。
209
307
 
210
- ## 权限与数据 · Permissions & Data
308
+ On startup the bot auto-discovers common local `@deepseek-ai/dsh` installations. Set these two
309
+ variables only when auto-discovery fails or a special profile is required.
310
+
311
+ ## 权限与数据 | Permissions & Data
211
312
 
212
313
  本工具在**本机**运行,安装前请知悉它会访问:
213
314
 
315
+ This tool runs **locally**; before installing, be aware that it accesses:
316
+
214
317
  - **飞书凭据**:PersonalAgent 应用的 `app_id` / `app_secret`,明文写入本机 `~/.dsh-lark/config.json`(文件权限 600)。
215
318
  - **文件系统**:读取 / 写入你通过 `/cd`、`/ws` 指定的工作目录(含执行 shell 命令、修改文件)。
216
319
  - **网络**:向飞书开放平台建立 WebSocket 出站长连接收发消息;向 DeepSeek API 发送任务上下文。
320
+ - **本地回调**:运行 `lark_notify` 工具时,dsh runtime 子进程通过 `127.0.0.1` 随机端口 +
321
+ 每启动随机 token 回调 bridge 进程(仅本机回环,不监听公网)。
217
322
  - **进程**:spawn 本机 `dsh` runtime 子进程(`dsh-sdk-jsonrpc-server` / `dsh-acp` profile)执行 agent 任务。
218
323
  - **dsh 配置**:`/model` `/providers` `/provider` `/key` 命令按 dsh 官方存储协议读写
219
324
  `~/.dsh/settings.yaml` 与 `~/.dsh/.credentials.yaml`(仅管理员可写;settings 只存 `apiKeyEnv`
220
325
  引用,凭据文件权限 0600、目录 0700,字面密钥不进入 settings 或聊天记录)。
221
326
 
327
+ - **Feishu credentials**: the PersonalAgent app `app_id` / `app_secret`, stored in plaintext at
328
+ `~/.dsh-lark/config.json` (file mode 600).
329
+ - **File system**: reads / writes the working directories you choose with `/cd` and `/ws`
330
+ (including running shell commands and modifying files).
331
+ - **Network**: an outbound WebSocket long connection to the Feishu open platform for messages, and
332
+ task context sent to the DeepSeek API.
333
+ - **Local callback**: when the `lark_notify` tool runs, the dsh runtime subprocess calls the
334
+ bridge process back over a random 127.0.0.1 port with a per-boot token (loopback only).
335
+ - **Processes**: spawns local `dsh` runtime subprocesses (`dsh-sdk-jsonrpc-server` / `dsh-acp`
336
+ profiles) to run agent tasks.
337
+ - **dsh configuration**: `/model` `/providers` `/provider` `/key` read / write
338
+ `~/.dsh/settings.yaml` and `~/.dsh/.credentials.yaml` using the official dsh storage protocol
339
+ (admin-only writes; settings keep only `apiKeyEnv` references; credentials file mode 0600,
340
+ directory 0700; literal keys never enter settings or chat history).
341
+
222
342
  所有数据仅在本机与飞书、DeepSeek 之间流转,不收集、不上传任何遥测。密钥不会提交进仓库(见 `.gitignore`)。
223
343
 
224
- ## 排障 · Troubleshooting
344
+ All data flows only between this machine, Feishu and DeepSeek; nothing is collected or uploaded
345
+ as telemetry. Keys are never committed to the repository (see `.gitignore`).
346
+
347
+ ## 排障 | Troubleshooting
225
348
 
226
349
  先运行 `dsh-lark-bot doctor`,它会检查 profile、工作目录,并对当前 adapter 做真实可用性探测
227
350
  (`sdk` / `acp` / `headless` 对应 runtime 的初始化握手)。
228
351
 
352
+ Run `dsh-lark-bot doctor` first; it checks the profile and working directory and performs a real
353
+ availability probe for the current adapter (`sdk` / `acp` / `headless` runtime handshake).
354
+
229
355
  常见问题:
230
356
 
357
+ Common issues:
358
+
231
359
  - **bot 静默 / 长连接失败**:查看 stderr 上的 JSONL 日志,关注 `channel` 与 `channel-command` 类别;SDK 会自动重连。
232
360
  - **agent 无响应**:发送 `/status` 查看当前 scope、cwd 和 active run;发送 `/stop` 终止当前任务;超过 `DSH_LARK_RUN_TIMEOUT_MS` 时看门狗会自动终止。
233
361
  - **首次扫码失败**:确认本机时间准确、网络可访问飞书开放平台;已拿到 App ID/Secret 时可用 `--app-id` / `--app-secret` 跳过扫码。
234
362
 
235
- 以后台服务方式运行时,日志写入 `~/.dsh-lark/profiles/<profile>/logs/bot.log`(JSON Lines,
236
- stdout stderr 合并);当前进程的 stderr 仍为 JSON Lines。
363
+ - **Silent bot / long-connection failure**: check the JSONL logs on stderr, focusing on the
364
+ `channel` and `channel-command` categories; the SDK reconnects automatically.
365
+ - **Unresponsive agent**: send `/status` to view the scope, cwd and active run; send `/stop` to
366
+ terminate the current task; the watchdog terminates it automatically after
367
+ `DSH_LARK_RUN_TIMEOUT_MS`.
368
+ - **First QR binding fails**: make sure the local clock is accurate and the Feishu open platform
369
+ is reachable; with an existing App ID/Secret you can skip scanning via `--app-id` /
370
+ `--app-secret`.
371
+
372
+ 桥接引擎日志写入 `~/.dsh-lark/profiles/<profile>/logs/bot.log`(JSON Lines);dsh 宿主日志走
373
+ dsh 自己的日志体系。
237
374
 
238
- ## 开发 · Development
375
+ The bridge engine logs to `~/.dsh-lark/profiles/<profile>/logs/bot.log` (JSON Lines); the dsh
376
+ host uses its own logging.
377
+
378
+ ## 开发 | Development
239
379
 
240
380
  ```bash
241
381
  pnpm install
@@ -243,16 +383,24 @@ pnpm typecheck
243
383
  pnpm test
244
384
  pnpm build
245
385
  pnpm ci:local
246
- pnpm release:check # ci:local + 上游一致性检查
247
- pnpm compat:probe # 临时 DSH_HOME 安装锁定版 dsh,跑真实 SDK 握手
248
- pnpm dsh:upstream # 对比 npm 上游 stable 与锁定矩阵
386
+ pnpm release:check # ci:local + 上游一致性检查 | ci:local + upstream consistency check
387
+ pnpm compat:probe # 临时 DSH_HOME 安装锁定版 dsh,跑真实 SDK 握手 | installs pinned dsh into a temp DSH_HOME and runs a real SDK handshake
388
+ pnpm dsh:upstream # 对比 npm 上游 stable 与锁定矩阵 | compares npm upstream stable with the pinned matrix
249
389
  ```
250
390
 
251
391
  开发规范见 [`AGENTS.md`](AGENTS.md),模块契约见 [`docs/API.md`](docs/API.md),架构见 [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)。
252
392
  兼容矩阵的升级政策与自动化见 [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md)。
253
393
 
394
+ See [`AGENTS.md`](AGENTS.md) for the development workflow, [`docs/API.md`](docs/API.md) for
395
+ module contracts, and [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the architecture. See
396
+ [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for the compatibility matrix, upgrade policy
397
+ and automation.
398
+
254
399
  发布双包(`dsh-lark-bot` 与 `dsh-feishu-bot` 共享同一份 dist / 版本 / 依赖):
255
400
 
401
+ Publishing both packages (`dsh-lark-bot` and `dsh-feishu-bot` share the same dist / version /
402
+ dependencies):
403
+
256
404
  ```bash
257
405
  pnpm publish:dual:dry-run
258
406
  pnpm publish:dual
@@ -260,16 +408,30 @@ pnpm publish:dual
260
408
 
261
409
  `scripts/publish-dual-packages.mjs` 从根 `package.json` 生成两份仅 `name` / `bin` 不同的发布清单,避免两份源码漂移。GitHub tag `v*` 会触发 [`release.yml`](.github/workflows/release.yml) 自动发布两个 npm 包并创建 Release。
262
410
 
411
+ `scripts/publish-dual-packages.mjs` generates two publish manifests from the root
412
+ `package.json`, differing only in `name` / `bin`, so the two copies never drift. A GitHub tag
413
+ `v*` triggers [`release.yml`](.github/workflows/release.yml) to publish both npm packages and
414
+ create a Release automatically.
415
+
263
416
  同一份 dist 还会以 `@plutokeating/dsh-lark-bot` 和 `@plutokeating/dsh-feishu-bot` 发布到 GitHub Packages,便于在 GitHub Packages 页面查看。
264
417
 
265
- ## 许可与安全 · License & Security
418
+ The same dist is also published to GitHub Packages as `@plutokeating/dsh-lark-bot` and
419
+ `@plutokeating/dsh-feishu-bot`, viewable on the GitHub Packages page.
420
+
421
+ ## 许可与安全 | License & Security
266
422
 
267
423
  - **许可证**:GNU Affero General Public License v3.0(见 `LICENSE`)。
268
424
  - **安全报告**:如发现安全漏洞,请通过 GitHub Security Advisory 私下报告,勿公开 issue。
269
425
  - **安全模型**:默认拒绝、密钥脱敏、路径 containment、SSRF 防护、过期事件拒绝与交互工具
270
426
  默认禁用——详见 [`SECURITY.md`](SECURITY.md)。
271
427
 
272
- ## 文档 · Documentation
428
+ - **License**: GNU Affero General Public License v3.0 (see `LICENSE`).
429
+ - **Security reports**: report vulnerabilities privately via GitHub Security Advisory; do not
430
+ open a public issue.
431
+ - **Security model**: default-deny, secret redaction, path containment, SSRF protection, stale
432
+ event rejection and default-disabled interactive tools — see [`SECURITY.md`](SECURITY.md).
433
+
434
+ ## 文档 | Documentation
273
435
 
274
436
  > 接手本项目的工程师:**先读 [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md) 和 [`docs/RESEARCH.md`](docs/RESEARCH.md)**,即可完整理解项目诉求与来龙去脉,无需线下沟通。
275
437
  > Engineers taking over this project: **read [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md) and [`docs/RESEARCH.md`](docs/RESEARCH.md) first**.
@@ -290,9 +452,9 @@ pnpm publish:dual
290
452
  | [`SECURITY.md`](SECURITY.md) | 安全模型与报告渠道<br>Security model & reporting |
291
453
  | [`AGENTS.md`](AGENTS.md) | AI Agent 开发工作流规范<br>AI agent workflow spec |
292
454
 
293
- ## 架构 · Architecture
455
+ ## 架构 | Architecture
294
456
 
295
- > 详见 [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) · See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for details.
457
+ > 详见 [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for details.
296
458
 
297
459
  ```
298
460
  飞书 / Lark ──WebSocket 长连接──▶ bridge/ ──▶ session/ ──▶ workspace/ ──▶ adapters/ ──▶ dsh ──▶ DeepSeek V4
@@ -302,7 +464,7 @@ pnpm publish:dual
302
464
 
303
465
  The core idea: **decouple the Feishu channel from the agent backend**. The bridge layer follows the battle-tested `lark-channel-bridge` approach (WebSocket long-connection + streaming cards + session routing); the agent backend is abstracted behind an adapter, defaulting to the official DeepSeek Harness SDK (`DSH_LARK_ADAPTER=sdk`), with an optional ACP approval mode and the legacy headless fallback.
304
466
 
305
- ## 目录结构 · Directory Structure
467
+ ## 目录结构 | Directory Structure
306
468
 
307
469
  | 目录 Dir | 职责 Responsibility |
308
470
  | :--- | :--- |
@@ -314,28 +476,27 @@ The core idea: **decouple the Feishu channel from the agent backend**. The bridg
314
476
  | `src/card/` | 流式卡片状态与渲染<br>Streaming card state & rendering |
315
477
  | `src/bot/` | 运行注册、消息排队、审批/问答注册表<br>Run registry, queueing, approval/question registries |
316
478
  | `src/commands/` | 斜杠命令(/cd /ws /new …)<br>Slash commands |
317
- | `src/cli/` | CLI 入口与 start / status / restart / stop / doctor 命令<br>CLI entry & service commands |
479
+ | `src/cli/` | CLI 入口:`setup`(唯一安装命令)/ `doctor`(诊断)/ 隐藏 `run`<br>CLI entry: setup / doctor / hidden run |
318
480
  | `src/config/` | profile / 配置 / 访问白名单 / dsh 配置管理<br>Profile, config, access & dsh config management |
319
481
  | `src/core/` | 结构化日志<br>Structured logging |
320
482
  | `src/media/` | 附件下载与文本注入<br>Attachment download & text injection |
321
483
  | `src/platform/` | 跨平台原子写入<br>Cross-platform atomic writes |
322
- | `src/service/` | 后台服务管理(systemd / launchd / 计划任务 / 便携 supervisor)<br>Background service management |
323
484
  | `docs/` | 架构、路线图等文档<br>Architecture, roadmap & docs |
324
485
  | `reference/` | 参考研究用的克隆仓库(不提交)<br>Cloned reference repos (not committed) |
325
486
 
326
- ## 路线图 · Roadmap
487
+ ## 路线图 | Roadmap
327
488
 
328
- 见 [`docs/roadmap.md`](docs/roadmap.md) · See [`docs/roadmap.md`](docs/roadmap.md).
489
+ 见 [`docs/roadmap.md`](docs/roadmap.md) | See [`docs/roadmap.md`](docs/roadmap.md).
329
490
 
330
- ## 参考项目 · References
491
+ ## 参考项目 | References
331
492
 
332
493
  | 项目 Project | 说明 About |
333
494
  | :--- | :--- |
334
- | [`zarazhangrui/lark-coding-agent-bridge`](https://github.com/zarazhangrui/lark-coding-agent-bridge) | 飞书 ↔ Claude Code / Codex 桥接,本项目的直接参照 |
335
- | [`deepseek-ai/deepseek-harness`](https://github.com/deepseek-ai/deepseek-harness) | DeepSeek Harness(`dsh`),agent 后端 |
336
- | [`grinev/opencode-telegram-bot`](https://github.com/grinev/opencode-telegram-bot) | OpenCode 的 Telegram 手机端,另一参照 |
495
+ | [`zarazhangrui/lark-coding-agent-bridge`](https://github.com/zarazhangrui/lark-coding-agent-bridge) | 飞书 ↔ Claude Code / Codex 桥接,本项目的直接参照<br>Feishu ↔ Claude Code / Codex bridge; the direct reference for this project |
496
+ | [`deepseek-ai/deepseek-harness`](https://github.com/deepseek-ai/deepseek-harness) | DeepSeek Harness(`dsh`),agent 后端<br>DeepSeek Harness (`dsh`), the agent backend |
497
+ | [`grinev/opencode-telegram-bot`](https://github.com/grinev/opencode-telegram-bot) | OpenCode 的 Telegram 手机端,另一参照<br>Telegram mobile client for OpenCode; another reference |
337
498
 
338
- ## 免责声明 · Disclaimer
499
+ ## 免责声明 | Disclaimer
339
500
 
340
501
  > [!NOTE]
341
502
  > 本项目为非官方社区工具,与 DeepSeek、字节跳动 / 飞书(Lark)无关联,亦未获得其背书。DeepSeek Harness、Feishu / Lark 及相关商标归各自权利人所有。
package/SECURITY.md CHANGED
@@ -33,14 +33,15 @@
33
33
  9. **管理操作鉴权**:飞书会话内对 dsh 配置的写操作(`/model default`、`/model add|remove`、
34
34
  `/provider add|update|remove`、`/key set|remove`)仅管理员可执行(管理员由
35
35
  `/invite admin <open_id>` 定义);查看类命令(`/model`、`/providers`、`/key list`)开放。
36
+ 10. **本地回调隔离**:`lark_notify` 工具的回调服务只绑定 `127.0.0.1`,每次启动生成随机
37
+ token 鉴权(不落盘、不进日志),请求体限 1MB;`/notify` 与角色 / 配置写命令同为管理员操作。
36
38
 
37
39
  ## 数据与凭据 · Data & credentials
38
40
 
39
41
  - 本地配置 `~/.dsh-lark/config.json` 以 `0600` 权限写入。
40
42
  - 飞书凭据明文保存在本机配置文件;日志与卡片不输出真实密钥。
41
- - 后台服务把 `DEEPSEEK_API_KEY`、`DSH_LARK_*`、`PATH` 等环境快照到
42
- `~/.dsh-lark/service/service.env`(`0600`);systemd / launchd 单元文件中的 `EnvironmentFile`
43
- 只引用该文件,不内联密钥。
43
+ - 桥接引擎在 dsh 宿主进程内运行,凭据与 `DSH_LARK_*` 环境直接随 dsh 进程提供,无独立服务
44
+ 环境快照文件;敏感值不进日志与卡片。
44
45
  - 后台运行日志写入 `~/.dsh-lark/profiles/<profile>/logs/bot.log`(JSON Lines,密钥字段脱敏后输出)。
45
46
  - 聊天命令管理的 dsh 配置按官方存储协议写入:`~/.dsh/settings.yaml`(只存 `apiKeyEnv`
46
47
  引用,不落字面密钥)与 `~/.dsh/.credentials.yaml`(目录 0700、文件 0600)。bot 永不回显
@@ -0,0 +1,30 @@
1
+ # dsh-lark-bot as a profile bundle.
2
+
3
+ # Installed with `dsh plugin --profile <name> add dsh-lark-bot` (or the
4
+ # single `dsh-lark-bot setup` command), dsh appends this package to the profile's
5
+ # `dsh.profile.bundles` and applies this patch on boot:
6
+ # - `dsh-lark-bot/plugin` starts the full bridge engine IN-PROCESS (Feishu
7
+ # channel, workspace/session layers, notify server, nested dsh SDK
8
+ # runtime) and exposes `ctx.larkBridge` (status / stop).
9
+ # - `dsh-lark-bot/notify` mounts the `lark_notify` tool for the host agent.
10
+ # First boot without credentials prints a QR code for one-time binding.
11
+ # Set DSH_LARK_DISABLED=1 to keep the engine stopped.
12
+
13
+ - insert:
14
+ - id: dsh-lark-bot
15
+ name: 'dsh-lark-bot/plugin'
16
+ config:
17
+ home: !!js process.env.DSH_LARK_HOME
18
+ tenant: !!js process.env.DSH_LARK_TENANT ?? 'feishu'
19
+ appId: !!js process.env.DSH_LARK_APP_ID
20
+ appSecret: !!js process.env.DSH_LARK_APP_SECRET
21
+ workspace: !!js process.env.DSH_LARK_WORKSPACE
22
+ adapter: !!js process.env.DSH_LARK_ADAPTER
23
+ model: !!js process.env.DSH_LARK_MODEL
24
+ disabled: !!js process.env.DSH_LARK_DISABLED === '1'
25
+
26
+ - id: lark-notify
27
+ name: 'dsh-lark-bot/notify'
28
+ config:
29
+ endpoint: !!js process.env.DSH_LARK_NOTIFY_URL
30
+ token: !!js process.env.DSH_LARK_NOTIFY_TOKEN