前言¶
DeepSeek Harness(DSH)目前對會話的操作只有「歸檔」:歸檔只是把會話 id 記進 archivedSessionIds,日誌目錄原封不動。這就帶來兩個問題:一是真正的刪除能力缺失,二是已經發出的請求無法修改。
tazewell/dsh-session-tidy 插件補上了這兩點:把會話移入可恢復的 7 天回收站,以及通過 fork 分支的方式修改已經發送的請求。
插件簡介¶
tazewell/dsh-session-tidy 是一個 DSH 工作流插件,提供兩個核心能力:
- 可恢復刪除:刪除會話時,文件移動到
~/.dsh/session-trash/entries/<時間戳>-<會話 id>/,7 天內可恢復,過期後惰性清理。 - 分叉編輯:在任意一條用戶消息上點擊鉛筆圖標,修改後 fork 一個分支會話,原會話根據選項移入回收站或保留。
安裝¶
插件包名爲 dsh-session-tidy,版本 1.0.0。
插件管理器(推薦):使用插件管理器的 install_bundle 指向包目錄(或解壓後的目錄),或在插件市場裏按包名安裝。管理器會負責 profile 的 package.json、cordis.patch.yml 與依賴。
手動登記:在 ~/.dsh/profiles/<profile>/package.json 裏添加:
"dependencies": { "dsh-session-tidy": "^1.0.0" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-session-tidy"] } }
然後在 profile 目錄安裝依賴並重啓 DSH。
會話刪除與恢復¶
側邊欄每個會話的懸浮操作區和「…」菜單各有一個刪除入口。
- 點擊刪除 → 確認對話框顯示會話標題。
- 確認後 Host 先停止該會話正在跑的任務(子代理、後臺命令、定時提醒),再把它移入回收站,並清掉投影緩存。
- 側邊欄底部的垃圾桶按鈕打開回收站,可以:
- 恢復:文件回到原來的會話目錄、重新掛回原工作區、解除歸檔;
- 徹底刪除:立即刪掉回收站裏的目錄,不可恢復;
- 清空回收站:刪除全部記錄(會二次確認)。
當前正在主視圖打開的會話不能刪除:對話框會提示先切換到其他會話。
存儲位置與保留期¶
~/.dsh/session-trash/entries/<時間戳>-<會話 id>/
meta.json # id、標題、原工作區、刪除時間、字節數
session/ # 原來的會話目錄
回收站保留 7 天,過期條目在下次打開回收站時惰性清理。
安全機制¶
- 刪除只發生在
~/.dsh內,路徑會做目錄逃逸校驗。 - 接口只接受本機迴環調用、同源請求並帶
x-dsh-plugin: session-tidy頭,杜絕任意網頁或局域網客戶端調用。
修改已經發送的請求¶
每條用戶消息下面(時間、複製按鈕那一行)都多了一個鉛筆圖標:鼠標移到那條消息上纔會顯現,點它就改這條請求——不必是最後一條。
- 點擊某條消息的鉛筆 → 對話框「修改這條請求」裏就顯示這條請求的原文,可以直接改。
- 確認後插件在該請求之前 fork 出一個分支會話,把改好的內容寫進新會話的輸入框草稿,並自動切過去。分支的歷史正好停在「這條請求之前」,所以這條提問和它後面(以及它自己的半截回答)都不會帶過去。
- 在分支裏看過沒問題就回車發送。
切點規則¶
切點取的是上一條已完成 turn 的結尾(turn/end 的 seq),不是「消息 seq − 1」:用戶消息前面還有它自己那條 turn 的 turn/start、step/start,按 seq − 1 切會讓宿主給這個空 turn 補一個「forked」結束,界面上就會多出一行沒有內容的「已完成,用時 1 秒」。規則還會跳過這種空 turn(兩條 turn-tail 相鄰),所以之前編輯留下的空殼會在下一次編輯時一起丟掉。
原會話處理¶
對話框裏有一個默認勾選的選項「把原會話移入回收站(7 天內可恢復)」:
- 勾選(默認):分支沿用原會話的標題,原會話進回收站,側邊欄裏看起來就是「同一個會話被改掉了」;想找回來隨時去回收站恢復。
- 取消勾選:原會話保留,分支標題加
(1)後綴,兩個會話並存,可以對照。
如果原會話移入回收站失敗(比如文件一時被佔用),分支照常保留並提示原因,不會因爲回收失敗把已建好的分支丟掉。
爲什麼 fork¶
DSH 目前沒有「原地截斷會話日誌」的能力(只能歸檔、不能回退),fork 是唯一能「替換掉這條請求」又不丟歷史的方式。
限制¶
- 只能取回文本:附件、
@引用的 chip 不會跟着過去(正文會保留)。 - 會話正在跑的時候鉛筆置灰(先停止,再編輯);沒有可編輯文本(比如只發了圖片)的消息不顯示。
- 改的是較早的消息時,那條消息之後的對話只存在於原會話裏——所以默認把原會話放進回收站,取消勾選就能兩邊都留着。
- 草稿是寫給分支會話的,取消編輯不會污染當前會話的草稿。
- 分支和原會話共享同一條前綴歷史,所以上下文是連續的。
結構說明¶
index.js— Host 入口:解析 DSH home、註冊/plugin/session-tidy前綴路由,刪除前調用workspaceRegistry.archiveSession(id, { stopActivity: true }),恢復後重新attachSession並unarchiveSession。lib/trash.js— 回收站存儲:移動(跨盤迴退到複製+刪除)、meta、恢復、清理、過期。lib/routes.js— HTTP 層:GET trash、POST delete|restore|purge|empty,含同源與請求頭校驗。client.js— 瀏覽器側:會話行刪除按鈕、菜單項、側邊欄底部回收站入口、每條用戶消息的懸停鉛筆(注入到官方氣泡操作行)、確認框 / 回收站對話框 / Toast(全部使用--dsw-alias-*主題變量,跟隨明暗主題)。cordis.patch.yml— bundle patch,插入session-tidy這一行。
測試與驗證¶
運行測試:
node --test "test/*.test.mjs"
38 個用例覆蓋回收站存儲、HTTP 路由(迴環/同源校驗、回滾、錯誤碼)、Host 註冊,Client 的插槽註冊與詞典完整性,以及消息鉛筆的注入 / 禁用 / 取值、彈窗內直接編輯、空內容禁用確認、fork 切點(上一條 turn/end、跳過空 turn)、草稿寫入(寫入的是改後文本)、原會話入回收站與失敗提示。
已安裝到 desktop profile 並現場確認 /plugin/session-tidy/trash 返回 {"ok":true,"entries":[]},說明 Host 半已生效;瀏覽器內的最終視覺呈現需要在實際頁面裏確認。
適用場景¶
適合需要頻繁清理會話、或者需要修改已發送請求的 DSH 用戶。插件以當前 dsh 進程權限運行,安裝前應檢查源碼與許可證(MIT)。
後續計劃¶
- 空會話 / 空分支批量清理
- 分支血緣標記與「回到原會話」
- 編輯時帶上附件與
@引用 - 批量清理面板(按工作區篩選、按大小排序、批量刪除)
- 導出會話、存儲佔用統計