@addozhang/dsh-discord
English | 中文
DeepSeek Harness 的 Discord 优先适配器:在 Discord 服务器中运行 DSH 会话——@机器人下一个任务,线程即开,回答流式输出,审批与提问以按钮形式送到手机上,随手即可回应。
零额外进程:适配器是 DSH 插件,直接挂载到你的 dsh web profile。会话状态保存在 DSH,持久绑定保存在 profile 的存储域中。
功能
- @提及驱动会话 — 在已绑定的频道中,被授权的
@机器人 <任务>会锚定一个线程(你的消息成为首帖)、创建 DSH 会话,并且至多提交一次。线程内的后续消息无需 @ 即可排队。消息附带的图片会一并送达:在严格的大小与主机白名单约束下从 Discord CDN 下载,并作为 image parts 提交给多模态模型。 - 流式渲染 — typing 指示、单条头消息原地编辑、逐工具活动行、代码围栏感知的长文分段、一次性收尾;Turn 结束时活动消息会被删除。
- 审批与提问(双面) — DSH 的 ask 渲染为按钮、下拉菜单与自由文本弹窗,并同时镜像到 web/桌面端:两端先答先得,另一端的控件与卡片自动失效(无 web 客户端时 Discord 单独承载)。所有权强制校验(提问者——或后续 Turn 的线程属主——才能点击),超时清扫 fail-closed,结算后的控件原地置灰。
- 会话控制 —
/steer、/stop、/queue list|remove带运行所有权校验;/project bind|list|info与/session resume管理 Guild↔工作区绑定与历史会话;/guild forget供操作员清理。 - 模型切换 —
/model show读取会话的实时模型目录;/model select走交互式 provider → 模型 → 推理强度级联,也可直接填写provider/model应用。默认对所有授权成员开放,可收紧为仅 Host 操作员。 - 适配器状态 —
/info显示适配器版本、连接状态与项目链接(反馈/文档)。任意频道可用。 - 权限切换 —
/permission show/set读写会话权限预设(沙箱 + 审批捆绑档位),走宿主自己的/permission命令路径,journal 自动记审计;danger-full-access需按钮二次确认。 - 设置卡片,开箱双语 — Token 引导与连接/断开(存入 Host 凭据服务,绝不写入设置或日志)、服务器白名单、自动归档与语言。所有 Discord 可见文案提供中英双语;Bot 默认跟随 DSH 语言偏好,也可从卡片固定。
- 安全设计 — 显式服务器白名单内的 deny-first 授权。提及抑制双保险:每条请求携带
allowed_mentions,外加 wire body 的字节级提及中和。DSH 提交至多一次,并做保留 unknown 的对账——结果不明的投递绝不盲目重发。绑定重启后持久;READY 扫描会重建被删除的 category/控制频道,而把被删除的工作区频道视为用户意图(解除映射,workspace 保持可重新绑定)。
环境要求
- dsh CLI(web profile)。dsh 与适配器的通道需匹配——见版本支持。
- Node.js
^22.19.0 || >=24 - 一个 Discord 应用(含 Bot 用户),并在开发者门户启用 MESSAGE CONTENT 特权 intent(Developer Portal → 你的应用 → Bot → Privileged Gateway Intents)
版本支持
两条通道并行发布,各自跟随经过真机验证的 dsh 宿主面。适配器与 dsh CLI 请取同一行:
| 通道 | 适配器 | dsh CLI | 安装命令 |
|---|---|---|---|
| stable(0.2.1 线) | 0.6.6 — npm latest | 0.2.1-rc.3+ — npm latest/next | dsh plugin --profile web add @addozhang/dsh-discord |
| next(0.2.1 线) | >=0.6.5-rc.1 — npm next | 0.2.1-rc.3+ — npm latest/next | dsh plugin --profile web add @addozhang/dsh-discord@next |
| 旧线(0.1.7) | 0.5.0 — 精确版本号 | 0.1.7-rc.1 — 精确版本号 | dsh plugin --profile web add @addozhang/[email protected] |
- 适配器
0.6.5+不再随包携带任何 dsh 内部包:dsh-storage-domain的声明辅助(defineDomain/domainTable)已内联进插件,宿主的storageDomain服务按结构化契约消费。因此 dsh CLI / Desktop 在 0.2.1 线内升级(含0.2.1-rc.5起生效的插件精确版本兼容门)不会再禁用本插件。宿主 API 面仍由 startup 探针守护——宿主缺少所需服务面时拒绝激活并给出一条可操作诊断。 - 适配器
0.6.1–0.6.4的存量安装注意: 这些版本把[email protected]作为运行时依赖随包携带。dsh0.2.1-rc.5起宿主会禁用 profile 树中与运行时版本不精确匹配的插件行——被携带的副本盖住宿主副本后,storageDomain服务随之消失,插件保持 pending(UI 里既无工作区也无会话,数据无损)。把适配器升级到0.6.5+即修复;若曾在 profile 的package.json里手工添加过@deepseek-ai/dsh-storage-domain条目(一种临时缓解),请一并移除——否则下一次宿主升级它会自己撞上同一道门禁。 - 更早的配对关系不变:适配器
0.6.0-rc.1↔ dsh0.2.0-rc.2(dist-tags 已移到 0.2.1,两侧都只能精确版本号安装),适配器0.5.0同理反向钉在0.1.7-rc.1线;适配器>=0.5.0-rc.4(含0.5.0)使用 0.1.7 的 profile-backed settings forms 与控制器服务,在更旧的宿主上无法加载(startup 探针会给出一条可操作的诊断后拒绝激活);0.5.0-rc.1–rc.3对应 dsh0.1.6-alpha;适配器0.4.x使用旧版apiProxy宿主面(该面已在0.1.6-alpha中移除)——它仍是 dsh0.1.5stable 线的配对,可用精确版本号安装(如@addozhang/[email protected])。 - 切换 dsh CLI 通道:
npm install -g @deepseek-ai/dsh@latest(0.2.1-rc.x,配适配器 0.6.5+)或npm install -g @deepseek-ai/[email protected](配适配器 0.5.0)。 next刚发版后,@next规格可能解析到过期的缓存版本。若装到的版本偏旧,请改用精确版本号安装(如@addozhang/[email protected]),并核对 profilenode_modules中的version字段。
安装
使用 dsh CLI 安装——它会自动把包装进 profile 并注册 bundle。下面是 stable 通道;next 通道使用版本支持表中的 @next 命令(up / rm 同规格):
dsh plugin --profile web add @addozhang/dsh-discord
然后重启 dsh web 并刷新浏览器。dsh plugin 会自动对账 profile 的 bundle 列表——无需手动编辑。
升级与卸载使用同一条命令:
dsh plugin --profile web up @addozhang/dsh-discord # 升级;bundle 列表会重新对账
dsh plugin --profile web rm @addozhang/dsh-discord # 卸载;先执行 /guild forget 清理适配器记录
如果不用 CLI、手工管理 profile,等价做法是在 profile 目录里用 pnpm 安装本包,并在 dsh.profile.bundles 中自行登记:
{
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@addozhang/dsh-discord"] } }
}
配置
全部配置项位于 dsh-discord 设置命名空间,既可以在设置卡片中修改,也可以直接编辑 profile 的用户设置(settings.yaml):
| 配置项 | 默认值 | 说明 |
|---|---|---|
enabled | false | 适配器总开关;卡片 Connect 在 Token 存入后启动。 |
allowedGuildIds | [] | 服务器白名单。白名单之外零响应、零 DSH 调用。 |
memberUserIds / memberRoleIds | [] | 白名单 Guild 内的成员级授权。 |
administratorUserIds / administratorRoleIds | [] | 工作区管理员级(/project bind)。 |
deniedUserIds / deniedRoleIds | [] | 拒绝名单;优先级高于上述一切授权。 |
hostOperatorUserIds | [] | Host 操作员(/guild forget;启用 modelSelectOperatorOnly 后也包括 /model select)。 |
modelSelectOperatorOnly | false | 将 /model select 限制为 Host 操作员(仅 settings.yaml,卡片不展示)。默认 false:任何授权成员均可切换,且切换仍会更新 Host 默认。 |
permissionSelectOperatorOnly | true | 将 /permission set 限制为 Host 操作员(仅 settings.yaml)。默认 true——比 /model 更严,因为「完全权限」会同时解除沙箱与审批;可放开为任何授权成员可切换。 |
defaultVerbosity | essential-tools | 工具活动行粒度:text-only、essential-tools、full-tools。 |
language | auto | Bot 可见文案语言:auto 跟随 DSH 语言偏好(非中文渲染英文),或固定 zh/en。 |
streamUpdateIntervalMs | 800 | 流式编辑合并间隔(250–10000)。 |
typingIntervalMs | 7000 | typing 心跳(1000–30000)。 |
approvalTimeoutMs | 600000 | 审批超时(30000–86400000);超时自动拒绝。 |
questionTimeoutMs | 1800000 | 问题超时(30000–86400000);超时取消所属 Turn。 |
threadAutoArchiveMinutes | 1440 | 任务线程自动归档:60、1440、4320 或 10080。 |
dsh-discord:
allowedGuildIds: ["1517134847850709032"]
language: auto
设置卡片暴露三个高频项(服务器白名单、自动归档、语言)以及连接与 Token 面;其余键完全支持通过 settings.yaml 配置。非法的已存配置会保留最近一次有效配置。
初始设置
- 以至少以下权限把 Bot 邀请到你的服务器:查看频道、管理频道(适配器要创建自己的分类和工作区频道)、发送消息、创建公共线程、在线程中发送消息、上传文件、读取消息历史。
- 启动 profile 并打开 Web 界面。
- 在 Settings → Discord 中粘贴 Bot Token(开发者门户 → 你的应用 → Bot → Reset Token)并点击 Connect。Token 由 Host 凭据服务保存——绝不写入设置、日志或客户端。
- 填写 允许的服务器(服务器 ID 获取方式:Discord 开发者模式 → 右键服务器 → 复制服务器 ID)。白名单之外的一切都会被忽略。
/model select默认对任何授权成员开放(单人自用部署)。如需限制为 Host 操作员:在hostOperatorUserIds中加入其用户 ID,并把modelSelectOperatorOnly设为true(settings.yaml)。/guild forget始终需要 Host 操作员。- 选择 Bot 语言,然后在已绑定的频道 @机器人 开始会话。
命令
| 命令 | 位置 | 说明 |
|---|---|---|
/project bind | 任意频道 | 将 Guild 绑定到工作区(管理员;会创建主频道) |
/project list / info | 任意频道 | 列出工作区 / 查看当前频道绑定 |
/queue list, /queue remove | 会话线程 | 查看与移除待处理队列 |
/steer, /stop | 会话线程 | 插话或取消运行中的 Turn——线程内任意成员可操作当前 Turn(有意为之的共享驾驶舱模型,面向单人与小团队场景;审批/提问保持更严的提问人-or-线程主人规则) |
/info | 任意频道 | 显示适配器版本、连接状态与项目链接 |
/model show / select | 会话线程 | 查看实时模型目录;select 不带参数时走交互式 provider → 模型 → 推理强度级联(默认对所有授权成员开放) |
/session resume | 项目频道 | 自动补全选择本工作区的历史会话(显示标题与时间,最新优先),恢复为当前频道的新线程;空白、已挂线程、subagent、已归档的会话不会出现。线程会渲染会话历史——回答与工具摘要之外,用户输入以引用行回显(插件/系统注入永不回显)。适配器重启后线程只补齐错过部分:持久化的渲染水位抑制已投递过的历史,已绑定会话在重连时自动重订阅,因此从 web UI 发起的回合也会落进对应线程 |
/guild forget | 任意频道 | 仅操作员:移除适配器记录 |
/permission show / set | 会话线程 | 查看或切换会话权限预设(仅可查看 / 工作区内修改 / 完全权限——沙箱与审批的捆绑档位,目录取自宿主实时配置)。set danger-full-access 先要求按钮确认;预设自动补全;默认仅 Host 操作员可切换(permissionSelectOperatorOnly 可放开)。任何入口(含 web UI)的切换都会在线程渲染一行系统消息 |
设计说明
- 适配器为 function/namespace 插件(
inject: ['sessionController', 'workspaceController', 'sessionQuery', 'webServer', 'credentials', 'settings', 'storageDomain', 'connection', 'commands', 'permissionPresets']),将 Discord Gateway、命令面、流式渲染器与设置卡片挂载到 DSH web profile。 - 设置卡片是首次使用的引导面:Token 输入通过插件管理通道写入凭据服务的
DSH_DISCORD_BOT_TOKEN引用,然后触发启动链。断开连接保留凭据;留空重连直接使用已存 Token。 - 发布工作流通过 npm trusted publishing (OIDC) 认证——任何地方都不保存发布凭证。
- 适配器启动链带代际计数,Connect/Disconnect 与初始启动竞争时只会产生一个 Gateway。
- 凭据探测会回退到
resolve():Host 的describe()不识别环境变量来源的值——已连接的适配器不会被误报为未配置。 - 适配器日志默认静默:流程记录走 Host 的 debug 级别,失败形态的事件升到 warn——默认级别下不会向 DSH 进程打印任何内容。
- 链路级 trace:启动前设置
DSH_DISCORD_TRACE=1可将 mux 帧、丢弃点与投递结果输出到 stderr(默认静默)。存在原因:Host 在该面上未为插件日志接线任何 exporter,也没有日志级别开关——logger.debug输出不可见;Host 提供等价机制后应移除。
已知限制与推迟项
/preset、/skill、/host保持注销状态 — 控制模块已实现并通过单元测试,待路由接线时回归(/preset的会话线程守卫一并处理)。- verbosity 为全局设置(DSH 生态有按频道设置的先例)。
- 经 Kimaki 对齐后有意推迟:reconcile-interactions 接线、ask 等待期暂停 typing、fail-closed 绑定/会话属主 store 接线、凭据轮换监听。
- 已知张力:流式编辑 250ms 下限与高负载下 Discord 编辑预算的冲突(429 自愈),以及 typing 缺少时长上限看门狗。
开发
pnpm install --ignore-scripts
pnpm test # 825 tests incl. gateway/REST twin E2E
pnpm typecheck
pnpm lint
pnpm build # lib + client bundle
在 profile 中试用本地构建:
pnpm pack --pack-destination /tmp
dsh plugin --profile <your-profile> add file:/tmp/addozhang-dsh-discord-<version>.tgz
dsh plugin 会把相对路径锚定到调用目录,因此在已执行 pnpm build 的仓库里也可以直接 dsh plugin --profile <your-profile> add ../fiber。重复 pack + add 即可刷新已安装副本,然后重启 dsh web。
发布由 GitHub Actions 经 npm trusted publishing (OIDC) 完成(npm version <level> && git push --follow-tags)——任何地方都不保存发布凭证。实现遵循 openspec/changes/build-discord-native-adapter/ 中的 OpenSpec 变更(设计、能力 spec、验证清单、评审报告)。
许可证
MIT