@modesto_ma/dsh-channels 0.1.0-beta.1 → 0.2.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 +39 -29
- package/docs/access-control-design.md +4 -4
- package/docs/feishu-onboarding.md +11 -7
- package/lib/client.js +1698 -875
- package/lib/client.js.map +1 -1
- package/lib/index.js +447 -78
- package/lib/index.js.map +1 -1
- package/package.json +16 -14
- package/src/client/api.ts +20 -0
- package/src/client/catalog.ts +1 -1
- package/src/client/index.ts +1 -1
- package/src/client/panel/access-card.tsx +294 -0
- package/src/client/panel/access-tab.tsx +46 -0
- package/src/client/panel/advanced-tab.tsx +80 -0
- package/src/client/panel/cleanup-card.tsx +104 -0
- package/src/client/panel/connection-tab.tsx +214 -0
- package/src/client/panel/credentials-card.tsx +104 -0
- package/src/client/panel/index.tsx +862 -0
- package/src/client/panel/model-tab.tsx +23 -0
- package/src/client/panel/sessions-tab.tsx +21 -0
- package/src/client/panel/shared.tsx +488 -0
- package/src/client/panel/workspace-tab.tsx +40 -0
- package/src/client/styles.ts +24 -6
- package/src/config.ts +17 -4
- package/src/index.ts +24 -8
- package/src/service.ts +142 -26
- package/src/settings/contract.ts +207 -35
- package/src/settings/directory-picker.ts +121 -0
- package/src/settings/routes.ts +49 -2
- package/src/settings/surface.ts +159 -21
- package/src/client/panel.tsx +0 -1475
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ DeepSeek Harness(DSH)飞书渠道插件:**一个 dsh 实例对应一个飞
|
|
|
11
11
|
- **结构化提问**:模型调用 `ask_user_question` 时,插件监听主机 `user-questions/request` 瀑布并发一张问答卡(每个问题一组选项按钮,多选先勾选再「提交本题选择」),答案回填给模型;主机自带的应答者只有 Web 客户端,没有本插件时纯飞书会话会以 `NO_PROVIDER` 失败。超时(`questionTimeoutMs`,默认 5 分钟)或回合取消时本轮提问失败(fail-closed);没有可选项的问题直接提示用文字作答,**阻塞期间普通文本回复即作为该问题的自由文本答案**(同时支持多选后的自定义文本)
|
|
12
12
|
- **准入与授权(默认开启)**:**管理员不受白名单限制**(私聊、任意群聊——包括尚未授权的群——都能直接发起会话);其他人私聊只收到一条固定提示(`/userid` 例外),群聊需要「群已授权 + 用户在全局白名单」两层同时命中。机器人被拉进群后私聊管理员发**群信息卡**(未授权群附授权按钮,用于放行白名单用户);已授权群里未授权用户 @ 会触发用户授权卡。授权入口:飞书 `/auth` 命令、授权卡、Web 设置面板;管理员 open_id 在面板配置(私聊 `/userid` 获取)
|
|
13
13
|
- 全部基于飞书官方 SDK [`@larksuiteoapi/node-sdk`](https://www.npmjs.com/package/@larksuiteoapi/node-sdk)(WebSocket 长连接,免公网)
|
|
14
|
-
- **Web 设置面板**:Web/桌面端 **设置 →
|
|
14
|
+
- **Web 设置面板**:Web/桌面端 **设置 → 飞书渠道**,顶部状态头 + 6 个标签页(连接 / 会话与行为 / 模型 / 工作区 / 访问授权 / 高级);凭据不完整时插件不连接、面板显示三步引导,填写保存后自动连接(保存写入本机覆盖文件,部分字段需重连生效);详见下文「Web 设置面板」章节
|
|
15
15
|
|
|
16
16
|
设计与可行性论证见 [docs/feasibility-and-design.md](docs/feasibility-and-design.md)。
|
|
17
17
|
|
|
@@ -53,40 +53,40 @@ DeepSeek Harness(DSH)飞书渠道插件:**一个 dsh 实例对应一个飞
|
|
|
53
53
|
|
|
54
54
|
包内含可选的浏览器半区(`lib/client.js`,DSH client module):在 Web/桌面端 **设置** 导航注册「飞书渠道」分区。宿主没有 `webServer` 服务(headless profile)时不加载面板,飞书通道本身不受影响。
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
**连接时机**:启用插件时**不会无条件连接飞书**。插件启动先读取 profile 配置与 Web 覆盖,再检查 `appId` / `appSecret` 两个凭据引用能否解析出值:
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
- **凭据完整** → 建立飞书长连接(重启 DSH、重新加载插件时同样先检查再连接)。
|
|
59
|
+
- **凭据不完整** → 插件正常加载、**不建连接**、不报错,面板显示「待配置」与三步引导;在「连接」标签页填好两项凭据并保存后自动连接。
|
|
60
|
+
- **连接失败**(凭据错误、网络等)→ 记录在面板状态卡,插件保持加载;修好凭据或网络后点「重试」。
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
**面板结构**:顶部固定连接状态头(阶段徽标:待配置 / 未连接 / 连接中 / 已连接 / 连接失败、一句话摘要、刷新按钮),下方按标签页分区:
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
| 标签页 | 内容 |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| 连接 | 连接状态与连接信息(长连接状态、Bot open_id、运行时长、话题路由 / 活动会话 / 在途回复)、未配置时的三步引导、飞书应用凭据、最近一次连接失败原因、需重连的待生效提醒 |
|
|
67
|
+
| 会话与行为 | 私聊模式、普通群 @ 要求、话题兜底、首次私聊引导、权限切换、附件接收 |
|
|
68
|
+
| 模型 | 模型服务商、模型 id、推理档位、Agent 预设(宿主目录驱动的级联下拉) |
|
|
69
|
+
| 工作区 | 工作区根目录(可点「选择目录…」调用系统目录选择框)、过期工作区保留期、自动清理、「工作区清理」预览与手动执行 |
|
|
70
|
+
| 访问授权 | 管理员 open_id、准入模式、申请有效期;已授权群 / 用户白名单与待处理申请 |
|
|
71
|
+
| 高级 | 流式刷新 / 状态行 / SDK 日志级别、部署级只读参数、Web 覆盖文件路径与「清除 Web 覆盖」 |
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
**连接状态**:阶段徽标(待配置 / 未连接 / 连接中 / 已连接 / 连接失败)、飞书长连接状态、Bot open_id 尾号、运行时长、话题路由数 / 活动会话 / 在途回复、最近一次连接失败原因;每 5 秒自动刷新,也可手动刷新或**重启飞书连接**(会断开当前长连接并中断进行中的回复)。徽标不是健康时会额外显示「健康判定」原因——健康等级由宿主**所有 Cordis fiber** 折叠而来,因此「降级」也可能来自其它插件入口仍在等待依赖/加载(与飞书通道无关),原因行会列出对应插件名;「连接失败」只针对飞书连接本身,插件入口保持加载。
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
| --- | --- | --- |
|
|
68
|
-
| 工作区与文件 | `baseDir` | 立即生效(只影响之后新建的会话/工作区;已有会话不迁移) |
|
|
69
|
-
| 工作区与文件 | `workspaceRetention`、`workspaceRetentionAuto` | 立即生效(清理动作由「工作区清理」卡片触发) |
|
|
70
|
-
| 行为 | `dmMode`、`requireMention` | 需重启连接 |
|
|
71
|
-
| 行为 | `threadFallback`、`welcomeOnboarding`、`allowPermissionSwitch` | 立即生效 |
|
|
72
|
-
| 行为 | `accessMode`、`adminOpenId`、`authRequestTtlDays` | 立即生效(准入判定每次消息实时读取) |
|
|
73
|
-
| 内容与附件 | `acceptAttachments` | 立即生效 |
|
|
74
|
-
| 模型 | `provider`、`model`、`reasoningEffort`、`agentPreset` | 新会话生效(已有会话的模型/预设创建时已固定) |
|
|
75
|
-
| 流式卡片 | `refreshMs`、`statusRefreshMs`、`loggerLevel` | 需重启连接 |
|
|
75
|
+
**飞书应用凭据**:在「连接 → 飞书应用凭据」卡片里填写 **App ID / App Secret** 并保存,值经宿主 `ctx.credentials` 写入 DSH 凭据库(默认 `$DSH_HOME/.credentials.yaml` 的 `refs:` 段,仍遵循凭据层的解析优先级),面板只显示「已配置 / 未配置」与来源,**永不回显已存值**。两项齐全且通道未运行时保存后自动建立连接;已连接时保存只提示重连;只填了一项时保存成功但**不会连接**(状态保持「待配置」),补齐另一项后自动连接。已存值可以单独「移除已存值」;卡片下方显示的是凭据**引用名**(profile 配置里的 `appId` / `appSecret`),换引用名仍需改 profile 配置。
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
**统一保存**:除连接类操作外,可编辑字段共用一个草稿;每个表单标签页底部是「保存更改 / 放弃更改」,只提交改动过的字段,标注「需重连」的项在下次连接时生效;保存后「连接」标签页顶部横幅列出待生效项并提供一键重连。
|
|
78
78
|
|
|
79
|
-
`
|
|
79
|
+
**模型选择器**:模型与推理在面板里是**独立的「模型」标签页**:宿主 LLM 服务可用时,`provider` / `model` / `reasoningEffort` 与 `agentPreset` 渲染为**下拉选择**而不是手填:provider 来自 `ctx.llm.listProviders()`,model 来自所选 provider 的 `listModels()`,推理档位来自 `resolveModelInfo(provider, model).reasoning.efforts`,Agent 预设来自 `agentPresets.list()`。每个选择器的首项是「留空 = 部署默认 / 适配器默认 / roster 默认」,有部署默认模型(`agentDefaultModel`)或 roster 默认预设时会在标签里带上具体值。选择按依赖级联:先选 provider 才会加载 model,选了 model 才会加载推理档位;宿主暂时无法枚举的项(服务未挂载、适配器查询失败/超时)自动退回原来的自由文本框,已保存但当前列表里没有的值会作为「当前配置,不在宿主机列表中」选项保留,不会在打开面板时被静默改掉。级联查询走只读的 `GET /dsh-channels/catalog?provider=…&model=…`(Host 侧短 TTL 缓存,单次查询 4 秒上限)。`provider` 与 `model` 在宿主侧是一条完整的请求路由,因此面板保存时要求**两者同时设置或同时留空**,不允许只选一半。
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
`baseDir` 是**模型/工具产生文件的落点**:**每个飞书话题拥有一个独立工作区**(私聊 `<baseDir>/topics/p2p/<open_id>/<topic>/`,群聊 `<baseDir>/topics/groups/<chat_id>/<open_id>/<topic>/`,topic 来自话题 id;无话题的降级会话用 session id。旧版本留下的「用户 × 聊天」共享工作区仍在原路径,与新话题工作区互不嵌套)。面板里只接受**绝对路径**(`~` 开头按家目录展开,拒绝文件系统根目录),保存时会创建并校验该目录,不可用时当场报错,不会等到飞书里提示「会话创建失败」。已有 Session / 工作区不会被迁移,因此切到新目录后旧话题继续用旧工作区(话题内 `/renew` 也一样),只有之后新开的话题使用新目录。
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
**可视化选择工作区根目录**:输入框旁的「选择目录…」按钮会调用**宿主机的系统目录选择框**(macOS 的 NSOpenPanel / Windows 的文件夹对话框),选中后把绝对路径填进草稿,仍需点「保存更改」才落盘。该能力转发自宿主可选的 `ctx.directoryPicker` 服务:桌面端/本机 GUI 会话(native 后端)提供按钮;headless、远程或 SSH 会话没有可服务的显示会话(browse 后端),面板不显示按钮、保留手写输入,插件在缺少该服务的旧宿主上照常加载。选择框打开期间请求保持挂起;取消是正常结果,不会报错。
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
**工作区清理**:「工作区」标签页内提供保留期与「工作区清理」卡片,用于回收长期不用的飞书工作区。保留期可选 `off / 7 天 / 30 天 / 90 天 / 180 天`(默认 `off`);卡片实时预览「插件工作区总数 / 可清理数量 / 预计释放空间」,点「立即清理」需二次确认;也可开启 `workspaceRetentionAuto` 在启动后与每日自动执行一次。清理动作只针对 `<baseDir>` 下由本插件创建(标题以 `飞书私聊 ·` / `飞书群聊 ·` 开头)的工作区:删除目录、注销 workspace registry,并把仍指向它的活跃路由退休为墓碑(该旧话题收到消息会明确提示「话题已过期」,不会恢复到一个已删除的目录)。**Harness Session 日志与事件记录不删除**;删除不可恢复,`off` 时按钮禁用。未建立飞书连接时(存储域未打开)预览不可用,卡片会提示先连接。
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
**访问授权**:「访问授权」标签页集中管理准入:管理员 open_id(`ou_` 开头,私聊 `/userid` 获取)、准入模式、授权申请有效期;「已授权群」「已授权用户」列表支持增删(群 ID 可从入群群信息卡或 `/groupid` 获得,用户 open_id 可用 `/userid` 查看);「待处理申请」可一键授权/忽略。白名单只约束非管理员:管理员在任何私聊/群聊都直接放行。`guarded` 且管理员未配置时标签页顶部会红字提示“当前会拒绝所有对话”。授权白名单与申请记录保存在插件 `storageDomain`(`channels_routes` 域),重启后保留;未建立飞书连接时白名单尚未加载,标签页会提示「连接建立后加载授权列表」并禁用写操作。
|
|
88
88
|
|
|
89
|
-
**配置层级**:`configSchema` 默认值 < profile `cordis.patch.yml` 的 `config` < Web 面板覆盖。面板只把可编辑字段写入 `$DSH_HOME/dsh-channels/settings.json`(可用配置项 `settingsFile`
|
|
89
|
+
**配置层级**:`configSchema` 默认值 < profile `cordis.patch.yml` 的 `config` < Web 面板覆盖。面板只把可编辑字段写入 `$DSH_HOME/dsh-channels/settings.json`(可用配置项 `settingsFile` 改路径);「高级 → 清除 Web 覆盖」删除该文件并回落到 profile 配置。`baseDir` 可在「工作区」标签页编辑(绝对路径;只影响之后新建的会话);超时、路由 TTL 等仍只读展示。凭据**值**在「连接 → 飞书应用凭据」编辑,凭据**引用名**(`appId` / `appSecret` 配置项)仍由 profile 配置决定。
|
|
90
90
|
|
|
91
91
|
**为什么落在插件自己的文件而不是 profile 的 `cordis.patch.yml`?** DSH 提供官方 `ctx.configEditor.edit()`,可以安全写 profile patch(完整 Config 校验、保留注释与 `!!js`、原子替换、失败回滚、与 HMR 串行);但它是「完整配置编辑」通道——本插件的 Config 是 zod,没有 schemastery `.volatile()` 标记,普通字段写入会触发 Loader 重载插件,等于每次保存都断开并重连飞书;而且该服务只在有 `profileContext` 的启动器(桌面端 / `dsh web`)存在。`$DSH_HOME/<plugin>/` 是 DSH 插件保存运行时数据的惯例(如 dsh-pet 的 `$DSH_HOME/dsh-pet/`),因此面板偏好写入 `$DSH_HOME/dsh-channels/settings.json`:保存即生效(需重连字段除外)、可一键清除回退、不依赖 `profileContext`;profile 的 `cordis.patch.yml` 继续作为部署级基础配置层。若将来要求「所有配置统一进 profile」,迁移路径是改用 `ctx.configEditor.edit()` 并接受保存触发插件重载。
|
|
92
92
|
|
|
@@ -149,7 +149,13 @@ src/
|
|
|
149
149
|
├── feishu-channel.ts # 官方 SDK Channel 适配(可注入 stub)
|
|
150
150
|
├── client/ # 浏览器半区:设置 →「飞书渠道」页面(构建到 lib/client.js)
|
|
151
151
|
│ ├── index.ts # client 插件入口:settings.section 注册 + 样式
|
|
152
|
-
│ ├── panel
|
|
152
|
+
│ ├── panel/ # 页面外壳 + 六个标签页
|
|
153
|
+
│ │ ├── index.tsx # 加载 / 5s 状态轮询 / 全局草稿 / catalog 级联 / 顶部状态头 / Tab
|
|
154
|
+
│ │ ├── shared.tsx # 字段渲染原语、保存栏、阶段徽标、草稿校验
|
|
155
|
+
│ │ ├── connection-tab.tsx # 连接:三步引导 / 连接信息 / 待生效提醒 / 凭据卡
|
|
156
|
+
│ │ ├── credentials-card.tsx # App ID / App Secret 编辑(不回显)
|
|
157
|
+
│ │ ├── sessions-tab.tsx / model-tab.tsx / workspace-tab.tsx / access-tab.tsx / advanced-tab.tsx
|
|
158
|
+
│ │ └── cleanup-card.tsx / access-card.tsx
|
|
153
159
|
│ ├── catalog.ts # 选择器目录折叠:Host 字段 + 实时目录 → 表单字段
|
|
154
160
|
│ ├── api.ts # 同源 /dsh-channels/* 请求封装
|
|
155
161
|
│ └── styles.ts # 语义 token 样式(注入一次)
|
|
@@ -157,7 +163,8 @@ src/
|
|
|
157
163
|
│ ├── contract.ts # 双端共享 wire 类型 / 字段清单 / 路由常量
|
|
158
164
|
│ ├── overlay.ts # settings.json 读写、校验、合并
|
|
159
165
|
│ ├── catalog.ts # 宿主选择目录:provider/model/推理档位/preset
|
|
160
|
-
│ ├──
|
|
166
|
+
│ ├── directory-picker.ts # 系统目录选择框适配(ctx.directoryPicker native 后端)
|
|
167
|
+
│ ├── surface.ts # 状态 / 面板视图模型 + 保存 / 清除 / 重连 / 选目录
|
|
161
168
|
│ └── routes.ts # HTTP 路由 + 同源写保护
|
|
162
169
|
└── workspaces.ts # 话题 → 独立工作区目录 + 附件 staging 目录
|
|
163
170
|
```
|
|
@@ -184,7 +191,9 @@ DSH_HOME=$DSH_HOME pnpm dsh plugin --profile web add link:/path/to/dsh_channels
|
|
|
184
191
|
|
|
185
192
|
npm 发行包已包含构建产物:Host 入口是 `lib/index.js`(profile 直接以 ESM 加载,不经过 TypeScript strip;`package.json` 的 `main` 指向它),设置面板是 `lib/client.js`。本地 `link:` 安装前仍必须先执行 `pnpm build`。安装或修改后重启 dsh(桌面端重启应用,`dsh web` 重启服务并刷新页面)。DSH 只加载已构建产物,直接改 `src/` 不会生效;没有 web 载体的 profile 不注册面板,飞书通道照常运行。
|
|
186
193
|
|
|
187
|
-
包内的 `cordis.patch.yml` 会自动把 `@modesto_ma/dsh-channels` 加入 profile 的 bundle 列表,并提供稳定 `id: dsh-channels` 的 Loader 行;profile
|
|
194
|
+
包内的 `cordis.patch.yml` 会自动把 `@modesto_ma/dsh-channels` 加入 profile 的 bundle 列表,并提供稳定 `id: dsh-channels` 的 Loader 行;profile 可在 `$DSH_HOME/profiles/web/cordis.patch.yml` 中按该 id 提供实例配置(不提供时使用默认凭据引用名):
|
|
195
|
+
|
|
196
|
+
`appId` / `appSecret` 也各自有默认引用名 `FEISHU_APP_ID` / `FEISHU_APP_SECRET`:凭据库使用这两个名字时,bundle 行即使暂时没有 `config` 也能完成 Loader 校验并启动 Host 半侧,从而先打开设置面板补全凭据;使用自定义引用名时再按需覆盖。
|
|
188
197
|
|
|
189
198
|
```yaml
|
|
190
199
|
- id: dsh-channels
|
|
@@ -231,11 +240,11 @@ FEISHU_APP_SECRET: xxxxxxxx
|
|
|
231
240
|
|
|
232
241
|
也可以不手改文件:安装并在 Web 面板里打开 **设置 → 飞书渠道**,在「飞书应用凭据」卡片填入 App ID / App Secret 保存即可(值同样写进该凭据库)。
|
|
233
242
|
|
|
234
|
-
文件必须仅属主可读(dsh 强制校验,否则拒绝启动):`chmod 600 $DSH_HOME/.credentials.yaml`。解析优先级:进程环境变量 > `.credentials.yaml` > `<cwd>/.env` > `$DSH_HOME/.env`(由 `dsh-credentials-local` 提供,热加载)。配置里只写引用名,明文密钥会被 schema
|
|
243
|
+
文件必须仅属主可读(dsh 强制校验,否则拒绝启动):`chmod 600 $DSH_HOME/.credentials.yaml`。解析优先级:进程环境变量 > `.credentials.yaml` > `<cwd>/.env` > `$DSH_HOME/.env`(由 `dsh-credentials-local` 提供,热加载)。配置里只写引用名,明文密钥会被 schema 拒绝。改动凭据后:Web 面板保存会即时写入,未连接时自动建立连接、已连接时提示重连;手改 `.credentials.yaml` 由凭据层热加载,但正在运行的连接不会自动使用新值,需在面板点「重启飞书连接」。
|
|
235
244
|
|
|
236
245
|
验证组合(不启动服务):`DSH_HOME=$DSH_HOME pnpm dsh web --dump-config | grep dsh-channels`
|
|
237
246
|
|
|
238
|
-
启动成功标志(控制台):`[dsh-channels] feishu long connection established, bot open_id: ou_xxx
|
|
247
|
+
启动成功标志(控制台):`[dsh-channels] feishu long connection established, bot open_id: ou_xxx`;凭据不完整时不会连接,日志会提示缺少的凭据引用(如 `飞书应用凭据未配置完整(缺少 FEISHU_APP_SECRET…)`),打开 Web **设置 → 飞书渠道 → 连接** 补齐即可。
|
|
239
248
|
|
|
240
249
|
宿主 profile 已内置所需服务(agent-loop、llm-deepseek、session 持久化、storage-domain、workspace);推荐确认 `dsh-token-meter` 已启用(卡片上下文占用显示)。
|
|
241
250
|
|
|
@@ -284,6 +293,7 @@ FEISHU_APP_SECRET: xxxxxxxx
|
|
|
284
293
|
- 重启修复会**全量替换**中断的卡片:旧进程里已流出的部分正文随之消失(本地没有副本,patch 是全量语义);修复是一次性 + 一次重试,不再无限重试。
|
|
285
294
|
- 路由 GC 是 TTL 兜底:未监听飞书“群解散/话题删除”事件做主动清理;真实话题过期后写入持久化墓碑,用户回来会收到明确拒绝,不会在旧话题中误建新 Session。
|
|
286
295
|
- 消息去重是**至多一次**语义:接受后、副作用完成前崩溃的极小窗口内,重投消息会被丢弃——中断修复卡提示“请重新发送消息”,用户重发即可(新 message id 正常处理)。
|
|
296
|
+
- 插件启用时**不会无条件连接飞书**:只有两项凭据都能解析时才建连,凭据不完整时插件照常加载、面板显示「待配置」引导;连接失败只影响连接本身,插件入口保持加载。
|
|
287
297
|
- Web 面板编辑的是当前凭据**引用名**背后的值(profile 配置 `appId` / `appSecret` 指向的 ref);更换引用名仍需编辑 profile 配置并重启 DSH。凭据提供方只读时面板会禁用输入并提示。
|
|
288
298
|
- Web 面板的模型字段优先渲染为宿主目录驱动的下拉(provider → model → 推理档位);宿主没有 LLM 服务或目录查询失败时退回自由文本,手填错误仍会在下一次模型请求时由 Host 报错;「重启飞书连接」会中断进行中的回复。
|
|
289
299
|
- 持久化盘点与全部缺口状态见 [docs/persistence.md](docs/persistence.md)。
|
|
@@ -300,4 +310,4 @@ pnpm verify:client # client loader 冒烟
|
|
|
300
310
|
pnpm check # 以上全部
|
|
301
311
|
```
|
|
302
312
|
|
|
303
|
-
测试以 stub 替换官方 SDK 与 DSH 宿主服务,无需真实凭据。`tests/settings.test.ts` 覆盖:覆盖层 schema
|
|
313
|
+
测试以 stub 替换官方 SDK 与 DSH 宿主服务,无需真实凭据。`tests/settings.test.ts` 覆盖:覆盖层 schema/层级、面板视图模型、连接阶段(待配置/未连接/已连接/失败)、凭据保存按就绪度连接、HTTP 路由(含同源写保护)、`apply()` 的 webServer 接线、模型选择器的宿主目录与降级行为;`tests/client-catalog.test.ts` 覆盖浏览器半区的目录折叠(含依赖项解禁回归);以及 `FeishuService` 的覆盖加载 / 热更新 / 重启 / 连接失败记录 / 监听器释放。
|
|
@@ -392,7 +392,7 @@ SDK 的 `LarkChannel` 已内置 `EventMap['botAdded']`(`im.chat.member.bot.add
|
|
|
392
392
|
1. 装好插件、配好凭据、重启;启动日志:
|
|
393
393
|
`[dsh-channels] 准入=guarded,管理员未配置:所有对话将被拒绝;私聊机器人发送 /userid 获取 open_id`
|
|
394
394
|
2. 在飞书私聊机器人发 `/userid`(任何私聊发送者都可用,只回固定文本、不建会话)→ 拿到 `ou_xxx`;
|
|
395
|
-
3. Web 面板「飞书渠道 →
|
|
395
|
+
3. Web 面板「飞书渠道 → 访问授权 → 管理员 open_id」填入 `ou_xxx` 保存(立即生效);
|
|
396
396
|
4. 面板状态显示管理员已配置;管理员私聊可正常对话。
|
|
397
397
|
|
|
398
398
|
### 场景 B:给非管理员开启群的访问(三种入口)
|
|
@@ -426,7 +426,7 @@ SDK 的 `LarkChannel` 已内置 `EventMap['botAdded']`(`im.chat.member.bot.add
|
|
|
426
426
|
|
|
427
427
|
## 7. Web 面板
|
|
428
428
|
|
|
429
|
-
### 7.1
|
|
429
|
+
### 7.1 访问授权新增字段(`access` 组)
|
|
430
430
|
|
|
431
431
|
| key | kind | 说明 |
|
|
432
432
|
|---|---|---|
|
|
@@ -462,7 +462,7 @@ SDK 的 `LarkChannel` 已内置 `EventMap['botAdded']`(`im.chat.member.bot.add
|
|
|
462
462
|
UI:
|
|
463
463
|
|
|
464
464
|
- 顶部警示条:`guarded` 且管理员未配置时红字提示“当前会拒绝所有对话,请先配置管理员 open_id”;
|
|
465
|
-
- 「管理员」行:显示当前 open_id /
|
|
465
|
+
- 「管理员」行:显示当前 open_id / 未配置(编辑在上方准入表单里);
|
|
466
466
|
- 「已授权群」列表:群名(未知时显示 chat_id)、来源、时间 + 移除;输入框可手填 chat_id 添加;
|
|
467
467
|
- 「已授权用户」列表:昵称(未知时显示 open_id)+ 移除;输入框可手填 open_id 添加;
|
|
468
468
|
- 「待处理申请」列表:群申请 / 用户申请,各带「授权」「忽略」;
|
|
@@ -504,7 +504,7 @@ UI:
|
|
|
504
504
|
- [x] `InboundRouter` 接入 `access.admit`;话题/附件/问答/续写的 sender + chatId 校验
|
|
505
505
|
- [x] 命令面准入:`/userid`、`/groupid` bootstrap 放行;`/auth` 管理员专用;其他命令(含非法/未知命令)先判准入再发卡
|
|
506
506
|
- [x] `/auth` 核心子命令:`status` / `allow` / `revoke` / `list` / `user add|remove`
|
|
507
|
-
- [x] Web
|
|
507
|
+
- [x] Web 面板:「访问授权」标签页加 `adminOpenId`/准入模式;白名单卡片(群/用户增删,自动授权仍无开关);`/dsh-channels/access*` 路由(同源写保护)
|
|
508
508
|
- [x] 入群事件接线(wrapper `onBotAdded` + `getChatInfo`):管理员私聊收群信息卡,未授权群附「授权本群 / 忽略」按钮
|
|
509
509
|
- [x] 管理员引导:启动日志、`/userid` 文案、面板未配置警示
|
|
510
510
|
- [x] 错误兜底文案脱敏
|
|
@@ -84,7 +84,9 @@ FEISHU_APP_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
|
84
84
|
chmod 600 $DSH_HOME/.credentials.yaml
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
解析优先级(由 `dsh-credentials-local` 提供,热加载):进程环境变量 > `.credentials.yaml` > 启动目录 `.env` > `$DSH_HOME/.env
|
|
87
|
+
解析优先级(由 `dsh-credentials-local` 提供,热加载):进程环境变量 > `.credentials.yaml` > 启动目录 `.env` > `$DSH_HOME/.env`。不想用凭据库时,直接导出环境变量也能生效。凭据改动后不必重启 dsh:面板保存会即时写入并自动连接/提示重连;手改 `.credentials.yaml` 由凭据层热加载,但运行中的连接不会自动换用新值,需在面板点「重启飞书连接」。
|
|
88
|
+
|
|
89
|
+
**连接时机**:启用插件时不会无条件连接飞书。插件加载后先检查 `appId` / `appSecret` 两个凭据引用是否都能解析:都就绪才建立长连接;缺任意一项时插件照常加载(设置面板可用),状态为「待配置」且不连接;连接失败只记录在面板里,插件入口保持加载。因此可以「先装插件 → 在面板里填凭据 → 自动连接」,也可以在装插件前就把凭据写进凭据库。
|
|
88
90
|
|
|
89
91
|
### 3.2 写补丁层
|
|
90
92
|
|
|
@@ -115,7 +117,7 @@ chmod 600 $DSH_HOME/.credentials.yaml
|
|
|
115
117
|
|
|
116
118
|
| 配置项 | 默认 | 说明 |
|
|
117
119
|
|--------|------|------|
|
|
118
|
-
| `appId` / `appSecret` |
|
|
120
|
+
| `appId` / `appSecret` | `FEISHU_APP_ID` / `FEISHU_APP_SECRET` | 凭据引用名(shell 标识符),经 `ctx.credentials` 解析;仅当凭据库使用其它变量名时才需要覆盖。明文密钥会被拒绝 |
|
|
119
121
|
| `baseDir` | `./channels-data` | 工作区目录树根:每个话题一个独立工作区,`topics/p2p/<open_id>/<topic>/`、`topics/groups/<chat_id>/<open_id>/<topic>/`(模型/工具产生文件的落点);Web 面板可覆盖,只接受绝对路径,`~` 展开,保存时创建并校验目录,只影响之后新建的话题 |
|
|
120
122
|
| `provider` / `model` | 部署默认 | 新建 session 的路由;省略时继承部署默认 |
|
|
121
123
|
| `reasoningEffort` | 适配器/provider 默认 | Session 初始/重置推理档位;可在话题内用 `/effort` 覆盖 |
|
|
@@ -135,7 +137,7 @@ chmod 600 $DSH_HOME/.credentials.yaml
|
|
|
135
137
|
插件默认 `accessMode: 'guarded'`:**没有配置管理员时,所有对话都会被拒绝**(这是 fail-closed 的安全默认值)。初始化顺序:
|
|
136
138
|
|
|
137
139
|
1. 启动 dsh 后在飞书**私聊机器人**发送 `/userid`(未配置管理员时任何私聊用户都可以用,只回固定文本,不建会话)→ 复制返回的 `ou_...`;
|
|
138
|
-
2. 打开 Web **设置 → 飞书渠道 →
|
|
140
|
+
2. 打开 Web **设置 → 飞书渠道 → 访问授权**,把 `ou_...` 填进「管理员 open_id」并保存(立即生效);也可以直接写 profile 的 `adminOpenId`;
|
|
139
141
|
3. 现在管理员私聊机器人即可正常对话。**其他用户私聊会收到一条固定提示**(“非管理员禁用私聊功能哦…”),不会建会话;
|
|
140
142
|
4. **给群授权**(三种入口任选;目的是放行**非管理员**,管理员本人在任何群都能直接对话):
|
|
141
143
|
- 机器人被拉进群 → 管理员私聊收到**群信息卡**(群名/`chat_id`/成员数/邀请人)→ 点「授权本群」;
|
|
@@ -175,18 +177,20 @@ DSH_HOME=$DSH_HOME pnpm dsh web # 默认 http://127.0.0.1:3080
|
|
|
175
177
|
|
|
176
178
|
> 第二行只在宿主挂载了 `approval` 服务时出现;若显示 `主机未挂载 approval 服务,HITL 审批应答关闭`,说明该部署未启用 HITL(`approval/request` 事件永远不会派发),并非插件故障。
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
**未配置凭据(不是启动失败)**:日志会提示 `飞书应用凭据未配置完整(缺少 FEISHU_APP_…)`,插件照常加载但**不连接**;打开 Web **设置 → 飞书渠道 → 连接**,按三步引导填写 App ID / App Secret 并保存后自动连接。
|
|
181
|
+
|
|
182
|
+
**常见连接失败**(插件保持加载,面板「连接」标签页显示原因,可重试):
|
|
179
183
|
|
|
180
184
|
| 输出 | 原因 |
|
|
181
185
|
|------|------|
|
|
182
186
|
| `could not resolve bot identity via /open-apis/bot/v3/info` | App ID/Secret 错误,或未开启机器人能力 |
|
|
183
187
|
| `permission_denied` / `invalid tenant access token` | 同上,先核对凭证再查权限 |
|
|
184
|
-
| `credential "FEISHU_APP_ID" is not configured` |
|
|
188
|
+
| `credential "FEISHU_APP_ID" is not configured` | 连接时解析不到凭据(例如刚手改了凭据库但面板状态尚未刷新,或环境变量缺失),见 §3.1;面板保存后会自动重连 |
|
|
185
189
|
| `is readable beyond its owner (mode 644)` | `.credentials.yaml` 权限过宽,`chmod 600` 后重启 |
|
|
186
190
|
| `dsh: plugin tree failed to load … dsh-channels` | 插件本身加载失败(多为 `name:` 拼写或未安装),看后续 cause |
|
|
187
191
|
| 无任何 `dsh-channels` 输出 | 插件未装载:检查 `--dump-config` 是否含条目、补丁层是否用了 `insert:` 格式 |
|
|
188
192
|
|
|
189
|
-
> 说明:插件内部其余日志走 dsh 的 cordis logger,web
|
|
193
|
+
> 说明:插件内部其余日志走 dsh 的 cordis logger,web 组合下部分早期日志可能只进缓冲不落终端;**生命周期日志**(连接成功 / 连接失败 / 凭据未配置)额外直接输出到控制台,联调时以它们为准。
|
|
190
194
|
|
|
191
195
|
## 5. 三通道联调清单
|
|
192
196
|
|
|
@@ -242,7 +246,7 @@ DSH_HOME=$DSH_HOME pnpm dsh web # 默认 http://127.0.0.1:3080
|
|
|
242
246
|
| 私聊无响应 | 用户是否在应用**可用范围**内;权限 `im:message.p2p_msg:readonly` 是否随版本发布;若返回的是“非管理员禁用私聊功能哦”,说明准入生效(把该用户加入白名单或让管理员对话) |
|
|
243
247
|
| 私聊提示“机器人尚未配置管理员” | `accessMode: 'guarded'` 且未配置 `adminOpenId`:按 §3.3 在面板填写管理员 open_id |
|
|
244
248
|
| 机器人被拉进群但管理员没收到群信息卡 | 是否订阅 **im.chat.member.bot.added_v1** 事件并重新发布版本;群信息读取权限是否已开通(`getChatInfo` 失败只会缺群名,不影响卡片本体) |
|
|
245
|
-
| 群内 @ 机器人无响应(登录台无 access 报错) | 管理员不受白名单限制,可直接对话;**非管理员**需要该群已授权且自己在用户白名单里。可用 `/auth status`(管理员)或 Web
|
|
249
|
+
| 群内 @ 机器人无响应(登录台无 access 报错) | 管理员不受白名单限制,可直接对话;**非管理员**需要该群已授权且自己在用户白名单里。可用 `/auth status`(管理员)或 Web 面板「访问授权」标签页确认 |
|
|
246
250
|
| `/auth` 无反应 | `/auth` 仅管理员可用;非管理员在群里会被静默忽略、私聊会收到固定提示 |
|
|
247
251
|
| 群聊 @ 无响应 | 事件订阅是否勾选“接收群聊中 @ 机器人消息”;机器人是否在群内且未被群主禁言 |
|
|
248
252
|
| 有 Typing 但无卡片 | 权限 `im:message` / `im:message:update`;卡片 2.0 需要较新的飞书客户端(升级客户端后重试) |
|