dsh-discord-bot:把 dsh 投影到 Discord,不開放任何入站端口

前言

dsh 跑在家裏或公司的一臺機器上,人在外面,想看某個會話走到哪一步,或者臨時給某個工作區派個活。常規做法是 SSH 端口轉發,或者把 web UI 暴露到公網——前者要求你能路由到那臺機器,後者要求公網 IP 或反向代理,再不然就是掛一個隧道服務,而隧道服務手裏握着你機器的鑰匙。

dsh-discord-bot 走的是另一條路:把 Discord 當作控制面。機器只向 Discord gateway 發起一條出站 WebSocket 並保持住,命令從這條既有連接進來。不監聽端口、不轉發端口、不引入新的入站攻擊面。下面介紹這個插件能做什麼、怎麼裝、開哪些開關之前要想清楚什麼。

這是什麼

dsh-discord-bot 是 DeepSeek Harness(下稱 dsh)的社區插件,由 Oliver0804 維護,MIT 許可證,當前版本 0.3.4,依賴 discord.js ^14.27.0,要求 Node >= 20。它把一個 dsh profile 投影到一個 Discord guild 上:一個分類(category)下,每個工作區對應一個文本頻道,再配一套 /dsh … 命令,可以在頻道里讀會話軌跡、看即時子代理、下發工作。dsh 的理念是「一切皆插件」,遠程訪問這件事在這裏也被做成了插件。

核心功能

只出站的連接

插件向 Discord gateway 打開一條 WebSocket 並保持。每條命令都經由這條既有連接送達,所以 harness 可以在 NAT、CGNAT、酒店網絡或公司防火牆後面應答——無需端口轉發、動態 DNS、反向代理,也不需要持有你機器密鑰的隧道服務。只要這臺機器訪問得了 discord.com,你就能用手機查它。沒有任何東西在監聽,也就沒有新增的入站攻擊面。

讀取與監視

讀取側覆蓋:sessions、trajectories、raw event timelines、subagents、lineage。在工作區頻道內用 /dsh … 命令可以讀會話軌跡(session trajectories)與即時子代理(live subagents)。

監視側是 mirror: true:harness 的每個回合——不管由 web UI、tui 還是 cron 發起——都會即時出現在對應工作區頻道里。默認關閉,因爲它意味着持續把會話內容導出到聊天平臺。

寫入與運行

寫入包括註冊工作區和切換 profile 配置:

  • /dsh workspace:註冊工作區
  • /dsh model:切換默認模型
  • /dsh preset:切換 agent preset
  • /dsh permission:切換權限 preset

運行側只有一條 /dsh run <prompt>:向工作區 agent 交付提示詞,並流式回傳該回合。默認關閉(allowRun: false)——其餘命令都是在描述工作,只有這一條會讓工作真的發生在你的機器上。

頻道默認私有

分類與頻道拒絕 @everyone,只授予 bot 和 allowedUserIds 裏的用戶;名單爲空時只剩 guild owner。同一條規則也決定誰能運行命令,所以一個人能讀什麼和他能問什麼不會分叉。

隱私設置在每次同步時重新應用,而不是隻在創建時:已經存在的分類、或在此功能開啓之前建好的分類,同樣會被鎖上。如果 bot 缺少 Manage Channels,它做不了任何限制,會在日誌和 /dsh sync 裏明確說明,而不是讓你誤以爲已經鎖好。

另外,bot 以點擊者所用的語言回答。

安裝與啓用

先在 Discord 側準備 bot,再裝進 dsh profile。

1、創建 bot。在 Discord Developer Portal(https://discord.com/developers/applications)依次 New Application → Bot → Reset Token,複製 token。不需要任何特權 intents,Message Content 保持關閉。

2、邀請 bot 進服務器,scope 用 botapplications.commands

https://discord.com/oauth2/authorize?client_id=<APP_ID>&permissions=268487696&scope=bot+applications.commands

<APP_ID> 換成你的應用 ID。permissions=268487696 對應 View Channels、Send Messages、Embed Links、Attach Files、Manage Channels、Manage Roles。最後一個是容易漏的:寫頻道權限覆蓋——也就是讓頻道變私有的那件事——需要 Manage Roles,而 Discord 在缺少它時只報一句 Missing Access。缺了它 bot 仍能工作,但頻道保持全網可讀,並且每次同步都會提示。

3、安裝進 dsh profile:

npx dsh-discord-bot-setup --profile web

setup 腳本會安裝包、向 profile 註冊 bundle、把 token 寫入 $DSH_HOME/discord-bot.token(mode 600),並在 profile 的 patch 層追加一條配置覆蓋。沒傳的參數會交互式詢問;profile 裏已存在對應配置行時,腳本拒絕執行且不改動 profile。

非交互式寫法:

npx dsh-discord-bot-setup --profile web --guild 123456789012345678 --token "$TOKEN" --yes

--print 只預覽將寫入的行,不做任何更改。

4、重啓 dsh 並驗證:

dsh --profile web

打開新出現的 dsh 分類,運行 /dsh status

手動安裝與配置

不想用 setup 腳本的話:

dsh plugin --profile web add dsh-discord-bot

這一步安裝包並把插件掛進 profile 的 bundle 層,插件自帶的 cordis.patch.yml 由此成爲組合配置樹的一層。此時插件會離線啓動並在日誌裏說明——因爲還沒有人告訴它綁定哪個 guild。在 profile 自己的 cordis.patch.yml 裏補一條 id 定向 override:

- id: discord-bot
  config:
    guildId: '123456789012345678'
    tokenFile: '/Users/you/.dsh/discord-bot.token'
    categoryName: 'dsh'

注意這是 override,不是第二個 insert。bundle 層已經掛載了這一行,兩層帶同一 id 不會合並,而是組合出兩個實例——同一個 guild 上兩個 bot,每條命令回答兩次。用下面的命令檢查組合後的配置樹,確認 id: discord-bot 只出現一次:

dsh --profile web --dump-config

順帶一提,這個插件屬於 host plane,不要放進 agent preset:它服務所有工作區和所有會話,按會話複製一份在第二個會話就會衝突。

從 0.3.1 或更早版本升級

0.3.1 及更早版本沒有 bundle 層,setup 腳本當時寫進 profile 的是完整的 insert: 行;現在包自己掛載,那行會組合出第二個 bot。把舊行替換成上面的 id 覆蓋行,保留你自己的值:

# 之前                             # 之後
- insert:                         - id: discord-bot
    - id: discord-bot               config:
      name: 'dsh-discord-bot'         guildId: '…'
      config:                         tokenFile: '…'
        guildId: '…'

暫時不改也不會壞:bundle 的行沒有配置,只會記一條缺少 guildId 的日誌並保持離線,不會讓組合失敗。改完再用 --dump-config 確認只有一個 id: discord-bot

典型用法

經過上面的步驟,guild 裏會出現一個 dsh 分類,結構大致是:

dsh                    ← 分類
├── dsh                ← 工作區 /Users/you/Documents/dsh
├── sweepbot-home      ← 工作區 /Users/you/code/game/godot/sweepbot_home
└── my-api             ← 工作區 /Users/you/work/my-api

在對應頻道里發 /dsh run <prompt>,頻道里會出現一張運行卡片,標明當前在執行哪個工具,附 Trace、Timeline、Subagents、Todos、Export、Steer、Stop 等按鈕;Trace 裏是每一次工具調用與結果,底部附帶耗時、token 與緩存命中率。會話進行到哪一步、每一步做了什麼,都能在手機上直接看到。

安全邊界與兩個默認關閉的開關

mirrorallowRun 默認都是關的,原因相同:內容出口。

  • mirror: true 會持續把會話內容導出到 Discord。
  • allowRun: true 之後,allowedUserIds 內的任何人都能讓 agent 在 harness 機器上編輯文件、運行命令——從手機上。此時名單不再只是隱私邊界,而成了 shell 訪問名單。README 的建議是:名單隻留自己;開啓時權限 preset 優先選 ask,而不是 danger-full-access

邊界方面,bot 不會削弱 dsh 自身的沙箱與審批策略:本地會被 harness 拒絕的操作,在這裏同樣被拒絕,它也無法代你批准。它也跨不過工作區邊界——訪問不了其他工作區頻道里的會話。

適用場景與注意

適合:

  • dsh 跑在 NAT、CGNAT 或公司防火牆後面、沒有公網入口的機器上;
  • 需要在手機或任何裝了 Discord 的設備上查看和驅動會話;
  • 小範圍使用:把允許的人加進 allowedUserIds,頻道可讀範圍和命令權限保持一致。

不適合:

  • 不接受會話內容經過 Discord 的情況——命令應答與 mirror 都經由 Discord 這條通道;
  • 需要把訪問權開放給名單之外的人的場合,這套權限模型不爲此設計。

兩點提醒:插件以當前 dsh 進程的權限運行,它能觸達的範圍就是 dsh 進程能觸達的範圍;安裝任何第三方插件前,建議先讀一遍源碼、確認許可證(本項目爲 MIT)。

結尾

一句話回顧:一條出站 WebSocket,把工作區、會話軌跡和 harness 自己的命令帶到 Discord,全程不開放入站端口。項目地址與社區目錄頁:

  • GitHub:https://github.com/Oliver0804/dsh-discord-bot
  • 社區目錄頁:https://www.skillhub.cn/plugins/Oliver0804/dsh-discord-bot

社區目錄爲獨立站點,與 DeepSeek 或幻方無官方從屬關係。

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

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

小夜