dsh-plugin-im-remote-control:用飞书机器人远程驱动 DSH 会话

前言

DSH 的日常交互主要在桌面端完成。人离开工位时,想用手机或 IM 给正在跑的 Harness 会话发一条指令、看模型结论,或处理一次 ask 档审批,往往需要额外搭回调、内网穿透或自建桥接。dsh-plugin-im-remote-control(维护者 raven3005672)把飞书(Lark)机器人和 DSH 宿主绑在一起:消息经 sessionController.prompt 进入会话,回合结束把 assistant 文本回帖;审批和 ask_user_question 可在飞书里用卡片或斜杠命令处理。当前交付的是 direct 模式——插件进程内持有飞书 WebSocket 长连接,不需要公网 IP。包版本 0.2.0,许可证 MIT,在 DSH 插件目录中归类为客户端。

下面按定位、能力、安装配置、典型用法和注意事项说明。

这是什么

插件全称 dsh-plugin-im-remote-control,一句话定位:用飞书机器人远程控制一个 DSH 会话。飞书侧私聊或群聊 @ 机器人发消息,等价于在桌面输入框投递 user turn;插件监听会话事件,在聊天里回帖、发回执,并把审批与提问转发到飞书。中控会话还可通过 HTTP dispatch 把任务投到其他会话,由插件负责把执行结果绑回对应聊天。

设计细节(状态机、竞速、卡片协议等)见仓库 docs/DESIGN.md。微信接入与 gateway 冷启动模式代码保留但未启用。

核心功能

资料中已核实的能力如下。

能力 说明
飞书长连接 插件内 WebSocket,无需公网回调地址
私聊 / 群聊 私聊直接处理;群聊须 @ 机器人
消息进会话 走 sessionController.prompt,不绕过 session log
回合回帖 回合结束发送最后一步 assistant 文本;dispatch 任务首行带 【会话名】
表情回执 收到消息贴 Get;会话忙时贴 OneSecond(可由 ack 关闭)
分发接口 Bearer token + chat allowlist,POST /im-remote-control/dispatch
审批转发 ask 档审批以卡片发到飞书,按钮或 /approve、/deny,与桌面弹窗竞速
卡片提问 ask_user_question 以卡片展示选项;多选或自定义用 /answer
图片输入 下载飞书图片作为 image part(PNG/JPEG/GIF/WebP,单张 ≤10 MB,单条最多 4 张)
引用回复路由 引用机器人某条结果回复时,消息回到产生该结果的会话
设置页 DSH「设置 → 远程控制」可编辑凭据、allowlist、渠道等(改动需重启生效)
/whoami 返回发送者 open_id,用于配置 allowlist

尚未交付:非图片文件、语音/音频、微信、gateway 冷启动、超限重试、多实例等。

工作方式概览:

飞书(私聊 / 群聊 @)
  │  WebSocket 长连接(插件持有)
  ▼
dsh-plugin-im-remote-control(Host)
  ├─ sessionController.prompt  → 目标会话 user 消息
  ├─ ctx.on('session/event')   → 回合结束回帖
  ├─ ctx.on('approval/request') → 卡片审批
  ├─ ctx.on('user-questions/request') → 卡片提问
  ├─ card.action.trigger       → 按钮点击
  └─ ctx.webServer             → /dispatch、/check、/status

消息按 session 队列(mode: 'queue' 对应宿主 agent.followup())串行处理;只有经插件投递的回合会回帖,桌面手动发起的回合不受影响。

安装与启用

安装命令

从 npm 安装(将 <profile> 换成你的 profile 名):

dsh plugin --profile <profile> add dsh-plugin-im-remote-control

或从本地构建目录安装(lib/ 不入库,需先构建):

cd /path/to/dsh-plugin-im-remote-control && npm install && npm run build
dsh plugin --profile <profile> add /path/to/dsh-plugin-im-remote-control

运行环境要求(来自 package.json):Node ^22.19.0 || >=24.0.0,DSH >=0.2.0 <0.3.0;与 DSH 0.2.1-rc.2 标注为 compatible。

profile 配置

包的 dsh.bundle.patch 已 insert 插件行。你在 profile 的 cordis.patch.yml 里只需加一条同 id 的覆盖行(不要再次 insert 同 id,否则会挂两份长连接且设置页找不到配置):

- id: dsh-plugin-im-remote-control
  name: dsh-plugin-im-remote-control
  config:
    feishu:
      appId: cli_xxxxxxxxxxxxxxxx
      appSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    controllerSessionId: session-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    channels: [feishu]
    allowedChats:
      - oc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    allowedUsers:
      - name: 我自己
        openId: ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ack: true
    reply: true

覆盖行的 config 是整体替换,不是深合并,需要的键要一次写全。

配置改完后重启 DSH:Host 半边与飞书连接仅在启动时加载;设置页的修改同样要重启后才应用到连接。

可选兜底文件 $DSH_HOME/im-remote-control.json(默认 ~/.dsh/im-remote-control.json)可补充凭据与 allowlist;行内显式配置优先,allowlist 数组取并集。

飞书应用准备

  1. 在飞书开放平台创建企业自建应用,开启「机器人」。
  2. 权限:im:message、im:message.group_msg、im:message:send_as_bot。
  3. 事件订阅选长连接,订阅 im.message.receive_v1(无需公网地址)。
  4. 在回调配置页把 card.action.trigger 也设为长连接(卡片按钮交互);缺这一步点按钮会报 200340。
  5. 发布并把机器人加入目标群或私聊使用。
  6. 在飞书里对机器人发 /whoami,把返回的 open_id 填入 allowedUsers 或 allowedOpenIds。

访问控制(fail-closed)

allowedChats、allowedUsers、allowedOpenIds 至少配一项,否则插件只注册设置页探测、不连飞书(日志 no access control configured),也不会处理 dispatch。数组写错会直接报错,不能当成「空 = 不限制」。

主要配置项:

字段 说明
feishu.appId / feishu.appSecret 自建应用凭据;设置页 Secret 只显示掩码,不留存明文回显
controllerSessionId 中控会话 ID(兼容旧字段 sessionId)
channels 默认未设置即飞书;[] 表示不连飞书
ack / reply 默认 true,控制表情回执与回合回帖
enabled false 时不启动插件

典型用法

日常对话

私聊机器人直接发文字;群聊须 @ 机器人。文本与图片(在模型支持 image 输入时)进入 controllerSessionId 指定的中控会话,或由引用回复路由到产生某条机器人结果的执行会话。

斜杠命令

命令 作用
/whoami 返回发送者 open_id
/approve <id> 批准审批(allowed-once)
/deny <id> 拒绝审批
/answer <id> <文本> 回答提问;多选用逗号分隔选项

群聊发命令也要 @ 机器人。

审批卡片约 120 秒内有效,超时自动拒绝;提问卡片约 5 分钟内有效,超时只撤回卡片,桌面仍可作答。飞书与桌面竞速:谁先决定谁生效。

引用回复

对机器人发出的回合结果做「引用回复」,下一条消息进入该结果所属会话,适合 dispatch 出去的任务在飞书里做追问;不引用时消息仍进中控。

中控分发

中控会话可通过 POST /im-remote-control/dispatch 把任务投给任意会话。鉴权为 Authorization: Bearer <token>,且 chatId 须在 allowedChats 中。token 每次挂载随机生成,写入 $DSH_HOME/im-remote-control.token(权限 0600)。仓库提供 scripts/dispatch.mjs 可读该 token 调用。

设置页通过 POST /im-remote-control/check(头 x-imrc-check: 1)做只读探测,GET /im-remote-control/status 查看哪些字段已配置(不含 Secret 明文)。

适用场景与注意

适合谁:需要在飞书里收发 DSH 回合、远程点审批或答 ask_user_question 的开发者;希望用长连接、不暴露公网回调的小型自建部署。

权限与安全:allowlist 中的飞书账号等价于能在 DSH 进程权限下驱动 agent(含 shell、读写文件)。插件以当前 DSH 进程的系统用户权限运行;安装前应自行审阅 源码 与 MIT 许可证。官方建议从飞书驱动的会话使用 workspace-write + ask,避免 danger-full-access + never 让远程消息无刹车执行。

飞书账号即执行权,宜开启二次验证并保持 allowlist 尽量小。/im-remote-control/* 路由由插件挂在 Host web server 上,不走 GUI 的 cookie 认证:dispatch 靠 Bearer token;若 Host 绑定非回环地址,这些路由会一并暴露(/status 最坏仅泄露布尔状态与 Secret 末四位掩码)。

已知限制:非图片文件不转发;回帖仅最后一步 assistant 文本,超过约 3500 字符会截断;一个飞书应用只应有一条长连接、一个实例对应一个中控 sessionId;审批仅对 ask 档有意义(never 档不产生审批请求)。

DSH 生态强调「一切皆插件」;SkillHub 目录 为社区站点,与 DeepSeek / 幻方无官方从属关系。

结尾

dsh-plugin-im-remote-control 把飞书长连接、会话 prompt、回合回帖、审批与提问卡片和 dispatch 串成一条可落地的远程控制链路,direct 模式无需公网回调。查阅安装细节与更新说明见 GitHub 仓库,在 SkillHub 插件页 可浏览分类与简介。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye