dsh-api:在 dsh 已監聽的端口上開一層 HTTP 控制面

前言

用腳本、桌面殼或編輯器插件驅動 dsh 時,常遇到一個問題:改語言、切工作區、感知 agent 什麼時候空閒,這些能力都長在 dsh 進程內部。外部進程要麼直接伸手調它的 in-process services,要麼各寫各的通道,接口不統一,耦合也重。

dsh-api 的做法是把這件事收斂到一個入口:dsh 本來就在 127.0.0.1 上監聽 HTTP,插件直接在這條 socket 上掛一組 /dsh-api/* JSON 路由,同機的任何進程——桌面包裝器、瀏覽器擴展、CLI、編輯器集成——都從這裏走。下面介紹它的定位、接口、安裝和常見問題。

這是什麼

dsh-api 是 lilming123 維護的 dsh 插件,當前版本 0.1.0,MIT 許可證。它把 dsh 的內部能力——語言設置、工作區註冊表、companion 橋接——以 JSON 路由的形式暴露在 dsh 已監聽的 127.0.0.1 端口上。不新開端口,除 Node 本身外零運行時依賴,路由前綴默認 /dsh-api

DSH 生態的理念是「一切皆插件」,這個插件遵循的正是這個前提:裝進 profile,隨 dsh web 一起加載。

核心功能:兩層路由

路由分兩層,掛在同一個 /dsh-api 前綴下。

原生路由

插件加載後即可用,不依賴任何額外進程:

方法 路徑 用途
GET /dsh-api/health 存活檢查與基本身份信息(dsh 端口、cwd、companion 是否註冊)
GET /dsh-api/language 讀取 locale.preference
POST /dsh-api/language 寫入 locale.preferencezhen
GET /dsh-api/workspace/list 列出 workspaceRegistry 的全部工作區
GET /dsh-api/workspace/current 當前 cwd 與 companion 快照
POST /dsh-api/workspace/create { path, title? } 註冊新工作區
GET /dsh-api/events SSE 事件流

事件流

GET /dsh-api/events 是一條 SSE 長連接,事件有五類:

  • ready:連接建立;
  • agent-idle:任一 agent/status 事件從 running 轉爲 idle 時觸發,攜帶 sessionIdtitlepreviousStatus 等字段;
  • approval-needed:對 dsh approval/request 瀑布的只讀旁路——插件觀察請求、廣播摘要,控制權原樣交回真正的應答鏈;
  • heartbeat:每 25 秒一幀,防止代理空閒斷連;
  • server-stopping:dsh 關閉前廣播,之後 socket 關閉。

companion 橋接路由

第二層需要已註冊 companion。companion 指任何本地進程:向 $DSH_HOME/dsh-api-companion.json 寫入 { port, token, pid, ... },並實現 /companion/* 協議。未註冊 companion 時,這些路由返回 503,原生路由不受影響:

方法 路徑 用途
GET /dsh-api/companion/state companion 狀態快照
POST /dsh-api/workspace/open 切換 dsh cwd(companion 下重啓 dsh)
POST /dsh-api/input/paste 注入文本到 dsh UI
POST /dsh-api/window/show 聚焦宿主窗口
POST /dsh-api/window/reload 重載宿主窗口
POST /dsh-api/app/quit 退出宿主應用

安裝與啓用

先裝插件,再確認加載方式:

dsh plugin --profile web add github:lilming123/dsh-api

README 中還列出了 npm 形式(dsh plugin --profile web add dsh-api),但標註爲 once published,當前是否可直接使用以倉庫 README 爲準。

安裝後的行爲:

1、dsh plugin 是 pnpm 薄封裝,包落入 $DSH_HOME/profiles/<profile>/node_modules/
2、dsh-api 註冊進該 profile 的 bundle 列表;
3、下次 dsh web 自動加載,不需要 --patch

Node 版本要求 >= 20。另外,桌面端 dsh-desktop 檢測到已安裝的 dsh-api 會跳過其內置回退版本;只有你直接驅動 dsh 時才需要手動裝這份插件。

配置

插件有兩個配置項,寫在 loader entry 的 config 裏:

默認值 用途
basePath /dsh-api HTTP 路由前綴
companionFile $DSH_HOME/dsh-api-companion.json companion 發現文件,按需讀取

例如把路由前綴改成 /control,在 $DSH_HOME/profiles/web/cordis.patch.yml 寫:

- id: dsh-api
  config:
    basePath: /control

這樣所有路由就以 /control 開頭。

典型用法

經過上面的步驟,插件已隨 dsh web 加載。下面用 curl 走一遍常用接口(端口沿用 README 示例中的 3181,以你的實際啓動參數爲準)。

1、存活檢查:

curl http://127.0.0.1:3181/dsh-api/health

返回 dsh 端口、cwd、companion 是否註冊等信息,可用來確認插件已加載。

2、訂閱事件流:

curl -N http://127.0.0.1:3181/dsh-api/events

-N 讓 curl 不做緩衝,直接打印 SSE 幀:readyagent-idleapproval-needed,以及每 25 秒一幀的 heartbeat

3、寫語言偏好與註冊工作區:POST /dsh-api/language 接收 { "language": "zh" | "en" }POST /dsh-api/workspace/create 接收 { path, title? }path 指向要註冊的目錄,title 可選。

4、跑示例腳本:倉庫 examples/ 下有兩個可直接運行的文件,curl.sh 遍歷所有端點,events.mjs 是零依賴的 Node SSE 訂閱示例,適合作爲自己集成的起點。

5、改源碼調試時用開發模式:

git clone https://github.com/lilming123/dsh-api.git
cd dsh-api

mkdir -p "$DSH_HOME/profiles/web/dsh-api-dev"
ln -sf "$PWD/index.mjs" "$DSH_HOME/profiles/web/dsh-api-dev/index.mjs"
cat > /tmp/dsh-api-dev.patch.yml <<'YML'
- insert:
    - id: dsh-api-dev
      name: ./dsh-api-dev/index.mjs
YML

dsh web --patch /tmp/dsh-api-dev.patch.yml --port 3181

dsh-api 是純 ESM 插件,沒有構建步驟。做法是把 clone 下來的 index.mjs 軟鏈進 profile 的 dsh-api-dev/ 目錄,再用 --patch 把它插進加載列表,指定 3181 端口啓動。

安全模型

三類約束值得知道:

  • 只綁定 dsh 已監聽的 127.0.0.1,不新開端口,外網進不來;
  • 變更類請求校驗 Origin:無 Origin 頭(CLI 場景)與迴環 origin 放行,其餘返回 403;
  • companion 橋接路由通過 x-dsh-api-companion-token 請求頭轉發發現文件中的 token,由 companion 側校驗,不匹配即拒絕。

常見問題

按現象查:

  • /dsh-api/* 全部 404:插件沒加載。檢查 ~/.dsh/profiles/web/package.jsondsh.profile.bundles 是否含 dsh-api~/.dsh/profiles/web/node_modules/dsh-api 是否存在,缺哪個就重跑安裝命令;
  • POST /dsh-api/workspace/create 返回 503:當前 dsh 上下文缺 workspaceRegistry——要麼 dsh 版本早於該服務,要麼 profile patch 把它裁掉了。升級 dsh(npm i -g @deepseek-ai/dsh)後再試;
  • companion 路由返回 503:沒有註冊 companion。直接跑 dsh 而不經 dsh-desktop 之類的殼時這是預期行爲,原生路由(/health/language/workspace/*/events)照常可用;
  • SSE 流每約 60 秒斷一次:反向代理在空閒殺連接。插件已每 25 秒發 heartbeat,仍斷就調大代理空閒超時,或去掉代理——dsh-api 綁定 127.0.0.1,本來就不需要代理。

適用場景與注意

適合誰:

  • 給 dsh 做桌面殼、瀏覽器擴展、編輯器集成的工具作者,需要一個統一 HTTP 入口,不想各自摸 in-process services;
  • 需要監聽 agent 空閒、審批事件做外部自動化的腳本;
  • 想從外部讀取或註冊工作區、切換 dsh cwd 的場景。

注意:插件以當前 dsh 進程的權限運行,通過它暴露的接口能觸達 dsh 進程能觸達的資源。安裝前建議先讀一遍源碼(主體是 index.mjs,純 ESM,沒有構建步驟),並確認 MIT 許可證符合你的使用方式。

小結

dsh-api 的價值在於收斂:複用 dsh 已有的 127.0.0.1 socket,一套固定的 /dsh-api/* JSON 路由,外加一層可選的 companion 橋接,讓外部工具驅動 dsh 有了統一入口。倉庫見 GitHub:https://github.com/lilming123/dsh-api;社區目錄頁(獨立站點,與 DeepSeek、幻方無官方從屬關係):https://www.skillhub.cn/plugins/lilming123/dsh-api

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

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

小夜