前言¶
用腳本、桌面殼或編輯器插件驅動 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.preference(zh 或 en) |
| 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時觸發,攜帶sessionId、title、previousStatus等字段;approval-needed:對 dshapproval/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 幀:ready、agent-idle、approval-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.json的dsh.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。