前言¶
DSH 的理念是「一切皆插件」,瀏覽器插件之間經常需要協作:一個插件負責界面表面,另一個插件讀取文檔狀態,或者 Worker、iframe bridge、host IPC adapter 需要複用同一份前端能力。
這類協作如果直接複製組件、同步 DOM,或者把 Cordis service 對象跨端傳遞,邊界會很難控制。下面介紹的 dsh-ui-container 面向這個問題:它提供一個可複用的 UI 表面容器,並用一個較小的遠程協議連接另一個前端,遠程契約傳輸文檔快照和變更通知,不傳輸 React 元素、DOM 節點或 Cordis service 對象。
這是什麼¶
dsh-ui-container 是由 CH4ACKO3 維護的 DeepSeek Harness 瀏覽器插件,包名爲 @ch4acko3/dsh-ui-container,許可證爲 MIT。
它的定位是 remote-capable recursive UI surface container,核心職責是:
- 擁有 named UI surfaces
- 管理 document providers
- 提供 recursive React hosts
- 提供連接另一個前端所需的小遠程協議
這個插件的關鍵邊界是:接收端仍然在自己的前端裏渲染投影;遠程契約不搬運 React 元素、DOM 節點或 Cordis service 對象。
核心能力¶
下面介紹它已經明確的能力。
能力協商¶
協議版本 1 會在強制握手階段協商以下能力:
documents:解析基於 URI 的文檔投影。subscriptions:訂閱某個 URI,並在其投影可能變化時發送較小的失效通知。surface_commands:把 open、reveal、close 命令路由到已掛載的 surface session。
其中,surface_commands 默認禁用,需要服務端顯式開啓。
傳輸通道¶
它支持兩類通道:
- 跨進程
MessagePort通道 - WebSocket 網絡通道
線上契約¶
線上契約使用 JSON-RPC 2.0,方法名帶主版本號。
連接只允許一次握手。握手之後,後續方法必須屬於已經協商的能力。
所有遠程文檔內容和元數據要求 JSON 兼容。
安裝與啓用¶
先安裝到 DSH profile:
dsh plugin --profile web add github:CH4ACKO3/dsh-ui-container
如果安裝來源會觸發 Git 依賴的 prepare 構建,使用 pnpm 10 或更新版本時,需要先批准首次安裝報告中的精確包鍵,寫入該 profile 的 pnpm-workspace.yaml,再重複執行安裝命令。
典型用法¶
在其他瀏覽器插件中注入服務¶
其他瀏覽器插件可以從 @ch4acko3/dsh-ui-container/client 導入公共 API,並注入 uiContainer Cordis service。之後即可通過 ctx.uiContainer 訪問容器能力。
用 MessagePort 連接另一個前端¶
適用於 Worker、iframe bridge 或 host IPC adapter。先創建 host 和 client 通道,再暴露服務端,最後連接客戶端。
const hostChannel = createMessagePortUiRemoteChannel(hostPort)
const clientChannel = createMessagePortUiRemoteChannel(clientPort)
const stopServing = exposeUiContainerRemote(ctx.uiContainer, hostChannel, {
server: {
name: 'patchouli-host',
version: '0.1.0',
instance_id: crypto.randomUUID(),
},
})
const remote = await UiContainerRemoteClient.connect(clientChannel, {
client: {
name: 'patchouli-window',
version: '0.1.0',
instance_id: crypto.randomUUID(),
},
protocol_versions: [UI_REMOTE_PROTOCOL_VERSION],
capabilities: ['documents', 'subscriptions'],
})
const unregister = ctx.uiContainer.documents.registerProvider(
remote.createDocumentProvider('memory'),
)
這裏,exposeUiContainerRemote 把容器暴露到 host 通道,UiContainerRemoteClient.connect 在 client 通道完成握手。經過上面的步驟,客戶端側可以註冊一個來自遠端的 document provider。
在生命週期結束時,應按擁有這些 ports 的生命週期處理 unregister、remote 和 stopServing。
用 WebSocket 暴露容器¶
遠程傳輸層不定義認證。如果通過 WebSocket 暴露容器,擁有該端點的應用必須在調用 exposeUiContainerRemote 之前,自行處理認證、授權、TLS 和 origin policy。
假設 socket 是已通過應用層安全策略檢查的 WebSocket 連接,可以先創建通道,再暴露容器:
const channel = createWebSocketUiRemoteChannel(socket)
exposeUiContainerRemote(ctx.uiContainer, channel, {
server: {
name: 'patchouli-host',
version: '0.1.0',
instance_id: crypto.randomUUID(),
},
capabilities: ['documents', 'subscriptions'],
})
適用場景與注意¶
適合這類場景:
- 需要把 DSH 瀏覽器插件中的 UI 表面、文檔投影或 document provider 暴露給另一個前端。
- 需要在 Worker、iframe bridge、host IPC adapter 或 WebSocket 端點之間共享容器能力,而不想跨邊界發送 DOM 或組件樹。
- 希望接收端基於 JSON 兼容的文檔投影,在本地完成渲染。
注意以下邊界:
- 插件運行在 DSH 宿主環境中。安裝前請檢查源碼和 MIT 許可證,並確認它對當前 profile 的權限邊界。
- 遠程協議本身不提供認證。使用 WebSocket 時,服務端必須自己執行認證、授權、TLS 和 origin policy。
surface_commands默認禁用。服務端只有在明確允許某個主體控制對應前端會話時,才應啓用該能力。- 每條連接只允許一次握手;握手後只能調用已協商能力內的方法。
- 如果通過 Git 依賴安裝,使用 pnpm 10 或更新版本時,需要批准首次安裝報告中的精確包鍵,再重複安裝命令。
結尾¶
dsh-ui-container 的價值,是把 DSH 插件之間的前端協作從「搬 DOM / 組件樹」收斂爲「協商文檔投影和變更通知」。它沒有擴大前端對象本身的傳輸邊界,而是用較窄的遠程契約完成跨進程、跨端點的容器複用。