# dsh-mobile-upgrade

[English](../../README.md) | [简体中文](../zh-Hans/README.md) | 繁體中文 | [日本語](../ja/README.md) | [한국어](../ko/README.md) | [Español](../es/README.md) | [Français](../fr/README.md) | [Deutsch](../de/README.md) | [Русский](../ru/README.md)

面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)（`dsh`）web profile 的行動版體驗修復，以單一外掛交付。介面幾乎都透過宿主自身的槽位與狀態訊號呈現——不接管版面、不輪詢聊天內容。少數覆蓋層刻意用固定定位的純 DOM——左下角連線晶片/卡片、自我更新橫幅、共用提示條：它們必須恰好在宿主 React 樹凍結時依然存活。

## 你會得到

- **重新啟動服務列** — 設定 → 一般裡多一條「重新啟動服務」。先確認，再重新啟動 `dsh` 程序，服務恢復應答後頁面自動重新整理。
- **窄螢幕抽屜側欄** — 1024px 以下收合時側欄整體停到螢幕外，收合的觀感改由外掛自己的懸浮球承擔：一個 56px 圓形半透明的純 DOM 元素，並不是側欄（舊設計把側欄自身縮成晶片，宿主重建或皮膚改樣式就壞）。球自帶圖示——複製宿主鯨魚並剝掉樣式鉤子的副本，軌道掛載前用內建圖示兜底——尺寸固定，皮膚動不了。點按時外掛透過宿主自己發佈的控件（`[data-sidebar-opener]` / `[data-sidebar-toggle]`）促其展開，展開內容一掛載，全高側欄即從球的一側滑入；抽屜駐留期間球漸隱，關閉（遮罩、選取會話或抽屜頭部開關）在同一幀把面板滑出、球漸顯。面板寬度恆定，滑動只動 transform、不會半途卡住；展開的抽屜仍用主題自己的側欄色板疊出實體不透明底，玻璃皮膚不能再把它變透明。球可拖到任一側邊（記住位置），抽屜從球貼著的一側開啟；外掛沒按過的宿主控件（視窗列的開側欄按鈕、Escape、重新掛載）會被鏡像同步而不是與之互拗。此功能涉及的每個宿主元素都透過公開的 `data-*` 契約或穩定的 local 類名定位——不再依賴任何建置雜湊。
- **可捲動的問題卡片** — 1024px 以下待回答的問題再也無法埋沒自己的選項：問題被限制在自有的捲動區域內，於是長問題就地捲動，下方的選項清單保有剩餘空間，選項、提交列與收合/關閉按鈕始終留在螢幕上並可以點到。短問題不受影響，卡片仍貼合自身內容。
- **風暴安全的反應性** — 抽屜/選單觀察器與設定輪詢器以受限速率回應串流訊息爆發，宿主無法連線時自動退避；重連期間側欄軌道重新掛載時保留抽屜狀態而不是來回擺動，關閉抽屜的點擊在重新掛載後重試而不是落在過期的開關上：大量會話同時串流輸出不再凍結輸入，也不會把側欄抽動到點不動——無論抽屜展開還是收合。
- **子代理目錄防護** — 宿主每次請求都列舉整個會話語料來產生子代理目錄（長歷史下約 1s），其用戶端又在每次選取、晶片懸停與成員變動事件時發起詢問。外掛包住這次重新整理：活躍會話清單中沒有子代理的父層不再被詢問，同一父層至多每 2.5s 被問一次，重新整理起點彼此錯開——子代理扇出不再以全量語料掃描拖垮宿主。
- **點擊展開的譜系晶片** — 桌面端上，子代理晶片（「N 個子代理」與子代理標題切換器）在目前宿主裡只對懸停展開，點擊無效。外掛把晶片上的點擊轉換成宿主已經理解的懸停事件對，於是點擊即可開合子代理樹（祖先麵包屑保留原有的點擊導覽）。
- **窄螢幕頭部收納器** — 1024px 以下，會話頭部的晶片（譜系、任務、預設）比手機還寬且僅能懸停。它們摺疊成一枚膠囊（`≡ 標題 · N agents · M jobs`）；點按後開啟全寬面板，內含會話譜系（每個祖先皆可點按，並標註各自的後代數）、以家族根為根的子代理樹——列資料渲染自活躍會話清單，分支經防護重新整理按需擷取目錄——以及本會話的背景任務。桌面端維持不變。
- **自我更新** — 用戶端 bundle 按修訂版不可變發佈，手機分頁可能連跑舊版好幾天。頁面把啟動時的修訂版與伺服器目前發佈的修訂版比對，待頁面閒置時（絕不在輸入草稿期間）自行重新整理，或提供可點按的橫幅。
- **會話列表渲染節流** — 宿主對每個已掛載會話的每次投影變化都推送一個全值幀，而執行中子代理的計時視圖在每個已提交事件上都會變化，於是繁忙的後台機群會以每秒 50-150 幀灌進頁面。每個幀此前都會重渲染整個會話列表（一次重建要遍歷全部摘要外加 O(n²) 快取清掃——實測佔掉主執行緒的大半時間，頁面凍結到只能重新載入）。插件把這些重渲染合併到一個自適應的尾隨間隔上，同時數值仍原封不動地流入各會話自己的儲存——背景串流不再凍結頁面，無論是新會話還是舊會話。
- **連線狀態卡片** — 宿主左下角的連線控件點擊後毫無可感知的反應：它請求的重連扎回同一條已經僵死的傳輸，恢復提示是個不可點擊、靠計時器消失的 div，而窄屏的側欄抽屜干脆不渲染它。外掛在左下角用純 DOM 晶片錨定連線狀態（宿主 React 樹凍結時依然存活），並在其上方彈出半常駐卡片：指標在卡片內時它不消失，移開後自動消失；卡片裡是兩個真正有效的操作——透過連線服務立即重連，以及整頁手動重新整理。卡住或失敗的 `/api/` 請求也在同一處呈現：晶片上有徽標與計數，卡片裡是請求清單加服務探活——無論多少請求停滯或失敗，聊天輸入框旁邊不再出現任何警告。
- **逐功能開關** — 外掛在 設定 → 外掛 裡安裝 `dsh-mobile-upgrade` 設定節，每個功能一枚開關。

## 截圖

懸浮球、側欄抽屜、窄螢幕設定標籤與窄螢幕頭部收納器（含標註）：

| | |
|---|---|
| ![懸浮球](../../res/shot-floating-chip.png) | ![側欄抽屜](../../res/shot-drawer.png) |
| ![窄螢幕設定標籤](../../res/shot-settings-tabs.png) | ![窄螢幕頭部收納器](../../res/shot-header-collector.png) |

## 安裝

```sh
dsh plugin --profile web add dsh-mobile-upgrade
```

重新啟動 `dsh web`，然後在手機上開啟 web profile：重新啟動列在 設定 → 一般，功能開關在 設定 → 外掛 → dsh-mobile-upgrade。附件請直接使用宿主輸入框內建的附件系統。

需要 `dsh` 0.2.0-rc.2 或更新版本；本外掛針對 `dsh` 0.2.2 開發與驗證（宿主內建附件系統已取代本外掛的上傳功能）。0.2.2 已自帶窄螢幕抽屜、設定標籤、受寬度約束的模型選單以及按模型編輯輸入型別的編輯器，本外掛不再重複實作這些：相關覆蓋是刪除而不是重新補雜湊，剩下的是懸浮球接管與下列增強。

## 設定

外掛設定卡按功能列出開關（詳見「功能開關」一節）；`restartEnabled` 還控制重新啟動路由：

| 鍵 | 預設值 | 意義 |
|---|---|---|
| `restartEnabled` | `true` | 提供重新啟動服務列及其路由 |

## 功能開關

上文每個功能都可以在 設定 → 外掛 → dsh-mobile-upgrade 裡切換（下次頁面載入生效），也可以按裝置用 `localStorage` 鍵覆寫——`mfx-restart`、`mfx-drawer`、`mfx-net`、`mfx-questions`、`mfx-selfupdate`、`mfx-agents`、`mfx-header`、`mfx-listthrottle`, `mfx-conn`——值為 `"0"` 即關閉該功能。

## 已知限制

- 客戶端透過宿主公開的 `data-*` 契約（`data-sidebar-drawer`、`data-sidebar-collapsed`、`data-sidebar-mask`、`data-sidebar-toggle`、`data-sidebar-opener`、`data-rightbar-col`、`data-shortcut-modal`、`data-slot`）掛鉤宿主 UI；宿主沒有發佈屬性時，改用 CSS 模組類名的 local 部分（`_sidebarCol`、`_crumbs`、`_tabs`）。兩者都能跨建置存活：建置只改變 local 名前面的雜湊。宿主若重新命名這些契約，對應功能會降級，待本外掛跟進調整；其餘功能不受影響。問題卡片中的問題區域仍由卡片自身的 `data-question-key` 鉤子定位。
- 頭部收納器與譜系點擊墊片都跑在宿主自身的資料上（活躍會話清單及其子代理目錄）；除受防護的分支擷取外不新增請求，點按某個模式仍在載入中的列，會在對應目錄送達後自行完成。
- 輸入模態開關只能補寫你自行自訂過的供應商路由；純目錄路由依設計唯讀——憑空造一個目錄節會導致模型目錄崩塌。

## 安全說明

外掛的 HTTP 路由（重新啟動、設定編輯）與宿主共用同一個 web server，因此統一走 connection 服務的 `requestRejection`：與宿主閘道相同的 Host/來源校驗與瀏覽器會話校驗（來源不可信回傳 403，沒有有效瀏覽器會話回傳 401）。這樣一條會重新啟動行程、改寫 profile 供應商目錄的路由，就不再能從未鑑別的網路側存取。若宿主沒有暴露該介面，路由回退到部署自身的閘門，宿主半邊會記一則警告——對外暴露部署之前，請仍把它放到保護其餘介面的同一道閘門之後（反向代理認證、僅回環繫結）。

## 社群連結

- [Linux.Do](https://linux.do) —— 一個分享與討論技術的社群。

## 授權

以[合成原始碼授權條款（SySL）1.0 版](LICENSE)散佈。

> NOTICE: This software includes code generated by artificial intelligence. See the LICENSE file for the Synthetic Source License terms, including model disclosure requirements.
