← Back to home@thdlrt

dsh-workspace-hot

Create and archive DeepSeek Harness sessions from outside the running Host — no restart, no refresh. 让运行中的 DSH 从外部创建/归档会话。

Stars
0
Language
JavaScript
Created
Oct 22, 2026
Updated
Oct 22, 2026

Introduction

dsh-workspace-hot

让运行中的 DeepSeek Harness 具备「从外部创建 / 归档会话」的能力 —— 不重启、不刷新页面。

License npm Topic

dsh plugin --profile web add dsh-workspace-hot

装完重启 app 一次(让插件与它的宿主侧服务加载);此后登记和归档都即时生效,不再需要重启。

简体中文 · English

解决什么问题

桌面版宿主独占 ~/.dsh/storages/workspace.json。任何外部进程去改这个文件,都是在一个看不见的缓存上做手脚:宿主把整张表放在内存里并会原样写回,外部改动要么被静默覆盖,要么更糟——破坏完整性校验,让整个工作区面板加载不出来。

还有第二个容易被忽略的缺口:把会话挂进工作区只更新了成员列表,而客户端另有一张会话摘要表;宿主不发 api-session/added,那一行就不会出现,即使注册表本身是对的。

这个插件从宿主内部把两个缺口一起补上:

  • 写入只经过宿主:插件跑在宿主进程里,调用公开的注册表 API(create / attachSession / archiveSession / unarchiveSession),workspace.json 始终只有一个写者。
  • 告诉客户端:登记时发出官方客户端消费的 api-session/added 摘要事件,会话立刻出现。
  • 归档是宿主的持久化写入:归档集由注册表自己发布,UI 自动更新,不需要额外事件;归档从不删除任何文件。

工作方式

外部进程                    Host 进程 (插件)                    客户端
--------                    ----------------                    ------
写 requests/<id>.json  →  fs.watch(requests) 去抖
                             ↓
                          validateRequest(id, action)
                             ↓
                          workspaceRegistry.create()
                          workspace.attachSession()
                             ↓
                          ctx.emit('api-session/added')  →  侧边栏立即出现
                             ↓
读 receipts/<id>.json  ←  原子写入回执(成功/失败都会写)

请求是不可变的,且只被确认一次。失败的请求会保留回执,重试请用新的 id。队列就是一个目录,所以任何语言、任何工具都能提交——不开端口、不起 socket、没有鉴权面。

请求协议

任何丢进 $DSH_HOME/dsh-workspace-hot/requests/(默认 ~/.dsh/dsh-workspace-hot/requests/)的 JSON 就是一条请求。先写 <id>.json.tmp 再重命名,避免读到写了一半的文件。

字段类型必填含义
version1是协议版本
id字符串 [A-Za-z0-9_-]{1,100}是必须等于文件名主干,也是回执文件名
actionregister | archive | unarchive否,默认 register操作
workspacePath绝对路径register 必填要创建或复用的工作区
sessionIdsession-…register 可选;归档类必填要放入或隐藏的会话
title非空字符串否工作区新建时的标题
stopActivity布尔否会话正在跑时强制归档(默认宿主会拒绝)

回执

写入 receipts/<id>.json:

{ "version": 1, "id": "register-…", "ok": true,
  "action": "register", "workspaceId": "…", "workspacePath": "E:\\code\\app",
  "sessionId": "session-…", "registered": true, "summaryPublished": true,
  "completedAt": "2026-10-22T06:29:41.512Z" }

ok: false 一定带 error。归档回执报 archived(最终状态)与 changed(本次是否真的改动)。

命令行助手(Windows PowerShell)

两个脚本都会先校验 status.json(插件已加载、版本匹配、pid 存活),宿主没就绪就什么都不碰。

# 把会话放进工作区,并发布会话摘要
.\register-workspace.ps1 -WorkspacePath 'E:\code\app' -SessionId 'session-…'

# 隐藏 / 恢复会话(文件保留,位置可还原)
.\session-actions.ps1 -Action archive   -SessionId 'session-…'
.\session-actions.ps1 -Action unarchive -SessionId 'session-…'

# 强制归档仍在运行的会话
.\session-actions.ps1 -Action archive   -SessionId 'session-…' -StopActivity

# 查看插件状态
.\register-workspace.ps1 -Check

DSH 目录不在 ~/.dsh 时加 -DshHome。

为什么需要「热」登记

派发系统通常把活干在另一个进程里(dsh --profile headless <task>)。那个会话是真实存在的,但它诞生于桌面宿主之外,于是左栏什么都没有。接着只剩两个坏选择:重启 app(对话没了),或者手改 workspace.json(数据可能没了)。

有了这个插件,外部派发者可以:

  1. 起会话;
  2. 写一条 register 请求;
  3. 它立刻出现在左栏——能点开、能续聊、能归档。

同一条通道也覆盖清理:把一次性会话归档而不删文件,需要时再取消归档回到原位。

兼容性与限制

  • 基于 DSH 0.2.0-rc.2 桌面版(Cordis 插件 API,ctx.inject / ctx.effect)。
  • 注入 workspaceRegistry、sessionPersistence、sessionQuery、sessions、agents。若未来版本改了其中某个名字,插件会激活失败并在 ~/.dsh/logs/dsh-workspace-hot.log 写明原因,而不是半残运行。
  • 登记要求会话已落盘(sessionPersistence.stat),且其 header 的 cwd 解析后等于目标工作区——这条校验属于宿主,是有意为之。
  • 归档不是删除:session-* 文件仍留在磁盘,注册表只是把它从各个分组界面隐藏。
  • 文件队列意味着「同机同用户」。它不开网络监听,也没有需要配置的鉴权。

开发

node tests/smoke.mjs

测试跑在临时 DSH_HOME + 假注册表上:登记、摘要事件、重放/幂等、未知会话、非法 action、缺字段、归档与取消归档幂等、生命周期关闭。全程不调用模型。

许可证

MIT,见 LICENSE。