前言¶
在 DeepSeek Harness(DSH)裏用 Web UI 讓模型改代碼時,常見情況是:某一輪改錯了,你希望只撤回這一輪,或者把工作區恢復到更早某一輪結束時的樣子,並且先看 diff 再決定是否寫回磁盤。
DSH 自帶的 @deepseek-ai/dsh-workspace-changes 會記錄一輪裏改了哪些文件並展示 diff,但快照放在 Session 的臨時目錄裏,Session 或 Host 結束就沒了,也沒有回滾能力。dsh-checkpoints 在此基礎上增加影子 git 倉庫(重啓後仍在)和可按文件勾選、帶預覽的回滾,行爲上接近 Cursor 的檢查點體驗。
下面介紹這個由 tower666 維護、歸類爲工作流的 bundle 插件如何安裝、能做什麼,以及使用時需要注意的安全邊界。
這是什麼¶
dsh-checkpoints(npm 包名同名,當前資料中的版本爲 1.1.0,MIT 許可證)是面向 DSH Web 平臺的 bundle:安裝後會寫入 profile,Host 重啓後加載。
它在 Harness 主目錄下維護與真實工作區隔離的 shadow git 倉庫,在每一輪對話的 turn/start 與 turn/end 各拍一次快照,並把該輪變更文件列表記入目錄旁的 catalog;Web 頁在每個已完成輪次下展示一行操作入口,同時暴露 /api/checkpoints.* 接口,並把同等能力以 workspace_checkpoint 工具交給模型(寫盤前走 DSH 審批)。
與 workspace-changes 的差別¶
| 能力 | dsh-workspace-changes(官方插件) | dsh-checkpoints |
|---|---|---|
| 記錄每輪 diff | 有 | 有(並持久化) |
| 快照存放 | Session 臨時目錄 | $DSH_HOME/workspace-checkpoints |
| 重啓後保留 | 否 | 是 |
| 回滾 / 撤銷 | 無 | 有,支持預覽與按文件勾選 |
升級 bundle 時 README 寫明尚無自動升級路徑:需先移除再安裝新版本;但 $DSH_HOME/workspace-checkpoints 下的檢查點在移除與重裝後仍會保留,對話側歷史可繼續用。
核心功能¶
快照與目錄¶
- 在
turn/start、turn/end把工作區快照寫入 shadow 倉庫,並把該輪變更文件列表寫入 catalog。 - 默認存儲目錄爲
$DSH_HOME/workspace-checkpoints(可通過 mount 配置storeDir覆蓋)。
Web UI 上每個輪次一行¶
最新一輪與更早輪次提供的動作不同:
最新一輪 ⟲ N files changed in this turn [Undo this turn's changes…]
更早輪次 ⟲ N files changed in this turn [Revert to this turn…]
| 輪次位置 | 動作 | 基線 | 文件列表 |
|---|---|---|---|
| 最新 | Undo this turn’s changes | 本輪開始時的內容 | 僅本輪改過的文件 |
| 更早 | Revert to this turn | 該輪結束時的工作區 | 該輪結束與當前之間所有有差異的路徑 |
說明:歷史輪次行不提供「只撤銷某一輪、卻保留其後各輪改動」;在歷史位置上的語義是「回到這裏」。最新輪沒有「之後的輪次」,因此只提供撤銷本輪。
對話框會列出文件與行數、按需加載 unified diff 預覽、支持全選/全不選,只寫勾選中的文件。基線中不存在的路徑會標爲將刪除;超過大小限制的快照標爲不可回滾(not revertable)。應用後還可撤銷本次回滾本身。
兩類回滾語義¶
- Undo this turn’s changes:把本輪動過的文件恢復爲本輪開始時的內容;本輪未碰的文件不動。
- Revert to this turn:讓整個工作區等同該輪結束時的狀態;保留該輪及之前的改動,丟棄之後所有輪的改動。最新輪不顯示此項。
執行寫盤前,當前將被覆蓋的狀態會先被快照,因此上述操作本身也可以再 undo。
HTTP API¶
路由掛在 ctx.connection.fetch 下、位於 /api 內,受 Connection 鑑權,返回 no-cache JSON:
| 路由 | 方法 | 用途 |
|---|---|---|
/api/checkpoints.turns?sessionId= |
GET | 某 Session 的全部已記錄輪次 |
/api/checkpoints.plan |
POST | 生成回滾預覽(body:{sessionId, turn, side?, paths?};side: 'start' 默認表示撤銷該輪自身改動,side: 'end' 表示回到該輪結束態) |
/api/checkpoints.diff?planId=&path= |
GET | 某預覽 plan 下單文件的 unified diff |
/api/checkpoints.restore |
POST | 應用預覽({planId}) |
/api/checkpoints.undo |
POST | 撤銷已應用的回滾({undoId}) |
回滾分兩階段:plan 只讀;返回的 planId 一次性有效,並在 planTtlMs(默認 600000 ms)後過期。若在預覽打開期間任一計劃內文件被改動,restore 會拒絕。路徑相對錄製的工作區根解析,絕對路徑或越界路徑會被拒絕。
模型工具¶
對外暴露 workspace_checkpoint 工具,寫操作經 ctx.approval.request(),由 Session 審批策略決定;'unavailable' 時失敗關閉。審批服務要求處於 open turn,Web 側則由對話框完成預覽與確認。
安裝與啓用¶
該包是 bundle:安裝即選中 profile,正在運行的 Host 需重啓一次後纔會加載。
從 npm(推薦)¶
dsh plugin --profile web add dsh-checkpoints
也可在 Web UI 的 Plugins → Add 填入包名,或通過 Creator 預設裏 plugin_manager 的 install_bundle,target 填 dsh-checkpoints。npm 包頁:https://www.npmjs.com/package/dsh-checkpoints。
從 git 指定版本¶
dsh plugin --profile web add git+https://github.com/tower666/dsh-checkpoints.git#v1.1.0
將上述 spec 作爲 install_bundle 的 target 亦可;需要不可變來源時可用 commit SHA 替代 tag。
從本地目錄¶
install_bundle 的 target 指向本倉庫絕對路徑。
運行環境¶
package.json 要求 dsh 引擎 ^0.2.1-rc.3、node >=20。
配置(Mount)¶
在 profile 中掛載示例:
- name: 'dsh-checkpoints'
config:
maxFileBytes: 2097152
| 字段 | 默認值 | 含義 |
|---|---|---|
storeDir |
$DSH_HOME/workspace-checkpoints |
shadow 倉庫與 catalog 目錄 |
timeoutMs |
30000 |
單次 git 命令超時(毫秒) |
outputMaxBytes |
8388608 |
單次 git 輸出保留上限(字節) |
maxFileBytes |
2097152 |
回滾寫盤與 diff 的單文件快照上限;更大則 unsupported: oversized |
maxDiffBytes |
524288 |
單次預覽 unified diff 文本上限 |
maxTurnsPerSession |
300 |
每 Session catalog 保留輪次上限,超出則丟棄最舊 |
planTtlMs |
600000 |
未應用的預覽 plan 有效時長 |
bundle 刻意未聲明 Config schema:從工作區目錄安裝時無法依賴 Host 自帶的 schema 庫,非法配置會回落到上表默認值而非阻止激活。
安全模型(使用前宜知曉)¶
- 不寫入用戶倉庫:快照命令的
GIT_DIR指向 shadow 倉庫;用戶.git僅通過只讀GIT_ALTERNATE_OBJECT_DIRECTORIES掛接對象庫。集成測試對宿主.git樹做前後哈希比對。 - 使用空的
GIT_CONFIG_GLOBAL,並設置core.autocrlf=false、core.safecrlf=false,避免全局 git 配置改變字節級一致性。 - 工作目錄即使不在任何 git 倉庫內,仍可建檢查點;shadow 倉庫自包含。
- 大於
maxFileBytes的 blob 會列出但不參與寫回。
插件以當前 DSH 進程權限運行;安裝前請自行審閱源碼與許可證(MIT),並在生產工作區先小範圍試用回滾流程。
存儲佈局(簡要)¶
$DSH_HOME/workspace-checkpoints/
catalog.json # session → turn → {beforeTree, afterTree, files}
empty-gitconfig
repos/<sha1(workspace)>/ # 每個工作區一個 shadow 倉庫
.git/
index
...
適用場景¶
- 在 DSH Web 上長對話改代碼,需要跨 Host 重啓仍能查看歷史輪次變更並回滾。
- 希望先預覽 diff、再按文件勾選寫盤,而不是整目錄盲目還原。
- 需要把檢查點能力以 API 或
workspace_checkpoint工具納入自動化,並接受 DSH 審批門禁。
不宜期待:在不回到某一歷史結束態的前提下,單獨「摘掉」中間某一舊輪而保留其後改動——當前 UI 行動作不支持這種語義。
結尾¶
dsh-checkpoints 用持久 shadow git 與 catalog,補上了 DSH 原生 workspace-changes 在生命週期與回滾上的缺口;配合預覽、plan/restore 兩階段與對用戶倉庫的只讀隔離,適合把 Web 對話當成可撤銷的多輪編輯會話來用。